diff options
-rw-r--r-- | Documentation/powerpc/dts-bindings/xilinx.txt | 11 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 15 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-xilinx-of.c | 300 |
4 files changed, 329 insertions, 2 deletions
diff --git a/Documentation/powerpc/dts-bindings/xilinx.txt b/Documentation/powerpc/dts-bindings/xilinx.txt index 80339fe4300b..ea68046bb9cb 100644 --- a/Documentation/powerpc/dts-bindings/xilinx.txt +++ b/Documentation/powerpc/dts-bindings/xilinx.txt | |||
@@ -292,4 +292,15 @@ | |||
292 | - reg-offset : A value of 3 is required | 292 | - reg-offset : A value of 3 is required |
293 | - reg-shift : A value of 2 is required | 293 | - reg-shift : A value of 2 is required |
294 | 294 | ||
295 | vii) Xilinx USB Host controller | ||
296 | |||
297 | The Xilinx USB host controller is EHCI compatible but with a different | ||
298 | base address for the EHCI registers, and it is always a big-endian | ||
299 | USB Host controller. The hardware can be configured as high speed only, | ||
300 | or high speed/full speed hybrid. | ||
301 | |||
302 | Required properties: | ||
303 | - xlnx,support-usb-fs: A value 0 means the core is built as high speed | ||
304 | only. A value 1 means the core also supports | ||
305 | full speed devices. | ||
295 | 306 | ||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 9b43b226817f..6d97e039cdbb 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -90,14 +90,25 @@ config USB_EHCI_TT_NEWSCHED | |||
90 | 90 | ||
91 | config USB_EHCI_BIG_ENDIAN_MMIO | 91 | config USB_EHCI_BIG_ENDIAN_MMIO |
92 | bool | 92 | bool |
93 | depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX) | 93 | depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX) |
94 | default y | 94 | default y |
95 | 95 | ||
96 | config USB_EHCI_BIG_ENDIAN_DESC | 96 | config USB_EHCI_BIG_ENDIAN_DESC |
97 | bool | 97 | bool |
98 | depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX) | 98 | depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX) |
99 | default y | 99 | default y |
100 | 100 | ||
101 | config XPS_USB_HCD_XILINX | ||
102 | bool "Use Xilinx usb host EHCI controller core" | ||
103 | depends on USB_EHCI_HCD && (PPC32 || MICROBLAZE) | ||
104 | select USB_EHCI_BIG_ENDIAN_DESC | ||
105 | select USB_EHCI_BIG_ENDIAN_MMIO | ||
106 | ---help--- | ||
107 | Xilinx xps USB host controller core is EHCI compilant and has | ||
108 | transaction translator built-in. It can be configured to either | ||
109 | support both high speed and full speed devices, or high speed | ||
110 | devices only. | ||
111 | |||
101 | config USB_EHCI_FSL | 112 | config USB_EHCI_FSL |
102 | bool "Support for Freescale on-chip EHCI USB controller" | 113 | bool "Support for Freescale on-chip EHCI USB controller" |
103 | depends on USB_EHCI_HCD && FSL_SOC | 114 | depends on USB_EHCI_HCD && FSL_SOC |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d8f4aaa616f2..e2afb2b5faf8 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -1120,6 +1120,11 @@ MODULE_LICENSE ("GPL"); | |||
1120 | #define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver | 1120 | #define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver |
1121 | #endif | 1121 | #endif |
1122 | 1122 | ||
1123 | #ifdef CONFIG_XPS_USB_HCD_XILINX | ||
1124 | #include "ehci-xilinx-of.c" | ||
1125 | #define OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver | ||
1126 | #endif | ||
1127 | |||
1123 | #ifdef CONFIG_PLAT_ORION | 1128 | #ifdef CONFIG_PLAT_ORION |
1124 | #include "ehci-orion.c" | 1129 | #include "ehci-orion.c" |
1125 | #define PLATFORM_DRIVER ehci_orion_driver | 1130 | #define PLATFORM_DRIVER ehci_orion_driver |
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c new file mode 100644 index 000000000000..a5861531ad3e --- /dev/null +++ b/drivers/usb/host/ehci-xilinx-of.c | |||
@@ -0,0 +1,300 @@ | |||
1 | /* | ||
2 | * EHCI HCD (Host Controller Driver) for USB. | ||
3 | * | ||
4 | * Bus Glue for Xilinx EHCI core on the of_platform bus | ||
5 | * | ||
6 | * Copyright (c) 2009 Xilinx, Inc. | ||
7 | * | ||
8 | * Based on "ehci-ppc-of.c" by Valentine Barshak <vbarshak@ru.mvista.com> | ||
9 | * and "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de> | ||
10 | * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, but | ||
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
20 | * for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software Foundation, | ||
24 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/signal.h> | ||
29 | |||
30 | #include <linux/of.h> | ||
31 | #include <linux/of_platform.h> | ||
32 | |||
33 | /** | ||
34 | * ehci_xilinx_of_setup - Initialize the device for ehci_reset() | ||
35 | * @hcd: Pointer to the usb_hcd device to which the host controller bound | ||
36 | * | ||
37 | * called during probe() after chip reset completes. | ||
38 | */ | ||
39 | static int ehci_xilinx_of_setup(struct usb_hcd *hcd) | ||
40 | { | ||
41 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
42 | int retval; | ||
43 | |||
44 | retval = ehci_halt(ehci); | ||
45 | if (retval) | ||
46 | return retval; | ||
47 | |||
48 | retval = ehci_init(hcd); | ||
49 | if (retval) | ||
50 | return retval; | ||
51 | |||
52 | ehci->sbrn = 0x20; | ||
53 | |||
54 | return ehci_reset(ehci); | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * ehci_xilinx_port_handed_over - hand the port out if failed to enable it | ||
59 | * @hcd: Pointer to the usb_hcd device to which the host controller bound | ||
60 | * @portnum:Port number to which the device is attached. | ||
61 | * | ||
62 | * This function is used as a place to tell the user that the Xilinx USB host | ||
63 | * controller does support LS devices. And in an HS only configuration, it | ||
64 | * does not support FS devices either. It is hoped that this can help a | ||
65 | * confused user. | ||
66 | * | ||
67 | * There are cases when the host controller fails to enable the port due to, | ||
68 | * for example, insufficient power that can be supplied to the device from | ||
69 | * the USB bus. In those cases, the messages printed here are not helpful. | ||
70 | */ | ||
71 | static int ehci_xilinx_port_handed_over(struct usb_hcd *hcd, int portnum) | ||
72 | { | ||
73 | dev_warn(hcd->self.controller, "port %d cannot be enabled\n", portnum); | ||
74 | if (hcd->has_tt) { | ||
75 | dev_warn(hcd->self.controller, | ||
76 | "Maybe you have connected a low speed device?\n"); | ||
77 | |||
78 | dev_warn(hcd->self.controller, | ||
79 | "We do not support low speed devices\n"); | ||
80 | } else { | ||
81 | dev_warn(hcd->self.controller, | ||
82 | "Maybe your device is not a high speed device?\n"); | ||
83 | dev_warn(hcd->self.controller, | ||
84 | "The USB host controller does not support full speed " | ||
85 | "nor low speed devices\n"); | ||
86 | dev_warn(hcd->self.controller, | ||
87 | "You can reconfigure the host controller to have " | ||
88 | "full speed support\n"); | ||
89 | } | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | |||
95 | static const struct hc_driver ehci_xilinx_of_hc_driver = { | ||
96 | .description = hcd_name, | ||
97 | .product_desc = "OF EHCI", | ||
98 | .hcd_priv_size = sizeof(struct ehci_hcd), | ||
99 | |||
100 | /* | ||
101 | * generic hardware linkage | ||
102 | */ | ||
103 | .irq = ehci_irq, | ||
104 | .flags = HCD_MEMORY | HCD_USB2, | ||
105 | |||
106 | /* | ||
107 | * basic lifecycle operations | ||
108 | */ | ||
109 | .reset = ehci_xilinx_of_setup, | ||
110 | .start = ehci_run, | ||
111 | .stop = ehci_stop, | ||
112 | .shutdown = ehci_shutdown, | ||
113 | |||
114 | /* | ||
115 | * managing i/o requests and associated device resources | ||
116 | */ | ||
117 | .urb_enqueue = ehci_urb_enqueue, | ||
118 | .urb_dequeue = ehci_urb_dequeue, | ||
119 | .endpoint_disable = ehci_endpoint_disable, | ||
120 | |||
121 | /* | ||
122 | * scheduling support | ||
123 | */ | ||
124 | .get_frame_number = ehci_get_frame, | ||
125 | |||
126 | /* | ||
127 | * root hub support | ||
128 | */ | ||
129 | .hub_status_data = ehci_hub_status_data, | ||
130 | .hub_control = ehci_hub_control, | ||
131 | #ifdef CONFIG_PM | ||
132 | .bus_suspend = ehci_bus_suspend, | ||
133 | .bus_resume = ehci_bus_resume, | ||
134 | #endif | ||
135 | .relinquish_port = NULL, | ||
136 | .port_handed_over = ehci_xilinx_port_handed_over, | ||
137 | |||
138 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
139 | }; | ||
140 | |||
141 | /** | ||
142 | * ehci_hcd_xilinx_of_probe - Probe method for the USB host controller | ||
143 | * @op: pointer to the of_device to which the host controller bound | ||
144 | * @match: pointer to of_device_id structure, not used | ||
145 | * | ||
146 | * This function requests resources and sets up appropriate properties for the | ||
147 | * host controller. Because the Xilinx USB host controller can be configured | ||
148 | * as HS only or HS/FS only, it checks the configuration in the device tree | ||
149 | * entry, and sets an appropriate value for hcd->has_tt. | ||
150 | */ | ||
151 | static int __devinit | ||
152 | ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match) | ||
153 | { | ||
154 | struct device_node *dn = op->node; | ||
155 | struct usb_hcd *hcd; | ||
156 | struct ehci_hcd *ehci; | ||
157 | struct resource res; | ||
158 | int irq; | ||
159 | int rv; | ||
160 | int *value; | ||
161 | |||
162 | if (usb_disabled()) | ||
163 | return -ENODEV; | ||
164 | |||
165 | dev_dbg(&op->dev, "initializing XILINX-OF USB Controller\n"); | ||
166 | |||
167 | rv = of_address_to_resource(dn, 0, &res); | ||
168 | if (rv) | ||
169 | return rv; | ||
170 | |||
171 | hcd = usb_create_hcd(&ehci_xilinx_of_hc_driver, &op->dev, | ||
172 | "XILINX-OF USB"); | ||
173 | if (!hcd) | ||
174 | return -ENOMEM; | ||
175 | |||
176 | hcd->rsrc_start = res.start; | ||
177 | hcd->rsrc_len = res.end - res.start + 1; | ||
178 | |||
179 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | ||
180 | printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); | ||
181 | rv = -EBUSY; | ||
182 | goto err_rmr; | ||
183 | } | ||
184 | |||
185 | irq = irq_of_parse_and_map(dn, 0); | ||
186 | if (irq == NO_IRQ) { | ||
187 | printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); | ||
188 | rv = -EBUSY; | ||
189 | goto err_irq; | ||
190 | } | ||
191 | |||
192 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
193 | if (!hcd->regs) { | ||
194 | printk(KERN_ERR __FILE__ ": ioremap failed\n"); | ||
195 | rv = -ENOMEM; | ||
196 | goto err_ioremap; | ||
197 | } | ||
198 | |||
199 | ehci = hcd_to_ehci(hcd); | ||
200 | |||
201 | /* This core always has big-endian register interface and uses | ||
202 | * big-endian memory descriptors. | ||
203 | */ | ||
204 | ehci->big_endian_mmio = 1; | ||
205 | ehci->big_endian_desc = 1; | ||
206 | |||
207 | /* Check whether the FS support option is selected in the hardware. | ||
208 | */ | ||
209 | value = (int *)of_get_property(dn, "xlnx,support-usb-fs", NULL); | ||
210 | if (value && (*value == 1)) { | ||
211 | ehci_dbg(ehci, "USB host controller supports FS devices\n"); | ||
212 | hcd->has_tt = 1; | ||
213 | } else { | ||
214 | ehci_dbg(ehci, | ||
215 | "USB host controller is HS only\n"); | ||
216 | hcd->has_tt = 0; | ||
217 | } | ||
218 | |||
219 | /* Debug registers are at the first 0x100 region | ||
220 | */ | ||
221 | ehci->caps = hcd->regs + 0x100; | ||
222 | ehci->regs = hcd->regs + 0x100 + | ||
223 | HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); | ||
224 | |||
225 | /* cache this readonly data; minimize chip reads */ | ||
226 | ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); | ||
227 | |||
228 | rv = usb_add_hcd(hcd, irq, 0); | ||
229 | if (rv == 0) | ||
230 | return 0; | ||
231 | |||
232 | iounmap(hcd->regs); | ||
233 | |||
234 | err_ioremap: | ||
235 | err_irq: | ||
236 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
237 | err_rmr: | ||
238 | usb_put_hcd(hcd); | ||
239 | |||
240 | return rv; | ||
241 | } | ||
242 | |||
243 | /** | ||
244 | * ehci_hcd_xilinx_of_remove - shutdown hcd and release resources | ||
245 | * @op: pointer to of_device structure that is to be removed | ||
246 | * | ||
247 | * Remove the hcd structure, and release resources that has been requested | ||
248 | * during probe. | ||
249 | */ | ||
250 | static int ehci_hcd_xilinx_of_remove(struct of_device *op) | ||
251 | { | ||
252 | struct usb_hcd *hcd = dev_get_drvdata(&op->dev); | ||
253 | dev_set_drvdata(&op->dev, NULL); | ||
254 | |||
255 | dev_dbg(&op->dev, "stopping XILINX-OF USB Controller\n"); | ||
256 | |||
257 | usb_remove_hcd(hcd); | ||
258 | |||
259 | iounmap(hcd->regs); | ||
260 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
261 | |||
262 | usb_put_hcd(hcd); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * ehci_hcd_xilinx_of_shutdown - shutdown the hcd | ||
269 | * @op: pointer to of_device structure that is to be removed | ||
270 | * | ||
271 | * Properly shutdown the hcd, call driver's shutdown routine. | ||
272 | */ | ||
273 | static int ehci_hcd_xilinx_of_shutdown(struct of_device *op) | ||
274 | { | ||
275 | struct usb_hcd *hcd = dev_get_drvdata(&op->dev); | ||
276 | |||
277 | if (hcd->driver->shutdown) | ||
278 | hcd->driver->shutdown(hcd); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | |||
284 | static struct of_device_id ehci_hcd_xilinx_of_match[] = { | ||
285 | {.compatible = "xlnx,xps-usb-host-1.00.a",}, | ||
286 | {}, | ||
287 | }; | ||
288 | MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match); | ||
289 | |||
290 | static struct of_platform_driver ehci_hcd_xilinx_of_driver = { | ||
291 | .name = "xilinx-of-ehci", | ||
292 | .match_table = ehci_hcd_xilinx_of_match, | ||
293 | .probe = ehci_hcd_xilinx_of_probe, | ||
294 | .remove = ehci_hcd_xilinx_of_remove, | ||
295 | .shutdown = ehci_hcd_xilinx_of_shutdown, | ||
296 | .driver = { | ||
297 | .name = "xilinx-of-ehci", | ||
298 | .owner = THIS_MODULE, | ||
299 | }, | ||
300 | }; | ||