nt9856x/code/hdal/drivers/k_driver/source/comm/usb2dev/usb2dev.c
2023-03-28 15:07:53 +08:00

2019 lines
49 KiB
C
Executable File

/*
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 <stdio.h>
#include <string.h>
#include "interrupt.h"
#include "pll.h"
#include "pll_protected.h"
#include "efuse_protected.h"
#else
#include <plat/efuse_protected.h>
#include <linux/gpio.h>
#include <plat/nvt-gpio.h>
#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;i<len;i++) {
if(!(i&0xF))
DBG_DUMP("\r\n");
if(i == mark) {
mark += pDesc[i];
DBG_DUMP("^C0x%02X ",pDesc[i]);
} else {
DBG_DUMP("0x%02X ",pDesc[i]);
}
}
DBG_DUMP("\r\n");
}
}
BOOL usb_debugDump(CHAR *strCmd);
BOOL usb_debugDump(CHAR *strCmd)
{
T_USB_TOP_REG RegTop;
T_USB_PHYTSTSELECT_REG devPhyTest;
T_USB_DEVMAXPS_EP_REG EpMaxps;
UINT32 i;
RegTop.reg = USB_GETREG(USB_TOP_REG_OFS);
devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS);
DBG_DUMP("Device Roll as ");
if(RegTop.bit.ID) {
DBG_DUMP("DEVICE.(%s) in %s\r\n",devPhyTest.bit.UNPLUG?"DISABLE":"ENABLE",usb2dev_is_highspeed_enabled()?"HS":"FS");
for (i = 1; i < 16; i++) {
EpMaxps.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS+((i-1)<<2));
DBG_DUMP("EP%02d-%s(%s) FIFO-Blk-No=%d Ofs=%d\r\n",i,(gUSBManage.ep_config_hs[i-1].Direction == EP_DIR_OUT)?"OUT":"IN "
,gUSBManage.ep_config_hs[i-1].enable?"ENABLE ":"DISABLE"
,((gUSBManage.ep_config_hs[i-1].blk_size>512)+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;
}
//@}
//@}