Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 127224
b: refs/heads/master
c: 796bcae
h: refs/heads/master
v: v3
  • Loading branch information
Vitaly Bordug authored and Greg Kroah-Hartman committed Jan 7, 2009
1 parent fd2fe77 commit 7df1fb4
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cd40c4c45eaedc289d2e1cc33b18a49a211f0f82
refs/heads/master: 796bcae7361c28cf825780f6f1aac9dd3411394e
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/boot/dts/sequoia.dts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@
};

USB1: usb@e0000400 {
compatible = "ohci-be";
compatible = "ibm,usb-ohci-440epx", "ohci-be";
reg = <0x00000000 0xe0000400 0x00000060>;
interrupt-parent = <&UIC0>;
interrupts = <0x15 0x8>;
Expand Down
9 changes: 8 additions & 1 deletion trunk/drivers/usb/host/ehci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,15 @@ static int check_reset_complete (
port_status &= ~PORT_RWC_BITS;
ehci_writel(ehci, port_status, status_reg);

} else
/* ensure 440EPX ohci controller state is operational */
if (ehci->has_amcc_usb23)
set_ohci_hcfs(ehci, 1);
} else {
ehci_dbg (ehci, "port %d high speed\n", index + 1);
/* ensure 440EPx ohci controller state is suspended */
if (ehci->has_amcc_usb23)
set_ohci_hcfs(ehci, 0);
}

return port_status;
}
Expand Down
45 changes: 44 additions & 1 deletion trunk/drivers/usb/host/ehci-ppc-of.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,13 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dn = op->node;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct ehci_hcd *ehci = NULL;
struct resource res;
int irq;
int rv;

struct device_node *np;

if (usb_disabled())
return -ENODEV;

Expand Down Expand Up @@ -149,6 +151,20 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
}

ehci = hcd_to_ehci(hcd);
np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
if (np != NULL) {
/* claim we really affected by usb23 erratum */
if (!of_address_to_resource(np, 0, &res))
ehci->ohci_hcctrl_reg = ioremap(res.start +
OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
else
pr_debug(__FILE__ ": no ohci offset in fdt\n");
if (!ehci->ohci_hcctrl_reg) {
pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n");
} else {
ehci->has_amcc_usb23 = 1;
}
}

if (of_get_property(dn, "big-endian", NULL)) {
ehci->big_endian_mmio = 1;
Expand Down Expand Up @@ -181,6 +197,9 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
irq_dispose_mapping(irq);
err_irq:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

if (ehci->has_amcc_usb23)
iounmap(ehci->ohci_hcctrl_reg);
err_rmr:
usb_put_hcd(hcd);

Expand All @@ -191,6 +210,11 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
static int ehci_hcd_ppc_of_remove(struct of_device *op)
{
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);

struct device_node *np;
struct resource res;

dev_set_drvdata(&op->dev, NULL);

dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
Expand All @@ -201,6 +225,25 @@ static int ehci_hcd_ppc_of_remove(struct of_device *op)
irq_dispose_mapping(hcd->irq);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

/* use request_mem_region to test if the ohci driver is loaded. if so
* ensure the ohci core is operational.
*/
if (ehci->has_amcc_usb23) {
np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
if (np != NULL) {
if (!of_address_to_resource(np, 0, &res))
if (!request_mem_region(res.start,
0x4, hcd_name))
set_ohci_hcfs(ehci, 1);
else
release_mem_region(res.start, 0x4);
else
pr_debug(__FILE__ ": no ohci offset in fdt\n");
of_node_put(np);
}

iounmap(ehci->ohci_hcctrl_reg);
}
usb_put_hcd(hcd);

return 0;
Expand Down
34 changes: 34 additions & 0 deletions trunk/drivers/usb/host/ehci.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ struct ehci_hcd { /* one per controller */
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
unsigned has_amcc_usb23:1;

/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
#define OHCI_USB_OPER (2 << 6)
#define OHCI_USB_SUSPEND (3 << 6)

#define OHCI_HCCTRL_OFFSET 0x4
#define OHCI_HCCTRL_LEN 0x4
__hc32 *ohci_hcctrl_reg;

u8 sbrn; /* packed release number */

Expand Down Expand Up @@ -636,6 +646,30 @@ static inline void ehci_writel(const struct ehci_hcd *ehci,
#endif
}

/*
* On certain ppc-44x SoC there is a HW issue, that could only worked around with
* explicit suspend/operate of OHCI. This function hereby makes sense only on that arch.
* Other common bits are dependant on has_amcc_usb23 quirk flag.
*/
#ifdef CONFIG_44x
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
{
u32 hc_control;

hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS);
if (operational)
hc_control |= OHCI_USB_OPER;
else
hc_control |= OHCI_USB_SUSPEND;

writel_be(hc_control, ehci->ohci_hcctrl_reg);
(void) readl_be(ehci->ohci_hcctrl_reg);
}
#else
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
{ }
#endif

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

/*
Expand Down
25 changes: 25 additions & 0 deletions trunk/drivers/usb/host/ohci-ppc-of.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)

int rv;
int is_bigendian;
struct device_node *np;

if (usb_disabled())
return -ENODEV;
Expand Down Expand Up @@ -147,6 +148,30 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
if (rv == 0)
return 0;

/* by now, 440epx is known to show usb_23 erratum */
np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx");

/* Work around - At this point ohci_run has executed, the
* controller is running, everything, the root ports, etc., is
* set up. If the ehci driver is loaded, put the ohci 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. If the ehci driver is not
* loaded, do nothing. request_mem_region is used to test if
* the ehci driver is loaded.
*/
if (np != NULL) {
if (!of_address_to_resource(np, 0, &res)) {
if (!request_mem_region(res.start, 0x4, hcd_name)) {
writel_be((readl_be(&ohci->regs->control) |
OHCI_USB_SUSPEND), &ohci->regs->control);
(void) readl_be(&ohci->regs->control);
} else
release_mem_region(res.start, 0x4);
} else
pr_debug(__FILE__ ": cannot get ehci offset from fdt\n");
}

iounmap(hcd->regs);
err_ioremap:
irq_dispose_mapping(irq);
Expand Down

0 comments on commit 7df1fb4

Please sign in to comment.