[U-Boot] [PATCH 00/11] 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(-)

DWC3 UDC driver requires presence of .reset callback in a composite driver. This setting is similar to the one nowadays present in linux kernel.
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/gadget/composite.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 729a0fa..d96296c 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -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,

Added #includes are necessary to allow dwc3 to compile and run on u-boot for Odroid XU3.
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/linux-compat.h | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h index b36f68f..40470aa 100644 --- a/drivers/usb/dwc3/linux-compat.h +++ b/drivers/usb/dwc3/linux-compat.h @@ -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)

Hi,
On Monday 23 February 2015 07:32 PM, Lukasz Majewski wrote:
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.
Signed-off-by: Lukasz Majewski l.majewski@samsung.com
drivers/usb/dwc3/linux-compat.h | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h index b36f68f..40470aa 100644 --- a/drivers/usb/dwc3/linux-compat.h +++ b/drivers/usb/dwc3/linux-compat.h @@ -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

From: Inha Song ideal.song@samsung.com
Signed-off-by: Inha Song ideal.song@samsung.com --- drivers/usb/dwc3/core.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 3f8a4e9..3355468 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -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;

On Monday, February 23, 2015 at 03:02:24 PM, Lukasz Majewski wrote:
From: Inha Song ideal.song@samsung.com
Signed-off-by: Inha Song ideal.song@samsung.com
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

From: Joonyoung Shim jy0922.shim@samsung.com
Signed-off-by: Joonyoung Shim jy0922.shim@samsung.com --- drivers/usb/dwc3/core.c | 2 +- drivers/usb/dwc3/core.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4c3637f..d690870 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -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;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 3355468..45e431b 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -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

Hi,
On Monday 23 February 2015 07:32 PM, Lukasz Majewski wrote:
From: Joonyoung Shim jy0922.shim@samsung.com
commit message please.
-Kishon
Signed-off-by: Joonyoung Shim jy0922.shim@samsung.com
drivers/usb/dwc3/core.c | 2 +- drivers/usb/dwc3/core.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4c3637f..d690870 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -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;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 3355468..45e431b 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -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

Signed-off-by: Joonyoung Shim jy0922.shim@samsung.com Signed-off-by: Lukasz Majewski l.majewski@samsung.com [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(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d690870..fc3b0d9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -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"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 45e431b..304e0c1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -727,6 +727,7 @@ struct dwc3 {
void __iomem *regs; size_t regs_size; + void __iomem *phy_regs;
enum usb_dr_mode dr_mode;
diff --git a/include/dwc3-uboot.h b/include/dwc3-uboot.h index 09ff8a7..4c363cb 100644 --- a/include/dwc3-uboot.h +++ b/include/dwc3-uboot.h @@ -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;

Hi,
On Monday 23 February 2015 07:32 PM, Lukasz Majewski wrote:
commit message here again.
Signed-off-by: Joonyoung Shim jy0922.shim@samsung.com Signed-off-by: Lukasz Majewski l.majewski@samsung.com [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(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d690870..fc3b0d9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -14,7 +14,12 @@
- SPDX-License-Identifier: GPL-2.0
*/
+#include "linux-compat.h"
This is already included.
- #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.
+#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);
+}
This function shouldn't be here at all.
- /**
- 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");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 45e431b..304e0c1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -727,6 +727,7 @@ struct dwc3 {
void __iomem *regs; size_t regs_size;
void __iomem *phy_regs;
enum usb_dr_mode dr_mode;
diff --git a/include/dwc3-uboot.h b/include/dwc3-uboot.h index 09ff8a7..4c363cb 100644 --- a/include/dwc3-uboot.h +++ b/include/dwc3-uboot.h @@ -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

From: Marek Szyprowski m.szyprowski@samsung.com
DWC3 hangs on OUT requests smaller than maxpacket size, so HACK the request length to be at least equal to maxpacket size.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/usb/dwc3/gadget.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 01bc83b..f8a75d3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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

Hi,
On Monday 23 February 2015 07:32 PM, Lukasz Majewski wrote:
From: Marek Szyprowski m.szyprowski@samsung.com
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
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com
drivers/usb/dwc3/gadget.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 01bc83b..f8a75d3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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

Hi Kishon,
Hi,
On Monday 23 February 2015 07:32 PM, Lukasz Majewski wrote:
From: Marek Szyprowski m.szyprowski@samsung.com
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:
Testing: *) tested DFU RAM and DFU MMC in dra7xx and am43xx
Have you tried to run test at ./test/dfu directory?
Thanks Kishon
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com
drivers/usb/dwc3/gadget.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 01bc83b..f8a75d3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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

Hi,
On Monday 23 February 2015 08:14 PM, Lukasz Majewski wrote:
Hi Kishon,
Hi,
On Monday 23 February 2015 07:32 PM, Lukasz Majewski wrote:
From: Marek Szyprowski m.szyprowski@samsung.com
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!
In the v2 commit letter you have stated that this code was tested with DFU MMC:
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

From: Marek Szyprowski m.szyprowski@samsung.com
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.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/usb/gadget/epautoconf.c | 21 ++++++++++++++++++++- drivers/usb/gadget/gadget_chips.h | 8 ++++++++ 2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 0df4b2a..899f254 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -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 */ diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index cc94771..c859df2 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -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

From: Marek Szyprowski m.szyprowski@samsung.com
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.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/usb/dwc3/core.c | 7 ------- drivers/usb/dwc3/gadget.c | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index fc3b0d9..846475a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -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; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f8a75d3..4a4923f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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); + } }

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).
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/gadget.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4a4923f..810e224 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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; } }

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
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 810e224..97f23e5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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,

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)
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/gadget.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 97f23e5..cb15a38 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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)) {

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/dw...
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(-)

This definition is necessary for Exynos based boards to work properly.
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- board/samsung/common/board.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c index 6c7f59b..7b10877 100644 --- a/board/samsung/common/board.c +++ b/board/samsung/common/board.c @@ -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; +}

This definition is necessary for S5PC110 based GONI board to work properly.
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- board/samsung/goni/goni.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/board/samsung/goni/goni.c b/board/samsung/goni/goni.c index 58cf96e..d943d63 100644 --- a/board/samsung/goni/goni.c +++ b/board/samsung/goni/goni.c @@ -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; +}

From: Inha Song ideal.song@samsung.com
This patch invokes board-specific USB cleanup (board_usb_cleanup) function in the mass storage gadget
Signed-off-by: Inha Song ideal.song@samsung.com --- common/cmd_usb_mass_storage.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/common/cmd_usb_mass_storage.c b/common/cmd_usb_mass_storage.c index c5f909d..ccd4cc5 100644 --- a/common/cmd_usb_mass_storage.c +++ b/common/cmd_usb_mass_storage.c @@ -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; }

From: Inha Song ideal.song@samsung.com
This patch invokes board-specific USB cleanup (board_usb_cleanup) function in the thor gadget.
Signed-off-by: Inha Song ideal.song@samsung.com --- common/cmd_thordown.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/common/cmd_thordown.c b/common/cmd_thordown.c index 8ed1dc6..436b7f5 100644 --- a/common/cmd_thordown.c +++ b/common/cmd_thordown.c @@ -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();

DWC3 UDC driver requires presence of .reset callback in a composite driver. This setting is similar to the one nowadays present in linux kernel.
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/gadget/composite.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 729a0fa..d96296c 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -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,

The BIT() macro is used only in those places, so it is reasonable to replace it by a constant value.
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/core.h | 2 +- drivers/usb/dwc3/gadget.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index c5debf7..5288a18 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -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;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4be4d99..a497fbb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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

From: Joonyoung Shim jy0922.shim@samsung.com
This commit makes the dwc3_set_mode() as static, to prevent collisions.
Signed-off-by: Joonyoung Shim jy0922.shim@samsung.com Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/core.c | 2 +- drivers/usb/dwc3/core.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index aebebb4..45bb724 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -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;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5288a18..72d2fcd 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -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

From: Marek Szyprowski m.szyprowski@samsung.com
DWC3 hangs on OUT requests smaller than maxpacket size, so HACK the request length to be at least equal to maxpacket size.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/usb/dwc3/gadget.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a497fbb..737cb3e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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.

From: Marek Szyprowski m.szyprowski@samsung.com
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.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/usb/gadget/epautoconf.c | 24 +++++++++++++++++++++++- drivers/usb/gadget/gadget_chips.h | 8 ++++++++ 2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 0df4b2a..6ddbe83 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -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 */ diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index cc94771..c859df2 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -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

From: Marek Szyprowski m.szyprowski@samsung.com
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.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/usb/dwc3/core.c | 7 ------- drivers/usb/dwc3/gadget.c | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 45bb724..d067ef3 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -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; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 737cb3e..d5dc70c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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); + } }

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).
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/gadget.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d5dc70c..0c7082c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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; } }

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
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0c7082c..b282f6a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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,

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)
Signed-off-by: Lukasz Majewski l.majewski@samsung.com --- drivers/usb/dwc3/gadget.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b282f6a..763c951 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -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)) {

From: Marek Szyprowski m.szyprowski@samsung.com
Storing thor device struct as an EP private data. It is necessary for DWC3 operation.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/usb/gadget/f_thor.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index 1fd41ff..6346370 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -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 =

On Tuesday, March 03, 2015 at 05:32:02 PM, Lukasz Majewski wrote:
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
participants (3)
-
Kishon Vijay Abraham I
-
Lukasz Majewski
-
Marek Vasut