merge of '7393275c6ccce67cadeb49d4afb3459e56edf8a9'
[vuplus_openembedded] / packages / linux / linux-rp-2.6.24 / tosa / 0010-OHCI-driver-for-TMIO-devices.patch
1 From e5f06830bc8d3ef4792c9c0569825d0347b39852 Mon Sep 17 00:00:00 2001
2 From: Ian Molton <spyro@f2s.com>
3 Date: Fri, 4 Jan 2008 18:43:31 +0000
4 Subject: [PATCH 10/64] OHCI driver for TMIO devices
5
6 ---
7  drivers/usb/Kconfig          |    1 +
8  drivers/usb/host/Kconfig     |    1 +
9  drivers/usb/host/ohci-hcd.c  |    5 +
10  drivers/usb/host/ohci-tmio.c |  369 ++++++++++++++++++++++++++++++++++++++++++
11  4 files changed, 376 insertions(+), 0 deletions(-)
12  create mode 100644 drivers/usb/host/ohci-tmio.c
13
14 diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
15 index 7580aa5..8912042 100644
16 --- a/drivers/usb/Kconfig
17 +++ b/drivers/usb/Kconfig
18 @@ -36,6 +36,7 @@ config USB_ARCH_HAS_OHCI
19         default y if ARCH_EP93XX
20         default y if ARCH_AT91
21         default y if ARCH_PNX4008
22 +       default y if MFD_TC6393XB
23         # PPC:
24         default y if STB03xxx
25         default y if PPC_MPC52xx
26 diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
27 index 49a91c5..5ae3589 100644
28 --- a/drivers/usb/host/Kconfig
29 +++ b/drivers/usb/host/Kconfig
30 @@ -101,6 +101,7 @@ config USB_OHCI_HCD
31         depends on USB && USB_ARCH_HAS_OHCI
32         select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
33         select I2C if ARCH_PNX4008
34 +       select DMABOUNCE if MFD_TC6393XB
35         ---help---
36           The Open Host Controller Interface (OHCI) is a standard for accessing
37           USB 1.1 host controller hardware.  It does more in hardware than Intel's
38 diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
39 index ecfe800..77abf3e 100644
40 --- a/drivers/usb/host/ohci-hcd.c
41 +++ b/drivers/usb/host/ohci-hcd.c
42 @@ -1043,6 +1043,11 @@ MODULE_LICENSE ("GPL");
43  #define PS3_SYSTEM_BUS_DRIVER  ps3_ohci_driver
44  #endif
45  
46 +#ifdef CONFIG_MFD_TC6393XB
47 +#include "ohci-tmio.c"
48 +#define PLATFORM_DRIVER                ohci_hcd_tmio_driver
49 +#endif
50 +
51  #ifdef CONFIG_USB_OHCI_HCD_SSB
52  #include "ohci-ssb.c"
53  #define SSB_OHCI_DRIVER                ssb_ohci_driver
54 diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
55 new file mode 100644
56 index 0000000..be609f3
57 --- /dev/null
58 +++ b/drivers/usb/host/ohci-tmio.c
59 @@ -0,0 +1,369 @@
60 +/*
61 + * OHCI HCD(Host Controller Driver) for USB.
62 + *
63 + *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
64 + *(C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
65 + *(C) Copyright 2002 Hewlett-Packard Company
66 + *
67 + * Bus glue for Toshiba Mobile IO(TMIO) Controller's OHCI core
68 + *(C) Copyright 2005 Chris Humbert <mahadri-usb@drigon.com>
69 + *
70 + * This is known to work with the following variants:
71 + *     TC6393XB revision 3     (32kB SRAM)
72 + *
73 + * The TMIO's OHCI core DMAs through a small internal buffer that
74 + * is directly addressable by the CPU.  dma_declare_coherent_memory
75 + * and DMA bounce buffers allow the higher-level OHCI host driver to
76 + * work.  However, the dma API doesn't handle dma mapping failures
77 + * well(dma_sg_map() is a prime example), so it is unusable.
78 + *
79 + * This HC pretends be a PIO-ish controller and uses the kernel's
80 + * generic allocator for the entire SRAM.  Using the USB core's
81 + * usb_operations, we provide hcd_buffer_alloc/free.  Using the OHCI's
82 + * ohci_ops, we provide memory management for OHCI's TDs and EDs.  We
83 + * internally queue a URB's TDs until enough dma memory is available
84 + * to enqueue them with the HC.
85 + *
86 + * Written from sparse documentation from Toshiba and Sharp's driver
87 + * for the 2.4 kernel,
88 + *     usb-ohci-tc6393.c(C) Copyright 2004 Lineo Solutions, Inc.
89 + *
90 + * This program is free software; you can redistribute it and/or modify
91 + * it under the terms of the GNU General Public License version 2 as
92 + * published by the Free Software Foundation.
93 + */
94 +
95 +/*#include <linux/fs.h>
96 +#include <linux/mount.h>
97 +#include <linux/pagemap.h>
98 +#include <linux/init.h>
99 +#include <linux/namei.h>
100 +#include <linux/sched.h>*/
101 +#include <linux/platform_device.h>
102 +#include <linux/mfd-core.h>
103 +#include <linux/mfd/tmio.h>
104 +#include <linux/dma-mapping.h>
105 +
106 +/*-------------------------------------------------------------------------*/
107 +
108 +/*
109 + * USB Host Controller Configuration Register
110 + */
111 +struct tmio_uhccr {
112 +       u8 x00[8];
113 +       u8      revid;  /* 0x08 Revision ID                             */
114 +       u8 x01[7];
115 +       u16     basel;  /* 0x10 USB Control Register Base Address Low   */
116 +       u16     baseh;  /* 0x12 USB Control Register Base Address High  */
117 +       u8 x02[0x2c];
118 +       u8      ilme;   /* 0x40 Internal Local Memory Enable            */
119 +       u8 x03[0x0b];
120 +       u16     pm;     /* 0x4c Power Management                        */
121 +       u8 x04[2];
122 +       u8      intc;   /* 0x50 INT Control                             */
123 +       u8 x05[3];
124 +       u16     lmw1l;  /* 0x54 Local Memory Window 1 LMADRS Low        */
125 +       u16     lmw1h;  /* 0x56 Local Memory Window 1 LMADRS High       */
126 +       u16     lmw1bl; /* 0x58 Local Memory Window 1 Base Address Low  */
127 +       u16     lmw1bh; /* 0x5A Local Memory Window 1 Base Address High */
128 +       u16     lmw2l;  /* 0x5C Local Memory Window 2 LMADRS Low        */
129 +       u16     lmw2h;  /* 0x5E Local Memory Window 2 LMADRS High       */
130 +       u16     lmw2bl; /* 0x60 Local Memory Window 2 Base Address Low  */
131 +       u16     lmw2bh; /* 0x62 Local Memory Window 2 Base Address High */
132 +       u8 x06[0x98];
133 +       u8      misc;   /* 0xFC MISC                                    */
134 +       u8 x07[3];
135 +} __attribute__((packed));
136 +
137 +#define UHCCR_PM_GKEN      0x0001
138 +#define UHCCR_PM_CKRNEN    0x0002
139 +#define UHCCR_PM_USBPW1    0x0004
140 +#define UHCCR_PM_USBPW2    0x0008
141 +#define UHCCR_PM_PMEE      0x0100
142 +#define UHCCR_PM_PMES      0x8000
143 +
144 +/*-------------------------------------------------------------------------*/
145 +
146 +struct tmio_hcd {
147 +       struct tmio_uhccr __iomem *ccr;
148 +};
149 +
150 +#define hcd_to_tmio(hcd)       ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1))
151 +#define ohci_to_tmio(ohci)     ((struct tmio_hcd *)(ohci + 1))
152 +
153 +/*-------------------------------------------------------------------------*/
154 +
155 +static void tmio_stop_hc(struct platform_device *dev)
156 +{
157 +       struct mfd_cell                 *cell   = mfd_get_cell(dev);
158 +       struct usb_hcd                  *hcd    = platform_get_drvdata(dev);
159 +       struct tmio_hcd                 *tmio   = hcd_to_tmio(hcd);
160 +       struct tmio_uhccr __iomem       *ccr    = tmio->ccr;
161 +       u16                             pm;
162 +
163 +       pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN | UHCCR_PM_USBPW1 | UHCCR_PM_USBPW2;
164 +       iowrite8(0,             &ccr->intc);
165 +       iowrite8(0,             &ccr->ilme);
166 +       iowrite16(0,            &ccr->basel);
167 +       iowrite16(0,            &ccr->baseh);
168 +       iowrite16(pm,   &ccr->pm);
169 +
170 +       cell->disable(dev);
171 +}
172 +
173 +static void tmio_start_hc(struct platform_device *dev)
174 +{
175 +       struct mfd_cell                 *cell   = mfd_get_cell(dev);
176 +       struct usb_hcd                  *hcd    = platform_get_drvdata(dev);
177 +       struct tmio_hcd                 *tmio   = hcd_to_tmio(hcd);
178 +       struct tmio_uhccr __iomem       *ccr    = tmio->ccr;
179 +       u16                             pm;
180 +       unsigned long                   base    = hcd->rsrc_start;
181 +
182 +       pm = UHCCR_PM_CKRNEN | UHCCR_PM_GKEN | UHCCR_PM_PMEE | UHCCR_PM_PMES;
183 +       cell->enable(dev);
184 +
185 +       iowrite16(pm,   &ccr->pm);
186 +       iowrite16(base,         &ccr->basel);
187 +       iowrite16(base >> 16,   &ccr->baseh);
188 +       iowrite8(1,             &ccr->ilme);
189 +       iowrite8(2,             &ccr->intc);
190 +
191 +       dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n",
192 +                       ioread8(&ccr->revid), hcd->rsrc_start, hcd->irq);
193 +}
194 +
195 +static int usb_hcd_tmio_probe(const struct hc_driver *driver,
196 +               struct platform_device *dev)
197 +{
198 +       struct resource         *config = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONFIG);
199 +       struct resource         *regs   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONTROL);
200 +       struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
201 +       int                     irq     = platform_get_irq(dev, 0);
202 +       struct tmio_hcd         *tmio;
203 +       struct ohci_hcd         *ohci;
204 +       struct usb_hcd          *hcd;
205 +       int                     retval;
206 +
207 +       if (usb_disabled())
208 +               return -ENODEV;
209 +
210 +       hcd = usb_create_hcd(driver, &dev->dev, dev->dev.bus_id);
211 +       if (!hcd) {
212 +               retval = -ENOMEM;
213 +               goto err_usb_create_hcd;
214 +       }
215 +
216 +       hcd->rsrc_start = regs->start;
217 +       hcd->rsrc_len   = regs->end - regs->start + 1;
218 +
219 +       tmio            = hcd_to_tmio(hcd);
220 +
221 +       tmio->ccr = ioremap(config->start, config->end - config->start + 1);
222 +       if (!tmio->ccr) {
223 +               retval = -ENOMEM;
224 +               goto err_ioremap_ccr;
225 +       }
226 +
227 +       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
228 +       if (!hcd->regs) {
229 +               retval = -ENOMEM;
230 +               goto err_ioremap_regs;
231 +       }
232 +
233 +       if (dma_declare_coherent_memory(&dev->dev, sram->start,
234 +                               sram->start,
235 +                               sram->end - sram->start + 1,
236 +                               DMA_MEMORY_MAP) != DMA_MEMORY_MAP) {
237 +               retval = -EBUSY;
238 +               goto err_dma_declare;
239 +       }
240 +
241 +       retval = dmabounce_register_dev(&dev->dev, 512, 4096);
242 +       if (retval)
243 +               goto err_dmabounce_register_dev;
244 +
245 +       tmio_start_hc(dev);
246 +       ohci = hcd_to_ohci(hcd);
247 +       ohci_hcd_init(ohci);
248 +
249 +       retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
250 +
251 +       if (retval == 0)
252 +               return retval;
253 +
254 +       tmio_stop_hc(dev);
255 +
256 +       dmabounce_unregister_dev(&dev->dev);
257 +err_dmabounce_register_dev:
258 +       dma_release_declared_memory(&dev->dev);
259 +err_dma_declare:
260 +       iounmap(hcd->regs);
261 +err_ioremap_regs:
262 +       iounmap(tmio->ccr);
263 +err_ioremap_ccr:
264 +       usb_put_hcd(hcd);
265 +err_usb_create_hcd:
266 +
267 +       return retval;
268 +}
269 +
270 +static void usb_hcd_tmio_remove(struct usb_hcd *hcd, struct platform_device *dev)
271 +{
272 +       struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
273 +
274 +       usb_remove_hcd(hcd);
275 +       tmio_stop_hc(dev);
276 +       dmabounce_unregister_dev(&dev->dev);
277 +       dma_release_declared_memory(&dev->dev);
278 +       iounmap(hcd->regs);
279 +       iounmap(tmio->ccr);
280 +       usb_put_hcd(hcd);
281 +}
282 +
283 +static int __devinit
284 +ohci_tmio_start(struct usb_hcd *hcd)
285 +{
286 +       struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
287 +       int                     retval;
288 +
289 +       if ((retval = ohci_init(ohci)) < 0)
290 +               return retval;
291 +
292 +       if ((retval = ohci_run(ohci)) < 0) {
293 +               err("can't start %s", hcd->self.bus_name);
294 +               ohci_stop(hcd);
295 +               return retval;
296 +       }
297 +
298 +       return 0;
299 +}
300 +
301 +static const struct hc_driver ohci_tmio_hc_driver = {
302 +       .description =          hcd_name,
303 +       .product_desc =         "TMIO OHCI USB Host Controller",
304 +       .hcd_priv_size =        sizeof(struct ohci_hcd) + sizeof (struct tmio_hcd),
305 +
306 +       /* generic hardware linkage */
307 +       .irq =                  ohci_irq,
308 +       .flags =                HCD_USB11 | HCD_MEMORY,
309 +
310 +       /* basic lifecycle operations */
311 +       .start =                ohci_tmio_start,
312 +       .stop =                 ohci_stop,
313 +       .shutdown =             ohci_shutdown,
314 +
315 +       /* managing i/o requests and associated device resources */
316 +       .urb_enqueue =          ohci_urb_enqueue,
317 +       .urb_dequeue =          ohci_urb_dequeue,
318 +       .endpoint_disable =     ohci_endpoint_disable,
319 +
320 +       /* scheduling support */
321 +       .get_frame_number =     ohci_get_frame,
322 +
323 +       /* root hub support */
324 +       .hub_status_data =      ohci_hub_status_data,
325 +       .hub_control =          ohci_hub_control,
326 +       .hub_irq_enable =       ohci_rhsc_enable,
327 +#ifdef CONFIG_PM
328 +       .bus_suspend =          ohci_bus_suspend,
329 +       .bus_resume =           ohci_bus_resume,
330 +#endif
331 +       .start_port_reset =     ohci_start_port_reset,
332 +};
333 +
334 +/*-------------------------------------------------------------------------*/
335 +static struct platform_driver ohci_hcd_tmio_driver;
336 +
337 +static int
338 +tmio_dmabounce_check(struct device *dev, dma_addr_t dma, size_t size, void *data)
339 +{
340 +       struct resource         *sram   = data;
341 +#ifdef DEBUG
342 +       printk(KERN_ERR "tmio_dmabounce_check: %08x %d\n", dma, size);
343 +#endif
344 +
345 +       if (dev->driver != &ohci_hcd_tmio_driver.driver)
346 +               return 0;
347 +
348 +       if (sram->start <= dma && dma + size <= sram->end)
349 +               return 0;
350 +
351 +       return 1;
352 +}
353 +
354 +static u64 dma_mask = DMA_32BIT_MASK;
355 +
356 +static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
357 +{
358 +       struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
359 +
360 +       dev->dev.dma_mask = &dma_mask;
361 +       dev->dev.coherent_dma_mask = DMA_32BIT_MASK;
362 +
363 +       dmabounce_register_checker(tmio_dmabounce_check, sram);
364 +
365 +       return usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
366 +}
367 +
368 +static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
369 +{
370 +       struct usb_hcd          *hcd    = platform_get_drvdata(dev);
371 +       struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
372 +
373 +       usb_hcd_tmio_remove(hcd, dev);
374 +
375 +       platform_set_drvdata(dev, NULL);
376 +
377 +       dmabounce_remove_checker(tmio_dmabounce_check, sram);
378 +
379 +       return 0;
380 +}
381 +
382 +#ifdef CONFIG_PM
383 +static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
384 +{
385 +       struct usb_hcd          *hcd    = platform_get_drvdata(dev);
386 +       struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
387 +
388 +       if (time_before(jiffies, ohci->next_statechange))
389 +               msleep(5);
390 +       ohci->next_statechange = jiffies;
391 +
392 +       tmio_stop_hc(dev);
393 +       hcd->state = HC_STATE_SUSPENDED;
394 +       dev->dev.power.power_state = PMSG_SUSPEND;
395 +
396 +       return 0;
397 +}
398 +
399 +static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
400 +{
401 +       struct usb_hcd          *hcd    = platform_get_drvdata(dev);
402 +       struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
403 +
404 +       if (time_before(jiffies, ohci->next_statechange))
405 +               msleep(5);
406 +       ohci->next_statechange = jiffies;
407 +
408 +       tmio_start_hc(dev);
409 +
410 +       dev->dev.power.power_state = PMSG_ON;
411 +       usb_hcd_resume_root_hub(hcd);
412 +
413 +       return 0;
414 +}
415 +#endif
416 +
417 +static struct platform_driver ohci_hcd_tmio_driver = {
418 +       .probe          = ohci_hcd_tmio_drv_probe,
419 +       .remove         = ohci_hcd_tmio_drv_remove,
420 +       .shutdown       = usb_hcd_platform_shutdown,
421 +#ifdef CONFIG_PM
422 +       .suspend        = ohci_hcd_tmio_drv_suspend,
423 +       .resume         = ohci_hcd_tmio_drv_resume,
424 +#endif
425 +       .driver         = {
426 +               .name   = "tmio-ohci",
427 +       },
428 +};
429 -- 
430 1.5.3.8
431