[PATCH 2.6.21] Work around for PPC440EPX USBH_23errrata

"Mark Miesfeld" <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
(Sorry for this repost, apparently the mailserver reformats before sending.)

There is a published errata for the PPC440EPX, USBH_23: EHCI and OHCI
Linux module contention.  The overview states: When running Linux with
both EHCI and OHCI modules loaded, the EHCI module experiences a fatal
error when a high-speed device is connected to the USB2.0 Host controller.
The EHCI module functions normally when the OHCI module is not loaded.

The patch below is a software work around for the problem. I would like to
discuss the probability of the patch being accepted into the kernel and /
or what could be done to increase the probability.  The patch is against
the head of the DENX git repository, linux-2.6-denx.git.

Signed-off-by: Mark Miesfeld <[email protected]>

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 012954b..1569c8b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -67,6 +67,26 @@ config USB_EHCI_TT_NEWSCHED

 	  If unsure, say N.

+config  USB_PPC440EPX_USBH_23_ERRATA
+	bool "PPC440EPX USBH_23 ERRATA EHCI and OHCI contention"
+	depends on USB_EHCI_HCD && 440EPX
+	default y
+	select USB_OHCI_HCD
+	select USB_OHCI_HCD_PPC_SOC
+	---help---
+	  Allows the EHCI and OHCI drivers to be loaded together when using
+	  the USB Host controller on the 440EPX processor chip. This is
+	  necessary when either high speed or full speed devices may be
+	  connected to the USB Host port.  You must compile and use the OHCI
+	  driver when selecting this option.
+
+	  The option is not needed if the USB Host port is only used with
+	  USB 2.0 high speed devices and the OHCI driver is not compiled or
+	  loaded.
+
+	  Say N when the OHCI driver for the 440EPX will not be compiled or
+	  will not be loaded.  If unsure, say Y.
+
 config USB_EHCI_BIG_ENDIAN_MMIO
 	bool
 	depends on USB_EHCI_HCD
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 1813b7c..03516d4 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -289,6 +289,12 @@ static inline void remove_companion_file

 /*-------------------------------------------------------------------------*/

+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+extern void ohci_ppc_set_hcfs(int state);
+#define HCFS_SUSPEND      0
+#define HCFS_OPERATIONAL  1
+#endif
+
 static int check_reset_complete (
 	struct ehci_hcd	*ehci,
 	int		index,
@@ -319,8 +325,17 @@ static int check_reset_complete (
 		port_status &= ~PORT_RWC_BITS;
 		ehci_writel(ehci, port_status, status_reg);

-	} else
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+		/* ensure 440EPX ohci controller state is operational */
+		ohci_ppc_set_hcfs(HCFS_OPERATIONAL);
+#endif
+	} else {
 		ehci_dbg (ehci, "port %d high speed\n", index + 1);
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+		/* ensure 440EPx ohci controller state is suspended */
+		ohci_ppc_set_hcfs(HCFS_SUSPEND);
+#endif
+	}

 	return port_status;
 }
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1a2e177..7195311 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -20,6 +20,37 @@ #include <linux/signal.h>
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */

+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+struct ohci_hcd	*cached_ohci = NULL;
+#define HCFS_SUSPEND      0
+#define HCFS_OPERATIONAL  1
+void ohci_ppc_set_hcfs(int state) {
+	u32 hc_control;
+
+	hc_control = (ohci_readl(cached_ohci, &cached_ohci->regs->control)
+		      & ~OHCI_CTRL_HCFS);
+
+	switch ( state )  {
+	case HCFS_SUSPEND:
+		hc_control |= OHCI_USB_SUSPEND;
+		break;
+	case HCFS_OPERATIONAL :
+		hc_control |= OHCI_USB_OPER;
+		break;
+
+	default:
+		/* this is unexpected, shoud never happen */
+		hc_control |= OHCI_USB_SUSPEND;
+		break;
+	}
+
+	/* write the new state and flush the write. */
+	ohci_writel(cached_ohci, hc_control, &cached_ohci->regs->control);
+	(void) ohci_readl(cached_ohci, &cached_ohci->regs->control);
+}
+EXPORT_SYMBOL (ohci_ppc_set_hcfs);
+#endif
+
 /**
  * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
  * Context: !in_interrupt()
@@ -76,9 +107,27 @@ static int usb_hcd_ppc_soc_probe(const s
 	ohci_hcd_init(ohci);

 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
-	if (retval == 0)
+	if (retval == 0) {
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+		/* At this point ohci_run has executed, the controller is
+		 * running, the root ports set up, etc.  Now, put the core in
+		 * the suspended state.  The ehci driver will bring it out of
+		 * suspended state when / if a non-high speed USB device is
+		 * attached to the USB Host port.
+		 */
+		u32 hc_control;
+		cached_ohci = ohci;
+		spin_lock_irq(&ohci->lock);
+
+		hc_control = ohci_readl(ohci, &ohci->regs->control);
+		hc_control |= OHCI_USB_SUSPEND;
+		ohci_writel(ohci, hc_control, &ohci->regs->control);
+		(void) ohci_readl(ohci, &ohci->regs->control);
+
+		spin_unlock_irq(&ohci->lock);
+#endif
 		return retval;
-
+	}
 	pr_debug("Removing PPC-SOC USB Controller\n");

 	iounmap(hcd->regs);

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.