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