aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2011-08-19 11:10:58 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-22 19:03:11 -0400
commit72246da40f3719af3bfd104a2365b32537c27d83 (patch)
treedb6a4b139c24340e0d5dccab8d9df0b23ab509ef /drivers/usb/dwc3/core.c
parent500fdf8becb9c8d51970c7ac6a4fa308a5481ebe (diff)
usb: Introduce DesignWare USB3 DRD Driver
The DesignWare USB3 is a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. Several other parameters can be configured like amount of FIFO space, amount of TX and RX endpoints, amount of Host Interrupters, etc. The current driver has been validated with a virtual model of version 1.73a of that core and with an FPGA burned with version 1.83a of the DRD core. We have support for PCIe bus, which is used on FPGA prototyping, and for the OMAP5, more adaptation (or glue) layers can be easily added and the driver is half prepared to handle any possible configuration the HW engineer has chosen considering we have the information on one of the GHWPARAMS registers to do runtime checking of certain features. More runtime checks can, and should, be added in order to make this driver even more flexible with regards to number of endpoints, FIFO sizes, transfer types, etc. While this supports only the device side, for now, we will add support for Host side (xHCI - see the updated series Sebastian has sent [1]) and OTG after we have it all stabilized. [1] http://marc.info/?l=linux-usb&m=131341992020339&w=2 Signed-off-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r--drivers/usb/dwc3/core.c467
1 files changed, 467 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
new file mode 100644
index 000000000000..443e4fb9b8f3
--- /dev/null
+++ b/drivers/usb/dwc3/core.c
@@ -0,0 +1,467 @@
1/**
2 * core.c - DesignWare USB3 DRD Controller Core file
3 *
4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
5 * All rights reserved.
6 *
7 * Authors: Felipe Balbi <balbi@ti.com>,
8 * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions, and the following disclaimer,
15 * without modification.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the above-listed copyright holders may not be used
20 * to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * ALTERNATIVELY, this software may be distributed under the terms of the
24 * GNU General Public License ("GPL") version 2, as published by the Free
25 * Software Foundation.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
28 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
29 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#include <linux/kernel.h>
41#include <linux/slab.h>
42#include <linux/spinlock.h>
43#include <linux/platform_device.h>
44#include <linux/pm_runtime.h>
45#include <linux/interrupt.h>
46#include <linux/ioport.h>
47#include <linux/io.h>
48#include <linux/list.h>
49#include <linux/delay.h>
50#include <linux/dma-mapping.h>
51
52#include <linux/usb/ch9.h>
53#include <linux/usb/gadget.h>
54
55#include "core.h"
56#include "gadget.h"
57#include "io.h"
58
59#include "debug.h"
60
61/**
62 * dwc3_core_soft_reset - Issues core soft reset and PHY reset
63 * @dwc: pointer to our context structure
64 */
65static void dwc3_core_soft_reset(struct dwc3 *dwc)
66{
67 u32 reg;
68
69 /* Before Resetting PHY, put Core in Reset */
70 reg = dwc3_readl(dwc->regs, DWC3_GCTL);
71 reg |= DWC3_GCTL_CORESOFTRESET;
72 dwc3_writel(dwc->regs, DWC3_GCTL, reg);
73
74 /* Assert USB3 PHY reset */
75 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
76 reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
77 dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
78
79 /* Assert USB2 PHY reset */
80 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
81 reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
82 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
83
84 mdelay(100);
85
86 /* Clear USB3 PHY reset */
87 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
88 reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
89 dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
90
91 /* Clear USB2 PHY reset */
92 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
93 reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
94 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
95
96 /* After PHYs are stable we can take Core out of reset state */
97 reg = dwc3_readl(dwc->regs, DWC3_GCTL);
98 reg &= ~DWC3_GCTL_CORESOFTRESET;
99 dwc3_writel(dwc->regs, DWC3_GCTL, reg);
100}
101
102/**
103 * dwc3_free_one_event_buffer - Frees one event buffer
104 * @dwc: Pointer to our controller context structure
105 * @evt: Pointer to event buffer to be freed
106 */
107static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
108 struct dwc3_event_buffer *evt)
109{
110 dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
111 kfree(evt);
112}
113
114/**
115 * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
116 * @dwc: Pointer to our controller context structure
117 * @length: size of the event buffer
118 *
119 * Returns a pointer to the allocated event buffer structure on succes
120 * otherwise ERR_PTR(errno).
121 */
122static struct dwc3_event_buffer *__devinit
123dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
124{
125 struct dwc3_event_buffer *evt;
126
127 evt = kzalloc(sizeof(*evt), GFP_KERNEL);
128 if (!evt)
129 return ERR_PTR(-ENOMEM);
130
131 evt->dwc = dwc;
132 evt->length = length;
133 evt->buf = dma_alloc_coherent(dwc->dev, length,
134 &evt->dma, GFP_KERNEL);
135 if (!evt->buf) {
136 kfree(evt);
137 return ERR_PTR(-ENOMEM);
138 }
139
140 return evt;
141}
142
143/**
144 * dwc3_free_event_buffers - frees all allocated event buffers
145 * @dwc: Pointer to our controller context structure
146 */
147static void dwc3_free_event_buffers(struct dwc3 *dwc)
148{
149 struct dwc3_event_buffer *evt;
150 int i;
151
152 for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
153 evt = dwc->ev_buffs[i];
154 if (evt) {
155 dwc3_free_one_event_buffer(dwc, evt);
156 dwc->ev_buffs[i] = NULL;
157 }
158 }
159}
160
161/**
162 * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
163 * @dwc: Pointer to out controller context structure
164 * @num: number of event buffers to allocate
165 * @length: size of event buffer
166 *
167 * Returns 0 on success otherwise negative errno. In error the case, dwc
168 * may contain some buffers allocated but not all which were requested.
169 */
170static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
171 unsigned length)
172{
173 int i;
174
175 for (i = 0; i < num; i++) {
176 struct dwc3_event_buffer *evt;
177
178 evt = dwc3_alloc_one_event_buffer(dwc, length);
179 if (IS_ERR(evt)) {
180 dev_err(dwc->dev, "can't allocate event buffer\n");
181 return PTR_ERR(evt);
182 }
183 dwc->ev_buffs[i] = evt;
184 }
185
186 return 0;
187}
188
189/**
190 * dwc3_event_buffers_setup - setup our allocated event buffers
191 * @dwc: Pointer to out controller context structure
192 *
193 * Returns 0 on success otherwise negative errno.
194 */
195static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
196{
197 struct dwc3_event_buffer *evt;
198 int n;
199
200 for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
201 evt = dwc->ev_buffs[n];
202 dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
203 evt->buf, (unsigned long long) evt->dma,
204 evt->length);
205
206 dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
207 lower_32_bits(evt->dma));
208 dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
209 upper_32_bits(evt->dma));
210 dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
211 evt->length & 0xffff);
212 dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
213 }
214
215 return 0;
216}
217
218static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
219{
220 struct dwc3_event_buffer *evt;
221 int n;
222
223 for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
224 evt = dwc->ev_buffs[n];
225 dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
226 dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
227 dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
228 dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
229 }
230}
231
232/**
233 * dwc3_core_init - Low-level initialization of DWC3 Core
234 * @dwc: Pointer to our controller context structure
235 *
236 * Returns 0 on success otherwise negative errno.
237 */
238static int __devinit dwc3_core_init(struct dwc3 *dwc)
239{
240 unsigned long timeout;
241 u32 reg;
242 int ret;
243
244 dwc3_core_soft_reset(dwc);
245
246 /* issue device SoftReset too */
247 timeout = jiffies + msecs_to_jiffies(500);
248 dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
249 do {
250 reg = dwc3_readl(dwc->regs, DWC3_DCTL);
251 if (!(reg & DWC3_DCTL_CSFTRST))
252 break;
253
254 if (time_after(jiffies, timeout)) {
255 dev_err(dwc->dev, "Reset Timed Out\n");
256 ret = -ETIMEDOUT;
257 goto err0;
258 }
259
260 cpu_relax();
261 } while (true);
262
263 reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
264 /* This should read as U3 followed by revision number */
265 if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
266 dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
267 ret = -ENODEV;
268 goto err0;
269 }
270
271 dwc->revision = reg & DWC3_GSNPSREV_MASK;
272
273 ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
274 DWC3_EVENT_BUFFERS_SIZE);
275 if (ret) {
276 dev_err(dwc->dev, "failed to allocate event buffers\n");
277 ret = -ENOMEM;
278 goto err1;
279 }
280
281 ret = dwc3_event_buffers_setup(dwc);
282 if (ret) {
283 dev_err(dwc->dev, "failed to setup event buffers\n");
284 goto err1;
285 }
286
287 return 0;
288
289err1:
290 dwc3_free_event_buffers(dwc);
291
292err0:
293 return ret;
294}
295
296static void dwc3_core_exit(struct dwc3 *dwc)
297{
298 dwc3_event_buffers_cleanup(dwc);
299 dwc3_free_event_buffers(dwc);
300}
301
302#define DWC3_ALIGN_MASK (16 - 1)
303
304static int __devinit dwc3_probe(struct platform_device *pdev)
305{
306 const struct platform_device_id *id = platform_get_device_id(pdev);
307 struct resource *res;
308 struct dwc3 *dwc;
309 void __iomem *regs;
310 unsigned int features = id->driver_data;
311 int ret = -ENOMEM;
312 int irq;
313 void *mem;
314
315 mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
316 if (!mem) {
317 dev_err(&pdev->dev, "not enough memory\n");
318 goto err0;
319 }
320 dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
321 dwc->mem = mem;
322
323 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
324 if (!res) {
325 dev_err(&pdev->dev, "missing resource\n");
326 goto err1;
327 }
328
329 res = request_mem_region(res->start, resource_size(res),
330 dev_name(&pdev->dev));
331 if (!res) {
332 dev_err(&pdev->dev, "can't request mem region\n");
333 goto err1;
334 }
335
336 regs = ioremap(res->start, resource_size(res));
337 if (!regs) {
338 dev_err(&pdev->dev, "ioremap failed\n");
339 goto err2;
340 }
341
342 irq = platform_get_irq(pdev, 0);
343 if (irq < 0) {
344 dev_err(&pdev->dev, "missing IRQ\n");
345 goto err3;
346 }
347
348 spin_lock_init(&dwc->lock);
349 platform_set_drvdata(pdev, dwc);
350
351 dwc->regs = regs;
352 dwc->regs_size = resource_size(res);
353 dwc->dev = &pdev->dev;
354 dwc->irq = irq;
355
356 pm_runtime_enable(&pdev->dev);
357 pm_runtime_get_sync(&pdev->dev);
358 pm_runtime_forbid(&pdev->dev);
359
360 ret = dwc3_core_init(dwc);
361 if (ret) {
362 dev_err(&pdev->dev, "failed to initialize core\n");
363 goto err3;
364 }
365
366 if (features & DWC3_HAS_PERIPHERAL) {
367 ret = dwc3_gadget_init(dwc);
368 if (ret) {
369 dev_err(&pdev->dev, "failed to initialized gadget\n");
370 goto err4;
371 }
372 }
373
374 ret = dwc3_debugfs_init(dwc);
375 if (ret) {
376 dev_err(&pdev->dev, "failed to initialize debugfs\n");
377 goto err5;
378 }
379
380 pm_runtime_allow(&pdev->dev);
381
382 return 0;
383
384err5:
385 if (features & DWC3_HAS_PERIPHERAL)
386 dwc3_gadget_exit(dwc);
387
388err4:
389 dwc3_core_exit(dwc);
390
391err3:
392 iounmap(regs);
393
394err2:
395 release_mem_region(res->start, resource_size(res));
396
397err1:
398 kfree(dwc->mem);
399
400err0:
401 return ret;
402}
403
404static int __devexit dwc3_remove(struct platform_device *pdev)
405{
406 const struct platform_device_id *id = platform_get_device_id(pdev);
407 struct dwc3 *dwc = platform_get_drvdata(pdev);
408 struct resource *res;
409 unsigned int features = id->driver_data;
410
411 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
412
413 pm_runtime_put(&pdev->dev);
414 pm_runtime_disable(&pdev->dev);
415
416 dwc3_debugfs_exit(dwc);
417
418 if (features & DWC3_HAS_PERIPHERAL)
419 dwc3_gadget_exit(dwc);
420
421 dwc3_core_exit(dwc);
422 release_mem_region(res->start, resource_size(res));
423 iounmap(dwc->regs);
424 kfree(dwc->mem);
425
426 return 0;
427}
428
429static const struct platform_device_id dwc3_id_table[] __devinitconst = {
430 {
431 .name = "dwc3-omap",
432 .driver_data = (DWC3_HAS_PERIPHERAL
433 | DWC3_HAS_XHCI
434 | DWC3_HAS_OTG),
435 },
436 {
437 .name = "dwc3-pci",
438 .driver_data = DWC3_HAS_PERIPHERAL,
439 },
440 { }, /* Terminating Entry */
441};
442MODULE_DEVICE_TABLE(platform, dwc3_id_table);
443
444static struct platform_driver dwc3_driver = {
445 .probe = dwc3_probe,
446 .remove = __devexit_p(dwc3_remove),
447 .driver = {
448 .name = "dwc3",
449 },
450 .id_table = dwc3_id_table,
451};
452
453MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
454MODULE_LICENSE("Dual BSD/GPL");
455MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
456
457static int __devinit dwc3_init(void)
458{
459 return platform_driver_register(&dwc3_driver);
460}
461module_init(dwc3_init);
462
463static void __exit dwc3_exit(void)
464{
465 platform_driver_unregister(&dwc3_driver);
466}
467module_exit(dwc3_exit);