2 * Implementation of low level MUSB core logic (variant independent)
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 /*===========================================================================*
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 /*===========================================================================*
30 * MUSB core implementation *
32 *===========================================================================*/
34 /*===========================================================================*
36 *===========================================================================*/
38 musb_set_state(musb_core_config
* cfg
)
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 *===========================================================================*/
65 musb_check_rxpktrdy(void * cfg
, hcd_reg1 ep_num
)
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
)
83 /* Get RX status register for any other EP */
84 if (HCD_RD2(r
, MUSB_REG_HOST_RXCSR
) &
85 MUSB_VAL_HOST_RXCSR_RXPKTRDY
)
93 /*===========================================================================*
94 * musb_in_stage_cleanup *
95 *===========================================================================*/
97 musb_in_stage_cleanup(void * cfg
, hcd_reg1 ep_num
)
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 *===========================================================================*/
113 musb_clear_rxpktrdy(void * cfg
, hcd_reg1 ep_num
)
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
);
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 *===========================================================================*/
148 musb_clear_statuspkt(void * cfg
)
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 /*===========================================================================*
171 *===========================================================================*/
173 musb_get_count(void * cfg
)
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 /*===========================================================================*
192 *===========================================================================*/
194 musb_read_fifo(void * cfg
, void * output
, int size
, hcd_reg1 fifo_num
)
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 */
231 *output_b
++ = HCD_RD1(r
, fifo_addr
);
237 /*===========================================================================*
239 *===========================================================================*/
241 musb_write_fifo(void * cfg
, void * input
, int size
, hcd_reg1 fifo_num
)
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 */
278 HCD_WR1(r
, fifo_addr
, *input_b
++);
284 /*===========================================================================*
286 *===========================================================================*/
288 musb_core_start(void * cfg
)
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
);
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 /*===========================================================================*
317 *===========================================================================*/
319 musb_core_stop(void * cfg
)
326 r
= ((musb_core_config
*)cfg
)->regs
;
328 /* Disable all interrupts */
329 HCD_WR1(r
, MUSB_REG_INTRUSBE
, MUSB_VAL_INTRUSBE_NONE
);
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 *===========================================================================*/
348 musb_setup_device(void * cfg
, hcd_reg1 ep
, hcd_reg1 addr
,
349 hcd_datatog
* tx_tog
, hcd_datatog
* rx_tog
)
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
)
368 musb_core_config
* core
;
374 core
= (musb_core_config
*)cfg
;
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
);
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
);
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");
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");
428 /*===========================================================================*
430 *===========================================================================*/
432 musb_setup_stage(void * cfg
, hcd_ctrlrequest
* setup
)
436 musb_core_config
* core
;
441 core
= (musb_core_config
*)cfg
;
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 /*===========================================================================*
467 *===========================================================================*/
469 musb_rx_stage(void * cfg
, hcd_datarequest
* request
)
471 musb_core_config
* core
;
473 hcd_reg1 host_rxtype
;
478 core
= (musb_core_config
*)cfg
;
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
;
496 case HCD_TRANSFER_INTERRUPT
:
497 host_rxtype
|= MUSB_VAL_HOST_XXTYPE_INTERRUPT
;
500 USB_ASSERT(0, "Unsupported transfer type");
503 if (HCD_SPEED_HIGH
== request
->speed
)
504 host_rxtype
|= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED
;
506 host_rxtype
|= MUSB_VAL_HOST_XXTYPE_FULL_SPEED
;
508 /* Rewrite HOST_RXTYPE */
509 HCD_WR1(r
, MUSB_REG_HOST_RXTYPE
, host_rxtype
);
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
);
519 /* Not required by all MUSB implementations, but
520 * left here just in case */
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
);
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 */
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
);
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 /*===========================================================================*
557 *===========================================================================*/
559 musb_tx_stage(void * cfg
, hcd_datarequest
* request
)
561 musb_core_config
* core
;
563 hcd_reg1 host_txtype
;
568 core
= (musb_core_config
*)cfg
;
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
;
586 case HCD_TRANSFER_INTERRUPT
:
587 host_txtype
|= MUSB_VAL_HOST_XXTYPE_INTERRUPT
;
590 USB_ASSERT(0, "Unsupported transfer type");
593 if (HCD_SPEED_HIGH
== request
->speed
)
594 host_txtype
|= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED
;
596 host_txtype
|= MUSB_VAL_HOST_XXTYPE_FULL_SPEED
;
598 /* Rewrite HOST_TXTYPE */
599 HCD_WR1(r
, MUSB_REG_HOST_TXTYPE
, host_txtype
);
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
);
609 /* Not required by all MUSB implementations, but
610 * left here just in case */
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
);
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 */
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
);
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 *===========================================================================*/
659 musb_in_data_stage(void * cfg
)
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 *===========================================================================*/
684 musb_out_data_stage(void * cfg
)
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 *===========================================================================*/
701 musb_in_status_stage(void * cfg
)
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 *===========================================================================*/
728 musb_out_status_stage(void * cfg
)
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 /*===========================================================================*
753 *===========================================================================*/
755 musb_read_data(void * cfg
, hcd_reg1
* buffer
, hcd_reg1 ep_num
)
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");
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
);
781 /*===========================================================================*
783 *===========================================================================*/
785 musb_check_error(void * cfg
, hcd_transfer xfer
, hcd_reg1 ep
, hcd_direction dir
)
787 /* Possible error handling schemes for MUSB */
790 MUSB_INVALID_ERROR_CASE
,
797 musb_core_config
* core
;
800 musb_error_case error_case
;
804 /* TODO: ISO transfer */
805 USB_ASSERT(HCD_TRANSFER_ISOCHRONOUS
!= xfer
,
806 "ISO transfer not supported");
808 core
= (musb_core_config
*)cfg
;
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
;
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
);
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
);
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
);
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
;
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
);
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
);
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
);
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
;
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
);
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
);
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
);
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
);