[2/3] usb: dwc3: workaround: clock gating issues

Message ID 1393364180-15074-2-git-send-email-balbi@ti.com
State Accepted
Commit 32a4a135847b1e600c64756b7c7c7a91eb2f0aa9
Headers show

Commit Message

Felipe Balbi Feb. 25, 2014, 9:36 p.m.
Revisions between 2.10a and 2.50a (included) have
a known issue which may cause xHCI compliance tests
to fail and/or quality issues with Isochronous
transactions.

Note that this issue only impacts certain configurations
of those revisions, namely the ones which have clock
gating enabled.

The suggested workaround is to disable clock gating in
known broken revisions, make sure HW LPM is disabled
and set GCTL.SOFITPSYNC to 1.

Signed-off-by: Felipe Balbi <balbi@ti.com>
---
 drivers/usb/dwc3/core.c | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

Comments

Felipe Balbi Feb. 26, 2014, 3:20 p.m. | #1
On Wed, Feb 26, 2014 at 02:19:38AM +0300, Sergei Shtylyov wrote:
> Hello.
> 
> On 02/26/2014 12:36 AM, Felipe Balbi wrote:
> 
> >Revisions between 2.10a and 2.50a (included) have
> >a known issue which may cause xHCI compliance tests
> >to fail and/or quality issues with Isochronous
> >transactions.
> 
> >Note that this issue only impacts certain configurations
> >of those revisions, namely the ones which have clock
> >gating enabled.
> 
> >The suggested workaround is to disable clock gating in
> >known broken revisions, make sure HW LPM is disabled
> >and set GCTL.SOFITPSYNC to 1.
> 
> >Signed-off-by: Felipe Balbi <balbi@ti.com>
> >---
> >  drivers/usb/dwc3/core.c | 37 ++++++++++++++++++++++++++++---------
> >  1 file changed, 28 insertions(+), 9 deletions(-)
> 
> >diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> >index 1cf1fb5..3270974 100644
> >--- a/drivers/usb/dwc3/core.c
> >+++ b/drivers/usb/dwc3/core.c
> >@@ -389,7 +389,26 @@ static int dwc3_core_init(struct dwc3 *dwc)
> >
> >  	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
> >  	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
> >-		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
> >+		/**
> >+		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
> >+		 * issue which would cause xHCI compliance tests to fail.
> >+		 *
> >+		 * Because of that we cannot enable clock gating on such
> >+		 * configurations.
> >+		 *
> >+		 * Refers to:
> >+		 *
> >+		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
> >+		 * SOF/ITP Mode Used
> >+		 */
> >+		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
> >+				dwc->dr_mode == USB_DR_MODE_OTG) &&
> >+				(dwc->revision >= DWC3_REVISION_210A &&
> >+				dwc->revision <= DWC3_REVISION_250A)) {
> >+			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
> >+		} else {
> >+			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
> >+		}
> 
>    I'm surprised checkpatch.pl doesn't protest about {} here. :-)

hehe, it was supposed to have more lines and then I figured it wouldn't
be needed. I'll remove those braces. Thanks for noticing.

Patch

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 1cf1fb5..3270974 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -389,7 +389,26 @@  static int dwc3_core_init(struct dwc3 *dwc)
 
 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
-		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		/**
+		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
+		 * issue which would cause xHCI compliance tests to fail.
+		 *
+		 * Because of that we cannot enable clock gating on such
+		 * configurations.
+		 *
+		 * Refers to:
+		 *
+		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
+		 * SOF/ITP Mode Used
+		 */
+		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
+				dwc->dr_mode == USB_DR_MODE_OTG) &&
+				(dwc->revision >= DWC3_REVISION_210A &&
+				dwc->revision <= DWC3_REVISION_250A)) {
+			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
+		} else {
+			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		}
 		break;
 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
 		/* enable hibernation here */
@@ -584,6 +603,14 @@  static int dwc3_probe(struct platform_device *pdev)
 		goto err0;
 	}
 
+	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+		dwc->dr_mode = USB_DR_MODE_HOST;
+	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+		dwc->dr_mode = USB_DR_MODE_OTG;
+
 	ret = dwc3_core_init(dwc);
 	if (ret) {
 		dev_err(dev, "failed to initialize core\n");
@@ -599,14 +626,6 @@  static int dwc3_probe(struct platform_device *pdev)
 		goto err1;
 	}
 
-	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
-		dwc->dr_mode = USB_DR_MODE_HOST;
-	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
-		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
-
-	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
-		dwc->dr_mode = USB_DR_MODE_OTG;
-
 	switch (dwc->dr_mode) {
 	case USB_DR_MODE_PERIPHERAL:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);