summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorRamneek Mehresh <ramneek.mehresh@freescale.com>2013-04-16 08:41:19 (GMT)
committerFleming Andrew-AFLEMING <AFLEMING@freescale.com>2013-05-02 04:51:51 (GMT)
commitcb74e74b3f5bb0aeaa1a36ee20d311c671da02c8 (patch)
treedaf10d2c01da919d6d473d509d14e2ad8630988d /drivers/usb
parentc4a4e6fbc411a53a25e653a14835bbda6f55a198 (diff)
downloadlinux-fsl-qoriq-cb74e74b3f5bb0aeaa1a36ee20d311c671da02c8.tar.xz
fsl/usb: Workaround for USB erratum-A005275
Incoming packets are randomly corrucpted by h/w resulting in varying errors. This workaround makes FS as default mode in all affected socs by - Disabling HS chirp signalling - Forcing EPS field of all packets to FS This errata does not affect FS mode. Forces all HS devices to connect in FS mode for all socs affected by this erratum: P3041 and P2041 rev 1.0 and 1.1 P5020 and P5010 rev 1.0 and 2.0 P5040 and P1010 rev 1.0 Workaround can be disabled by mentioning "no_erratum_a005275" in hwconfig string (in u-boot command line) Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com> Change-Id: Ie7b75b033220e4be44b5c769d7c187928d84dd6d Reviewed-on: http://git.am.freescale.net:8181/1435 Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com> Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-fsl.c4
-rw-r--r--drivers/usb/host/ehci-hub.c7
-rw-r--r--drivers/usb/host/ehci-q.c6
-rw-r--r--drivers/usb/host/ehci.h12
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c35
5 files changed, 63 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 50167c3..732bc43 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -365,6 +365,10 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
}
+ /* Deal with USB erratum A-005275 */
+ if (pdata->has_fsl_erratum_a005275 == 1)
+ ehci->has_fsl_hs_errata = 1;
+
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))
if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 7d06e77..586b2d4 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1064,6 +1064,13 @@ static int ehci_hub_control (
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
+
+ /* Force full-speed connect for FSL high-speed erratum;
+ * disable HS Chirp by setting PFSC bit
+ */
+ if (ehci_has_fsl_hs_errata(ehci))
+ temp |= (1 << PORTSC_FSL_PFSC);
+
ehci_writel(ehci, temp, status_reg);
break;
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 23d1369..8cc03ee 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -926,7 +926,11 @@ qh_make (
break;
case USB_SPEED_HIGH: /* no TT involved */
- info1 |= QH_HIGH_SPEED;
+ if (!ehci_has_fsl_hs_errata(ehci))
+ info1 |= QH_HIGH_SPEED;
+ else
+ info1 |= QH_FULL_SPEED;
+
if (type == PIPE_CONTROL) {
info1 |= (EHCI_TUNE_RL_HS << 28);
info1 |= 64 << 16; /* usb2 fixed maxpacket */
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index c204b81..8703484 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -194,6 +194,7 @@ struct ehci_hcd { /* one per controller */
/* SILICON QUIRKS */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
+ unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
unsigned big_endian_capbase:1;
@@ -622,6 +623,17 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_port_speed(ehci, portsc) USB_PORT_STAT_HIGH_SPEED
#endif
+#define PORTSC_FSL_PFSC 24 /* Port Force Full-Speed Connect */
+
+#if defined(CONFIG_PPC_85xx)
+/* Some Freescale processors have an erratum (USB A-005275) in which
+ * incoming packets get corrupted in HS mode
+ */
+#define ehci_has_fsl_hs_errata(e) ((e)->has_fsl_hs_errata)
+#else
+#define ehci_has_fsl_hs_errata(e) (0)
+#endif
+
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PPC_83xx
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 11e0b79..20e89ca 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -17,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/module.h>
+#include <asm/mpc85xx.h>
struct fsl_usb2_dev_data {
char *dr_mode; /* controller mode */
@@ -119,6 +120,30 @@ error:
static const struct of_device_id fsl_usb2_mph_dr_of_match[];
+static bool has_erratum_a005275(struct device_node *node)
+{
+ unsigned int svr = mfspr(SPRN_SVR);
+ bool flag = false;
+ /* Deal with USB Erratum USB A-005275
+ * Packet corruption in HS mode, default to
+ * FS mode for the following
+ * P3041 and P2041 rev 1.0 and 1.1
+ * P5020 and P5010 rev 1.0 and 2.0
+ * P5040 and P1010 rev 1.0
+ */
+ if ((fsl_svr_is(SVR_P3041)) || (fsl_svr_is(SVR_P3041_E)) ||
+ (fsl_svr_is(SVR_P2041)) || (fsl_svr_is(SVR_P2041_E)))
+ flag = (IS_SVR_REV(svr, 1, 0)) || (IS_SVR_REV(svr, 1, 1));
+ else if ((fsl_svr_is(SVR_P5020)) || (fsl_svr_is(SVR_P5020_E)) ||
+ (fsl_svr_is(SVR_P5010)) || (fsl_svr_is(SVR_P5010_E)))
+ flag = (IS_SVR_REV(svr, 1, 0)) || (IS_SVR_REV(svr, 2, 0));
+ else if ((fsl_svr_is(SVR_P5040)) || (fsl_svr_is(SVR_P5040_E)) ||
+ (fsl_svr_is(SVR_P1010)) || (fsl_svr_is(SVR_P1010_E)))
+ flag = IS_SVR_REV(svr, 1, 0);
+
+ return flag;
+}
+
static int usb_get_ver_info(struct device_node *np)
{
int ver = -1;
@@ -206,6 +231,16 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
pdata->phy_mode = determine_usb_phy(prop);
pdata->controller_ver = usb_get_ver_info(np);
+ /* Activate workaround for USB erratum-A005275 if
+ * fsl,no-erratum-a005275 property not defined for
+ * affected socs
+ */
+ if (!of_get_property(np, "fsl,no-erratum-a005275", NULL) &&
+ has_erratum_a005275(np))
+ pdata->has_fsl_erratum_a005275 = 1;
+ else
+ pdata->has_fsl_erratum_a005275 = 0;
+
if (pdata->have_sysif_regs) {
if (pdata->controller_ver < 0) {
dev_warn(&ofdev->dev, "Could not get controller version\n");