Skip to contentSkip to conversation

usb: dwc3: Fixes and improvements for DWC3 driver

PATCH New Lukasz Majewski 3 participants 35 messages Feb 23, 2015 – Mar 3, 2015

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover usb: dwc3: Fixes and improvements for DWC3 driver

Those patches should be applied on top of Kishon Vijay Abraham I work (v1) [40 patches]:

https://patchwork.ozlabs.org/patch/442467/
"dra7xx: am43xx: add dwc3 gadget driver support and enable dfu"

Those changes fixes composite, DFU and UMS gadgets - as a result relevant tests (available at test/{dfu|ums} pass.

Test HW: Odroid XU3 - Exynos5422

There is one important thing to note:

Since on our setup Data and Instruction Caches seems to be broken (or at least don't behave as expected) the comments regarding cache management in DWC3 still applies.

I will look on them at v2 of this patch set. This code should be also easily applicable on top of v2.

Inha Song (1):
usb: dwc3: Add BIT() macro

Joonyoung Shim (1):
usb: dwc3: make dwc3_set_mode to static

Marek Szyprowski (3):
usb: dwc3: add a workaround for too small OUT requests
usb: dwc3: gadget: add common endpoint configuration for dwc3 udc
driver
usb: dwc3: optimize interrupt loop

?ukasz Majewski (6):
usb: composite: Add .reset callback to usb_gadget_driver structure
usb: dwc3: linux-compat: Fix: Adding missing include files
usb: dwc3: Set usbdrd phy ctrl and mode in dwc3 core
usb: dwc3: gadget: Set all ctrl fields of Transfer Control Blocks
(TRB) to be LST
usb: dwc3: gadget: Set non EP0 max packet limit to 512B
usb: dwc3: Correct clean up code for requests

 drivers/usb/dwc3/core.c           | 86 +++++++++++++++++++++++++++++++++++----
 drivers/usb/dwc3/core.h           |  3 +-
 drivers/usb/dwc3/gadget.c         | 76 ++++++++++++++++------------------
 drivers/usb/dwc3/linux-compat.h   |  3 ++
 drivers/usb/gadget/composite.c    |  1 +
 drivers/usb/gadget/epautoconf.c   | 21 +++++++++-
 drivers/usb/gadget/gadget_chips.h |  8 ++++
 include/dwc3-uboot.h              |  2 +
 8 files changed, 149 insertions(+), 51 deletions(-)
Signature · 1 line
2.0.0.rc2
#1 lore raw

PATCH 1/11 usb: composite: Add .reset callback to usb_gadget_driver structure

DWC3 UDC driver requires presence of .reset callback in a composite driver. This setting is similar to the one nowadays present in linux kernel.

---
 drivers/usb/gadget/composite.c | 1 +
 1 file changed, 1 insertion(+)
drivers/usb/gadget/composite.c +1 -0
index 729a0fa..d96296c 100644
@@ -1052,6 +1052,7 @@ static struct usb_gadget_driver composite_driver = {
 	.unbind         = composite_unbind,
 
 	.setup		= composite_setup,
+	.reset          = composite_disconnect,
 	.disconnect	= composite_disconnect,
 
 	.suspend        = composite_suspend,
Signature · 1 line
2.0.0.rc2
#2 lore raw

PATCH 2/11 usb: dwc3: linux-compat: Fix: Adding missing include files

In reply to Lukasz Majewski

Added #includes are necessary to allow dwc3 to compile and run on u-boot for Odroid XU3.

---
 drivers/usb/dwc3/linux-compat.h | 3 +++
 1 file changed, 3 insertions(+)
drivers/usb/dwc3/linux-compat.h +3 -0
index b36f68f..40470aa 100644
@@ -12,6 +12,9 @@
 #ifndef __DWC3_LINUX_COMPAT__
 #define __DWC3_LINUX_COMPAT__
 
+#include <common.h>
+#include <linux/compat.h>
+
 #define pr_debug(format)                debug(format)
 #define WARN(val, format, arg...)	debug(format, ##arg)
 #define dev_WARN(dev, format, arg...)	debug(format, ##arg)
Signature · 1 line
2.0.0.rc2
#3 lore raw

PATCH 2/11 usb: dwc3: linux-compat: Fix: Adding missing include files

Hi,

Quoted 2 lines · Lukasz Majewski

Added #includes are necessary to allow dwc3 to compile and run on u-boot for Odroid XU3.

I think you should also add the files for Odroid XU3.

Quoted 11 lines
---
  drivers/usb/dwc3/linux-compat.h | 3 +++
  1 file changed, 3 insertions(+)
drivers/usb/dwc3/linux-compat.h +0 -0
index b36f68f..40470aa 100644

drivers/usb/dwc3/linux-compat.h line 16

Quoted 5 lines
drivers/usb/dwc3/linux-compat.h +2 -0
@@ -12,6 +12,9 @@
  #ifndef __DWC3_LINUX_COMPAT__
  #define __DWC3_LINUX_COMPAT__
 
+#include <common.h>
+#include <linux/compat.h>

These are not needed for dwc3 core driver. So I'd assume it is required only for Odroid XU3 file? For other files it is redundant.

Thanks
Kishon

#4 lore raw

PATCH 3/11 usb: dwc3: Add BIT() macro

In reply to Lukasz Majewski

From: Inha Song <[email protected]>

---
 drivers/usb/dwc3/core.h | 1 +
 1 file changed, 1 insertion(+)
drivers/usb/dwc3/core.h +1 -0
index 3f8a4e9..3355468 100644
@@ -392,6 +392,7 @@ struct dwc3_event_buffer {
 	unsigned int		count;
 	unsigned int		flags;
 
+#define BIT(x)			(1 << x)
 #define DWC3_EVENT_PENDING	BIT(0)
 
 	dma_addr_t		dma;
Signature · 1 line
2.0.0.rc2
#5 lore raw

PATCH 3/11 usb: dwc3: Add BIT() macro

Quoted 3 lines · Lukasz Majewski

From: Inha Song <[email protected]>

Is such confusing macro really necessary please ?

Moreover, the #define BIT(x) (1 << x) should really be #define BIT(x) (1 << (x)) (with (x) in round brackets).

Best regards,
Marek Vasut

#6 lore raw

PATCH 4/11 usb: dwc3: make dwc3_set_mode to static

In reply to Lukasz Majewski

From: Joonyoung Shim <[email protected]>

---
 drivers/usb/dwc3/core.c | 2 +-
 drivers/usb/dwc3/core.h | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)
drivers/usb/dwc3/core.c +1 -1
index 4c3637f..d690870 100644
@@ -32,7 +32,7 @@
 static LIST_HEAD(dwc3_list);
 /* -------------------------------------------------------------------------- */
 
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 {
 	u32 reg;
 
drivers/usb/dwc3/core.h +0 -1
index 3355468..45e431b 100644
@@ -988,7 +988,6 @@ struct dwc3_gadget_ep_cmd_params {
 #define DWC3_HAS_OTG			BIT(3)
 
 /* prototypes */
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
 #ifdef CONFIG_USB_DWC3_HOST
Signature · 1 line
2.0.0.rc2
#7 lore raw

PATCH 4/11 usb: dwc3: make dwc3_set_mode to static

Hi,

Quoted 1 line · Lukasz Majewski

From: Joonyoung Shim <[email protected]>

commit message please.

-Kishon

Quoted 33 lines
---
  drivers/usb/dwc3/core.c | 2 +-
  drivers/usb/dwc3/core.h | 1 -
  2 files changed, 1 insertion(+), 2 deletions(-)
drivers/usb/dwc3/core.c +1 -1
index 4c3637f..d690870 100644
@@ -32,7 +32,7 @@
  static LIST_HEAD(dwc3_list);
  /* -------------------------------------------------------------------------- */
 
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
  {
  	u32 reg;
 
drivers/usb/dwc3/core.h +0 -1
index 3355468..45e431b 100644
@@ -988,7 +988,6 @@ struct dwc3_gadget_ep_cmd_params {
  #define DWC3_HAS_OTG			BIT(3)
 
  /* prototypes */
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
  int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
  #ifdef CONFIG_USB_DWC3_HOST
#8 lore raw

PATCH 5/11 usb: dwc3: Set usbdrd phy ctrl and mode in dwc3 core

In reply to Lukasz Majewski
[The code has been rebased on v2 dwc3 support provided by Kishon Vijay Abraham I]
---
 drivers/usb/dwc3/core.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/usb/dwc3/core.h |  1 +
 include/dwc3-uboot.h    |  2 ++
 3 files changed, 79 insertions(+), 1 deletion(-)
drivers/usb/dwc3/core.c +76 -1
index d690870..fc3b0d9 100644
@@ -14,7 +14,12 @@
  * SPDX-License-Identifier:     GPL-2.0
  */
 
+#include "linux-compat.h"
+
 #include <common.h>
+#include <asm/arch/power.h>
+#include <asm/arch/xhci-exynos.h>
+#include <asm/cache.h>
 #include <malloc.h>
 #include <dwc3-uboot.h>
 #include <asm/dma-mapping.h>
@@ -42,6 +47,71 @@ static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 
+static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
+{
+	u32 reg;
+
+	/* Reset USB 3.0 PHY */
+	writel(0x0, &phy->phy_reg0);
+
+	clrbits_le32(&phy->phy_param0,
+			/* Select PHY CLK source */
+			PHYPARAM0_REF_USE_PAD |
+			/* Set Loss-of-Signal Detector sensitivity */
+			PHYPARAM0_REF_LOSLEVEL_MASK);
+	setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
+
+
+	writel(0x0, &phy->phy_resume);
+
+	/*
+	 * Setting the Frame length Adj value[6:1] to default 0x20
+	 * See xHCI 1.0 spec, 5.2.4
+	 */
+	setbits_le32(&phy->link_system,
+			LINKSYSTEM_XHCI_VERSION_CONTROL |
+			LINKSYSTEM_FLADJ(0x20));
+
+	/* Set Tx De-Emphasis level */
+	clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
+	setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
+
+	setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
+
+	/* PHYTEST POWERDOWN Control */
+	clrbits_le32(&phy->phy_test,
+			PHYTEST_POWERDOWN_SSP |
+			PHYTEST_POWERDOWN_HSP);
+
+	/* UTMI Power Control */
+	writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
+
+		/* Use core clock from main PLL */
+	reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+		/* Default 24Mhz crystal clock */
+		PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
+		PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+		PHYCLKRST_SSC_REFCLKSEL(0) |
+		/* Force PortReset of PHY */
+		PHYCLKRST_PORTRESET |
+		/* Digital power supply in normal operating mode */
+		PHYCLKRST_RETENABLEN |
+		/* Enable ref clock for SS function */
+		PHYCLKRST_REF_SSP_EN |
+		/* Enable spread spectrum */
+		PHYCLKRST_SSC_EN |
+		/* Power down HS Bias and PLL blocks in suspend mode */
+		PHYCLKRST_COMMONONN;
+
+	writel(reg, &phy->phy_clk_rst);
+
+	/* giving time to Phy clock to settle before resetting */
+	udelay(10);
+
+	reg &= ~PHYCLKRST_PORTRESET;
+	writel(reg, &phy->phy_clk_rst);
+}
+
 /**
  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
  * @dwc: pointer to our context structure
@@ -66,6 +136,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
 	mdelay(100);
+	exynos5_usb3_phy_init((struct exynos_usb3_phy *)dwc->phy_regs);
 
 	/* Clear USB3 PHY reset */
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
@@ -599,6 +670,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
 
 #define DWC3_ALIGN_MASK		(16 - 1)
 
+void set_usbdrd_phy_ctrl(unsigned int enable);
 /**
  * dwc3_uboot_init - dwc3 core uboot initialization code
  * @dwc3_dev: struct dwc3_device containing initialization data
@@ -629,7 +701,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
 	dwc->mem = mem;
 
-	dwc->regs	= (int *)(dwc3_dev->base + DWC3_GLOBALS_REGS_START);
+	dwc->regs = (int *)(dwc3_dev->base + DWC3_GLOBALS_REGS_START);
+	dwc->phy_regs = (int *)(dwc3_dev->phy_base);
 
 	/* default to highest possible threshold */
 	lpm_nyet_threshold = 0xff;
@@ -697,6 +770,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
 		dwc->dr_mode = USB_DR_MODE_OTG;
 
+	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
+
 	ret = dwc3_core_init(dwc);
 	if (ret) {
 		dev_err(dev, "failed to initialize core\n");
drivers/usb/dwc3/core.h +1 -0
index 45e431b..304e0c1 100644
@@ -727,6 +727,7 @@ struct dwc3 {
 
 	void __iomem		*regs;
 	size_t			regs_size;
+	void __iomem		*phy_regs;
 
 	enum usb_dr_mode	dr_mode;
 
include/dwc3-uboot.h +2 -0
index 09ff8a7..4c363cb 100644
@@ -14,6 +14,8 @@
 
 struct dwc3_device {
 	int base;
+	int phy_base;
+	unsigned needs_fifo_resize:1;
 	enum usb_dr_mode dr_mode;
 	u32 maximum_speed;
 	unsigned tx_fifo_resize:1;
Signature · 1 line
2.0.0.rc2
#9 lore raw

PATCH 5/11 usb: dwc3: Set usbdrd phy ctrl and mode in dwc3 core

Hi,

On Monday 23 February 2015 07:32 PM, Lukasz Majewski wrote:

commit message here again.

Quoted 14 lines
[The code has been rebased on v2 dwc3 support provided by Kishon Vijay Abraham I]
---
  drivers/usb/dwc3/core.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-
  drivers/usb/dwc3/core.h |  1 +
  include/dwc3-uboot.h    |  2 ++
  3 files changed, 79 insertions(+), 1 deletion(-)
drivers/usb/dwc3/core.c +0 -0
index d690870..fc3b0d9 100644

drivers/usb/dwc3/core.c line 17

Quoted 4 lines
drivers/usb/dwc3/core.c +1 -0
@@ -14,7 +14,12 @@
   * SPDX-License-Identifier:     GPL-2.0
   */
 
+#include "linux-compat.h"

This is already included.

drivers/usb/dwc3/core.c line 21

Quoted 4 lines
drivers/usb/dwc3/core.c +3 -0
+
  #include <common.h>
+#include <asm/arch/power.h>
+#include <asm/arch/xhci-exynos.h>

Don't do platform specific stuff in DWC3 core files and break other platforms.

Quoted 62 lines
drivers/usb/dwc3/core.c +55 -0
+#include <asm/cache.h>
  #include <malloc.h>
  #include <dwc3-uboot.h>
  #include <asm/dma-mapping.h>
@@ -42,6 +47,71 @@ static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
  	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
  }
 
+static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
+{
+	u32 reg;
+
+	/* Reset USB 3.0 PHY */
+	writel(0x0, &phy->phy_reg0);
+
+	clrbits_le32(&phy->phy_param0,
+			/* Select PHY CLK source */
+			PHYPARAM0_REF_USE_PAD |
+			/* Set Loss-of-Signal Detector sensitivity */
+			PHYPARAM0_REF_LOSLEVEL_MASK);
+	setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
+
+
+	writel(0x0, &phy->phy_resume);
+
+	/*
+	 * Setting the Frame length Adj value[6:1] to default 0x20
+	 * See xHCI 1.0 spec, 5.2.4
+	 */
+	setbits_le32(&phy->link_system,
+			LINKSYSTEM_XHCI_VERSION_CONTROL |
+			LINKSYSTEM_FLADJ(0x20));
+
+	/* Set Tx De-Emphasis level */
+	clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
+	setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
+
+	setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
+
+	/* PHYTEST POWERDOWN Control */
+	clrbits_le32(&phy->phy_test,
+			PHYTEST_POWERDOWN_SSP |
+			PHYTEST_POWERDOWN_HSP);
+
+	/* UTMI Power Control */
+	writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
+
+		/* Use core clock from main PLL */
+	reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+		/* Default 24Mhz crystal clock */
+		PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
+		PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+		PHYCLKRST_SSC_REFCLKSEL(0) |
+		/* Force PortReset of PHY */
+		PHYCLKRST_PORTRESET |
+		/* Digital power supply in normal operating mode */
+		PHYCLKRST_RETENABLEN |
+		/* Enable ref clock for SS function */
+		PHYCLKRST_REF_SSP_EN |
+		/* Enable spread spectrum */
+		PHYCLKRST_SSC_EN |
+		/* Power down HS Bias and PLL blocks in suspend mode */

drivers/usb/dwc3/core.c static void dwc3_set_mode(struct dwc3 *dwc, u32 mode) · line 113

Quoted 10 lines
drivers/usb/dwc3/core.c +10 -0
+		PHYCLKRST_COMMONONN;
+
+	writel(reg, &phy->phy_clk_rst);
+
+	/* giving time to Phy clock to settle before resetting */
+	udelay(10);
+
+	reg &= ~PHYCLKRST_PORTRESET;
+	writel(reg, &phy->phy_clk_rst);
+}

This function shouldn't be here at all.

Quoted 56 lines
drivers/usb/dwc3/core.c +7 -1
+
  /**
   * dwc3_core_soft_reset - Issues core soft reset and PHY reset
   * @dwc: pointer to our context structure
@@ -66,6 +136,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
  	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
  	mdelay(100);
+	exynos5_usb3_phy_init((struct exynos_usb3_phy *)dwc->phy_regs);
 
  	/* Clear USB3 PHY reset */
  	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
@@ -599,6 +670,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
 
  #define DWC3_ALIGN_MASK		(16 - 1)
 
+void set_usbdrd_phy_ctrl(unsigned int enable);
  /**
   * dwc3_uboot_init - dwc3 core uboot initialization code
   * @dwc3_dev: struct dwc3_device containing initialization data
@@ -629,7 +701,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
  	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
  	dwc->mem = mem;
 
-	dwc->regs	= (int *)(dwc3_dev->base + DWC3_GLOBALS_REGS_START);
+	dwc->regs = (int *)(dwc3_dev->base + DWC3_GLOBALS_REGS_START);
+	dwc->phy_regs = (int *)(dwc3_dev->phy_base);
 
  	/* default to highest possible threshold */
  	lpm_nyet_threshold = 0xff;
@@ -697,6 +770,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
  	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
  		dwc->dr_mode = USB_DR_MODE_OTG;
 
+	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
+
  	ret = dwc3_core_init(dwc);
  	if (ret) {
  		dev_err(dev, "failed to initialize core\n");
drivers/usb/dwc3/core.h +1 -0
index 45e431b..304e0c1 100644
@@ -727,6 +727,7 @@ struct dwc3 {
 
  	void __iomem		*regs;
  	size_t			regs_size;
+	void __iomem		*phy_regs;
 
  	enum usb_dr_mode	dr_mode;
 
include/dwc3-uboot.h +0 -0
index 09ff8a7..4c363cb 100644

include/dwc3-uboot.h line 18

Quoted 5 lines
include/dwc3-uboot.h +2 -0
@@ -14,6 +14,8 @@
 
  struct dwc3_device {
  	int base;
+	int phy_base;
+	unsigned needs_fifo_resize:1;

tx_fifo_resize is already part of this structure.

Thanks
Kishon

#10 lore raw

PATCH 6/11 usb: dwc3: add a workaround for too small OUT requests

In reply to Lukasz Majewski

From: Marek Szyprowski <[email protected]>

DWC3 hangs on OUT requests smaller than maxpacket size, so HACK the request length to be at least equal to maxpacket size.

---
 drivers/usb/dwc3/gadget.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/usb/dwc3/gadget.c +6 -0
index 01bc83b..f8a75d3 100644
@@ -974,6 +974,12 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 	req->direction		= dep->direction;
 	req->epnum		= dep->number;
 
+	/* DWC3 hangs on OUT requests smaller than maxpacket size,
+	   so HACK the request length */
+	if (dep->direction == 0 &&
+	    req->request.length < dep->endpoint.maxpacket)
+		req->request.length = dep->endpoint.maxpacket;
+
 	/*
 	 * We only add to our list of requests now and
 	 * start consuming the list once we get XferNotReady
Signature · 1 line
2.0.0.rc2
#11 lore raw

PATCH 6/11 usb: dwc3: add a workaround for too small OUT requests

Hi,

Quoted 4 lines · Lukasz Majewski

From: Marek Szyprowski <[email protected]>

DWC3 hangs on OUT requests smaller than maxpacket size, so HACK the request length to be at least equal to maxpacket size.

Curious to know using which gadget this issue was seen.

Thanks
Kishon

Quoted 24 lines
---
  drivers/usb/dwc3/gadget.c | 6 ++++++
  1 file changed, 6 insertions(+)
drivers/usb/dwc3/gadget.c +6 -0
index 01bc83b..f8a75d3 100644
@@ -974,6 +974,12 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
  	req->direction		= dep->direction;
  	req->epnum		= dep->number;
 
+	/* DWC3 hangs on OUT requests smaller than maxpacket size,
+	   so HACK the request length */
+	if (dep->direction == 0 &&
+	    req->request.length < dep->endpoint.maxpacket)
+		req->request.length = dep->endpoint.maxpacket;
+
  	/*
  	 * We only add to our list of requests now and
  	 * start consuming the list once we get XferNotReady
#12 lore raw

PATCH 6/11 usb: dwc3: add a workaround for too small OUT requests

Hi Kishon,

Quoted 9 lines

Hi,

Quoted 4 lines · Lukasz Majewski

From: Marek Szyprowski <[email protected]>

DWC3 hangs on OUT requests smaller than maxpacket size, so HACK the request length to be at least equal to maxpacket size.

Curious to know using which gadget this issue was seen.

We have been testing this code with USB Mass Storage, Thor and DFU gadgets.

In the v2 commit letter you have stated that this code was tested with DFU MMC:

Quoted 2 lines
Quoted 2 lines

Testing:
*) tested DFU RAM and DFU MMC in dra7xx and am43xx

Have you tried to run test at ./test/dfu directory?

Quoted 29 lines

Thanks
Kishon

Quoted 25 lines
---
  drivers/usb/dwc3/gadget.c | 6 ++++++
  1 file changed, 6 insertions(+)
drivers/usb/dwc3/gadget.c +6 -0
index 01bc83b..f8a75d3 100644
@@ -974,6 +974,12 @@ static int __dwc3_gadget_ep_queue(struct
 dwc3_ep *dep, struct dwc3_request *req)
 req->direction		= dep->direction;
 req->epnum		= dep->number;
 
+	/* DWC3 hangs on OUT requests smaller than maxpacket size,
+	   so HACK the request length */
+	if (dep->direction == 0 &&
+	    req->request.length < dep->endpoint.maxpacket)
+		req->request.length = dep->endpoint.maxpacket;
+
  	/*
  	 * We only add to our list of requests now and

* start consuming the list once we get XferNotReady

Signature · 5 lines
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
#13 lore raw

PATCH 6/11 usb: dwc3: add a workaround for too small OUT requests

Hi,

Quoted 7 lines · Lukasz Majewski

Hi Kishon,

Quoted 5 lines

Hi,

Quoted 2 lines · Lukasz Majewski

From: Marek Szyprowski <[email protected]>

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

DWC3 hangs on OUT requests smaller than maxpacket size, so HACK the request length to be at least equal to maxpacket size.

Curious to know using which gadget this issue was seen.

We have been testing this code with USB Mass Storage, Thor and DFU gadgets.

nice!

Quoted 8 lines

In the v2 commit letter you have stated that this code was tested with DFU MMC:

Quoted 2 lines
Quoted 2 lines

Testing:
*) tested DFU RAM and DFU MMC in dra7xx and am43xx

Have you tried to run test at ./test/dfu directory?

Haven't seen that before. I download images MLO, u-boot.img, uImage, fdt etc using dfu and do a boot test using the downloaded images.

Will try using the ./test/dfu directory.

Thanks
Kishon

#14 lore raw

PATCH 7/11 usb: dwc3: gadget: add common endpoint configuration for dwc3 udc driver

In reply to Lukasz Majewski

From: Marek Szyprowski <[email protected]>

This patch adds code to select standard, commonly used usb endpoint configuration (ep1in-bulk, ep2out-bulk, ep3in-int) to dwc3 driver. This ensures compatibility with old userspace and windows drivers, which expects hardcoded endpoint numbers.

---
 drivers/usb/gadget/epautoconf.c   | 21 ++++++++++++++++++++-
 drivers/usb/gadget/gadget_chips.h |  8 ++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)
drivers/usb/gadget/epautoconf.c +20 -1
index 0df4b2a..899f254 100644
@@ -220,7 +220,7 @@ struct usb_ep *usb_ep_autoconfig(
 	struct usb_endpoint_descriptor	*desc
 )
 {
-	struct usb_ep	*ep;
+	struct usb_ep	*ep = NULL;
 	u8		type;
 
 	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
@@ -261,6 +261,25 @@ struct usb_ep *usb_ep_autoconfig(
 		ep = find_ep(gadget, "ep1-bulk");
 		if (ep && ep_matches(gadget, ep, desc))
 			return ep;
+	} else if (gadget_is_dwc3(gadget)) {
+		const char *name = NULL;
+		/*
+		 First try standard, common configuration: ep1in-bulk,
+		 ep2out-bulk, ep3in-int to match other udc drivers to avoid confusion
+		 in already deployed software (endpoint numbers hardcoded in userspace
+		 software/drivers)
+		 */
+		if ((desc->bEndpointAddress & USB_DIR_IN) && type == USB_ENDPOINT_XFER_BULK)
+			name = "ep1in";
+		else if ((desc->bEndpointAddress & USB_DIR_IN) == 0 && type == USB_ENDPOINT_XFER_BULK)
+			name = "ep2out";
+		else if ((desc->bEndpointAddress & USB_DIR_IN) && type == USB_ENDPOINT_XFER_INT)
+			name = "ep3in";
+
+		if (name)
+			ep = find_ep(gadget, name);
+		if (ep && ep_matches(gadget, ep, desc))
+			return ep;
 	}
 
 	/* Second, look at endpoints until an unclaimed one looks usable */
drivers/usb/gadget/gadget_chips.h +8 -0
index cc94771..c859df2 100644
@@ -156,6 +156,14 @@
 #define gadget_is_fotg210(g)        0
 #endif
 
+#ifdef CONFIG_USB_DWC3_GADGET
+#define gadget_is_dwc3(g)        (!strcmp("dwc3-gadget", (g)->name))
+#else
+#define gadget_is_dwc3(g)        0
+#endif
+
+
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
Signature · 1 line
2.0.0.rc2
#15 lore raw

PATCH 8/11 usb: dwc3: optimize interrupt loop

In reply to Lukasz Majewski

From: Marek Szyprowski <[email protected]>

There is no point in calling dwc3_thread_interrupt() if no event is pending. There is also no point in flushing event cache in EVERY loop iteration.

---
 drivers/usb/dwc3/core.c   |  7 -------
 drivers/usb/dwc3/gadget.c | 15 +++++++++++++--
 2 files changed, 13 insertions(+), 9 deletions(-)
drivers/usb/dwc3/core.c +0 -7
index fc3b0d9..846475a 100644
@@ -844,18 +844,11 @@ void dwc3_uboot_exit(int index)
 void dwc3_uboot_handle_interrupt(int index)
 {
 	struct dwc3 *dwc = NULL;
-	int i;
-	struct dwc3_event_buffer *evt;
 
 	list_for_each_entry(dwc, &dwc3_list, list) {
 		if (dwc->index != index)
 			continue;
 
-		for (i = 0; i < dwc->num_event_buffers; i++) {
-			evt = dwc->ev_buffs[i];
-			dwc3_flush_cache((int)evt->buf, evt->length);
-		}
-
 		dwc3_gadget_uboot_handle_interrupt(dwc);
 		break;
 	}
drivers/usb/dwc3/gadget.c +13 -2
index f8a75d3..4a4923f 100644
@@ -2680,6 +2680,17 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
  */
 void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc)
 {
-	dwc3_interrupt(0, dwc);
-	dwc3_thread_interrupt(0, dwc);
+	int ret = dwc3_interrupt(0, dwc);
+
+	if (ret == IRQ_WAKE_THREAD) {
+		int i;
+		struct dwc3_event_buffer *evt;
+
+		for (i = 0; i < dwc->num_event_buffers; i++) {
+			evt = dwc->ev_buffs[i];
+			dwc3_flush_cache((int)evt->buf, evt->length);
+		}
+
+		dwc3_thread_interrupt(0, dwc);
+	}
 }
Signature · 1 line
2.0.0.rc2
#16 lore raw

PATCH 9/11 usb: dwc3: gadget: Set all ctrl fields of Transfer Control Blocks (TRB) to be LST

In reply to Lukasz Majewski

It turned out that current dwc3 gadget code is preparing multiple TRBs for a transfer. Unfortunately, when multiple requests are in the same queue, only for the last one the LST (last) ctrl bit is set.

Due to that dwc3 HW executes all TRBs up till the one marked as last. Unfortunately, UMS requires call of ->complete callback after any send TRB. This is the reason for "hangs" in executing UMS.

This code simplifies this situation and set each TRB's ctrl field bit to be last (LST bit).

---
 drivers/usb/dwc3/gadget.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)
drivers/usb/dwc3/gadget.c +2 -13
index 4a4923f..810e224 100644
@@ -789,7 +789,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 	struct dwc3_request	*req, *n;
 	u32			trbs_left;
 	u32			max;
-	unsigned int		last_one = 0;
 
 	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
 
@@ -839,24 +838,14 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 	list_for_each_entry_safe(req, n, &dep->request_list, list) {
 		unsigned	length;
 		dma_addr_t	dma;
-		last_one = false;
 
 		dma = req->request.dma;
 		length = req->request.length;
-		trbs_left--;
-
-		if (!trbs_left)
-			last_one = 1;
-
-		/* Is this the last request? */
-		if (list_is_last(&req->list, &dep->request_list))
-			last_one = 1;
 
 		dwc3_prepare_one_trb(dep, req, dma, length,
-				last_one, false, 0);
+				     true, false, 0);
 
-		if (last_one)
-			break;
+		break;
 	}
 }
 
Signature · 1 line
2.0.0.rc2
#17 lore raw

PATCH 10/11 usb: dwc3: gadget: Set non EP0 max packet limit to 512B

In reply to Lukasz Majewski

Commit "drivers/dwc3: add a workaround for too small OUT requests" sets max packet for OUT requests when transfer is smaller.

Until this change the default maxpacket for non EP0 EPs was 1024. This is too much, since UMS LBA size is 512B

---
 drivers/usb/dwc3/gadget.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/dwc3/gadget.c +1 -1
index 810e224..97f23e5 100644
@@ -1603,7 +1603,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 		} else {
 			int		ret;
 
-			usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);
+			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
 			dep->endpoint.max_streams = 15;
 			dep->endpoint.ops = &dwc3_gadget_ep_ops;
 			list_add_tail(&dep->endpoint.ep_list,
Signature · 1 line
2.0.0.rc2
#18 lore raw

PATCH 11/11 usb: dwc3: Correct clean up code for requests

In reply to Lukasz Majewski

For u-boot dwc3 driver the scatter gather list support has been removed from original linux code. It is correct, since we try to send one request at a time.
However, the cleanup left spurious break, which caused early exit from loop at dwc3_cleanup_done_reqs() function. As a result the dwc3_gadget_giveback() wasn't called and caused USB Mass Storage to hang.

This commit removes this problem and refactor the code to remove superfluous do { } while(1) loop.

Test HW: Odroid XU3 (with ./test/ums/ums_gadget_test.sh)

---
 drivers/usb/dwc3/gadget.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/usb/dwc3/gadget.c +14 -24
index 97f23e5..cb15a38 100644
@@ -1753,33 +1753,23 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 	struct dwc3_request	*req;
 	struct dwc3_trb		*trb;
 	unsigned int		slot;
-	int			ret;
-
-	do {
-		req = next_request(&dep->req_queued);
-		if (!req) {
-			WARN_ON_ONCE(1);
-			return 1;
-		}
-
-		slot = req->start_slot;
-		if ((slot == DWC3_TRB_NUM - 1) &&
-			usb_endpoint_xfer_isoc(dep->endpoint.desc))
-			slot++;
-		slot %= DWC3_TRB_NUM;
-		trb = &dep->trb_pool[slot];
 
-		dwc3_flush_cache((int)trb, sizeof(*trb));
-		ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
-				event, status);
-		if (ret)
-			break;
+	req = next_request(&dep->req_queued);
+	if (!req) {
+		WARN_ON_ONCE(1);
+		return 1;
+	}
 
-		dwc3_gadget_giveback(dep, req, status);
+	slot = req->start_slot;
+	if ((slot == DWC3_TRB_NUM - 1) &&
+	    usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		slot++;
+	slot %= DWC3_TRB_NUM;
+	trb = &dep->trb_pool[slot];
 
-		if (ret)
-			break;
-	} while (1);
+	dwc3_flush_cache((int)trb, sizeof(*trb));
+	__dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
+	dwc3_gadget_giveback(dep, req, status);
 
 	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
 			list_empty(&dep->req_queued)) {
Signature · 1 line
2.0.0.rc2
#19 lore raw

cover usb: dwc3: Fixes and improvements for DWC3 driver

In reply to Lukasz Majewski

This patch set should be applied on top of recent Kishon Vijay Abraham I work (v2) regarding providing dwc3 support to u-boot as well as clean up of the linux-compat header file.

For the whole patch set please refer to -dfu u-boot repo, branch (devel/dwc3_gadget):
http://git.denx.de/?p=u-boot/u-boot-dfu.git;a=shortlog;h=refs/heads/devel/dwc3_gadget

This patch set fixes things, so all Samsung boards compile after applying DWC3 support.

Tests and comments are welcome.

Inha Song (2):
usb: gadget: UMS: Invoke board specific USB cleanup interface
usb: gadget: thor: Invoke board specific USB cleanup interface

Joonyoung Shim (1):
usb: dwc3: make dwc3_set_mode to static

Marek Szyprowski (4):
usb: dwc3: add a workaround for too small OUT requests
usb: dwc3: gadget: add common endpoint configuration for dwc3 udc
driver
usb: dwc3: optimize interrupt loop
usb: gadget: thor: Claim EP after allocating it in thor gadget

?ukasz Majewski (7):
usb: board: samsung: Add default board_usb_cleanup() definition for
Exynos SoCs
usb: board: goni: Add default board_usb_cleanup() definition for Goni
board
usb: composite: Add .reset callback to usb_gadget_driver structure
usb: dwc3: Remove BIT(x) macro from DWC3's gadget code
usb: dwc3: gadget: Set all ctrl fields of Transfer Control Blocks
(TRB) to be LST
usb: dwc3: gadget: Set non EP0 max packet limit to 512B
usb: dwc3: Correct clean up code for requests

 board/samsung/common/board.c      |  6 +++
 board/samsung/goni/goni.c         |  5 +++
 common/cmd_thordown.c             |  1 +
 common/cmd_usb_mass_storage.c     |  1 +
 drivers/usb/dwc3/core.c           |  9 +----
 drivers/usb/dwc3/core.h           |  3 +-
 drivers/usb/dwc3/gadget.c         | 80 +++++++++++++++++++--------------------
 drivers/usb/gadget/composite.c    |  1 +
 drivers/usb/gadget/epautoconf.c   | 24 +++++++++++-
 drivers/usb/gadget/f_thor.c       |  3 ++
 drivers/usb/gadget/gadget_chips.h |  8 ++++
 11 files changed, 89 insertions(+), 52 deletions(-)
Signature · 1 line
2.0.0.rc2
#20 lore raw

PATCH 1/14 usb: board: samsung: Add default board_usb_cleanup() definition for Exynos SoCs

This definition is necessary for Exynos based boards to work properly.

---
 board/samsung/common/board.c | 6 ++++++
 1 file changed, 6 insertions(+)
board/samsung/common/board.c +6 -0
index 6c7f59b..7b10877 100644
@@ -25,6 +25,7 @@
 #include <asm/arch/sromc.h>
 #include <lcd.h>
 #include <samsung/misc.h>
+#include <usb.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -380,3 +381,8 @@ void reset_misc(void)
 		dm_gpio_set_value(&gpio, 1);
 	}
 }
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+	return 0;
+}
Signature · 1 line
2.0.0.rc2
#21 lore raw

PATCH 2/14 usb: board: goni: Add default board_usb_cleanup() definition for Goni board

In reply to Lukasz Majewski

This definition is necessary for S5PC110 based GONI board to work properly.

---
 board/samsung/goni/goni.c | 5 +++++
 1 file changed, 5 insertions(+)
board/samsung/goni/goni.c +5 -0
index 58cf96e..d943d63 100644
@@ -206,3 +206,8 @@ int misc_init_r(void)
 	return 0;
 }
 #endif
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+	return 0;
+}
Signature · 1 line
2.0.0.rc2
#22 lore raw

PATCH 3/14 usb: gadget: UMS: Invoke board specific USB cleanup interface

In reply to Lukasz Majewski

From: Inha Song <[email protected]>

This patch invokes board-specific USB cleanup (board_usb_cleanup) function in the mass storage gadget

---
 common/cmd_usb_mass_storage.c | 1 +
 1 file changed, 1 insertion(+)
common/cmd_usb_mass_storage.c +1 -0
index c5f909d..ccd4cc5 100644
@@ -154,6 +154,7 @@ int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
 	}
 exit:
 	g_dnl_unregister();
+	board_usb_cleanup(controller_index, USB_INIT_DEVICE);
 	return CMD_RET_SUCCESS;
 }
 
Signature · 1 line
2.0.0.rc2
#23 lore raw

PATCH 4/14 usb: gadget: thor: Invoke board specific USB cleanup interface

In reply to Lukasz Majewski

From: Inha Song <[email protected]>

This patch invokes board-specific USB cleanup (board_usb_cleanup) function in the thor gadget.

---
 common/cmd_thordown.c | 1 +
 1 file changed, 1 insertion(+)
common/cmd_thordown.c +1 -0
index 8ed1dc6..436b7f5 100644
@@ -56,6 +56,7 @@ int do_thor_down(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 exit:
 	g_dnl_unregister();
+	board_usb_cleanup(controller_index, USB_INIT_DEVICE);
 done:
 	dfu_free_entities();
 
Signature · 1 line
2.0.0.rc2
#24 lore raw

PATCH 5/14 usb: composite: Add .reset callback to usb_gadget_driver structure

In reply to Lukasz Majewski

DWC3 UDC driver requires presence of .reset callback in a composite driver. This setting is similar to the one nowadays present in linux kernel.

---
 drivers/usb/gadget/composite.c | 1 +
 1 file changed, 1 insertion(+)
drivers/usb/gadget/composite.c +1 -0
index 729a0fa..d96296c 100644
@@ -1052,6 +1052,7 @@ static struct usb_gadget_driver composite_driver = {
 	.unbind         = composite_unbind,
 
 	.setup		= composite_setup,
+	.reset          = composite_disconnect,
 	.disconnect	= composite_disconnect,
 
 	.suspend        = composite_suspend,
Signature · 1 line
2.0.0.rc2
#25 lore raw

PATCH 6/14 usb: dwc3: Remove BIT(x) macro from DWC3's gadget code

In reply to Lukasz Majewski

The BIT() macro is used only in those places, so it is reasonable to replace it by a constant value.

---
 drivers/usb/dwc3/core.h   | 2 +-
 drivers/usb/dwc3/gadget.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/usb/dwc3/core.h +1 -1
index c5debf7..5288a18 100644
@@ -392,7 +392,7 @@ struct dwc3_event_buffer {
 	unsigned int		count;
 	unsigned int		flags;
 
-#define DWC3_EVENT_PENDING	BIT(0)
+#define DWC3_EVENT_PENDING	(1UL << 0)
 
 	dma_addr_t		dma;
 
drivers/usb/dwc3/gadget.c +1 -1
index 4be4d99..a497fbb 100644
@@ -2365,7 +2365,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
 static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
 		unsigned int evtinfo)
 {
-	unsigned int is_ss = evtinfo & BIT(4);
+	unsigned int is_ss = evtinfo & (1UL << 4);
 
 	/**
 	 * WORKAROUND: DWC3 revison 2.20a with hibernation support
Signature · 1 line
2.0.0.rc2
#26 lore raw

PATCH 7/14 usb: dwc3: make dwc3_set_mode to static

In reply to Lukasz Majewski

From: Joonyoung Shim <[email protected]>

This commit makes the dwc3_set_mode() as static, to prevent collisions.

---
 drivers/usb/dwc3/core.c | 2 +-
 drivers/usb/dwc3/core.h | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)
drivers/usb/dwc3/core.c +1 -1
index aebebb4..45bb724 100644
@@ -30,7 +30,7 @@
 static LIST_HEAD(dwc3_list);
 /* -------------------------------------------------------------------------- */
 
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 {
 	u32 reg;
 
drivers/usb/dwc3/core.h +0 -1
index 5288a18..72d2fcd 100644
@@ -987,7 +987,6 @@ struct dwc3_gadget_ep_cmd_params {
 #define DWC3_HAS_OTG			BIT(3)
 
 /* prototypes */
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
 #ifdef CONFIG_USB_DWC3_HOST
Signature · 1 line
2.0.0.rc2
#27 lore raw

PATCH 8/14 usb: dwc3: add a workaround for too small OUT requests

In reply to Lukasz Majewski

From: Marek Szyprowski <[email protected]>

DWC3 hangs on OUT requests smaller than maxpacket size, so HACK the request length to be at least equal to maxpacket size.

---
 drivers/usb/dwc3/gadget.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/usb/dwc3/gadget.c +8 -0
index a497fbb..737cb3e 100644
@@ -973,6 +973,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 	req->epnum		= dep->number;
 
 	/*
+	 * DWC3 hangs on OUT requests smaller than maxpacket size,
+	 * so HACK the request length
+	 */
+	if (dep->direction == 0 &&
+	    req->request.length < dep->endpoint.maxpacket)
+		req->request.length = dep->endpoint.maxpacket;
+
+	/*
 	 * We only add to our list of requests now and
 	 * start consuming the list once we get XferNotReady
 	 * IRQ.
Signature · 1 line
2.0.0.rc2
#28 lore raw

PATCH 9/14 usb: dwc3: gadget: add common endpoint configuration for dwc3 udc driver

In reply to Lukasz Majewski

From: Marek Szyprowski <[email protected]>

This patch adds code to select standard, commonly used usb endpoint configuration (ep1in-bulk, ep2out-bulk, ep3in-int) to dwc3 driver. This ensures compatibility with old userspace and windows drivers, which expects hardcoded endpoint numbers.

---
 drivers/usb/gadget/epautoconf.c   | 24 +++++++++++++++++++++++-
 drivers/usb/gadget/gadget_chips.h |  8 ++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)
drivers/usb/gadget/epautoconf.c +23 -1
index 0df4b2a..6ddbe83 100644
@@ -220,7 +220,7 @@ struct usb_ep *usb_ep_autoconfig(
 	struct usb_endpoint_descriptor	*desc
 )
 {
-	struct usb_ep	*ep;
+	struct usb_ep	*ep = NULL;
 	u8		type;
 
 	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
@@ -261,6 +261,28 @@ struct usb_ep *usb_ep_autoconfig(
 		ep = find_ep(gadget, "ep1-bulk");
 		if (ep && ep_matches(gadget, ep, desc))
 			return ep;
+	} else if (gadget_is_dwc3(gadget)) {
+		const char *name = NULL;
+		/*
+		 * First try standard, common configuration: ep1in-bulk,
+		 * ep2out-bulk, ep3in-int to match other udc drivers to avoid
+		 * confusion in already deployed software (endpoint numbers
+		 * hardcoded in userspace software/drivers)
+		 */
+		if ((desc->bEndpointAddress & USB_DIR_IN) &&
+		    type == USB_ENDPOINT_XFER_BULK)
+			name = "ep1in";
+		else if ((desc->bEndpointAddress & USB_DIR_IN) == 0 &&
+			 type == USB_ENDPOINT_XFER_BULK)
+			name = "ep2out";
+		else if ((desc->bEndpointAddress & USB_DIR_IN) &&
+			 type == USB_ENDPOINT_XFER_INT)
+			name = "ep3in";
+
+		if (name)
+			ep = find_ep(gadget, name);
+		if (ep && ep_matches(gadget, ep, desc))
+			return ep;
 	}
 
 	/* Second, look at endpoints until an unclaimed one looks usable */
drivers/usb/gadget/gadget_chips.h +8 -0
index cc94771..c859df2 100644
@@ -156,6 +156,14 @@
 #define gadget_is_fotg210(g)        0
 #endif
 
+#ifdef CONFIG_USB_DWC3_GADGET
+#define gadget_is_dwc3(g)        (!strcmp("dwc3-gadget", (g)->name))
+#else
+#define gadget_is_dwc3(g)        0
+#endif
+
+
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
Signature · 1 line
2.0.0.rc2
#29 lore raw

PATCH 10/14 usb: dwc3: optimize interrupt loop

In reply to Lukasz Majewski

From: Marek Szyprowski <[email protected]>

There is no point in calling dwc3_thread_interrupt() if no event is pending. There is also no point in flushing event cache in EVERY loop iteration.

---
 drivers/usb/dwc3/core.c   |  7 -------
 drivers/usb/dwc3/gadget.c | 15 +++++++++++++--
 2 files changed, 13 insertions(+), 9 deletions(-)
drivers/usb/dwc3/core.c +0 -7
index 45bb724..d067ef3 100644
@@ -766,18 +766,11 @@ void dwc3_uboot_exit(int index)
 void dwc3_uboot_handle_interrupt(int index)
 {
 	struct dwc3 *dwc = NULL;
-	int i;
-	struct dwc3_event_buffer *evt;
 
 	list_for_each_entry(dwc, &dwc3_list, list) {
 		if (dwc->index != index)
 			continue;
 
-		for (i = 0; i < dwc->num_event_buffers; i++) {
-			evt = dwc->ev_buffs[i];
-			dwc3_flush_cache((int)evt->buf, evt->length);
-		}
-
 		dwc3_gadget_uboot_handle_interrupt(dwc);
 		break;
 	}
drivers/usb/dwc3/gadget.c +13 -2
index 737cb3e..d5dc70c 100644
@@ -2681,6 +2681,17 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
  */
 void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc)
 {
-	dwc3_interrupt(0, dwc);
-	dwc3_thread_interrupt(0, dwc);
+	int ret = dwc3_interrupt(0, dwc);
+
+	if (ret == IRQ_WAKE_THREAD) {
+		int i;
+		struct dwc3_event_buffer *evt;
+
+		for (i = 0; i < dwc->num_event_buffers; i++) {
+			evt = dwc->ev_buffs[i];
+			dwc3_flush_cache((int)evt->buf, evt->length);
+		}
+
+		dwc3_thread_interrupt(0, dwc);
+	}
 }
Signature · 1 line
2.0.0.rc2
#30 lore raw

PATCH 11/14 usb: dwc3: gadget: Set all ctrl fields of Transfer Control Blocks (TRB) to be LST

In reply to Lukasz Majewski

It turned out that current dwc3 gadget code is preparing multiple TRBs for a transfer. Unfortunately, when multiple requests are in the same queue, only for the last one the LST (last) ctrl bit is set.

Due to that dwc3 HW executes all TRBs up till the one marked as last. Unfortunately, UMS requires call of ->complete callback after any send TRB. This is the reason for "hangs" in executing UMS.

This code simplifies this situation and set each TRB's ctrl field bit to be last (LST bit).

---
 drivers/usb/dwc3/gadget.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)
drivers/usb/dwc3/gadget.c +2 -13
index d5dc70c..0c7082c 100644
@@ -787,7 +787,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 	struct dwc3_request	*req, *n;
 	u32			trbs_left;
 	u32			max;
-	unsigned int		last_one = 0;
 
 	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
 
@@ -837,24 +836,14 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 	list_for_each_entry_safe(req, n, &dep->request_list, list) {
 		unsigned	length;
 		dma_addr_t	dma;
-		last_one = false;
 
 		dma = req->request.dma;
 		length = req->request.length;
-		trbs_left--;
-
-		if (!trbs_left)
-			last_one = 1;
-
-		/* Is this the last request? */
-		if (list_is_last(&req->list, &dep->request_list))
-			last_one = 1;
 
 		dwc3_prepare_one_trb(dep, req, dma, length,
-				last_one, false, 0);
+				     true, false, 0);
 
-		if (last_one)
-			break;
+		break;
 	}
 }
 
Signature · 1 line
2.0.0.rc2
#31 lore raw

PATCH 12/14 usb: dwc3: gadget: Set non EP0 max packet limit to 512B

In reply to Lukasz Majewski

Commit "drivers/dwc3: add a workaround for too small OUT requests" sets max packet for OUT requests when transfer is smaller.

Until this change the default maxpacket for non EP0 EPs was 1024. This is too much, since UMS LBA size is 512B

---
 drivers/usb/dwc3/gadget.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/dwc3/gadget.c +1 -1
index 0c7082c..b282f6a 100644
@@ -1603,7 +1603,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 		} else {
 			int		ret;
 
-			usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);
+			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
 			dep->endpoint.max_streams = 15;
 			dep->endpoint.ops = &dwc3_gadget_ep_ops;
 			list_add_tail(&dep->endpoint.ep_list,
Signature · 1 line
2.0.0.rc2
#32 lore raw

PATCH 13/14 usb: dwc3: Correct clean up code for requests

In reply to Lukasz Majewski

For u-boot dwc3 driver the scatter gather list support has been removed from original linux code. It is correct, since we try to send one request at a time.
However, the cleanup left spurious break, which caused early exit from loop at dwc3_cleanup_done_reqs() function. As a result the dwc3_gadget_giveback() wasn't called and caused USB Mass Storage to hang.

This commit removes this problem and refactor the code to remove superfluous do { } while(1) loop.

Test HW: Odroid XU3 (with ./test/ums/ums_gadget_test.sh)

---
 drivers/usb/dwc3/gadget.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/usb/dwc3/gadget.c +14 -24
index b282f6a..763c951 100644
@@ -1753,33 +1753,23 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 	struct dwc3_request	*req;
 	struct dwc3_trb		*trb;
 	unsigned int		slot;
-	int			ret;
-
-	do {
-		req = next_request(&dep->req_queued);
-		if (!req) {
-			WARN_ON_ONCE(1);
-			return 1;
-		}
-
-		slot = req->start_slot;
-		if ((slot == DWC3_TRB_NUM - 1) &&
-			usb_endpoint_xfer_isoc(dep->endpoint.desc))
-			slot++;
-		slot %= DWC3_TRB_NUM;
-		trb = &dep->trb_pool[slot];
 
-		dwc3_flush_cache((int)trb, sizeof(*trb));
-		ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
-				event, status);
-		if (ret)
-			break;
+	req = next_request(&dep->req_queued);
+	if (!req) {
+		WARN_ON_ONCE(1);
+		return 1;
+	}
 
-		dwc3_gadget_giveback(dep, req, status);
+	slot = req->start_slot;
+	if ((slot == DWC3_TRB_NUM - 1) &&
+	    usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		slot++;
+	slot %= DWC3_TRB_NUM;
+	trb = &dep->trb_pool[slot];
 
-		if (ret)
-			break;
-	} while (1);
+	dwc3_flush_cache((int)trb, sizeof(*trb));
+	__dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
+	dwc3_gadget_giveback(dep, req, status);
 
 	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
 			list_empty(&dep->req_queued)) {
Signature · 1 line
2.0.0.rc2
#33 lore raw

PATCH 14/14 usb: gadget: thor: Claim EP after allocating it in thor gadget

In reply to Lukasz Majewski

From: Marek Szyprowski <[email protected]>

Storing thor device struct as an EP private data. It is necessary for DWC3 operation.

---
 drivers/usb/gadget/f_thor.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/usb/gadget/f_thor.c +3 -0
index 1fd41ff..6346370 100644
@@ -806,6 +806,7 @@ static int thor_func_bind(struct usb_configuration *c, struct usb_function *f)
 	}
 
 	dev->in_ep = ep; /* Store IN EP for enabling @ setup */
+	ep->driver_data = dev;
 
 	ep = usb_ep_autoconfig(gadget, &fs_out_desc);
 	if (!ep) {
@@ -818,6 +819,7 @@ static int thor_func_bind(struct usb_configuration *c, struct usb_function *f)
 				fs_out_desc.bEndpointAddress;
 
 	dev->out_ep = ep; /* Store OUT EP for enabling @ setup */
+	ep->driver_data = dev;
 
 	ep = usb_ep_autoconfig(gadget, &fs_int_desc);
 	if (!ep) {
@@ -826,6 +828,7 @@ static int thor_func_bind(struct usb_configuration *c, struct usb_function *f)
 	}
 
 	dev->int_ep = ep;
+	ep->driver_data = dev;
 
 	if (gadget_is_dualspeed(gadget)) {
 		hs_int_desc.bEndpointAddress =
Signature · 1 line
2.0.0.rc2
#34 lore raw

cover usb: dwc3: Fixes and improvements for DWC3 driver

In reply to Lukasz Majewski
Quoted 11 lines · Lukasz Majewski

This patch set should be applied on top of recent Kishon Vijay Abraham I work (v2) regarding providing dwc3 support to u-boot as well as clean up of the linux-compat header file.

For the whole patch set please refer to -dfu u-boot repo, branch (devel/dwc3_gadget):
http://git.denx.de/?p=u-boot/u-boot-dfu.git;a=shortlog;h=refs/heads/devel/d
wc3_gadget

This patch set fixes things, so all Samsung boards compile after applying DWC3 support.

I picked this all into the topic/dwc3 branch and replaced the old patches. Please let me know if there's something broken.

Thanks!

Best regards,
Marek Vasut