Index: dwc_otg.c =================================================================== --- dwc_otg.c (revision 244665) +++ dwc_otg.c (working copy) @@ -62,10 +62,15 @@ #include #include #include +#include +#include +#include #include #include +#define DWC_OTG_USE_DMA +//#undef DWC_OTG_USE_DMA #define USB_DEBUG_VAR dwc_otg_debug #include @@ -110,7 +115,7 @@ TUNABLE_INT("hw.usb.dwc_otg.use_hsic", &dwc_otg_use_hsic); #ifdef USB_DEBUG -static int dwc_otg_debug; +static int dwc_otg_debug = 0; SYSCTL_INT(_hw_usb_dwc_otg, OID_AUTO, debug, CTLFLAG_RW, &dwc_otg_debug, 0, "DWC OTG debug level"); @@ -218,13 +223,19 @@ (tx_start / 4)); for (x = 0; x != sc->sc_host_ch_max; x++) { +#ifdef DWC_OTG_USE_DMA /* enable interrupts */ DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x), + HCINT_CHHLTD); +#else + /* enable interrupts */ + DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x), HCINT_STALL | HCINT_BBLERR | HCINT_XACTERR | HCINT_NAK | HCINT_ACK | HCINT_NYET | HCINT_CHHLTD | HCINT_FRMOVRUN | HCINT_DATATGLERR); +#endif } /* enable host channel interrupts */ @@ -489,6 +500,7 @@ static void dwc_otg_common_rx_ack(struct dwc_otg_softc *sc) { +#ifndef DWC_OTG_USE_DMA DPRINTFN(5, "RX status clear\n"); /* enable RX FIFO level interrupt */ @@ -497,6 +509,7 @@ /* clear cached status */ sc->sc_last_rx_status = 0; +#endif } static void @@ -595,7 +608,6 @@ } for (; x != max_channel; x++) { - if (sc->sc_chan_state[x].allocated) continue; if (sc->sc_chan_state[x].wait_sof != 0) @@ -687,6 +699,9 @@ hcint = sc->sc_chan_state[td->channel].hcint; + if (td->state == DWC_CHAN_ST_START) + goto check_state; + DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", td->channel, td->state, hcint, DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)), @@ -720,6 +735,7 @@ td->errcnt = 0; } +check_state: switch (td->state) { case DWC_CHAN_ST_START: goto send_pkt; @@ -808,7 +824,6 @@ td->state = DWC_CHAN_ST_WAIT_ANE; } - usbd_copy_out(td->pc, 0, &req, sizeof(req)); DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), (sizeof(req) << HCTSIZ_XFERSIZE_SHIFT) | @@ -817,16 +832,27 @@ DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); +#ifdef DWC_OTG_USE_DMA + struct usb_page_search buf_res; + usbd_get_page(td->pc, 0, &buf_res); + usb_pc_cpu_flush(td->pc); + if (buf_res.physaddr & 3) + panic("Non-aligned physaddr"); + DWC_OTG_WRITE_4(sc, DOTG_HCDMA(td->channel), buf_res.physaddr); +#endif + hcchar = td->hcchar; hcchar &= ~HCCHAR_EPDIR_IN; /* must enable channel before writing data to FIFO */ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); +#ifndef DWC_OTG_USE_DMA + usbd_copy_out(td->pc, 0, &req, sizeof(req)); /* transfer data into FIFO */ bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl, DOTG_DFIFO(td->channel), (uint32_t *)&req, sizeof(req) / 4); - +#endif /* store number of bytes transmitted */ td->tx_bytes = sizeof(req); @@ -1006,8 +1032,10 @@ uint8_t delta; delta = sc->sc_tmr_val - td->tmr_val; - if (delta >= 128) + if (delta >= 128) { + goto busy; + } td->tmr_val = sc->sc_tmr_val + td->tmr_res; } else if (td->did_nak != 0) { goto busy; @@ -1030,8 +1058,12 @@ struct dwc_otg_softc *sc; uint32_t hcint; uint32_t hcchar; +#ifdef DWC_OTG_USE_DMA + uint32_t hctsiz; +#endif uint32_t count; uint8_t ep_type; + int in_data; if (dwc_otg_host_channel_alloc(td)) return (1); /* busy */ @@ -1044,11 +1076,19 @@ hcint = sc->sc_chan_state[td->channel].hcint; + if (td->state == DWC_CHAN_ST_START) + goto check_state; + DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", td->channel, td->state, hcint, DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)), DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel))); +#ifdef DWC_OTG_USE_DMA + if (!(hcint & HCINT_CHHLTD)) + goto busy; +#endif + /* check interrupt bits */ if (hcint & (HCINT_RETRY | @@ -1058,16 +1098,36 @@ DPRINTF("CH=%d STALL\n", td->channel); td->error_stall = 1; td->error_any = 1; - return (0); /* complete */ + goto complete; /* complete */ } else if (hcint & HCINT_ERRORS) { DPRINTF("CH=%d ERROR\n", td->channel); td->errcnt++; if (td->hcsplt != 0 || td->errcnt >= 3) { td->error_any = 1; - return (0); /* complete */ + goto complete; /* complete */ } } +#ifdef DWC_OTG_USE_DMA + if (((ep_type == UE_BULK) || (ep_type == UE_CONTROL)) && + (hcint & HCINT_NAK)) { + /* + * NAK clears error for bulk/control transfers + * in DMA mode + */ + if (td->hcsplt == 0) { + td->errcnt = 0; + hcint &= ~HCINT_NAK; + sc->sc_chan_state[td->channel].hcint = hcint; + uint32_t hcintmsk = DWC_OTG_READ_4(sc, + DOTG_HCINTMSK(td->channel)); + hcintmsk &= ~HCINT_NAK; + DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(td->channel), + hcintmsk); + } + } +#endif + /* channel must be disabled before we can complete the transfer */ if (hcint & (HCINT_ERRORS | HCINT_RETRY | @@ -1079,6 +1139,24 @@ td->errcnt = 0; } + in_data = 0; + count = 0; + +#ifdef DWC_OTG_USE_DMA + if (hcint == 0) + goto check_state; + + if (td->state != DWC_CHAN_ST_WAIT_S_ANE) { + in_data = 1; + hctsiz = DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel)); + count = (hctsiz >> HCTSIZ_XFERSIZE_SHIFT) & HCTSIZ_XFERSIZE_MASK; + count = td->max_packet_size - count; + usb_pc_cpu_invalidate(td->pc); + } + else + in_data = 0; + +#else /* check endpoint status */ if (sc->sc_last_rx_status == 0) goto check_state; @@ -1086,6 +1164,7 @@ if (GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) != td->channel) goto check_state; + in_data = 0; switch (sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) { case GRXSTSRH_IN_DATA: @@ -1101,11 +1180,20 @@ break; } - td->toggle ^= 1; - /* get the packet byte count */ count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status); + in_data = 1; + default: + DPRINTF("OTHER\n"); + break; + } + +#endif + + if (in_data) { + td->toggle ^= 1; + /* verify the packet byte count */ if (count != td->max_packet_size) { if (count < td->max_packet_size) { @@ -1118,7 +1206,7 @@ /* release FIFO */ dwc_otg_common_rx_ack(sc); - return (0); /* we are complete */ + goto complete; /* we are complete */ } } @@ -1129,22 +1217,21 @@ /* release FIFO */ dwc_otg_common_rx_ack(sc); - return (0); /* we are complete */ + goto complete; /* we are complete */ } + +#ifndef DWC_OTG_USE_DMA usbd_copy_in(td->pc, td->offset, sc->sc_rx_bounce_buffer, count); +#endif td->remainder -= count; td->offset += count; hcint |= HCINT_SOFTWARE_ONLY | HCINT_ACK; sc->sc_chan_state[td->channel].hcint = hcint; - break; + } - default: - DPRINTF("OTHER\n"); - break; - } /* release FIFO */ dwc_otg_common_rx_ack(sc); @@ -1184,7 +1271,7 @@ /* check if we are complete */ if ((td->remainder == 0) || (td->got_short != 0)) { if (td->short_pkt) - return (0); /* complete */ + goto complete; /* complete */ /* * Else need to receive a zero length @@ -1260,6 +1347,16 @@ (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); +#ifdef DWC_OTG_USE_DMA + { + struct usb_page_search buf_res; + usbd_get_page(td->pc, td->offset, &buf_res); + if (buf_res.physaddr & 3) + panic("Non-aligned physaddr"); + DWC_OTG_WRITE_4(sc, DOTG_HCDMA(td->channel), buf_res.physaddr); + } +#endif + DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); hcchar = td->hcchar; @@ -1317,6 +1414,17 @@ DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); +#ifdef DWC_OTG_USE_DMA + { + struct usb_page_search buf_res; + usbd_get_page(td->pc, td->offset, &buf_res); + usb_pc_cpu_invalidate(td->pc); + if (buf_res.physaddr & 3) + panic("Non-aligned physaddr"); + DWC_OTG_WRITE_4(sc, DOTG_HCDMA(td->channel), buf_res.physaddr); + } +#endif + hcchar = td->hcchar; hcchar |= HCCHAR_EPDIR_IN; @@ -1325,6 +1433,11 @@ busy: return (1); /* busy */ +complete: +#ifdef DWC_OTG_USE_DMA + usb_pc_cpu_invalidate(td->pc); +#endif + return (0); } static uint8_t @@ -1447,6 +1560,7 @@ uint32_t count; uint32_t hcint; uint32_t hcchar; + uint32_t hctsiz; uint8_t ep_type; if (dwc_otg_host_channel_alloc(td)) @@ -1460,11 +1574,19 @@ hcint = sc->sc_chan_state[td->channel].hcint; + if (td->state == DWC_CHAN_ST_START) + goto check_state; + DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", td->channel, td->state, hcint, DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)), DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel))); +#ifdef DWC_OTG_USE_DMA + if (!(hcint & HCINT_CHHLTD)) + goto busy; +#endif + if (hcint & (HCINT_RETRY | HCINT_ACK | HCINT_NYET)) { /* give success bits priority over failure bits */ @@ -1493,6 +1615,7 @@ td->errcnt = 0; } +check_state: switch (td->state) { case DWC_CHAN_ST_START: goto send_pkt; @@ -1584,6 +1707,7 @@ send_pkt: if (dwc_otg_host_rate_check(td)) { + printf("BUSY!!!!!!!!!!!!!!\n"); td->state = DWC_CHAN_ST_TX_PKT; dwc_otg_host_channel_free(td); goto busy; @@ -1616,27 +1740,46 @@ count = td->remainder; } - /* TODO: HCTSIZ_DOPNG */ - - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), - (count << HCTSIZ_XFERSIZE_SHIFT) | + hctsiz = (count << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : - (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); + (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)); + +#ifdef DWC_OTG_USE_DMA + if (ep_type == UE_BULK) { + hctsiz |= HCTSIZ_DOPNG; + } +#endif + + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), hctsiz); DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); +#ifdef DWC_OTG_USE_DMA + if (count != 0) { + + struct usb_page_search buf_res; + usbd_get_page(td->pc, td->offset, &buf_res); + usb_pc_cpu_flush(td->pc); + if (buf_res.physaddr & 3) + panic("Non-aligned physaddr"); + + DWC_OTG_WRITE_4(sc, DOTG_HCDMA(td->channel), buf_res.physaddr); + } +#endif + hcchar = td->hcchar; hcchar &= ~HCCHAR_EPDIR_IN; /* must enable before writing data to FIFO */ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); +#ifndef DWC_OTG_USE_DMA if (count != 0) { - /* clear topmost word before copy */ sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0; + /* copy out data */ usbd_copy_out(td->pc, td->offset, sc->sc_tx_bounce_buffer, count); @@ -1646,6 +1789,7 @@ DOTG_DFIFO(td->channel), sc->sc_tx_bounce_buffer, (count + 3) / 4); } +#endif /* store number of bytes transmitted */ td->tx_bytes = count; @@ -2043,7 +2187,9 @@ { struct usb_xfer *xfer; uint32_t temp; +#ifndef DWC_OTG_USE_DMA uint8_t got_rx_status; +#endif uint8_t x; repeat: @@ -2057,6 +2203,7 @@ } } +#ifndef DWC_OTG_USE_DMA if (sc->sc_last_rx_status == 0) { temp = DWC_OTG_READ_4(sc, DOTG_GINTSTS); @@ -2123,6 +2270,7 @@ got_rx_status = 1; } +#endif TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { if (!dwc_otg_xfer_do_fifo(xfer)) { @@ -2131,6 +2279,7 @@ } } +#ifndef DWC_OTG_USE_DMA if (got_rx_status) { /* check if data was consumed */ if (sc->sc_last_rx_status == 0) @@ -2140,6 +2289,7 @@ sc->sc_irq_mask &= ~GINTSTS_RXFLVL; DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); } +#endif } static void @@ -2416,8 +2566,8 @@ uint8_t need_sync; uint8_t is_host; - DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpointno), + DPRINTFN(9, "xfer=%p addr=%d endpt=%d sumlen=%d speed=%d\n", + xfer, xfer->address, UE_GET_ADDR(xfer->endpointno), xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); temp.max_frame_size = xfer->max_frame_size; @@ -3068,6 +3218,7 @@ dwc_otg_init(struct dwc_otg_softc *sc) { uint32_t temp; + uint32_t ahbcfg; DPRINTF("start\n"); @@ -3218,9 +3369,12 @@ DWC_OTG_WRITE_4(sc, DOTG_HCFG, temp); } + ahbcfg = GAHBCFG_GLBLINTRMSK; +#ifdef DWC_OTG_USE_DMA + ahbcfg |= GAHBCFG_DMAEN; +#endif /* only enable global IRQ */ - DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG, - GAHBCFG_GLBLINTRMSK); + DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG, ahbcfg); /* turn off clocks */ dwc_otg_clocks_off(sc); @@ -3989,6 +4143,9 @@ parm->hc_max_packet_size = 0x500; parm->hc_max_packet_count = 1; parm->hc_max_frame_size = 0x500; +#ifdef DWC_OTG_USE_DMA + xfer->flags_int.bdma_enable = 1; +#endif usbd_transfer_setup_sub(parm);