]>
Commit | Line | Data |
---|---|---|
62db1c0d VK |
1 | /* |
2 | * Based on drivers/usb/gadget/omap1510_udc.c | |
3 | * TI OMAP1510 USB bus interface driver | |
4 | * | |
5 | * (C) Copyright 2009 | |
6 | * Vipin Kumar, ST Micoelectronics, [email protected]. | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
62db1c0d VK |
9 | */ |
10 | ||
11 | #include <common.h> | |
12 | #include <asm/io.h> | |
13 | ||
14 | #include <usbdevice.h> | |
15 | #include "ep0.h" | |
2721551a | 16 | #include <usb/designware_udc.h> |
449697f1 | 17 | #include <usb/udc.h> |
62db1c0d | 18 | #include <asm/arch/hardware.h> |
62db1c0d VK |
19 | |
20 | #define UDC_INIT_MDELAY 80 /* Device settle delay */ | |
21 | ||
22 | /* Some kind of debugging output... */ | |
2721551a | 23 | #ifndef DEBUG_DWUSBTTY |
62db1c0d VK |
24 | #define UDCDBG(str) |
25 | #define UDCDBGA(fmt, args...) | |
26 | #else | |
27 | #define UDCDBG(str) serial_printf(str "\n") | |
28 | #define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args) | |
29 | #endif | |
30 | ||
31 | static struct urb *ep0_urb; | |
32 | static struct usb_device_instance *udc_device; | |
33 | ||
34 | static struct plug_regs *const plug_regs_p = | |
35 | (struct plug_regs * const)CONFIG_SYS_PLUG_BASE; | |
36 | static struct udc_regs *const udc_regs_p = | |
37 | (struct udc_regs * const)CONFIG_SYS_USBD_BASE; | |
38 | static struct udc_endp_regs *const outep_regs_p = | |
39 | &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0]; | |
40 | static struct udc_endp_regs *const inep_regs_p = | |
41 | &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0]; | |
42 | ||
43 | /* | |
44 | * udc_state_transition - Write the next packet to TxFIFO. | |
45 | * @initial: Initial state. | |
46 | * @final: Final state. | |
47 | * | |
48 | * Helper function to implement device state changes. The device states and | |
49 | * the events that transition between them are: | |
50 | * | |
51 | * STATE_ATTACHED | |
52 | * || /\ | |
53 | * \/ || | |
54 | * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET | |
55 | * || /\ | |
56 | * \/ || | |
57 | * STATE_POWERED | |
58 | * || /\ | |
59 | * \/ || | |
60 | * DEVICE_RESET DEVICE_POWER_INTERRUPTION | |
61 | * || /\ | |
62 | * \/ || | |
63 | * STATE_DEFAULT | |
64 | * || /\ | |
65 | * \/ || | |
66 | * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET | |
67 | * || /\ | |
68 | * \/ || | |
69 | * STATE_ADDRESSED | |
70 | * || /\ | |
71 | * \/ || | |
72 | * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED | |
73 | * || /\ | |
74 | * \/ || | |
75 | * STATE_CONFIGURED | |
76 | * | |
77 | * udc_state_transition transitions up (in the direction from STATE_ATTACHED | |
78 | * to STATE_CONFIGURED) from the specified initial state to the specified final | |
79 | * state, passing through each intermediate state on the way. If the initial | |
80 | * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then | |
81 | * no state transitions will take place. | |
82 | * | |
83 | * udc_state_transition also transitions down (in the direction from | |
84 | * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the | |
85 | * specified final state, passing through each intermediate state on the way. | |
86 | * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final | |
87 | * state, then no state transitions will take place. | |
88 | * | |
89 | * This function must only be called with interrupts disabled. | |
90 | */ | |
91 | static void udc_state_transition(usb_device_state_t initial, | |
92 | usb_device_state_t final) | |
93 | { | |
94 | if (initial < final) { | |
95 | switch (initial) { | |
96 | case STATE_ATTACHED: | |
97 | usbd_device_event_irq(udc_device, | |
98 | DEVICE_HUB_CONFIGURED, 0); | |
99 | if (final == STATE_POWERED) | |
100 | break; | |
101 | case STATE_POWERED: | |
102 | usbd_device_event_irq(udc_device, DEVICE_RESET, 0); | |
103 | if (final == STATE_DEFAULT) | |
104 | break; | |
105 | case STATE_DEFAULT: | |
106 | usbd_device_event_irq(udc_device, | |
107 | DEVICE_ADDRESS_ASSIGNED, 0); | |
108 | if (final == STATE_ADDRESSED) | |
109 | break; | |
110 | case STATE_ADDRESSED: | |
111 | usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); | |
112 | case STATE_CONFIGURED: | |
113 | break; | |
114 | default: | |
115 | break; | |
116 | } | |
117 | } else if (initial > final) { | |
118 | switch (initial) { | |
119 | case STATE_CONFIGURED: | |
120 | usbd_device_event_irq(udc_device, | |
121 | DEVICE_DE_CONFIGURED, 0); | |
122 | if (final == STATE_ADDRESSED) | |
123 | break; | |
124 | case STATE_ADDRESSED: | |
125 | usbd_device_event_irq(udc_device, DEVICE_RESET, 0); | |
126 | if (final == STATE_DEFAULT) | |
127 | break; | |
128 | case STATE_DEFAULT: | |
129 | usbd_device_event_irq(udc_device, | |
130 | DEVICE_POWER_INTERRUPTION, 0); | |
131 | if (final == STATE_POWERED) | |
132 | break; | |
133 | case STATE_POWERED: | |
134 | usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); | |
135 | case STATE_ATTACHED: | |
136 | break; | |
137 | default: | |
138 | break; | |
139 | } | |
140 | } | |
141 | } | |
142 | ||
143 | /* Stall endpoint */ | |
144 | static void udc_stall_ep(u32 ep_num) | |
145 | { | |
146 | writel(readl(&inep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, | |
147 | &inep_regs_p[ep_num].endp_cntl); | |
148 | ||
149 | writel(readl(&outep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, | |
150 | &outep_regs_p[ep_num].endp_cntl); | |
151 | } | |
152 | ||
153 | static void *get_fifo(int ep_num, int in) | |
154 | { | |
155 | u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE; | |
156 | ||
157 | switch (ep_num) { | |
158 | case UDC_EP3: | |
159 | fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn); | |
160 | /* break intentionally left out */ | |
161 | ||
162 | case UDC_EP1: | |
163 | fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn); | |
164 | /* break intentionally left out */ | |
165 | ||
166 | case UDC_EP0: | |
167 | default: | |
168 | if (in) { | |
169 | fifo_ptr += | |
170 | readl(&outep_regs_p[2].endp_maxpacksize) >> 16; | |
171 | /* break intentionally left out */ | |
172 | } else { | |
173 | break; | |
174 | } | |
175 | ||
176 | case UDC_EP2: | |
177 | fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16; | |
178 | /* break intentionally left out */ | |
179 | } | |
180 | ||
181 | return (void *)fifo_ptr; | |
182 | } | |
183 | ||
184 | static int usbgetpckfromfifo(int epNum, u8 *bufp, u32 len) | |
185 | { | |
186 | u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0); | |
187 | u32 i, nw, nb; | |
188 | u32 *wrdp; | |
189 | u8 *bytp; | |
f50dcd60 | 190 | u32 tmp[128]; |
62db1c0d VK |
191 | |
192 | if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY) | |
193 | return -1; | |
194 | ||
195 | nw = len / sizeof(u32); | |
196 | nb = len % sizeof(u32); | |
197 | ||
f50dcd60 SH |
198 | /* use tmp buf if bufp is not word aligned */ |
199 | if ((int)bufp & 0x3) | |
200 | wrdp = (u32 *)&tmp[0]; | |
201 | else | |
202 | wrdp = (u32 *)bufp; | |
203 | ||
62db1c0d VK |
204 | for (i = 0; i < nw; i++) { |
205 | writel(readl(fifo_ptr), wrdp); | |
206 | wrdp++; | |
207 | } | |
208 | ||
209 | bytp = (u8 *)wrdp; | |
210 | for (i = 0; i < nb; i++) { | |
211 | writeb(readb(fifo_ptr), bytp); | |
212 | fifo_ptr++; | |
213 | bytp++; | |
214 | } | |
215 | readl(&outep_regs_p[epNum].write_done); | |
216 | ||
f50dcd60 SH |
217 | /* copy back tmp buffer to bufp if bufp is not word aligned */ |
218 | if ((int)bufp & 0x3) | |
219 | memcpy(bufp, tmp, len); | |
220 | ||
62db1c0d VK |
221 | return 0; |
222 | } | |
223 | ||
224 | static void usbputpcktofifo(int epNum, u8 *bufp, u32 len) | |
225 | { | |
226 | u32 i, nw, nb; | |
227 | u32 *wrdp; | |
228 | u8 *bytp; | |
229 | u8 *fifo_ptr = get_fifo(epNum, 1); | |
230 | ||
231 | nw = len / sizeof(int); | |
232 | nb = len % sizeof(int); | |
233 | wrdp = (u32 *)bufp; | |
234 | for (i = 0; i < nw; i++) { | |
235 | writel(*wrdp, fifo_ptr); | |
236 | wrdp++; | |
237 | } | |
238 | ||
239 | bytp = (u8 *)wrdp; | |
240 | for (i = 0; i < nb; i++) { | |
241 | writeb(*bytp, fifo_ptr); | |
242 | fifo_ptr++; | |
243 | bytp++; | |
244 | } | |
245 | } | |
246 | ||
247 | /* | |
2721551a | 248 | * dw_write_noniso_tx_fifo - Write the next packet to TxFIFO. |
62db1c0d VK |
249 | * @endpoint: Endpoint pointer. |
250 | * | |
251 | * If the endpoint has an active tx_urb, then the next packet of data from the | |
252 | * URB is written to the tx FIFO. The total amount of data in the urb is given | |
253 | * by urb->actual_length. The maximum amount of data that can be sent in any | |
254 | * one packet is given by endpoint->tx_packetSize. The number of data bytes | |
255 | * from this URB that have already been transmitted is given by endpoint->sent. | |
256 | * endpoint->last is updated by this routine with the number of data bytes | |
257 | * transmitted in this packet. | |
258 | * | |
259 | */ | |
2721551a | 260 | static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance |
62db1c0d VK |
261 | *endpoint) |
262 | { | |
263 | struct urb *urb = endpoint->tx_urb; | |
264 | int align; | |
265 | ||
266 | if (urb) { | |
267 | u32 last; | |
268 | ||
269 | UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d", | |
270 | urb->buffer, urb->buffer_length, urb->actual_length); | |
271 | ||
b4141195 MY |
272 | last = min_t(u32, urb->actual_length - endpoint->sent, |
273 | endpoint->tx_packetSize); | |
62db1c0d VK |
274 | |
275 | if (last) { | |
276 | u8 *cp = urb->buffer + endpoint->sent; | |
277 | ||
278 | /* | |
279 | * This ensures that USBD packet fifo is accessed | |
280 | * - through word aligned pointer or | |
281 | * - through non word aligned pointer but only | |
282 | * with a max length to make the next packet | |
283 | * word aligned | |
284 | */ | |
285 | ||
286 | align = ((ulong)cp % sizeof(int)); | |
287 | if (align) | |
c79cba37 | 288 | last = min(last, sizeof(int) - align); |
62db1c0d VK |
289 | |
290 | UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d", | |
291 | endpoint->sent, endpoint->tx_packetSize, last); | |
292 | ||
293 | usbputpcktofifo(endpoint->endpoint_address & | |
294 | USB_ENDPOINT_NUMBER_MASK, cp, last); | |
295 | } | |
296 | endpoint->last = last; | |
297 | } | |
298 | } | |
299 | ||
300 | /* | |
301 | * Handle SETUP USB interrupt. | |
302 | * This function implements TRM Figure 14-14. | |
303 | */ | |
2721551a | 304 | static void dw_udc_setup(struct usb_endpoint_instance *endpoint) |
62db1c0d VK |
305 | { |
306 | u8 *datap = (u8 *)&ep0_urb->device_request; | |
307 | int ep_addr = endpoint->endpoint_address; | |
308 | ||
309 | UDCDBG("-> Entering device setup"); | |
310 | usbgetpckfromfifo(ep_addr, datap, 8); | |
311 | ||
312 | /* Try to process setup packet */ | |
313 | if (ep0_recv_setup(ep0_urb)) { | |
314 | /* Not a setup packet, stall next EP0 transaction */ | |
315 | udc_stall_ep(0); | |
316 | UDCDBG("can't parse setup packet, still waiting for setup"); | |
317 | return; | |
318 | } | |
319 | ||
320 | /* Check direction */ | |
321 | if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) | |
322 | == USB_REQ_HOST2DEVICE) { | |
323 | UDCDBG("control write on EP0"); | |
324 | if (le16_to_cpu(ep0_urb->device_request.wLength)) { | |
325 | /* Stall this request */ | |
326 | UDCDBG("Stalling unsupported EP0 control write data " | |
327 | "stage."); | |
328 | udc_stall_ep(0); | |
329 | } | |
330 | } else { | |
331 | ||
332 | UDCDBG("control read on EP0"); | |
333 | /* | |
334 | * The ep0_recv_setup function has already placed our response | |
335 | * packet data in ep0_urb->buffer and the packet length in | |
336 | * ep0_urb->actual_length. | |
337 | */ | |
338 | endpoint->tx_urb = ep0_urb; | |
339 | endpoint->sent = 0; | |
340 | /* | |
2721551a | 341 | * Write packet data to the FIFO. dw_write_noniso_tx_fifo |
62db1c0d VK |
342 | * will update endpoint->last with the number of bytes written |
343 | * to the FIFO. | |
344 | */ | |
2721551a | 345 | dw_write_noniso_tx_fifo(endpoint); |
62db1c0d VK |
346 | |
347 | writel(0x0, &inep_regs_p[ep_addr].write_done); | |
348 | } | |
349 | ||
350 | udc_unset_nak(endpoint->endpoint_address); | |
351 | ||
352 | UDCDBG("<- Leaving device setup"); | |
353 | } | |
354 | ||
355 | /* | |
356 | * Handle endpoint 0 RX interrupt | |
357 | */ | |
2721551a | 358 | static void dw_udc_ep0_rx(struct usb_endpoint_instance *endpoint) |
62db1c0d VK |
359 | { |
360 | u8 dummy[64]; | |
361 | ||
362 | UDCDBG("RX on EP0"); | |
363 | ||
364 | /* Check direction */ | |
365 | if ((ep0_urb->device_request.bmRequestType | |
366 | & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { | |
367 | /* | |
368 | * This rx interrupt must be for a control write data | |
369 | * stage packet. | |
370 | * | |
371 | * We don't support control write data stages. | |
372 | * We should never end up here. | |
373 | */ | |
374 | ||
375 | UDCDBG("Stalling unexpected EP0 control write " | |
376 | "data stage packet"); | |
377 | udc_stall_ep(0); | |
378 | } else { | |
379 | /* | |
380 | * This rx interrupt must be for a control read status | |
381 | * stage packet. | |
382 | */ | |
383 | UDCDBG("ACK on EP0 control read status stage packet"); | |
384 | u32 len = (readl(&outep_regs_p[0].endp_status) >> 11) & 0xfff; | |
385 | usbgetpckfromfifo(0, dummy, len); | |
386 | } | |
387 | } | |
388 | ||
389 | /* | |
390 | * Handle endpoint 0 TX interrupt | |
391 | */ | |
2721551a | 392 | static void dw_udc_ep0_tx(struct usb_endpoint_instance *endpoint) |
62db1c0d VK |
393 | { |
394 | struct usb_device_request *request = &ep0_urb->device_request; | |
395 | int ep_addr; | |
396 | ||
397 | UDCDBG("TX on EP0"); | |
398 | ||
399 | /* Check direction */ | |
400 | if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) == | |
401 | USB_REQ_HOST2DEVICE) { | |
402 | /* | |
403 | * This tx interrupt must be for a control write status | |
404 | * stage packet. | |
405 | */ | |
406 | UDCDBG("ACK on EP0 control write status stage packet"); | |
407 | } else { | |
408 | /* | |
409 | * This tx interrupt must be for a control read data | |
410 | * stage packet. | |
411 | */ | |
412 | int wLength = le16_to_cpu(request->wLength); | |
413 | ||
414 | /* | |
415 | * Update our count of bytes sent so far in this | |
416 | * transfer. | |
417 | */ | |
418 | endpoint->sent += endpoint->last; | |
419 | ||
420 | /* | |
421 | * We are finished with this transfer if we have sent | |
422 | * all of the bytes in our tx urb (urb->actual_length) | |
423 | * unless we need a zero-length terminating packet. We | |
424 | * need a zero-length terminating packet if we returned | |
425 | * fewer bytes than were requested (wLength) by the host, | |
426 | * and the number of bytes we returned is an exact | |
427 | * multiple of the packet size endpoint->tx_packetSize. | |
428 | */ | |
429 | if ((endpoint->sent == ep0_urb->actual_length) && | |
430 | ((ep0_urb->actual_length == wLength) || | |
431 | (endpoint->last != endpoint->tx_packetSize))) { | |
432 | /* Done with control read data stage. */ | |
433 | UDCDBG("control read data stage complete"); | |
434 | } else { | |
435 | /* | |
436 | * We still have another packet of data to send | |
437 | * in this control read data stage or else we | |
438 | * need a zero-length terminating packet. | |
439 | */ | |
440 | UDCDBG("ACK control read data stage packet"); | |
2721551a | 441 | dw_write_noniso_tx_fifo(endpoint); |
62db1c0d VK |
442 | |
443 | ep_addr = endpoint->endpoint_address; | |
444 | writel(0x0, &inep_regs_p[ep_addr].write_done); | |
445 | } | |
446 | } | |
447 | } | |
448 | ||
2721551a | 449 | static struct usb_endpoint_instance *dw_find_ep(int ep) |
62db1c0d VK |
450 | { |
451 | int i; | |
452 | ||
453 | for (i = 0; i < udc_device->bus->max_endpoints; i++) { | |
454 | if ((udc_device->bus->endpoint_array[i].endpoint_address & | |
455 | USB_ENDPOINT_NUMBER_MASK) == ep) | |
456 | return &udc_device->bus->endpoint_array[i]; | |
457 | } | |
458 | return NULL; | |
459 | } | |
460 | ||
461 | /* | |
462 | * Handle RX transaction on non-ISO endpoint. | |
463 | * The ep argument is a physical endpoint number for a non-ISO IN endpoint | |
464 | * in the range 1 to 15. | |
465 | */ | |
2721551a | 466 | static void dw_udc_epn_rx(int ep) |
62db1c0d VK |
467 | { |
468 | int nbytes = 0; | |
469 | struct urb *urb; | |
2721551a | 470 | struct usb_endpoint_instance *endpoint = dw_find_ep(ep); |
62db1c0d VK |
471 | |
472 | if (endpoint) { | |
473 | urb = endpoint->rcv_urb; | |
474 | ||
475 | if (urb) { | |
476 | u8 *cp = urb->buffer + urb->actual_length; | |
477 | ||
478 | nbytes = (readl(&outep_regs_p[ep].endp_status) >> 11) & | |
479 | 0xfff; | |
480 | usbgetpckfromfifo(ep, cp, nbytes); | |
481 | usbd_rcv_complete(endpoint, nbytes, 0); | |
482 | } | |
483 | } | |
484 | } | |
485 | ||
486 | /* | |
487 | * Handle TX transaction on non-ISO endpoint. | |
488 | * The ep argument is a physical endpoint number for a non-ISO IN endpoint | |
489 | * in the range 16 to 30. | |
490 | */ | |
2721551a | 491 | static void dw_udc_epn_tx(int ep) |
62db1c0d | 492 | { |
2721551a | 493 | struct usb_endpoint_instance *endpoint = dw_find_ep(ep); |
62db1c0d | 494 | |
dc3e7739 VK |
495 | if (!endpoint) |
496 | return; | |
497 | ||
62db1c0d VK |
498 | /* |
499 | * We need to transmit a terminating zero-length packet now if | |
500 | * we have sent all of the data in this URB and the transfer | |
501 | * size was an exact multiple of the packet size. | |
502 | */ | |
dc3e7739 VK |
503 | if (endpoint->tx_urb && |
504 | (endpoint->last == endpoint->tx_packetSize) && | |
505 | (endpoint->tx_urb->actual_length - endpoint->sent - | |
506 | endpoint->last == 0)) { | |
507 | /* handle zero length packet here */ | |
508 | writel(0x0, &inep_regs_p[ep].write_done); | |
509 | ||
510 | } | |
511 | ||
512 | if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { | |
62db1c0d VK |
513 | /* retire the data that was just sent */ |
514 | usbd_tx_complete(endpoint); | |
515 | /* | |
516 | * Check to see if we have more data ready to transmit | |
517 | * now. | |
518 | */ | |
519 | if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { | |
520 | /* write data to FIFO */ | |
2721551a | 521 | dw_write_noniso_tx_fifo(endpoint); |
62db1c0d VK |
522 | writel(0x0, &inep_regs_p[ep].write_done); |
523 | ||
524 | } else if (endpoint->tx_urb | |
525 | && (endpoint->tx_urb->actual_length == 0)) { | |
526 | /* udc_set_nak(ep); */ | |
527 | } | |
528 | } | |
529 | } | |
530 | ||
531 | /* | |
532 | * Start of public functions. | |
533 | */ | |
534 | ||
535 | /* Called to start packet transmission. */ | |
536 | int udc_endpoint_write(struct usb_endpoint_instance *endpoint) | |
537 | { | |
538 | udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK); | |
539 | return 0; | |
540 | } | |
541 | ||
542 | /* Start to initialize h/w stuff */ | |
543 | int udc_init(void) | |
544 | { | |
545 | int i; | |
546 | u32 plug_st; | |
547 | ||
548 | udc_device = NULL; | |
549 | ||
550 | UDCDBG("starting"); | |
551 | ||
552 | readl(&plug_regs_p->plug_pending); | |
553 | ||
62db1c0d VK |
554 | for (i = 0; i < UDC_INIT_MDELAY; i++) |
555 | udelay(1000); | |
556 | ||
557 | plug_st = readl(&plug_regs_p->plug_state); | |
558 | writel(plug_st | PLUG_STATUS_EN, &plug_regs_p->plug_state); | |
559 | ||
560 | writel(~0x0, &udc_regs_p->endp_int); | |
561 | writel(~0x0, &udc_regs_p->dev_int_mask); | |
562 | writel(~0x0, &udc_regs_p->endp_int_mask); | |
563 | ||
23b0e694 | 564 | #ifndef CONFIG_USBD_HS |
62db1c0d | 565 | writel(DEV_CONF_FS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | |
62db1c0d | 566 | DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); |
23b0e694 VK |
567 | #else |
568 | writel(DEV_CONF_HS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | | |
569 | DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); | |
570 | #endif | |
62db1c0d | 571 | |
dc3e7739 | 572 | writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl); |
62db1c0d VK |
573 | |
574 | /* Clear all interrupts pending */ | |
575 | writel(DEV_INT_MSK, &udc_regs_p->dev_int); | |
576 | ||
577 | return 0; | |
578 | } | |
579 | ||
23b0e694 VK |
580 | int is_usbd_high_speed(void) |
581 | { | |
582 | return (readl(&udc_regs_p->dev_stat) & DEV_STAT_ENUM) ? 0 : 1; | |
583 | } | |
584 | ||
62db1c0d VK |
585 | /* |
586 | * udc_setup_ep - setup endpoint | |
587 | * Associate a physical endpoint with endpoint_instance | |
588 | */ | |
589 | void udc_setup_ep(struct usb_device_instance *device, | |
590 | u32 ep, struct usb_endpoint_instance *endpoint) | |
591 | { | |
592 | UDCDBGA("setting up endpoint addr %x", endpoint->endpoint_address); | |
593 | int ep_addr; | |
594 | int ep_num, ep_type; | |
595 | int packet_size; | |
596 | int buffer_size; | |
597 | int attributes; | |
598 | char *tt; | |
599 | u32 endp_intmask; | |
600 | ||
dc3e7739 VK |
601 | if ((ep != 0) && (udc_device->device_state < STATE_ADDRESSED)) |
602 | return; | |
603 | ||
00caae6d | 604 | tt = env_get("usbtty"); |
62db1c0d VK |
605 | if (!tt) |
606 | tt = "generic"; | |
607 | ||
608 | ep_addr = endpoint->endpoint_address; | |
609 | ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; | |
610 | ||
611 | if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { | |
612 | /* IN endpoint */ | |
613 | packet_size = endpoint->tx_packetSize; | |
614 | buffer_size = packet_size * 2; | |
615 | attributes = endpoint->tx_attributes; | |
616 | } else { | |
617 | /* OUT endpoint */ | |
618 | packet_size = endpoint->rcv_packetSize; | |
619 | buffer_size = packet_size * 2; | |
620 | attributes = endpoint->rcv_attributes; | |
621 | } | |
622 | ||
623 | switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { | |
624 | case USB_ENDPOINT_XFER_CONTROL: | |
625 | ep_type = ENDP_EPTYPE_CNTL; | |
626 | break; | |
627 | case USB_ENDPOINT_XFER_BULK: | |
628 | default: | |
629 | ep_type = ENDP_EPTYPE_BULK; | |
630 | break; | |
631 | case USB_ENDPOINT_XFER_INT: | |
632 | ep_type = ENDP_EPTYPE_INT; | |
633 | break; | |
634 | case USB_ENDPOINT_XFER_ISOC: | |
635 | ep_type = ENDP_EPTYPE_ISO; | |
636 | break; | |
637 | } | |
638 | ||
639 | struct udc_endp_regs *out_p = &outep_regs_p[ep_num]; | |
640 | struct udc_endp_regs *in_p = &inep_regs_p[ep_num]; | |
641 | ||
642 | if (!ep_addr) { | |
643 | /* Setup endpoint 0 */ | |
644 | buffer_size = packet_size; | |
645 | ||
646 | writel(readl(&in_p->endp_cntl) | ENDP_CNTL_CNAK, | |
647 | &in_p->endp_cntl); | |
648 | ||
649 | writel(readl(&out_p->endp_cntl) | ENDP_CNTL_CNAK, | |
650 | &out_p->endp_cntl); | |
651 | ||
652 | writel(ENDP_CNTL_CONTROL | ENDP_CNTL_FLUSH, &in_p->endp_cntl); | |
653 | ||
654 | writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); | |
655 | ||
656 | writel(packet_size, &in_p->endp_maxpacksize); | |
657 | ||
658 | writel(ENDP_CNTL_CONTROL | ENDP_CNTL_RRDY, &out_p->endp_cntl); | |
659 | ||
660 | writel(packet_size | ((buffer_size / sizeof(int)) << 16), | |
661 | &out_p->endp_maxpacksize); | |
662 | ||
62db1c0d VK |
663 | } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { |
664 | /* Setup the IN endpoint */ | |
665 | writel(0x0, &in_p->endp_status); | |
666 | writel((ep_type << 4) | ENDP_CNTL_RRDY, &in_p->endp_cntl); | |
667 | writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); | |
668 | writel(packet_size, &in_p->endp_maxpacksize); | |
669 | ||
670 | if (!strcmp(tt, "cdc_acm")) { | |
671 | if (ep_type == ENDP_EPTYPE_INT) { | |
672 | /* Conf no. 1 Interface no. 0 */ | |
673 | writel((packet_size << 19) | | |
674 | ENDP_EPDIR_IN | (1 << 7) | | |
675 | (0 << 11) | (ep_type << 5) | ep_num, | |
676 | &udc_regs_p->udc_endp_reg[ep_num]); | |
677 | } else { | |
678 | /* Conf no. 1 Interface no. 1 */ | |
679 | writel((packet_size << 19) | | |
680 | ENDP_EPDIR_IN | (1 << 7) | | |
681 | (1 << 11) | (ep_type << 5) | ep_num, | |
682 | &udc_regs_p->udc_endp_reg[ep_num]); | |
683 | } | |
684 | } else { | |
685 | /* Conf no. 1 Interface no. 0 */ | |
686 | writel((packet_size << 19) | | |
687 | ENDP_EPDIR_IN | (1 << 7) | | |
688 | (0 << 11) | (ep_type << 5) | ep_num, | |
689 | &udc_regs_p->udc_endp_reg[ep_num]); | |
690 | } | |
691 | ||
692 | } else { | |
693 | /* Setup the OUT endpoint */ | |
694 | writel(0x0, &out_p->endp_status); | |
695 | writel((ep_type << 4) | ENDP_CNTL_RRDY, &out_p->endp_cntl); | |
696 | writel(packet_size | ((buffer_size / sizeof(int)) << 16), | |
697 | &out_p->endp_maxpacksize); | |
698 | ||
699 | if (!strcmp(tt, "cdc_acm")) { | |
700 | writel((packet_size << 19) | | |
701 | ENDP_EPDIR_OUT | (1 << 7) | | |
702 | (1 << 11) | (ep_type << 5) | ep_num, | |
703 | &udc_regs_p->udc_endp_reg[ep_num]); | |
704 | } else { | |
705 | writel((packet_size << 19) | | |
706 | ENDP_EPDIR_OUT | (1 << 7) | | |
707 | (0 << 11) | (ep_type << 5) | ep_num, | |
708 | &udc_regs_p->udc_endp_reg[ep_num]); | |
709 | } | |
710 | ||
711 | } | |
712 | ||
713 | endp_intmask = readl(&udc_regs_p->endp_int_mask); | |
714 | endp_intmask &= ~((1 << ep_num) | 0x10000 << ep_num); | |
715 | writel(endp_intmask, &udc_regs_p->endp_int_mask); | |
716 | } | |
717 | ||
718 | /* Turn on the USB connection by enabling the pullup resistor */ | |
719 | void udc_connect(void) | |
720 | { | |
dc3e7739 VK |
721 | u32 plug_st, dev_cntl; |
722 | ||
723 | dev_cntl = readl(&udc_regs_p->dev_cntl); | |
724 | dev_cntl |= DEV_CNTL_SOFTDISCONNECT; | |
725 | writel(dev_cntl, &udc_regs_p->dev_cntl); | |
726 | ||
727 | udelay(1000); | |
728 | ||
729 | dev_cntl = readl(&udc_regs_p->dev_cntl); | |
730 | dev_cntl &= ~DEV_CNTL_SOFTDISCONNECT; | |
731 | writel(dev_cntl, &udc_regs_p->dev_cntl); | |
62db1c0d VK |
732 | |
733 | plug_st = readl(&plug_regs_p->plug_state); | |
734 | plug_st &= ~(PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); | |
735 | writel(plug_st, &plug_regs_p->plug_state); | |
736 | } | |
737 | ||
738 | /* Turn off the USB connection by disabling the pullup resistor */ | |
739 | void udc_disconnect(void) | |
740 | { | |
741 | u32 plug_st; | |
742 | ||
dc3e7739 VK |
743 | writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl); |
744 | ||
62db1c0d VK |
745 | plug_st = readl(&plug_regs_p->plug_state); |
746 | plug_st |= (PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); | |
747 | writel(plug_st, &plug_regs_p->plug_state); | |
748 | } | |
749 | ||
750 | /* Switch on the UDC */ | |
751 | void udc_enable(struct usb_device_instance *device) | |
752 | { | |
753 | UDCDBGA("enable device %p, status %d", device, device->status); | |
754 | ||
755 | /* Save the device structure pointer */ | |
756 | udc_device = device; | |
757 | ||
758 | /* Setup ep0 urb */ | |
759 | if (!ep0_urb) { | |
760 | ep0_urb = | |
761 | usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array); | |
762 | } else { | |
763 | serial_printf("udc_enable: ep0_urb already allocated %p\n", | |
764 | ep0_urb); | |
765 | } | |
766 | ||
767 | writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); | |
768 | } | |
769 | ||
770 | /** | |
771 | * udc_startup - allow udc code to do any additional startup | |
772 | */ | |
773 | void udc_startup_events(struct usb_device_instance *device) | |
774 | { | |
775 | /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ | |
776 | usbd_device_event_irq(device, DEVICE_INIT, 0); | |
777 | ||
778 | /* | |
779 | * The DEVICE_CREATE event puts the USB device in the state | |
780 | * STATE_ATTACHED. | |
781 | */ | |
782 | usbd_device_event_irq(device, DEVICE_CREATE, 0); | |
783 | ||
784 | /* | |
785 | * Some USB controller driver implementations signal | |
786 | * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. | |
787 | * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, | |
788 | * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. | |
2721551a | 789 | * The DW USB client controller has the capability to detect when the |
62db1c0d VK |
790 | * USB cable is connected to a powered USB bus, so we will defer the |
791 | * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later. | |
792 | */ | |
793 | ||
794 | udc_enable(device); | |
795 | } | |
796 | ||
797 | /* | |
798 | * Plug detection interrupt handling | |
799 | */ | |
4df4f3c9 | 800 | static void dw_udc_plug_irq(void) |
62db1c0d VK |
801 | { |
802 | if (readl(&plug_regs_p->plug_state) & PLUG_STATUS_ATTACHED) { | |
803 | /* | |
804 | * USB cable attached | |
805 | * Turn off PHY reset bit (PLUG detect). | |
806 | * Switch PHY opmode to normal operation (PLUG detect). | |
807 | */ | |
808 | udc_connect(); | |
809 | writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); | |
810 | ||
811 | UDCDBG("device attached and powered"); | |
812 | udc_state_transition(udc_device->device_state, STATE_POWERED); | |
813 | } else { | |
62db1c0d VK |
814 | writel(~0x0, &udc_regs_p->dev_int_mask); |
815 | ||
816 | UDCDBG("device detached or unpowered"); | |
817 | udc_state_transition(udc_device->device_state, STATE_ATTACHED); | |
818 | } | |
819 | } | |
820 | ||
821 | /* | |
822 | * Device interrupt handling | |
823 | */ | |
4df4f3c9 | 824 | static void dw_udc_dev_irq(void) |
62db1c0d VK |
825 | { |
826 | if (readl(&udc_regs_p->dev_int) & DEV_INT_USBRESET) { | |
827 | writel(~0x0, &udc_regs_p->endp_int_mask); | |
828 | ||
62db1c0d VK |
829 | writel(readl(&inep_regs_p[0].endp_cntl) | ENDP_CNTL_FLUSH, |
830 | &inep_regs_p[0].endp_cntl); | |
831 | ||
832 | writel(DEV_INT_USBRESET, &udc_regs_p->dev_int); | |
833 | ||
dc3e7739 VK |
834 | /* |
835 | * This endpoint0 specific register can be programmed only | |
836 | * after the phy clock is initialized | |
837 | */ | |
838 | writel((EP0_MAX_PACKET_SIZE << 19) | ENDP_EPTYPE_CNTL, | |
839 | &udc_regs_p->udc_endp_reg[0]); | |
840 | ||
62db1c0d VK |
841 | UDCDBG("device reset in progess"); |
842 | udc_state_transition(udc_device->device_state, STATE_DEFAULT); | |
843 | } | |
844 | ||
845 | /* Device Enumeration completed */ | |
846 | if (readl(&udc_regs_p->dev_int) & DEV_INT_ENUM) { | |
847 | writel(DEV_INT_ENUM, &udc_regs_p->dev_int); | |
848 | ||
849 | /* Endpoint interrupt enabled for Ctrl IN & Ctrl OUT */ | |
850 | writel(readl(&udc_regs_p->endp_int_mask) & ~0x10001, | |
851 | &udc_regs_p->endp_int_mask); | |
852 | ||
853 | UDCDBG("default -> addressed"); | |
854 | udc_state_transition(udc_device->device_state, STATE_ADDRESSED); | |
855 | } | |
856 | ||
857 | /* The USB will be in SUSPEND in 3 ms */ | |
858 | if (readl(&udc_regs_p->dev_int) & DEV_INT_INACTIVE) { | |
859 | writel(DEV_INT_INACTIVE, &udc_regs_p->dev_int); | |
860 | ||
861 | UDCDBG("entering inactive state"); | |
862 | /* usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); */ | |
863 | } | |
864 | ||
865 | /* SetConfiguration command received */ | |
866 | if (readl(&udc_regs_p->dev_int) & DEV_INT_SETCFG) { | |
867 | writel(DEV_INT_SETCFG, &udc_regs_p->dev_int); | |
868 | ||
869 | UDCDBG("entering configured state"); | |
870 | udc_state_transition(udc_device->device_state, | |
871 | STATE_CONFIGURED); | |
872 | } | |
873 | ||
874 | /* SetInterface command received */ | |
875 | if (readl(&udc_regs_p->dev_int) & DEV_INT_SETINTF) | |
876 | writel(DEV_INT_SETINTF, &udc_regs_p->dev_int); | |
877 | ||
878 | /* USB Suspend detected on cable */ | |
879 | if (readl(&udc_regs_p->dev_int) & DEV_INT_SUSPUSB) { | |
880 | writel(DEV_INT_SUSPUSB, &udc_regs_p->dev_int); | |
881 | ||
882 | UDCDBG("entering suspended state"); | |
883 | usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); | |
884 | } | |
885 | ||
886 | /* USB Start-Of-Frame detected on cable */ | |
887 | if (readl(&udc_regs_p->dev_int) & DEV_INT_SOF) | |
888 | writel(DEV_INT_SOF, &udc_regs_p->dev_int); | |
889 | } | |
890 | ||
891 | /* | |
892 | * Endpoint interrupt handling | |
893 | */ | |
4df4f3c9 | 894 | static void dw_udc_endpoint_irq(void) |
62db1c0d VK |
895 | { |
896 | while (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLOUT) { | |
897 | ||
898 | writel(ENDP0_INT_CTRLOUT, &udc_regs_p->endp_int); | |
899 | ||
900 | if ((readl(&outep_regs_p[0].endp_status) & ENDP_STATUS_OUTMSK) | |
901 | == ENDP_STATUS_OUT_SETUP) { | |
2721551a | 902 | dw_udc_setup(udc_device->bus->endpoint_array + 0); |
62db1c0d VK |
903 | writel(ENDP_STATUS_OUT_SETUP, |
904 | &outep_regs_p[0].endp_status); | |
905 | ||
906 | } else if ((readl(&outep_regs_p[0].endp_status) & | |
907 | ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { | |
2721551a | 908 | dw_udc_ep0_rx(udc_device->bus->endpoint_array + 0); |
62db1c0d VK |
909 | writel(ENDP_STATUS_OUT_DATA, |
910 | &outep_regs_p[0].endp_status); | |
911 | ||
912 | } else if ((readl(&outep_regs_p[0].endp_status) & | |
913 | ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { | |
914 | /* NONE received */ | |
915 | } | |
916 | ||
917 | writel(0x0, &outep_regs_p[0].endp_status); | |
918 | } | |
919 | ||
920 | if (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLIN) { | |
2721551a | 921 | dw_udc_ep0_tx(udc_device->bus->endpoint_array + 0); |
62db1c0d VK |
922 | |
923 | writel(ENDP_STATUS_IN, &inep_regs_p[0].endp_status); | |
924 | writel(ENDP0_INT_CTRLIN, &udc_regs_p->endp_int); | |
925 | } | |
926 | ||
dc3e7739 | 927 | if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOOUT_MSK) { |
62db1c0d VK |
928 | u32 epnum = 0; |
929 | u32 ep_int = readl(&udc_regs_p->endp_int) & | |
930 | ENDP_INT_NONISOOUT_MSK; | |
931 | ||
932 | ep_int >>= 16; | |
933 | while (0x0 == (ep_int & 0x1)) { | |
934 | ep_int >>= 1; | |
935 | epnum++; | |
936 | } | |
937 | ||
938 | writel((1 << 16) << epnum, &udc_regs_p->endp_int); | |
939 | ||
940 | if ((readl(&outep_regs_p[epnum].endp_status) & | |
941 | ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { | |
942 | ||
2721551a | 943 | dw_udc_epn_rx(epnum); |
62db1c0d VK |
944 | writel(ENDP_STATUS_OUT_DATA, |
945 | &outep_regs_p[epnum].endp_status); | |
946 | } else if ((readl(&outep_regs_p[epnum].endp_status) & | |
947 | ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { | |
948 | writel(0x0, &outep_regs_p[epnum].endp_status); | |
949 | } | |
950 | } | |
951 | ||
952 | if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOIN_MSK) { | |
953 | u32 epnum = 0; | |
954 | u32 ep_int = readl(&udc_regs_p->endp_int) & | |
955 | ENDP_INT_NONISOIN_MSK; | |
956 | ||
957 | while (0x0 == (ep_int & 0x1)) { | |
958 | ep_int >>= 1; | |
959 | epnum++; | |
960 | } | |
961 | ||
962 | if (readl(&inep_regs_p[epnum].endp_status) & ENDP_STATUS_IN) { | |
963 | writel(ENDP_STATUS_IN, | |
964 | &outep_regs_p[epnum].endp_status); | |
2721551a | 965 | dw_udc_epn_tx(epnum); |
62db1c0d VK |
966 | |
967 | writel(ENDP_STATUS_IN, | |
968 | &outep_regs_p[epnum].endp_status); | |
969 | } | |
970 | ||
971 | writel((1 << epnum), &udc_regs_p->endp_int); | |
972 | } | |
973 | } | |
974 | ||
975 | /* | |
976 | * UDC interrupts | |
977 | */ | |
978 | void udc_irq(void) | |
979 | { | |
980 | /* | |
981 | * Loop while we have interrupts. | |
982 | * If we don't do this, the input chain | |
983 | * polling delay is likely to miss | |
984 | * host requests. | |
985 | */ | |
986 | while (readl(&plug_regs_p->plug_pending)) | |
2721551a | 987 | dw_udc_plug_irq(); |
62db1c0d VK |
988 | |
989 | while (readl(&udc_regs_p->dev_int)) | |
2721551a | 990 | dw_udc_dev_irq(); |
62db1c0d VK |
991 | |
992 | if (readl(&udc_regs_p->endp_int)) | |
2721551a | 993 | dw_udc_endpoint_irq(); |
62db1c0d VK |
994 | } |
995 | ||
996 | /* Flow control */ | |
997 | void udc_set_nak(int epid) | |
998 | { | |
999 | writel(readl(&inep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, | |
1000 | &inep_regs_p[epid].endp_cntl); | |
1001 | ||
1002 | writel(readl(&outep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, | |
1003 | &outep_regs_p[epid].endp_cntl); | |
1004 | } | |
1005 | ||
1006 | void udc_unset_nak(int epid) | |
1007 | { | |
1008 | u32 val; | |
1009 | ||
1010 | val = readl(&inep_regs_p[epid].endp_cntl); | |
1011 | val &= ~ENDP_CNTL_SNAK; | |
1012 | val |= ENDP_CNTL_CNAK; | |
1013 | writel(val, &inep_regs_p[epid].endp_cntl); | |
1014 | ||
1015 | val = readl(&outep_regs_p[epid].endp_cntl); | |
1016 | val &= ~ENDP_CNTL_SNAK; | |
1017 | val |= ENDP_CNTL_CNAK; | |
1018 | writel(val, &outep_regs_p[epid].endp_cntl); | |
1019 | } |