fsl/usb: Workaround for USB erratum-A005275
Workaround makes FS as default mode on all affected socs.
Add support to check erratum-A005275 validity for an soc. This info is
required to determine whether a given soc is affected by this erratum.
Add quirk for this erratum "has_fsl_erratum_a005275" . This quirk is used
to enable workaround for the errata
Force FS mode as default by:
- making EPS as FS
- setting PFSC bit to disable HS chirping
This workaround can be disabled by mentioning "no_erratum_a005275" in
hwconfig string
Signed-off-by: Chris Packham <judge.packham@gmail.com>
Reviewed-by: York Sun <york.sun@nxp.com>
diff --git a/arch/powerpc/cpu/mpc85xx/Kconfig b/arch/powerpc/cpu/mpc85xx/Kconfig
index 7d139ff..309ca29 100644
--- a/arch/powerpc/cpu/mpc85xx/Kconfig
+++ b/arch/powerpc/cpu/mpc85xx/Kconfig
@@ -659,6 +659,7 @@
select SYS_FSL_ERRATUM_A004477
select SYS_FSL_ERRATUM_A004508
select SYS_FSL_ERRATUM_A005125
+ select SYS_FSL_ERRATUM_A005275
select SYS_FSL_ERRATUM_A006261
select SYS_FSL_ERRATUM_A007075
select SYS_FSL_ERRATUM_ESDHC111
@@ -821,6 +822,7 @@
select FSL_LAW
select SYS_FSL_ERRATUM_A004510
select SYS_FSL_ERRATUM_A004849
+ select SYS_FSL_ERRATUM_A005275
select SYS_FSL_ERRATUM_A006261
select SYS_FSL_ERRATUM_CPU_A003999
select SYS_FSL_ERRATUM_DDR_A003
@@ -845,6 +847,7 @@
select SYS_FSL_DDR_VER_44
select SYS_FSL_ERRATUM_A004510
select SYS_FSL_ERRATUM_A004849
+ select SYS_FSL_ERRATUM_A005275
select SYS_FSL_ERRATUM_A005812
select SYS_FSL_ERRATUM_A006261
select SYS_FSL_ERRATUM_CPU_A003999
@@ -910,6 +913,7 @@
select FSL_LAW
select SYS_FSL_DDR_VER_44
select SYS_FSL_ERRATUM_A004510
+ select SYS_FSL_ERRATUM_A005275
select SYS_FSL_ERRATUM_A006261
select SYS_FSL_ERRATUM_DDR_A003
select SYS_FSL_ERRATUM_DDR_A003474
@@ -935,6 +939,7 @@
select SYS_FSL_DDR_VER_44
select SYS_FSL_ERRATUM_A004510
select SYS_FSL_ERRATUM_A004699
+ select SYS_FSL_ERRATUM_A005275
select SYS_FSL_ERRATUM_A005812
select SYS_FSL_ERRATUM_A006261
select SYS_FSL_ERRATUM_DDR_A003
@@ -1303,6 +1308,9 @@
config SYS_FSL_ERRATUM_A005871
bool
+config SYS_FSL_ERRATUM_A005275
+ bool
+
config SYS_FSL_ERRATUM_A006261
bool
diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
index eda2e7e..e455d8b 100644
--- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c
+++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
@@ -307,6 +307,10 @@
(SVR_REV(svr) <= CONFIG_SYS_FSL_A004447_SVR_REV))
puts("Work-around for Erratum I2C-A004447 enabled\n");
#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A005275
+ if (has_erratum_a005275())
+ puts("Work-around for Erratum A005275 enabled\n");
+#endif
#ifdef CONFIG_SYS_FSL_ERRATUM_A006261
if (has_erratum_a006261())
puts("Work-around for Erratum A006261 enabled\n");
diff --git a/drivers/usb/common/fsl-errata.c b/drivers/usb/common/fsl-errata.c
index 386130d..9eb1d23 100644
--- a/drivers/usb/common/fsl-errata.c
+++ b/drivers/usb/common/fsl-errata.c
@@ -6,6 +6,7 @@
*/
#include <common.h>
+#include <hwconfig.h>
#include <fsl_errata.h>
#include<fsl_usb.h>
#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
@@ -44,6 +45,33 @@
return false;
}
+bool has_erratum_a005275(void)
+{
+ u32 svr = get_svr();
+ u32 soc = SVR_SOC_VER(svr);
+
+ if (hwconfig("no_erratum_a005275"))
+ return false;
+
+ switch (soc) {
+#ifdef CONFIG_PPC
+ case SVR_P3041:
+ case SVR_P2041:
+ case SVR_P2040:
+ return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1);
+ case SVR_P5010:
+ case SVR_P5020:
+ case SVR_P5021:
+ return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+ case SVR_P5040:
+ case SVR_P1010:
+ return IS_SVR_REV(svr, 1, 0);
+#endif
+ }
+
+ return false;
+}
+
bool has_erratum_a006261(void)
{
u32 svr = get_svr();
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index a04f6a3..a8fb2b8 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -93,6 +93,7 @@
struct usb_ehci *ehci = NULL;
struct ehci_hccr *hccr;
struct ehci_hcor *hcor;
+ struct ehci_ctrl *ehci_ctrl = &priv->ehci;
/*
* Get the base address for EHCI controller from the device node
@@ -107,6 +108,8 @@
hcor = (struct ehci_hcor *)
((void *)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+ ehci_ctrl->has_fsl_erratum_a005275 = has_erratum_a005275();
+
if (ehci_fsl_init(priv, ehci, hccr, hcor) < 0)
return -ENXIO;
@@ -145,6 +148,8 @@
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
+ struct ehci_ctrl *ehci_ctrl = container_of(hccr,
+ struct ehci_ctrl, hccr);
struct usb_ehci *ehci = NULL;
switch (index) {
@@ -163,6 +168,8 @@
*hcor = (struct ehci_hcor *)((uint32_t) *hccr +
HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+ ehci_ctrl->has_fsl_erratum_a005275 = has_erratum_a005275();
+
return ehci_fsl_init(index, ehci, *hccr, *hcor);
}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 199b3a8..d1d8f08 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -409,9 +409,15 @@
endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) |
QH_ENDPT1_MAXPKTLEN(maxpacket) | QH_ENDPT1_H(0) |
QH_ENDPT1_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) |
- QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) |
QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) |
QH_ENDPT1_DEVADDR(usb_pipedevice(pipe));
+
+ /* Force FS for fsl HS quirk */
+ if (!ctrl->has_fsl_erratum_a005275)
+ endpt |= QH_ENDPT1_EPS(ehci_encode_speed(dev->speed));
+ else
+ endpt |= QH_ENDPT1_EPS(ehci_encode_speed(QH_FULL_SPEED));
+
qh->qh_endpt1 = cpu_to_hc32(endpt);
endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0);
qh->qh_endpt2 = cpu_to_hc32(endpt);
@@ -832,6 +838,10 @@
} else {
int ret;
+ /* Disable chirp for HS erratum */
+ if (ctrl->has_fsl_erratum_a005275)
+ reg |= PORTSC_FSL_PFSC;
+
reg |= EHCI_PS_PR;
reg &= ~EHCI_PS_PE;
ehci_writel(status_reg, reg);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 7945016..6c359af 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -8,6 +8,7 @@
#ifndef USB_EHCI_H
#define USB_EHCI_H
+#include <stdbool.h>
#include <usb.h>
#include <generic-phy.h>
@@ -66,6 +67,8 @@
#define PORTSC_PSPD_FS 0x0
#define PORTSC_PSPD_LS 0x1
#define PORTSC_PSPD_HS 0x2
+#define PORTSC_FSL_PFSC BIT(24) /* PFSC bit to disable HS chirping */
+
uint32_t or_systune;
} __attribute__ ((packed, aligned(4)));
@@ -251,6 +254,7 @@
uint32_t *periodic_list;
int periodic_schedules;
int ntds;
+ bool has_fsl_erratum_a005275; /* Freescale HS silicon quirk */
struct ehci_ops ops;
void *priv; /* client's private data */
};
diff --git a/include/fsl_usb.h b/include/fsl_usb.h
index e9e1dd6..c0f076b 100644
--- a/include/fsl_usb.h
+++ b/include/fsl_usb.h
@@ -87,6 +87,7 @@
/* USB Erratum Checking code */
#if defined(CONFIG_PPC) || defined(CONFIG_ARM)
bool has_dual_phy(void);
+bool has_erratum_a005275(void);
bool has_erratum_a006261(void);
bool has_erratum_a007075(void);
bool has_erratum_a007798(void);