Mx28 USB workaround for errata

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I had a lot of USB errors on i.mx28. I could reproduce it most easily with USB-serial adapters, and USB modems (CDC and WWAN drivers). If I sent some data to the TTY port with the echo command in a loop (so basically open the port, send data, and close the port), all of the devices were dropped down from the root hub. (Later I found, it is enough to just periodically open and close the TTY port.)

The reason was an mx28 errata: "ENGR119653 USB: ARM to USB register error issue"

Freescale issued a patch for 2.6.35 to workaround this problem last year. I ported this patch. However, it is not totally "device tree compatible". I mean, this patch is only needed for mx28, not for the other SOCs using chipidea, and I used ifdefs. So you can't compile a kernel both for mx28 and e.g. for mx23. If you check the patch, you see, that it is modifying the lowest layer, the writel() function; it is changing it to an SWP instruction. According the errata, I need to use SWP instructions to write USB registers.

So I'm curious, what other possibilities do I have to make this patch device tree compatible? I mean, I can't check the machine's type on each USB register writing. Then I could use function pointers for register writing function, or weak aliases somehow. But that would causes an overhead because of the additional function calling, instead of simple inline assembly codes.

What's the standard way in this case? Or should I just leave the patch as it is?

--------
Robert Hodaszi



From de71990cd37a973a598ba8924d415696ea5dabdf Mon Sep 17 00:00:00 2001
From: Robert Hodaszi <robert.hodaszi@xxxxxxxx>
Date: Mon, 23 Sep 2013 18:07:18 +0200
Subject: [PATCH] usb: chipidea: implement workaround for i.mx28 errata
 ENGR119653: USB: ARM to USB register error issue

From the i.mx28 Errata:

ENGR119653 USB: ARM to USB register error issue

Description:
The ARM writes a data error to the USB core register unless SRM SWP instruction is used.
The issue occurs when all of the following conditions are met:
1. Last AHB access is to the non-USB AHB slave
2. Current AHB access is to the USB
3. These two accesses are back-to-back
4. The last data phase of the last AHB access has a wait state
5. Only happens when D-cache is enabled

Projected Impact:
The USB register does not get correct data when writing to the USB slave through the AHB bus
when D-cache is enabled.

Workaround:
All USB register write operations must use the ARM SWP instruction.

Projected Solution:
No fix scheduled.

Signed-off-by: Robert Hodaszi <robert.hodaszi@xxxxxxxx>
---
 drivers/usb/chipidea/ci.h |   13 +++++++++++++
 drivers/usb/host/ehci.h   |    9 +++++++++
 2 files changed, 22 insertions(+)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 1c94fc5..1ba7428 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -25,6 +25,19 @@
 #define CI_HDRC_PAGE_SIZE  4096ul /* page size for TD's */
 #define ENDPT_MAX          32

+#ifdef CONFIG_SOC_IMX28
+/* Fix errata ENGR119653 for i.mx28 */
+static inline void safe_writel(u32 val32, volatile u32 *addr)
+{
+	__asm__ ("swp %0, %0, [%1]" : : "r"(val32), "r"(addr));
+}
+
+#undef iowrite32
+#undef writel
+#define iowrite32(v, addr) safe_writel(v, addr)
+#define writel(v, addr) safe_writel(v, addr)
+#endif
+

/******************************************************************************
  * STRUCTURES

*****************************************************************************/
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 7c978b2..34dbec0 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -675,6 +675,13 @@ static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
 #endif
 }

+#ifdef CONFIG_SOC_IMX28
+static inline void fsl_safe_writel(u32 val32, volatile u32 *addr)
+{
+	__asm__ ("swp %0, %0, [%1]" : : "r"(val32), "r"(addr));
+}
+#endif
+
 static inline void ehci_writel(const struct ehci_hcd *ehci,
 		const unsigned int val, __u32 __iomem *regs)
 {
@@ -682,6 +689,8 @@ static inline void ehci_writel(const struct ehci_hcd *ehci,
 	ehci_big_endian_mmio(ehci) ?
 		writel_be(val, regs) :
 		writel(val, regs);
+#elif defined(CONFIG_SOC_IMX28)
+	fsl_safe_writel(val, regs);
 #else
 	writel(val, regs);
 #endif



--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux