Re: DMA programming on DaVinci

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux