1 /* ==========================================================================
2 * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_pcd_intr.c $
7 * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
8 * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
9 * otherwise expressly agreed to in writing between Synopsys and you.
11 * The Software IS NOT an item of Licensed Software or Licensed Product under
12 * any End User Software License Agreement or Agreement for Licensed Product
13 * with Synopsys or any supplement thereto. You are permitted to use and
14 * redistribute this Software in source and binary forms, with or without
15 * modification, provided that redistributions of source code must retain this
16 * notice. You may not view, use, disclose, copy or distribute this file or
17 * any information contained herein except pursuant to this license grant from
18 * Synopsys. If you do not agree with this notice, including the disclaimer
19 * below, then you are not authorized to use the Software.
21 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32 * ========================================================================== */
34 #include <linux/interrupt.h>
35 #include <linux/dma-mapping.h>
36 #include "dwc_otg_driver.h"
37 #include "dwc_otg_pcd.h"
42 /* request functions defined in "dwc_otg_pcd.c" */
43 extern void request_done( dwc_otg_pcd_ep_t *_ep, dwc_otg_pcd_request_t *_req,
45 extern void request_nuke( dwc_otg_pcd_ep_t *_ep );
46 extern void dwc_otg_pcd_update_otg( dwc_otg_pcd_t *_pcd,
47 const unsigned _reset );
49 * This file contains the implementation of the PCD Interrupt handlers.
51 * The PCD handles the device interrupts. Many conditions can cause a
52 * device interrupt. When an interrupt occurs, the device interrupt
53 * service routine determines the cause of the interrupt and
54 * dispatches handling to the appropriate function. These interrupt
55 * handling functions are described below.
56 * All interrupt registers are processed from LSB to MSB.
61 * This function prints the ep0 state for debug purposes.
63 static inline void print_ep0_state( dwc_otg_pcd_t *_pcd )
68 switch (_pcd->ep0state)
71 strcpy(str, "EP0_DISCONNECT");
74 strcpy(str, "EP0_IDLE");
76 case EP0_IN_DATA_PHASE:
77 strcpy(str, "EP0_IN_DATA_PHASE");
79 case EP0_OUT_DATA_PHASE:
80 strcpy(str, "EP0_OUT_DATA_PHASE");
83 strcpy(str,"EP0_STATUS");
86 strcpy(str,"EP0_STALL");
89 strcpy(str,"EP0_INVALID");
92 DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, _pcd->ep0state);
97 * This function returns pointer to in ep struct with number ep_num
99 static inline dwc_otg_pcd_ep_t* get_in_ep( dwc_otg_pcd_t *_pcd, uint32_t ep_num)
102 int num_in_eps = GET_CORE_IF(_pcd)->dev_if->num_in_eps;
109 for(i = 0; i < num_in_eps; ++i)
111 if(_pcd->in_ep[i].dwc_ep.num == ep_num)
112 return &_pcd->in_ep[i];
118 * This function returns pointer to out ep struct with number ep_num
120 static inline dwc_otg_pcd_ep_t* get_out_ep( dwc_otg_pcd_t *_pcd, uint32_t ep_num)
123 int num_out_eps = GET_CORE_IF(_pcd)->dev_if->num_out_eps;
130 for(i = 0; i < num_out_eps; ++i)
132 if(_pcd->out_ep[i].dwc_ep.num == ep_num)
133 return &_pcd->out_ep[i];
139 * This functions gets a pointer to an EP from the wIndex address
140 * value of the control request.
142 static dwc_otg_pcd_ep_t *get_ep_by_addr (dwc_otg_pcd_t *_pcd, u16 _wIndex)
144 dwc_otg_pcd_ep_t *ep;
146 if ((_wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
148 list_for_each_entry( ep, &_pcd->gadget.ep_list, ep.ep_list)
154 bEndpointAddress = ep->desc->bEndpointAddress;
155 if ((_wIndex ^ bEndpointAddress) & USB_DIR_IN)
157 if ((_wIndex & 0x0f) == (bEndpointAddress & 0x0f))
164 * This function checks the EP request queue, if the queue is not
165 * empty the next request is started.
167 void start_next_request( dwc_otg_pcd_ep_t *_ep )
169 dwc_otg_pcd_request_t *req = 0;
171 if (!list_empty(&_ep->queue))
173 req = list_entry(_ep->queue.next,
174 dwc_otg_pcd_request_t, queue);
176 /* Setup and start the Transfer */
177 _ep->dwc_ep.start_xfer_buff = req->req.buf;
178 _ep->dwc_ep.xfer_buff = req->req.buf;
179 _ep->dwc_ep.xfer_len = req->req.length;
180 _ep->dwc_ep.xfer_count = 0;
181 _ep->dwc_ep.dma_addr = req->req.dma;
182 _ep->dwc_ep.sent_zlp = 0;
183 _ep->dwc_ep.total_len = _ep->dwc_ep.xfer_len;
185 dwc_otg_ep_start_transfer( GET_CORE_IF(_ep->pcd), &_ep->dwc_ep );
190 * This function handles the SOF Interrupts. At this time the SOF
191 * Interrupt is disabled.
193 int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t *_pcd)
195 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
197 gintsts_data_t gintsts;
199 //DWC_DEBUGPL(DBG_PCD, "SOF\n");
201 /* Clear interrupt */
203 gintsts.b.sofintr = 1;
204 dwc_write_reg32 (&core_if->core_global_regs->gintsts, gintsts.d32);
211 * This function handles the Rx Status Queue Level Interrupt, which
212 * indicates that there is a least one packet in the Rx FIFO. The
213 * packets are moved from the FIFO to memory, where they will be
214 * processed when the Endpoint Interrupt Register indicates Transfer
215 * Complete or SETUP Phase Done.
217 * Repeat the following until the Rx Status Queue is empty:
218 * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
220 * -# If Receive FIFO is empty then skip to step Clear the interrupt
222 * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
223 * SETUP data to the buffer
224 * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
225 * to the destination buffer
227 int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t *_pcd)
229 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
230 dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
231 gintmsk_data_t gintmask = {.d32=0};
232 device_grxsts_data_t status;
233 dwc_otg_pcd_ep_t *ep;
234 gintsts_data_t gintsts;
236 static char *dpid_str[] ={ "D0", "D2", "D1", "MDATA" };
239 //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
240 /* Disable the Rx Status Queue Level interrupt */
241 gintmask.b.rxstsqlvl= 1;
242 dwc_modify_reg32( &global_regs->gintmsk, gintmask.d32, 0);
244 /* Get the Status from the top of the FIFO */
245 status.d32 = dwc_read_reg32( &global_regs->grxstsp );
247 DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
248 "pktsts:%x Frame:%d(0x%0x)\n",
249 status.b.epnum, status.b.bcnt,
250 dpid_str[status.b.dpid],
251 status.b.pktsts, status.b.fn, status.b.fn);
252 /* Get pointer to EP structure */
253 ep = get_out_ep(_pcd, status.b.epnum);
254 // ep = &_pcd->out_ep[ status.b.epnum - 1];
256 switch (status.b.pktsts)
258 case DWC_DSTS_GOUT_NAK:
259 DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
261 case DWC_STS_DATA_UPDT:
262 DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
263 if (status.b.bcnt && ep->dwc_ep.xfer_buff)
265 /** @todo NGS Check for buffer overflow? */
266 dwc_otg_read_packet( core_if,
267 ep->dwc_ep.xfer_buff,
269 ep->dwc_ep.xfer_count += status.b.bcnt;
270 ep->dwc_ep.xfer_buff += status.b.bcnt;
273 case DWC_STS_XFER_COMP:
274 DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
276 case DWC_DSTS_SETUP_COMP:
278 DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
281 case DWC_DSTS_SETUP_UPDT:
282 dwc_otg_read_setup_packet( core_if, _pcd->setup_pkt->d32);
285 "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
286 _pcd->setup_pkt->req.bRequestType,
287 _pcd->setup_pkt->req.bRequest,
288 _pcd->setup_pkt->req.wValue,
289 _pcd->setup_pkt->req.wIndex,
290 _pcd->setup_pkt->req.wLength);
292 ep->dwc_ep.xfer_count += status.b.bcnt;
295 DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
300 /* Enable the Rx Status Queue Level interrupt */
301 dwc_modify_reg32( &global_regs->gintmsk, 0, gintmask.d32);
302 /* Clear interrupt */
304 gintsts.b.rxstsqlvl = 1;
305 dwc_write_reg32 (&global_regs->gintsts, gintsts.d32);
307 //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
311 * This function examines the Device IN Token Learning Queue to
312 * determine the EP number of the last IN token received. This
313 * implementation is for the Mass Storage device where there are only
314 * 2 IN EPs (Control-IN and BULK-IN).
316 * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
317 * are 8 EP Numbers in each of the other possible DTKNQ Registers.
319 * @param _core_if Programming view of DWC_otg controller.
322 static inline int get_ep_of_last_in_token(dwc_otg_core_if_t *_core_if)
324 dwc_otg_device_global_regs_t *dev_global_regs =
325 _core_if->dev_if->dev_global_regs;
326 const uint32_t TOKEN_Q_DEPTH = _core_if->hwcfg2.b.dev_token_q_depth;
327 /* Number of Token Queue Registers */
328 const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
329 dtknq1_data_t dtknqr1;
330 uint32_t in_tkn_epnums[4];
333 volatile uint32_t *addr = &dev_global_regs->dtknqr1;
336 //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
339 /* Read the DTKNQ Registers */
340 for (i = 0; i < DTKNQ_REG_CNT; i++)
342 in_tkn_epnums[ i ] = dwc_read_reg32(addr);
343 DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i+1,
345 if (addr == &dev_global_regs->dvbusdis)
347 addr = &dev_global_regs->dtknqr3_dthrctl;
356 /* Copy the DTKNQR1 data to the bit field. */
357 dtknqr1.d32 = in_tkn_epnums[0];
358 /* Get the EP numbers */
359 in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
360 ndx = dtknqr1.b.intknwptr - 1;
362 //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
365 /** @todo Find a simpler way to calculate the max
367 int cnt = TOKEN_Q_DEPTH;
368 if (TOKEN_Q_DEPTH <= 6)
370 cnt = TOKEN_Q_DEPTH - 1;
372 else if (TOKEN_Q_DEPTH <= 14)
374 cnt = TOKEN_Q_DEPTH - 7;
376 else if (TOKEN_Q_DEPTH <= 22)
378 cnt = TOKEN_Q_DEPTH - 15;
382 cnt = TOKEN_Q_DEPTH - 23;
384 epnum = (in_tkn_epnums[ DTKNQ_REG_CNT - 1 ] >> (cnt * 4)) & 0xF;
390 epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
395 epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
400 epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
405 epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
408 //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
413 * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
414 * The active request is checked for the next packet to be loaded into
415 * the non-periodic Tx FIFO.
417 int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t *_pcd)
419 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
420 dwc_otg_core_global_regs_t *global_regs =
421 core_if->core_global_regs;
422 dwc_otg_dev_in_ep_regs_t *ep_regs;
423 gnptxsts_data_t txstatus = {.d32 = 0};
424 gintsts_data_t gintsts;
427 dwc_otg_pcd_ep_t *ep = 0;
431 /* Get the epnum from the IN Token Learning Queue. */
432 epnum = get_ep_of_last_in_token(core_if);
433 ep = get_in_ep(_pcd, epnum);
436 ep = &_pcd->in_ep[epnum-1];
440 DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %s(%d) \n", ep->ep.name, epnum );
442 ep_regs = core_if->dev_if->in_ep_regs[epnum];
444 len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
445 if (len > ep->dwc_ep.maxpacket)
447 len = ep->dwc_ep.maxpacket;
449 dwords = (len + 3)/4;
452 /* While there is space in the queue and space in the FIFO and
453 * More data to tranfer, Write packets to the Tx FIFO */
454 txstatus.d32 = dwc_read_reg32( &global_regs->gnptxsts );
455 DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n",txstatus.d32);
457 while (txstatus.b.nptxqspcavail > 0 &&
458 txstatus.b.nptxfspcavail > dwords &&
459 ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len)
462 dwc_otg_ep_write_packet( core_if, &ep->dwc_ep, 0 );
463 len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
465 if (len > ep->dwc_ep.maxpacket)
467 len = ep->dwc_ep.maxpacket;
470 dwords = (len + 3)/4;
471 txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts);
472 DWC_DEBUGPL(DBG_PCDV,"GNPTXSTS=0x%08x\n",txstatus.d32);
475 DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
476 dwc_read_reg32( &global_regs->gnptxsts));
478 /* Clear interrupt */
480 gintsts.b.nptxfempty = 1;
481 dwc_write_reg32 (&global_regs->gintsts, gintsts.d32);
487 * This function is called when dedicated Tx FIFO Empty interrupt occurs.
488 * The active request is checked for the next packet to be loaded into
489 * apropriate Tx FIFO.
491 static int32_t write_empty_tx_fifo(dwc_otg_pcd_t *_pcd, uint32_t epnum)
493 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
494 dwc_otg_dev_if_t* dev_if = core_if->dev_if;
495 dwc_otg_dev_in_ep_regs_t *ep_regs;
496 dtxfsts_data_t txstatus = {.d32 = 0};
497 dwc_otg_pcd_ep_t *ep = 0;
501 ep = get_in_ep(_pcd, epnum);
504 ep = &_pcd->in_ep[epnum-1];
508 DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %s(%d) \n", ep->ep.name, epnum );
510 ep_regs = core_if->dev_if->in_ep_regs[epnum];
512 len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
514 if (len > ep->dwc_ep.maxpacket)
516 len = ep->dwc_ep.maxpacket;
519 dwords = (len + 3)/4;
521 /* While there is space in the queue and space in the FIFO and
522 * More data to tranfer, Write packets to the Tx FIFO */
523 txstatus.d32 = dwc_read_reg32( &dev_if->in_ep_regs[epnum]->dtxfsts);
524 DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n",epnum,txstatus.d32);
526 while (txstatus.b.txfspcavail > dwords &&
527 ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
528 ep->dwc_ep.xfer_len != 0)
531 dwc_otg_ep_write_packet( core_if, &ep->dwc_ep, 0);
533 len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
534 if (len > ep->dwc_ep.maxpacket)
536 len = ep->dwc_ep.maxpacket;
539 dwords = (len + 3)/4;
540 txstatus.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts);
541 DWC_DEBUGPL(DBG_PCDV,"dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
544 DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n",epnum,dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts));
551 * This function is called when the Device is disconnected. It stops
552 * any active requests and informs the Gadget driver of the
555 void dwc_otg_pcd_stop(dwc_otg_pcd_t *_pcd)
557 int i, num_in_eps, num_out_eps;
558 dwc_otg_pcd_ep_t *ep;
560 gintmsk_data_t intr_mask = {.d32 = 0};
562 SPIN_LOCK(&_pcd->lock);
564 num_in_eps = GET_CORE_IF(_pcd)->dev_if->num_in_eps;
565 num_out_eps = GET_CORE_IF(_pcd)->dev_if->num_out_eps;
567 DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__ );
568 /* don't disconnect drivers more than once */
569 if (_pcd->ep0state == EP0_DISCONNECT)
571 SPIN_UNLOCK(&_pcd->lock);
572 DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__ );
575 _pcd->ep0state = EP0_DISCONNECT;
577 /* Reset the OTG state. */
578 dwc_otg_pcd_update_otg( _pcd, 1);
580 /* Disable the NP Tx Fifo Empty Interrupt. */
581 intr_mask.b.nptxfempty = 1;
582 dwc_modify_reg32(&GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
585 /* Flush the FIFOs */
586 /**@todo NGS Flush Periodic FIFOs */
587 dwc_otg_flush_tx_fifo( GET_CORE_IF(_pcd), 0);
588 dwc_otg_flush_rx_fifo( GET_CORE_IF(_pcd) );
590 /* prevent new request submissions, kill any outstanding requests */
593 /* prevent new request submissions, kill any outstanding requests */
594 for (i = 0; i < num_in_eps; i++)
596 dwc_otg_pcd_ep_t *ep = &_pcd->in_ep[i];
599 /* prevent new request submissions, kill any outstanding requests */
600 for (i = 0; i < num_out_eps; i++)
602 dwc_otg_pcd_ep_t *ep = &_pcd->out_ep[i];
606 /* report disconnect; the driver is already quiesced */
607 if (_pcd->driver && _pcd->driver->disconnect)
609 SPIN_UNLOCK(&_pcd->lock);
610 _pcd->driver->disconnect(&_pcd->gadget);
611 SPIN_LOCK(&_pcd->lock);
613 SPIN_UNLOCK(&_pcd->lock);
617 * This interrupt indicates that ...
619 int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t *_pcd)
621 gintmsk_data_t intr_mask = { .d32 = 0};
622 gintsts_data_t gintsts;
624 DWC_PRINT("INTERRUPT Handler not implemented for %s\n", "i2cintr");
625 intr_mask.b.i2cintr = 1;
626 dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
629 /* Clear interrupt */
631 gintsts.b.i2cintr = 1;
632 dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
639 * This interrupt indicates that ...
641 int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t *_pcd)
643 gintsts_data_t gintsts;
645 DWC_PRINT("Early Suspend Detected\n");
647 /* Clear interrupt */
649 gintsts.b.erlysuspend = 1;
650 dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
656 * This function configures EPO to receive SETUP packets.
658 * @todo NGS: Update the comments from the HW FS.
660 * -# Program the following fields in the endpoint specific registers
661 * for Control OUT EP 0, in order to receive a setup packet
662 * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
664 * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
665 * to back setup packets)
666 * - In DMA mode, DOEPDMA0 Register with a memory address to
667 * store any setup packets received
669 * @param _core_if Programming view of DWC_otg controller.
670 * @param _pcd Programming view of the PCD.
672 static inline void ep0_out_start( dwc_otg_core_if_t *_core_if, dwc_otg_pcd_t *_pcd )
674 dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
675 deptsiz0_data_t doeptsize0 = { .d32 = 0};
678 DWC_DEBUGPL(DBG_PCDV,"%s() doepctl0=%0x\n", __func__,
679 dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
682 doeptsize0.b.supcnt = 3;
683 doeptsize0.b.pktcnt = 1;
684 doeptsize0.b.xfersize = 8*3;
686 dwc_write_reg32( &dev_if->out_ep_regs[0]->doeptsiz,
689 if (_core_if->dma_enable)
691 depctl_data_t doepctl = { .d32 = 0 };
692 /** @todo dma needs to handle multiple setup packets (up to 3) */
693 dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma,
694 _pcd->setup_pkt_dma_handle);
696 doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);
699 doepctl.d32 = 0x80008000;
700 dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl,
704 DWC_DEBUGPL(DBG_PCDV,"doepctl0=%0x\n",
705 dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
706 DWC_DEBUGPL(DBG_PCDV,"diepctl0=%0x\n",
707 dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
713 * This interrupt occurs when a USB Reset is detected. When the USB
714 * Reset Interrupt occurs the device state is set to DEFAULT and the
715 * EP0 state is set to IDLE.
716 * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
717 * -# Unmask the following interrupt bits
718 * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
719 * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
720 * - DOEPMSK.SETUP = 1
721 * - DOEPMSK.XferCompl = 1
722 * - DIEPMSK.XferCompl = 1
723 * - DIEPMSK.TimeOut = 1
724 * -# Program the following fields in the endpoint specific registers
725 * for Control OUT EP 0, in order to receive a setup packet
726 * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
728 * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
729 * to back setup packets)
730 * - In DMA mode, DOEPDMA0 Register with a memory address to
731 * store any setup packets received
732 * At this point, all the required initialization, except for enabling
733 * the control 0 OUT endpoint is done, for receiving SETUP packets.
735 int32_t dwc_otg_pcd_handle_usb_reset_intr( dwc_otg_pcd_t * _pcd)
737 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
738 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
739 depctl_data_t doepctl = { .d32 = 0};
740 daint_data_t daintmsk = { .d32 = 0};
741 doepmsk_data_t doepmsk = { .d32 = 0};
742 diepmsk_data_t diepmsk = { .d32 = 0};
743 dcfg_data_t dcfg = { .d32=0 };
744 grstctl_t resetctl = { .d32=0 };
745 dctl_data_t dctl = {.d32=0};
747 gintsts_data_t gintsts;
749 DWC_PRINT("USB RESET\n");
751 /* reset the HNP settings */
752 dwc_otg_pcd_update_otg( _pcd, 1);
754 /* Clear the Remote Wakeup Signalling */
755 dctl.b.rmtwkupsig = 1;
756 dwc_modify_reg32( &core_if->dev_if->dev_global_regs->dctl,
759 /* Set NAK for all OUT EPs */
761 for (i=0; i <= dev_if->num_out_eps; i++)
763 dwc_write_reg32( &dev_if->out_ep_regs[i]->doepctl,
767 /* Flush the NP Tx FIFO , CHANGE 0x0 to 0x10 to flush all fifo. */
768 dwc_otg_flush_tx_fifo( core_if, 0x10 );
769 /* Flush the Learning Queue */
770 resetctl.b.intknqflsh = 1;
771 dwc_write_reg32( &core_if->core_global_regs->grstctl, resetctl.d32);
773 daintmsk.b.inep0 = 1;
774 daintmsk.b.outep0 = 1;
775 dwc_write_reg32( &dev_if->dev_global_regs->daintmsk, daintmsk.d32 );
778 doepmsk.b.xfercompl = 1;
779 doepmsk.b.ahberr = 1;
780 doepmsk.b.epdisabled = 1;
781 dwc_write_reg32( &dev_if->dev_global_regs->doepmsk, doepmsk.d32 );
783 diepmsk.b.xfercompl = 1;
784 diepmsk.b.timeout = 1;
785 diepmsk.b.epdisabled = 1;
786 diepmsk.b.ahberr = 1;
787 diepmsk.b.intknepmis = 1;
788 dwc_write_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32 );
789 /* Reset Device Address */
790 dcfg.d32 = dwc_read_reg32( &dev_if->dev_global_regs->dcfg);
792 dwc_write_reg32( &dev_if->dev_global_regs->dcfg, dcfg.d32);
794 /* setup EP0 to receive SETUP packets */
795 ep0_out_start( core_if, _pcd );
797 /* Clear interrupt */
799 gintsts.b.usbreset = 1;
800 dwc_write_reg32 (&core_if->core_global_regs->gintsts, gintsts.d32);
806 * Get the device speed from the device status register and convert it
807 * to USB speed constant.
809 * @param _core_if Programming view of DWC_otg controller.
811 static int get_device_speed( dwc_otg_core_if_t *_core_if )
814 enum usb_device_speed speed = USB_SPEED_UNKNOWN;
815 dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts);
817 switch (dsts.b.enumspd)
819 case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
820 speed = USB_SPEED_HIGH;
822 case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
823 case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
824 speed = USB_SPEED_FULL;
827 case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
828 speed = USB_SPEED_LOW;
836 * Read the device status register and set the device speed in the
838 * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
840 int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t *_pcd)
842 dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
843 gintsts_data_t gintsts;
844 gusbcfg_data_t gusbcfg;
845 volatile depctl_data_t depctl = {.d32 = 0};
846 dwc_otg_core_global_regs_t *global_regs =
847 GET_CORE_IF(_pcd)->core_global_regs;
848 uint32_t gsnpsid = global_regs->gsnpsid;
849 uint8_t utmi16b, utmi8b;
850 DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
852 if(gsnpsid >= (uint32_t)0x4f54260a)
862 dwc_otg_ep0_activate( GET_CORE_IF(_pcd), &ep0->dwc_ep );
865 print_ep0_state(_pcd);
869 _pcd->ep0state = EP0_IDLE;
873 _pcd->gadget.speed = get_device_speed(GET_CORE_IF(_pcd));
875 /* Set USB turnaround time based on device speed and PHY interface. */
876 gusbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
877 if (_pcd->gadget.speed == USB_SPEED_HIGH)
879 depctl.b.mps = 0x200;
880 if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_ULPI)
883 gusbcfg.b.usbtrdtim = 9;
885 if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI)
888 /* UTMI+ interface */
889 if (GET_CORE_IF(_pcd)->hwcfg4.b.utmi_phy_data_width == 0)
891 gusbcfg.b.usbtrdtim = utmi8b;
893 else if (GET_CORE_IF(_pcd)->hwcfg4.b.utmi_phy_data_width == 1)
895 gusbcfg.b.usbtrdtim = utmi16b;
897 else if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 8)
899 gusbcfg.b.usbtrdtim = utmi8b;
903 gusbcfg.b.usbtrdtim = utmi16b;
906 if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI)
908 /* UTMI+ OR ULPI interface */
909 if (gusbcfg.b.ulpi_utmi_sel == 1)
912 gusbcfg.b.usbtrdtim = 9;
916 /* UTMI+ interface */
917 if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16)
919 gusbcfg.b.usbtrdtim = utmi16b;
923 gusbcfg.b.usbtrdtim = utmi8b;
931 /* Full or low speed */
932 gusbcfg.b.usbtrdtim = 9;
934 dwc_write_reg32(&global_regs->gusbcfg, gusbcfg.d32);
936 /* Clear interrupt */
938 gintsts.b.enumdone = 1;
939 dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
942 depctl.b.setd0pid = 1;
943 dwc_write_reg32( &GET_CORE_IF(_pcd)->dev_if->in_ep_regs[1]->diepctl, depctl.d32);
947 depctl.b.usbactep = 1;
948 dwc_write_reg32( &GET_CORE_IF(_pcd)->dev_if->out_ep_regs[2]->doepctl, depctl.d32 );
949 dwc_write_reg32( &GET_CORE_IF(_pcd)->dev_if->out_ep_regs[4]->doepctl, depctl.d32 );
950 dwc_write_reg32( &GET_CORE_IF(_pcd)->dev_if->out_ep_regs[6]->doepctl, depctl.d32 );
951 dwc_write_reg32( &GET_CORE_IF(_pcd)->dev_if->out_ep_regs[8]->doepctl, depctl.d32 );
956 * This interrupt indicates that the ISO OUT Packet was dropped due to
957 * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
958 * read all the data from the Rx FIFO.
960 int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t *_pcd )
962 gintmsk_data_t intr_mask = { .d32 = 0};
963 gintsts_data_t gintsts;
965 DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
968 intr_mask.b.isooutdrop = 1;
969 dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
972 /* Clear interrupt */
974 gintsts.b.isooutdrop = 1;
975 dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
982 * This interrupt indicates the end of the portion of the micro-frame
983 * for periodic transactions. If there is a periodic transaction for
984 * the next frame, load the packets into the EP periodic Tx FIFO.
986 int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t *_pcd )
988 gintmsk_data_t intr_mask = { .d32 = 0};
989 gintsts_data_t gintsts;
990 DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
993 intr_mask.b.eopframe = 1;
994 dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
997 /* Clear interrupt */
999 gintsts.b.eopframe = 1;
1000 dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
1007 * This interrupt indicates that EP of the packet on the top of the
1008 * non-periodic Tx FIFO does not match EP of the IN Token received.
1010 * The "Device IN Token Queue" Registers are read to determine the
1011 * order the IN Tokens have been received. The non-periodic Tx FIFO
1012 * is flushed, so it can be reloaded in the order seen in the IN Token
1015 int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_core_if_t *_core_if)
1017 gintsts_data_t gintsts;
1018 DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _core_if);
1020 /* Clear interrupt */
1022 gintsts.b.epmismatch = 1;
1023 dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
1029 * This funcion stalls EP0.
1031 static inline void ep0_do_stall( dwc_otg_pcd_t *_pcd, const int err_val )
1033 dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
1034 struct usb_ctrlrequest *ctrl = &_pcd->setup_pkt->req;
1035 DWC_WARN("req %02x.%02x v%04x i%04x l%04x protocol STALL; err %d\n",
1036 ctrl->bRequestType, ctrl->bRequest,ctrl->wValue, ctrl->wIndex, ctrl->wLength, err_val);
1038 ep0->dwc_ep.is_in = 1;
1039 dwc_otg_ep_set_stall( _pcd->otg_dev->core_if, &ep0->dwc_ep );
1040 _pcd->ep0.stopped = 1;
1041 _pcd->ep0state = EP0_IDLE;
1042 ep0_out_start( GET_CORE_IF(_pcd), _pcd );
1046 * This functions delegates the setup command to the gadget driver.
1048 static inline void do_gadget_setup( dwc_otg_pcd_t *_pcd,
1049 struct usb_ctrlrequest * _ctrl)
1052 if (_pcd->driver && _pcd->driver->setup)
1054 SPIN_UNLOCK(&_pcd->lock);
1055 ret = _pcd->driver->setup(&_pcd->gadget, _ctrl);
1056 if(spin_is_locked(&_pcd->lock))
1057 DWC_PRINT("%s warning: pcd->lock locked without unlock\n", __func__);
1058 SPIN_LOCK(&_pcd->lock);
1061 ep0_do_stall( _pcd, ret );
1064 /** @todo This is a g_file_storage gadget driver specific
1065 * workaround: a DELAYED_STATUS result from the fsg_setup
1066 * routine will result in the gadget queueing a EP0 IN status
1067 * phase for a two-stage control transfer. Exactly the same as
1068 * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
1069 * specific request. Need a generic way to know when the gadget
1070 * driver will queue the status phase. Can we assume when we
1071 * call the gadget driver setup() function that it will always
1072 * queue and require the following flag? Need to look into
1076 if (ret == 256 + 999)
1078 _pcd->request_config = 1;
1084 * This function starts the Zero-Length Packet for the IN status phase
1085 * of a 2 stage control transfer.
1087 static inline void do_setup_in_status_phase( dwc_otg_pcd_t *_pcd)
1089 dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
1090 if (_pcd->ep0state == EP0_STALL)
1095 _pcd->ep0state = EP0_STATUS;
1097 /* Prepare for more SETUP Packets */
1098 DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
1099 ep0->dwc_ep.xfer_len = 0;
1100 ep0->dwc_ep.xfer_count = 0;
1101 ep0->dwc_ep.is_in = 1;
1102 ep0->dwc_ep.dma_addr = _pcd->setup_pkt_dma_handle;
1104 dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );
1106 /* Prepare for more SETUP Packets */
1107 ep0_out_start( GET_CORE_IF(_pcd), _pcd );
1112 * This function starts the Zero-Length Packet for the OUT status phase
1113 * of a 2 stage control transfer.
1115 static inline void do_setup_out_status_phase( dwc_otg_pcd_t *_pcd)
1117 dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
1118 if (_pcd->ep0state == EP0_STALL)
1120 DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
1123 _pcd->ep0state = EP0_STATUS;
1125 /* Prepare for more SETUP Packets */
1126 //ep0_out_start( GET_CORE_IF(_pcd), _pcd );
1128 DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
1129 ep0->dwc_ep.xfer_len = 0;
1130 ep0->dwc_ep.xfer_count = 0;
1131 ep0->dwc_ep.is_in = 0;
1132 //ep0->dwc_ep.dma_addr = 0xffffffff;
1133 ep0->dwc_ep.dma_addr = _pcd->setup_pkt_dma_handle;
1134 dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );
1136 /* Prepare for more SETUP Packets */
1137 ep0_out_start( GET_CORE_IF(_pcd), _pcd );
1142 * Clear the EP halt (STALL) and if pending requests start the
1145 static inline void pcd_clear_halt( dwc_otg_pcd_t *_pcd, dwc_otg_pcd_ep_t *_ep )
1147 if(_ep->dwc_ep.stall_clear_flag == 0)
1148 dwc_otg_ep_clear_stall( GET_CORE_IF(_pcd), &_ep->dwc_ep );
1150 /* Reactive the EP */
1151 dwc_otg_ep_activate( GET_CORE_IF(_pcd), &_ep->dwc_ep );
1155 /* If there is a request in the EP queue start it */
1157 /** @todo FIXME: this causes an EP mismatch in DMA mode.
1158 * epmismatch not yet implemented. */
1161 * Above fixme is solved by implmenting a tasklet to call the
1162 * start_next_request(), outside of interrupt context at some
1163 * time after the current time, after a clear-halt setup packet.
1164 * Still need to implement ep mismatch in the future if a gadget
1165 * ever uses more than one endpoint at once
1167 if (GET_CORE_IF(_pcd)->dma_enable)
1170 tasklet_schedule (_pcd->start_xfer_tasklet);
1176 DWC_ERROR("tasklet schedule\n");
1177 tasklet_schedule (_pcd->start_xfer_tasklet);
1178 if (GET_CORE_IF(_pcd)->core_params->opt)
1180 start_next_request( _ep );
1185 /* Start Control Status Phase */
1186 do_setup_in_status_phase( _pcd );
1190 * This function is called when the SET_FEATURE TEST_MODE Setup packet
1191 * is sent from the host. The Device Control register is written with
1192 * the Test Mode bits set to the specified Test Mode. This is done as
1193 * a tasklet so that the "Status" phase of the control transfer
1194 * completes before transmitting the TEST packets.
1196 * @todo This has not been tested since the tasklet struct was put
1197 * into the PCD struct!
1200 static void do_test_mode( unsigned long _data )
1203 dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_data;
1204 dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
1205 int test_mode = pcd->test_mode;
1208 // DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
1210 dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);
1221 case 3: // TEST_SE0_NAK
1225 case 4: // TEST_PACKET
1229 case 5: // TEST_FORCE_ENABLE
1233 dwc_write_reg32(&core_if->dev_if->dev_global_regs->dctl,
1239 * This function process the SET_FEATURE Setup Commands.
1241 static inline void do_set_feature( dwc_otg_pcd_t *_pcd )
1243 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
1244 dwc_otg_core_global_regs_t *global_regs =
1245 core_if->core_global_regs;
1246 struct usb_ctrlrequest ctrl = _pcd->setup_pkt->req;
1247 dwc_otg_pcd_ep_t *ep = 0;
1248 int32_t otg_cap_param = core_if->core_params->otg_cap;
1249 gotgctl_data_t gotgctl = { .d32 = 0 };
1251 DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
1252 ctrl.bRequestType, ctrl.bRequest,
1253 ctrl.wValue, ctrl.wIndex, ctrl.wLength);
1254 DWC_DEBUGPL(DBG_PCD,"otg_cap=%d\n", otg_cap_param);
1257 switch (ctrl.bRequestType & USB_RECIP_MASK)
1259 case USB_RECIP_DEVICE:
1260 switch (ctrl.wValue)
1262 case USB_DEVICE_REMOTE_WAKEUP:
1263 _pcd->remote_wakeup_enable = 1;
1266 case USB_DEVICE_TEST_MODE:
1267 /* Setup the Test Mode tasklet to do the Test
1268 * Packet generation after the SETUP Status
1269 * phase has completed. */
1271 /** @todo This has not been tested since the
1272 * tasklet struct was put into the PCD
1274 _pcd->test_mode_tasklet.next = 0;
1275 _pcd->test_mode_tasklet.state = 0;
1276 atomic_set( &_pcd->test_mode_tasklet.count, 0);
1277 _pcd->test_mode_tasklet.func = do_test_mode;
1278 _pcd->test_mode_tasklet.data = (unsigned long)_pcd;
1279 _pcd->test_mode = ctrl.wIndex >> 8;
1280 tasklet_schedule(&_pcd->test_mode_tasklet);
1283 case USB_DEVICE_B_HNP_ENABLE:
1284 DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
1286 /* dev may initiate HNP */
1287 if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
1289 _pcd->b_hnp_enable = 1;
1290 dwc_otg_pcd_update_otg( _pcd, 0 );
1291 DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
1292 /**@todo Is the gotgctl.devhnpen cleared
1293 * by a USB Reset? */
1294 gotgctl.b.devhnpen = 1;
1295 gotgctl.b.hnpreq = 1;
1296 dwc_write_reg32( &global_regs->gotgctl, gotgctl.d32 );
1300 ep0_do_stall( _pcd, -EOPNOTSUPP);
1304 case USB_DEVICE_A_HNP_SUPPORT:
1305 /* RH port supports HNP */
1306 DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
1307 if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
1309 _pcd->a_hnp_support = 1;
1310 dwc_otg_pcd_update_otg( _pcd, 0 );
1314 ep0_do_stall( _pcd, -EOPNOTSUPP);
1318 case USB_DEVICE_A_ALT_HNP_SUPPORT:
1319 /* other RH port does */
1320 DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
1321 if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
1323 _pcd->a_alt_hnp_support = 1;
1324 dwc_otg_pcd_update_otg( _pcd, 0 );
1328 ep0_do_stall( _pcd, -EOPNOTSUPP);
1332 do_setup_in_status_phase( _pcd );
1335 case USB_RECIP_INTERFACE:
1336 do_gadget_setup(_pcd, &ctrl );
1339 case USB_RECIP_ENDPOINT:
1340 if (ctrl.wValue == USB_ENDPOINT_HALT)
1342 ep = get_ep_by_addr(_pcd, ctrl.wIndex);
1345 ep0_do_stall(_pcd, -EOPNOTSUPP);
1349 dwc_otg_ep_set_stall( core_if, &ep->dwc_ep );
1351 do_setup_in_status_phase( _pcd );
1357 * This function process the CLEAR_FEATURE Setup Commands.
1359 static inline void do_clear_feature( dwc_otg_pcd_t *_pcd )
1361 struct usb_ctrlrequest ctrl = _pcd->setup_pkt->req;
1362 dwc_otg_pcd_ep_t *ep = 0;
1365 DWC_DEBUGPL(DBG_PCD,
1366 "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
1367 ctrl.bRequestType, ctrl.bRequest,
1368 ctrl.wValue, ctrl.wIndex, ctrl.wLength);
1370 switch (ctrl.bRequestType & USB_RECIP_MASK)
1372 case USB_RECIP_DEVICE:
1373 switch (ctrl.wValue)
1375 case USB_DEVICE_REMOTE_WAKEUP:
1376 _pcd->remote_wakeup_enable = 0;
1379 case USB_DEVICE_TEST_MODE:
1380 /** @todo Add CLEAR_FEATURE for TEST modes. */
1383 do_setup_in_status_phase( _pcd );
1386 case USB_RECIP_ENDPOINT:
1387 ep = get_ep_by_addr(_pcd, ctrl.wIndex);
1390 ep0_do_stall(_pcd, -EOPNOTSUPP);
1394 pcd_clear_halt(_pcd, ep );
1401 * This function processes SETUP commands. In Linux, the USB Command
1402 * processing is done in two places - the first being the PCD and the
1403 * second in the Gadget Driver (for example, the File-Backed Storage
1407 * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
1409 * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
1410 * defined in chapter 9 of the USB 2.0 Specification chapter 9
1413 * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
1414 * requests are the ENDPOINT_HALT feature is procesed, all others the
1415 * interface requests are ignored.</td></tr>
1417 * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
1418 * requests are processed by the PCD. Interface requests are passed
1419 * to the Gadget Driver.</td></tr>
1421 * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
1422 * with device address received </td></tr>
1424 * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
1425 * requested descriptor</td></tr>
1427 * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
1428 * not implemented by any of the existing Gadget Drivers.</td></tr>
1430 * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
1431 * all EPs and enable EPs for new configuration.</td></tr>
1433 * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
1434 * the current configuration</td></tr>
1436 * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
1437 * EPs and enable EPs for new configuration.</td></tr>
1439 * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
1440 * current interface.</td></tr>
1442 * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
1443 * message.</td></tr>
1446 * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
1447 * processed by pcd_setup. Calling the Function Driver's setup function from
1448 * pcd_setup processes the gadget SETUP commands.
1450 static inline void pcd_setup( dwc_otg_pcd_t *_pcd )
1452 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
1453 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
1454 struct usb_ctrlrequest ctrl = _pcd->setup_pkt->req;
1455 dwc_otg_pcd_ep_t *ep;
1456 dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
1457 uint16_t *status = _pcd->status_buf;
1459 deptsiz0_data_t doeptsize0 = { .d32 = 0};
1462 DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
1463 ctrl.bRequestType, ctrl.bRequest,
1464 ctrl.wValue, ctrl.wIndex, ctrl.wLength);
1467 doeptsize0.d32 = dwc_read_reg32( &dev_if->out_ep_regs[0]->doeptsiz );
1469 /** @todo handle > 1 setup packet , assert error for now */
1470 if (core_if->dma_enable && (doeptsize0.b.supcnt < 2))
1472 DWC_ERROR ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
1475 /* Clean up the request queue */
1476 request_nuke( ep0 );
1479 if (ctrl.bRequestType & USB_DIR_IN)
1481 ep0->dwc_ep.is_in = 1;
1482 _pcd->ep0state = EP0_IN_DATA_PHASE;
1486 ep0->dwc_ep.is_in = 0;
1487 _pcd->ep0state = EP0_OUT_DATA_PHASE;
1489 if (ctrl.wLength == 0)
1491 ep0->dwc_ep.is_in = 1;
1492 _pcd->ep0state = EP0_STATUS;
1494 if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
1496 /* handle non-standard (class/vendor) requests in the gadget driver */
1497 do_gadget_setup(_pcd, &ctrl );
1501 /** @todo NGS: Handle bad setup packet? */
1503 switch (ctrl.bRequest)
1505 case USB_REQ_GET_STATUS:
1507 DWC_DEBUGPL(DBG_PCD,
1508 "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
1509 ctrl.bRequestType, ctrl.bRequest,
1510 ctrl.wValue, ctrl.wIndex, ctrl.wLength);
1513 switch (ctrl.bRequestType & USB_RECIP_MASK)
1515 case USB_RECIP_DEVICE:
1516 *status = 0x1; /* Self powered */
1517 *status |= _pcd->remote_wakeup_enable << 1;
1520 case USB_RECIP_INTERFACE:
1524 case USB_RECIP_ENDPOINT:
1525 ep = get_ep_by_addr(_pcd, ctrl.wIndex);
1526 if ( ep == 0 || ctrl.wLength > 2)
1528 ep0_do_stall(_pcd, -EOPNOTSUPP);
1531 /** @todo check for EP stall */
1532 *status = ep->stopped;
1535 _pcd->ep0_pending = 1;
1537 ep0->dwc_ep.start_xfer_buff = (uint8_t *)status;
1538 ep0->dwc_ep.xfer_buff = (uint8_t *)status;
1539 ep0->dwc_ep.dma_addr = _pcd->status_buf_dma_handle;
1540 ep0->dwc_ep.xfer_len = 2;
1541 ep0->dwc_ep.xfer_count = 0;
1542 ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
1543 dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );
1546 case USB_REQ_CLEAR_FEATURE:
1547 do_clear_feature( _pcd );
1550 case USB_REQ_SET_FEATURE:
1551 do_set_feature( _pcd );
1554 case USB_REQ_SET_ADDRESS:
1555 if (ctrl.bRequestType == USB_RECIP_DEVICE)
1557 dcfg_data_t dcfg = {.d32=0};
1560 DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
1562 dcfg.b.devaddr = ctrl.wValue;
1563 dwc_modify_reg32( &dev_if->dev_global_regs->dcfg,
1565 do_setup_in_status_phase( _pcd );
1570 case USB_REQ_SET_INTERFACE:
1571 case USB_REQ_SET_CONFIGURATION:
1572 _pcd->request_config = 1; /* Configuration changed */
1573 do_gadget_setup(_pcd, &ctrl );
1576 case USB_REQ_SYNCH_FRAME:
1577 do_gadget_setup(_pcd, &ctrl );
1581 /* Call the Gadget Driver's setup functions */
1582 do_gadget_setup(_pcd, &ctrl );
1588 * This function completes the ep0 control transfer.
1590 static int32_t ep0_complete_request( dwc_otg_pcd_ep_t *_ep )
1592 dwc_otg_core_if_t *core_if = GET_CORE_IF(_ep->pcd);
1593 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
1594 dwc_otg_dev_in_ep_regs_t *in_ep_regs =
1595 dev_if->in_ep_regs[_ep->dwc_ep.num];
1597 dwc_otg_dev_out_ep_regs_t *out_ep_regs =
1598 dev_if->out_ep_regs[_ep->dwc_ep.num];
1600 deptsiz0_data_t deptsiz;
1601 dwc_otg_pcd_request_t *req;
1603 dwc_otg_pcd_t *pcd = _ep->pcd;
1605 DWC_DEBUGPL(DBG_PCDV, "%s() %s\n", __func__, _ep->ep.name);
1607 if (pcd->ep0_pending && list_empty(&_ep->queue))
1609 if (_ep->dwc_ep.is_in)
1612 DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
1614 do_setup_out_status_phase(pcd);
1619 DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
1621 do_setup_in_status_phase(pcd);
1623 pcd->ep0_pending = 0;
1624 pcd->ep0state = EP0_STATUS;
1628 if (list_empty(&_ep->queue))
1632 req = list_entry(_ep->queue.next, dwc_otg_pcd_request_t, queue);
1635 if (pcd->ep0state == EP0_STATUS)
1640 else if (req->req.zero)
1642 DWC_PRINT("%s--------------------------------------------------\n",__func__);
1643 req->req.actual = _ep->dwc_ep.xfer_count;
1644 //do_setup_in_status_phase (pcd);
1646 _ep->dwc_ep.xfer_len = 0;
1647 _ep->dwc_ep.xfer_count = 0;
1648 _ep->dwc_ep.sent_zlp = 1;
1649 dwc_otg_ep0_start_transfer( GET_CORE_IF(pcd), &_ep->dwc_ep );
1653 else if (_ep->dwc_ep.is_in)
1655 deptsiz.d32 = dwc_read_reg32( &in_ep_regs->dieptsiz);
1657 DWC_DEBUGPL(DBG_PCDV, "%s len=%d xfersize=%d pktcnt=%d\n",
1658 _ep->ep.name, _ep->dwc_ep.xfer_len,
1659 deptsiz.b.xfersize, deptsiz.b.pktcnt);
1661 if (deptsiz.b.xfersize == 0)
1663 req->req.actual = _ep->dwc_ep.xfer_count;
1664 /* Is a Zero Len Packet needed? */
1665 //if (req->req.zero) {
1667 DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
1669 do_setup_out_status_phase(pcd);
1676 deptsiz.d32 = dwc_read_reg32( &out_ep_regs->doeptsiz);
1677 DWC_DEBUGPL(DBG_PCDV, "%s len=%d xsize=%d pktcnt=%d\n",
1678 _ep->ep.name, _ep->dwc_ep.xfer_len,
1682 req->req.actual = _ep->dwc_ep.xfer_count;
1684 /* Is a Zero Len Packet needed? */
1685 //if (req->req.zero) {
1687 DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
1689 do_setup_in_status_phase(pcd);
1692 /* Complete the request */
1695 request_done(_ep, req, 0);
1696 _ep->dwc_ep.start_xfer_buff = 0;
1697 _ep->dwc_ep.xfer_buff = 0;
1698 _ep->dwc_ep.xfer_len = 0;
1705 * This function completes the request for the EP. If there are
1706 * additional requests for the EP in the queue they will be started.
1708 static void complete_ep( dwc_otg_pcd_ep_t *_ep )
1710 dwc_otg_core_if_t *core_if = GET_CORE_IF(_ep->pcd);
1711 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
1712 dwc_otg_dev_in_ep_regs_t *in_ep_regs =
1713 dev_if->in_ep_regs[_ep->dwc_ep.num];
1714 deptsiz_data_t deptsiz;
1715 dwc_otg_pcd_request_t *req = 0;
1718 DWC_DEBUGPL(DBG_PCDV,"%s() %s-%s\n", __func__, _ep->ep.name,
1719 (_ep->dwc_ep.is_in?"IN":"OUT"));
1721 /* Get any pending requests */
1722 if (!list_empty(&_ep->queue))
1724 req = list_entry(_ep->queue.next, dwc_otg_pcd_request_t,
1727 DWC_DEBUGPL(DBG_PCD, "Requests %d\n",_ep->pcd->request_pending);
1729 if (_ep->dwc_ep.is_in)
1731 deptsiz.d32 = dwc_read_reg32( &in_ep_regs->dieptsiz);
1733 if (core_if->dma_enable)
1735 if (deptsiz.b.xfersize == 0)
1736 _ep->dwc_ep.xfer_count = _ep->dwc_ep.xfer_len;
1739 DWC_DEBUGPL(DBG_PCDV, "%s len=%d xfersize=%d pktcnt=%d\n",
1740 _ep->ep.name, _ep->dwc_ep.xfer_len,
1741 deptsiz.b.xfersize, deptsiz.b.pktcnt);
1743 if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0 &&
1744 _ep->dwc_ep.xfer_count == _ep->dwc_ep.xfer_len)
1750 DWC_WARN("Incomplete transfer (%s-%s [siz=%d pkt=%d])\n",
1751 _ep->ep.name, (_ep->dwc_ep.is_in?"IN":"OUT"),
1752 deptsiz.b.xfersize, deptsiz.b.pktcnt);
1757 dwc_otg_dev_out_ep_regs_t *out_ep_regs =
1758 dev_if->out_ep_regs[_ep->dwc_ep.num];
1760 deptsiz.d32 = dwc_read_reg32( &out_ep_regs->doeptsiz);
1764 DWC_DEBUGPL(DBG_PCDV, "addr %p, %s len=%d cnt=%d xsize=%d pktcnt=%d\n",
1765 &out_ep_regs->doeptsiz, _ep->ep.name, _ep->dwc_ep.xfer_len,
1766 _ep->dwc_ep.xfer_count,
1773 /* Complete the request */
1777 /* HSL @RK,20090807 */
1779 if (core_if->dma_enable)
1781 req->req.actual = _ep->dwc_ep.xfer_len - deptsiz.b.xfersize;
1785 req->req.actual = _ep->dwc_ep.xfer_count;
1787 request_done(_ep, req, 0);
1789 DWC_PRINT("\n++++++FIND NULL req,ep=%s++++++++++\n" , _ep->ep.name );
1790 _ep->pcd->request_pending = 0;
1792 _ep->dwc_ep.start_xfer_buff = 0;
1793 _ep->dwc_ep.xfer_buff = 0;
1794 _ep->dwc_ep.xfer_len = 0;
1796 /* If there is a request in the queue start it.*/
1797 start_next_request( _ep );
1802 * This function handles EP0 Control transfers.
1804 * The state of the control tranfers are tracked in
1805 * <code>ep0state</code>.
1807 static void handle_ep0( dwc_otg_pcd_t *_pcd )
1809 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
1810 dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
1811 deptsiz_data_t deptsiz;
1814 DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
1815 print_ep0_state(_pcd);
1818 switch (_pcd->ep0state)
1820 case EP0_DISCONNECT:
1824 _pcd->request_config = 0;
1829 case EP0_IN_DATA_PHASE:
1831 DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
1832 ep0->dwc_ep.num, (ep0->dwc_ep.is_in ?"IN":"OUT"),
1833 ep0->dwc_ep.type, ep0->dwc_ep.maxpacket );
1835 if (core_if->dma_enable)
1838 * For EP0 we can only program 1 packet at a time so we
1839 * need to do the make calculations after each complete.
1840 * Call write_packet to make the calculations, as in
1841 * slave mode, and use those values to determine if we
1844 dwc_otg_ep_write_packet (core_if, &ep0->dwc_ep, 1);
1846 if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)
1848 dwc_otg_ep0_continue_transfer ( GET_CORE_IF(_pcd), &ep0->dwc_ep );
1849 DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
1850 }else if (ep0->dwc_ep.sent_zlp) {
1851 dwc_otg_ep0_continue_transfer(GET_CORE_IF(_pcd), &ep0->dwc_ep);
1852 ep0->dwc_ep.sent_zlp = 0;
1853 DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
1857 ep0_complete_request( ep0 );
1858 DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
1861 case EP0_OUT_DATA_PHASE:
1863 DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
1864 ep0->dwc_ep.num, (ep0->dwc_ep.is_in ?"IN":"OUT"),
1865 ep0->dwc_ep.type, ep0->dwc_ep.maxpacket );
1867 deptsiz.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[0]->dieptsiz);
1868 ep0->dwc_ep.xfer_count = ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
1869 ep0_complete_request( ep0 );
1874 DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
1875 ep0_complete_request( ep0 );
1876 _pcd->ep0state = EP0_IDLE;
1878 ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
1880 /* Prepare for more SETUP Packets */
1881 if (core_if->dma_enable)
1883 ep0_out_start( core_if, _pcd );
1886 if (!GET_CORE_IF(_pcd)->dma_enable)
1890 depctl_data_t diepctl;
1891 diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[0]->diepctl);
1893 if (_pcd->ep0.queue_sof)
1895 _pcd->ep0.queue_sof = 0;
1896 start_next_request (&_pcd->ep0);
1899 diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[0]->diepctl);
1901 if (_pcd->ep0.queue_sof)
1903 _pcd->ep0.queue_sof = 0;
1904 start_next_request (&_pcd->ep0);
1906 for (i=0; i < core_if->dev_if->num_in_eps; i++)
1908 diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[i+1]->diepctl);
1910 if (_pcd->in_ep[i].queue_sof)
1912 _pcd->in_ep[i].queue_sof = 0;
1913 start_next_request (&_pcd->in_ep[i]);
1920 DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
1924 print_ep0_state(_pcd);
1931 static void restart_transfer( dwc_otg_pcd_t *_pcd, const uint32_t _epnum)
1933 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
1934 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
1935 deptsiz_data_t dieptsiz = {.d32=0};
1936 //depctl_data_t diepctl = {.d32=0};
1937 dwc_otg_pcd_ep_t *ep;
1939 dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[_epnum]->dieptsiz);
1941 ep = get_in_ep(_pcd, _epnum);
1944 ep = &_pcd->in_ep[ _epnum - 1];
1948 DWC_DEBUGPL(DBG_PCD,"xfer_buff=%p xfer_count=%0x xfer_len=%0x"
1949 " stopped=%d\n", ep->dwc_ep.xfer_buff,
1950 ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len ,
1953 * If xfersize is 0 and pktcnt in not 0, resend the last packet.
1955 if ( dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
1956 ep->dwc_ep.start_xfer_buff != 0)
1958 if ( ep->dwc_ep.xfer_len <= ep->dwc_ep.maxpacket )
1960 ep->dwc_ep.xfer_count = 0;
1961 ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
1965 ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
1966 /* convert packet size to dwords. */
1967 ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
1970 DWC_DEBUGPL(DBG_PCD,"xfer_buff=%p xfer_count=%0x "
1971 "xfer_len=%0x stopped=%d\n",
1972 ep->dwc_ep.xfer_buff,
1973 ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len ,
1978 dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
1982 dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
1989 * handle the IN EP disable interrupt.
1991 static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t *_pcd,
1992 const uint32_t _epnum)
1994 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
1995 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
1996 deptsiz_data_t dieptsiz = {.d32=0};
1997 dctl_data_t dctl = {.d32=0};
1998 dwc_otg_pcd_ep_t *ep;
2001 ep = get_in_ep(_pcd, _epnum);
2002 dwc_ep = &ep->dwc_ep;
2006 ep = &_pcd->in_ep[ _epnum - 1];
2007 dwc_ep = &_pcd->in_ep[ _epnum - 1].dwc_ep;
2012 dwc_ep = &_pcd->ep0.dwc_ep;
2015 DWC_DEBUGPL(DBG_PCD,"diepctl%d=%0x\n", _epnum,
2016 dwc_read_reg32(&dev_if->in_ep_regs[_epnum]->diepctl));
2017 dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[_epnum]->dieptsiz);
2019 DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
2021 dieptsiz.b.xfersize );
2025 /* Flush the Tx FIFO */
2026 /** @todo NGS: This is not the correct FIFO */
2027 /* 20091009,HSL@RK,our dwc fifo work at dedicated mode, use 0x10 to flush all , not 0 */
2028 dwc_otg_flush_tx_fifo( core_if, 0x10 );
2030 /* Clear the Global IN NP NAK */
2032 dctl.b.cgnpinnak = 1;
2033 dwc_modify_reg32(&dev_if->dev_global_regs->dctl,
2035 /* Restart the transaction */
2036 if (dieptsiz.b.pktcnt != 0 ||
2037 dieptsiz.b.xfersize != 0)
2039 restart_transfer( _pcd, _epnum );
2044 /* Restart the transaction */
2045 if (dieptsiz.b.pktcnt != 0 ||
2046 dieptsiz.b.xfersize != 0)
2048 restart_transfer( _pcd, _epnum );
2050 DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
2055 * Handler for the IN EP timeout handshake interrupt.
2057 static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t *_pcd,
2058 const uint32_t _epnum)
2060 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
2061 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
2064 deptsiz_data_t dieptsiz = {.d32=0};
2067 dctl_data_t dctl = {.d32=0};
2068 dwc_otg_pcd_ep_t *ep;
2070 gintmsk_data_t intr_mask = {.d32 = 0};
2072 ep = get_in_ep(_pcd, _epnum);
2075 ep = &_pcd->in_ep[ _epnum - 1];
2080 /* Disable the NP Tx Fifo Empty Interrrupt */
2081 if (!core_if->dma_enable)
2083 intr_mask.b.nptxfempty = 1;
2084 dwc_modify_reg32( &core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
2086 /** @todo NGS Check EP type.
2087 * Implement for Periodic EPs */
2091 /* Enable the Global IN NAK Effective Interrupt */
2092 intr_mask.d32 = 0; /* Bug fixed - clear mask b4 reusing */
2093 intr_mask.b.ginnakeff = 1;
2094 dwc_modify_reg32( &core_if->core_global_regs->gintmsk,
2097 /* Set Global IN NAK */
2098 dctl.b.sgnpinnak = 1;
2099 dwc_modify_reg32(&dev_if->dev_global_regs->dctl,
2100 dctl.d32, dctl.d32);
2105 dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz);
2106 DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
2108 dieptsiz.b.xfersize );
2111 #ifdef DISABLE_PERIODIC_EP
2113 * Set the NAK bit for this EP to
2114 * start the disable process.
2118 dwc_modify_reg32(&dev_if->in_ep_regs[epnum]->diepctl, diepctl.d32, diepctl.d32);
2125 * This interrupt indicates that an IN EP has a pending Interrupt.
2126 * The sequence for handling the IN EP interrupt is shown below:
2127 * -# Read the Device All Endpoint Interrupt register
2128 * -# Repeat the following for each IN EP interrupt bit set (from
2130 * -# Read the Device Endpoint Interrupt (DIEPINTn) register
2131 * -# If "Transfer Complete" call the request complete function
2132 * -# If "Endpoint Disabled" complete the EP disable procedure.
2133 * -# If "AHB Error Interrupt" log error
2134 * -# If "Time-out Handshake" log error
2135 * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
2137 * -# If "IN Token EP Mismatch" (disable, this is handled by EP
2138 * Mismatch Interrupt)
2140 static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t *_pcd)
2142 #define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
2144 diepint_data_t diepint = {.d32=0}; \
2145 diepint.b.__intr = 1; \
2146 dwc_write_reg32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
2150 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
2151 dwc_otg_dev_if_t *dev_if = core_if->dev_if;
2152 diepint_data_t diepint = {.d32=0};
2153 depctl_data_t diepctl = {.d32=0};
2156 dwc_otg_pcd_ep_t *ep;
2158 uint32_t _empty_msk, _diepctl;
2159 gintmsk_data_t intr_mask = {.d32 = 0};
2163 DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
2165 /* Read in the device interrupt bits */
2166 ep_intr = dwc_otg_read_dev_all_in_ep_intr( core_if );
2168 /* Service the Device IN interrupts for each endpoint */
2175 /* Get EP pointer */
2176 ep = get_in_ep(_pcd, epnum);
2178 DWC_PRINT("%s epnum %d epintr %x\n", __func__, epnum, ep_intr);
2181 dwc_ep = &ep->dwc_ep;
2183 _diepctl = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl);
2184 _empty_msk = dwc_read_reg32(&dev_if->dev_global_regs->dtknqr4_fifoemptymsk);
2186 DWC_DEBUGPL(DBG_PCDV, "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",epnum, _empty_msk, _diepctl);
2188 DWC_DEBUGPL(DBG_PCD,
2189 "EP%d-%s: type=%d, mps=%d\n",
2190 dwc_ep->num, (dwc_ep->is_in ?"IN":"OUT"),
2191 dwc_ep->type, dwc_ep->maxpacket );
2193 diepint.d32 = dwc_otg_read_dev_in_ep_intr( core_if, dwc_ep );
2195 DWC_DEBUGPL(DBG_PCDV, "EP %d Interrupt Register - 0x%x\n", epnum, diepint.d32);
2196 /* Transfer complete */
2197 if ( diepint.b.xfercompl )
2200 DWC_DEBUGPL(DBG_PCD,"EP%d IN Xfer Complete\n", epnum);
2202 /* Disable the NP Tx FIFO Empty
2204 if(core_if->en_multiple_tx_fifo == 0)
2206 intr_mask.b.nptxfempty = 1;
2207 dwc_modify_reg32( &core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
2211 /* Disable the Tx FIFO Empty Interrupt for this EP */
2212 uint32_t fifoemptymsk = 0x1 << dwc_ep->num;
2213 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
2216 /* Clear the bit in DIEPINTn for this interrupt */
2217 CLEAR_IN_EP_INTR(core_if,epnum,xfercompl);
2219 /* Complete the transfer */
2229 /* Endpoint disable */
2230 if ( diepint.b.epdisabled )
2232 DWC_DEBUGPL(DBG_ANY,"EP%d IN disabled\n", epnum);
2233 handle_in_ep_disable_intr( _pcd, epnum );
2235 /* Clear the bit in DIEPINTn for this interrupt */
2236 CLEAR_IN_EP_INTR(core_if,epnum,epdisabled);
2239 if ( diepint.b.ahberr )
2241 DWC_DEBUGPL(DBG_ANY,"EP%d IN AHB Error\n", epnum);
2242 /* Clear the bit in DIEPINTn for this interrupt */
2243 CLEAR_IN_EP_INTR(core_if,epnum,ahberr);
2245 /* TimeOUT Handshake (non-ISOC IN EPs) */
2246 if ( diepint.b.timeout )
2248 DWC_DEBUGPL(DBG_ANY,"EP%d IN Time-out\n", epnum);
2249 handle_in_ep_timeout_intr( _pcd, epnum );
2251 CLEAR_IN_EP_INTR(core_if,epnum,timeout);
2253 /** IN Token received with TxF Empty */
2254 if (diepint.b.intktxfemp)
2256 DWC_DEBUGPL(DBG_ANY,"EP%d IN TKN TxFifo Empty\n",
2258 if (!ep->stopped && epnum != 0)
2260 diepmsk_data_t diepmsk = { .d32 = 0};
2261 diepmsk.b.intktxfemp = 1;
2262 dwc_modify_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32, 0 );
2263 start_next_request(ep);
2265 CLEAR_IN_EP_INTR(core_if,epnum,intktxfemp);
2267 /** IN Token Received with EP mismatch */
2268 if (diepint.b.intknepmis)
2270 DWC_DEBUGPL(DBG_ANY,"EP%d IN TKN EP Mismatch\n", epnum);
2271 CLEAR_IN_EP_INTR(core_if,epnum,intknepmis);
2273 /** IN Endpoint NAK Effective */
2274 if (diepint.b.inepnakeff)
2276 DWC_DEBUGPL(DBG_ANY,"EP%d IN EP NAK Effective\n", epnum);
2282 diepctl.b.epdis = 1;
2283 dwc_modify_reg32(&dev_if->in_ep_regs[epnum]->diepctl, diepctl.d32, diepctl.d32);
2285 CLEAR_IN_EP_INTR(core_if,epnum,inepnakeff);
2289 /** IN EP Tx FIFO Empty Intr */
2290 if (diepint.b.emptyintr)
2292 DWC_DEBUGPL(DBG_ANY,"EP%d Tx FIFO Empty Intr \n", epnum);
2293 write_empty_tx_fifo(_pcd, epnum);
2295 CLEAR_IN_EP_INTR(core_if,epnum,emptyintr);
2304 #undef CLEAR_IN_EP_INTR
2308 * This interrupt indicates that an OUT EP has a pending Interrupt.
2309 * The sequence for handling the OUT EP interrupt is shown below:
2310 * -# Read the Device All Endpoint Interrupt register
2311 * -# Repeat the following for each OUT EP interrupt bit set (from
2313 * -# Read the Device Endpoint Interrupt (DOEPINTn) register
2314 * -# If "Transfer Complete" call the request complete function
2315 * -# If "Endpoint Disabled" complete the EP disable procedure.
2316 * -# If "AHB Error Interrupt" log error
2317 * -# If "Setup Phase Done" process Setup Packet (See Standard USB
2318 * Command Processing)
2320 static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t *_pcd)
2322 #define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
2324 doepint_data_t doepint = {.d32=0}; \
2325 doepint.b.__intr = 1; \
2326 dwc_write_reg32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
2330 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
2332 doepint_data_t doepint = {.d32=0};
2336 DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
2338 /* Read in the device interrupt bits */
2339 ep_intr = dwc_otg_read_dev_all_out_ep_intr( core_if );
2340 // dwc_otg_dump_dev_registers(core_if);
2346 /* Get EP pointer */
2347 dwc_ep = &((get_out_ep(_pcd, epnum))->dwc_ep);
2348 // dwc_ep = &_pcd->out_ep[ epnum - 1].dwc_ep;
2351 DWC_DEBUGPL(DBG_PCDV,
2352 "EP%d-%s: type=%d, mps=%d\n",
2353 dwc_ep->num, (dwc_ep->is_in ?"IN":"OUT"),
2354 dwc_ep->type, dwc_ep->maxpacket );
2356 doepint.d32 = dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
2358 /* Transfer complete */
2359 if ( doepint.b.xfercompl )
2361 DWC_DEBUGPL(DBG_PCD,"EP%d OUT Xfer Complete\n",
2364 /* Clear the bit in DOEPINTn for this interrupt */
2365 CLEAR_OUT_EP_INTR(core_if,epnum,xfercompl);
2373 complete_ep( get_out_ep(_pcd, epnum) );
2374 // complete_ep( &_pcd->out_ep[ epnum - 1] );
2377 /* Endpoint disable */
2378 if ( doepint.b.epdisabled )
2380 DWC_DEBUGPL(DBG_PCD,"EP%d OUT disabled\n", epnum);
2381 /* Clear the bit in DOEPINTn for this interrupt */
2382 CLEAR_OUT_EP_INTR(core_if,epnum,epdisabled);
2385 if ( doepint.b.ahberr )
2387 DWC_DEBUGPL(DBG_PCD,"EP%d OUT AHB Error\n", epnum);
2388 DWC_DEBUGPL(DBG_PCD,"EP DMA REG %d \n", core_if->dev_if->out_ep_regs[epnum]->doepdma);
2389 CLEAR_OUT_EP_INTR(core_if,epnum,ahberr);
2391 /* Setup Phase Done (contorl EPs) */
2392 if ( doepint.b.setup )
2395 DWC_DEBUGPL(DBG_PCD,"EP%d SETUP Done\n",
2399 CLEAR_OUT_EP_INTR(core_if,epnum,setup);
2408 #undef CLEAR_OUT_EP_INTR
2412 * Incomplete ISO IN Transfer Interrupt.
2413 * This interrupt indicates one of the following conditions occurred
2414 * while transmitting an ISOC transaction.
2415 * - Corrupted IN Token for ISOC EP.
2416 * - Packet not complete in FIFO.
2417 * The follow actions will be taken:
2418 * -# Determine the EP
2419 * -# Set incomplete flag in dwc_ep structure
2420 * -# Disable EP; when "Endpoint Disabled" interrupt is received
2423 int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t *_pcd)
2425 gintmsk_data_t intr_mask = { .d32 = 0};
2426 gintsts_data_t gintsts;
2427 DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
2428 "IN ISOC Incomplete");
2430 intr_mask.b.incomplisoin = 1;
2431 dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
2434 /* Clear interrupt */
2436 gintsts.b.incomplisoin = 1;
2437 dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
2444 * Incomplete ISO OUT Transfer Interrupt.
2446 * This interrupt indicates that the core has dropped an ISO OUT
2447 * packet. The following conditions can be the cause:
2448 * - FIFO Full, the entire packet would not fit in the FIFO.
2451 * The follow actions will be taken:
2452 * -# Determine the EP
2453 * -# Set incomplete flag in dwc_ep structure
2454 * -# Read any data from the FIFO
2455 * -# Disable EP. when "Endpoint Disabled" interrupt is received
2458 int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t *_pcd)
2460 /** @todo implement ISR */
2461 gintmsk_data_t intr_mask = { .d32 = 0};
2462 gintsts_data_t gintsts;
2463 DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
2464 "OUT ISOC Incomplete");
2466 intr_mask.b.incomplisoout = 1;
2467 dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
2470 /* Clear interrupt */
2472 gintsts.b.incomplisoout = 1;
2473 dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
2480 * This function handles the Global IN NAK Effective interrupt.
2483 int32_t dwc_otg_pcd_handle_in_nak_effective( dwc_otg_pcd_t *_pcd )
2485 dwc_otg_dev_if_t *dev_if = GET_CORE_IF(_pcd)->dev_if;
2486 depctl_data_t diepctl = { .d32 = 0};
2487 depctl_data_t diepctl_rd = { .d32 = 0};
2488 gintmsk_data_t intr_mask = { .d32 = 0};
2489 gintsts_data_t gintsts;
2492 DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
2494 /* Disable all active IN EPs */
2495 diepctl.b.epdis = 1;
2498 for (i=0; i <= dev_if->num_in_eps; i++)
2500 diepctl_rd.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
2501 if (diepctl_rd.b.epena)
2503 dwc_write_reg32( &dev_if->in_ep_regs[i]->diepctl,
2507 /* Disable the Global IN NAK Effective Interrupt */
2508 intr_mask.b.ginnakeff = 1;
2509 dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
2512 /* Clear interrupt */
2514 gintsts.b.ginnakeff = 1;
2515 dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
2522 * OUT NAK Effective.
2525 int32_t dwc_otg_pcd_handle_out_nak_effective( dwc_otg_pcd_t *_pcd )
2527 gintmsk_data_t intr_mask = { .d32 = 0};
2528 gintsts_data_t gintsts;
2530 DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
2531 "Global IN NAK Effective\n");
2532 /* Disable the Global IN NAK Effective Interrupt */
2533 intr_mask.b.goutnakeff = 1;
2534 dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
2537 /* Clear interrupt */
2539 gintsts.b.goutnakeff = 1;
2540 dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
2548 * PCD interrupt handler.
2550 * The PCD handles the device interrupts. Many conditions can cause a
2551 * device interrupt. When an interrupt occurs, the device interrupt
2552 * service routine determines the cause of the interrupt and
2553 * dispatches handling to the appropriate function. These interrupt
2554 * handling functions are described below.
2556 * All interrupt registers are processed from LSB to MSB.
2559 int32_t dwc_otg_pcd_handle_intr( dwc_otg_pcd_t *_pcd )
2561 dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
2563 dwc_otg_core_global_regs_t *global_regs =
2564 core_if->core_global_regs;
2566 gintsts_data_t gintr_status;
2570 DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
2572 dwc_read_reg32( &global_regs->gintsts),
2573 dwc_read_reg32( &global_regs->gintmsk));
2576 if (dwc_otg_is_device_mode(core_if))
2578 SPIN_LOCK(&_pcd->lock);
2580 DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
2582 dwc_read_reg32( &global_regs->gintsts),
2583 dwc_read_reg32( &global_regs->gintmsk));
2586 gintr_status.d32 = dwc_otg_read_core_intr(core_if);
2587 if (!gintr_status.d32)
2589 SPIN_UNLOCK(&_pcd->lock);
2592 DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
2593 __func__, gintr_status.d32 );
2595 if (gintr_status.b.sofintr)
2597 retval |= dwc_otg_pcd_handle_sof_intr( _pcd );
2599 if (gintr_status.b.rxstsqlvl)
2601 retval |= dwc_otg_pcd_handle_rx_status_q_level_intr( _pcd );
2603 if (gintr_status.b.nptxfempty)
2605 retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr( _pcd );
2607 if (gintr_status.b.ginnakeff)
2609 retval |= dwc_otg_pcd_handle_in_nak_effective( _pcd );
2611 if (gintr_status.b.goutnakeff)
2613 retval |= dwc_otg_pcd_handle_out_nak_effective( _pcd );
2615 if (gintr_status.b.i2cintr)
2617 retval |= dwc_otg_pcd_handle_i2c_intr( _pcd );
2619 if (gintr_status.b.erlysuspend)
2621 retval |= dwc_otg_pcd_handle_early_suspend_intr( _pcd );
2623 if (gintr_status.b.usbreset)
2625 retval |= dwc_otg_pcd_handle_usb_reset_intr( _pcd );
2626 _pcd->conn_status = -1;
2628 if (gintr_status.b.enumdone)
2630 retval |= dwc_otg_pcd_handle_enum_done_intr( _pcd );
2632 if (gintr_status.b.isooutdrop)
2634 retval |= dwc_otg_pcd_handle_isoc_out_packet_dropped_intr( _pcd );
2636 if (gintr_status.b.eopframe)
2638 retval |= dwc_otg_pcd_handle_end_periodic_frame_intr( _pcd );
2640 if (gintr_status.b.epmismatch)
2642 retval |= dwc_otg_pcd_handle_ep_mismatch_intr( core_if );
2644 if (gintr_status.b.inepint)
2646 retval |= dwc_otg_pcd_handle_in_ep_intr( _pcd );
2648 if (gintr_status.b.outepintr)
2650 retval |= dwc_otg_pcd_handle_out_ep_intr( _pcd );
2652 if (gintr_status.b.incomplisoin)
2654 retval |= dwc_otg_pcd_handle_incomplete_isoc_in_intr( _pcd );
2656 if (gintr_status.b.incomplisoout)
2658 retval |= dwc_otg_pcd_handle_incomplete_isoc_out_intr( _pcd );
2661 DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
2662 dwc_read_reg32( &global_regs->gintsts));
2664 SPIN_UNLOCK(&_pcd->lock);
2669 #endif /* DWC_HOST_ONLY */