Browse Source

[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 <rpurdie@rpsys.net>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
David Brownell 19 years ago
parent
commit
fdd13b36c4

+ 4 - 5
drivers/usb/host/ohci-dbg.c

@@ -228,23 +228,22 @@ ohci_dump_roothub (
 	char **next,
 	char **next,
 	unsigned *size)
 	unsigned *size)
 {
 {
-	u32			temp, ndp, i;
+	u32			temp, i;
 
 
 	temp = roothub_a (controller);
 	temp = roothub_a (controller);
 	if (temp == ~(u32)0)
 	if (temp == ~(u32)0)
 		return;
 		return;
-	ndp = (temp & RH_A_NDP);
 
 
 	if (verbose) {
 	if (verbose) {
 		ohci_dbg_sw (controller, next, size,
 		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_POTPGT) >> 24) & 0xff,
 			(temp & RH_A_NOCP) ? " NOCP" : "",
 			(temp & RH_A_NOCP) ? " NOCP" : "",
 			(temp & RH_A_OCPM) ? " OCPM" : "",
 			(temp & RH_A_OCPM) ? " OCPM" : "",
 			(temp & RH_A_DT) ? " DT" : "",
 			(temp & RH_A_DT) ? " DT" : "",
 			(temp & RH_A_NPS) ? " NPS" : "",
 			(temp & RH_A_NPS) ? " NPS" : "",
 			(temp & RH_A_PSM) ? " PSM" : "",
 			(temp & RH_A_PSM) ? " PSM" : "",
-			ndp
+			(temp & RH_A_NDP), controller->num_ports
 			);
 			);
 		temp = roothub_b (controller);
 		temp = roothub_b (controller);
 		ohci_dbg_sw (controller, next, size,
 		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);
 		temp = roothub_portstatus (controller, i);
 		dbg_port_sw (controller, i, temp, next, size);
 		dbg_port_sw (controller, i, temp, next, size);
 	}
 	}

+ 6 - 4
drivers/usb/host/ohci-hcd.c

@@ -484,6 +484,10 @@ static int ohci_init (struct ohci_hcd *ohci)
 	// flush the writes
 	// flush the writes
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	(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)
 	if (ohci->hcca)
 		return 0;
 		return 0;
 
 
@@ -560,10 +564,8 @@ static int ohci_run (struct ohci_hcd *ohci)
 	msleep(temp);
 	msleep(temp);
 	temp = roothub_a (ohci);
 	temp = roothub_a (ohci);
 	if (!(temp & RH_A_NPS)) {
 	if (!(temp & RH_A_NPS)) {
-		unsigned ports = temp & RH_A_NDP; 
-
 		/* power down each port */
 		/* 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_writel (ohci, RH_PS_LSDA,
 				&ohci->regs->roothub.portstatus [temp]);
 				&ohci->regs->roothub.portstatus [temp]);
 	}
 	}
@@ -861,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
 		 * and that if we try to turn them back on the root hub
 		 * and that if we try to turn them back on the root hub
 		 * will respond to CSC processing.
 		 * will respond to CSC processing.
 		 */
 		 */
-		i = roothub_a (ohci) & RH_A_NDP;
+		i = ohci->num_ports;
 		while (i--)
 		while (i--)
 			ohci_writel (ohci, RH_PS_PSS,
 			ohci_writel (ohci, RH_PS_PSS,
 				&ohci->regs->roothub.portstatus [temp]);
 				&ohci->regs->roothub.portstatus [temp]);

+ 11 - 11
drivers/usb/host/ohci-hub.c

@@ -184,7 +184,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
 	if (status != -EINPROGRESS)
 	if (status != -EINPROGRESS)
 		return status;
 		return status;
 
 
-	temp = roothub_a (ohci) & RH_A_NDP;
+	temp = ohci->num_ports;
 	enables = 0;
 	enables = 0;
 	while (temp--) {
 	while (temp--) {
 		u32 stat = ohci_readl (ohci,
 		u32 stat = ohci_readl (ohci,
@@ -304,7 +304,7 @@ static int
 ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	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;
 	int		can_suspend = hcd->can_wakeup;
 	unsigned long	flags;
 	unsigned long	flags;
 
 
@@ -319,9 +319,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 		goto done;
 		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);
 			  ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
 		/* retry later; "should not happen" */
 		/* retry later; "should not happen" */
 		goto done;
 		goto done;
@@ -332,13 +333,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 		buf [0] = changed = 1;
 		buf [0] = changed = 1;
 	else
 	else
 		buf [0] = 0;
 		buf [0] = 0;
-	if (ports > 7) {
+	if (ohci->num_ports > 7) {
 		buf [1] = 0;
 		buf [1] = 0;
 		length++;
 		length++;
 	}
 	}
 
 
 	/* look at each port */
 	/* look at each port */
-	for (i = 0; i < ports; i++) {
+	for (i = 0; i < ohci->num_ports; i++) {
 		u32	status = roothub_portstatus (ohci, i);
 		u32	status = roothub_portstatus (ohci, i);
 
 
 		if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
 		if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
@@ -395,15 +396,14 @@ ohci_hub_descriptor (
 	struct usb_hub_descriptor	*desc
 	struct usb_hub_descriptor	*desc
 ) {
 ) {
 	u32		rh = roothub_a (ohci);
 	u32		rh = roothub_a (ohci);
-	int		ports = rh & RH_A_NDP; 
 	u16		temp;
 	u16		temp;
 
 
 	desc->bDescriptorType = 0x29;
 	desc->bDescriptorType = 0x29;
 	desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
 	desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
 	desc->bHubContrCurrent = 0;
 	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;
 	desc->bDescLength = 7 + 2 * temp;
 
 
 	temp = 0;
 	temp = 0;
@@ -421,7 +421,7 @@ ohci_hub_descriptor (
 	rh = roothub_b (ohci);
 	rh = roothub_b (ohci);
 	memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
 	memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
 	desc->bitmap [0] = rh & RH_B_DR;
 	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 [1] = (rh & RH_B_DR) >> 8;
 		desc->bitmap [2] = 0xff;
 		desc->bitmap [2] = 0xff;
 	} else
 	} else

+ 3 - 0
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);
 	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)
 	if ((ret = ohci_init(ohci)) < 0)
 		return ret;
 		return ret;
 
 

+ 1 - 0
drivers/usb/host/ohci.h

@@ -383,6 +383,7 @@ struct ohci_hcd {
 	/*
 	/*
 	 * driver state
 	 * driver state
 	 */
 	 */
+	int			num_ports;
 	int			load [NUM_INTS];
 	int			load [NUM_INTS];
 	u32 			hc_control;	/* copy of hc control reg */
 	u32 			hc_control;	/* copy of hc control reg */
 	unsigned long		next_statechange;	/* suspend/resume */
 	unsigned long		next_statechange;	/* suspend/resume */