[PATCH] USB: OHCI relies less on NDP register

Some OHCI implementations have differences in the way the NDP register
(in roothub_a) reports the number of ports present. This patch allows the
platform specific code to optionally supply the number of ports. The
driver just reads the value at init (if not supplied) instead of reading
it every time its needed (except for an AMD756 bug workaround).

It also sets the value correctly for the ARM pxa27x architecture.

Signed-Off-By: Richard Purdie <[EMAIL PROTECTED]>
Signed-off-by: David Brownell <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>

---
commit fdd13b36c4a501d8787a27e54635fbd943f2685d
tree eebcc2fc677b5b625235e2e0797b5f9ab6d74905
parent e0fd3cbc50a8c925e8e7d8448df689015362c458
author David Brownell <[EMAIL PROTECTED]> Wed, 31 Aug 2005 11:52:57 -0700
committer Greg Kroah-Hartman <[EMAIL PROTECTED]> Mon, 12 Sep 2005 12:23:46 -0700

 drivers/usb/host/ohci-dbg.c    |    9 ++++-----
 drivers/usb/host/ohci-hcd.c    |   10 ++++++----
 drivers/usb/host/ohci-hub.c    |   22 +++++++++++-----------
 drivers/usb/host/ohci-pxa27x.c |    3 +++
 drivers/usb/host/ohci.h        |    1 +
 5 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -228,23 +228,22 @@ ohci_dump_roothub (
        char **next,
        unsigned *size)
 {
-       u32                     temp, ndp, i;
+       u32                     temp, i;
 
        temp = roothub_a (controller);
        if (temp == ~(u32)0)
                return;
-       ndp = (temp & RH_A_NDP);
 
        if (verbose) {
                ohci_dbg_sw (controller, next, size,
-                       "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp,
+                       "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp,
                        ((temp & RH_A_POTPGT) >> 24) & 0xff,
                        (temp & RH_A_NOCP) ? " NOCP" : "",
                        (temp & RH_A_OCPM) ? " OCPM" : "",
                        (temp & RH_A_DT) ? " DT" : "",
                        (temp & RH_A_NPS) ? " NPS" : "",
                        (temp & RH_A_PSM) ? " PSM" : "",
-                       ndp
+                       (temp & RH_A_NDP), controller->num_ports
                        );
                temp = roothub_b (controller);
                ohci_dbg_sw (controller, next, size,
@@ -266,7 +265,7 @@ ohci_dump_roothub (
                        );
        }
 
-       for (i = 0; i < ndp; i++) {
+       for (i = 0; i < controller->num_ports; i++) {
                temp = roothub_portstatus (controller, i);
                dbg_port_sw (controller, i, temp, next, size);
        }
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -484,6 +484,10 @@ static int ohci_init (struct ohci_hcd *o
        // flush the writes
        (void) ohci_readl (ohci, &ohci->regs->control);
 
+       /* Read the number of ports unless overridden */
+       if (ohci->num_ports == 0)
+               ohci->num_ports = roothub_a(ohci) & RH_A_NDP;
+
        if (ohci->hcca)
                return 0;
 
@@ -560,10 +564,8 @@ static int ohci_run (struct ohci_hcd *oh
        msleep(temp);
        temp = roothub_a (ohci);
        if (!(temp & RH_A_NPS)) {
-               unsigned ports = temp & RH_A_NDP; 
-
                /* power down each port */
-               for (temp = 0; temp < ports; temp++)
+               for (temp = 0; temp < ohci->num_ports; temp++)
                        ohci_writel (ohci, RH_PS_LSDA,
                                &ohci->regs->roothub.portstatus [temp]);
        }
@@ -861,7 +863,7 @@ static int ohci_restart (struct ohci_hcd
                 * and that if we try to turn them back on the root hub
                 * will respond to CSC processing.
                 */
-               i = roothub_a (ohci) & RH_A_NDP;
+               i = ohci->num_ports;
                while (i--)
                        ohci_writel (ohci, RH_PS_PSS,
                                &ohci->regs->roothub.portstatus [temp]);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -184,7 +184,7 @@ static int ohci_hub_resume (struct usb_h
        if (status != -EINPROGRESS)
                return status;
 
-       temp = roothub_a (ohci) & RH_A_NDP;
+       temp = ohci->num_ports;
        enables = 0;
        while (temp--) {
                u32 stat = ohci_readl (ohci,
@@ -304,7 +304,7 @@ static int
 ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-       int             ports, i, changed = 0, length = 1;
+       int             i, changed = 0, length = 1;
        int             can_suspend = hcd->can_wakeup;
        unsigned long   flags;
 
@@ -319,9 +319,10 @@ ohci_hub_status_data (struct usb_hcd *hc
                goto done;
        }
 
-       ports = roothub_a (ohci) & RH_A_NDP; 
-       if (ports > MAX_ROOT_PORTS) {
-               ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports,
+       /* undocumented erratum seen on at least rev D */
+       if ((ohci->flags & OHCI_QUIRK_AMD756)
+                       && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) {
+               ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n",
                          ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
                /* retry later; "should not happen" */
                goto done;
@@ -332,13 +333,13 @@ ohci_hub_status_data (struct usb_hcd *hc
                buf [0] = changed = 1;
        else
                buf [0] = 0;
-       if (ports > 7) {
+       if (ohci->num_ports > 7) {
                buf [1] = 0;
                length++;
        }
 
        /* look at each port */
-       for (i = 0; i < ports; i++) {
+       for (i = 0; i < ohci->num_ports; i++) {
                u32     status = roothub_portstatus (ohci, i);
 
                if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
@@ -395,15 +396,14 @@ ohci_hub_descriptor (
        struct usb_hub_descriptor       *desc
 ) {
        u32             rh = roothub_a (ohci);
-       int             ports = rh & RH_A_NDP; 
        u16             temp;
 
        desc->bDescriptorType = 0x29;
        desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
        desc->bHubContrCurrent = 0;
 
-       desc->bNbrPorts = ports;
-       temp = 1 + (ports / 8);
+       desc->bNbrPorts = ohci->num_ports;
+       temp = 1 + (ohci->num_ports / 8);
        desc->bDescLength = 7 + 2 * temp;
 
        temp = 0;
@@ -421,7 +421,7 @@ ohci_hub_descriptor (
        rh = roothub_b (ohci);
        memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
        desc->bitmap [0] = rh & RH_B_DR;
-       if (ports > 7) {
+       if (ohci->num_ports > 7) {
                desc->bitmap [1] = (rh & RH_B_DR) >> 8;
                desc->bitmap [2] = 0xff;
        } else
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -258,6 +258,9 @@ ohci_pxa27x_start (struct usb_hcd *hcd)
 
        ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci);
 
+       /* The value of NDP in roothub_a is incorrect on this hardware */
+       ohci->num_ports = 3;
+
        if ((ret = ohci_init(ohci)) < 0)
                return ret;
 
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -383,6 +383,7 @@ struct ohci_hcd {
        /*
         * driver state
         */
+       int                     num_ports;
        int                     load [NUM_INTS];
        u32                     hc_control;     /* copy of hc control reg */
        unsigned long           next_statechange;       /* suspend/resume */



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to