/** * This function writes a packet into the Tx FIFO associated with the * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For * periodic EPs the periodic Tx FIFO associated with the EP is written * with all packets for the next micro-frame. * * @param _core_if Programming view of DWC_otg controller. * @param _ep The EP to write packet for. * @param _dma Indicates if DMA is being used. */ void dwc_otg_ep_write_packet( dwc_ep_t *_ep) { /** * The buffer is padded to DWORD on a per packet basis in * slave/dma mode if the MPS is not DWORD aligned. The last * packet, if short, is also padded to a multiple of DWORD. * * ep->xfer_buff always starts DWORD aligned in memory and is a * multiple of DWORD in length * * ep->xfer_len can be any number of bytes * * ep->xfer_count is a multiple of ep->maxpacket until the last * packet * * FIFO access is DWORD */ uint32_t i; uint32_t byte_count; uint32_t dword_count; uint32_t fifo; uint8_t *data_buff = _ep->xfer_buff; uint32_t temp_data ; //DBG("dwc_otg_ep_write_packet() : %d\n",_ep->xfer_len); if (_ep->xfer_count >= _ep->xfer_len) { //DWC_WARN("%s() No data for EP%d!!!\n", "dwc_otg_ep_write_packet", _ep->num); return; } /* Find the byte length of the packet either short packet or MPS */ if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket) { byte_count = _ep->xfer_len - _ep->xfer_count; } else { byte_count = _ep->maxpacket; } /* Find the DWORD length, padded by extra bytes as neccessary if MPS * is not a multiple of DWORD */ dword_count = (byte_count + 3) / 4; //fifo = _core_if->data_fifo[_ep->num]; fifo = DWC_REG_DATA_FIFO(_ep->num); for (i=0; i<dword_count; i++) { temp_data =get_unaligned(data_buff); dwc_write_reg32( fifo, temp_data ); data_buff += 4; } _ep->xfer_count += byte_count; _ep->xfer_buff += byte_count; flush_cpu_cache(); }
int dwc_pcd_irq() { gintsts_data_t gintr_status; gintsts_data_t gintr_msk; gintr_msk.d32 = dwc_read_reg32(DWC_REG_GINTMSK); gintr_status.d32 = dwc_read_reg32(DWC_REG_GINTSTS); if((gintr_status.d32 & gintr_msk.d32)== 0) return 0; //DBG("irq gintmsk: 0x%08x\n",gintr_msk.d32); //DBG("irq gintrsts: 0x%08x\n",gintr_status.d32); gintr_status.d32 = gintr_status.d32 & gintr_msk.d32; //DBG("irq gintmsk & gintrsts = 0x%08x\n",gintr_status.d32); if (gintr_status.b.rxstsqlvl) { dwc_otg_pcd_handle_rx_status_q_level_intr(); } if (gintr_status.b.nptxfempty) { dwc_otg_pcd_handle_np_tx_fifo_empty_intr( ); } if (gintr_status.b.usbreset) { dwc_otg_pcd_handle_usb_reset_intr( ); } if (gintr_status.b.enumdone) { dwc_otg_pcd_handle_enum_done_intr(); } if (gintr_status.b.epmismatch) { //dwc_otg_pcd_handle_ep_mismatch_intr( core_if ); } if (gintr_status.b.inepint) { dwc_otg_pcd_handle_in_ep_intr(); } if (gintr_status.b.outepintr) { dwc_otg_pcd_handle_out_ep_intr( ); } dwc_write_reg32(DWC_REG_GINTSTS,gintr_status.d32); flush_cpu_cache(); return 0; }
/** * This function configures EP0 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 * */ static void ep0_out_start(void) { deptsiz0_data_t doeptsize0 = { 0}; depctl_data_t doepctl = { 0 }; doeptsize0.b.supcnt = 3; doeptsize0.b.pktcnt = 1; doeptsize0.b.xfersize = 8*3; DBG("ep0_out_start()\n"); dwc_write_reg32( DWC_REG_OUT_EP_TSIZE(0),doeptsize0.d32 ); // EP enable doepctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0)); doepctl.b.epena = 1; doepctl.d32 = 0x80008000; dwc_write_reg32(DWC_REG_OUT_EP_REG(0),doepctl.d32); flush_cpu_cache(); }
static void sync_buf_post_cpu(struct cach_buf *buf, enum hwmem_access next_access, struct hwmem_region *next_region) { bool write = next_access & HWMEM_ACCESS_WRITE; bool read = next_access & HWMEM_ACCESS_READ; struct cach_range region_range; if (!write && !read) return; region_2_range(next_region, buf->size, ®ion_range); if (write) { if (speculative_data_prefetch()) { /* Defer invalidate */ struct cach_range intersection; intersect_range(&buf->range_in_cpu_cache, ®ion_range, &intersection); expand_range(&buf->range_invalid_in_cpu_cache, &intersection); clean_cpu_cache(buf, ®ion_range); } else { flush_cpu_cache(buf, ®ion_range); } } if (read) clean_cpu_cache(buf, ®ion_range); if (buf->in_cpu_write_buf) { drain_cpu_write_buf(); buf->in_cpu_write_buf = false; } }
/** * This interrupt indicates that an IN EP has a pending Interrupt. * The sequence for handling the IN EP interrupt is shown below: * -# Read the Device All Endpoint Interrupt register * -# Repeat the following for each IN EP interrupt bit set (from * LSB to MSB). * -# Read the Device Endpoint Interrupt (DIEPINTn) register * -# If "Transfer Complete" call the request complete function * -# If "Endpoint Disabled" complete the EP disable procedure. * -# If "AHB Error Interrupt" log error * -# If "Time-out Handshake" log error * -# If "IN Token Received when TxFIFO Empty" write packet to Tx * FIFO. * -# If "IN Token EP Mismatch" (disable, this is handled by EP * Mismatch Interrupt) */ static int32_t dwc_otg_pcd_handle_in_ep_intr(void) { #define CLEAR_IN_EP_INTR(__epnum,__intr) \ do { \ diepint_data_t diepint = { 0 }; \ diepint.b.__intr = 1; \ dwc_write_reg32(DWC_REG_IN_EP_INTR(__epnum), \ diepint.d32); \ } while (0) diepint_data_t diepint = { 0 }; // depctl_data_t diepctl = { 0 }; uint32_t ep_intr; uint32_t epnum = 0; gintmsk_data_t intr_mask = {0}; gintsts_data_t gintsts; DBG( "dwc_otg_pcd_handle_in_ep_intr()\n" ); /* Read in the device interrupt bits */ ep_intr = (dwc_read_reg32(DWC_REG_DAINT) & dwc_read_reg32( DWC_REG_DAINTMSK)); ep_intr =( (ep_intr & 0xffff) ); /* Clear the INEPINT in GINTSTS */ /* Clear all the interrupt bits for all IN endpoints in DAINT */ gintsts.d32 = 0; gintsts.b.inepint = 1; dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32); dwc_write_reg32(DWC_REG_DAINT, 0xFFFF ); flush_cpu_cache(); /* Service the Device IN interrupts for each endpoint */ while ( ep_intr ) { if (ep_intr&0x1) { diepint.d32 = (dwc_read_reg32( DWC_REG_IN_EP_INTR(epnum)) & dwc_read_reg32(DWC_REG_DAINTMSK)); /* Transfer complete */ if ( diepint.b.xfercompl ) { /* Disable the NP Tx FIFO Empty * Interrrupt */ intr_mask.b.nptxfempty = 1; dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, 0); /* Clear the bit in DIEPINTn for this interrupt */ CLEAR_IN_EP_INTR(epnum,xfercompl); /* Complete the transfer */ if (epnum == 0) { handle_ep0( 0 ); } else { complete_ep( epnum,1 ); } } /* Endpoint disable */ if ( diepint.b.epdisabled ) { handle_in_ep_disable_intr( epnum ); /* Clear the bit in DIEPINTn for this interrupt */ CLEAR_IN_EP_INTR(epnum,epdisabled); } /* AHB Error */ if ( diepint.b.ahberr ) { /* Clear the bit in DIEPINTn for this interrupt */ CLEAR_IN_EP_INTR(epnum,ahberr); } /* TimeOUT Handshake (non-ISOC IN EPs) */ if ( diepint.b.timeout ) { handle_in_ep_timeout_intr( epnum ); CLEAR_IN_EP_INTR(epnum,timeout); } /** IN Token received with TxF Empty */ if (diepint.b.intktxfemp) { DWN_MSG("diepint.b.intktxfemp\n"); #if 0 if (!ep->stopped && epnum != 0) { diepmsk_data_t diepmsk = { 0}; diepmsk.b.intktxfemp = 1; dwc_modify_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32, 0 ); start_next_request(ep); } #endif CLEAR_IN_EP_INTR(epnum,intktxfemp); } /** IN Token Received with EP mismatch */ if (diepint.b.intknepmis) { DWN_MSG("intknepmis ep%d\n", epnum); CLEAR_IN_EP_INTR(epnum,intknepmis); } /** IN Endpoint NAK Effective */ if (diepint.b.inepnakeff) { CLEAR_IN_EP_INTR(epnum,inepnakeff); } } epnum++; ep_intr >>=1; } return 1; #undef CLEAR_IN_EP_INTR }
/** * This interrupt occurs when the non-periodic Tx FIFO is half-empty. * The active request is checked for the next packet to be loaded into * the non-periodic Tx FIFO. */ int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(void) { gnptxsts_data_t txstatus = {0}; gintsts_data_t gintsts; int epnum = 0; dwc_ep_t *ep = 0; uint32_t len = 0; int dwords; depctl_data_t depctl; DBG("dwc_otg_pcd_handle_np_tx_fifo_empty_intr()\n"); /* Get the epnum from the IN Token Learning Queue. */ for (epnum=0; epnum < NUM_EP; epnum++) { ep = &g_dwc_eps[epnum]; /* IN endpoint ? */ if (epnum && !ep->is_in ) { continue; } depctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(epnum)); if (depctl.b.epena != 1) continue; if (ep->type == DWC_OTG_EP_TYPE_INTR && ep->xfer_len == 0) continue; flush_cpu_cache(); len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } dwords = (len + 3)/4; //DBG("nptx: write data to fifo, ep%d , size %d\n",epnum,len); /* 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( DWC_REG_GNPTXSTS ); while (txstatus.b.nptxqspcavail > 0 && txstatus.b.nptxfspcavail > dwords && ep->xfer_count < ep->xfer_len) { flush_cpu_cache(); /* Write the FIFO */ dwc_otg_ep_write_packet( ep ); len = ep->xfer_len - ep->xfer_count; if (len > ep->maxpacket) { len = ep->maxpacket; } dwords = (len + 3)/4; flush_cpu_cache(); //txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS); #if 1 /* TODO: Remove these code. Because, if code break from "while"(Line427), an incomplete-in-trans will occour. Then the tansfer will break. */ int retry = 50000; //retry times while (retry--) { txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS); if(txstatus.b.nptxqspcavail > 0 || //txstatus.b.nptxfspcavail <= dwords || ep->xfer_count >= ep->xfer_len) break; else { flush_cpu_cache(); } } if (retry <= 0) { //DWC_ERROR("TxFIFO FULL: Can't trans data to HOST !\n"); } /* END todo */ #endif } } /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.nptxfempty = 1; dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32); return 1; }
int dwc_pcd_irq(void) { gintsts_data_t gintr_status; gintsts_data_t gintr_msk; gintr_msk.d32 = dwc_read_reg32(DWC_REG_GINTMSK); gintr_status.d32 = dwc_read_reg32(DWC_REG_GINTSTS); if ((gintr_status.d32 & gintr_msk.d32)== 0) return 0; DBG("irq gintmsk: 0x%08x\n",gintr_msk.d32); DBG("irq gintrsts: 0x%08x\n",gintr_status.d32); gintr_status.d32 = gintr_status.d32 & gintr_msk.d32; DBG("irq gintmsk & gintrsts = 0x%08x\n",gintr_status.d32); if (gintr_status.b.sofintr) { if (_sofintr_not_occur) { DWN_MSG("sof\n"); _sofintr_not_occur = 0; } } if (gintr_status.b.rxstsqlvl) { dwc_otg_pcd_handle_rx_status_q_level_intr(); pcd_out_completed(&this_pcd[0]); } if (gintr_status.b.nptxfempty) { dwc_otg_pcd_handle_np_tx_fifo_empty_intr( ); } if (gintr_status.b.usbreset) { dwc_otg_pcd_handle_usb_reset_intr( ); } if (gintr_status.b.enumdone) { dwc_otg_pcd_handle_enum_done_intr(); } if (gintr_status.b.epmismatch) { //dwc_otg_pcd_handle_ep_mismatch_intr( core_if ); } if (gintr_status.b.inepint) { dwc_otg_pcd_handle_in_ep_intr(); } if (gintr_status.b.outepintr) { dwc_otg_pcd_handle_out_ep_intr( ); } #if 0 if (gintr_status.b.otgintr) { gotgint_data_t gotgint; gotgint.d32 = dwc_read_reg32(DWC_REG_GOTGINT); if (gotgint.b.sesenddet) { printf("dis-connect-intr\n"); cb_4_dis_connect_intr(); } } #endif//#if 0 dwc_write_reg32(DWC_REG_GINTSTS,gintr_status.d32); flush_cpu_cache(); return 0; }
/** * 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(void) { depctl_data_t doepctl = { 0}; daint_data_t daintmsk = { 0}; doepmsk_data_t doepmsk = { 0}; diepmsk_data_t diepmsk = { 0}; dcfg_data_t dcfg = { 0 }; depctl_data_t diepctl = { 0}; depctl_data_t diepctl_rd = { 0}; grstctl_t resetctl = { 0 }; dctl_data_t dctl = { 0 }; int i = 0; gintsts_data_t gintsts; DBG("\nUSB RESET\n"); /* Clear the Remote Wakeup Signalling */ dctl.b.rmtwkupsig = 1; dwc_modify_reg32( DWC_REG_DCTL,dctl.d32, 0 ); /* Disable all active IN EPs */ diepctl.b.epdis = 1; diepctl.b.snak = 1; for (i=0; i < NUM_EP; i++) { diepctl_rd.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(i)); if (diepctl_rd.b.epena) { dwc_write_reg32(DWC_REG_IN_EP_REG(i),diepctl.d32 ); } } /* Set NAK for all OUT EPs */ doepctl.b.snak = 1; for (i=0; i < NUM_EP; i++) { dwc_write_reg32(DWC_REG_OUT_EP_REG(i), doepctl.d32 ); } /* Flush the NP Tx FIFO */ dwc_otg_flush_tx_fifo( 0 ); /* Flush the Learning Queue */ resetctl.b.intknqflsh = 1; dwc_write_reg32( DWC_REG_GRSTCTL, resetctl.d32); daintmsk.b.inep0 = 1; daintmsk.b.outep0 = 1; dwc_write_reg32( DWC_REG_DAINTMSK, daintmsk.d32 ); doepmsk.b.setup = 1; doepmsk.b.xfercompl = 1; doepmsk.b.ahberr = 1; doepmsk.b.epdisabled = 1; dwc_write_reg32( DWC_REG_DOEPMSK, doepmsk.d32 ); diepmsk.b.xfercompl = 1; diepmsk.b.timeout = 1; diepmsk.b.epdisabled = 1; diepmsk.b.ahberr = 1; dwc_write_reg32( DWC_REG_DIEPMSK, diepmsk.d32 ); /* Reset Device Address */ dcfg.d32 = dwc_read_reg32( DWC_REG_DCFG); dcfg.b.devaddr = 0; dwc_write_reg32( DWC_REG_DCFG, dcfg.d32); /* setup EP0 to receive SETUP packets */ ep0_out_start(); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.usbreset = 1; dwc_write_reg32 ( DWC_REG_GINTSTS, gintsts.d32); flush_cpu_cache(); return 1; }