/** * @file usb_bsp_e3.c * @brief usb board support source file. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include #include "usb_bsp_e3_reg.h" #if !CONFIG_OS #include #endif #define USB_BSP_LOG_EN 0 struct usb_irq { void (*handler)(void *arg); void *arg; }; enum usb_irq_id { USB_IRQ_OHCI = 0, USB_IRQ_EHCI, USB_IRQ_PERI, USB_IRQ_DMA0, USB_IRQ_DMA1, USB_IRQ_OTG, USB_IRQ_NUM }; static struct usb_irq usb_irq_table[USB_IRQ_NUM]; static volatile uint32_t usb_int_sts_msk; #if !CONFIG_OS volatile uint32_t usb_tick_cnt; static sdrv_btm_t usb_tick_ctrl; static sdrv_btm_cfg_t usb_tick_cfg = { .base = DEVICE_BASE(BTM1), .irq = DEVICE_INTR(BTM1_O_BTM), .tmr_id = SDRV_BTM_G1, .tmr_cfg = { .si_val = 23, .inc_val = 1, .frc_rld_rst_cnt_en = true, .term_use_mode = SDRV_BTM_DIRECT, .cmp_use_mode = SDRV_BTM_DIRECT, .cnt_dir = SDRV_BTM_CNT_UP, .cnt_mode = SDRV_BTM_CONTINOUS_MODE, } }; static void usb_tick_handler(void *p) { usb_tick_cnt++; } void usb_tick_init(uint32_t btm_base, int btm_irq) { usb_tick_cfg.base = btm_base; usb_tick_cfg.irq = btm_irq; sdrv_btm_init(&usb_tick_ctrl, &usb_tick_cfg); sdrv_btm_set_callback(&usb_tick_ctrl, usb_tick_handler, &usb_tick_ctrl); sdrv_btm_start(&usb_tick_ctrl, BTM_TYPE_PERIOD, BTM_TIME_US, 0); } uint32_t usb_tick_get_us(void) { return sdrv_btm_get_counter(&usb_tick_ctrl); } #endif static int usb_handler(uint32_t irq, void *arg) { uint32_t int_sts; int_sts = readl(OTG_NCR_STS7); int_sts &= usb_int_sts_msk; if (int_sts & (OTG_STS7_IXL_INT | OTG_STS7_DMA0_INT | OTG_STS7_DMA1_INT | OTG_STS7_BVALID_INT)) { if (usb_irq_table[USB_IRQ_PERI].handler) usb_irq_table[USB_IRQ_PERI].handler(usb_irq_table[USB_IRQ_PERI].arg); } if (int_sts & OTG_STS7_EHCI_INT) { if (usb_irq_table[USB_IRQ_EHCI].handler) usb_irq_table[USB_IRQ_EHCI].handler(usb_irq_table[USB_IRQ_EHCI].arg); } if (int_sts & OTG_STS7_OHCI_INT) { if (usb_irq_table[USB_IRQ_OHCI].handler) usb_irq_table[USB_IRQ_OHCI].handler(usb_irq_table[USB_IRQ_OHCI].arg); } if (int_sts & OTG_STS7_OB_INT) { if (usb_irq_table[USB_IRQ_OTG].handler) usb_irq_table[USB_IRQ_OTG].handler(usb_irq_table[USB_IRQ_OTG].arg); } if (int_sts & OTG_STS7_AHB_INT) { printf("unexpected usb AHB Bus Error %X\r\n", int_sts); CLRSETBITS_32(USBH_INT_STATUS, INT_STATUS_ULPI_INT | INT_STATUS_WAKEON_INT, INT_STATUS_AHB_INT); } if (int_sts & (OTG_STS7_WKON_INT | OTG_STS7_DMAERR_INT)) { printf("unexpected usb int %X\r\n", int_sts); } return 0; } void usb_irq_init(void) { usb_int_sts_msk = OTG_STS7_AHB_INT | OTG_STS7_WKON_INT | OTG_STS7_DMAERR_INT; SETBITS_32(OTG_NCR_CTL0, OTG_CTL0_AHB_INTEN | OTG_CTL0_WKON_INTEN | OTG_CTL0_DMAERR_INTEN); irq_attach(DEVICE_INTR(USB0), usb_handler, NULL); #if !CONFIG_USB_OTG irq_enable(DEVICE_INTR(USB0)); #endif return; } void usb_bsp_wait_pll_lock(void) { uint32_t wait_cnt = 0xFFFF; #if USB_BSP_LOG_EN uint64_t start_us; start_us = current_time_hires(); #endif while (!(readl(PHY_NCR_STS1) & PHY_STS_PLLLOCK)) { /* Wait for PLL Lock */ wait_cnt--; if (!wait_cnt) break; } #if USB_BSP_LOG_EN printf("hw_usb_wait_pll_lock from %lld to %lld\r\n", start_us, current_time_hires()); #endif if (!(readl(PHY_NCR_STS1) & PHY_STS_PLLLOCK)) printf("PHY_NCR_STS1 status %X\r\n", readl(PHY_NCR_STS1)); } #ifdef CONFIG_USB_DEVICE /* ********************************************************************************************************* * USBD_BSP_InitUSB0() * * Description : USB device controller board-specific initialization. * * Argument(s) : p_drv Pointer to device driver structure. * * Return(s) : none. * * Caller(s) : Device controller driver init function via 'p_drv_api->Init()' * * Note(s) : none. ********************************************************************************************************* */ static void USBD_BSP_InitUSB0 (USBD_DRV *p_drv) { SETBITS_32(USBH_COMMCTRL, COMMCTRL_OTG_PERI); /* 0 : Host, 1 : Peri */ writew((USB_CFG_BUSWAIT & 0x003f), USBD_BUSWAIT); SETBITS_32(USBD_DCTRL, DCTRL_PR_ROUND_ROBIN | DCTRL_INT_LVL); #if USB_LOW_VBUS SETBITS_32(OTG_NCR_CTL6, OTG_CTL6_INTTYPE_BOTH << OTG_CTL6_BVALID_INTTYPE_POS); #endif usb_irq_table[USB_IRQ_PERI].handler = (CPU_FNCT_PTR)p_drv->API_Ptr->ISR_Handler; usb_irq_table[USB_IRQ_PERI].arg = p_drv; return; } /* ********************************************************************************************************* * USBD_BSP_ConnUSB0() * * Description : Enable USB0 interrupt. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : Device controller driver start function via 'p_drv_api->Conn()' * * Note(s) : none. ********************************************************************************************************* */ static void USBD_BSP_ConnUSB0 (void) { setbits_32(&usb_int_sts_msk, OTG_STS7_IXL_INT | OTG_STS7_DMA0_INT | OTG_STS7_DMA1_INT); SETBITS_32(OTG_NCR_CTL0, OTG_CTL0_IXL_INTEN | OTG_CTL0_DMA0_INTEN | OTG_CTL0_DMA1_INTEN); #if USB_LOW_VBUS setbits_32(&usb_int_sts_msk, OTG_STS7_BVALID_INT); SETBITS_32(OTG_NCR_CTL7, OTG_CTL7_BVALID_INTEN); #endif return; } /* ********************************************************************************************************* * USBD_BSP_DisconnUSB0() * * Description : Disable USB0 interrupt. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : Device controller driver stop function via 'p_drv_api->Disconn()' * * Note(s) : none. ********************************************************************************************************* */ static void USBD_BSP_DisconnUSB0 (void) { #if USB_LOW_VBUS CLRBITS_32(OTG_NCR_CTL7, OTG_CTL7_BVALID_INTEN); clrbits_32(&usb_int_sts_msk, OTG_STS7_BVALID_INT); #endif CLRBITS_32(OTG_NCR_CTL0, OTG_CTL0_IXL_INTEN | OTG_CTL0_DMA0_INTEN | OTG_CTL0_DMA1_INTEN); clrbits_32(&usb_int_sts_msk, OTG_STS7_IXL_INT | OTG_STS7_DMA0_INT | OTG_STS7_DMA1_INT); } USBD_DRV_BSP_API USBD_DrvBSP_TAISHAN_USB0 = { USBD_BSP_InitUSB0, USBD_BSP_ConnUSB0, USBD_BSP_DisconnUSB0 }; #if USB_LOW_VBUS uint16_t USBD_DrvGetVbInt(void *p_reg) { return (readl(OTG_NCR_STS7) & OTG_STS7_BVALID_INT) ? 1 : 0; } uint16_t USBD_DrvGetVbStatus(void *p_reg) { uint16_t vbus[3]; do { /* Ensure port debounce. */ vbus[0] = readl(PHY_NCR_STS4) & PHY_STS_BVALID; udelay(10u); vbus[1] = readl(PHY_NCR_STS4) & PHY_STS_BVALID; udelay(10u); writel(OTG_STS7_BVALID_INT, OTG_NCR_STS7); vbus[2] = readl(PHY_NCR_STS4) & PHY_STS_BVALID; } while ((vbus[0] != vbus[1]) || (vbus[1] != vbus[2])); return vbus[2]; } #endif #endif #ifdef CONFIG_USB_HOST /* Enable write to USBH_UTMI_CTRL */ static inline void usbh_uphy_write_en(bool en) { if (en) SETBITS_32(USBH_REGEN_CG_CTRL, REGEN_CG_CTRL_UPHY_WEN); else CLRBITS_32(USBH_REGEN_CG_CTRL, REGEN_CG_CTRL_UPHY_WEN); } static void USB0H_BSP_Init (void) { static bool hci_inited = 0; if (hci_inited) return; hci_inited = 1; #if USB_OC_INVERT SETBITS_32(OTG_NCR_CTL1, OTG_CTL1_EXT_OCINV); #endif SETBITS_32(USBH_USBCTR, USBCTR_USBH_RST); udelay(2); #if CONFIG_USB_OTG SETBITS_32(USBH_ADP_CTRL, ADP_CTRL_ID_PULLUP); #else SETBITS_32(USBH_VBCTRL, VBCTRL_VBOUT); #endif CLRBITS_32(USBH_COMMCTRL, COMMCTRL_OTG_PERI); /* 0 : Host, 1 : Peri */ usb_bsp_wait_pll_lock(); writel(INT_ENABLE_AHB_INTEN | INT_ENABLE_UCOM_INTEN | INT_ENABLE_WAKEON_INTEN | INT_ENABLE_USBH_INTAEN | INT_ENABLE_USBH_INTBEN, USBH_INT_ENABLE); writel(0, USBH_AHB_BUS_CTR); CLRSETBITS_32(USBH_REGEN_CG_CTRL, REGEN_CG_CTRL_PERI_CLK_MSK | REGEN_CG_CTRL_HOST_CLK_MSK, REGEN_CG_CTRL_NONUSE_CLK_MSK); usbh_uphy_write_en(1); DSB; CLRBITS_32(USBH_UTMI_CTRL, UTMI_CTRL_LS_TXDAT_INV_EN); DSB; usbh_uphy_write_en(0); writel(SPD_CTRL_SUSPENDM_ENABLE | SPD_CTRL_WKCNNT_ENABLE, USBH_SPD_CTRL); return; } static void USB0H_BSP_EHCI_Init ( USBH_HC_DRV *p_hc_drv, USBH_ERR *p_err) { usb_irq_table[USB_IRQ_EHCI].arg = p_hc_drv; USB0H_BSP_Init(); *p_err = USBH_ERR_NONE; } static void USB0H_BSP_OHCI_Init ( USBH_HC_DRV *p_hc_drv, USBH_ERR *p_err) { usb_irq_table[USB_IRQ_OHCI].arg = p_hc_drv; USB0H_BSP_Init(); *p_err = USBH_ERR_NONE; } static void USB0H_BSP_EHCI_ISR_Reg ( CPU_FNCT_PTR isr_fnct, USBH_ERR *p_err) { usb_irq_table[USB_IRQ_EHCI].handler = isr_fnct; setbits_32(&usb_int_sts_msk, OTG_STS7_EHCI_INT); SETBITS_32(OTG_NCR_CTL0, OTG_CTL0_EHCI_INTEN); *p_err = USBH_ERR_NONE; } static void USB0H_BSP_OHCI_ISR_Reg ( CPU_FNCT_PTR isr_fnct, USBH_ERR *p_err) { usb_irq_table[USB_IRQ_OHCI].handler = isr_fnct; setbits_32(&usb_int_sts_msk, OTG_STS7_OHCI_INT); SETBITS_32(OTG_NCR_CTL0, OTG_CTL0_OHCI_INTEN); *p_err = USBH_ERR_NONE; } static void USB0H_BSP_EHCI_ISR_Unreg (USBH_ERR *p_err) { CLRBITS_32(OTG_NCR_CTL0, OTG_CTL0_EHCI_INTEN); clrbits_32(&usb_int_sts_msk, OTG_STS7_EHCI_INT); *p_err = USBH_ERR_NONE; } static void USB0H_BSP_OHCI_ISR_Unreg (USBH_ERR *p_err) { CLRBITS_32(OTG_NCR_CTL0, OTG_CTL0_OHCI_INTEN); clrbits_32(&usb_int_sts_msk, OTG_STS7_OHCI_INT); *p_err = USBH_ERR_NONE; } USBH_HC_BSP_API USB0H_EHCI_BSP_TAISHAN = { USB0H_BSP_EHCI_Init, USB0H_BSP_EHCI_ISR_Reg, USB0H_BSP_EHCI_ISR_Unreg }; USBH_HC_BSP_API USB0H_OHCI_BSP_TAISHAN = { USB0H_BSP_OHCI_Init, USB0H_BSP_OHCI_ISR_Reg, USB0H_BSP_OHCI_ISR_Unreg }; #endif #if CONFIG_USB_OTG void USB0_BSP_OTG_ISR_Reg (CPU_FNCT_PTR isr_fnct, void *arg) { usb_irq_table[USB_IRQ_OTG].handler = isr_fnct; usb_irq_table[USB_IRQ_OTG].arg = arg; setbits_32(&usb_int_sts_msk, OTG_STS7_OB_INT); SETBITS_32(OTG_NCR_CTL0, OTG_CTL0_OB_INTEN); } #endif