/* USB device driver Primary interface for USB device driver @file usb.h @ingroup mIDrvUSB_Device @note Nothing Copyright Novatek Microelectronics Corp. 2014. All rights reserved. */ #ifndef __KERNEL__ #include #include #include "interrupt.h" #include "pll.h" #include "pll_protected.h" #include "efuse_protected.h" #else #include #include #include #include "linux/delay.h" #endif #include "usb2dev.h" #include "usb2dev_reg.h" #include "usb2dev_int.h" //#include "dma_protected.h" //#include "gpio.h" //#include "top.h" //#include "pad.h" //#include "Utility.h" //#include "uart.h" //#include "SxCmd.h" unsigned int rtos_usb2dev_debug_level = NVT_DBG_WRN; static VK_DEFINE_SPINLOCK(my_lock); #define loc_cpu(flags) vk_spin_lock_irqsave(&my_lock, flags) #define unl_cpu(flags) vk_spin_unlock_irqrestore(&my_lock, flags) #if (_FPGA_EMULATION_ == 1) #include "i2c.h" // PinmuxCfg.c static I2C_SESSION gUsbI2cSes; static PI2C_OBJ pUsbI2CObj; #endif // Global funcs & variables USB_MNG gUSBManage; UINT32 gUSBCauseGroup[4]; UINT32 gUSBCause; volatile UINT32 USBPhyDisable; BOOL gUSBOpen = FALSE; USB_GENERIC_CB gUsbSetInterfaceHdl = NULL; USB_CTRL_MODE gUsbCtrlMode = USB_CTRL_MODE_DEVICE; USB_GENERIC_CB gUsbChargingCB = NULL; USB_CHARGER_STS gChargerSts = USB_CHARGER_STS_NONE; BOOL gUsbUseShareFIFO = FALSE; #if _EMULATION_ USB_FIFO_NUM gTestFifoOffset = USB_FIFO0; #endif BOOL usb_suspend_to_dramoff_en = FALSE; static USB_CONTROLLER_STATE USBControllerState = USB_CONTROLLER_STATE_NONE; static BOOL bUsbHighSpeed = TRUE; static BOOL bStandardCharger = TRUE; ID FLG_ID_USBTSK; //ID FLG_ID_USB; ID SEMID_USB; THREAD_HANDLE USBCtlStartTsk_ID; THREAD_HANDLE USBSetupHalTsk_ID; // // Internal function declaration // static ER usb_openInternal(BOOL bChkCharger, UINT32 uiDebounce); static BOOL usb_chkDataContact(void); static BOOL usb_chkPCbyLineSts(void); #if _USB2DEV_TODO_ static ER usb_powerdown_callback(CLK_PDN_MODE Mode, BOOL bEnter); #endif #if (_EMULATION_ == ENABLE) extern ER usb_openDebounceTest(UINT32 uiDebounce); extern UINT32 usb_readIntGrp2(void); extern UINT32 usb_getLineStatus(void); extern void usb_testDataContact(void); extern void usb_testChargingPort(void); extern void usb_testChargingPortSecondary(void); #endif #ifdef __KERNEL__ static int USB_PLUGIN_GPIO = D_GPIO(7); static int USB_PLUGIN_POLAR = 1; #define GPIO_INT_USBPLUGIN 43 void usb_detect_vbusgpio(int vbus_gpio_pin, int vbus_gpio_pol) { USB_PLUGIN_GPIO = vbus_gpio_pin; USB_PLUGIN_POLAR = vbus_gpio_pol; } static UINT32 gpio_getIntStatus(UINT32 ipin) { gpio_direction_input(USB_PLUGIN_GPIO); return (UINT32) ((gpio_get_value(USB_PLUGIN_GPIO) == USB_PLUGIN_POLAR) ? 1 : 0 ); } #endif /** @addtogroup mIDrvUSB_Device */ //@{ /* USB device ISR USB controller device interrupt handler. @return void */ irqreturn_t usb_isr(int irq, void *devid) { REGVALUE devIntGrp, devIntGrpMsk; USB_PutString("usb_isr\n"); devIntGrp = USB_GETREG(USB_DEVINTGROUP_REG_OFS); devIntGrpMsk = ~USB_GETREG(USB_DEVINTGROUPMASK_REG_OFS); devIntGrp = devIntGrp & devIntGrpMsk; if (devIntGrp & BIT3) { USB_PutString(" Interrupt Source Group 3 !! \r\n"); usb_devINTGrp3(); } if (devIntGrp & (BIT0|BIT1|BIT2)) { usb2dev_set_config(USB_CONFIG_ID_INTEN, DISABLE); gUSBCause = devIntGrp & (BIT0|BIT1|BIT2); iset_flg(FLG_ID_USBTSK, FLGUSB_SIG); } return IRQ_HANDLED; } /* Lock USB This function will lock USB module @return - @b E_OK: Done with no errors. - @b E_ID: Outside semaphore ID number range - @b E_NOEXS: Semaphore does not yet exist */ static ER usb_lock(void) { ER erReturn; erReturn = wai_sem(SEMID_USB); if (erReturn != E_OK) { return erReturn; } gUSBOpen = TRUE; return E_OK; } /* Unlock USB This function will unlock USB module @return - @b E_OK: Done with no errors. - @b E_ID: Outside semaphore ID number range - @b E_NOEXS: Semaphore does not yet exist - @b E_QOVR: Semaphore's counter error, maximum counter < counter */ static ER usb_unlock(void) { gUSBOpen = FALSE; sig_sem(SEMID_USB); return E_OK; } /* Attach USB driver. This function will enalbe USB clock. @return void */ static void usb_attach(void) {} /* Detach driver. This function will disable USB clock @return void */ static void usb_detach(void) {} /* FOTG200 USB device controller initialization. This function is internal used for usb2dev_open() to initialize some setting of USB device controller @return void */ void usb_initFOTG200(void) { T_USB_DEVADDR_REG devAddr; T_USB_PHYTSTSELECT_REG devPhyTest; T_USB_DEVIDLECNT_REG devIdleCnt; T_USB_DEVMAINCTRL_REG devMainCtl; T_USB_DEVTEST_REG devTest; T_USB_GLOBALINTMASK_REG glbIntMsk; T_USB_DEVINTMASKGROUP0_REG devIntMskGrp0; T_USB_DEVINTMASKGROUP2_REG devIntMskGrp2; #if _USE_VDMA_FIFO_ T_USB_DEVVDMA_CTRL_REG devVdmaCtrl; #endif //set USB Device in unconfigure state devAddr.reg = USB_GETREG(USB_DEVADDR_REG_OFS); devAddr.bit.AFT_CONF = 0; // Fix printer connect fail if test mode is enabled devAddr.bit.RST_DEBOUNCE_INVL = 5; // set debounce time to 5ms USB_SETREG(USB_DEVADDR_REG_OFS, devAddr.reg); // chip enable devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.CHIP_EN = 1; #ifdef CONFIG_NVT_FPGA_EMULATION devMainCtl.bit.HALF_SPEED = 1; #else devMainCtl.bit.HALF_SPEED = 0; #endif USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // suspend counter devIdleCnt.reg = USB_GETREG(USB_DEVIDLECNT_REG_OFS); devIdleCnt.bit.IDLE_CNT = 0; USB_SETREG(USB_DEVIDLECNT_REG_OFS, devIdleCnt.reg); // clear interrupt USB_SETREG(USB_DEVINTGROUP2_REG_OFS, 0xFFFFFFFF); // disable all fifo interrupt USB_SETREG(USB_DEVINTMASKGROUP1_REG_OFS, 0xFFFFFF); // soft reset devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.SFRST = 1; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // soft reset clear devMainCtl.bit.SFRST = 0; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // clear all fifo devTest.reg = USB_GETREG(USB_DEVTEST_REG_OFS); devTest.bit.TST_CLRFF = 1; USB_SETREG(USB_DEVTEST_REG_OFS, devTest.reg); // disable Host & OTG interrupt glbIntMsk.reg = USB_GETREG(USB_GLOBALINTMASK_REG_OFS); glbIntMsk.bit.MOTG_INT = 1; glbIntMsk.bit.MHC_INT = 1; glbIntMsk.bit.INT_POLARITY = 1; USB_SETREG(USB_GLOBALINTMASK_REG_OFS, glbIntMsk.reg); // maks CX_IN/CX_OUT/CX_COMEND interrupt devIntMskGrp0.reg = USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS); devIntMskGrp0.bit.MCX_IN_INT = 1; devIntMskGrp0.bit.MCX_OUT_INT = 1; devIntMskGrp0.bit.MCX_COMEND = 1; USB_SETREG(USB_DEVINTMASKGROUP0_REG_OFS, devIntMskGrp0.reg); // mask DEV_IDLE interrupt devIntMskGrp2.reg = USB_GETREG(USB_DEVINTMASKGROUP2_REG_OFS); devIntMskGrp2.bit.MDEV_IDLE = 1; devIntMskGrp2.bit.MDEV_WAKEUP_BYVBUS = 1; devIntMskGrp2.bit.MTX0BYTE_INT = 1; USB_SETREG(USB_DEVINTMASKGROUP2_REG_OFS, devIntMskGrp2.reg); #if _USE_VDMA_FIFO_ devVdmaCtrl.reg = USB_GETREG(USB_DEVVDMA_CTRL_REG_OFS); #ifndef _NVT_EMULATION_ devVdmaCtrl.bit.VDMA_EN = 0; USB_SETREG(USB_DEVVDMA_CTRL_REG_OFS, devVdmaCtrl.reg); //DBG_DUMP("TOGGLE VDMA_EN\r\n"); USB_DELAY_MS(1); #endif devVdmaCtrl.bit.VDMA_EN = 1; USB_SETREG(USB_DEVVDMA_CTRL_REG_OFS, devVdmaCtrl.reg); #endif // enable global interrupt devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.GLINT_EN = 1; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS); devPhyTest.bit.UNPLUG = 0; USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); if (gUSBManage.fp_event_callback) { gUSBManage.fp_event_callback(USB_EVENT_CONNECT); } if ((gUsbChargingCB != NULL) && (gChargerSts == USB_CHARGER_STS_NONE)) { gUsbChargingCB(USB_CHARGE_EVENT_CONNECT); } } /* Check PC by line status @return - @b TRUE: PC - @b FALSE: no PC (maybe charger) */ static BOOL usb_chkPCbyLineSts(void) { T_USB_DEVMAINCTRL_REG devMainCtl; T_USB_PHYTSTSELECT_REG devPhyTest; T_USB_HCPORTSTACTRL_REG portStatusReg; unsigned long flags; // Assume UCLK is already enabled // chip enable devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.CHIP_EN = 1; // bit[5] // soft reset devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.SFRST = 1; // bit[4] USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // soft reset clear devMainCtl.bit.SFRST = 0; // bit[4] USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // Lock CPU to prevent we raise D+ pull-up too long loc_cpu(flags); // Enable D+ pull-up devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS); devPhyTest.bit.UNPLUG = 0; // bit[0] USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); USB_DELAY_US_POLL(20); portStatusReg.reg = USB_GETREG(USB_HCPORTSTACTRL_REG_OFS); // Restore CPU interrupt unl_cpu(flags); // Disable D+ pull-up devPhyTest.bit.UNPLUG = 1; // bit[0] USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); if (portStatusReg.bit.LINE_STS == 0x02) { // If line staus == J state // DBG_ERR("line sts check: PC\r\n"); return TRUE; // PC } else { // DBG_ERR("line sts check: charger\r\n"); return FALSE; // not PC (charger) } } /* Open USB driver internally Initialize USB module and enable interrupt, start running control & setup task for ISR etc... @param[in] bChkCharger detect usb charger - @b TRUE: only use this API to detect charger - @b FALSE: use this API to connect with usb host @param[in] uiDebounce debounce time to detect usb charger, unit: 10ms @return - @b E_OK: open success - @b E_OACV: USB driver is already opened - @b E_ID: Outside semaphore ID number range - @b E_NOEXS: Semaphore does not yet exist - @b E_SYS: USB has been unplug, so ignore this request... - @b E_TMOUT: USB Host does not respond,ex: charger - @b E_NOSPT: USB Host is disconnected */ static ER usb_openInternal(BOOL bChkCharger, UINT32 uiDebounce) { ER erReturn; T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_DEVDMACTRL1_REG devDMACtl1_bak; T_USB_OTGCTRLSTATUS_REG otgCtrlSts; T_USB_PHYTOP_REG RegTop; if (gUSBOpen) { DBG_ERR("driver already opened\r\n"); return E_OACV; } erReturn = usb_lock(); if (erReturn != E_OK) { return erReturn; } //if (bChkCharger == FALSE) { // erReturn = clr_flg(FLG_ID_USB, FLGPTN_USB); // if (erReturn != E_OK) { // return erReturn; // } //} //Reason: To avoid re-enter USB device after "Safety Removed" state //If we don't anything, we can NOT access USB registers in suspend mode. if (usb2dev_get_controller_state() == USB_CONTROLLER_STATE_SUSPEND) { //Hardware reset USB register.... try to leave suspend mode. #ifndef __KERNEL__ #if 0//USB2_TEST pll_enableSystemReset(USB2_RSTN); pll_disableSystemReset(USB2_RSTN); #else pll_enableSystemReset(USB_RSTN); pll_disableSystemReset(USB_RSTN); #endif #else { unsigned long flags; loc_cpu(flags); iowrite32( (ioread32((void *)(0xFD020084)) & ~(0x1<<19)), (void *)(0xFD020084)); iowrite32( (ioread32((void *)(0xFD020084)) | (0x1<<19)), (void *)(0xFD020084)); unl_cpu(flags); } #endif usb2dev_power_on_init(bUsbHighSpeed); usb_setControllerState(USB_CONTROLLER_STATE_NONE); } usb_attach(); // Set Controller as Device Mode RegTop.reg = USB_GETREG(USB_PHYTOP_REG_OFS); RegTop.bit.USB_ID = 1; USB_SETREG(USB_PHYTOP_REG_OFS, RegTop.reg); usb2dev_set_vbusi(TRUE); if (bChkCharger == FALSE) { // start running control & setup task for isr USBCtlStartTsk_ID = vos_task_create(USBCtlStartTsk, 0, "USBCtlStartTsk", TSK_PRI_USBCTRL, TSK_STKSIZE_USBCTRL); vos_task_resume(USBCtlStartTsk_ID); USBSetupHalTsk_ID = vos_task_create(USBSetupHalTsk, 0, "USBSetupHalTsk", TSK_PRI_USBSETUP, TSK_STKSIZE_USBSETUP); vos_task_resume(USBSetupHalTsk_ID); } // decrease VBUS debounce time from 540us to 200us otgCtrlSts.reg = USB_GETREG(USB_OTGCTRLSTATUS_REG_OFS); otgCtrlSts.bit.Vbus_FLT_SEL = 1; USB_SETREG(USB_OTGCTRLSTATUS_REG_OFS, otgCtrlSts.reg); //turn on the usb physical layer. devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; // bit[31] USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); if (devDMACtl1_bak.bit.DEVPHY_SUSPEND == 1) { // wait VBUS debounce time passed USB_DELAY_US_POLL(200); } usb_initFOTG200(); // Clear FIFOs usb2dev_clear_fifo(); #if (USB_STANDARD_CHARGER_DETECT == 1) if (bChkCharger == TRUE) { return E_OK; } #else { // Detect USB host by RESET signal T_USB_DEVINTGROUP2_REG devIntGrp2; UINT32 i = USB_HOST_TIMEOUT_PERIOD; while (i) { // The USB Driver interrupt has not enabled. Polling sts is safe. devIntGrp2.reg = USB_GETREG(USB_DEVINTGROUP2_REG_OFS); if (devIntGrp2.bit.USBRST_INT == 1) { //DBG_WRN("#Host:0x%x,i=%d\n\r",devIntGrp2.reg, i); break; } else { USB_DELAY_MS(1); i--; } } if (i == 0) { DBG_ERR("No USBHost\r\n"); return E_TMOUT; } } #endif // Pre-set USB DMA flag to mark DMA channel is available set_flg(FLG_ID_USBTSK, FLGPTN_USB_DMA_RDY); #ifndef __KERNEL__ request_irq(INT_ID_USB, usb_isr, IRQF_TRIGGER_HIGH, 0, 0); #endif return erReturn; } /* set USB controller state. @param[in] eUSBCtrlState USB controller state - @b USB_CONTROLLER_STATE_NONE: USB is not used - @b USB_CONTROLLER_STATE_RESET: USB is in reset state - @b USB_CONTROLLER_STATE_SUSPEND: USB is in suspend state @return void */ void usb_setControllerState(USB_CONTROLLER_STATE eUSBCtrlState) { USBControllerState = eUSBCtrlState; } /* Check Data Contact Check Data Contact (DP/DM is connected with host) @return - @b TRUE: contact with host - @b FALSE: NOT contact with host */ static BOOL usb_chkDataContact(void) { BOOL bContact = TRUE; T_USB_PHYCTRL0B_REG PhyReg0B; T_USB_PHYCTRL0C_REG PhyReg0C; T_USB_CHARGER_CONTROL_REG chargerCtrlReg; // Set DP/DM Pull-Down resist as SW control PhyReg0B.reg = USBPHY_GETREG(USB_PHYCTRL0B_REG_OFS); PhyReg0B.bit.DATARPDM = 1; PhyReg0B.bit.DATARPDP = 1; USBPHY_SETREG(USB_PHYCTRL0B_REG_OFS, PhyReg0B.reg); // Enable DM Pull-Down resist PhyReg0C.reg = USBPHY_GETREG(USB_PHYCTRL0C_REG_OFS); PhyReg0C.bit.DATARPDM = 1; USBPHY_SETREG(USB_PHYCTRL0C_REG_OFS, PhyReg0C.reg); #if 0 // Check DCD for 4x3= 12ms for (i = 0; i < 3; i++) { chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); chargerCtrlReg.bit.DCD_DETECT_EN = 1; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); // The Host is delay about 3.8ms to get result. // So we must delay 4ms. USB_DELAY_MS(4); chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); if (chargerCtrlReg.bit.DCD_DETECT_EN == 1) { bContact = FALSE; break; } } #else chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); chargerCtrlReg.bit.DCD_DETECT_EN = 1; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); if (in_interrupt() || in_atomic() || irqs_disabled()) { USB_DELAY_US_POLL(11000); } else { USB_DELAY_MS(11); } chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); if (chargerCtrlReg.bit.DCD_DETECT_EN == 1) { bContact = FALSE; } #endif chargerCtrlReg.bit.DCD_DETECT_EN = 0; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); // Disable DM Pull-Down resist PhyReg0C.bit.DATARPDM = 0; USBPHY_SETREG(USB_PHYCTRL0C_REG_OFS, PhyReg0C.reg); // Restore DP/DM Pull-Down resist as HW control PhyReg0B.bit.DATARPDM = 0; PhyReg0B.bit.DATARPDP = 0; USBPHY_SETREG(USB_PHYCTRL0B_REG_OFS, PhyReg0B.reg); return bContact; } static void usb_enableHighSpeed(BOOL bHighSpeed) { T_USB_DEVMAINCTRL_REG devMainCtl; devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); if (bHighSpeed) { devMainCtl.bit.FORCE_FS = 0; // bit[9] } else { devMainCtl.bit.FORCE_FS = 1; // bit[9] } USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); } #if _USB2DEV_TODO_ /* Power Down Mode Clock Callback to make PHY saving power */ static ER usb_powerdown_callback(CLK_PDN_MODE Mode, BOOL bEnter) { #if _FPGA_EMULATION_ return E_OK; #endif if (!usb_suspend_to_dramoff_en) { if (gUSBOpen) { DBG_ERR("USB Driver shall be close first.\r\n"); } if((Mode == CLK_PDN_MODE_SLEEP1) || (Mode <= CLK_PDN_MODE_SLEEP2) || (Mode <= CLK_PDN_MODE_SLEEP3)) { if(bEnter) { // IP provided to make PHY deeply sleeping OUTW(0xF06010D0, 0xFF); OUTW(0xF06010D4, 0x34); OUTW(0xF0601008, 0x14); OUTW(0xF0601000, 0x88); OUTW(0xF0601030, 0x35); OUTW(0xF060102c, 0xFF); } else { pll_enableSystemReset(USB_RSTN); pll_disableSystemReset(USB_RSTN); usb2dev_power_on_init(bUsbHighSpeed); usb_setControllerState(USB_CONTROLLER_STATE_NONE); } } } return E_OK; } static void usb_showDescriptor(UINT8 *pDesc, CHAR *pName) { UINT32 i,len,mark=0; if(pDesc == NULL) { DBG_DUMP("^RNone of %s Desc\r\n\n",pName); } else { DBG_DUMP("^Y%s Desc:",pName); len = pDesc[0]; if((pDesc[1] == USB_CONFIGURATION_DESCRIPTOR_TYPE) || (pDesc[1] == USB_BOS_DESCRIPTOR_TYPE)) len = pDesc[2]; for(i=0;i512)+1)*gUSBManage.ep_config_hs[i-1].blk_num , (gUSBManage.ep_config_hs[i-1].Direction == EP_DIR_OUT)?EpMaxps.bit.FNO_OEP:EpMaxps.bit.FNO_IEP); } usb_showDescriptor((UINT8 *)gUSBManage.p_dev_desc, "DEVICE"); usb_showDescriptor((UINT8 *)gUSBManage.p_config_desc_hs, "HS_CONFIG"); usb_showDescriptor((UINT8 *)gUSBManage.p_config_desc_fs, "FS_CONFIG"); } else { DBG_DUMP("HOST.(%s)\r\n",USB_GETREG(0x10)&0x1?"ENABLE":"DISABLE"); } return TRUE; } #endif static void usb_installCmd(void) { #if _USB2DEV_TODO_ static BOOL bInstall = FALSE; static SXCMD_BEGIN(usb, "usb debug message dump") SXCMD_ITEM("usb2", usb_debugDump, "dump usb 2.0 info") SXCMD_END() if (bInstall == FALSE) { SxCmd_AddTable(usb); bInstall = TRUE; } #endif } #if 1 /** @name USB Driver API */ //@{ /** Open USB driver Initialize USB module and enable interrupt, start running control & setup task for ISR etc... @return - @b E_OK: open success - @b E_OACV: USB driver is already opened - @b E_ID: Outside semaphore ID number range - @b E_NOEXS: Semaphore does not yet exist - @b E_SYS: USB has been unplug, so ignore this request... */ ER usb2dev_open(void) { usb_installCmd(); return usb_openInternal(FALSE, 0); } /** Check usb charger Check if connect with a usb charger @param[in] uiDebounce debounce time to detect usb charger, unit: 10ms @return - @b USB_CHARGER_STS_NONE: PC or not charger detected - @b USB_CHARGER_STS_CHARGING_DOWNSTREAM_PORT: charging downstream port - @b USB_CHARGER_STS_CHARGER: charger detected */ USB_CHARGER_STS usb2dev_check_charger(UINT32 uiDebounce) { #if 1 T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_DEVDMACTRL1_REG devDMACtl1_bak; if (gUSBOpen) { DBG_ERR("driver already opened\r\n"); return USB_CHARGER_STS_NONE; } usb_attach(); devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); if ((!bStandardCharger) && (usb_chkDataContact() == FALSE) && gpio_getIntStatus(GPIO_INT_USBPLUGIN)) { // If support non-standard charger, VBUS detect, but no D+/D- not correctly contacted // Then it might be D+/D- open type charger gChargerSts = USB_CHARGER_STS_CHARGER; } else { // If D+/D- is contacted, follow standard charger detection flow T_USB_CHARGER_CONTROL_REG chargerCtrlReg; T_USB_BUS_STATUS_REG busStsReg; chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); chargerCtrlReg.bit.CHG_DETECT_EN = 1; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); if (in_interrupt() || in_atomic() || irqs_disabled()) { USB_DELAY_US_POLL(40000); } else { USB_DELAY_MS(40); } busStsReg.reg = USB_GETREG(USB_BUS_STATUS_REG_OFS); chargerCtrlReg.bit.CHG_DETECT_EN = 0; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); if (busStsReg.bit.CHG_DET == 0) { // standard downstream port. i.e. PC if (bStandardCharger) { gChargerSts = USB_CHARGER_STS_NONE; } else { if (usb_chkPCbyLineSts() == TRUE) { if ((gpio_getIntStatus(GPIO_INT_USBPLUGIN) == 0) || (usb_chkDataContact() == FALSE)) { // Double confirm USB plug status DBG_ERR("line sts check: disconnect\r\n"); gChargerSts = USB_CHARGER_STS_DISCONNECT; } else { DBG_ERR("line sts check: PC\r\n"); gChargerSts = USB_CHARGER_STS_NONE; } } else { DBG_ERR("line sts check: charger\r\n"); gChargerSts = USB_CHARGER_STS_CHARGER; } } } else { // charger or charging downstream port chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); chargerCtrlReg.bit.SECOND_CHG_DETECT_EN = 1; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); if (in_interrupt() || in_atomic() || irqs_disabled()) { USB_DELAY_US_POLL(40000); } else { USB_DELAY_MS(40); } busStsReg.reg = USB_GETREG(USB_BUS_STATUS_REG_OFS); chargerCtrlReg.bit.SECOND_CHG_DETECT_EN = 0; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); if (busStsReg.bit.CHG_DET == 0) { // charging downstream port if (bStandardCharger) { gChargerSts = USB_CHARGER_STS_CHARGING_DOWNSTREAM_PORT; } else { if (usb_chkPCbyLineSts() == TRUE) { if ((gpio_getIntStatus(GPIO_INT_USBPLUGIN) == 0) || (usb_chkDataContact() == FALSE)) { // Double confirm USB plug status DBG_ERR("line sts check2: disconnect\r\n"); gChargerSts = USB_CHARGER_STS_DISCONNECT; } else { DBG_ERR("line sts check2: charge PC\r\n"); gChargerSts = USB_CHARGER_STS_CHARGING_DOWNSTREAM_PORT; } // gChargerSts = USB_CHARGER_STS_CHARGING_DOWNSTREAM_PORT; } else { DBG_ERR("line sts check2: charger\r\n"); gChargerSts = USB_CHARGER_STS_CHARGER; } } } else { // dedicated charging port gChargerSts = USB_CHARGER_STS_CHARGER; } } } USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1_bak.reg); usb_detach(); if (gUsbChargingCB != NULL) { switch (gChargerSts) { case USB_CHARGER_STS_CHARGER: case USB_CHARGER_STS_CHARGING_DOWNSTREAM_PORT: { gUsbChargingCB(USB_CHARGE_EVENT_CHARGER); } break; default: break; } } return gChargerSts; #else return USB_CHARGER_STS_CHARGER; #endif } void usb2dev_init(void) { //vos_flag_create(&FLG_ID_USB, NULL, "FLG_ID_USB"); vos_flag_create(&FLG_ID_USBTSK, NULL, "FLG_ID_USBTSK"); vos_sem_create(&SEMID_USB, 1, "SEMID_USB"); } void usb2dev_uninit(void) { vos_sem_destroy(SEMID_USB); vos_flag_destroy(FLG_ID_USBTSK); //vos_flag_destroy(FLG_ID_USB); } static BOOL usb2dev_init_done; /** USB Power on initialization. @note This API SHOULD be invoked in system init phase. Else USB may be malfunctioned. @param[in] bHighSpeed set USB in high/full speed mode - @b TRUE: high speed mode - @b FALSE: full speed mode @return void */ void usb2dev_power_on_init(BOOL bHighSpeed) { T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_HCMISC_REG hcMiscReg; //DBG_DUMP("enter\r\n"); if(!usb2dev_init_done) { usb2dev_init(); usb2dev_init_done = 1; } #if 0 //def _FPGA_EMULATION_ #if (_FPGA_EMULATION_ == 1) pll_enableSystemReset(USB_RSTN); pll_disableSystemReset(USB_RSTN); // For PHY board I2C connection pUsbI2CObj = i2c_getDrvObject(0); if (pUsbI2CObj->open(&gUsbI2cSes) != E_OK) { DBG_ERR("Open I2C driver fail\r\n"); return; } pUsbI2CObj->setConfig(gUsbI2cSes, I2C_CONFIG_ID_MODE, I2C_MODE_MASTER); pUsbI2CObj->setConfig(gUsbI2cSes, I2C_CONFIG_ID_BUSCLOCK, 80000); pUsbI2CObj->setConfig(gUsbI2cSes, I2C_CONFIG_ID_HANDLE_NACK, TRUE); // switch to page-0 usb_writePhyReg(0xFF, 0x00); // Switch TC gpio to usb mode. usb_writePhyReg(0xBF, 0x0A); pUsbI2CObj->close(gUsbI2cSes); #endif #endif gUsbCtrlMode = USB_CTRL_MODE_DEVICE; //gfpVendorReqHdl = NULL; usb_attach(); // default set to device mode usb_setID(TRUE); //It is possible that loader has turn off the USB physical layer. //So we should turn on the usb physical layer. devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DEVPHY_SUSPEND = 0; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); vos_util_delay_us_polling(50); usb_enableHighSpeed(bHighSpeed); bUsbHighSpeed = bHighSpeed; // Bug fix for host resume pulse hcMiscReg.reg = USB_GETREG(USB_HCMISC_REG_OFS); hcMiscReg.bit.RESM_SE0_CNT = 0x22; USB_SETREG(USB_HCMISC_REG_OFS, hcMiscReg.reg); // Clear FIFOs usb2dev_clear_fifo(); gUSBCxFinishAction = USB_ACT_IDLE; #if !_FPGA_EMULATION_ usb_writePhyReg(0x51, 0x20); usb_writePhyReg(0x50, 0x30); /* Apply eFuse settings */ { UINT16 SWCTRL=4,SQSEL=4,RESINT=0x8; UINT32 temp; #if 1//_USB2DEV_TODO_ { UINT16 data = 0; INT32 result; result= efuse_readParamOps(EFUSE_USBC_TRIM_DATA, &data); if(result >= 0) { SWCTRL = data&0x7; SQSEL = (data>>3)&0x7; RESINT = (data>>6)&0x1F; } } #endif usb_readPhyReg(0x06, &temp); temp &= ~(0x7<<1); temp |= (SWCTRL<<1); usb_writePhyReg(0x06, temp); usb_readPhyReg(0x05, &temp); temp &= ~(0x7<<2); temp |= (SQSEL<<2); usb_writePhyReg(0x05, temp); USB_SETREG(0x30C, 0x100+RESINT); usb_writePhyReg(0x52, 0x60+RESINT); } usb_writePhyReg(0x51, 0x00); #endif //USB Device is unattached. //Disable USB physcial layer. IT will auto re-function when USB plug-in devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DEVPHY_SUSPEND = 1; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); #ifndef __KERNEL__ { UINT32 uiApbFreq; T_USB_DCD_COUNTER_REG RegDcdCnt; uiApbFreq = pll_getClockRate(PLL_CLKSEL_APB); RegDcdCnt.reg = USB_GETREG(USB_DCD_COUNTER_REG_OFS); if (uiApbFreq == PLL_CLKSEL_APB_80) { RegDcdCnt.bit.DCD_COUNT = 808080; } else if (uiApbFreq == PLL_CLKSEL_APB_120) { RegDcdCnt.bit.DCD_COUNT = 1212120; } else if (uiApbFreq == PLL_CLKSEL_APB_60) { RegDcdCnt.bit.DCD_COUNT = 606060; }else { RegDcdCnt.bit.DCD_COUNT = 0; } USB_SETREG(USB_DCD_COUNTER_REG_OFS, RegDcdCnt.reg); } #else { T_USB_DCD_COUNTER_REG RegDcdCnt; RegDcdCnt.reg = USB_GETREG(USB_DCD_COUNTER_REG_OFS); RegDcdCnt.bit.DCD_COUNT = 606060; USB_SETREG(USB_DCD_COUNTER_REG_OFS, RegDcdCnt.reg); } #endif //turn off USB clock in real chip to save power! usb_detach(); #ifndef __KERNEL__ //Set VBUS GPIO status as level trigger. //we don't open GPIO here, since we don't require it... gpio_setIntTypePol(GPIO_INT_USBPLUGIN, GPIO_INTTYPE_LEVEL, GPIO_INTPOL_POSHIGH); #endif #if _USB2DEV_TODO_ clk_set_callback(CLK_CALLBACK_USB_PWRDN, usb_powerdown_callback); #endif //DBG_DUMP("exit\r\n"); } /** USB Change state Calling this function to get the current plug status. Application should remember the plug/unplug state to avoid calling open/close function multiple! @return - @b FALSE: Unplug State. - @b TRUE: Plug State. */ BOOL usb2dev_state_change(void) { if (!gUSBOpen) { if (gpio_getIntStatus(GPIO_INT_USBPLUGIN)) // VBUSI GPIO is HIGH { BOOL bContatct = TRUE; if (bStandardCharger) { // If standard charger, also check DCD T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_DEVDMACTRL1_REG devDMACtl1_bak; usb_attach(); devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; // bit[31] USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); bContatct = usb_chkDataContact(); USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1_bak.reg); usb_detach(); } if (bContatct) { USBPhyDisable = 0; usb2dev_set_vbusi(TRUE); return TRUE; } } //USB CLK is disable, and GPIO status is off, so USB is in unplug state. gChargerSts = USB_CHARGER_STS_NONE; USBPhyDisable = 0xFFFFFFFF; usb2dev_set_vbusi(FALSE); return FALSE; } else { if (gpio_getIntStatus(GPIO_INT_USBPLUGIN)) // VBUSI GPIO is HIGH { USBPhyDisable = 0; usb2dev_set_vbusi(TRUE); return TRUE; } else { gChargerSts = USB_CHARGER_STS_NONE; USBPhyDisable = 0xFFFFFFFF; usb2dev_set_vbusi(FALSE); return FALSE; } } } void usb2dev_reset_cfg(void) { usb_FIFO_EPxCfg(); } /** Close USB device driver access. This function will stop USB DMA, terminate control and setup task, disable interrupt and USB clock etc... @return - @b E_OK: open success - @b E_OACV: USB driver is not opened - @b E_ID: Outside semaphore ID number range - @b E_NOEXS: Semaphore does not yet exist - @b E_QOVR: Semaphore's counter error, maximum counter < counter */ ER usb2dev_close(void) { ER erReturn; FLGPTN uiFlag; T_USB_PHYTSTSELECT_REG devPhyTest; T_USB_DEVMAINCTRL_REG devMainCtl; T_USB_DEVDMACTRL1_REG devDMACtl1; if (!gUSBOpen) { DBG_ERR("driver not opened\r\n"); return E_OACV; } #ifndef __KERNEL__ free_irq(INT_ID_USB, 0); #endif // Abort All ongoing DMA Channels usb_abortDMA(USB_EP_NOT_USE, USB_DMACH_ALL); vos_flag_wait_interruptible(&uiFlag, FLG_ID_USBTSK, FLGUSB_SETUPTSK_IDLE, TWF_ORW); set_flg(FLG_ID_USBTSK, FLGUSB_SETUPTSK_STOP); vos_flag_wait_interruptible(&uiFlag, FLG_ID_USBTSK, FLGUSB_CTLTSK_IDLE, TWF_ORW); set_flg(FLG_ID_USBTSK, FLGUSB_CTLTSK_STOP); if ((gUsbChargingCB != NULL) && (gChargerSts == USB_CHARGER_STS_NONE)) { gUsbChargingCB(USB_CHARGE_EVENT_DISCONNECT); } // 1. WE CAN NOT READ USB_DetectVBUS() since USB CLK could be turn off in real case!! // 2. If you want to use USB_DetectVBUS(), you should check USB CLK is on! if (gpio_getIntStatus(GPIO_INT_USBPLUGIN) == 0) { // If USB cable is unplug from host //Reason: To avoid access USB Register when device enter suspend mode. if (usb2dev_get_controller_state() == USB_CONTROLLER_STATE_SUSPEND) { //This case is USB device enter suspend mode... //Notice: Device will not Reenumeration during this state.... erReturn = usb_unlock(); if (erReturn != E_OK) { return erReturn; } return E_OK; } if (gUSBManage.fp_event_callback) { gUSBManage.fp_event_callback(USB_EVENT_DISCONNECT); } //Clear this flag will be done in AP open if AP want to reconnect USB! devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS); devPhyTest.bit.UNPLUG = 1; // bit[0] USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); // soft reset devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.SFRST = 1; // bit[4] USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // soft reset clear devMainCtl.bit.SFRST = 0; // bit[4] USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); } else { #ifdef __KERNEL__ if (usb2dev_get_controller_state() == USB_CONTROLLER_STATE_SUSPEND) { unsigned long flags; loc_cpu(flags); iowrite32( (ioread32((void *)(0xFD020084)) & ~(0x1<<19)), (void *)(0xFD020084)); iowrite32( (ioread32((void *)(0xFD020084)) | (0x1<<19)), (void *)(0xFD020084)); unl_cpu(flags); usb2dev_power_on_init(bUsbHighSpeed); } #endif // USB cable connect with host // Even usb cable is removed, we should remove DP pull-up. // Else PC will consider device is still connected devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS); devPhyTest.bit.UNPLUG = 1; USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); //Disable Physical if device is unplug. //It will be failed if device in connect mode... devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DEVPHY_SUSPEND = 1; // bit[31] USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); usb_detach(); //Reason: To avoid access USB Register when device enter suspend mode. usb_setControllerState(USB_CONTROLLER_STATE_NONE); } gfpVendorReqHdl = NULL; gUsbSetInterfaceHdl = NULL; erReturn = usb_unlock(); if (erReturn != E_OK) { return erReturn; } return E_OK; } /** Set VBUSI state Force VBUSI state for USB controller This API should be invoked when upper layer want to force USB connect without usb2dev_state_change() @param[in] bPlug state of current VBUSI - @b TRUE: VBUSI is HIGH - @b FALSE: VBUSI is LOW @return void */ void usb2dev_set_vbusi(BOOL bPlug) { T_USB_PHYTOP_REG RegTop; unsigned long flags; loc_cpu(flags); RegTop.reg = USB_GETREG(USB_PHYTOP_REG_OFS); RegTop.bit.USB_VBUSI = bPlug; USB_SETREG(USB_PHYTOP_REG_OFS, RegTop.reg); unl_cpu(flags); } /** Set the callback function when wakeup from standby mode User can use this API to register call back when system is waked up from power down/standby mode. The installed call back will be invoked if system is waked up by USB (resume/reset). @param[in] fpIsr User defined ISR for wakeup interrupt @return void */ void usb2dev_set_standby_wakeup(DRV_CB fpIsr) { #ifndef __KERNEL__ //clear GPIO_INT_USBWAKEUP status first gpio_clearIntStatus(GPIO_INT_USBWAKEUP); gpio_enableInt(GPIO_INT_USBWAKEUP); gpio_setIntIsr(GPIO_INT_USBWAKEUP, fpIsr); #endif } /** get USB controller state. @return USB controller state - @b USB_CONTROLLER_STATE_NONE: USB is not used - @b USB_CONTROLLER_STATE_RESET: USB is in reset state - @b USB_CONTROLLER_STATE_SUSPEND: USB is in suspend state */ USB_CONTROLLER_STATE usb2dev_get_controller_state(void) { return USBControllerState; } /** Check set configuration result This API is provided to upper layer to check if USB is under set configuration state. @return - @b TRUE: under set configuration - @b FALSE: not under set configuration */ BOOL usb2dev_check_configured(void) { T_USB_DEVADDR_REG devAddr; devAddr.reg = USB_GETREG(USB_DEVADDR_REG_OFS); return devAddr.bit.AFT_CONF; } /** Set USB controller configuration @param[in] configID configuration identifier @param[in] configContext configuration context for configID @return - @b E_OK: set configuration success - @b E_NOSPT: configID is not supported */ ER usb2dev_set_config(USB_CONFIG_ID configID, UINT32 configContext) { ER erReturn = E_OK; switch (configID) { case USB_CONFIG_ID_STANDARD_CHARGER: { bStandardCharger = configContext; } break; case USB_CONFIG_ID_USE_SHARE_FIFO: { gUsbUseShareFIFO = configContext > 0; } break; case USB_CONFIG_ID_SUSPEND_DRAMOFF: { usb_suspend_to_dramoff_en = configContext > 0; } break; // // emulation use only. // #if _EMULATION_ case USB_CONFIG_ID_FIFO_START_OFS: { gTestFifoOffset = configContext; } break; #else case USB_CONFIG_ID_FIFO_START_OFS: { DBG_WRN("Reserved function. %d\r\n", configID); } break; #endif case USB_CONFIG_ID_INTEN: { unsigned long flags; loc_cpu(flags); if(configContext > 0) USB_SETREG(USB_DEVINTGROUPMASK_REG_OFS, 0x0); else USB_SETREG(USB_DEVINTGROUPMASK_REG_OFS, 0x7); unl_cpu(flags); } break; default: { erReturn = E_NOSPT; DBG_WRN("ID No Suprted (%d)\r\n", configID); } break; } return erReturn; } /** Get USB controller configuration @param[in] configID configuration identifier @return configuration context for configID */ UINT32 usb2dev_get_config(USB_CONFIG_ID configID) { switch (configID) { case USB_CONFIG_ID_STANDARD_CHARGER: { return bStandardCharger; } case USB_CONFIG_ID_SQUELCH_LEVEL: { T_USB_PHYCTRL05_REG phySquelch; phySquelch.reg = USBPHY_GETREG(USB_PHYCTRL05_REG_OFS); return phySquelch.bit.SQ_SEL; } break; case USB_CONFIG_ID_HS_SWING: { T_USB_PHYCTRL06_REG phySwingReg; phySwingReg.reg = USBPHY_GETREG(USB_PHYCTRL06_REG_OFS); return phySwingReg.bit.SWCTRL; } break; case USB_CONFIG_ID_REF_CURRENT: { T_USB_PHYCTRL3A_REG phyRefAdjReg; phyRefAdjReg.reg = USBPHY_GETREG(USB_PHYCTRL3A_REG_OFS); return phyRefAdjReg.bit.IREFSEL; } break; case USB_CONFIG_ID_USE_SHARE_FIFO: { return gUsbUseShareFIFO; } break; case USB_CONFIG_ID_CHECK_CXOUT: { T_USB_DEVINTGROUP0_REG devintgrp0; devintgrp0.reg = USB_GETREG(USB_DEVINTGROUP0_REG_OFS); return devintgrp0.bit.CX_OUT_INT; } break; default: { return 0; } } } /** Set usb call back routine This function provides a facility for upper layer to install callback routine. @param[in] callBackID callback routine identifier @param[in] pCallBack callback routine to be installed @return - @b E_OK: install callback success - @b E_NOSPT: callBackID is not valid */ ER usb2dev_set_callback(USB_CALLBACK callBackID, USB_GENERIC_CB pCallBack) { switch (callBackID) { case USB_CALLBACK_CHARGING_EVENT: { gUsbChargingCB = pCallBack; } break; case USB_CALLBACK_CX_VENDOR_REQUEST: { gfpVendorReqHdl = pCallBack; } break; case USB_CALLBACK_CX_CLASS_REQUEST: { gfpClassRequest = (FP)pCallBack; } break; case USB_CALLBACK_SET_INTERFACE: { gUsbSetInterfaceHdl = pCallBack; } break; case USB_CALLBACK_STD_UNKNOWN_REQ: gfpStdUnknownReq = pCallBack; break; default: { return E_NOSPT; } } return E_OK; } /** Get the current setting of USB speed mode. @return - @b TRUE: device is in High speed - @b FALSE: device is in full speed */ BOOL usb2dev_is_highspeed_enabled(void) { T_USB_DEVMAINCTRL_REG devMainCtl; devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); return (BOOL)(devMainCtl.bit.HS_EN); } /** Initialize USB Management Infomation Table Data Structure Initialize USB Management Infomation Table Data Structure. User can allocate local parameter of USB_MNG and apply usb_initManagement to it. And then start configure the management table. @param[in] pMng USB Management Infomation Table pointer @return void */ void usb2dev_init_management(USB_MNG *pMng) { if (pMng) { memset(pMng, 0x00, sizeof(USB_MNG)); pMng->magic_no = USB_MNG_MAGICNO; } } /** Apply USB Management Infomation Table Apply USB Management Infomation Table to USB Driver. @param[in] pMng USB Management Infomation Table pointer @return - @b E_OK: Apply management info success. - @b E_PAR: Input parameter is NULL pointer. - @b E_CTX: No Init. Please apply usb_initManagement() to pMng first. */ ER usb2dev_set_management(USB_MNG *pMng) { if (!pMng) { DBG_ERR("NULL PTR!\r\n"); return E_PAR; } if (pMng->magic_no != USB_MNG_MAGICNO) { DBG_ERR("UN-INIT!\r\n"); return E_CTX; } memcpy(&gUSBManage, pMng, sizeof(USB_MNG)); return E_OK; } /** Get Current USB Management Infomation Table Get Current USB Management Infomation Table to USB Driver. @param[out] pMng USB Management Infomation Table pointer @return - @b E_OK: Apply management info success. - @b E_PAR: Input parameter is NULL pointer. - @b E_CTX: No Init. Please apply usb_initManagement() to pMng first. */ ER usb2dev_get_management(USB_MNG *pMng) { if (!pMng) { DBG_ERR("NULL PTR!\r\n"); return E_PAR; } memcpy(pMng, &gUSBManage, sizeof(USB_MNG)); return E_OK; } #endif #if (_EMULATION_ == ENABLE) /* Open USB reset debounce test (Engineer usage API) @param[in] uiDebounce reset debounce interval (unit: ms) @return - @b E_OK: open success - @b Else: fail */ ER usb_openDebounceTest(UINT32 uiDebounce) { T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_DEVDMACTRL1_REG devDMACtl1_bak; T_USB_OTGCTRLSTATUS_REG otgCtrlSts; T_USB_DEVMAINCTRL_REG devMainCtl; T_USB_PHYTSTSELECT_REG devPhyTest; T_USB_DEVADDR_REG devaddr; //if (gUSBOpen) //{ // DBG_ERR("driver already opened\r\n"); // return E_OACV; //} //erReturn = usb_lock(); //if (erReturn != E_OK) //{ // return erReturn; //} //Reason: To avoid re-enter USB device after "Safety Removed" state //If we don't anything, we can NOT access USB registers in suspend mode. if (usb2dev_get_controller_state() == USB_CONTROLLER_STATE_SUSPEND) { //Hardware reset USB register.... try to leave suspend mode. #if _USE_USB_CH2_ pll_enableSystemReset(USB2_RSTN); pll_disableSystemReset(USB2_RSTN); #else pll_enableSystemReset(USB_RSTN); pll_disableSystemReset(USB_RSTN); #endif usb_setControllerState(USB_CONTROLLER_STATE_NONE); } usb_attach(); otgCtrlSts.reg = USB_GETREG(USB_OTGCTRLSTATUS_REG_OFS); otgCtrlSts.bit.Vbus_FLT_SEL = 1; // decrease VBUS debounce time from 540ms to 200ms USB_SETREG(USB_OTGCTRLSTATUS_REG_OFS, otgCtrlSts.reg); //turn on the usb physical layer. devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; // bit[31] USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); if (devDMACtl1_bak.bit.DEVPHY_SUSPEND == 1) { // wait VBUS debounce time passed USB_DELAY_US_POLL(200); } // chip enable devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.CHIP_EN = 1; // bit[5] #ifdef _FPGA_EMULATION_ #if (_FPGA_EMULATION_ == 1) devMainCtl.bit.HALF_SPEED = 1; #endif #endif // Write tested debounce interval devaddr.reg = USB_GETREG(USB_DEVADDR_REG_OFS); devaddr.bit.RST_DEBOUNCE_INVL = uiDebounce; USB_SETREG(USB_DEVADDR_REG_OFS, devaddr.reg); // soft reset devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.SFRST = 1; // bit[4] USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // soft reset clear devMainCtl.bit.SFRST = 0; // bit[4] USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); #if 0//USB2_TEST drv_disableInt(DRV_INT_USB2); #else //drv_disableInt(DRV_INT_USB); #endif devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS); devPhyTest.bit.UNPLUG = 0; // bit[0] USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); return E_OK; } /* Read USB interupt status group2 (Engineer usage API) For test f/w to get interrupt status of reset flag @return interrupt status */ UINT32 usb_readIntGrp2(void) { return USB_GETREG(USB_DEVINTGROUP2_REG_OFS); } /* Read line status (Engineer usage API) For test f/w to get line status @return line status */ UINT32 usb_getLineStatus(void) { T_USB_HCPORTSTACTRL_REG portStatusReg; portStatusReg.reg = USB_GETREG(USB_HCPORTSTACTRL_REG_OFS); return portStatusReg.bit.LINE_STS; } /* Test Data Contact Test Data Contact (for h/w verification) @return void */ void usb_testDataContact(void) { T_USB_DEVDMACTRL1_REG devDMACtl1; //T_USB_DEVDMACTRL1_REG devDMACtl1_bak; usb_attach(); devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); //devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; // bit[31] USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); usb2dev_set_vbusi(TRUE); if (usb_chkDataContact()) { DBG_DUMP("\r\nUSB data contact detected\r\n"); } else { DBG_DUMP("\r\nUSB data contact NOT detected\r\n"); } usb2dev_set_vbusi(FALSE); usb_detach(); } /* Test charging port Test charging port (for h/w verification) @return void */ void usb_testChargingPort(void) { #if 0 T_USB_CHARGER_CONTROL_REG chargerCtrlReg; T_USB_BUS_STATUS_REG busStsReg; T_USB_DEVDMACTRL1_REG devDMACtl1; //T_USB_DEVDMACTRL1_REG devDMACtl1_bak; usb_attach(); devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); //devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; // bit[31] USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); DBG_ERR("Vdat_ref: Detect Range (0.25 - 0.4)V to (0.8 ~ 2.0)V \r"); DBG_ERR("Press 'q' to exit...\r\n"); chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); chargerCtrlReg.bit.CHG_DETECT_EN = 1; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); while (1) { CHAR input; busStsReg.reg = USB_GETREG(USB_BUS_STATUS_REG_OFS); if (busStsReg.bit.CHG_DET == 0) { DBG_ERR("Vdat_ref: outside range\r"); } else { DBG_ERR("Vdat_ref: inside range\r"); } uart_chkChar(&input); if (input == 'q') { break; } USB_DELAY_MS(50); } chargerCtrlReg.bit.CHG_DETECT_EN = 0; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); usb_detach(); #endif } /* Test charging port secondary Test charging port secondary (for h/w verification) @return void */ void usb_testChargingPortSecondary(void) { #if 0 T_USB_CHARGER_CONTROL_REG chargerCtrlReg; T_USB_BUS_STATUS_REG busStsReg; T_USB_DEVDMACTRL1_REG devDMACtl1; //T_USB_DEVDMACTRL1_REG devDMACtl1_bak; usb_attach(); devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); //devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; // bit[31] USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); DBG_ERR("Vdat_ref: Detect Range (0.25 - 0.4)V to (0.8 ~ 2.0)V \r"); DBG_ERR("Press 'q' to exit...\r\n"); chargerCtrlReg.reg = USB_GETREG(USB_CHARGER_CONTROL_REG_OFS); chargerCtrlReg.bit.SECOND_CHG_DETECT_EN = 1; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); while (1) { CHAR input; busStsReg.reg = USB_GETREG(USB_BUS_STATUS_REG_OFS); if (busStsReg.bit.CHG_DET == 0) { DBG_ERR("Vdat_ref: outside range\r"); } else { DBG_ERR("Vdat_ref: inside range\r"); } uart_chkChar(&input); if (input == 'q') { break; } USB_DELAY_MS(50); } chargerCtrlReg.bit.SECOND_CHG_DETECT_EN = 0; USB_SETREG(USB_CHARGER_CONTROL_REG_OFS, chargerCtrlReg.reg); usb_detach(); #endif } #endif /* */ void usb_setID(BOOL bDevice) { T_USB_PHYTOP_REG RegTop; unsigned long flags; loc_cpu(flags); RegTop.reg = USB_GETREG(USB_PHYTOP_REG_OFS); RegTop.bit.USB_ID = bDevice; USB_SETREG(USB_PHYTOP_REG_OFS, RegTop.reg); unl_cpu(flags); } /* Write USB PHY register @param[in] uiOffset register address @param[in] uiValue register value @return - @b E_OK: success */ ER usb_writePhyReg(UINT32 uiOffset, UINT32 uiValue) { #ifdef _FPGA_EMULATION_ #if (_FPGA_EMULATION_ == 1) I2C_DATA I2cData; I2C_BYTE I2cByte[4]; I2C_STS I2cSts; UINT32 ADDR = 0xC0; i2c_lock(gUsbI2cSes); I2cData.pByte = I2cByte; I2cData.ByteCount = I2C_BYTE_CNT_3; I2cByte[0].uiValue = ADDR; I2cByte[0].Param = I2C_BYTE_PARAM_START; I2cByte[1].uiValue = uiOffset; I2cByte[1].Param = I2C_BYTE_PARAM_NONE; I2cByte[2].uiValue = uiValue; I2cByte[2].Param = I2C_BYTE_PARAM_STOP; I2cSts = i2c_transmit(&I2cData); if ((I2cSts != I2C_STS_OK) && (I2cSts != I2C_STS_STOP)) { DBG_ERR("Tx Err. %d\r\n", I2cSts); } i2c_unlock(gUsbI2cSes); #else // Real board USBPHY_SETREG(USB_PHY_BASE_OFS + uiOffset * 4, uiValue); // [510 bug patch]: Add dummy read after write //USB_GETREG(USB_PHY_BASE_OFS + uiOffset * 4); #endif #endif return E_OK; } /* Read USB PHY register @param[in] uiOffset register address @param[out] puiValue register value @return - @b E_OK: success */ ER usb_readPhyReg(UINT32 uiOffset, UINT32 *puiValue) { #ifdef _FPGA_EMULATION_ #if (_FPGA_EMULATION_ == 1) I2C_DATA I2cData; I2C_BYTE I2cByte[4]; I2C_STS I2cSts; UINT32 ADDR = 0xC0; i2c_lock(gUsbI2cSes); I2cData.pByte = I2cByte; I2cData.ByteCount = I2C_BYTE_CNT_3; I2cByte[0].uiValue = ADDR; I2cByte[0].Param = I2C_BYTE_PARAM_START; I2cByte[1].uiValue = uiOffset; I2cByte[1].Param = I2C_BYTE_PARAM_NONE; I2cByte[2].uiValue = ADDR | 0x1; I2cByte[2].Param = I2C_BYTE_PARAM_START; I2cSts = i2c_transmit(&I2cData); if (I2cSts != I2C_STS_OK) { DBG_ERR("Tx Err1. %d\r\n", I2cSts); } I2cData.ByteCount = I2C_BYTE_CNT_1; I2cByte[0].Param = I2C_BYTE_PARAM_NACK | I2C_BYTE_PARAM_STOP; I2cSts = i2c_receive(&I2cData); if ((I2cSts != I2C_STS_OK) && (I2cSts != I2C_STS_STOP)) { DBG_ERR("RX Err. %d\r\n", I2cSts); } i2c_unlock(gUsbI2cSes); *puiValue = I2cByte[0].uiValue; #else // Real board *puiValue = USBPHY_GETREG(USB_PHY_BASE_OFS + uiOffset * 4); #endif #endif return E_OK; } //@} //@}