usb: dwc3: gadget: Preserve UDC max speed setting
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 <wcheng@codeaurora.org> Link: https://lore.kernel.org/r/1609283136-22140-3-git-send-email-wcheng@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
77adb8bdf4
Коммит
7c9a259846
|
@ -1125,6 +1125,7 @@ struct dwc3 {
|
|||
u32 nr_scratch;
|
||||
u32 u1u2;
|
||||
u32 maximum_speed;
|
||||
u32 gadget_max_speed;
|
||||
|
||||
u32 ip;
|
||||
|
||||
|
|
|
@ -2036,6 +2036,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;
|
||||
|
@ -2058,6 +2113,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;
|
||||
|
@ -2420,59 +2476,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(&dwc->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;
|
||||
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", speed);
|
||||
|
||||
if (DWC3_IP_IS(DWC3))
|
||||
reg |= DWC3_DCFG_SUPERSPEED;
|
||||
else
|
||||
reg |= DWC3_DCFG_SUPERSPEED_PLUS;
|
||||
}
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
dwc->gadget_max_speed = speed;
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче