[PATCH v2 2/2] usb: dwc3: gadget: Preserve UDC max speed setting

2020-12-29 Thread Wesley Cheng
The USB gadget/UDC driver can restrict the DWC3 controller speed using
dwc3_gadget_set_speed().  Store this setting into a variable, in order for
this setting to persist across controller resets due to runtime PM.

Signed-off-by: Wesley Cheng 
---
 drivers/usb/dwc3/core.h   |   1 +
 drivers/usb/dwc3/gadget.c | 108 --
 2 files changed, 58 insertions(+), 51 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 2f04b3e42bf1..390d3deef0ba 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1119,6 +1119,7 @@ struct dwc3 {
u32 nr_scratch;
u32 u1u2;
u32 maximum_speed;
+   u32 gadget_max_speed;
 
u32 ip;
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index babf977cadc0..c145da1d8ba5 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1941,6 +1941,61 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
}
 }
 
+static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
+{
+   u32 reg;
+
+   reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+   reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+   /*
+* WORKAROUND: DWC3 revision < 2.20a have an issue
+* which would cause metastability state on Run/Stop
+* bit if we try to force the IP to USB2-only mode.
+*
+* Because of that, we cannot configure the IP to any
+* speed other than the SuperSpeed
+*
+* Refers to:
+*
+* STAR#9000525659: Clock Domain Crossing on DCTL in
+* USB 2.0 Mode
+*/
+   if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
+   !dwc->dis_metastability_quirk) {
+   reg |= DWC3_DCFG_SUPERSPEED;
+   } else {
+   switch (dwc->gadget_max_speed) {
+   case USB_SPEED_LOW:
+   reg |= DWC3_DCFG_LOWSPEED;
+   break;
+   case USB_SPEED_FULL:
+   reg |= DWC3_DCFG_FULLSPEED;
+   break;
+   case USB_SPEED_HIGH:
+   reg |= DWC3_DCFG_HIGHSPEED;
+   break;
+   case USB_SPEED_SUPER:
+   reg |= DWC3_DCFG_SUPERSPEED;
+   break;
+   case USB_SPEED_SUPER_PLUS:
+   if (DWC3_IP_IS(DWC3))
+   reg |= DWC3_DCFG_SUPERSPEED;
+   else
+   reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+   break;
+   default:
+   dev_err(dwc->dev, "invalid speed (%d)\n", 
dwc->gadget_max_speed);
+
+   if (DWC3_IP_IS(DWC3))
+   reg |= DWC3_DCFG_SUPERSPEED;
+   else
+   reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+   }
+   }
+   dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
 static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 {
u32 reg;
@@ -1963,6 +2018,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int 
is_on, int suspend)
if (dwc->has_hibernation)
reg |= DWC3_DCTL_KEEP_CONNECT;
 
+   __dwc3_gadget_set_speed(dwc);
dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
@@ -2325,59 +2381,9 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g,
 {
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long   flags;
-   u32 reg;
 
spin_lock_irqsave(>lock, flags);
-   reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-   reg &= ~(DWC3_DCFG_SPEED_MASK);
-
-   /*
-* WORKAROUND: DWC3 revision < 2.20a have an issue
-* which would cause metastability state on Run/Stop
-* bit if we try to force the IP to USB2-only mode.
-*
-* Because of that, we cannot configure the IP to any
-* speed other than the SuperSpeed
-*
-* Refers to:
-*
-* STAR#9000525659: Clock Domain Crossing on DCTL in
-* USB 2.0 Mode
-*/
-   if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
-   !dwc->dis_metastability_quirk) {
-   reg |= DWC3_DCFG_SUPERSPEED;
-   } else {
-   switch (speed) {
-   case USB_SPEED_LOW:
-   reg |= DWC3_DCFG_LOWSPEED;
-   break;
-   case USB_SPEED_FULL:
-   reg |= DWC3_DCFG_FULLSPEED;
-   break;
-   case USB_SPEED_HIGH:
-   reg |= DWC3_DCFG_HIGHSPEED;
-   break;
-   case USB_SPEED_SUPER:
-   reg |= DWC3_DCFG_SUPERSPEED;
-  

[PATCH v2 2/2] usb: dwc3: gadget: Preserve UDC max speed setting

2020-11-05 Thread Wesley Cheng
The USB gadget/UDC driver can restrict the DWC3 controller speed using
dwc3_gadget_set_speed().  Store this setting into a variable, in order for
this setting to persist across controller resets due to runtime PM.

Signed-off-by: Wesley Cheng 
---
 drivers/usb/dwc3/core.h   |   1 +
 drivers/usb/dwc3/gadget.c | 108 --
 2 files changed, 58 insertions(+), 51 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 2f04b3e42bf1..390d3deef0ba 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1119,6 +1119,7 @@ struct dwc3 {
u32 nr_scratch;
u32 u1u2;
u32 maximum_speed;
+   u32 gadget_max_speed;
 
u32 ip;
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index babf977cadc0..c145da1d8ba5 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1941,6 +1941,61 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
}
 }
 
+static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
+{
+   u32 reg;
+
+   reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+   reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+   /*
+* WORKAROUND: DWC3 revision < 2.20a have an issue
+* which would cause metastability state on Run/Stop
+* bit if we try to force the IP to USB2-only mode.
+*
+* Because of that, we cannot configure the IP to any
+* speed other than the SuperSpeed
+*
+* Refers to:
+*
+* STAR#9000525659: Clock Domain Crossing on DCTL in
+* USB 2.0 Mode
+*/
+   if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
+   !dwc->dis_metastability_quirk) {
+   reg |= DWC3_DCFG_SUPERSPEED;
+   } else {
+   switch (dwc->gadget_max_speed) {
+   case USB_SPEED_LOW:
+   reg |= DWC3_DCFG_LOWSPEED;
+   break;
+   case USB_SPEED_FULL:
+   reg |= DWC3_DCFG_FULLSPEED;
+   break;
+   case USB_SPEED_HIGH:
+   reg |= DWC3_DCFG_HIGHSPEED;
+   break;
+   case USB_SPEED_SUPER:
+   reg |= DWC3_DCFG_SUPERSPEED;
+   break;
+   case USB_SPEED_SUPER_PLUS:
+   if (DWC3_IP_IS(DWC3))
+   reg |= DWC3_DCFG_SUPERSPEED;
+   else
+   reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+   break;
+   default:
+   dev_err(dwc->dev, "invalid speed (%d)\n", 
dwc->gadget_max_speed);
+
+   if (DWC3_IP_IS(DWC3))
+   reg |= DWC3_DCFG_SUPERSPEED;
+   else
+   reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+   }
+   }
+   dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
 static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 {
u32 reg;
@@ -1963,6 +2018,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int 
is_on, int suspend)
if (dwc->has_hibernation)
reg |= DWC3_DCTL_KEEP_CONNECT;
 
+   __dwc3_gadget_set_speed(dwc);
dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
@@ -2325,59 +2381,9 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g,
 {
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long   flags;
-   u32 reg;
 
spin_lock_irqsave(>lock, flags);
-   reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-   reg &= ~(DWC3_DCFG_SPEED_MASK);
-
-   /*
-* WORKAROUND: DWC3 revision < 2.20a have an issue
-* which would cause metastability state on Run/Stop
-* bit if we try to force the IP to USB2-only mode.
-*
-* Because of that, we cannot configure the IP to any
-* speed other than the SuperSpeed
-*
-* Refers to:
-*
-* STAR#9000525659: Clock Domain Crossing on DCTL in
-* USB 2.0 Mode
-*/
-   if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
-   !dwc->dis_metastability_quirk) {
-   reg |= DWC3_DCFG_SUPERSPEED;
-   } else {
-   switch (speed) {
-   case USB_SPEED_LOW:
-   reg |= DWC3_DCFG_LOWSPEED;
-   break;
-   case USB_SPEED_FULL:
-   reg |= DWC3_DCFG_FULLSPEED;
-   break;
-   case USB_SPEED_HIGH:
-   reg |= DWC3_DCFG_HIGHSPEED;
-   break;
-   case USB_SPEED_SUPER:
-   reg |= DWC3_DCFG_SUPERSPEED;
-