Remove building with NOCRYPTO option
[minix3.git] / minix / drivers / usb / usbd / hcd / musb / musb_core.c
blob37417d5e20e671c94dc753ec9e5786371cff3894
1 /*
2 * Implementation of low level MUSB core logic (variant independent)
3 */
5 #include <string.h> /* memcpy */
7 #include <usbd/hcd_common.h>
8 #include <usbd/hcd_interface.h>
9 #include <usbd/usbd_common.h>
11 #include "musb_core.h"
12 #include "musb_regs.h"
15 /*===========================================================================*
16 * Local prototypes *
17 *===========================================================================*/
18 static void musb_set_state(musb_core_config *);
19 static int musb_check_rxpktrdy(void *, hcd_reg1);
20 static void musb_in_stage_cleanup(void *, hcd_reg1);
21 static void musb_clear_rxpktrdy(void *, hcd_reg1);
22 static void musb_clear_statuspkt(void *);
23 static int musb_get_count(void *);
24 static void musb_read_fifo(void *, void *, int, hcd_reg1);
25 static void musb_write_fifo(void *, void *, int, hcd_reg1);
28 /*===========================================================================*
29 * *
30 * MUSB core implementation *
31 * *
32 *===========================================================================*/
34 /*===========================================================================*
35 * musb_set_state *
36 *===========================================================================*/
37 static void
38 musb_set_state(musb_core_config * cfg)
40 void * r;
42 DEBUG_DUMP;
44 r = cfg->regs;
46 USB_ASSERT(cfg->ep <= HCD_LAST_EP, "Invalid EP supplied");
47 USB_ASSERT(cfg->addr <= HCD_LAST_ADDR, "Invalid address supplied");
49 /* Set EP and address to be used in next MUSB command */
51 /* Set EP by selecting INDEX */
52 HCD_WR1(r, MUSB_REG_INDEX, cfg->ep);
54 /* Use device with address 'cfg->addr' */
55 HCD_WR1(r, MUSB_REG_FADDR, cfg->addr);
56 HCD_WR2(r, MUSB_REG_CONFIG(cfg->ep, MUSB_REG_RXFUNCADDR), cfg->addr);
57 HCD_WR2(r, MUSB_REG_CONFIG(cfg->ep, MUSB_REG_TXFUNCADDR), cfg->addr);
61 /*===========================================================================*
62 * musb_check_rxpktrdy *
63 *===========================================================================*/
64 static int
65 musb_check_rxpktrdy(void * cfg, hcd_reg1 ep_num)
67 void * r;
69 DEBUG_DUMP;
71 r = ((musb_core_config *)cfg)->regs;
73 /* Set EP and device address to be used in this command */
74 musb_set_state((musb_core_config *)cfg);
76 /* Check for RXPKTRDY */
77 if (HCD_DEFAULT_EP == ep_num) {
78 /* Get control status register for EP 0 */
79 if (HCD_RD2(r, MUSB_REG_HOST_CSR0) &
80 MUSB_VAL_HOST_CSR0_RXPKTRDY)
81 return EXIT_SUCCESS;
82 } else {
83 /* Get RX status register for any other EP */
84 if (HCD_RD2(r, MUSB_REG_HOST_RXCSR) &
85 MUSB_VAL_HOST_RXCSR_RXPKTRDY)
86 return EXIT_SUCCESS;
89 return EXIT_FAILURE;
93 /*===========================================================================*
94 * musb_in_stage_cleanup *
95 *===========================================================================*/
96 static void
97 musb_in_stage_cleanup(void * cfg, hcd_reg1 ep_num)
99 DEBUG_DUMP;
101 musb_clear_rxpktrdy(cfg, ep_num);
103 /* For control EP 0 also clear STATUSPKT */
104 if (HCD_DEFAULT_EP == ep_num)
105 musb_clear_statuspkt(cfg);
109 /*===========================================================================*
110 * musb_clear_rxpktrdy *
111 *===========================================================================*/
112 static void
113 musb_clear_rxpktrdy(void * cfg, hcd_reg1 ep_num)
115 void * r;
116 hcd_reg2 host_csr;
118 DEBUG_DUMP;
120 r = ((musb_core_config *)cfg)->regs;
122 /* Set EP and device address to be used in this command */
123 musb_set_state((musb_core_config *)cfg);
125 /* Check for RXPKTRDY */
126 if (HCD_DEFAULT_EP == ep_num) {
127 /* Get control status register for EP 0 */
128 host_csr = HCD_RD2(r, MUSB_REG_HOST_CSR0);
130 /* Clear RXPKTRDY to signal receive completion */
131 HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_RXPKTRDY);
132 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
133 } else {
134 /* Get RX status register for any other EP */
135 host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
137 /* Clear RXPKTRDY to signal receive completion */
138 HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_RXPKTRDY);
139 HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
144 /*===========================================================================*
145 * musb_clear_statuspkt *
146 *===========================================================================*/
147 static void
148 musb_clear_statuspkt(void * cfg)
150 void * r;
151 hcd_reg2 host_csr0;
153 DEBUG_DUMP;
155 r = ((musb_core_config *)cfg)->regs;
157 /* Set EP and device address to be used in this command */
158 musb_set_state((musb_core_config *)cfg);
160 /* Get control status register for EP 0 */
161 host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
163 /* Clear STATUSPKT to signal status packet completion */
164 HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_STATUSPKT);
165 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
169 /*===========================================================================*
170 * musb_get_count *
171 *===========================================================================*/
172 static int
173 musb_get_count(void * cfg)
175 void * r;
177 DEBUG_DUMP;
179 r = ((musb_core_config *)cfg)->regs;
181 /* Set EP and device address to be used in this command */
182 musb_set_state((musb_core_config *)cfg);
184 /* Reserved part returns zero so no need to generalize
185 * this return for MUSB_REG_RXCOUNT */
186 return (int)(HCD_RD2(r, MUSB_REG_COUNT0));
190 /*===========================================================================*
191 * musb_read_fifo *
192 *===========================================================================*/
193 static void
194 musb_read_fifo(void * cfg, void * output, int size, hcd_reg1 fifo_num)
196 void * r;
198 hcd_reg1 * output_b;
199 hcd_reg4 * output_w;
201 hcd_addr fifo_addr;
203 DEBUG_DUMP;
205 USB_ASSERT(fifo_num <= HCD_LAST_EP, "Invalid FIFO number");
207 r = ((musb_core_config *)cfg)->regs;
208 fifo_addr = MUSB_REG_FIFO0 + (fifo_num * MUSB_REG_FIFO_LEN);
210 /* TODO: Apparently, FIFO can only be read by:
211 * 1. initially using words
212 * 2. using bytes for whatever remains
213 * Reading bytes first to achieve alignment of remaining data
214 * will for some reason disable further word based reading
215 * Such reading method, may not be optimal for unaligned data */
216 output_w = (hcd_reg4 *)output;
218 /* Try and copy aligned words */
219 if (0 == ((hcd_addr)output_w % sizeof(hcd_addr))) {
221 while (size > (int)(sizeof(*output_w) - 1)) {
222 *output_w++ = HCD_RD4(r, fifo_addr);
223 size -= sizeof(*output_w);
227 output_b = (hcd_reg1 *)output_w;
229 /* Then, go with remaining bytes */
230 while (size > 0) {
231 *output_b++ = HCD_RD1(r, fifo_addr);
232 size--;
237 /*===========================================================================*
238 * musb_write_fifo *
239 *===========================================================================*/
240 static void
241 musb_write_fifo(void * cfg, void * input, int size, hcd_reg1 fifo_num)
243 void * r;
245 hcd_reg1 * input_b;
246 hcd_reg4 * input_w;
248 hcd_addr fifo_addr;
250 DEBUG_DUMP;
252 USB_ASSERT(fifo_num <= HCD_LAST_EP, "Invalid FIFO number");
254 r = ((musb_core_config *)cfg)->regs;
255 fifo_addr = MUSB_REG_FIFO0 + (fifo_num * MUSB_REG_FIFO_LEN);
257 /* TODO: Apparently, FIFO can only be written by:
258 * 1. initially using words
259 * 2. using bytes for whatever remains
260 * Writing bytes first to achieve alignment of remaining data
261 * will for some reason disable further word based writing
262 * Such writing method, may not be optimal for unaligned data */
263 input_w = (hcd_reg4 *)input;
265 /* Try and copy aligned words */
266 if (0 == ((hcd_addr)input_w % sizeof(hcd_addr))) {
268 while (size > (int)(sizeof(*input_w) - 1)) {
269 HCD_WR4(r, fifo_addr, *input_w++);
270 size -= sizeof(*input_w);
274 input_b = (hcd_reg1 *)input_w;
276 /* Then, go with remaining bytes */
277 while (size > 0) {
278 HCD_WR1(r, fifo_addr, *input_b++);
279 size--;
284 /*===========================================================================*
285 * musb_core_start *
286 *===========================================================================*/
287 void
288 musb_core_start(void * cfg)
290 void * r;
291 hcd_reg1 devctl;
293 DEBUG_DUMP;
295 r = ((musb_core_config *)cfg)->regs;
297 /* Enable all interrupts valid for host */
298 HCD_WR1(r, MUSB_REG_INTRUSBE,
299 MUSB_VAL_INTRUSBE_SUSPEND |
300 MUSB_VAL_INTRUSBE_RESUME |
301 MUSB_VAL_INTRUSBE_RESET_BABBLE |
302 /* MUSB_VAL_INTRUSBE_SOF | */
303 MUSB_VAL_INTRUSBE_CONN |
304 MUSB_VAL_INTRUSBE_DISCON |
305 MUSB_VAL_INTRUSBE_SESSREQ |
306 MUSB_VAL_INTRUSBE_VBUSERR);
308 /* Start session */
309 devctl = HCD_RD1(r, MUSB_REG_DEVCTL);
310 HCD_SET(devctl, MUSB_VAL_DEVCTL_SESSION);
311 HCD_WR1(r, MUSB_REG_DEVCTL, devctl);
315 /*===========================================================================*
316 * musb_core_stop *
317 *===========================================================================*/
318 void
319 musb_core_stop(void * cfg)
321 void * r;
322 hcd_reg1 devctl;
324 DEBUG_DUMP;
326 r = ((musb_core_config *)cfg)->regs;
328 /* Disable all interrupts */
329 HCD_WR1(r, MUSB_REG_INTRUSBE, MUSB_VAL_INTRUSBE_NONE);
331 /* Stop session */
332 devctl = HCD_RD1(r, MUSB_REG_DEVCTL);
333 HCD_CLR(devctl, MUSB_VAL_DEVCTL_SESSION);
334 HCD_WR1(r, MUSB_REG_DEVCTL, devctl);
338 /*===========================================================================*
340 * HCD interface implementation *
342 *===========================================================================*/
344 /*===========================================================================*
345 * musb_setup_device *
346 *===========================================================================*/
347 void
348 musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr,
349 hcd_datatog * tx_tog, hcd_datatog * rx_tog)
351 DEBUG_DUMP;
353 /* Assign */
354 ((musb_core_config *)cfg)->ep = ep;
355 ((musb_core_config *)cfg)->addr = addr;
356 ((musb_core_config *)cfg)->datatog_tx = tx_tog;
357 ((musb_core_config *)cfg)->datatog_rx = rx_tog;
361 /*===========================================================================*
362 * musb_reset_device *
363 *===========================================================================*/
365 musb_reset_device(void * cfg, hcd_speed * speed)
367 void * r;
368 musb_core_config * core;
369 hcd_reg1 power;
370 hcd_reg1 host_type0;
372 DEBUG_DUMP;
374 core = (musb_core_config *)cfg;
375 r = core->regs;
377 /* Set initial parameters */
378 musb_setup_device(core, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR, NULL, NULL);
380 /* Set EP and device address to be used in this command */
381 musb_set_state(core);
383 /* Write reset bit and high speed negotiation wait for at least
384 * 20ms for reset, clear reset bit and wait for device */
385 power = HCD_RD1(r, MUSB_REG_POWER);
386 HCD_SET(power, MUSB_VAL_POWER_RESET | MUSB_VAL_POWER_HSEN);
387 HCD_WR1(r, MUSB_REG_POWER, power);
389 /* Sleep 25msec */
390 hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25));
392 power = HCD_RD1(r, MUSB_REG_POWER);
393 HCD_CLR(power, MUSB_VAL_POWER_RESET);
394 HCD_WR1(r, MUSB_REG_POWER, power);
396 /* Sleep 25msec */
397 hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25));
399 /* High speed check */
400 power = HCD_RD1(r, MUSB_REG_POWER);
402 if (power & MUSB_VAL_POWER_HSMODE) {
403 /* Set high-speed for EP0 */
404 host_type0 = HCD_RD1(r, MUSB_REG_HOST_TYPE0);
405 HCD_CLR(host_type0, MUSB_VAL_HOST_TYPE0_MASK);
406 HCD_SET(host_type0, MUSB_VAL_HOST_TYPE0_HIGH_SPEED);
407 HCD_WR1(r, MUSB_REG_HOST_TYPE0, host_type0);
409 *speed = HCD_SPEED_HIGH;
411 USB_DBG("High speed USB enabled");
412 } else {
413 /* Only full-speed supported */
414 host_type0 = HCD_RD1(r, MUSB_REG_HOST_TYPE0);
415 HCD_CLR(host_type0, MUSB_VAL_HOST_TYPE0_MASK);
416 HCD_SET(host_type0, MUSB_VAL_HOST_TYPE0_FULL_SPEED);
417 HCD_WR1(r, MUSB_REG_HOST_TYPE0, host_type0);
419 *speed = HCD_SPEED_FULL;
421 USB_DBG("High speed USB disabled");
424 return EXIT_SUCCESS;
428 /*===========================================================================*
429 * musb_setup_stage *
430 *===========================================================================*/
431 void
432 musb_setup_stage(void * cfg, hcd_ctrlrequest * setup)
434 void * r;
435 char * setup_byte;
436 musb_core_config * core;
437 hcd_reg2 host_csr0;
439 DEBUG_DUMP;
441 core = (musb_core_config *)cfg;
442 r = core->regs;
443 setup_byte = (char*)setup;
445 USB_ASSERT(0 == core->ep, "Only EP 0 can handle control transfers");
447 /* Set EP and device address to be used in this command */
448 musb_set_state(core);
450 /* Put USB setup data into EP0 FIFO */
451 HCD_WR4(r, MUSB_REG_FIFO0, HCD_8TO32(&setup_byte[0]));
452 HCD_WR4(r, MUSB_REG_FIFO0, HCD_8TO32(&setup_byte[sizeof(hcd_reg4)]));
454 /* Get control status register for EP 0 */
455 host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
457 /* Send actual packet from FIFO */
458 HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_TXPKTRDY |
459 MUSB_VAL_HOST_CSR0_SETUPPKT);
461 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
465 /*===========================================================================*
466 * musb_rx_stage *
467 *===========================================================================*/
468 void
469 musb_rx_stage(void * cfg, hcd_datarequest * request)
471 musb_core_config * core;
472 hcd_reg2 host_rxcsr;
473 hcd_reg1 host_rxtype;
474 void * r;
476 DEBUG_DUMP;
478 core = (musb_core_config *)cfg;
479 r = core->regs;
481 USB_ASSERT(request->max_packet_size <= HCD_MAX_MAXPACKETSIZE,
482 "Invalid wMaxPacketSize");
483 USB_ASSERT((core->ep <= HCD_LAST_EP) && (core->ep > HCD_DEFAULT_EP),
484 "Invalid bulk EP supplied");
486 /* Set EP and device address to be used in this command */
487 musb_set_state(core);
489 /* Evaluate RXTYPE */
490 host_rxtype = core->ep;
492 switch (request->type) {
493 case HCD_TRANSFER_BULK:
494 host_rxtype |= MUSB_VAL_HOST_XXTYPE_BULK;
495 break;
496 case HCD_TRANSFER_INTERRUPT:
497 host_rxtype |= MUSB_VAL_HOST_XXTYPE_INTERRUPT;
498 break;
499 default:
500 USB_ASSERT(0, "Unsupported transfer type");
503 if (HCD_SPEED_HIGH == request->speed)
504 host_rxtype |= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED;
505 else
506 host_rxtype |= MUSB_VAL_HOST_XXTYPE_FULL_SPEED;
508 /* Rewrite HOST_RXTYPE */
509 HCD_WR1(r, MUSB_REG_HOST_RXTYPE, host_rxtype);
511 /* Rewrite RXMAXP */
512 HCD_WR2(r, MUSB_REG_RXMAXP, request->max_packet_size);
514 /* Set HOST_RXINTERVAL (which means interval or NAK limit) */
515 HCD_WR1(r, MUSB_REG_HOST_RXINTERVAL, request->interval);
517 #if 0
519 /* Not required by all MUSB implementations, but
520 * left here just in case */
521 hcd_reg2 intrrxe;
523 /* Enable this interrupt */
524 intrrxe = HCD_RD2(r, MUSB_REG_INTRRXE);
525 HCD_SET(intrrxe, HCD_BIT(core->ep));
526 HCD_WR2(r, MUSB_REG_INTRRXE, intrrxe);
528 #endif
530 /* TODO: One reusable FIFO, no double buffering */
531 /* TODO: With this, only one device/EP can work at a time. Should this
532 * be changed, hcd_device_wait/hcd_device_continue calls must be fixed
533 * accordingly to allow handling multiple EP interrupts */
534 /* Assign FIFO */
535 HCD_WR2(r, MUSB_REG_RXFIFOADDR, MUSB_VAL_XXFIFOADDR_EP0_END);
536 HCD_WR1(r, MUSB_REG_RXFIFOSZ, MUSB_VAL_XXFIFOSZ_4096);
538 /* Make controller reconfigure */
539 host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
540 HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOGWREN); /* Enable first */
541 HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO);
542 HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
544 /* Set data toggle and start receiving */
545 host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
546 if (HCD_DATATOG_DATA0 == *(core->datatog_rx))
547 HCD_CLR(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOG);
548 else
549 HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOG);
550 HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_REQPKT);
551 HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
555 /*===========================================================================*
556 * musb_tx_stage *
557 *===========================================================================*/
558 void
559 musb_tx_stage(void * cfg, hcd_datarequest * request)
561 musb_core_config * core;
562 hcd_reg2 host_txcsr;
563 hcd_reg1 host_txtype;
564 void * r;
566 DEBUG_DUMP;
568 core = (musb_core_config *)cfg;
569 r = core->regs;
571 USB_ASSERT(request->max_packet_size <= HCD_MAX_MAXPACKETSIZE,
572 "Invalid wMaxPacketSize");
573 USB_ASSERT((core->ep <= HCD_LAST_EP) && (core->ep > HCD_DEFAULT_EP),
574 "Invalid bulk EP supplied");
576 /* Set EP and device address to be used in this command */
577 musb_set_state(core);
579 /* Evaluate TXTYPE */
580 host_txtype = core->ep;
582 switch (request->type) {
583 case HCD_TRANSFER_BULK:
584 host_txtype |= MUSB_VAL_HOST_XXTYPE_BULK;
585 break;
586 case HCD_TRANSFER_INTERRUPT:
587 host_txtype |= MUSB_VAL_HOST_XXTYPE_INTERRUPT;
588 break;
589 default:
590 USB_ASSERT(0, "Unsupported transfer type");
593 if (HCD_SPEED_HIGH == request->speed)
594 host_txtype |= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED;
595 else
596 host_txtype |= MUSB_VAL_HOST_XXTYPE_FULL_SPEED;
598 /* Rewrite HOST_TXTYPE */
599 HCD_WR1(r, MUSB_REG_HOST_TXTYPE, host_txtype);
601 /* Rewrite TXMAXP */
602 HCD_WR2(r, MUSB_REG_TXMAXP, request->max_packet_size);
604 /* Set HOST_TXINTERVAL (which means interval or NAK limit) */
605 HCD_WR1(r, MUSB_REG_HOST_TXINTERVAL, request->interval);
607 #if 0
609 /* Not required by all MUSB implementations, but
610 * left here just in case */
611 hcd_reg2 intrtxe;
613 /* Enable this interrupt */
614 intrtxe = HCD_RD2(r, MUSB_REG_INTRTXE);
615 HCD_SET(intrtxe, HCD_BIT(core->ep));
616 HCD_WR2(r, MUSB_REG_INTRTXE, intrtxe);
618 #endif
620 /* TODO: One reusable FIFO, no double buffering */
621 /* TODO: With this, only one device/EP can work at a time. Should this
622 * be changed, hcd_device_wait/hcd_device_continue calls must be fixed
623 * accordingly to allow handling multiple EP interrupts */
624 /* Assign FIFO */
625 HCD_WR2(r, MUSB_REG_TXFIFOADDR, MUSB_VAL_XXFIFOADDR_EP0_END);
626 HCD_WR1(r, MUSB_REG_TXFIFOSZ, MUSB_VAL_XXFIFOSZ_4096);
628 /* Make controller reconfigure */
629 host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
630 HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DMAMODE);
631 HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_FRCDATATOG);
632 HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DMAEN);
633 HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE);
634 HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_ISO);
635 HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_AUTOSET);
636 HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOGWREN); /* Enable first */
637 /* TODO: May have no effect */
638 HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
639 HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
641 /* Put data in FIFO */
642 musb_write_fifo(cfg, request->data, request->data_left, core->ep);
644 /* Set data toggle and start transmitting */
645 host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
646 if (HCD_DATATOG_DATA0 == *(core->datatog_tx))
647 HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOG);
648 else
649 HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOG);
650 HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_TXPKTRDY);
651 HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
655 /*===========================================================================*
656 * musb_in_data_stage *
657 *===========================================================================*/
658 void
659 musb_in_data_stage(void * cfg)
661 void * r;
662 hcd_reg2 host_csr0;
664 DEBUG_DUMP;
666 r = ((musb_core_config *)cfg)->regs;
668 /* Set EP and device address to be used in this command */
669 musb_set_state((musb_core_config *)cfg);
671 /* Get control status register for EP 0 */
672 host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
674 /* Request IN DATA stage */
675 HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_REQPKT);
676 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
680 /*===========================================================================*
681 * musb_out_data_stage *
682 *===========================================================================*/
683 void
684 musb_out_data_stage(void * cfg)
686 DEBUG_DUMP;
688 /* Set EP and device address to be used in this command */
689 musb_set_state((musb_core_config *)cfg);
691 /* TODO: Not needed for enumeration but may be needed later, if
692 * additional control transfers are implemented */
693 USB_ASSERT(0, "Setup packet's 'DATA OUT' stage not implemented");
697 /*===========================================================================*
698 * musb_in_status_stage *
699 *===========================================================================*/
700 void
701 musb_in_status_stage(void * cfg)
703 void * r;
704 hcd_reg2 host_csr0;
706 DEBUG_DUMP;
708 r = ((musb_core_config *)cfg)->regs;
710 /* Set EP and device address to be used in this command */
711 musb_set_state((musb_core_config *)cfg);
713 /* Get control status register for EP 0 */
714 host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
716 /* Request IN STATUS stage */
717 HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_REQPKT |
718 MUSB_VAL_HOST_CSR0_STATUSPKT);
720 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
724 /*===========================================================================*
725 * musb_out_status_stage *
726 *===========================================================================*/
727 void
728 musb_out_status_stage(void * cfg)
730 void * r;
731 hcd_reg2 host_csr0;
733 DEBUG_DUMP;
735 r = ((musb_core_config *)cfg)->regs;
737 /* Set EP and device address to be used in this command */
738 musb_set_state((musb_core_config *)cfg);
740 /* Get control status register for EP 0 */
741 host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
743 /* Request OUT STATUS stage */
744 HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_TXPKTRDY |
745 MUSB_VAL_HOST_CSR0_STATUSPKT);
747 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
751 /*===========================================================================*
752 * musb_read_data *
753 *===========================================================================*/
755 musb_read_data(void * cfg, hcd_reg1 * buffer, hcd_reg1 ep_num)
757 int count;
759 DEBUG_DUMP;
761 /* Check if anything received at all */
762 if (EXIT_SUCCESS != musb_check_rxpktrdy(cfg, ep_num)) {
763 USB_MSG("RXPKTRDY not set when receiving");
764 return HCD_READ_ERR;
767 /* Number of bytes received at any EP */
768 count = musb_get_count(cfg);
770 /* Read from given FIFO */
771 if ((NULL != buffer) && (count > 0))
772 musb_read_fifo(cfg, buffer, count, ep_num);
774 /* Cleanup after reading */
775 musb_in_stage_cleanup(cfg, ep_num);
777 return count;
781 /*===========================================================================*
782 * musb_check_error *
783 *===========================================================================*/
785 musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
787 /* Possible error handling schemes for MUSB */
788 typedef enum {
790 MUSB_INVALID_ERROR_CASE,
791 MUSB_EP0_ERROR_CASE,
792 MUSB_OUT_ERROR_CASE,
793 MUSB_IN_ERROR_CASE,
795 musb_error_case;
797 musb_core_config * core;
798 void * r;
799 hcd_reg2 host_csr;
800 musb_error_case error_case;
802 DEBUG_DUMP;
804 /* TODO: ISO transfer */
805 USB_ASSERT(HCD_TRANSFER_ISOCHRONOUS != xfer,
806 "ISO transfer not supported");
808 core = (musb_core_config *)cfg;
809 r = core->regs;
811 /* Set EP and device address to be used in this command */
812 musb_set_state((musb_core_config *)cfg);
814 /* Resolve which error needs to be checked
815 * so we can use proper MUSB registers */
816 error_case = MUSB_INVALID_ERROR_CASE;
818 if (HCD_DEFAULT_EP == ep) {
819 if (HCD_TRANSFER_CONTROL == xfer)
820 /* EP0, control, any direction */
821 error_case = MUSB_EP0_ERROR_CASE;
822 } else {
823 if (HCD_TRANSFER_CONTROL != xfer) {
824 if (HCD_DIRECTION_OUT == dir)
825 /* EP>0, non-control, out */
826 error_case = MUSB_OUT_ERROR_CASE;
827 else if (HCD_DIRECTION_IN == dir)
828 /* EP>0, non-control, in */
829 error_case = MUSB_IN_ERROR_CASE;
833 /* In MUSB, EP0 has it's own registers for error handling and it also
834 * seems to be the only way to handle errors for control transfers */
835 if (MUSB_EP0_ERROR_CASE == error_case) {
836 /* Get control status register */
837 host_csr = HCD_RD2(r, MUSB_REG_HOST_CSR0);
839 /* Check for common errors */
840 if (host_csr & MUSB_VAL_HOST_CSR0_ERROR) {
841 USB_MSG("HOST_CSR0 ERROR: %04X", host_csr);
842 HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_ERROR);
843 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
844 return EXIT_FAILURE;
847 if (host_csr & MUSB_VAL_HOST_CSR0_RXSTALL) {
848 USB_MSG("HOST_CSR0 STALL: %04X", host_csr);
849 HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_RXSTALL);
850 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
851 return EXIT_FAILURE;
854 if (host_csr & MUSB_VAL_HOST_CSR0_NAK_TIMEOUT) {
855 USB_MSG("HOST_CSR0 NAK_TIMEOUT: %04X", host_csr);
856 HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_NAK_TIMEOUT);
857 HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
858 return EXIT_FAILURE;
861 return EXIT_SUCCESS;
864 if (MUSB_OUT_ERROR_CASE == error_case) {
865 /* Get TX status register */
866 host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
868 /* Check for completion */
869 if (!(host_csr & MUSB_VAL_HOST_TXCSR_TXPKTRDY)) {
870 /* ACK received update data toggle */
871 *(core->datatog_tx) ^= HCD_DATATOG_DATA1;
872 return EXIT_SUCCESS;
875 /* Check for common errors */
876 if (host_csr & MUSB_VAL_HOST_TXCSR_ERROR) {
877 USB_MSG("HOST_TXCSR ERROR: %04X", host_csr);
878 HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_ERROR);
879 HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
880 return EXIT_FAILURE;
883 if (host_csr & MUSB_VAL_HOST_TXCSR_RXSTALL) {
884 USB_MSG("HOST_TXCSR STALL: %04X", host_csr);
885 HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_RXSTALL);
886 HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
887 return EXIT_FAILURE;
890 if (host_csr & MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT) {
891 USB_MSG("HOST_TXCSR NAK_TIMEOUT: %04X", host_csr);
892 /* Flush FIFO before clearing NAKTIMEOUT
893 * to abort transfer */
894 HCD_SET(host_csr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
895 HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
896 host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
897 HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT);
898 HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
899 return EXIT_FAILURE;
902 USB_ASSERT(0, "Invalid state of HOST_TXCSR");
905 if (MUSB_IN_ERROR_CASE == error_case) {
906 /* Get RX status register */
907 host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
909 /* Check for completion */
910 if (host_csr & MUSB_VAL_HOST_RXCSR_RXPKTRDY) {
911 /* ACK received update data toggle */
912 *(core->datatog_rx) ^= HCD_DATATOG_DATA1;
913 return EXIT_SUCCESS;
916 /* Check for common errors */
917 if (host_csr & MUSB_VAL_HOST_RXCSR_ERROR) {
918 USB_MSG("HOST_RXCSR ERROR: %04X", host_csr);
919 HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_ERROR);
920 HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
921 return EXIT_FAILURE;
924 if (host_csr & MUSB_VAL_HOST_RXCSR_RXSTALL) {
925 USB_MSG("HOST_RXCSR STALL: %04X", host_csr);
926 HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_RXSTALL);
927 HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
928 return EXIT_FAILURE;
931 if (host_csr & MUSB_VAL_HOST_RXCSR_NAKTIMEOUT) {
932 USB_MSG("HOST_RXCSR NAK_TIMEOUT: %04X", host_csr);
933 /* Clear REQPKT before NAKTIMEOUT to abort transfer */
934 HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_REQPKT);
935 HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
936 host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
937 HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_NAKTIMEOUT);
938 HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
939 return EXIT_FAILURE;
942 USB_ASSERT(0, "Invalid state of HOST_RXCSR");
945 USB_MSG("Invalid USB transfer error check: 0x%X, 0x%X, 0x%X",
946 (int)xfer, (int)ep, (int)dir);
947 return EXIT_FAILURE;