brcm47xx: add support for kernel 3.3
[openwrt.git] / target / linux / brcm47xx / patches-3.3 / 183-USB-Add-driver-for-the-bcma-bus.patch
1 --- a/drivers/usb/host/Kconfig
2 +++ b/drivers/usb/host/Kconfig
3 @@ -633,3 +633,15 @@ config USB_PXA168_EHCI
4         help
5           Enable support for Marvell PXA168 SoC's on-chip EHCI
6           host controller
7 +
8 +config USB_HCD_BCMA
9 +       tristate "BCMA usb host driver"
10 +       depends on BCMA && EXPERIMENTAL
11 +       select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
12 +       select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
13 +       help
14 +         Enbale support for the EHCI and OCHI host controller on an bcma bus.
15 +         It converts the bcma driver into two platform device drivers
16 +         for ehci and ohci.
17 +
18 +         If unsure, say N.
19 --- a/drivers/usb/host/Makefile
20 +++ b/drivers/usb/host/Makefile
21 @@ -37,3 +37,4 @@ obj-$(CONFIG_USB_IMX21_HCD)   += imx21-hcd
22  obj-$(CONFIG_USB_FSL_MPH_DR_OF)        += fsl-mph-dr-of.o
23  obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
24  obj-$(CONFIG_MIPS_ALCHEMY)     += alchemy-common.o
25 +obj-$(CONFIG_USB_HCD_BCMA)     += bcma-hcd.o
26 --- /dev/null
27 +++ b/drivers/usb/host/bcma-hcd.c
28 @@ -0,0 +1,334 @@
29 +/*
30 + * Broadcom specific Advanced Microcontroller Bus
31 + * Broadcom USB-core driver (BCMA bus glue)
32 + *
33 + * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
34 + *
35 + * Based on ssb-ohci driver
36 + * Copyright 2007 Michael Buesch <m@bues.ch>
37 + *
38 + * Derived from the OHCI-PCI driver
39 + * Copyright 1999 Roman Weissgaerber
40 + * Copyright 2000-2002 David Brownell
41 + * Copyright 1999 Linus Torvalds
42 + * Copyright 1999 Gregory P. Smith
43 + *
44 + * Derived from the USBcore related parts of Broadcom-SB
45 + * Copyright 2005-2011 Broadcom Corporation
46 + *
47 + * Licensed under the GNU/GPL. See COPYING for details.
48 + */
49 +#include <linux/bcma/bcma.h>
50 +#include <linux/delay.h>
51 +#include <linux/platform_device.h>
52 +#include <linux/module.h>
53 +#include <linux/usb/ehci_pdriver.h>
54 +#include <linux/usb/ohci_pdriver.h>
55 +
56 +MODULE_AUTHOR("Hauke Mehrtens");
57 +MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
58 +MODULE_LICENSE("GPL");
59 +
60 +struct bcma_hcd_device {
61 +       struct platform_device *ehci_dev;
62 +       struct platform_device *ohci_dev;
63 +};
64 +
65 +/* Wait for bitmask in a register to get set or cleared.
66 + * timeout is in units of ten-microseconds.
67 + */
68 +static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
69 +                         int timeout)
70 +{
71 +       int i;
72 +       u32 val;
73 +
74 +       for (i = 0; i < timeout; i++) {
75 +               val = bcma_read32(dev, reg);
76 +               if ((val & bitmask) == bitmask)
77 +                       return 0;
78 +               udelay(10);
79 +       }
80 +
81 +       return -ETIMEDOUT;
82 +}
83 +
84 +static void __devinit bcma_hcd_4716wa(struct bcma_device *dev)
85 +{
86 +#ifdef CONFIG_BCMA_DRIVER_MIPS
87 +       /* Work around for 4716 failures. */
88 +       if (dev->bus->chipinfo.id == 0x4716) {
89 +               u32 tmp;
90 +
91 +               tmp = bcma_cpu_clock(&dev->bus->drv_mips);
92 +               if (tmp >= 480000000)
93 +                       tmp = 0x1846b; /* set CDR to 0x11(fast) */
94 +               else if (tmp == 453000000)
95 +                       tmp = 0x1046b; /* set CDR to 0x10(slow) */
96 +               else
97 +                       tmp = 0;
98 +
99 +               /* Change Shim mdio control reg to fix host not acking at
100 +                * high frequencies
101 +                */
102 +               if (tmp) {
103 +                       bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
104 +                       udelay(500);
105 +
106 +                       bcma_write32(dev, 0x524, tmp);
107 +                       udelay(500);
108 +                       bcma_write32(dev, 0x524, 0x4ab);
109 +                       udelay(500);
110 +                       bcma_read32(dev, 0x528);
111 +                       bcma_write32(dev, 0x528, 0x80000000);
112 +               }
113 +       }
114 +#endif /* CONFIG_BCMA_DRIVER_MIPS */
115 +}
116 +
117 +/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
118 +static void __devinit bcma_hcd_init_chip(struct bcma_device *dev)
119 +{
120 +       u32 tmp;
121 +
122 +       /*
123 +        * USB 2.0 special considerations:
124 +        *
125 +        * 1. Since the core supports both OHCI and EHCI functions, it must
126 +        *    only be reset once.
127 +        *
128 +        * 2. In addition to the standard SI reset sequence, the Host Control
129 +        *    Register must be programmed to bring the USB core and various
130 +        *    phy components out of reset.
131 +        */
132 +       if (!bcma_core_is_enabled(dev)) {
133 +               bcma_core_enable(dev, 0);
134 +               mdelay(10);
135 +               if (dev->id.rev >= 5) {
136 +                       /* Enable Misc PLL */
137 +                       tmp = bcma_read32(dev, 0x1e0);
138 +                       tmp |= 0x100;
139 +                       bcma_write32(dev, 0x1e0, tmp);
140 +                       if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
141 +                               printk(KERN_EMERG "Failed to enable misc PPL!\n");
142 +
143 +                       /* Take out of resets */
144 +                       bcma_write32(dev, 0x200, 0x4ff);
145 +                       udelay(25);
146 +                       bcma_write32(dev, 0x200, 0x6ff);
147 +                       udelay(25);
148 +
149 +                       /* Make sure digital and AFE are locked in USB PHY */
150 +                       bcma_write32(dev, 0x524, 0x6b);
151 +                       udelay(50);
152 +                       tmp = bcma_read32(dev, 0x524);
153 +                       udelay(50);
154 +                       bcma_write32(dev, 0x524, 0xab);
155 +                       udelay(50);
156 +                       tmp = bcma_read32(dev, 0x524);
157 +                       udelay(50);
158 +                       bcma_write32(dev, 0x524, 0x2b);
159 +                       udelay(50);
160 +                       tmp = bcma_read32(dev, 0x524);
161 +                       udelay(50);
162 +                       bcma_write32(dev, 0x524, 0x10ab);
163 +                       udelay(50);
164 +                       tmp = bcma_read32(dev, 0x524);
165 +
166 +                       if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
167 +                               tmp = bcma_read32(dev, 0x528);
168 +                               printk(KERN_EMERG
169 +                                      "USB20H mdio_rddata 0x%08x\n", tmp);
170 +                       }
171 +                       bcma_write32(dev, 0x528, 0x80000000);
172 +                       tmp = bcma_read32(dev, 0x314);
173 +                       udelay(265);
174 +                       bcma_write32(dev, 0x200, 0x7ff);
175 +                       udelay(10);
176 +
177 +                       /* Take USB and HSIC out of non-driving modes */
178 +                       bcma_write32(dev, 0x510, 0);
179 +               } else {
180 +                       bcma_write32(dev, 0x200, 0x7ff);
181 +
182 +                       udelay(1);
183 +               }
184 +
185 +               bcma_hcd_4716wa(dev);
186 +       }
187 +}
188 +
189 +static const struct usb_ehci_pdata ehci_pdata = {
190 +};
191 +
192 +static const struct usb_ohci_pdata ohci_pdata = {
193 +};
194 +
195 +static struct platform_device * __devinit
196 +bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
197 +{
198 +       struct platform_device *hci_dev;
199 +       struct resource hci_res[2];
200 +       int ret = -ENOMEM;
201 +
202 +       memset(hci_res, 0, sizeof(hci_res));
203 +
204 +       hci_res[0].start = addr;
205 +       hci_res[0].end = hci_res[0].start + 0x1000 - 1;
206 +       hci_res[0].flags = IORESOURCE_MEM;
207 +
208 +       hci_res[1].start = dev->irq;
209 +       hci_res[1].flags = IORESOURCE_IRQ;
210 +
211 +       hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
212 +                                       "ehci-platform" , 0);
213 +       if (!hci_dev)
214 +               return NULL;
215 +
216 +       hci_dev->dev.parent = &dev->dev;
217 +       hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
218 +
219 +       ret = platform_device_add_resources(hci_dev, hci_res,
220 +                                           ARRAY_SIZE(hci_res));
221 +       if (ret)
222 +               goto err_alloc;
223 +       if (ohci)
224 +               ret = platform_device_add_data(hci_dev, &ohci_pdata,
225 +                                              sizeof(ohci_pdata));
226 +       else
227 +               ret = platform_device_add_data(hci_dev, &ehci_pdata,
228 +                                              sizeof(ehci_pdata));
229 +       if (ret)
230 +               goto err_alloc;
231 +       ret = platform_device_add(hci_dev);
232 +       if (ret)
233 +               goto err_alloc;
234 +
235 +       return hci_dev;
236 +
237 +err_alloc:
238 +       platform_device_put(hci_dev);
239 +       return ERR_PTR(ret);
240 +}
241 +
242 +static int __devinit bcma_hcd_probe(struct bcma_device *dev)
243 +{
244 +       int err;
245 +       u16 chipid_top;
246 +       u32 ohci_addr;
247 +       struct bcma_hcd_device *usb_dev;
248 +       struct bcma_chipinfo *chipinfo;
249 +
250 +       chipinfo = &dev->bus->chipinfo;
251 +       /* USBcores are only connected on embedded devices. */
252 +       chipid_top = (chipinfo->id & 0xFF00);
253 +       if (chipid_top != 0x4700 && chipid_top != 0x5300)
254 +               return -ENODEV;
255 +
256 +       /* TODO: Probably need checks here; is the core connected? */
257 +
258 +       if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
259 +           dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
260 +               return -EOPNOTSUPP;
261 +
262 +       usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
263 +       if (!usb_dev)
264 +               return -ENOMEM;
265 +
266 +       bcma_hcd_init_chip(dev);
267 +
268 +       /* In AI chips EHCI is addrspace 0, OHCI is 1 */
269 +       ohci_addr = dev->addr1;
270 +       if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
271 +           && chipinfo->rev == 0)
272 +               ohci_addr = 0x18009000;
273 +
274 +       usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
275 +       if (IS_ERR(usb_dev->ohci_dev)) {
276 +               err = PTR_ERR(usb_dev->ohci_dev);
277 +               goto err_free_usb_dev;
278 +       }
279 +
280 +       usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
281 +       if (IS_ERR(usb_dev->ehci_dev)) {
282 +               err = PTR_ERR(usb_dev->ehci_dev);
283 +               goto err_unregister_ohci_dev;
284 +       }
285 +
286 +       bcma_set_drvdata(dev, usb_dev);
287 +       return 0;
288 +
289 +err_unregister_ohci_dev:
290 +       platform_device_unregister(usb_dev->ohci_dev);
291 +err_free_usb_dev:
292 +       kfree(usb_dev);
293 +       return err;
294 +}
295 +
296 +static void __devexit bcma_hcd_remove(struct bcma_device *dev)
297 +{
298 +       struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
299 +       struct platform_device *ohci_dev = usb_dev->ohci_dev;
300 +       struct platform_device *ehci_dev = usb_dev->ehci_dev;
301 +
302 +       if (ohci_dev)
303 +               platform_device_unregister(ohci_dev);
304 +       if (ehci_dev)
305 +               platform_device_unregister(ehci_dev);
306 +
307 +       bcma_core_disable(dev, 0);
308 +}
309 +
310 +static void bcma_hcd_shutdown(struct bcma_device *dev)
311 +{
312 +       bcma_core_disable(dev, 0);
313 +}
314 +
315 +#ifdef CONFIG_PM
316 +
317 +static int bcma_hcd_suspend(struct bcma_device *dev, pm_message_t state)
318 +{
319 +       bcma_core_disable(dev, 0);
320 +
321 +       return 0;
322 +}
323 +
324 +static int bcma_hcd_resume(struct bcma_device *dev)
325 +{
326 +       bcma_core_enable(dev, 0);
327 +
328 +       return 0;
329 +}
330 +
331 +#else /* !CONFIG_PM */
332 +#define bcma_hcd_suspend       NULL
333 +#define bcma_hcd_resume        NULL
334 +#endif /* CONFIG_PM */
335 +
336 +static const struct bcma_device_id bcma_hcd_table[] __devinitconst = {
337 +       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
338 +       BCMA_CORETABLE_END
339 +};
340 +MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
341 +
342 +static struct bcma_driver bcma_hcd_driver = {
343 +       .name           = KBUILD_MODNAME,
344 +       .id_table       = bcma_hcd_table,
345 +       .probe          = bcma_hcd_probe,
346 +       .remove         = __devexit_p(bcma_hcd_remove),
347 +       .shutdown       = bcma_hcd_shutdown,
348 +       .suspend        = bcma_hcd_suspend,
349 +       .resume         = bcma_hcd_resume,
350 +};
351 +
352 +static int __init bcma_hcd_init(void)
353 +{
354 +       return bcma_driver_register(&bcma_hcd_driver);
355 +}
356 +module_init(bcma_hcd_init);
357 +
358 +static void __exit bcma_hcd_exit(void)
359 +{
360 +       bcma_driver_unregister(&bcma_hcd_driver);
361 +}
362 +module_exit(bcma_hcd_exit);