static __u32 USBC_Phy_TpWrite(__u32 usbc_no, __u32 addr, __u32 data, __u32 len) { __u32 temp = 0, dtmp = 0; __u32 j=0; dtmp = data; for(j = 0; j < len; j++) { /* set the bit address to be write */ temp = USBC_Readl(USBC_Phy_GetCsr(usbc_no)); temp &= ~(0xff << 8); temp |= ((addr + j) << 8); USBC_Writel(temp, USBC_Phy_GetCsr(usbc_no)); temp = USBC_Readb(USBC_Phy_GetCsr(usbc_no)); temp &= ~(0x1 << 7); temp |= (dtmp & 0x1) << 7; temp &= ~(0x1 << (usbc_no << 1)); USBC_Writeb(temp, USBC_Phy_GetCsr(usbc_no)); temp = USBC_Readb(USBC_Phy_GetCsr(usbc_no)); temp |= (0x1 << (usbc_no << 1)); USBC_Writeb( temp, USBC_Phy_GetCsr(usbc_no)); temp = USBC_Readb(USBC_Phy_GetCsr(usbc_no)); temp &= ~(0x1 << (usbc_no <<1 )); USBC_Writeb(temp, USBC_Phy_GetCsr(usbc_no)); dtmp >>= 1; } return data; }
/* ******************************************************************************* * sw_hcd_port_suspend * * Description: * suspend USB port * * Parameters: * sw_hcd : input. USB¿ØÖÆÆ÷ * do_suspend : input. flag. is suspend USB port or not? * * Return value: * void * * note: * void * ******************************************************************************* */ static void sw_hcd_port_suspend(struct sw_hcd *sw_hcd, bool do_suspend) { u8 power = 0; void __iomem *usbc_base = sw_hcd->mregs; if (!is_host_active(sw_hcd)){ DMSG_PANIC("ERR: usb host is not active\n"); return; } /* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and * sw_hcd_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect * SE0 changing to connect (J) or wakeup (K) states. */ power = USBC_Readb(USBC_REG_PCTL(usbc_base)); if (do_suspend) { int retries = 10000; DMSG_INFO("[sw_hcd]: suspend port.\n"); power &= ~(1 << USBC_BP_POWER_H_RESUME); power |= (1 << USBC_BP_POWER_H_SUSPEND); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); /* Needed for OPT A tests */ power = USBC_Readb(USBC_REG_PCTL(usbc_base)); while (power & (1 << USBC_BP_POWER_H_SUSPEND)) { power = USBC_Readb(USBC_REG_PCTL(usbc_base)); if (retries-- < 1) break; } DMSG_DBG_HCD("DBG: Root port suspended, power %02x\n", power); sw_hcd->port1_status |= USB_PORT_STAT_SUSPEND; }else if (power & (1 << USBC_BP_POWER_H_SUSPEND)){ DMSG_INFO("[sw_hcd]: suspend portend, resume port.\n"); power &= ~(1 << USBC_BP_POWER_H_SUSPEND); power |= (1 << USBC_BP_POWER_H_RESUME); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); DMSG_DBG_HCD("DBG: Root port resuming, power %02x\n", power); /* later, GetPortStatus will stop RESUME signaling */ sw_hcd->port1_status |= SW_HCD_PORT_STAT_RESUME; sw_hcd->rh_timer = jiffies + msecs_to_jiffies(20); }else{ DMSG_PANIC("WRN: sw_hcd_port_suspend nothing to do\n"); } return ; }
static void __USBC_Host_ep0_ConfigEp_Default(__u32 usbc_base_addr) { //--<1>--config ep0 csr USBC_Writew(1<<USBC_BP_CSR0_H_FlushFIFO, USBC_REG_CSR0(usbc_base_addr)); //--<2>--config polling interval USBC_Writeb(0x00, USBC_REG_TXINTERVAL(usbc_base_addr)); /* config ep transfer type */ USBC_Writeb(0x00, USBC_REG_EP0TYPE(usbc_base_addr)); }
static void __USBC_Host_Tx_ClearEpDma(__u32 usbc_base_addr) { __u16 ep_csr = 0; //auto_set, dma_tx_en, mode1 ep_csr = USBC_Readb(USBC_REG_TXCSR(usbc_base_addr) + 1); ep_csr &= ~((1 << USBC_BP_TXCSR_H_AUTOSET) >> 8); ep_csr &= ~((1 << USBC_BP_TXCSR_H_DMA_REQ_EN) >> 8); USBC_Writeb(ep_csr, (USBC_REG_TXCSR(usbc_base_addr) + 1)); //DMA_REQ_EN和DMA_REQ_MODE不能在同一个cycle中清除 ep_csr = USBC_Readb(USBC_REG_TXCSR(usbc_base_addr) + 1); ep_csr &= ~((1 << USBC_BP_TXCSR_H_DMA_REQ_MODE) >> 8); USBC_Writeb(ep_csr, (USBC_REG_TXCSR(usbc_base_addr) + 1)); }
static void __USBC_Host_Rx_ConfigEp(__u32 usbc_base_addr, __u32 ep_index, __u32 ts_mode, __u32 ts_type, __u32 is_double_fifo, __u32 ep_MaxPkt, __u32 interval) { __u16 reg_val = 0; __u16 temp = 0; //--<1>--config rx_csr USBC_Writew((1 << USBC_BP_RXCSR_H_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_H_FLUSH_FIFO), USBC_REG_RXCSR(usbc_base_addr)); if(is_double_fifo){ USBC_Writew((1 << USBC_BP_RXCSR_H_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_H_FLUSH_FIFO), USBC_REG_RXCSR(usbc_base_addr)); } //--<2>--config tx ep max packet reg_val = USBC_Readw(USBC_REG_RXMAXP(usbc_base_addr)); temp = ep_MaxPkt & ((1 << USBC_BP_RXMAXP_PACKET_COUNT) - 1); reg_val |= temp; USBC_Writew(reg_val, USBC_REG_RXMAXP(usbc_base_addr)); //--<3>--config ep transfer type __USBC_Host_Rx_EpType(usbc_base_addr, ep_index, ts_mode, ts_type); //--<4>--config polling interval USBC_Writeb(interval, USBC_REG_RXINTERVAL(usbc_base_addr)); }
static void __USBC_Host_Tx_ConfigEp_Default(__u32 usbc_base_addr) { //--<1>--config tx_csr, flush fifo, clear all to 0 USBC_Writew((1 << USBC_BP_TXCSR_H_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_H_FLUSH_FIFO), USBC_REG_TXCSR(usbc_base_addr)); USBC_Writew(0x00, USBC_REG_TXCSR(usbc_base_addr)); //--<2>--config tx ep max packet USBC_Writew(0x00, USBC_REG_TXMAXP(usbc_base_addr)); //--<3>--config ep transfer type USBC_Writeb(0x00, USBC_REG_TXTYPE(usbc_base_addr)); //--<4>--config polling interval USBC_Writeb(0x00, USBC_REG_TXINTERVAL(usbc_base_addr)); }
static __u32 usb_phy0_write(__u32 addr, __u32 data, __u32 dmask, __u32 usbc_base_addr) { __u32 i=0; data = data & 0x0f; addr = addr & 0x0f; dmask = dmask & 0x0f; USBC_Writeb((dmask<<4)|data, usbc_base_addr + 0x404 + 2); USBC_Writeb(addr|0x10, usbc_base_addr + 0x404); for(i=0;i<5;i++); USBC_Writeb(addr|0x30, usbc_base_addr + 0x404); for(i=0;i<5;i++); USBC_Writeb(addr|0x10, usbc_base_addr + 0x404); for(i=0;i<5;i++); return (USBC_Readb(usbc_base_addr + 0x404 + 3) & 0x0f); }
static void __USBC_Host_Rx_ConfigEp_Default(__u32 usbc_base_addr) { //--<1>--config rx_csr, 先刷fifo, 有全部清零 USBC_Writew((1 << USBC_BP_RXCSR_H_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_H_FLUSH_FIFO), USBC_REG_RXCSR(usbc_base_addr)); USBC_Writew(0x00, USBC_REG_RXCSR(usbc_base_addr)); //--<2>--config rx ep max packet USBC_Writew(0x00, USBC_REG_RXMAXP(usbc_base_addr)); //--<3>--config ep transfer type USBC_Writeb(0x00, USBC_REG_RXTYPE(usbc_base_addr)); //--<4>--config polling interval USBC_Writeb(0x00, USBC_REG_RXINTERVAL(usbc_base_addr)); }
/* *********************************************************************************** * USBC_Dev_SetAddress_default * * Description: * 清除host给device分配的地址 * * Arguments: * hUSB : input. USBC_open_otg获得的句柄, 记录了USBC所需要的一些关键数据 * * Returns: * * * note: * 无 * *********************************************************************************** */ void USBC_Dev_SetAddress_default(__hdle hUSB) { __usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB; if(usbc_otg == NULL){ return; } USBC_Writeb(0x00, USBC_REG_FADDR(usbc_otg->base_addr)); }
/* *********************************************************************************** * USBC_Dev_SetAddress * * Description: * 设置地址 * * Arguments: * hUSB : input. USBC_open_otg获得的句柄, 记录了USBC所需要的一些关键数据 * address : input. host分配的地址 * * Returns: * * * note: * 无 * *********************************************************************************** */ void USBC_Dev_SetAddress(__hdle hUSB, __u8 address) { __usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB; if(usbc_otg == NULL){ return; } USBC_Writeb(address, USBC_REG_FADDR(usbc_otg->base_addr)); }
static void __USBC_Host_ep0_ConfigEp(__u32 usbc_base_addr, __u32 ts_mode, __u32 interval) { //--<1>--config ep0 csr USBC_Writew(1<<USBC_BP_CSR0_H_FlushFIFO, USBC_REG_CSR0(usbc_base_addr)); //--<2>--config polling interval USBC_Writeb(interval, USBC_REG_NAKLIMIT0(usbc_base_addr)); /* config ep0 transfer type */ __USBC_Host_ep0_EpType(usbc_base_addr, ts_mode); }
static void __USBC_Dev_Rx_ClearEpDma(ulong usbc_base_addr) { __u16 ep_csr = 0; //auto_clear, dma_rx_en, mode0 ep_csr = USBC_Readb(USBC_REG_RXCSR(usbc_base_addr) + 1); ep_csr &= ~((1 << USBC_BP_RXCSR_D_AUTO_CLEAR) >> 8); ep_csr &= ~((1 << USBC_BP_RXCSR_D_DMA_REQ_MODE) >> 8); ep_csr &= ~((1 << USBC_BP_RXCSR_D_DMA_REQ_EN) >> 8); USBC_Writeb(ep_csr, (USBC_REG_RXCSR(usbc_base_addr) + 1)); }
void USBC_Host_SetHPortAddress(__hdle hUSB, __u32 ep_type, __u32 ep_index, __u8 address) { __usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB; if(usbc_otg == NULL){ return; } switch(ep_type){ case USBC_EP_TYPE_TX: USBC_Writeb(address, USBC_REG_TXHPORTx(usbc_otg->base_addr, ep_index)); break; case USBC_EP_TYPE_RX: USBC_Writeb(address, USBC_REG_RXHPORTx(usbc_otg->base_addr, ep_index)); break; default: break; } }
void USBC_Host_SetHubAddress(__hdle hUSB, __u32 ep_type, __u32 ep_index, __u32 is_mutli_tt, __u8 address) { __usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB; if(usbc_otg == NULL){ return; } switch(ep_type){ case USBC_EP_TYPE_TX: USBC_Writeb(((is_mutli_tt << USBC_BP_HADDR_MULTI_TT) | address), USBC_REG_TXHADDRx(usbc_otg->base_addr, ep_index)); break; case USBC_EP_TYPE_RX: USBC_Writeb(((is_mutli_tt << USBC_BP_HADDR_MULTI_TT) | address), USBC_REG_RXHADDRx(usbc_otg->base_addr, ep_index)); break; default: break; } }
void USBC_Host_SetHubAddress_Deafult(__hdle hUSB, __u32 ep_type, __u32 ep_index) { __usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB; if(usbc_otg == NULL){ return; } switch(ep_type){ case USBC_EP_TYPE_TX: USBC_Writeb(0x00, USBC_REG_TXHADDRx(usbc_otg->base_addr, ep_index)); break; case USBC_EP_TYPE_RX: USBC_Writeb(0x00, USBC_REG_RXHADDRx(usbc_otg->base_addr, ep_index)); break; default: break; } }
static void __USBC_Host_Tx_ConfigEpDma(__u32 usbc_base_addr) { __u16 ep_csr = 0; //auto_set, tx_mode, dma_tx_en, mode1 ep_csr = USBC_Readb(USBC_REG_TXCSR(usbc_base_addr) + 1); ep_csr |= (1 << USBC_BP_TXCSR_H_AUTOSET) >> 8; ep_csr |= (1 << USBC_BP_TXCSR_H_MODE) >> 8; ep_csr |= (1 << USBC_BP_TXCSR_H_DMA_REQ_EN) >> 8; ep_csr |= (1 << USBC_BP_TXCSR_H_DMA_REQ_MODE) >> 8; USBC_Writeb(ep_csr, (USBC_REG_TXCSR(usbc_base_addr) + 1)); }
static void __USBC_Host_Rx_ConfigEpDma(__u32 usbc_base_addr) { __u16 ep_csr = 0; //配置dma, auto_clear, dma_rx_en, mode1, ep_csr = USBC_Readb(USBC_REG_RXCSR(usbc_base_addr) + 1); ep_csr |= (1 << USBC_BP_RXCSR_H_AUTO_CLEAR) >> 8; ep_csr |= (1 << USBC_BP_RXCSR_H_AUTO_REQ) >> 8; // ep_csr &= ~((1 << USBC_BP_RXCSR_H_DMA_REQ_MODE) >> 8); ep_csr |= ((1 << USBC_BP_RXCSR_H_DMA_REQ_MODE) >> 8); ep_csr |= (1 << USBC_BP_RXCSR_H_DMA_REQ_EN) >> 8; USBC_Writeb(ep_csr, (USBC_REG_RXCSR(usbc_base_addr) + 1)); }
/* *************************************************************************** * * read out one bit of USB PHY register * *************************************************************************** */ static __u32 __USBC_PHY_REG_READ(__u32 usbc_base_addr, __u32 usbc_phy_reg_addr) { __u32 reg_val = 0; __u32 i = 0; USBC_Writeb(usbc_phy_reg_addr, USBC_REG_PHYCTL(USBC0_REGS_BASE) + 1); for(i=0; i<0x4; i++); reg_val = USBC_Readb(USBC_REG_PHYCTL(USBC0_REGS_BASE) + 2); if(usbc_base_addr == USBC0_REGS_BASE) return (reg_val & 0x1); else return ((reg_val >> 1) & 0x1); }
static void __USBC_Host_Rx_EpType(__u32 usbc_base_addr, __u32 ep_index, __u32 ts_mode, __u32 ts_type) { __u32 reg_val = 0; /* config transfer speed */ switch(ts_mode){ case USBC_TS_MODE_HS: reg_val |= 0x01 << USBC_BP_RXTYPE_SPEED; break; case USBC_TS_MODE_FS: reg_val |= 0x02 << USBC_BP_RXTYPE_SPEED; break; case USBC_TS_MODE_LS: reg_val |= 0x03 << USBC_BP_RXTYPE_SPEED; break; default: reg_val = 0; } //--<1>--config protocol switch(ts_type){ case USBC_TS_TYPE_ISO: reg_val |= 0x1 << USBC_BP_RXTYPE_PROROCOL; break; case USBC_TS_TYPE_BULK: reg_val |= 0x2 << USBC_BP_RXTYPE_PROROCOL; break; case USBC_TS_TYPE_INT: reg_val |= 0x3 << USBC_BP_RXTYPE_PROROCOL; break; default: break; } //--<2>--config target ep number reg_val |= ep_index; USBC_Writeb(reg_val, USBC_REG_RXTYPE(usbc_base_addr)); }
static void __USBC_Host_ep0_EpType(__u32 usbc_base_addr, __u32 ts_mode) { __u32 reg_val = 0; /* config transfer speed */ switch(ts_mode){ case USBC_TS_MODE_HS: reg_val |= 0x01 << USBC_BP_RXTYPE_SPEED; break; case USBC_TS_MODE_FS: reg_val |= 0x02 << USBC_BP_RXTYPE_SPEED; break; case USBC_TS_MODE_LS: reg_val |= 0x03 << USBC_BP_RXTYPE_SPEED; break; default: reg_val = 0; } USBC_Writeb(reg_val, USBC_REG_EP0TYPE(usbc_base_addr)); }
/* *************************************************************************** * * Write one bit of USB PHY register * *************************************************************************** */ static void __USBC_PHY_REG_WRITE(__u32 usbc_base_addr, __u32 usbc_phy_reg_addr, __u32 usbc_phy_reg_data) { __u32 reg_val = 0; USBC_Writeb(usbc_phy_reg_addr, USBC_REG_PHYCTL(USBC0_REGS_BASE) + 1); reg_val = USBC_Readb(USBC_REG_PHYCTL(USBC0_REGS_BASE)); reg_val &= ~(0x1 << 7); reg_val |= (usbc_phy_reg_data & 0x1) << 7; if(usbc_base_addr == USBC0_REGS_BASE){ reg_val &= ~0x1; USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE)); reg_val |= 0x1; USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE)); reg_val &= ~0x1; USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE)); }else{ reg_val &= ~0x2; USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE)); reg_val |= 0x2; USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE)); reg_val &= ~0x2; USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE)); } }
void USBC_Host_SetFunctionAddress(__hdle hUSB, __u32 EpType, __u32 EpIndex, __u32 FunctionAdress, __u32 MultiTT, __u32 HubAddress, __u32 HubPortNumber) { __usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB; __u8 temp_8 = 0; if(usbc_otg == NULL){ return; } if(MultiTT){ temp_8 = 1 << USBC_BP_HADDR_MULTI_TT; } temp_8 |= HubAddress; switch(EpType){ case USBC_EP_TYPE_TX: USBC_Writeb(FunctionAdress, USBC_REG_TXFADDRx(usbc_otg->base_addr, EpIndex)); USBC_Writeb(temp_8, USBC_REG_TXHADDRx(usbc_otg->base_addr, EpIndex)); USBC_Writeb(HubPortNumber, USBC_REG_TXHPORTx(usbc_otg->base_addr, EpIndex)); break; case USBC_EP_TYPE_RX: USBC_Writeb(FunctionAdress, USBC_REG_RXFADDRx(usbc_otg->base_addr, EpIndex)); USBC_Writeb(temp_8, USBC_REG_RXHADDRx(usbc_otg->base_addr, EpIndex)); USBC_Writeb(HubPortNumber, USBC_REG_RXHPORTx(usbc_otg->base_addr, EpIndex)); break; default: break; } }
/* ******************************************************************************* * sw_hcd_port_reset * * Description: * reset USB port * * Parameters: * sw_hcd : input. USB¿ØÖÆÆ÷ * do_reset : input. flag. is reset USB port or not? * * Return value: * void * * note: * void * ******************************************************************************* */ static void sw_hcd_port_reset(struct sw_hcd *sw_hcd, bool do_reset) { u8 power = 0; void __iomem *usbc_base = sw_hcd->mregs; if (!is_host_active(sw_hcd)){ DMSG_PANIC("ERR: usb host is not active\n"); return; } /* NOTE: caller guarantees it will turn off the reset when * the appropriate amount of time has passed */ power = USBC_Readb(USBC_REG_PCTL(usbc_base)); if (do_reset) { DMSG_INFO("[sw_hcd]: reset port. \n"); /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let sw_hcd start * generating SOFs. If we don't do this, OPT HS A 6.8 tests * fail with "Error! Did not receive an SOF before suspend * detected". */ if (power & (1 << USBC_BP_POWER_H_RESUME)) { while (time_before(jiffies, sw_hcd->rh_timer)){ msleep(1); } power &= ~(1 << USBC_BP_POWER_H_RESUME); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); msleep(1); } sw_hcd->ignore_disconnect = true; power &= 0xf0; power |= (1 << USBC_BP_POWER_H_RESET); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); sw_hcd->port1_status |= USB_PORT_STAT_RESET; sw_hcd->port1_status &= ~USB_PORT_STAT_ENABLE; sw_hcd->rh_timer = jiffies + msecs_to_jiffies(50); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_TX, 0); //set address ep0 { __u32 i = 1; __u8 old_ep_index = 0; old_ep_index = USBC_GetActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle); USBC_SelectActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle, 0); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_TX, 0); for( i = 1 ; i <= 5; i++){ USBC_SelectActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle, i); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_TX, i); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_RX, i); } USBC_SelectActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle, old_ep_index); } }else{ DMSG_INFO("[sw_hcd]: reset port stopped.\n"); UsbPhyEndReset(0); power &= ~(1 << USBC_BP_POWER_H_RESET); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); sw_hcd->ignore_disconnect = false; power = USBC_Readb(USBC_REG_PCTL(usbc_base)); if(power & (1 << USBC_BP_POWER_H_HIGH_SPEED_FLAG)){ DMSG_DBG_HCD("high-speed device connected\n"); sw_hcd->port1_status |= USB_PORT_STAT_HIGH_SPEED; } sw_hcd->port1_status &= ~USB_PORT_STAT_RESET; sw_hcd->port1_status |= USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET << 16) | (USB_PORT_STAT_C_ENABLE << 16); usb_hcd_poll_rh_status(sw_hcd_to_hcd(sw_hcd)); sw_hcd->vbuserr_retry = VBUSERR_RETRY_COUNT; } return ; }
/* ******************************************************************************* * sw_hcd_hub_control * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ int sw_hcd_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct sw_hcd *sw_hcd = hcd_to_sw_hcd(hcd); u32 temp = 0; int retval = 0; unsigned long flags = 0; void __iomem *usbc_base = sw_hcd->mregs; if(hcd == NULL){ DMSG_PANIC("ERR: invalid argment\n"); return -ESHUTDOWN; } spin_lock_irqsave(&sw_hcd->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { spin_unlock_irqrestore(&sw_hcd->lock, flags); return -ESHUTDOWN; } DMSG_DBG_HCD("sw_hcd_hub_control: typeReq = %x, wValue = 0x%x, wIndex = 0x%x\n", typeReq, wValue, wIndex); /* hub features: always zero, setting is a NOP * port features: reported, sometimes updated when host is active * no indicators */ switch (typeReq) { case ClearHubFeature: case SetHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: break; default: goto error; } break; case ClearPortFeature: if ((wIndex & 0xff) != 1){ goto error; } switch (wValue) { case USB_PORT_FEAT_ENABLE: break; case USB_PORT_FEAT_SUSPEND: sw_hcd_port_suspend(sw_hcd, false); break; case USB_PORT_FEAT_POWER: /* fixme */ sw_hcd_set_vbus(sw_hcd, 0); break; case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_SUSPEND: break; default: goto error; } DMSG_DBG_HCD("DBG: clear feature %d\n", wValue); sw_hcd->port1_status &= ~(1 << wValue); break; case GetHubDescriptor: { struct usb_hub_descriptor *desc = (void *)buf; desc->bDescLength = 9; desc->bDescriptorType = 0x29; desc->bNbrPorts = 1; desc->wHubCharacteristics = cpu_to_le16( 0x0001 /* per-port power switching */ | 0x0010 /* no overcurrent reporting */ ); desc->bPwrOn2PwrGood = 5; /* msec/2 */ desc->bHubContrCurrent = 0; /* workaround bogus struct definition */ desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */ desc->u.hs.DeviceRemovable[1] = 0xff; } break; case GetHubStatus: temp = 0; *(__le32 *) buf = cpu_to_le32(temp); break; case GetPortStatus: { if (wIndex != 1){ DMSG_PANIC("ERR: GetPortStatus parameter wIndex is not 1.\n"); goto error; } /* finish RESET signaling? */ if ((sw_hcd->port1_status & USB_PORT_STAT_RESET) && time_after_eq(jiffies, sw_hcd->rh_timer)){ sw_hcd_port_reset(sw_hcd, false); } /* finish RESUME signaling? */ if ((sw_hcd->port1_status & SW_HCD_PORT_STAT_RESUME) && time_after_eq(jiffies, sw_hcd->rh_timer)) { u8 power = 0; power = USBC_Readb(USBC_REG_PCTL(usbc_base)); power &= ~(1 << USBC_BP_POWER_H_RESUME); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); DMSG_DBG_HCD("DBG: root port resume stopped, power %02x\n", power); /* ISSUE: DaVinci (RTL 1.300) disconnects after * resume of high speed peripherals (but not full * speed ones). */ sw_hcd->is_active = 1; sw_hcd->port1_status &= ~(USB_PORT_STAT_SUSPEND | SW_HCD_PORT_STAT_RESUME); sw_hcd->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; usb_hcd_poll_rh_status(sw_hcd_to_hcd(sw_hcd)); } put_unaligned(cpu_to_le32(sw_hcd->port1_status & ~SW_HCD_PORT_STAT_RESUME), (__le32 *) buf); /* port change status is more interesting */ DMSG_DBG_HCD("DBG: port status %08x\n", sw_hcd->port1_status); } break; case SetPortFeature: { if ((wIndex & 0xff) != 1){ goto error; } switch (wValue) { case USB_PORT_FEAT_POWER: /* NOTE: this controller has a strange state machine * that involves "requesting sessions" according to * magic side effects from incompletely-described * rules about startup... * * This call is what really starts the host mode; be * very careful about side effects if you reorder any * initialization logic, e.g. for OTG, or change any * logic relating to VBUS power-up. */ sw_hcd_start(sw_hcd); break; case USB_PORT_FEAT_RESET: sw_hcd_port_reset(sw_hcd, true); break; case USB_PORT_FEAT_SUSPEND: sw_hcd_port_suspend(sw_hcd, true); break; case USB_PORT_FEAT_TEST: { if (unlikely(is_host_active(sw_hcd))){ DMSG_PANIC("ERR: usb host is not active\n"); goto error; } wIndex >>= 8; switch (wIndex) { case 1: DMSG_DBG_HCD("TEST_J\n"); temp = 1 << USBC_BP_TMCTL_TEST_J; break; case 2: DMSG_DBG_HCD("TEST_K\n"); temp = 1 << USBC_BP_TMCTL_TEST_K; break; case 3: DMSG_DBG_HCD("TEST_SE0_NAK\n"); temp = 1 << USBC_BP_TMCTL_TEST_SE0_NAK; break; case 4: DMSG_DBG_HCD("TEST_PACKET\n"); temp = 1 << USBC_BP_TMCTL_TEST_PACKET; sw_hcd_load_testpacket(sw_hcd); break; case 5: DMSG_DBG_HCD("TEST_FORCE_ENABLE\n"); temp = (1 << USBC_BP_TMCTL_FORCE_HOST) | (1 << USBC_BP_TMCTL_FORCE_HS); USBC_REG_set_bit_b(USBC_BP_DEVCTL_SESSION, USBC_REG_DEVCTL(usbc_base)); break; case 6: DMSG_DBG_HCD("TEST_FIFO_ACCESS\n"); temp = 1 << USBC_BP_TMCTL_FIFO_ACCESS; break; default: DMSG_PANIC("ERR: unkown SetPortFeature USB_PORT_FEAT_TEST wIndex(%d)\n", wIndex); goto error; } USBC_Writeb(temp, USBC_REG_TMCTL(usbc_base)); } break; default:{ DMSG_PANIC("ERR: unkown SetPortFeature wValue(%d)\n", wValue); goto error; } } DMSG_DBG_HCD("DBG: set feature %d\n", wValue); sw_hcd->port1_status |= 1 << wValue; } break; default: error: DMSG_PANIC("ERR: protocol stall on error\n"); /* "protocol stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&sw_hcd->lock, flags); return retval; }
void clear_usb_reg(__u32 usb_base) { __u32 reg_val = 0; __u32 i = 0; /* global control and status */ reg_val = USBC_Readl(USBC_REG_EX_USB_GCS(usb_base)); reg_val = 0x20; USBC_Writel(reg_val, USBC_REG_EX_USB_GCS(usb_base)); /* endpoint interrupt flag */ reg_val = USBC_Readl(USBC_REG_EX_USB_EPINTF(usb_base)); reg_val = 0x44; USBC_Writel(reg_val, USBC_REG_EX_USB_EPINTF(usb_base)); /* endpoint interrupt enable */ reg_val = USBC_Readl(USBC_REG_EX_USB_EPINTE(usb_base)); reg_val = 0x48; USBC_Writel(reg_val, USBC_REG_EX_USB_EPINTE(usb_base)); /* bus interrupt flag */ reg_val = USBC_Readl(USBC_REG_EX_USB_BUSINTF(usb_base)); reg_val = 0x4c; USBC_Writel(reg_val, USBC_REG_EX_USB_BUSINTF(usb_base)); /* bus interrupt enable */ reg_val = USBC_Readl(USBC_REG_EX_USB_BUSINTE(usb_base)); reg_val = 0x50; USBC_Writel(reg_val, USBC_REG_EX_USB_BUSINTE(usb_base)); /* endpoint control status */ for(i = 0; i < USBC_MAX_EP_NUM; i++) { USBC_Writeb(i, USBC_REG_EPIND(usb_base)); /* endpoint control status */ if (i == 0) { reg_val = USBC_Readl(USBC_REG_EX_USB_CSR0(usb_base)); reg_val = 0x00; USBC_Writel(reg_val, USBC_REG_EX_USB_CSR0(usb_base)); } else { /* TX endpoint control status */ reg_val = USBC_Readl(USBC_REG_EX_USB_TXCSR(usb_base)); reg_val = 0x00; USBC_Writel(reg_val, USBC_REG_EX_USB_TXCSR(usb_base)); /* RX endpoint control status */ reg_val = USBC_Readl(USBC_REG_EX_USB_RXCSR(usb_base)); reg_val = 0x00; USBC_Writel(reg_val, USBC_REG_EX_USB_RXCSR(usb_base)); } /* TX fifo seting */ reg_val = USBC_Readl(USBC_REG_EX_USB_TXFIFO(usb_base)); reg_val = 0x90; USBC_Writel(reg_val, USBC_REG_EX_USB_TXFIFO(usb_base)); /* RX fifo seting */ reg_val = USBC_Readl(USBC_REG_EX_USB_RXFIFO(usb_base)); reg_val = 0x94; USBC_Writel(reg_val, USBC_REG_EX_USB_RXFIFO(usb_base)); /* function address */ reg_val = USBC_Readl(USBC_REG_EX_USB_FADDR(usb_base)); reg_val = 0x00; USBC_Writel(reg_val, USBC_REG_EX_USB_FADDR(usb_base)); } USBC_Writeb(0x00, USBC_REG_EPIND(usb_base)); return; }