Hi,

John Youn <[email protected]> writes:
> ENDXFER polling is available on version 3.10a and later of the
> DWC_usb3 (USB 3.0) controller. With this feature, the software can poll
> the CMDACT bit in the DEPCMD register after issuing an ENDXFER command.
> This feature is enabled by writing GUCTL2[14].
>
> This feature is NOT available on the DWC_usb31 (USB 3.1) IP.
>
> Signed-off-by: John Youn <[email protected]>
> ---
>  drivers/usb/dwc3/core.c   | 11 +++++++++++
>  drivers/usb/dwc3/core.h   |  4 ++++
>  drivers/usb/dwc3/gadget.c | 31 ++++++++++++++++++++++++++++++-
>  3 files changed, 45 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 71ac7c2..057739d 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -704,6 +704,17 @@ static int dwc3_core_init(struct dwc3 *dwc)
>               break;
>       }
>  
> +     /*
> +      * ENDXFER polling is available on version 3.10a and later of
> +      * the DWC_usb3 controller. It is NOT available in the
> +      * DWC_usb31 controller.
> +      */
> +     if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
> +             reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
> +             reg |= DWC3_GUCTL2_RST_ACTBITLATER;
> +             dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
> +     }
> +
>       return 0;
>  
>  err4:
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 002e647..b2317e7 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -109,6 +109,7 @@
>  #define DWC3_GPRTBIMAP_HS1   0xc184
>  #define DWC3_GPRTBIMAP_FS0   0xc188
>  #define DWC3_GPRTBIMAP_FS1   0xc18c
> +#define DWC3_GUCTL2          0xc19c
>  
>  #define DWC3_VER_NUMBER              0xc1a0
>  #define DWC3_VER_TYPE                0xc1a4
> @@ -288,6 +289,9 @@
>  #define DWC3_GFLADJ_30MHZ_SDBND_SEL          (1 << 7)
>  #define DWC3_GFLADJ_30MHZ_MASK                       0x3f
>  
> +/* Global User Control Register 2 */
> +#define DWC3_GUCTL2_RST_ACTBITLATER          (1 << 14)
> +
>  /* Device Configuration Register */
>  #define DWC3_DCFG_DEVADDR(addr)      ((addr) << 3)
>  #define DWC3_DCFG_DEVADDR_MASK       DWC3_DCFG_DEVADDR(0x7f)
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index c6fe9a3..823e65d 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -2202,6 +2202,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, 
> u32 epnum, bool force)
>       struct dwc3_gadget_ep_cmd_params params;
>       u32 cmd;
>       int ret;
> +     unsigned int timeout;
>  
>       dep = dwc->eps[epnum];
>  
> @@ -2225,6 +2226,14 @@ static void dwc3_stop_active_transfer(struct dwc3 
> *dwc, u32 epnum, bool force)
>        *
>        * - Issue EndTransfer WITH CMDIOC bit set
>        * - Wait 100us
> +      *
> +      * As of IP version 3.10a of the DWC_usb3 IP, the controller
> +      * supports a mode to work around the above limitation. The
> +      * software can poll the CMDACT bit in the DEPCMD register
> +      * after issuing a EndTransfer command. This mode is enabled
> +      * by writing GUCTL2[14].
> +      *
> +      * This mode is NOT available on the DWC_usb31 IP.
>        */
>  
>       cmd = DWC3_DEPCMD_ENDTRANSFER;
> @@ -2236,7 +2245,27 @@ static void dwc3_stop_active_transfer(struct dwc3 
> *dwc, u32 epnum, bool force)
>       WARN_ON_ONCE(ret);
>       dep->resource_index = 0;
>       dep->flags &= ~DWC3_EP_BUSY;
> -     udelay(100);
> +
> +     if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) {
> +             udelay(100);
> +             return;
> +     }
> +
> +     timeout = 100;
> +
> +     do {
> +             cmd = dwc3_readl(dep->regs, DWC3_DEPCMD);
> +             if (!(cmd & DWC3_DEPCMD_CMDACT))
> +                     break;

we're already polling CMDACT bit when we send the command. Do we _need_
to poll it again? Seems like the check above for running udelay(100) is
enough. Just remove the return call from there.

> +             timeout--;
> +             if (!timeout) {
> +                     dev_err(dwc->dev, "EndTransfer didn't complete\n");
> +                     break;
> +             }
> +
> +             udelay(1);
> +     } while (1);

not into infinite loops, actually :-) See my recent patches removing
these infinite loops and udelay(1) calls.

-- 
balbi

Attachment: signature.asc
Description: PGP signature

Reply via email to