422 lines
11 KiB
C
422 lines
11 KiB
C
/**
|
|
* @file usb_bsp_e3.c
|
|
* @brief usb board support source file.
|
|
*
|
|
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <types.h>
|
|
#include <armv7-r/barriers.h>
|
|
#include <irq.h>
|
|
#include <reg.h>
|
|
#include <regs_base.h>
|
|
#include <irq_num.h>
|
|
#include <udelay/udelay.h>
|
|
#include "usb_bsp_e3_reg.h"
|
|
#if !CONFIG_OS
|
|
#include <sdrv_btm.h>
|
|
#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
|