+/*-------------------------------------------------------------------------*/
+
+/*
+ * While most USB host controllers implement their registers and
+ * in-memory communication descriptors in little-endian format,
+ * a minority (notably the IBM STB04XXX and the Motorola MPC5200
+ * processors) implement them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#else
+#define big_endian(ohci) 1 /* only big endian */
+#endif
+
+/*
+ * Big-endian read/write functions are arch-specific.
+ * Other arches can be added if/when they're needed.
+ */
+#if defined(CONFIG_PPC)
+#define readl_be(addr) in_be32((__force unsigned *)addr)
+#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
+#endif
+
+static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
+ __hc32 __iomem * regs)
+{
+ return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+}
+
+static inline void ohci_writel (const struct ohci_hcd *ohci,
+ const unsigned int val, __hc32 __iomem *regs)
+{
+ big_endian(ohci) ? writel_be (val, regs) :
+ writel (val, (__force u32 *)regs);
+}
+
+#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */
+
+#define big_endian(ohci) 0 /* only little endian */
+
+#ifdef CONFIG_ARCH_LH7A404
+ /* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers. This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+static inline unsigned int
+ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
+{
+ *(volatile __force unsigned int*) regs;
+ return *(volatile __force unsigned int*) regs;
+}
+#else
+ /* Standard version of ohci_readl uses standard, platform
+ * specific implementation. */
+static inline unsigned int
+ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
+{
+ return readl(regs);
+}
+#endif
+
+static inline void ohci_writel (const struct ohci_hcd *ohci,
+ const unsigned int val, __hc32 __iomem *regs)
+{
+ writel (val, regs);
+}
+
+#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */
+
+/*-------------------------------------------------------------------------*/
+
+/* cpu to ohci */
+static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
+{
+ return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+}
+
+static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
+{
+ return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+}
+
+static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
+{
+ return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+}
+
+static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
+{
+ return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+}
+
+/* ohci to cpu */
+static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
+{
+ return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+}
+
+static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
+{
+ return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+}
+
+static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
+{
+ return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+}
+
+static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
+{
+ return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void disable (struct ohci_hcd *ohci)
+{
+ ohci_to_hcd(ohci)->state = USB_STATE_HALT;
+}
+
+#define FI 0x2edf /* 12000 bits per frame (-1) */
+#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7))
+#define LSTHRESH 0x628 /* lowspeed bit threshold */
+
+static inline void periodic_reinit (struct ohci_hcd *ohci)
+{
+ u32 fi = ohci->fminterval & 0x0ffff;
+
+ ohci_writel (ohci, ((9 * fi) / 10) & 0x3fff,
+ &ohci->regs->periodicstart);
+}
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect. AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define read_roothub(hc, register, mask) ({ \
+ u32 temp = ohci_readl (hc, &hc->regs->roothub.register); \
+ if (temp == -1) \
+ disable (hc); \
+ else if (hc->flags & OHCI_QUIRK_AMD756) \
+ while (temp & mask) \
+ temp = ohci_readl (hc, &hc->regs->roothub.register); \
+ temp; })
+
+static u32 roothub_a (struct ohci_hcd *hc)
+ { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci_hcd *hc)
+ { return ohci_readl (hc, &hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci_hcd *hc)
+ { return ohci_readl (hc, &hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
+ { return read_roothub (hc, portstatus [i], 0xffe0fce0); }