Hello. On 12-01-2011 13:53, Felipe Balbi wrote:
Hi Sergei,
on DaVinci is extremely necessary to program EP CSR before channel_program() ?
Frankly speaking, I don't know. At least the DaVinci USB manuals have it this way.
I believe it's not a problem for the OMAP-based board and I doubt it's a problem for Blackfin too.
I think it would be easy to drop all the DMA magic if we figure out a way to program DMA that works for all engines. Possibly following what MUSB docs say would be enough:
. Program EP CSR . Program DMA ADDR and COUNT . Program DMA Control
So it would be something like:
From 586d9ea1b0417640877c201fdb88d2d555b8c174 Mon Sep 17 00:00:00 2001 From: Felipe Balbi<balbi@xxxxxx> Date: Wed, 12 Jan 2011 12:50:24 +0200 Subject: [PATCH] usb: musb: gadget: drop DMA ifdeffery Organization: Texas Instruments\n
MUSB DMA programming can be done in a simpler way if we drop all the DMA magic.
NYET-Signed-off-by: Felipe Balbi<balbi@xxxxxx> ---
Completely untested, just looking at the code. Didn't even compile this one.
drivers/usb/musb/musb_gadget.c | 149 +++++++++------------------------------ 1 files changed, 35 insertions(+), 114 deletions(-)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9b162df..d6aca24 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -347,87 +347,53 @@ static void txstate(struct musb *musb, struct musb_request *req) /* MUSB_TXCSR_P_ISO is still set correctly */ -#ifdef CONFIG_USB_INVENTRA_DMA - { - if (request_size < musb_ep->packet_sz) - musb_ep->dma->desired_mode = 0; - else - musb_ep->dma->desired_mode = 1; - - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - musb_ep->dma->desired_mode, - request->dma + request->actual, request_size); - if (use_dma) { - if (musb_ep->dma->desired_mode == 0) { - /* - * We must not clear the DMAMODE bit - * before the DMAENAB bit -- and the - * latter doesn't always get cleared - * before we get here... - */ - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB); - musb_writew(epio, MUSB_TXCSR, csr - | MUSB_TXCSR_P_WZC_BITS); - csr &= ~MUSB_TXCSR_DMAMODE; - csr |= (MUSB_TXCSR_DMAENAB | - MUSB_TXCSR_MODE); - /* against programming guide */ - } else { - csr |= (MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_MODE); - if (!musb_ep->hb_mult) - csr |= MUSB_TXCSR_AUTOSET; - } - csr&= ~MUSB_TXCSR_P_UNDERRUN; + if (request_size < musb_ep->packet_sz) + musb_ep->dma->desired_mode = 0; + else + musb_ep->dma->desired_mode = 1; - musb_writew(epio, MUSB_TXCSR, csr); - } + if (musb_ep->dma->desired_mode == 0) { + /* + * We must not clear the DMAMODE bit + * before the DMAENAB bit -- and the + * latter doesn't always get cleared + * before we get here... + */ + csr &= ~(MUSB_TXCSR_AUTOSET + | MUSB_TXCSR_DMAENAB); + musb_writew(epio, MUSB_TXCSR, csr + | MUSB_TXCSR_P_WZC_BITS); + csr &= ~MUSB_TXCSR_DMAMODE; + csr |= (MUSB_TXCSR_DMAENAB | + MUSB_TXCSR_MODE); + /* against programming guide */ + } else { + csr |= (MUSB_TXCSR_DMAENAB + | MUSB_TXCSR_DMAMODE + | MUSB_TXCSR_MODE); + if (!musb_ep->hb_mult) + csr |= MUSB_TXCSR_AUTOSET;
This bit is reserved on DaVinci, though probably setting it is safe...
} + csr &= ~MUSB_TXCSR_P_UNDERRUN; -#elif defined(CONFIG_USB_TI_CPPI_DMA) - /* program endpoint CSR first, then setup DMA */ - csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); - csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | - MUSB_TXCSR_MODE; - musb_writew(epio, MUSB_TXCSR, - (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) - | csr); - - /* ensure writebuffer is empty */ - csr = musb_readw(epio, MUSB_TXCSR); - - /* NOTE host side sets DMAENAB later than this; both are - * OK since the transfer dma glue (between CPPI and Mentor - * fifos) just tells CPPI it could start. Data only moves - * to the USB TX fifo when both fifos are ready. - */ + musb_writew(epio, MUSB_TXCSR, csr); - /* "mode" is irrelevant here; handle terminating ZLPs like - * PIO does, since the hardware RNDIS mode seems unreliable - * except for the last-packet-is-already-short case. - */ use_dma = use_dma && c->channel_program( musb_ep->dma, musb_ep->packet_sz, - 0, - request->dma + request->actual, - request_size); + musb_ep->dma->desired_mode,
Well, as the 'mode' is irrelevant for CPPI's Tx side and tusb6010_omap.c seems to ignore the mode altogether, this should work...
+ request->dma + request->actual, request_size); if (!use_dma) { c->channel_release(musb_ep->dma); musb_ep->dma = NULL; csr &= ~MUSB_TXCSR_DMAENAB; musb_writew(epio, MUSB_TXCSR, csr); - /* invariant: prequest->buf is non-null */ + + /* Case we enabled mode1 DMA, disable it */
In case?
+ if (musb_ep->dma->desired_mode) { + csr &= ~MUSB_TXCSR_DMAMODE; + musb_writew(epio, MUSB_TXCSR, csr); + } } -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - request->zero, - request->dma + request->actual, - request_size); -#endif } #endif @@ -627,37 +593,9 @@ static void rxstate(struct musb *musb, struct musb_request *req) return; } - if (is_cppi_enabled() && musb_ep->dma) { - struct dma_controller *c = musb->dma_controller; - struct dma_channel *channel = musb_ep->dma; - - /* NOTE: CPPI won't actually stop advancing the DMA - * queue after short packet transfers, so this is almost - * always going to run as IRQ-per-packet DMA so that - * faults will be handled correctly. - */ - if (c->channel_program(channel, - musb_ep->packet_sz, - !request->short_not_ok, - request->dma + request->actual, - request->length - request->actual)) { - - /* make sure that if an rxpkt arrived after the irq, - * the cppi engine will be ready to take it as soon - * as DMA is enabled - */ - csr &= ~(MUSB_RXCSR_AUTOCLEAR - | MUSB_RXCSR_DMAMODE); - csr |= MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_WZC_BITS; - musb_writew(epio, MUSB_RXCSR, csr); - return; - } - } - if (csr & MUSB_RXCSR_RXPKTRDY) { len = musb_readw(epio, MUSB_RXCOUNT); if (request->actual < request->length) { -#ifdef CONFIG_USB_INVENTRA_DMA if (is_dma_capable() && musb_ep->dma) { struct dma_controller *c; struct dma_channel *channel;
Here we have the following:
int use_dma = 0; c = musb->dma_controller; channel = musb_ep->dma; /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in * mode 0 only. So we do not get endpoint interrupts due to DMA * completion. We only get interrupts from DMA controller. * * We could operate in DMA mode 1 if we knew the size of the tranfer * in advance. For mass storage class, request->length = what the host * sends, so that'd work. But for pretty much everything else, * request->length is routinely more than what the host sends. For * most these gadgets, end of is signified either by a short packet, * or filling the last byte of the buffer. (Sending extra data in * that last pckate should trigger an overflow fault.) But in mode 1, * we don't get DMA completion interrrupt for short packets. * * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1), * to get endpoint interrupt on every DMA req, but that didn't seem * to work reliably. * * REVISIT an updated g_file_storage can set req->short_not_ok, which * then becomes usable as a runtime "use mode 1" hint... */ csr |= MUSB_RXCSR_DMAENAB; #ifdef USE_MODE1 csr |= MUSB_RXCSR_AUTOCLEAR;
This bit is reserved on DaVinci, though setting it probably is safe...
/* csr |= MUSB_RXCSR_DMAMODE; */ /* this special sequence (enabling and then * disabling MUSB_RXCSR_DMAMODE) is required * to get DMAReq to activate */ musb_writew(epio, MUSB_RXCSR, csr | MUSB_RXCSR_DMAMODE); #else if (!musb_ep->hb_mult && musb_ep->hw_ep->rx_double_buffered) csr |= MUSB_RXCSR_AUTOCLEAR;
Ditto.
#endif musb_writew(epio, MUSB_RXCSR, csr); if (request->actual < request->length) { int transfer_size = 0; #ifdef USE_MODE1 transfer_size = min(request->length - request->actual, channel->max_len); #else transfer_size = min(request->length - request->actual, (unsigned)len);
Transferring data by single packet is not effective on DaVinci.
#endif if (transfer_size <= musb_ep->packet_sz) musb_ep->dma->desired_mode = 0; else musb_ep->dma->desired_mode = 1; use_dma = c->channel_program( channel, musb_ep->packet_sz, channel->desired_mode,
So the mode will effectively be 0... this will probably work for DaVinci too. TUSB case is indifferent to mode anyway...
request->dma + request->actual, transfer_size); }
@@ -731,7 +669,6 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (use_dma) return; } -#endif /* Mentor's DMA */ fifo_count = request->length - request->actual; DBG(3, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", @@ -741,22 +678,6 @@ static void rxstate(struct musb *musb, struct musb_request *req) fifo_count = min_t(unsigned, len, fifo_count); -#ifdef CONFIG_USB_TUSB_OMAP_DMA - if (tusb_dma_omap() && musb_ep->dma) { - struct dma_controller *c = musb->dma_controller; - struct dma_channel *channel = musb_ep->dma; - u32 dma_addr = request->dma + request->actual; - int ret; - - ret = c->channel_program(channel, - musb_ep->packet_sz, - channel->desired_mode,
Hm, where it is set, I wonder? Though it doesn't mater anyway. :-)
- dma_addr, - fifo_count); - if (ret) - return; - } -#endif /* * Unmap the dma buffer back to cpu if dma channel * programming fails. This buffer is mapped if the
WBR, Sergei -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html