This has the remaining OHCI core tweaks to support two PPC embedded SOC
chips, which use non-standard byte order.  The only core changes would
affect ISO transfers; verified on some USB speakers.

Please merge.

- Dave
These are the remaining OHCI core (and Kconfig) updates for big-endian
support on STB03xxx and MPC52xx PPC chips.  These are the first known
implementations with big-endian register and memory layouts.

    - Two more in-memory fields, related to isochronous transfers
      have different behavior:  HCCA frame number, and ISO TD status.

    - Kconfig gets new OHCI options, for big-endian and little-endian.
      The default is little-endian; those PPC platforms can support
      both the on-chip big-endian version, and little-endian PCI chips.

Most of the related ohci core fixes have already been merged.

Signed-off-by: Dale Farnsworth <[EMAIL PROTECTED]>
Signed-off-by: David Brownell <[EMAIL PROTECTED]>

--- 1.10/drivers/usb/host/Kconfig	2004-12-06 11:45:04 -07:00
+++ edited/drivers/usb/host/Kconfig	2005-01-25 12:00:29 -07:00
@@ -7,13 +7,18 @@
 	default y if ARM				# SL-811
 	default PCI
 
-# many non-PCI hcds implement OHCI
+# many non-PCI SOC chips embed OHCI
 config USB_ARCH_HAS_OHCI
 	boolean
+	# ARM:
 	default y if SA1111
 	default y if ARCH_OMAP
 	default y if ARCH_LH7A404
 	default y if PXA27x
+	# PPC:
+	default y if STB03xxx
+	default y if PPC_MPC52xx
+	# more:
 	default PCI
 
 #
@@ -83,6 +88,35 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ohci-hcd.
+
+config USB_OHCI_HCD_PPC_SOC
+	bool "OHCI support for on-chip PPC USB controller"
+	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
+	default y
+	select USB_OHCI_BIG_ENDIAN
+	---help---
+	  Enables support for the USB controller on the MPC52xx or
+	  STB03xxx processor chip.  If unsure, say Y.
+
+config USB_OHCI_HCD_PCI
+	bool "OHCI support for PCI-bus USB controllers"
+	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+	default y
+	select USB_OHCI_LITTLE_ENDIAN
+	---help---
+	  Enables support for PCI-bus plug-in USB controller cards.
+	  If unsure, say Y.
+
+config USB_OHCI_BIG_ENDIAN
+	bool
+	depends on USB_OHCI_HCD
+	default n
+
+config USB_OHCI_LITTLE_ENDIAN
+	bool
+	depends on USB_OHCI_HCD
+	default n if STB03xxx || PPC_MPC52xx
+	default y
 
 config USB_UHCI_HCD
 	tristate "UHCI HCD (most Intel and VIA) support"
--- 1.37/drivers/usb/host/ohci-dbg.c	2004-12-18 08:22:52 -07:00
+++ edited/drivers/usb/host/ohci-dbg.c	2005-01-24 10:04:17 -07:00
@@ -328,7 +328,7 @@
 			hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff,
 			hc32_to_cpup (ohci, &td->hwBE));
 		for (i = 0; i < MAXPSW; i++) {
-			u16	psw = hc16_to_cpup (ohci, &td->hwPSW [i]);
+			u16	psw = ohci_hwPSW (ohci, td, i);
 			int	cc = (psw >> 12) & 0x0f;
 			ohci_dbg (ohci, "    psw [%d] = %2x, CC=%x %s=%d\n", i,
 				psw, cc,
--- 1.67/drivers/usb/host/ohci-q.c	2004-12-20 18:15:10 -07:00
+++ edited/drivers/usb/host/ohci-q.c	2005-01-24 10:04:17 -07:00
@@ -547,7 +547,8 @@
 	td->hwINFO = cpu_to_hc32 (ohci, info);
 	if (is_iso) {
 		td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
-		td->hwPSW [0] = cpu_to_hc16 (ohci, (data & 0x0FFF) | 0xE000);
+		*ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
+						(data & 0x0FFF) | 0xE000);
 		td->ed->last_iso = info & 0xffff;
 	} else {
 		td->hwCBP = cpu_to_hc32 (ohci, data); 
@@ -719,10 +720,12 @@
 
 	/* ISO ... drivers see per-TD length/status */
   	if (tdINFO & TD_ISO) {
- 		u16	tdPSW = hc16_to_cpu (ohci, td->hwPSW [0]);
+ 		u16	tdPSW = ohci_hwPSW (ohci, td, 0);
 		int	dlen = 0;
 
-		/* NOTE:  assumes FC in tdINFO == 0 (and MAXPSW == 1) */
+		/* NOTE:  assumes FC in tdINFO == 0, and that
+		 * only the first of 0..MAXPSW psws is used.
+		 */
 
  		cc = (tdPSW >> 12) & 0xF;
   		if (tdINFO & TD_CC)	/* hc didn't touch? */
--- 1.37/drivers/usb/host/ohci.h	2004-12-18 08:22:52 -07:00
+++ edited/drivers/usb/host/ohci.h	2005-01-24 10:04:18 -07:00
@@ -111,8 +111,10 @@
   	__hc32		hwNextTD;	/* Next TD Pointer */
   	__hc32		hwBE;		/* Memory Buffer End Pointer */
 
-	/* PSW is only for ISO */
-#define MAXPSW 1		/* hardware allows 8 */
+	/* PSW is only for ISO.  Only 1 PSW entry is used, but on
+	 * big-endian PPC hardware that's the second entry.
+	 */
+#define MAXPSW	2
   	__hc16		hwPSW [MAXPSW];
 
 	/* rest are purely for the driver's use */
@@ -183,7 +185,7 @@
 	/* 
 	 * OHCI defines u16 frame_no, followed by u16 zero pad.
 	 * Since some processors can't do 16 bit bus accesses,
-	 * portable access must be a 32 bit byteswapped access.
+	 * portable access must be a 32 bits wide.
 	 */
 	__hc32	frame_no;		/* current frame number */
 	__hc32	done_head;		/* info returned for an interrupt */
@@ -191,8 +193,6 @@
 	u8	what [4];		/* spec only identifies 252 bytes :) */
 } __attribute__ ((aligned(256)));
 
-#define ohci_frame_no(ohci) ((u16)hc32_to_cpup(ohci,&(ohci)->hcca->frame_no))
-  
 /*
  * This is the structure of the OHCI controller's memory mapped I/O region.
  * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
@@ -550,6 +550,44 @@
 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);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
+ * hardware handles 16 bit reads.  That creates a different confusion on
+ * some big-endian SOC implementations.  Same thing happens with PSW access.
+ */
+
+#ifdef CONFIG_STB03xxx
+#define OHCI_BE_FRAME_NO_SHIFT	16
+#else
+#define OHCI_BE_FRAME_NO_SHIFT	0
+#endif
+
+static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
+{
+	u32 tmp;
+	if (big_endian(ohci)) {
+		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
+		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+	} else
+		tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
+
+	return (u16)tmp;
+}
+
+static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
+                                 const struct td *td, int index)
+{
+	return (__hc16 *)(big_endian(ohci) ?
+			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
+}
+
+static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci,
+                               const struct td *td, int index)
+{
+	return hc16_to_cpup(ohci, ohci_hwPSWp(ohci, td, index));
 }
 
 /*-------------------------------------------------------------------------*/

Reply via email to