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