[U-Boot] [PATCH] usb: dwc2: fix gadget disconnect

Fabrice Gasnier fabrice.gasnier at st.com
Wed Apr 17 14:46:13 UTC 2019


This fixes a disconnect issue detected with fastboot command, when using
dwc2 driver.
- On u-boot side:
uboot>$ fastboot 0
- On USB host PC side, few seconds after
PC>$ fastboot reboot # Get stuck, uboot target never reboots

By enabling DEBUG_ISR logs, the bus suspend interrupt is seen before the
PC command has been issued. When the USB bus suspend occurs, there's a HACK
that disables the fastboot (composite driver). Here is the call stack
upon USB bus suspend:
- dwc2_handle_usb_suspend_intr()
  - dev->driver->disconnect()
    - composite_disconnect()
      - reset_config()
        - f->disable()
          - fastboot_disable()
            - usb_ep_disable(f_fb->out_ep);
            - usb_ep_disable(f_fb->in_ep);
            .. other disable calls.

When the resume interrupt happens, everything has been disabled, then
nothing happens. fastboot command gets stuck on HOST side.

Remove original HACK, that disconnects the composite driver upon
USB bus suspend. Implement disconnect detection instead:
- check GINTSTS OTG interrupt
- read GOTGINT register
- check GOTGINT, SesEndDet bit (e.g. session end)
This is inspired by what is implemented currently in Linux dwc2 driver.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier at st.com>
---

 drivers/usb/gadget/dwc2_udc_otg_regs.h     |  6 +++++-
 drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 14 ++++++++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h
index a1829b3..b685256 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_regs.h
+++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h
@@ -86,6 +86,9 @@ struct dwc2_usbotg_reg {
 #define B_SESSION_VALID		(0x1<<19)
 #define A_SESSION_VALID		(0x1<<18)
 
+/* DWC2_UDC_OTG_GOTINT */
+#define GOTGINT_SES_END_DET		(1<<2)
+
 /* DWC2_UDC_OTG_GAHBCFG */
 #define PTXFE_HALF			(0<<8)
 #define PTXFE_ZERO			(1<<8)
@@ -118,6 +121,7 @@ struct dwc2_usbotg_reg {
 #define INT_NP_TX_FIFO_EMPTY		(0x1<<5)
 #define INT_RX_FIFO_NOT_EMPTY		(0x1<<4)
 #define INT_SOF			(0x1<<3)
+#define INT_OTG			(0x1<<2)
 #define INT_DEV_MODE			(0x0<<0)
 #define INT_HOST_MODE			(0x1<<1)
 #define INT_GOUTNakEff			(0x01<<7)
@@ -246,7 +250,7 @@ struct dwc2_usbotg_reg {
 
 /* Masks definitions */
 #define GINTMSK_INIT	(INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\
-			| INT_RESET | INT_SUSPEND)
+			| INT_RESET | INT_SUSPEND | INT_OTG)
 #define DOEPMSK_INIT	(CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE)
 #define DIEPMSK_INIT	(NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE)
 #define GAHBCFG_INIT	(PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\
diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
index a75af49..7eb632d 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
+++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
@@ -467,7 +467,7 @@ static void process_ep_out_intr(struct dwc2_udc *dev)
 static int dwc2_udc_irq(int irq, void *_dev)
 {
 	struct dwc2_udc *dev = _dev;
-	u32 intr_status;
+	u32 intr_status, gotgint;
 	u32 usb_status, gintmsk;
 	unsigned long flags = 0;
 
@@ -521,14 +521,24 @@ static int dwc2_udc_irq(int irq, void *_dev)
 		    && dev->driver) {
 			if (dev->driver->suspend)
 				dev->driver->suspend(&dev->gadget);
+		}
+	}
+
+	if (intr_status & INT_OTG) {
+		gotgint = readl(&reg->gotgint);
+		debug_cond(DEBUG_ISR,
+			   "\tOTG interrupt: (GOTGINT):0x%x\n", gotgint);
 
-			/* HACK to let gadget detect disconnected state */
+		if (gotgint & GOTGINT_SES_END_DET) {
+			debug_cond(DEBUG_ISR, "\t\tSession End Detected\n");
+			/* Let gadget detect disconnected state */
 			if (dev->driver->disconnect) {
 				spin_unlock_irqrestore(&dev->lock, flags);
 				dev->driver->disconnect(&dev->gadget);
 				spin_lock_irqsave(&dev->lock, flags);
 			}
 		}
+		writel(gotgint, &reg->gotgint);
 	}
 
 	if (intr_status & INT_RESUME) {
-- 
2.7.4



More information about the U-Boot mailing list