linux-omap.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] musb: save OTG base physical address
@ 2010-05-17 11:08 Ajay Kumar Gupta
  2010-05-17 11:08 ` [PATCH 2/6 v2] musb: use system DMA to fix Inventra DMA issue on RTL-1.4 Ajay Kumar Gupta
  0 siblings, 1 reply; 8+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 11:08 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w, Ajay Kumar Gupta

OTG base physical address is required in calculating physical address
of endpoint FIFO which is needed by system dma.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
---
Patch created against linus'tree + all musb patches in Greg's queue

 drivers/usb/musb/musb_core.c |    6 ++++--
 drivers/usb/musb/musb_core.h |    1 +
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 705cc4a..94e787c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1867,7 +1867,8 @@ static void musb_free(struct musb *musb)
  *	not yet corrected for platform-specific offsets
  */
 static int __init
-musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
+musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl,
+			phys_addr_t ctrl_phys_addr)
 {
 	int			status;
 	struct musb		*musb;
@@ -1919,6 +1920,7 @@ bad_config:
 	musb->board_set_power = plat->set_power;
 	musb->set_clock = plat->set_clock;
 	musb->min_power = plat->min_power;
+	musb->ctrl_phys_base = ctrl_phys_addr;
 
 	/* Clock usage is chip-specific ... functional clock (DaVinci,
 	 * OMAP2430), or PHY ref (some TUSB6010 boards).  All this core
@@ -2136,7 +2138,7 @@ static int __init musb_probe(struct platform_device *pdev)
 	/* clobbered by use_dma=n */
 	orig_dma_mask = dev->dma_mask;
 #endif
-	status = musb_init_controller(dev, irq, base);
+	status = musb_init_controller(dev, irq, base, iomem->start);
 	if (status < 0)
 		iounmap(base);
 
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index ac17b00..d001894 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -367,6 +367,7 @@ struct musb {
 
 	struct device		*controller;
 	void __iomem		*ctrl_base;
+	phys_addr_t		ctrl_phys_base;
 	void __iomem		*mregs;
 
 #ifdef CONFIG_USB_TUSB6010
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/6 v2] musb: use system DMA to fix Inventra DMA issue on RTL-1.4
  2010-05-17 11:08 [PATCH 1/6] musb: save OTG base physical address Ajay Kumar Gupta
@ 2010-05-17 11:08 ` Ajay Kumar Gupta
       [not found]   ` <1274094488-15925-2-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 8+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 11:08 UTC (permalink / raw)
  To: linux-usb; +Cc: linux-omap, felipe.balbi, Ajay Kumar Gupta, Anand Gadiyar

MUSB RTL version 1.4 has a hardware issue when TX and RX DMA channels are
simultaneously enabled which results in DMA lockup.

Use system DMA for all RX channels as a workaround of this issue as this
will have minimal throughput overhead based on the fact that Rx transfers
are done in DMA mode-0 on OMAP34x/35x platforms. Also added stub functions
for non OMAP platforms so that there is no compilation failure.

Another approach to use PIO mode in opposite direction would increase the
cpu loading and thus using system DMA is preferred workaround.

Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
---
Patch created against linus'tree + all musb patches in Greg's queue
Changes from v1:
	- Added wrapper function to make it compilable for BlackFins

 drivers/usb/musb/Kconfig     |    9 +++
 drivers/usb/musb/musbhsdma.c |  132 ++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/musb/musbhsdma.h |   10 +++
 3 files changed, 151 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 07fe490..be5bea6 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -157,6 +157,15 @@ config USB_INVENTRA_DMA
 	help
 	  Enable DMA transfers using Mentor's engine.
 
+config MUSB_USE_SYSTEM_DMA_WORKAROUND
+	bool 'Use System DMA for Mentor DMA workaround'
+	depends on USB_MUSB_HDRC && USB_INVENTRA_DMA && ARCH_OMAP
+	default y
+	help
+          MUSB RTL version 1.4 (OMAP34x/35x) has a hardware issue when TX and RX
+          DMA channels are simultaneously enabled. To work around this issue,
+          you can choose to use System DMA for RX channels.
+
 config USB_TI_CPPI_DMA
 	bool
 	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 1008044..d2dab57 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -37,6 +37,97 @@
 #include "musb_core.h"
 #include "musbhsdma.h"
 
+#ifdef CONFIG_ARCH_OMAP
+#include <plat/dma.h>
+static void musb_sdma_channel_release(int ch_num)
+{
+	omap_stop_dma(ch_num);
+	omap_free_dma(ch_num);
+}
+static void musb_sdma_channel_abort(int ch_num)
+{
+	omap_stop_dma(ch_num);
+}
+static void musb_sdma_channel_program(struct musb *musb,
+		struct musb_dma_channel *musb_channel,
+		dma_addr_t dma_addr, u32 len)
+{
+	/* System DMA */
+	/* RX: set src = FIFO */
+	omap_set_dma_transfer_params(musb_channel->sysdma_channel,
+				OMAP_DMA_DATA_TYPE_S8,
+				len ? len : 1, 1, /* One frame */
+				OMAP_DMA_SYNC_ELEMENT,
+				OMAP24XX_DMA_NO_DEVICE,
+				0); /* Src Sync */
+
+	omap_set_dma_src_params(musb_channel->sysdma_channel, 0,
+				OMAP_DMA_AMODE_CONSTANT,
+				MUSB_FIFO_ADDRESS(musb->ctrl_phys_base,
+				musb_channel->epnum),
+				0, 0);
+
+	omap_set_dma_dest_params(musb_channel->sysdma_channel, 0,
+				OMAP_DMA_AMODE_POST_INC, dma_addr,
+				0, 0);
+
+	omap_set_dma_dest_data_pack(musb_channel->sysdma_channel, 1);
+	omap_set_dma_dest_burst_mode(musb_channel->sysdma_channel,
+				OMAP_DMA_DATA_BURST_16);
+
+	omap_start_dma(musb_channel->sysdma_channel);
+}
+static void musb_sysdma_completion(int lch, u16 ch_status, void *data)
+{
+	u32 addr;
+	unsigned long flags;
+
+	struct dma_channel *channel;
+
+	struct musb_dma_channel *musb_channel =
+					(struct musb_dma_channel *) data;
+	struct musb_dma_controller *controller = musb_channel->controller;
+	struct musb *musb = controller->private_data;
+	channel = &musb_channel->channel;
+
+	DBG(2, "lch = 0x%d, ch_status = 0x%x\n", lch, ch_status);
+	spin_lock_irqsave(&musb->lock, flags);
+
+	addr = (u32) omap_get_dma_dst_pos(musb_channel->sysdma_channel);
+	if (musb_channel->len == 0)
+		channel->actual_len = 0;
+	else
+		channel->actual_len = addr - musb_channel->start_addr;
+
+	DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
+		channel, musb_channel->start_addr, addr,
+		channel->actual_len, musb_channel->len,
+		(channel->actual_len < musb_channel->len) ?
+		"=> reconfig 0 " : " => complete");
+
+	channel->status = MUSB_DMA_STATUS_FREE;
+	musb_dma_completion(musb, musb_channel->epnum, musb_channel->transmit);
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return;
+}
+static int musb_sdma_channel_request(void *musb_channel, int *ch_num)
+{
+	return omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "MUSB SysDMA",
+			 musb_sysdma_completion, (void *) musb_channel, ch_num);
+}
+#else
+static int musb_sdma_channel_request(void *musb_channel, int *ch_num)
+{
+	return 1;
+}
+static void musb_sdma_channel_program(struct musb *musb,
+		struct musb_dma_channel *musb_channel,
+		dma_addr_t dma_addr, u32 len) {}
+static void musb_sdma_channel_abort(int ch_num) {}
+static void musb_sdma_channel_release(int ch_num) {}
+#endif /* CONFIG_ARCH_OMAP */
+
 static int dma_controller_start(struct dma_controller *c)
 {
 	/* nothing to do */
@@ -77,6 +168,7 @@ static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
 	struct musb_dma_controller *controller = container_of(c,
 			struct musb_dma_controller, controller);
 	struct musb_dma_channel *musb_channel = NULL;
+	struct musb *musb = controller->private_data;
 	struct dma_channel *channel = NULL;
 	u8 bit;
 
@@ -95,6 +187,32 @@ static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
 			/* Tx => mode 1; Rx => mode 0 */
 			channel->desired_mode = transmit;
 			channel->actual_len = 0;
+			musb_channel->sysdma_channel = -1;
+
+			/*
+			 * MUSB RTL version 1.4 (OMAP34x/35x) has a hardware
+			 * issue when TX and RX DMA channels are simultaneously
+			 * enabled. To work around this issue, use system DMA
+			 * for all RX channels.
+			 */
+			if (((musb->hwvers == MUSB_HWVERS_1400) && !transmit)
+				&& use_sdma_workaround()) {
+				int ret;
+				ret = musb_sdma_channel_request(
+					(void *) musb_channel,
+					&(musb_channel->sysdma_channel));
+
+				if (ret) {
+					printk(KERN_ERR "request_dma failed:"
+							" %d\n", ret);
+					controller->used_channels &=
+								~(1 << bit);
+					channel->status =
+							MUSB_DMA_STATUS_UNKNOWN;
+					musb_channel->sysdma_channel = -1;
+					channel = NULL;
+				}
+			}
 			break;
 		}
 	}
@@ -114,6 +232,11 @@ static void dma_channel_release(struct dma_channel *channel)
 		~(1 << musb_channel->idx);
 
 	channel->status = MUSB_DMA_STATUS_UNKNOWN;
+
+	if (musb_channel->sysdma_channel != -1) {
+		musb_sdma_channel_release(musb_channel->sysdma_channel);
+		musb_channel->sysdma_channel = -1;
+	}
 }
 
 static void configure_channel(struct dma_channel *channel,
@@ -122,12 +245,16 @@ static void configure_channel(struct dma_channel *channel,
 {
 	struct musb_dma_channel *musb_channel = channel->private_data;
 	struct musb_dma_controller *controller = musb_channel->controller;
+	struct musb *musb = controller->private_data;
 	void __iomem *mbase = controller->base;
 	u8 bchannel = musb_channel->idx;
 	u16 csr = 0;
 
 	DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
 			channel, packet_sz, dma_addr, len, mode);
+	if (musb_channel->sysdma_channel != -1) {
+		musb_sdma_channel_program(musb, musb_channel, dma_addr, len);
+	} else { /* Mentor DMA */
 
 	if (mode) {
 		csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
@@ -160,6 +287,7 @@ static void configure_channel(struct dma_channel *channel,
 	musb_writew(mbase,
 		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL),
 		csr);
+	}
 }
 
 static int dma_channel_program(struct dma_channel *channel,
@@ -214,6 +342,10 @@ static int dma_channel_abort(struct dma_channel *channel)
 			csr &= ~MUSB_TXCSR_DMAMODE;
 			musb_writew(mbase, offset, csr);
 		} else {
+			if (musb_channel->sysdma_channel != -1)
+				musb_sdma_channel_abort(
+					musb_channel->sysdma_channel);
+
 			offset = MUSB_EP_OFFSET(musb_channel->epnum,
 						MUSB_RXCSR);
 
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 613f95a..effc89a 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -142,6 +142,15 @@ static inline void musb_write_hsdma_count(void __iomem *mbase,
 
 #define MUSB_HSDMA_CHANNELS		8
 
+#define MUSB_FIFO_ADDRESS(base, epnum)      \
+	((unsigned long) (base + MUSB_FIFO_OFFSET(epnum)))
+
+#ifdef CONFIG_MUSB_USE_SYSTEM_DMA_WORKAROUND
+#define	use_sdma_workaround()	1
+#else
+#define	use_sdma_workaround()	0
+#endif
+
 struct musb_dma_controller;
 
 struct musb_dma_channel {
@@ -153,6 +162,7 @@ struct musb_dma_channel {
 	u8				idx;
 	u8				epnum;
 	u8				transmit;
+	int                             sysdma_channel;
 };
 
 struct musb_dma_controller {
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/6] musb: add function to check if Inventra DMA used
       [not found]   ` <1274094488-15925-2-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
@ 2010-05-17 11:08     ` Ajay Kumar Gupta
  2010-05-17 11:08       ` [PATCH 4/6] musb: use system DMA for unaligned buffers on RTL >= 1.8 Ajay Kumar Gupta
  0 siblings, 1 reply; 8+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 11:08 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w, Ajay Kumar Gupta

Added is_inventra_dma_enabled() funtion which would be required
for adding workaround for Inventra DMA issues. It can also be
used at other places instead of #ifdefs.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
---
 drivers/usb/musb/musb_dma.h |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 916065b..b8b385e 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -80,6 +80,12 @@ struct musb_hw_ep;
 #define tusb_dma_omap()			0
 #endif
 
+#ifdef CONFIG_USB_INVENTRA_DMA
+#define	is_inventra_dma_enabled()	1
+#else
+#define	is_inventra_dma_enabled()	0
+#endif
+
 /* Anomaly 05000456 - USB Receive Interrupt Is Not Generated in DMA Mode 1
  *	Only allow DMA mode 1 to be used when the USB will actually generate the
  *	interrupts we expect.
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/6] musb: use system DMA for unaligned buffers on RTL >= 1.8
  2010-05-17 11:08     ` [PATCH 3/6] musb: add function to check if Inventra DMA used Ajay Kumar Gupta
@ 2010-05-17 11:08       ` Ajay Kumar Gupta
       [not found]         ` <1274094488-15925-4-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 8+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 11:08 UTC (permalink / raw)
  To: linux-usb; +Cc: linux-omap, felipe.balbi, Ajay Kumar Gupta

MUSB RTL version 1.8 onward (OMAP3630, AM/DM37x, OMAP4) DMA requires
the buffers to be aligned on a four byte boundary. This affects USB
CDC/RNDIS class application where buffers are always unaligned.

Use system DMA for unaligned buffers as a workaround of this issue.

Current patch set supports device side CDC/RNDIS. Host side would
require change in Tx programming path for mode-0 operation when transfer
length is more than packet size.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
---
Patch created against linus'tree + all musb patches in Greg's queue
Changes from v1:
	- Added wrapper function to make it compilable for BlackFins

 drivers/usb/musb/Kconfig     |    6 +++
 drivers/usb/musb/musbhsdma.c |  103 ++++++++++++++++++++++++++++++++---------
 2 files changed, 86 insertions(+), 23 deletions(-)

diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index be5bea6..f518339 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -166,6 +166,12 @@ config MUSB_USE_SYSTEM_DMA_WORKAROUND
           DMA channels are simultaneously enabled. To work around this issue,
           you can choose to use System DMA for RX channels.
 
+	  Also on Mentor DMA in MUSB RTL version 1.8 (OMAP3630, AM/DM37x)
+	  requires buffers to be aligned on a four byte boundary. This affects
+	  USB CDC/RNDIS class application where buffers are always unaligned.
+	  To work around this issue, you can choose to use System DMA for
+	  unaligned buffers.
+
 config USB_TI_CPPI_DMA
 	bool
 	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index d2dab57..d29e487 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -52,8 +52,7 @@ static void musb_sdma_channel_program(struct musb *musb,
 		struct musb_dma_channel *musb_channel,
 		dma_addr_t dma_addr, u32 len)
 {
-	/* System DMA */
-	/* RX: set src = FIFO */
+	/* set transfer parameters */
 	omap_set_dma_transfer_params(musb_channel->sysdma_channel,
 				OMAP_DMA_DATA_TYPE_S8,
 				len ? len : 1, 1, /* One frame */
@@ -61,20 +60,39 @@ static void musb_sdma_channel_program(struct musb *musb,
 				OMAP24XX_DMA_NO_DEVICE,
 				0); /* Src Sync */
 
-	omap_set_dma_src_params(musb_channel->sysdma_channel, 0,
-				OMAP_DMA_AMODE_CONSTANT,
-				MUSB_FIFO_ADDRESS(musb->ctrl_phys_base,
-				musb_channel->epnum),
-				0, 0);
-
-	omap_set_dma_dest_params(musb_channel->sysdma_channel, 0,
-				OMAP_DMA_AMODE_POST_INC, dma_addr,
-				0, 0);
-
-	omap_set_dma_dest_data_pack(musb_channel->sysdma_channel, 1);
-	omap_set_dma_dest_burst_mode(musb_channel->sysdma_channel,
-				OMAP_DMA_DATA_BURST_16);
-
+	if (!musb_channel->transmit) {
+		/* RX: set src = FIFO */
+		omap_set_dma_src_params(musb_channel->sysdma_channel, 0,
+					OMAP_DMA_AMODE_CONSTANT,
+					MUSB_FIFO_ADDRESS(musb->ctrl_phys_base,
+					musb_channel->epnum),
+					0, 0);
+
+		omap_set_dma_dest_params(musb_channel->sysdma_channel, 0,
+					OMAP_DMA_AMODE_POST_INC, dma_addr,
+					0, 0);
+
+		omap_set_dma_dest_data_pack(musb_channel->sysdma_channel, 1);
+		omap_set_dma_dest_burst_mode(musb_channel->sysdma_channel,
+					OMAP_DMA_DATA_BURST_16);
+
+	} else if (musb_channel->transmit) {
+		/* TX: set dst = FIFO */
+		omap_set_dma_src_params(musb_channel->sysdma_channel, 0,
+					OMAP_DMA_AMODE_POST_INC, dma_addr,
+					0, 0);
+
+		omap_set_dma_dest_params(musb_channel->sysdma_channel, 0,
+					OMAP_DMA_AMODE_CONSTANT,
+					MUSB_FIFO_ADDRESS(musb->ctrl_phys_base,
+						musb_channel->epnum),
+					0, 0);
+
+		omap_set_dma_dest_data_pack(musb_channel->sysdma_channel, 0);
+		omap_set_dma_dest_burst_mode(musb_channel->sysdma_channel,
+					OMAP_DMA_DATA_BURST_DIS);
+	}
+	/* start the system dma */
 	omap_start_dma(musb_channel->sysdma_channel);
 }
 static void musb_sysdma_completion(int lch, u16 ch_status, void *data)
@@ -88,12 +106,18 @@ static void musb_sysdma_completion(int lch, u16 ch_status, void *data)
 					(struct musb_dma_channel *) data;
 	struct musb_dma_controller *controller = musb_channel->controller;
 	struct musb *musb = controller->private_data;
+	void __iomem *mbase = controller->base;
+
 	channel = &musb_channel->channel;
 
 	DBG(2, "lch = 0x%d, ch_status = 0x%x\n", lch, ch_status);
 	spin_lock_irqsave(&musb->lock, flags);
 
-	addr = (u32) omap_get_dma_dst_pos(musb_channel->sysdma_channel);
+	if (musb_channel->transmit)
+		addr = (u32) omap_get_dma_src_pos(musb_channel->sysdma_channel);
+	else
+		addr = (u32) omap_get_dma_dst_pos(musb_channel->sysdma_channel);
+
 	if (musb_channel->len == 0)
 		channel->actual_len = 0;
 	else
@@ -106,6 +130,26 @@ static void musb_sysdma_completion(int lch, u16 ch_status, void *data)
 		"=> reconfig 0 " : " => complete");
 
 	channel->status = MUSB_DMA_STATUS_FREE;
+
+	/* completed */
+	if ((musb_channel->transmit) && (channel->desired_mode == 0)
+		&& (channel->actual_len == musb_channel->max_packet_sz)) {
+
+		u8  epnum  = musb_channel->epnum;
+		int offset = MUSB_EP_OFFSET(epnum,
+				    MUSB_TXCSR);
+		u16 txcsr;
+
+		/*
+		 * The programming guide says that we
+		 * must clear DMAENAB before DMAMODE.
+		 */
+		musb_ep_select(mbase, epnum);
+		txcsr = musb_readw(mbase, offset);
+		txcsr |=  MUSB_TXCSR_TXPKTRDY;
+		musb_writew(mbase, offset, txcsr);
+	}
+
 	musb_dma_completion(musb, musb_channel->epnum, musb_channel->transmit);
 
 	spin_unlock_irqrestore(&musb->lock, flags);
@@ -194,8 +238,15 @@ static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
 			 * issue when TX and RX DMA channels are simultaneously
 			 * enabled. To work around this issue, use system DMA
 			 * for all RX channels.
+			 * Also on MUSB RTL version 1.8 onward (OMAP3630, OMAP4
+			 * and AM/DM37x) DMA requires buffers to be aligned on
+			 * a four byte boundary. This affects USB CDC/RNDIS
+			 * class application where buffers are always unaligned.
+			 * Using system DMA for unaligned buffers as a
+			 * workaround for this issue.
 			 */
-			if (((musb->hwvers == MUSB_HWVERS_1400) && !transmit)
+			if ((((musb->hwvers == MUSB_HWVERS_1400) && !transmit)
+				|| (musb->hwvers >= MUSB_HWVERS_1800))
 				&& use_sdma_workaround()) {
 				int ret;
 				ret = musb_sdma_channel_request(
@@ -248,11 +299,18 @@ static void configure_channel(struct dma_channel *channel,
 	struct musb *musb = controller->private_data;
 	void __iomem *mbase = controller->base;
 	u8 bchannel = musb_channel->idx;
+	u8 buffer_is_aligned = (dma_addr & 0x3) ? 0 : 1;
+	u8 use_sdma = (musb_channel->sysdma_channel == -1) ? 0 : 1;
 	u16 csr = 0;
 
 	DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
 			channel, packet_sz, dma_addr, len, mode);
-	if (musb_channel->sysdma_channel != -1) {
+
+	if (buffer_is_aligned && (packet_sz >= 512) &&
+			(musb->hwvers >= MUSB_HWVERS_1800))
+		use_sdma = 0;
+
+	if (use_sdma) {
 		musb_sdma_channel_program(musb, musb_channel, dma_addr, len);
 	} else { /* Mentor DMA */
 
@@ -328,6 +386,9 @@ static int dma_channel_abort(struct dma_channel *channel)
 	u16 csr;
 
 	if (channel->status == MUSB_DMA_STATUS_BUSY) {
+		if (musb_channel->sysdma_channel != -1)
+			musb_sdma_channel_abort(musb_channel->sysdma_channel);
+
 		if (musb_channel->transmit) {
 			offset = MUSB_EP_OFFSET(musb_channel->epnum,
 						MUSB_TXCSR);
@@ -342,10 +403,6 @@ static int dma_channel_abort(struct dma_channel *channel)
 			csr &= ~MUSB_TXCSR_DMAMODE;
 			musb_writew(mbase, offset, csr);
 		} else {
-			if (musb_channel->sysdma_channel != -1)
-				musb_sdma_channel_abort(
-					musb_channel->sysdma_channel);
-
 			offset = MUSB_EP_OFFSET(musb_channel->epnum,
 						MUSB_RXCSR);
 
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/6] musb: gadget: fix tx transfer path for mode0 operation
       [not found]         ` <1274094488-15925-4-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
@ 2010-05-17 11:08           ` Ajay Kumar Gupta
       [not found]             ` <1274094488-15925-5-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 8+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 11:08 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w, Ajay Kumar Gupta

Current gadget Tx path always programs DMA in mode-1 if request length
is more than packet size. As system DMA can work only in mode-0 so
updating the DMA mode and transfer length for it.

Also fixed an issue in device Tx completion path where 'is_dma' is
getting set unconditionally. This would fail the io if Tx transfer
is done in mode-0. Fixed it by updating it based on
'request->actual' length.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
---
 drivers/usb/musb/musb_gadget.c |   21 ++++++++++++++++++++-
 1 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 6fca870..9ac45e4 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -317,6 +317,22 @@ static void txstate(struct musb *musb, struct musb_request *req)
 			else
 				musb_ep->dma->desired_mode = 1;
 
+			/*
+			 * Use system dma for unaligned buffers on RTL >= 1.8
+			 * for Inventra DMA. As system DMA can work only in
+			 * mode-0 so update the desired_mode and request_size.
+			 */
+			if (is_inventra_dma_enabled() &&
+				((request->dma + request->actual) & 0x3) &&
+				(musb->hwvers >= MUSB_HWVERS_1800)) {
+
+				request_size = min_t(size_t,
+					musb_ep->hw_ep->max_packet_sz_tx,
+					request->length - request->actual);
+
+				musb_ep->dma->desired_mode = 0;
+			}
+
 			use_dma = use_dma && c->channel_program(
 					musb_ep->dma, musb_ep->packet_sz,
 					musb_ep->dma->desired_mode,
@@ -463,7 +479,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
 		u8	is_dma = 0;
 
 		if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
-			is_dma = 1;
 			csr |= MUSB_TXCSR_P_WZC_BITS;
 			csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
 				 MUSB_TXCSR_TXPKTRDY);
@@ -471,6 +486,10 @@ void musb_g_tx(struct musb *musb, u8 epnum)
 			/* Ensure writebuffer is empty. */
 			csr = musb_readw(epio, MUSB_TXCSR);
 			request->actual += musb_ep->dma->actual_len;
+
+			if (request->actual == request->length)
+				is_dma = 1;
+
 			DBG(4, "TXCSR%d %04x, DMA off, len %zu, req %p\n",
 				epnum, csr, musb_ep->dma->actual_len, request);
 		}
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6/6] musb: dma: use optimal transfer element for sdma
       [not found]             ` <1274094488-15925-5-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
@ 2010-05-17 11:08               ` Ajay Kumar Gupta
       [not found]                 ` <1274094488-15925-6-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 8+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 11:08 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w, Ajay Kumar Gupta

Use optimal values of transfer element based on buffer address in system
DMA programming. This would improve the performance.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
---
 drivers/usb/musb/musbhsdma.c |   29 ++++++++++++++++++++++++++---
 1 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index d29e487..39c1801 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -52,11 +52,34 @@ static void musb_sdma_channel_program(struct musb *musb,
 		struct musb_dma_channel *musb_channel,
 		dma_addr_t dma_addr, u32 len)
 {
+	u16 frame = len;
+	int data_type = OMAP_DMA_DATA_TYPE_S8;
+
+	switch (dma_addr & 0x3) {
+	case 0:
+		if ((len % 4) == 0) {
+			data_type = OMAP_DMA_DATA_TYPE_S32;
+			frame = len / 4;
+			break;
+		}
+	case 2:
+		if ((len % 2) == 0) {
+			data_type = OMAP_DMA_DATA_TYPE_S16;
+			frame = len / 2;
+			break;
+		}
+	case 1:
+	case 3:
+	default:
+		data_type = OMAP_DMA_DATA_TYPE_S8;
+		frame = len;
+			break;
+	}
 	/* set transfer parameters */
 	omap_set_dma_transfer_params(musb_channel->sysdma_channel,
-				OMAP_DMA_DATA_TYPE_S8,
-				len ? len : 1, 1, /* One frame */
-				OMAP_DMA_SYNC_ELEMENT,
+				data_type,
+				len ? frame : 1, 1, /* One frame */
+				OMAP_DMA_SYNC_FRAME,
 				OMAP24XX_DMA_NO_DEVICE,
 				0); /* Src Sync */
 
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 6/6] musb: dma: use optimal transfer element for sdma
       [not found]                 ` <1274094488-15925-6-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
@ 2010-05-18  9:47                   ` Sergei Shtylyov
  2010-05-18 10:11                     ` Gupta, Ajay Kumar
  0 siblings, 1 reply; 8+ messages in thread
From: Sergei Shtylyov @ 2010-05-18  9:47 UTC (permalink / raw)
  To: Ajay Kumar Gupta
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w

Hello.

Ajay Kumar Gupta wrote:

> Use optimal values of transfer element based on buffer address in system
> DMA programming. This would improve the performance.
> 
> Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
> ---
>  drivers/usb/musb/musbhsdma.c |   29 ++++++++++++++++++++++++++---
>  1 files changed, 26 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
> index d29e487..39c1801 100644
> --- a/drivers/usb/musb/musbhsdma.c
> +++ b/drivers/usb/musb/musbhsdma.c
> @@ -52,11 +52,34 @@ static void musb_sdma_channel_program(struct musb *musb,
>  		struct musb_dma_channel *musb_channel,
>  		dma_addr_t dma_addr, u32 len)
>  {
> +	u16 frame = len;
> +	int data_type = OMAP_DMA_DATA_TYPE_S8;
> +
> +	switch (dma_addr & 0x3) {
> +	case 0:
> +		if ((len % 4) == 0) {
> +			data_type = OMAP_DMA_DATA_TYPE_S32;
> +			frame = len / 4;
> +			break;
> +		}
> +	case 2:
> +		if ((len % 2) == 0) {
> +			data_type = OMAP_DMA_DATA_TYPE_S16;
> +			frame = len / 2;
> +			break;
> +		}
> +	case 1:
> +	case 3:
> +	default:
> +		data_type = OMAP_DMA_DATA_TYPE_S8;
> +		frame = len;
> +			break;

    The *break* is overindented.

WBR, Sergei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 6/6] musb: dma: use optimal transfer element for sdma
  2010-05-18  9:47                   ` Sergei Shtylyov
@ 2010-05-18 10:11                     ` Gupta, Ajay Kumar
  0 siblings, 0 replies; 8+ messages in thread
From: Gupta, Ajay Kumar @ 2010-05-18 10:11 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: linux-usb@vger.kernel.org, linux-omap@vger.kernel.org,
	felipe.balbi@nokia.com

Hi,
> Ajay Kumar Gupta wrote:
> 
> > Use optimal values of transfer element based on buffer address in system
> > DMA programming. This would improve the performance.
> >
> > Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
> > ---
> >  drivers/usb/musb/musbhsdma.c |   29 ++++++++++++++++++++++++++---
> >  1 files changed, 26 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
> > index d29e487..39c1801 100644
> > --- a/drivers/usb/musb/musbhsdma.c
> > +++ b/drivers/usb/musb/musbhsdma.c
> > @@ -52,11 +52,34 @@ static void musb_sdma_channel_program(struct musb
> *musb,
> >  		struct musb_dma_channel *musb_channel,
> >  		dma_addr_t dma_addr, u32 len)
> >  {
> > +	u16 frame = len;
> > +	int data_type = OMAP_DMA_DATA_TYPE_S8;
> > +
> > +	switch (dma_addr & 0x3) {
> > +	case 0:
> > +		if ((len % 4) == 0) {
> > +			data_type = OMAP_DMA_DATA_TYPE_S32;
> > +			frame = len / 4;
> > +			break;
> > +		}
> > +	case 2:
> > +		if ((len % 2) == 0) {
> > +			data_type = OMAP_DMA_DATA_TYPE_S16;
> > +			frame = len / 2;
> > +			break;
> > +		}
> > +	case 1:
> > +	case 3:
> > +	default:
> > +		data_type = OMAP_DMA_DATA_TYPE_S8;
> > +		frame = len;
> > +			break;
> 
>     The *break* is overindented.
Ok.

-Ajay
> 
> WBR, Sergei

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-05-18 10:11 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-17 11:08 [PATCH 1/6] musb: save OTG base physical address Ajay Kumar Gupta
2010-05-17 11:08 ` [PATCH 2/6 v2] musb: use system DMA to fix Inventra DMA issue on RTL-1.4 Ajay Kumar Gupta
     [not found]   ` <1274094488-15925-2-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
2010-05-17 11:08     ` [PATCH 3/6] musb: add function to check if Inventra DMA used Ajay Kumar Gupta
2010-05-17 11:08       ` [PATCH 4/6] musb: use system DMA for unaligned buffers on RTL >= 1.8 Ajay Kumar Gupta
     [not found]         ` <1274094488-15925-4-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
2010-05-17 11:08           ` [PATCH 5/6] musb: gadget: fix tx transfer path for mode0 operation Ajay Kumar Gupta
     [not found]             ` <1274094488-15925-5-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
2010-05-17 11:08               ` [PATCH 6/6] musb: dma: use optimal transfer element for sdma Ajay Kumar Gupta
     [not found]                 ` <1274094488-15925-6-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
2010-05-18  9:47                   ` Sergei Shtylyov
2010-05-18 10:11                     ` Gupta, Ajay Kumar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).