From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marek Vasut Date: Wed, 17 Apr 2019 20:54:58 +0200 Subject: [U-Boot] [PATCH] usb: dwc2: fix gadget disconnect In-Reply-To: <1555512373-10142-1-git-send-email-fabrice.gasnier@st.com> References: <1555512373-10142-1-git-send-email-fabrice.gasnier@st.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 Reviewed-by: Marek Vasut 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(®->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, ®->gotgint); > } > > if (intr_status & INT_RESUME) { > -- Best regards, Marek Vasut