diff options
-rw-r--r-- | arch/powerpc/boot/dts/sequoia.dts | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 9 | ||||
-rw-r--r-- | drivers/usb/host/ehci-ppc-of.c | 45 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 34 | ||||
-rw-r--r-- | drivers/usb/host/ohci-ppc-of.c | 25 |
5 files changed, 112 insertions, 3 deletions
diff --git a/arch/powerpc/boot/dts/sequoia.dts b/arch/powerpc/boot/dts/sequoia.dts index 3b295e8df53f..43cc68bd3192 100644 --- a/arch/powerpc/boot/dts/sequoia.dts +++ b/arch/powerpc/boot/dts/sequoia.dts | |||
@@ -134,7 +134,7 @@ | |||
134 | }; | 134 | }; |
135 | 135 | ||
136 | USB1: usb@e0000400 { | 136 | USB1: usb@e0000400 { |
137 | compatible = "ohci-be"; | 137 | compatible = "ibm,usb-ohci-440epx", "ohci-be"; |
138 | reg = <0x00000000 0xe0000400 0x00000060>; | 138 | reg = <0x00000000 0xe0000400 0x00000060>; |
139 | interrupt-parent = <&UIC0>; | 139 | interrupt-parent = <&UIC0>; |
140 | interrupts = <0x15 0x8>; | 140 | interrupts = <0x15 0x8>; |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 38650707dfe0..97a53a48a3d8 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -434,8 +434,15 @@ static int check_reset_complete ( | |||
434 | port_status &= ~PORT_RWC_BITS; | 434 | port_status &= ~PORT_RWC_BITS; |
435 | ehci_writel(ehci, port_status, status_reg); | 435 | ehci_writel(ehci, port_status, status_reg); |
436 | 436 | ||
437 | } else | 437 | /* ensure 440EPX ohci controller state is operational */ |
438 | if (ehci->has_amcc_usb23) | ||
439 | set_ohci_hcfs(ehci, 1); | ||
440 | } else { | ||
438 | ehci_dbg (ehci, "port %d high speed\n", index + 1); | 441 | ehci_dbg (ehci, "port %d high speed\n", index + 1); |
442 | /* ensure 440EPx ohci controller state is suspended */ | ||
443 | if (ehci->has_amcc_usb23) | ||
444 | set_ohci_hcfs(ehci, 0); | ||
445 | } | ||
439 | 446 | ||
440 | return port_status; | 447 | return port_status; |
441 | } | 448 | } |
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index b018deed2e8f..ef732b704f53 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c | |||
@@ -107,11 +107,13 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) | |||
107 | { | 107 | { |
108 | struct device_node *dn = op->node; | 108 | struct device_node *dn = op->node; |
109 | struct usb_hcd *hcd; | 109 | struct usb_hcd *hcd; |
110 | struct ehci_hcd *ehci; | 110 | struct ehci_hcd *ehci = NULL; |
111 | struct resource res; | 111 | struct resource res; |
112 | int irq; | 112 | int irq; |
113 | int rv; | 113 | int rv; |
114 | 114 | ||
115 | struct device_node *np; | ||
116 | |||
115 | if (usb_disabled()) | 117 | if (usb_disabled()) |
116 | return -ENODEV; | 118 | return -ENODEV; |
117 | 119 | ||
@@ -149,6 +151,20 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) | |||
149 | } | 151 | } |
150 | 152 | ||
151 | ehci = hcd_to_ehci(hcd); | 153 | ehci = hcd_to_ehci(hcd); |
154 | np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx"); | ||
155 | if (np != NULL) { | ||
156 | /* claim we really affected by usb23 erratum */ | ||
157 | if (!of_address_to_resource(np, 0, &res)) | ||
158 | ehci->ohci_hcctrl_reg = ioremap(res.start + | ||
159 | OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN); | ||
160 | else | ||
161 | pr_debug(__FILE__ ": no ohci offset in fdt\n"); | ||
162 | if (!ehci->ohci_hcctrl_reg) { | ||
163 | pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n"); | ||
164 | } else { | ||
165 | ehci->has_amcc_usb23 = 1; | ||
166 | } | ||
167 | } | ||
152 | 168 | ||
153 | if (of_get_property(dn, "big-endian", NULL)) { | 169 | if (of_get_property(dn, "big-endian", NULL)) { |
154 | ehci->big_endian_mmio = 1; | 170 | ehci->big_endian_mmio = 1; |
@@ -181,6 +197,9 @@ err_ioremap: | |||
181 | irq_dispose_mapping(irq); | 197 | irq_dispose_mapping(irq); |
182 | err_irq: | 198 | err_irq: |
183 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 199 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
200 | |||
201 | if (ehci->has_amcc_usb23) | ||
202 | iounmap(ehci->ohci_hcctrl_reg); | ||
184 | err_rmr: | 203 | err_rmr: |
185 | usb_put_hcd(hcd); | 204 | usb_put_hcd(hcd); |
186 | 205 | ||
@@ -191,6 +210,11 @@ err_rmr: | |||
191 | static int ehci_hcd_ppc_of_remove(struct of_device *op) | 210 | static int ehci_hcd_ppc_of_remove(struct of_device *op) |
192 | { | 211 | { |
193 | struct usb_hcd *hcd = dev_get_drvdata(&op->dev); | 212 | struct usb_hcd *hcd = dev_get_drvdata(&op->dev); |
213 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
214 | |||
215 | struct device_node *np; | ||
216 | struct resource res; | ||
217 | |||
194 | dev_set_drvdata(&op->dev, NULL); | 218 | dev_set_drvdata(&op->dev, NULL); |
195 | 219 | ||
196 | dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); | 220 | dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); |
@@ -201,6 +225,25 @@ static int ehci_hcd_ppc_of_remove(struct of_device *op) | |||
201 | irq_dispose_mapping(hcd->irq); | 225 | irq_dispose_mapping(hcd->irq); |
202 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 226 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
203 | 227 | ||
228 | /* use request_mem_region to test if the ohci driver is loaded. if so | ||
229 | * ensure the ohci core is operational. | ||
230 | */ | ||
231 | if (ehci->has_amcc_usb23) { | ||
232 | np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx"); | ||
233 | if (np != NULL) { | ||
234 | if (!of_address_to_resource(np, 0, &res)) | ||
235 | if (!request_mem_region(res.start, | ||
236 | 0x4, hcd_name)) | ||
237 | set_ohci_hcfs(ehci, 1); | ||
238 | else | ||
239 | release_mem_region(res.start, 0x4); | ||
240 | else | ||
241 | pr_debug(__FILE__ ": no ohci offset in fdt\n"); | ||
242 | of_node_put(np); | ||
243 | } | ||
244 | |||
245 | iounmap(ehci->ohci_hcctrl_reg); | ||
246 | } | ||
204 | usb_put_hcd(hcd); | 247 | usb_put_hcd(hcd); |
205 | 248 | ||
206 | return 0; | 249 | return 0; |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index c7d4b5a06bdb..fb7054ccf4fc 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -120,6 +120,16 @@ struct ehci_hcd { /* one per controller */ | |||
120 | unsigned has_fsl_port_bug:1; /* FreeScale */ | 120 | unsigned has_fsl_port_bug:1; /* FreeScale */ |
121 | unsigned big_endian_mmio:1; | 121 | unsigned big_endian_mmio:1; |
122 | unsigned big_endian_desc:1; | 122 | unsigned big_endian_desc:1; |
123 | unsigned has_amcc_usb23:1; | ||
124 | |||
125 | /* required for usb32 quirk */ | ||
126 | #define OHCI_CTRL_HCFS (3 << 6) | ||
127 | #define OHCI_USB_OPER (2 << 6) | ||
128 | #define OHCI_USB_SUSPEND (3 << 6) | ||
129 | |||
130 | #define OHCI_HCCTRL_OFFSET 0x4 | ||
131 | #define OHCI_HCCTRL_LEN 0x4 | ||
132 | __hc32 *ohci_hcctrl_reg; | ||
123 | 133 | ||
124 | u8 sbrn; /* packed release number */ | 134 | u8 sbrn; /* packed release number */ |
125 | 135 | ||
@@ -636,6 +646,30 @@ static inline void ehci_writel(const struct ehci_hcd *ehci, | |||
636 | #endif | 646 | #endif |
637 | } | 647 | } |
638 | 648 | ||
649 | /* | ||
650 | * On certain ppc-44x SoC there is a HW issue, that could only worked around with | ||
651 | * explicit suspend/operate of OHCI. This function hereby makes sense only on that arch. | ||
652 | * Other common bits are dependant on has_amcc_usb23 quirk flag. | ||
653 | */ | ||
654 | #ifdef CONFIG_44x | ||
655 | static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational) | ||
656 | { | ||
657 | u32 hc_control; | ||
658 | |||
659 | hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS); | ||
660 | if (operational) | ||
661 | hc_control |= OHCI_USB_OPER; | ||
662 | else | ||
663 | hc_control |= OHCI_USB_SUSPEND; | ||
664 | |||
665 | writel_be(hc_control, ehci->ohci_hcctrl_reg); | ||
666 | (void) readl_be(ehci->ohci_hcctrl_reg); | ||
667 | } | ||
668 | #else | ||
669 | static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational) | ||
670 | { } | ||
671 | #endif | ||
672 | |||
639 | /*-------------------------------------------------------------------------*/ | 673 | /*-------------------------------------------------------------------------*/ |
640 | 674 | ||
641 | /* | 675 | /* |
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 7ac53264ead3..68a301710297 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c | |||
@@ -91,6 +91,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) | |||
91 | 91 | ||
92 | int rv; | 92 | int rv; |
93 | int is_bigendian; | 93 | int is_bigendian; |
94 | struct device_node *np; | ||
94 | 95 | ||
95 | if (usb_disabled()) | 96 | if (usb_disabled()) |
96 | return -ENODEV; | 97 | return -ENODEV; |
@@ -147,6 +148,30 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) | |||
147 | if (rv == 0) | 148 | if (rv == 0) |
148 | return 0; | 149 | return 0; |
149 | 150 | ||
151 | /* by now, 440epx is known to show usb_23 erratum */ | ||
152 | np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx"); | ||
153 | |||
154 | /* Work around - At this point ohci_run has executed, the | ||
155 | * controller is running, everything, the root ports, etc., is | ||
156 | * set up. If the ehci driver is loaded, put the ohci core in | ||
157 | * the suspended state. The ehci driver will bring it out of | ||
158 | * suspended state when / if a non-high speed USB device is | ||
159 | * attached to the USB Host port. If the ehci driver is not | ||
160 | * loaded, do nothing. request_mem_region is used to test if | ||
161 | * the ehci driver is loaded. | ||
162 | */ | ||
163 | if (np != NULL) { | ||
164 | if (!of_address_to_resource(np, 0, &res)) { | ||
165 | if (!request_mem_region(res.start, 0x4, hcd_name)) { | ||
166 | writel_be((readl_be(&ohci->regs->control) | | ||
167 | OHCI_USB_SUSPEND), &ohci->regs->control); | ||
168 | (void) readl_be(&ohci->regs->control); | ||
169 | } else | ||
170 | release_mem_region(res.start, 0x4); | ||
171 | } else | ||
172 | pr_debug(__FILE__ ": cannot get ehci offset from fdt\n"); | ||
173 | } | ||
174 | |||
150 | iounmap(hcd->regs); | 175 | iounmap(hcd->regs); |
151 | err_ioremap: | 176 | err_ioremap: |
152 | irq_dispose_mapping(irq); | 177 | irq_dispose_mapping(irq); |