All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH] usb: dwc2: fix gadget disconnect
@ 2019-04-17 14:46 Fabrice Gasnier
  2019-04-17 18:54 ` Marek Vasut
  2019-04-19  6:30 ` Lukasz Majewski
  0 siblings, 2 replies; 3+ messages in thread
From: Fabrice Gasnier @ 2019-04-17 14:46 UTC (permalink / raw)
  To: u-boot

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@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

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

* [U-Boot] [PATCH] usb: dwc2: fix gadget disconnect
  2019-04-17 14:46 [U-Boot] [PATCH] usb: dwc2: fix gadget disconnect Fabrice Gasnier
@ 2019-04-17 18:54 ` Marek Vasut
  2019-04-19  6:30 ` Lukasz Majewski
  1 sibling, 0 replies; 3+ messages in thread
From: Marek Vasut @ 2019-04-17 18:54 UTC (permalink / raw)
  To: u-boot

On 4/17/19 4:46 PM, Fabrice Gasnier wrote:
> 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@st.com>

Reviewed-by: Marek Vasut <marex@denx.de>

This is Lukasz's topic, so you need his RB too.

Thanks

> ---
> 
>  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) {
> 


-- 
Best regards,
Marek Vasut

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

* [U-Boot] [PATCH] usb: dwc2: fix gadget disconnect
  2019-04-17 14:46 [U-Boot] [PATCH] usb: dwc2: fix gadget disconnect Fabrice Gasnier
  2019-04-17 18:54 ` Marek Vasut
@ 2019-04-19  6:30 ` Lukasz Majewski
  1 sibling, 0 replies; 3+ messages in thread
From: Lukasz Majewski @ 2019-04-19  6:30 UTC (permalink / raw)
  To: u-boot

On Wed, 17 Apr 2019 16:46:13 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> 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@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) {

Acked-by: Lukasz Majewski <lukma@denx.de>

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma at denx.de
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20190419/3d53fe64/attachment.sig>

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

end of thread, other threads:[~2019-04-19  6:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-17 14:46 [U-Boot] [PATCH] usb: dwc2: fix gadget disconnect Fabrice Gasnier
2019-04-17 18:54 ` Marek Vasut
2019-04-19  6:30 ` Lukasz Majewski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.