]>
Commit | Line | Data |
---|---|---|
38517a78 | 1 | /* |
be5e4bdc | 2 | * drivers/usb/gadget/dwc2_udc_otg.c |
e179cedd | 3 | * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers |
38517a78 ŁM |
4 | * |
5 | * Copyright (C) 2008 for Samsung Electronics | |
6 | * | |
7 | * BSP Support for Samsung's UDC driver | |
8 | * available at: | |
9 | * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git | |
10 | * | |
11 | * State machine bugfixes: | |
12 | * Marek Szyprowski <m.szyprowski@samsung.com> | |
13 | * | |
14 | * Ported to u-boot: | |
15 | * Marek Szyprowski <m.szyprowski@samsung.com> | |
16 | * Lukasz Majewski <l.majewski@samsumg.com> | |
17 | * | |
1a459660 | 18 | * SPDX-License-Identifier: GPL-2.0+ |
38517a78 | 19 | */ |
6734b6b2 | 20 | #undef DEBUG |
38517a78 ŁM |
21 | #include <common.h> |
22 | #include <asm/errno.h> | |
23 | #include <linux/list.h> | |
24 | #include <malloc.h> | |
25 | ||
26 | #include <linux/usb/ch9.h> | |
27 | #include <linux/usb/gadget.h> | |
28 | ||
29 | #include <asm/byteorder.h> | |
b2fb47f1 | 30 | #include <asm/unaligned.h> |
38517a78 ŁM |
31 | #include <asm/io.h> |
32 | ||
33 | #include <asm/mach-types.h> | |
38517a78 | 34 | |
f4d9bd06 MV |
35 | #include "dwc2_udc_otg_regs.h" |
36 | #include "dwc2_udc_otg_priv.h" | |
38517a78 ŁM |
37 | #include <usb/lin_gadget_compat.h> |
38 | ||
39 | /***********************************************************/ | |
40 | ||
41 | #define OTG_DMA_MODE 1 | |
42 | ||
f3b05ca5 ŁM |
43 | #define DEBUG_SETUP 0 |
44 | #define DEBUG_EP0 0 | |
45 | #define DEBUG_ISR 0 | |
46 | #define DEBUG_OUT_EP 0 | |
47 | #define DEBUG_IN_EP 0 | |
38517a78 | 48 | |
5d5716ee | 49 | #include <usb/dwc2_udc.h> |
38517a78 ŁM |
50 | |
51 | #define EP0_CON 0 | |
52 | #define EP_MASK 0xF | |
53 | ||
38517a78 ŁM |
54 | static char *state_names[] = { |
55 | "WAIT_FOR_SETUP", | |
56 | "DATA_STATE_XMIT", | |
57 | "DATA_STATE_NEED_ZLP", | |
58 | "WAIT_FOR_OUT_STATUS", | |
59 | "DATA_STATE_RECV", | |
60 | "WAIT_FOR_COMPLETE", | |
61 | "WAIT_FOR_OUT_COMPLETE", | |
62 | "WAIT_FOR_IN_COMPLETE", | |
63 | "WAIT_FOR_NULL_COMPLETE", | |
64 | }; | |
38517a78 | 65 | |
06cb6ccd | 66 | #define DRIVER_DESC "DWC2 HS USB OTG Device Driver, (c) Samsung Electronics" |
38517a78 ŁM |
67 | #define DRIVER_VERSION "15 March 2009" |
68 | ||
b4d5cf0b | 69 | struct dwc2_udc *the_controller; |
38517a78 | 70 | |
06cb6ccd | 71 | static const char driver_name[] = "dwc2-udc"; |
38517a78 ŁM |
72 | static const char driver_desc[] = DRIVER_DESC; |
73 | static const char ep0name[] = "ep0-control"; | |
74 | ||
75 | /* Max packet size*/ | |
76 | static unsigned int ep0_fifo_size = 64; | |
77 | static unsigned int ep_fifo_size = 512; | |
78 | static unsigned int ep_fifo_size2 = 1024; | |
79 | static int reset_available = 1; | |
80 | ||
81 | static struct usb_ctrlrequest *usb_ctrl; | |
82 | static dma_addr_t usb_ctrl_dma_addr; | |
83 | ||
84 | /* | |
85 | Local declarations. | |
86 | */ | |
ae1f2f0c | 87 | static int dwc2_ep_enable(struct usb_ep *ep, |
38517a78 | 88 | const struct usb_endpoint_descriptor *); |
ae1f2f0c | 89 | static int dwc2_ep_disable(struct usb_ep *ep); |
155e740f | 90 | static struct usb_request *dwc2_alloc_request(struct usb_ep *ep, |
38517a78 | 91 | gfp_t gfp_flags); |
155e740f | 92 | static void dwc2_free_request(struct usb_ep *ep, struct usb_request *); |
38517a78 | 93 | |
155e740f MV |
94 | static int dwc2_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags); |
95 | static int dwc2_dequeue(struct usb_ep *ep, struct usb_request *); | |
96 | static int dwc2_fifo_status(struct usb_ep *ep); | |
97 | static void dwc2_fifo_flush(struct usb_ep *ep); | |
28b97748 MV |
98 | static void dwc2_ep0_read(struct dwc2_udc *dev); |
99 | static void dwc2_ep0_kick(struct dwc2_udc *dev, struct dwc2_ep *ep); | |
155e740f | 100 | static void dwc2_handle_ep0(struct dwc2_udc *dev); |
28b97748 | 101 | static int dwc2_ep0_write(struct dwc2_udc *dev); |
c056c52b MV |
102 | static int write_fifo_ep0(struct dwc2_ep *ep, struct dwc2_request *req); |
103 | static void done(struct dwc2_ep *ep, struct dwc2_request *req, int status); | |
b4d5cf0b | 104 | static void stop_activity(struct dwc2_udc *dev, |
38517a78 | 105 | struct usb_gadget_driver *driver); |
b4d5cf0b MV |
106 | static int udc_enable(struct dwc2_udc *dev); |
107 | static void udc_set_address(struct dwc2_udc *dev, unsigned char address); | |
108 | static void reconfig_usbd(struct dwc2_udc *dev); | |
109 | static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed); | |
627d9298 | 110 | static void nuke(struct dwc2_ep *ep, int status); |
f52dd802 MV |
111 | static int dwc2_udc_set_halt(struct usb_ep *_ep, int value); |
112 | static void dwc2_udc_set_nak(struct dwc2_ep *ep); | |
38517a78 | 113 | |
6734b6b2 ŁM |
114 | void set_udc_gadget_private_data(void *p) |
115 | { | |
116 | debug_cond(DEBUG_SETUP != 0, | |
117 | "%s: the_controller: 0x%p, p: 0x%p\n", __func__, | |
118 | the_controller, p); | |
119 | the_controller->gadget.dev.device_data = p; | |
120 | } | |
121 | ||
122 | void *get_udc_gadget_private_data(struct usb_gadget *gadget) | |
123 | { | |
124 | return gadget->dev.device_data; | |
125 | } | |
126 | ||
ae1f2f0c MV |
127 | static struct usb_ep_ops dwc2_ep_ops = { |
128 | .enable = dwc2_ep_enable, | |
129 | .disable = dwc2_ep_disable, | |
38517a78 | 130 | |
155e740f MV |
131 | .alloc_request = dwc2_alloc_request, |
132 | .free_request = dwc2_free_request, | |
38517a78 | 133 | |
155e740f MV |
134 | .queue = dwc2_queue, |
135 | .dequeue = dwc2_dequeue, | |
38517a78 | 136 | |
f52dd802 | 137 | .set_halt = dwc2_udc_set_halt, |
155e740f MV |
138 | .fifo_status = dwc2_fifo_status, |
139 | .fifo_flush = dwc2_fifo_flush, | |
38517a78 ŁM |
140 | }; |
141 | ||
142 | #define create_proc_files() do {} while (0) | |
143 | #define remove_proc_files() do {} while (0) | |
144 | ||
145 | /***********************************************************/ | |
146 | ||
147 | void __iomem *regs_otg; | |
01472813 | 148 | struct dwc2_usbotg_reg *reg; |
38517a78 | 149 | |
f2ec4e34 ŁM |
150 | bool dfu_usb_get_reset(void) |
151 | { | |
152 | return !!(readl(®->gintsts) & INT_RESET); | |
153 | } | |
154 | ||
b4d5cf0b MV |
155 | __weak void otg_phy_init(struct dwc2_udc *dev) {} |
156 | __weak void otg_phy_off(struct dwc2_udc *dev) {} | |
38517a78 ŁM |
157 | |
158 | /***********************************************************/ | |
159 | ||
be5e4bdc | 160 | #include "dwc2_udc_otg_xfer_dma.c" |
38517a78 ŁM |
161 | |
162 | /* | |
163 | * udc_disable - disable USB device controller | |
164 | */ | |
b4d5cf0b | 165 | static void udc_disable(struct dwc2_udc *dev) |
38517a78 | 166 | { |
f3b05ca5 | 167 | debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); |
38517a78 ŁM |
168 | |
169 | udc_set_address(dev, 0); | |
170 | ||
171 | dev->ep0state = WAIT_FOR_SETUP; | |
172 | dev->gadget.speed = USB_SPEED_UNKNOWN; | |
173 | dev->usb_address = 0; | |
174 | ||
175 | otg_phy_off(dev); | |
176 | } | |
177 | ||
178 | /* | |
179 | * udc_reinit - initialize software state | |
180 | */ | |
b4d5cf0b | 181 | static void udc_reinit(struct dwc2_udc *dev) |
38517a78 ŁM |
182 | { |
183 | unsigned int i; | |
184 | ||
f3b05ca5 | 185 | debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); |
38517a78 ŁM |
186 | |
187 | /* device/ep0 records init */ | |
188 | INIT_LIST_HEAD(&dev->gadget.ep_list); | |
189 | INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); | |
190 | dev->ep0state = WAIT_FOR_SETUP; | |
191 | ||
192 | /* basic endpoint records init */ | |
507e677b | 193 | for (i = 0; i < DWC2_MAX_ENDPOINTS; i++) { |
627d9298 | 194 | struct dwc2_ep *ep = &dev->ep[i]; |
38517a78 ŁM |
195 | |
196 | if (i != 0) | |
197 | list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); | |
198 | ||
199 | ep->desc = 0; | |
200 | ep->stopped = 0; | |
201 | INIT_LIST_HEAD(&ep->queue); | |
202 | ep->pio_irqs = 0; | |
203 | } | |
204 | ||
205 | /* the rest was statically initialized, and is read-only */ | |
206 | } | |
207 | ||
208 | #define BYTES2MAXP(x) (x / 8) | |
209 | #define MAXP2BYTES(x) (x * 8) | |
210 | ||
211 | /* until it's enabled, this UDC should be completely invisible | |
212 | * to any USB host. | |
213 | */ | |
b4d5cf0b | 214 | static int udc_enable(struct dwc2_udc *dev) |
38517a78 | 215 | { |
f3b05ca5 | 216 | debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); |
38517a78 ŁM |
217 | |
218 | otg_phy_init(dev); | |
481a11c5 | 219 | reconfig_usbd(dev); |
38517a78 | 220 | |
f3b05ca5 | 221 | debug_cond(DEBUG_SETUP != 0, |
06cb6ccd | 222 | "DWC2 USB 2.0 OTG Controller Core Initialized : 0x%x\n", |
38517a78 ŁM |
223 | readl(®->gintmsk)); |
224 | ||
225 | dev->gadget.speed = USB_SPEED_UNKNOWN; | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | /* | |
231 | Register entry point for the peripheral controller driver. | |
232 | */ | |
233 | int usb_gadget_register_driver(struct usb_gadget_driver *driver) | |
234 | { | |
b4d5cf0b | 235 | struct dwc2_udc *dev = the_controller; |
38517a78 | 236 | int retval = 0; |
06fa91cd | 237 | unsigned long flags = 0; |
38517a78 | 238 | |
f3b05ca5 | 239 | debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name"); |
38517a78 ŁM |
240 | |
241 | if (!driver | |
242 | || (driver->speed != USB_SPEED_FULL | |
243 | && driver->speed != USB_SPEED_HIGH) | |
244 | || !driver->bind || !driver->disconnect || !driver->setup) | |
245 | return -EINVAL; | |
246 | if (!dev) | |
247 | return -ENODEV; | |
248 | if (dev->driver) | |
249 | return -EBUSY; | |
250 | ||
251 | spin_lock_irqsave(&dev->lock, flags); | |
252 | /* first hook up the driver ... */ | |
253 | dev->driver = driver; | |
254 | spin_unlock_irqrestore(&dev->lock, flags); | |
255 | ||
256 | if (retval) { /* TODO */ | |
257 | printf("target device_add failed, error %d\n", retval); | |
258 | return retval; | |
259 | } | |
260 | ||
261 | retval = driver->bind(&dev->gadget); | |
262 | if (retval) { | |
f3b05ca5 ŁM |
263 | debug_cond(DEBUG_SETUP != 0, |
264 | "%s: bind to driver --> error %d\n", | |
38517a78 ŁM |
265 | dev->gadget.name, retval); |
266 | dev->driver = 0; | |
267 | return retval; | |
268 | } | |
269 | ||
270 | enable_irq(IRQ_OTG); | |
271 | ||
f3b05ca5 ŁM |
272 | debug_cond(DEBUG_SETUP != 0, |
273 | "Registered gadget driver %s\n", dev->gadget.name); | |
38517a78 ŁM |
274 | udc_enable(dev); |
275 | ||
276 | return 0; | |
277 | } | |
278 | ||
279 | /* | |
280 | * Unregister entry point for the peripheral controller driver. | |
281 | */ | |
282 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) | |
283 | { | |
b4d5cf0b | 284 | struct dwc2_udc *dev = the_controller; |
06fa91cd | 285 | unsigned long flags = 0; |
38517a78 ŁM |
286 | |
287 | if (!dev) | |
288 | return -ENODEV; | |
289 | if (!driver || driver != dev->driver) | |
290 | return -EINVAL; | |
291 | ||
292 | spin_lock_irqsave(&dev->lock, flags); | |
293 | dev->driver = 0; | |
294 | stop_activity(dev, driver); | |
295 | spin_unlock_irqrestore(&dev->lock, flags); | |
296 | ||
297 | driver->unbind(&dev->gadget); | |
298 | ||
299 | disable_irq(IRQ_OTG); | |
300 | ||
301 | udc_disable(dev); | |
302 | return 0; | |
303 | } | |
304 | ||
305 | /* | |
306 | * done - retire a request; caller blocked irqs | |
307 | */ | |
c056c52b | 308 | static void done(struct dwc2_ep *ep, struct dwc2_request *req, int status) |
38517a78 ŁM |
309 | { |
310 | unsigned int stopped = ep->stopped; | |
311 | ||
ea2d9159 | 312 | debug("%s: %s %p, req = %p, stopped = %d\n", |
38517a78 ŁM |
313 | __func__, ep->ep.name, ep, &req->req, stopped); |
314 | ||
315 | list_del_init(&req->queue); | |
316 | ||
317 | if (likely(req->req.status == -EINPROGRESS)) | |
318 | req->req.status = status; | |
319 | else | |
320 | status = req->req.status; | |
321 | ||
322 | if (status && status != -ESHUTDOWN) { | |
ea2d9159 | 323 | debug("complete %s req %p stat %d len %u/%u\n", |
38517a78 ŁM |
324 | ep->ep.name, &req->req, status, |
325 | req->req.actual, req->req.length); | |
326 | } | |
327 | ||
328 | /* don't modify queue heads during completion callback */ | |
329 | ep->stopped = 1; | |
330 | ||
f3b05ca5 | 331 | #ifdef DEBUG |
38517a78 ŁM |
332 | printf("calling complete callback\n"); |
333 | { | |
334 | int i, len = req->req.length; | |
335 | ||
336 | printf("pkt[%d] = ", req->req.length); | |
337 | if (len > 64) | |
338 | len = 64; | |
339 | for (i = 0; i < len; i++) { | |
340 | printf("%02x", ((u8 *)req->req.buf)[i]); | |
341 | if ((i & 7) == 7) | |
342 | printf(" "); | |
343 | } | |
344 | printf("\n"); | |
345 | } | |
346 | #endif | |
347 | spin_unlock(&ep->dev->lock); | |
348 | req->req.complete(&ep->ep, &req->req); | |
349 | spin_lock(&ep->dev->lock); | |
350 | ||
ea2d9159 | 351 | debug("callback completed\n"); |
38517a78 ŁM |
352 | |
353 | ep->stopped = stopped; | |
354 | } | |
355 | ||
356 | /* | |
357 | * nuke - dequeue ALL requests | |
358 | */ | |
627d9298 | 359 | static void nuke(struct dwc2_ep *ep, int status) |
38517a78 | 360 | { |
c056c52b | 361 | struct dwc2_request *req; |
38517a78 | 362 | |
ea2d9159 | 363 | debug("%s: %s %p\n", __func__, ep->ep.name, ep); |
38517a78 ŁM |
364 | |
365 | /* called with irqs blocked */ | |
366 | while (!list_empty(&ep->queue)) { | |
c056c52b | 367 | req = list_entry(ep->queue.next, struct dwc2_request, queue); |
38517a78 ŁM |
368 | done(ep, req, status); |
369 | } | |
370 | } | |
371 | ||
b4d5cf0b | 372 | static void stop_activity(struct dwc2_udc *dev, |
38517a78 ŁM |
373 | struct usb_gadget_driver *driver) |
374 | { | |
375 | int i; | |
376 | ||
377 | /* don't disconnect drivers more than once */ | |
378 | if (dev->gadget.speed == USB_SPEED_UNKNOWN) | |
379 | driver = 0; | |
380 | dev->gadget.speed = USB_SPEED_UNKNOWN; | |
381 | ||
382 | /* prevent new request submissions, kill any outstanding requests */ | |
507e677b | 383 | for (i = 0; i < DWC2_MAX_ENDPOINTS; i++) { |
627d9298 | 384 | struct dwc2_ep *ep = &dev->ep[i]; |
38517a78 ŁM |
385 | ep->stopped = 1; |
386 | nuke(ep, -ESHUTDOWN); | |
387 | } | |
388 | ||
389 | /* report disconnect; the driver is already quiesced */ | |
390 | if (driver) { | |
391 | spin_unlock(&dev->lock); | |
392 | driver->disconnect(&dev->gadget); | |
393 | spin_lock(&dev->lock); | |
394 | } | |
395 | ||
396 | /* re-init driver-visible data structures */ | |
397 | udc_reinit(dev); | |
398 | } | |
399 | ||
b4d5cf0b | 400 | static void reconfig_usbd(struct dwc2_udc *dev) |
38517a78 ŁM |
401 | { |
402 | /* 2. Soft-reset OTG Core and then unreset again. */ | |
403 | int i; | |
404 | unsigned int uTemp = writel(CORE_SOFT_RESET, ®->grstctl); | |
481a11c5 | 405 | uint32_t dflt_gusbcfg; |
38517a78 | 406 | |
ea2d9159 | 407 | debug("Reseting OTG controller\n"); |
38517a78 | 408 | |
481a11c5 MV |
409 | dflt_gusbcfg = |
410 | 0<<15 /* PHY Low Power Clock sel*/ | |
38517a78 ŁM |
411 | |1<<14 /* Non-Periodic TxFIFO Rewind Enable*/ |
412 | |0x5<<10 /* Turnaround time*/ | |
413 | |0<<9 | 0<<8 /* [0:HNP disable,1:HNP enable][ 0:SRP disable*/ | |
414 | /* 1:SRP enable] H1= 1,1*/ | |
415 | |0<<7 /* Ulpi DDR sel*/ | |
416 | |0<<6 /* 0: high speed utmi+, 1: full speed serial*/ | |
417 | |0<<4 /* 0: utmi+, 1:ulpi*/ | |
f221db0e SR |
418 | #ifdef CONFIG_USB_GADGET_DWC2_OTG_PHY_BUS_WIDTH_8 |
419 | |0<<3 /* phy i/f 0:8bit, 1:16bit*/ | |
420 | #else | |
38517a78 | 421 | |1<<3 /* phy i/f 0:8bit, 1:16bit*/ |
f221db0e | 422 | #endif |
481a11c5 MV |
423 | |0x7<<0; /* HS/FS Timeout**/ |
424 | ||
425 | if (dev->pdata->usb_gusbcfg) | |
426 | dflt_gusbcfg = dev->pdata->usb_gusbcfg; | |
427 | ||
428 | writel(dflt_gusbcfg, ®->gusbcfg); | |
38517a78 ŁM |
429 | |
430 | /* 3. Put the OTG device core in the disconnected state.*/ | |
431 | uTemp = readl(®->dctl); | |
432 | uTemp |= SOFT_DISCONNECT; | |
433 | writel(uTemp, ®->dctl); | |
434 | ||
435 | udelay(20); | |
436 | ||
437 | /* 4. Make the OTG device core exit from the disconnected state.*/ | |
438 | uTemp = readl(®->dctl); | |
439 | uTemp = uTemp & ~SOFT_DISCONNECT; | |
440 | writel(uTemp, ®->dctl); | |
441 | ||
442 | /* 5. Configure OTG Core to initial settings of device mode.*/ | |
443 | /* [][1: full speed(30Mhz) 0:high speed]*/ | |
444 | writel(EP_MISS_CNT(1) | DEV_SPEED_HIGH_SPEED_20, ®->dcfg); | |
445 | ||
446 | mdelay(1); | |
447 | ||
448 | /* 6. Unmask the core interrupts*/ | |
449 | writel(GINTMSK_INIT, ®->gintmsk); | |
450 | ||
451 | /* 7. Set NAK bit of EP0, EP1, EP2*/ | |
452 | writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[EP0_CON].doepctl); | |
453 | writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[EP0_CON].diepctl); | |
454 | ||
507e677b | 455 | for (i = 1; i < DWC2_MAX_ENDPOINTS; i++) { |
38517a78 ŁM |
456 | writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[i].doepctl); |
457 | writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[i].diepctl); | |
458 | } | |
459 | ||
460 | /* 8. Unmask EPO interrupts*/ | |
461 | writel(((1 << EP0_CON) << DAINT_OUT_BIT) | |
462 | | (1 << EP0_CON), ®->daintmsk); | |
463 | ||
464 | /* 9. Unmask device OUT EP common interrupts*/ | |
465 | writel(DOEPMSK_INIT, ®->doepmsk); | |
466 | ||
467 | /* 10. Unmask device IN EP common interrupts*/ | |
468 | writel(DIEPMSK_INIT, ®->diepmsk); | |
469 | ||
470 | /* 11. Set Rx FIFO Size (in 32-bit words) */ | |
471 | writel(RX_FIFO_SIZE >> 2, ®->grxfsiz); | |
472 | ||
473 | /* 12. Set Non Periodic Tx FIFO Size */ | |
474 | writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0, | |
475 | ®->gnptxfsiz); | |
476 | ||
507e677b | 477 | for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++) |
38517a78 ŁM |
478 | writel((PTX_FIFO_SIZE >> 2) << 16 | |
479 | ((RX_FIFO_SIZE + NPTX_FIFO_SIZE + | |
480 | PTX_FIFO_SIZE*(i-1)) >> 2) << 0, | |
481 | ®->dieptxf[i-1]); | |
482 | ||
483 | /* Flush the RX FIFO */ | |
484 | writel(RX_FIFO_FLUSH, ®->grstctl); | |
485 | while (readl(®->grstctl) & RX_FIFO_FLUSH) | |
507e677b | 486 | debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__); |
38517a78 ŁM |
487 | |
488 | /* Flush all the Tx FIFO's */ | |
489 | writel(TX_FIFO_FLUSH_ALL, ®->grstctl); | |
490 | writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, ®->grstctl); | |
491 | while (readl(®->grstctl) & TX_FIFO_FLUSH) | |
507e677b | 492 | debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__); |
38517a78 ŁM |
493 | |
494 | /* 13. Clear NAK bit of EP0, EP1, EP2*/ | |
495 | /* For Slave mode*/ | |
496 | /* EP0: Control OUT */ | |
497 | writel(DEPCTL_EPDIS | DEPCTL_CNAK, | |
498 | ®->out_endp[EP0_CON].doepctl); | |
499 | ||
500 | /* 14. Initialize OTG Link Core.*/ | |
501 | writel(GAHBCFG_INIT, ®->gahbcfg); | |
502 | } | |
503 | ||
b4d5cf0b | 504 | static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed) |
38517a78 ŁM |
505 | { |
506 | unsigned int ep_ctrl; | |
507 | int i; | |
508 | ||
509 | if (speed == USB_SPEED_HIGH) { | |
510 | ep0_fifo_size = 64; | |
511 | ep_fifo_size = 512; | |
512 | ep_fifo_size2 = 1024; | |
513 | dev->gadget.speed = USB_SPEED_HIGH; | |
514 | } else { | |
515 | ep0_fifo_size = 64; | |
516 | ep_fifo_size = 64; | |
517 | ep_fifo_size2 = 64; | |
518 | dev->gadget.speed = USB_SPEED_FULL; | |
519 | } | |
520 | ||
521 | dev->ep[0].ep.maxpacket = ep0_fifo_size; | |
507e677b | 522 | for (i = 1; i < DWC2_MAX_ENDPOINTS; i++) |
38517a78 ŁM |
523 | dev->ep[i].ep.maxpacket = ep_fifo_size; |
524 | ||
525 | /* EP0 - Control IN (64 bytes)*/ | |
526 | ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); | |
527 | writel(ep_ctrl|(0<<0), ®->in_endp[EP0_CON].diepctl); | |
528 | ||
529 | /* EP0 - Control OUT (64 bytes)*/ | |
530 | ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); | |
531 | writel(ep_ctrl|(0<<0), ®->out_endp[EP0_CON].doepctl); | |
532 | } | |
533 | ||
ae1f2f0c | 534 | static int dwc2_ep_enable(struct usb_ep *_ep, |
38517a78 ŁM |
535 | const struct usb_endpoint_descriptor *desc) |
536 | { | |
627d9298 | 537 | struct dwc2_ep *ep; |
b4d5cf0b | 538 | struct dwc2_udc *dev; |
06fa91cd | 539 | unsigned long flags = 0; |
38517a78 | 540 | |
ea2d9159 | 541 | debug("%s: %p\n", __func__, _ep); |
38517a78 | 542 | |
627d9298 | 543 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 ŁM |
544 | if (!_ep || !desc || ep->desc || _ep->name == ep0name |
545 | || desc->bDescriptorType != USB_DT_ENDPOINT | |
546 | || ep->bEndpointAddress != desc->bEndpointAddress | |
b2fb47f1 TR |
547 | || ep_maxpacket(ep) < |
548 | le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))) { | |
38517a78 | 549 | |
ea2d9159 | 550 | debug("%s: bad ep or descriptor\n", __func__); |
38517a78 ŁM |
551 | return -EINVAL; |
552 | } | |
553 | ||
554 | /* xfer types must match, except that interrupt ~= bulk */ | |
555 | if (ep->bmAttributes != desc->bmAttributes | |
556 | && ep->bmAttributes != USB_ENDPOINT_XFER_BULK | |
557 | && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { | |
558 | ||
ea2d9159 | 559 | debug("%s: %s type mismatch\n", __func__, _ep->name); |
38517a78 ŁM |
560 | return -EINVAL; |
561 | } | |
562 | ||
563 | /* hardware _could_ do smaller, but driver doesn't */ | |
8c9b4d55 FW |
564 | if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK && |
565 | le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)) > | |
b2fb47f1 | 566 | ep_maxpacket(ep)) || !get_unaligned(&desc->wMaxPacketSize)) { |
38517a78 | 567 | |
ea2d9159 | 568 | debug("%s: bad %s maxpacket\n", __func__, _ep->name); |
38517a78 ŁM |
569 | return -ERANGE; |
570 | } | |
571 | ||
572 | dev = ep->dev; | |
573 | if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { | |
574 | ||
ea2d9159 | 575 | debug("%s: bogus device state\n", __func__); |
38517a78 ŁM |
576 | return -ESHUTDOWN; |
577 | } | |
578 | ||
579 | ep->stopped = 0; | |
580 | ep->desc = desc; | |
581 | ep->pio_irqs = 0; | |
b2fb47f1 | 582 | ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); |
38517a78 ŁM |
583 | |
584 | /* Reset halt state */ | |
f52dd802 MV |
585 | dwc2_udc_set_nak(ep); |
586 | dwc2_udc_set_halt(_ep, 0); | |
38517a78 ŁM |
587 | |
588 | spin_lock_irqsave(&ep->dev->lock, flags); | |
f52dd802 | 589 | dwc2_udc_ep_activate(ep); |
38517a78 ŁM |
590 | spin_unlock_irqrestore(&ep->dev->lock, flags); |
591 | ||
ea2d9159 | 592 | debug("%s: enabled %s, stopped = %d, maxpacket = %d\n", |
38517a78 ŁM |
593 | __func__, _ep->name, ep->stopped, ep->ep.maxpacket); |
594 | return 0; | |
595 | } | |
596 | ||
597 | /* | |
598 | * Disable EP | |
599 | */ | |
ae1f2f0c | 600 | static int dwc2_ep_disable(struct usb_ep *_ep) |
38517a78 | 601 | { |
627d9298 | 602 | struct dwc2_ep *ep; |
06fa91cd | 603 | unsigned long flags = 0; |
38517a78 | 604 | |
ea2d9159 | 605 | debug("%s: %p\n", __func__, _ep); |
38517a78 | 606 | |
627d9298 | 607 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 | 608 | if (!_ep || !ep->desc) { |
ea2d9159 | 609 | debug("%s: %s not enabled\n", __func__, |
38517a78 ŁM |
610 | _ep ? ep->ep.name : NULL); |
611 | return -EINVAL; | |
612 | } | |
613 | ||
614 | spin_lock_irqsave(&ep->dev->lock, flags); | |
615 | ||
616 | /* Nuke all pending requests */ | |
617 | nuke(ep, -ESHUTDOWN); | |
618 | ||
619 | ep->desc = 0; | |
620 | ep->stopped = 1; | |
621 | ||
622 | spin_unlock_irqrestore(&ep->dev->lock, flags); | |
623 | ||
ea2d9159 | 624 | debug("%s: disabled %s\n", __func__, _ep->name); |
38517a78 ŁM |
625 | return 0; |
626 | } | |
627 | ||
155e740f | 628 | static struct usb_request *dwc2_alloc_request(struct usb_ep *ep, |
38517a78 ŁM |
629 | gfp_t gfp_flags) |
630 | { | |
c056c52b | 631 | struct dwc2_request *req; |
38517a78 | 632 | |
ea2d9159 | 633 | debug("%s: %s %p\n", __func__, ep->name, ep); |
38517a78 | 634 | |
6777a3cf | 635 | req = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*req)); |
38517a78 ŁM |
636 | if (!req) |
637 | return 0; | |
638 | ||
639 | memset(req, 0, sizeof *req); | |
640 | INIT_LIST_HEAD(&req->queue); | |
641 | ||
642 | return &req->req; | |
643 | } | |
644 | ||
155e740f | 645 | static void dwc2_free_request(struct usb_ep *ep, struct usb_request *_req) |
38517a78 | 646 | { |
c056c52b | 647 | struct dwc2_request *req; |
38517a78 | 648 | |
ea2d9159 | 649 | debug("%s: %p\n", __func__, ep); |
38517a78 | 650 | |
c056c52b | 651 | req = container_of(_req, struct dwc2_request, req); |
38517a78 ŁM |
652 | WARN_ON(!list_empty(&req->queue)); |
653 | kfree(req); | |
654 | } | |
655 | ||
656 | /* dequeue JUST ONE request */ | |
155e740f | 657 | static int dwc2_dequeue(struct usb_ep *_ep, struct usb_request *_req) |
38517a78 | 658 | { |
627d9298 | 659 | struct dwc2_ep *ep; |
c056c52b | 660 | struct dwc2_request *req; |
06fa91cd | 661 | unsigned long flags = 0; |
38517a78 | 662 | |
ea2d9159 | 663 | debug("%s: %p\n", __func__, _ep); |
38517a78 | 664 | |
627d9298 | 665 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 ŁM |
666 | if (!_ep || ep->ep.name == ep0name) |
667 | return -EINVAL; | |
668 | ||
669 | spin_lock_irqsave(&ep->dev->lock, flags); | |
670 | ||
671 | /* make sure it's actually queued on this endpoint */ | |
672 | list_for_each_entry(req, &ep->queue, queue) { | |
673 | if (&req->req == _req) | |
674 | break; | |
675 | } | |
676 | if (&req->req != _req) { | |
677 | spin_unlock_irqrestore(&ep->dev->lock, flags); | |
678 | return -EINVAL; | |
679 | } | |
680 | ||
681 | done(ep, req, -ECONNRESET); | |
682 | ||
683 | spin_unlock_irqrestore(&ep->dev->lock, flags); | |
684 | return 0; | |
685 | } | |
686 | ||
687 | /* | |
688 | * Return bytes in EP FIFO | |
689 | */ | |
155e740f | 690 | static int dwc2_fifo_status(struct usb_ep *_ep) |
38517a78 ŁM |
691 | { |
692 | int count = 0; | |
627d9298 | 693 | struct dwc2_ep *ep; |
38517a78 | 694 | |
627d9298 | 695 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 | 696 | if (!_ep) { |
ea2d9159 | 697 | debug("%s: bad ep\n", __func__); |
38517a78 ŁM |
698 | return -ENODEV; |
699 | } | |
700 | ||
ea2d9159 | 701 | debug("%s: %d\n", __func__, ep_index(ep)); |
38517a78 ŁM |
702 | |
703 | /* LPD can't report unclaimed bytes from IN fifos */ | |
704 | if (ep_is_in(ep)) | |
705 | return -EOPNOTSUPP; | |
706 | ||
707 | return count; | |
708 | } | |
709 | ||
710 | /* | |
711 | * Flush EP FIFO | |
712 | */ | |
155e740f | 713 | static void dwc2_fifo_flush(struct usb_ep *_ep) |
38517a78 | 714 | { |
627d9298 | 715 | struct dwc2_ep *ep; |
38517a78 | 716 | |
627d9298 | 717 | ep = container_of(_ep, struct dwc2_ep, ep); |
38517a78 | 718 | if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { |
ea2d9159 | 719 | debug("%s: bad ep\n", __func__); |
38517a78 ŁM |
720 | return; |
721 | } | |
722 | ||
ea2d9159 | 723 | debug("%s: %d\n", __func__, ep_index(ep)); |
38517a78 ŁM |
724 | } |
725 | ||
f52dd802 | 726 | static const struct usb_gadget_ops dwc2_udc_ops = { |
38517a78 ŁM |
727 | /* current versions must always be self-powered */ |
728 | }; | |
729 | ||
b4d5cf0b | 730 | static struct dwc2_udc memory = { |
38517a78 ŁM |
731 | .usb_address = 0, |
732 | .gadget = { | |
f52dd802 | 733 | .ops = &dwc2_udc_ops, |
38517a78 ŁM |
734 | .ep0 = &memory.ep[0].ep, |
735 | .name = driver_name, | |
736 | }, | |
737 | ||
738 | /* control endpoint */ | |
739 | .ep[0] = { | |
740 | .ep = { | |
741 | .name = ep0name, | |
ae1f2f0c | 742 | .ops = &dwc2_ep_ops, |
38517a78 ŁM |
743 | .maxpacket = EP0_FIFO_SIZE, |
744 | }, | |
745 | .dev = &memory, | |
746 | ||
747 | .bEndpointAddress = 0, | |
748 | .bmAttributes = 0, | |
749 | ||
750 | .ep_type = ep_control, | |
751 | }, | |
752 | ||
753 | /* first group of endpoints */ | |
754 | .ep[1] = { | |
755 | .ep = { | |
756 | .name = "ep1in-bulk", | |
ae1f2f0c | 757 | .ops = &dwc2_ep_ops, |
38517a78 ŁM |
758 | .maxpacket = EP_FIFO_SIZE, |
759 | }, | |
760 | .dev = &memory, | |
761 | ||
762 | .bEndpointAddress = USB_DIR_IN | 1, | |
763 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
764 | ||
765 | .ep_type = ep_bulk_out, | |
766 | .fifo_num = 1, | |
767 | }, | |
768 | ||
769 | .ep[2] = { | |
770 | .ep = { | |
771 | .name = "ep2out-bulk", | |
ae1f2f0c | 772 | .ops = &dwc2_ep_ops, |
38517a78 ŁM |
773 | .maxpacket = EP_FIFO_SIZE, |
774 | }, | |
775 | .dev = &memory, | |
776 | ||
777 | .bEndpointAddress = USB_DIR_OUT | 2, | |
778 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
779 | ||
780 | .ep_type = ep_bulk_in, | |
781 | .fifo_num = 2, | |
782 | }, | |
783 | ||
784 | .ep[3] = { | |
785 | .ep = { | |
786 | .name = "ep3in-int", | |
ae1f2f0c | 787 | .ops = &dwc2_ep_ops, |
38517a78 ŁM |
788 | .maxpacket = EP_FIFO_SIZE, |
789 | }, | |
790 | .dev = &memory, | |
791 | ||
792 | .bEndpointAddress = USB_DIR_IN | 3, | |
793 | .bmAttributes = USB_ENDPOINT_XFER_INT, | |
794 | ||
795 | .ep_type = ep_interrupt, | |
796 | .fifo_num = 3, | |
797 | }, | |
798 | }; | |
799 | ||
800 | /* | |
801 | * probe - binds to the platform device | |
802 | */ | |
803 | ||
a4bb9b36 | 804 | int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata) |
38517a78 | 805 | { |
b4d5cf0b | 806 | struct dwc2_udc *dev = &memory; |
e0059eae | 807 | int retval = 0; |
38517a78 | 808 | |
ea2d9159 | 809 | debug("%s: %p\n", __func__, pdata); |
38517a78 ŁM |
810 | |
811 | dev->pdata = pdata; | |
812 | ||
01472813 | 813 | reg = (struct dwc2_usbotg_reg *)pdata->regs_otg; |
38517a78 ŁM |
814 | |
815 | /* regs_otg = (void *)pdata->regs_otg; */ | |
816 | ||
817 | dev->gadget.is_dualspeed = 1; /* Hack only*/ | |
818 | dev->gadget.is_otg = 0; | |
819 | dev->gadget.is_a_peripheral = 0; | |
820 | dev->gadget.b_hnp_enable = 0; | |
821 | dev->gadget.a_hnp_support = 0; | |
822 | dev->gadget.a_alt_hnp_support = 0; | |
823 | ||
824 | the_controller = dev; | |
825 | ||
e0059eae ŁM |
826 | usb_ctrl = memalign(CONFIG_SYS_CACHELINE_SIZE, |
827 | ROUND(sizeof(struct usb_ctrlrequest), | |
828 | CONFIG_SYS_CACHELINE_SIZE)); | |
829 | if (!usb_ctrl) { | |
830 | error("No memory available for UDC!\n"); | |
831 | return -ENOMEM; | |
38517a78 | 832 | } |
e0059eae ŁM |
833 | |
834 | usb_ctrl_dma_addr = (dma_addr_t) usb_ctrl; | |
38517a78 ŁM |
835 | |
836 | udc_reinit(dev); | |
837 | ||
838 | return retval; | |
839 | } | |
840 | ||
2d48aa69 | 841 | int usb_gadget_handle_interrupts(int index) |
38517a78 ŁM |
842 | { |
843 | u32 intr_status = readl(®->gintsts); | |
844 | u32 gintmsk = readl(®->gintmsk); | |
845 | ||
846 | if (intr_status & gintmsk) | |
f52dd802 | 847 | return dwc2_udc_irq(1, (void *)the_controller); |
38517a78 ŁM |
848 | return 0; |
849 | } |