📄 dwc_otg_pcd_intr.c
字号:
dwc_otg_dev_if_t* dev_if = core_if->dev_if; dwc_otg_dev_in_ep_regs_t *ep_regs; dtxfsts_data_t txstatus = {.d32 = 0}; dwc_otg_pcd_ep_t *ep = 0; uint32_t len = 0; int dwords; ep = get_in_ep(_pcd, epnum); DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %s(%d) \n", ep->ep.name, epnum ); ep_regs = core_if->dev_if->in_ep_regs[epnum]; len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; if (len > ep->dwc_ep.maxpacket) { len = ep->dwc_ep.maxpacket; } dwords = (len + 3)/4; /* While there is space in the queue and space in the FIFO and * More data to tranfer, Write packets to the Tx FIFO */ txstatus.d32 = dwc_read_reg32( &dev_if->in_ep_regs[epnum]->dtxfsts); DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n",epnum,txstatus.d32); while (txstatus.b.txfspcavail > dwords && ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len && ep->dwc_ep.xfer_len != 0) { /* Write the FIFO */ dwc_otg_ep_write_packet( core_if, &ep->dwc_ep, 0); len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; if (len > ep->dwc_ep.maxpacket) { len = ep->dwc_ep.maxpacket; } dwords = (len + 3)/4; txstatus.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts); DWC_DEBUGPL(DBG_PCDV,"dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32); } DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n",epnum,dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts)); return 1;}/** * This function is called when the Device is disconnected. It stops * any active requests and informs the Gadget driver of the * disconnect. */void dwc_otg_pcd_stop(dwc_otg_pcd_t *_pcd){ int i, num_in_eps, num_out_eps; dwc_otg_pcd_ep_t *ep; gintmsk_data_t intr_mask = {.d32 = 0}; num_in_eps = GET_CORE_IF(_pcd)->dev_if->num_in_eps; num_out_eps = GET_CORE_IF(_pcd)->dev_if->num_out_eps; DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__ ); /* don't disconnect drivers more than once */ if (_pcd->ep0state == EP0_DISCONNECT) { DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__ ); return; } _pcd->ep0state = EP0_DISCONNECT; /* Reset the OTG state. */ dwc_otg_pcd_update_otg( _pcd, 1); /* Disable the NP Tx Fifo Empty Interrupt. */ intr_mask.b.nptxfempty = 1; dwc_modify_reg32(&GET_CORE_IF(_pcd)->core_global_regs->gintmsk, intr_mask.d32, 0); /* Flush the FIFOs */ /**@todo NGS Flush Periodic FIFOs */ dwc_otg_flush_tx_fifo( GET_CORE_IF(_pcd), 0x10); dwc_otg_flush_rx_fifo( GET_CORE_IF(_pcd) ); /* prevent new request submissions, kill any outstanding requests */ ep = &_pcd->ep0; request_nuke(ep); /* prevent new request submissions, kill any outstanding requests */ for (i = 0; i < num_in_eps; i++) { dwc_otg_pcd_ep_t *ep = &_pcd->in_ep[i]; request_nuke(ep); } /* prevent new request submissions, kill any outstanding requests */ for (i = 0; i < num_out_eps; i++) { dwc_otg_pcd_ep_t *ep = &_pcd->out_ep[i]; request_nuke(ep); } /* report disconnect; the driver is already quiesced */ if (_pcd->driver && _pcd->driver->disconnect) { SPIN_UNLOCK(&_pcd->lock); _pcd->driver->disconnect(&_pcd->gadget); SPIN_LOCK(&_pcd->lock); }}/** * This interrupt indicates that ... */int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t *_pcd){ gintmsk_data_t intr_mask = { .d32 = 0}; gintsts_data_t gintsts; DWC_PRINT("INTERRUPT Handler not implemented for %s\n", "i2cintr"); intr_mask.b.i2cintr = 1; dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk, intr_mask.d32, 0 ); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.i2cintr = 1; dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts, gintsts.d32); return 1;}/** * This interrupt indicates that ... */int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t *_pcd){ gintsts_data_t gintsts;#if defined(VERBOSE) DWC_PRINT("Early Suspend Detected\n");#endif /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.erlysuspend = 1; dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts, gintsts.d32); return 1;}/** * This function configures EPO to receive SETUP packets. * * @todo NGS: Update the comments from the HW FS. * * -# Program the following fields in the endpoint specific registers * for Control OUT EP 0, in order to receive a setup packet * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back * setup packets) * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back * to back setup packets) * - In DMA mode, DOEPDMA0 Register with a memory address to * store any setup packets received * * @param _core_if Programming view of DWC_otg controller. * @param _pcd Programming view of the PCD. */static inline void ep0_out_start( dwc_otg_core_if_t *_core_if, dwc_otg_pcd_t *_pcd ){ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; deptsiz0_data_t doeptsize0 = { .d32 = 0}; dwc_otg_dma_desc_t* dma_desc; depctl_data_t doepctl = { .d32 = 0 };#ifdef VERBOSE DWC_DEBUGPL(DBG_PCDV,"%s() doepctl0=%0x\n", __func__, dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));#endif doeptsize0.b.supcnt = 3; doeptsize0.b.pktcnt = 1; doeptsize0.b.xfersize = 8*3; if (_core_if->dma_enable) { if (!_core_if->dma_desc_enable) { /** put here as for Hermes mode deptisz register should not be written */ dwc_write_reg32( &dev_if->out_ep_regs[0]->doeptsiz, doeptsize0.d32 ); /** @todo dma needs to handle multiple setup packets (up to 3) */ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma, _pcd->setup_pkt_dma_handle); } else { dev_if->setup_desc_index = (dev_if->setup_desc_index + 1) & 1; dma_desc = dev_if->setup_desc_addr[dev_if->setup_desc_index]; /** DMA Descriptor Setup */ dma_desc->status.b.bs = BS_HOST_BUSY; dma_desc->status.b.l = 1; dma_desc->status.b.ioc = 1; dma_desc->status.b.bytes = _pcd->ep0.dwc_ep.maxpacket; dma_desc->buf = (uint32_t*)_pcd->setup_pkt_dma_handle; dma_desc->status.b.bs = BS_HOST_READY; /** DOEPDMA0 Register write */ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma, dev_if->dma_setup_desc_addr[dev_if->setup_desc_index]); } /** DOEPCTL0 Register write */ doepctl.b.epena = 1; doepctl.b.cnak = 1; dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32); } else { /** put here as for Hermes mode deptisz register should not be written */ dwc_write_reg32( &dev_if->out_ep_regs[0]->doeptsiz, doeptsize0.d32 ); }#ifdef VERBOSE DWC_DEBUGPL(DBG_PCDV,"doepctl0=%0x\n", dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl)); DWC_DEBUGPL(DBG_PCDV,"diepctl0=%0x\n", dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));#endif}/** * This interrupt occurs when a USB Reset is detected. When the USB * Reset Interrupt occurs the device state is set to DEFAULT and the * EP0 state is set to IDLE. * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1) * -# Unmask the following interrupt bits * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint) * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint) * - DOEPMSK.SETUP = 1 * - DOEPMSK.XferCompl = 1 * - DIEPMSK.XferCompl = 1 * - DIEPMSK.TimeOut = 1 * -# Program the following fields in the endpoint specific registers * for Control OUT EP 0, in order to receive a setup packet * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back * setup packets) * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back * to back setup packets) * - In DMA mode, DOEPDMA0 Register with a memory address to * store any setup packets received * At this point, all the required initialization, except for enabling * the control 0 OUT endpoint is done, for receiving SETUP packets. */int32_t dwc_otg_pcd_handle_usb_reset_intr( dwc_otg_pcd_t * _pcd){ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd); dwc_otg_dev_if_t *dev_if = core_if->dev_if; depctl_data_t doepctl = { .d32 = 0}; daint_data_t daintmsk = { .d32 = 0}; doepmsk_data_t doepmsk = { .d32 = 0}; diepmsk_data_t diepmsk = { .d32 = 0}; dcfg_data_t dcfg = { .d32=0 }; grstctl_t resetctl = { .d32=0 }; dctl_data_t dctl = {.d32=0}; int i = 0; gintsts_data_t gintsts; DWC_PRINT("USB RESET\n");#ifdef _EN_ISOC_ for(i = 1;i < 16;++i) { dwc_otg_pcd_ep_t *ep; dwc_ep_t *dwc_ep; ep = get_in_ep(_pcd,i); if(ep != 0){ dwc_ep = &ep->dwc_ep; dwc_ep->next_frame = 0xffffffff; } }#endif /* _EN_ISOC_ */ /* reset the HNP settings */ dwc_otg_pcd_update_otg( _pcd, 1); /* Clear the Remote Wakeup Signalling */ dctl.b.rmtwkupsig = 1; dwc_modify_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0 ); /* Set NAK for all OUT EPs */ doepctl.b.snak = 1; for (i=0; i <= dev_if->num_out_eps; i++) { dwc_write_reg32( &dev_if->out_ep_regs[i]->doepctl, doepctl.d32 ); } /* Flush the NP Tx FIFO */ dwc_otg_flush_tx_fifo( core_if, 0x10 ); /* Flush the Learning Queue */ resetctl.b.intknqflsh = 1; dwc_write_reg32( &core_if->core_global_regs->grstctl, resetctl.d32); daintmsk.b.inep0 = 1; daintmsk.b.outep0 = 1; dwc_write_reg32( &dev_if->dev_global_regs->daintmsk, daintmsk.d32 ); doepmsk.b.setup = 1; doepmsk.b.xfercompl = 1; doepmsk.b.ahberr = 1; doepmsk.b.epdisabled = 1; if(core_if->dma_desc_enable) { doepmsk.b.stsphsercvd = 1; doepmsk.b.bna = 1; } dwc_write_reg32( &dev_if->dev_global_regs->doepmsk, doepmsk.d32 ); diepmsk.b.xfercompl = 1; diepmsk.b.timeout = 1; diepmsk.b.epdisabled = 1; diepmsk.b.ahberr = 1; diepmsk.b.intknepmis = 1; if(core_if->dma_desc_enable) { diepmsk.b.bna = 1; } dwc_write_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32 ); /* Reset Device Address */ dcfg.d32 = dwc_read_reg32( &dev_if->dev_global_regs->dcfg); dcfg.b.devaddr = 0; dwc_write_reg32( &dev_if->dev_global_regs->dcfg, dcfg.d32); /* setup EP0 to receive SETUP packets */ ep0_out_start( core_if, _pcd ); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.usbreset = 1; dwc_write_reg32 (&core_if->core_global_regs->gintsts, gintsts.d32); return 1;}/** * Get the device speed from the device status register and convert it * to USB speed constant. * * @param _core_if Programming view of DWC_otg controller. */static int get_device_speed( dwc_otg_core_if_t *_core_if ){ dsts_data_t dsts; enum usb_device_speed speed = USB_SPEED_UNKNOWN; dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts); switch (dsts.b.enumspd) { case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: speed = USB_SPEED_HIGH; break; case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ: speed = USB_SPEED_FULL; break; case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ: speed = USB_SPEED_LOW; break; } return speed;}/** * Read the device status register and set the device speed in the * data structure. * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate. */int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t *_pcd){ dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0; gintsts_data_t gintsts; gusbcfg_data_t gusbcfg; dwc_otg_core_global_regs_t *global_regs = GET_CORE_IF(_pcd)->core_global_regs; uint32_t gsnpsid = global_regs->gsnpsid; uint8_t utmi16b, utmi8b; DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n"); if(gsnpsid >= (uint32_t)0x4f54260a) { utmi16b = 6; utmi8b = 9; } else { utmi16b = 4; utmi8b = 8; } dwc_otg_ep0_activate( GET_CORE_IF(_pcd), &ep0->dwc_ep );#ifdef DEBUG_EP0 print_ep0_state(_pcd);#endif if (_pcd->ep0state == EP0_DISCONNECT) { _pcd->ep0state = EP0_IDLE; } else if (_pcd->ep0state == EP0_STALL) { _pcd->ep0state = EP0_IDLE; } _pcd->ep0state = EP0_IDLE; ep0->stopped = 0; _pcd->gadget.speed = get_device_speed(GET_CORE_IF(_pcd)); /* Set USB turnaround time based on device speed and PHY interface. */ gusbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); if (_pcd->gadget.speed == USB_SPEED_HIGH) { if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_ULPI) { /* ULPI interface */ gusbcfg.b.usbtrdtim = 9; } if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI) { /* UTMI+ interface */ if (GET_CORE_IF(_pcd)->hwcfg4.b.utmi_phy_data_width == 0) { gusbcfg.b.usbtrdtim = utmi8b; } else if (GET_CORE_IF(_pcd)->hwcfg4.b.utmi_phy_data_width == 1) {// DWC_PRINT("5555-16-1\n"); gusbcfg.b.usbtrdtim = utmi16b; } else if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 8) { gusbcfg.b.usbtrdtim = utmi8b; } else {// DWC_PRINT("5555-16-2\n"); gusbcfg.b.usbtrdtim = utmi16b; } } if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) { /* UTMI+ OR ULPI interface */ if (gusbcfg.b.ulpi_utmi_sel == 1) { /* ULPI interface */ gusbcfg.b.usbtrdtim = 9; } else { /* UTMI+ interface */ if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16) {// DWC_PRINT("5555-16-3\n"); gusbcfg.b.usbtrdtim = utmi16b; } else { gusbcfg.b.usbtrdtim = utmi8b; } } } } else { /* Full or low speed */ gusbcfg.b.usbtrdtim = 9; } dwc_write_reg32(&global_regs->gusbcfg, gusbcfg.d32); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.enumdone = 1; dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts, gintsts.d32 ); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -