|
@@ -270,27 +270,36 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
|
|
|
const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
|
|
|
struct dwc3 *dwc = dep->dwc;
|
|
|
u32 timeout = 1000;
|
|
|
+ u32 saved_config = 0;
|
|
|
u32 reg;
|
|
|
|
|
|
int cmd_status = 0;
|
|
|
- int susphy = false;
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
/*
|
|
|
- * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if
|
|
|
- * we're issuing an endpoint command, we must check if
|
|
|
- * GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it.
|
|
|
+ * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or
|
|
|
+ * GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an
|
|
|
+ * endpoint command.
|
|
|
*
|
|
|
- * We will also set SUSPHY bit to what it was before returning as stated
|
|
|
- * by the same section on Synopsys databook.
|
|
|
+ * Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY
|
|
|
+ * settings. Restore them after the command is completed.
|
|
|
+ *
|
|
|
+ * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
|
|
|
*/
|
|
|
if (dwc->gadget.speed <= USB_SPEED_HIGH) {
|
|
|
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
|
|
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
|
|
|
- susphy = true;
|
|
|
+ saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
|
|
|
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
|
|
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
|
|
}
|
|
|
+
|
|
|
+ if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) {
|
|
|
+ saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM;
|
|
|
+ reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (saved_config)
|
|
|
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
|
|
}
|
|
|
|
|
|
if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
|
|
@@ -389,9 +398,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (unlikely(susphy)) {
|
|
|
+ if (saved_config) {
|
|
|
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
|
|
- reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
|
|
+ reg |= saved_config;
|
|
|
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
|
|
}
|
|
|
|