1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2008 by Vitja Makarov
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
36 #define TCC7xx_USB_EPIF_IRQ_MASK 0xf
38 static int dbg_level
= 0x00;
39 static int global_ep_irq_mask
= 0x1;
40 #define DEBUG(level, fmt, args...) do { if (dbg_level & (level)) printf(fmt, ## args); } while (0)
49 #define printf(...) do {} while (0)
50 #define panicf_my panicf
52 int printf(const char *fmt
, ...);
53 #define panicf_my(fmt, args...) { \
54 int flags = disable_irq_save(); \
55 printf("*** PANIC ***"); \
56 printf(fmt, ## args); \
57 printf("*** PANIC ***"); \
58 while (usb_detect() == USB_INSERTED) \
67 unsigned char dir
; /* endpoint direction */
68 volatile uint16_t *ep
; /* hw ep buffer */
69 int id
; /* Endpoint id */
70 int mask
; /* Endpoint bit mask */
71 char *buf
; /* user buffer to store data */
72 int max_len
; /* how match data will fit */
73 int count
; /* actual data count */
77 static struct tcc_ep tcc_endpoints
[] = {
81 .ep
= &TCC7xx_USB_EP0_BUF
,
84 .ep
= &TCC7xx_USB_EP1_BUF
,
87 .ep
= &TCC7xx_USB_EP2_BUF
,
90 .ep
= &TCC7xx_USB_EP3_BUF
,
94 static bool usb_drv_write_ep(struct tcc_ep
*ep
);
95 static void usb_set_speed(int);
97 int usb_drv_request_endpoint(int type
, int dir
)
99 int flags
= disable_irq_save();
103 if (type
!= USB_ENDPOINT_XFER_BULK
)
106 if (dir
== USB_DIR_IN
)
111 if (!tcc_endpoints
[ep
].busy
) {
112 tcc_endpoints
[ep
].busy
= true;
113 tcc_endpoints
[ep
].dir
= dir
;
123 void usb_drv_release_endpoint(int ep
)
128 if (ep
< 1 || ep
> USB_NUM_ENDPOINTS
)
131 flags
= disable_irq_save();
133 tcc_endpoints
[ep
].busy
= false;
134 tcc_endpoints
[ep
].dir
= -1;
139 static inline void pullup_on(void)
141 TCC7xx_USB_PHY_CFG
= 0x000c;
144 static inline void pullup_off(void)
146 TCC7xx_USB_PHY_CFG
= 0x3e4c;
151 char *dump_data(char *data
, int count
)
153 static char buf
[1024];
157 for (i
= 0; i
< count
; i
++)
158 dump
+= snprintf(dump
, sizeof(buf
) - (dump
- buf
), "%02x", data
[i
]);
164 void handle_control(void)
166 /* control are always 8 bytes len */
167 static unsigned char ep_control
[8];
168 struct usb_ctrlrequest
*req
=
169 (struct usb_ctrlrequest
*) ep_control
;
171 unsigned short count
= 0;
175 /* select control endpoint */
176 TCC7xx_USB_INDEX
= 0x00;
177 stat
= TCC7xx_USB_EP0_STAT
;
181 TCC7xx_USB_EP0_STAT
= 0x10;
184 if (TCC7xx_USB_EP0_STAT
& 0x01) { /* RX */
185 uint16_t *ptr
= (uint16_t *) ep_control
;
187 count
= TCC7xx_USB_EP_BRCR
;
189 if (TCC7xx_USB_EP0_STAT
& 0x2)
190 TCC7xx_USB_EP0_STAT
= 0x02;
192 if (count
!= 4) { /* bad control? */
193 unsigned short dummy
;
196 dummy
= TCC7xx_USB_EP0_BUF
;
197 DEBUG(1, "WTF: count = %d", count
);
199 /* simply read control packet */
200 for (i
= 0; i
< count
; i
++)
201 ptr
[i
] = TCC7xx_USB_EP0_BUF
;
205 TCC7xx_USB_EP0_STAT
= 0x01;
206 DEBUG(1, "CTRL: len = %d %04x", count
, stat
);
207 } else if (TCC7xx_USB_EP0_STAT
& 0x02) { /* TX */
208 TCC7xx_USB_EP0_STAT
= 0x02;
209 DEBUG(2, "TX Done\n");
211 DEBUG(1, "stat: %04x", stat
);
216 if (0 == (stat
& 0x1) || count
!= 8)
218 #if 1 /* TODO: remove me someday */
221 uint16_t *ptr
= (uint16_t *) ep_control
;
222 for (i
= 1; i
< (count
>>1); i
++) {
223 if (ptr
[i
] != ptr
[0])
226 if (i
== (count
>>1)) {
227 /*DEBUG(2, */panicf_my("sanity failed");
232 type
= req
->bRequestType
;
234 /* TODO: don't pass some kinds of requests to upper level */
235 switch (req
->bRequest
) {
236 case USB_REQ_CLEAR_FEATURE
:
237 DEBUG(2, "USB_REQ_CLEAR_FEATURE");
238 DEBUG(2, "...%04x %04x", req
->wValue
, req
->wIndex
);
240 case USB_REQ_SET_ADDRESS
:
241 //DEBUG(2, "USB_REQ_SET_ADDRESS, %d %d", req->wValue, TCC7xx_USB_FUNC);
242 /* seems we don't have to set it manually
243 TCC7xx_USB_FUNC = req->wValue; */
245 case USB_REQ_GET_DESCRIPTOR
:
246 DEBUG(2, "gd, %02x %02x", req
->wValue
, req
->wIndex
);
248 case USB_REQ_GET_CONFIGURATION
:
249 DEBUG(2, "USB_REQ_GET_CONFIGURATION");
252 DEBUG(2, "req: %02x %02d", req
->bRequestType
, req
->bRequest
);
255 usb_core_control_request(req
);
259 void handle_ep_in(struct tcc_ep
*tcc_ep
, uint16_t stat
)
261 uint8_t *buf
= tcc_ep
->buf
;
262 uint16_t *wbuf
= (uint16_t *) buf
;
267 if (tcc_ep
->dir
!= USB_DIR_OUT
) {
268 panicf_my("ep%d: is input only", tcc_ep
->id
);
271 wcount
= TCC7xx_USB_EP_BRCR
;
273 DEBUG(2, "ep%d: %04x %04x", tcc_ep
->id
, stat
, wcount
);
277 if (stat
& TCC7xx_USP_EP_STAT_LWO
) {
283 panicf_my("ep%d: Unexpected packet! %d %x", tcc_ep
->id
, count
, TCC7xx_USB_EP_CTRL
);
284 if (tcc_ep
->max_len
< count
)
285 panicf_my("Too big packet: %d excepted %d %x", count
, tcc_ep
->max_len
, TCC7xx_USB_EP_CTRL
);
287 for (i
= 0; i
< wcount
; i
++)
288 wbuf
[i
] = *tcc_ep
->ep
;
290 if (count
& 1) { /* lwo */
291 uint16_t tmp
= *tcc_ep
->ep
;
292 buf
[count
- 1] = tmp
& 0xff;
297 TCC7xx_USB_EP_STAT
= TCC7xx_USB_EP_STAT
;
298 TCC7xx_USB_EPIF
= tcc_ep
->mask
;
299 TCC7xx_USB_EPIE
&= ~tcc_ep
->mask
; /* TODO: use INGLD? */
300 global_ep_irq_mask
&= ~tcc_ep
->mask
;
302 if (TCC7xx_USB_EP_STAT
& 0x1)
303 panicf_my("One more packet?");
305 TCC7xx_USB_EP_CTRL
|= TCC7xx_USB_EP_CTRL_OUTHD
;
307 usb_core_transfer_complete(tcc_ep
->id
, USB_DIR_OUT
, 0, count
);
311 void handle_ep_out(struct tcc_ep
*tcc_ep
, uint16_t stat
)
316 if (tcc_ep
->dir
!= USB_DIR_IN
) {
317 panicf_my("ep%d: is out only", tcc_ep
->id
);
320 // if (tcc_ep->buf == NULL) {
321 // panicf_my("%s:%d", __FILE__, __LINE__);
324 done
= usb_drv_write_ep(tcc_ep
);
326 // TCC7xx_USB_EP_STAT = 0x2; /* Clear TX stat */
327 TCC7xx_USB_EPIF
= tcc_ep
->mask
;
329 if (done
) { // tcc_ep->buf == NULL) {
330 TCC7xx_USB_EPIE
&= ~tcc_ep
->mask
;
331 global_ep_irq_mask
&= ~tcc_ep
->mask
;
333 // usb_core_transfer_complete(tcc_ep->id, USB_DIR_IN, 0, tcc_ep->count);
338 void handle_ep(unsigned short ep_irq
)
347 for (endpoint
= 1; endpoint
< 4; endpoint
++) {
348 struct tcc_ep
*tcc_ep
= &tcc_endpoints
[endpoint
];
351 if (0 == (ep_irq
& (1 << endpoint
)))
354 panicf_my("ep%d: wasn't requested", endpoint
);
356 TCC7xx_USB_INDEX
= endpoint
;
357 stat
= TCC7xx_USB_EP_STAT
;
359 DEBUG(1, "ep%d: %04x", endpoint
, stat
);
362 handle_ep_in(tcc_ep
, stat
);
364 handle_ep_out(tcc_ep
, stat
);
365 else /* TODO: remove me? */
366 panicf_my("Unhandled ep%d state: %x, %d", endpoint
, TCC7xx_USB_EP_STAT
, TCC7xx_USB_INDEX
);
371 static void usb_set_speed(int high_speed
)
373 TCC7xx_USB_EP_DIR
= 0x0000;
375 /* control endpoint */
376 TCC7xx_USB_INDEX
= 0;
377 TCC7xx_USB_EP0_CTRL
= 0x0000;
378 TCC7xx_USB_EP_MAXP
= 64;
379 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
| TCC7xx_USB_EP_CTRL_FLUSH
;
381 /* ep1: bulk-in, to host */
382 TCC7xx_USB_INDEX
= 1;
383 TCC7xx_USB_EP_DIR
|= (1 << 1);
384 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
;
387 TCC7xx_USB_EP_MAXP
= 512;
389 TCC7xx_USB_EP_MAXP
= 64;
391 TCC7xx_USB_EP_DMA_CTRL
= 0x0;
393 /* ep2: bulk-out, from host */
394 TCC7xx_USB_INDEX
= 2;
395 TCC7xx_USB_EP_DIR
&= ~(1 << 2);
396 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
;
399 TCC7xx_USB_EP_MAXP
= 512;
401 TCC7xx_USB_EP_MAXP
= 64;
403 TCC7xx_USB_EP_DMA_CTRL
= 0x0;
405 /* ep3: interrupt in */
406 TCC7xx_USB_INDEX
= 3;
407 TCC7xx_USB_EP_DIR
&= ~(1 << 3);
408 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
;
409 TCC7xx_USB_EP_MAXP
= 64;
411 TCC7xx_USB_EP_DMA_CTRL
= 0x0;
415 Reset TCC7xx usb device
417 static void usb_reset(void)
421 TCC7xx_USB_DELAY_CTRL
|= 0x81;
423 TCC7xx_USB_SYS_CTRL
= 0xa000 |
424 TCC7xx_USB_SYS_CTRL_RESET
|
425 TCC7xx_USB_SYS_CTRL_RFRE
|
426 TCC7xx_USB_SYS_CTRL_SPDEN
|
427 TCC7xx_USB_SYS_CTRL_VBONE
|
428 TCC7xx_USB_SYS_CTRL_VBOFE
;
433 TCC7xx_USB_EPIF
= TCC7xx_USB_EPIF_IRQ_MASK
;
434 global_ep_irq_mask
= 0x1;
435 TCC7xx_USB_EPIE
= global_ep_irq_mask
;
437 usb_core_bus_reset();
441 void USB_DEVICE(void)
443 unsigned short sys_stat
;
444 unsigned short ep_irq
;
445 unsigned short index_save
;
447 sys_stat
= TCC7xx_USB_SYS_STAT
;
449 if (sys_stat
& TCC7xx_USB_SYS_STAT_RESET
) {
450 TCC7xx_USB_SYS_STAT
= TCC7xx_USB_SYS_STAT_RESET
;
452 TCC7xx_USB_SYS_CTRL
|= TCC7xx_USB_SYS_CTRL_SUSPEND
;
456 if (sys_stat
& TCC7xx_USB_SYS_STAT_RESUME
) {
457 TCC7xx_USB_SYS_STAT
= TCC7xx_USB_SYS_STAT_RESUME
;
459 TCC7xx_USB_SYS_CTRL
|= TCC7xx_USB_SYS_CTRL_SUSPEND
;
463 if (sys_stat
& TCC7xx_USB_SYS_STAT_SPD_END
) {
465 TCC7xx_USB_SYS_STAT
= TCC7xx_USB_SYS_STAT_SPD_END
;
469 if (sys_stat
& TCC7xx_USB_SYS_STAT_ERRORS
) {
470 DEBUG(2, "errors: %4x", sys_stat
& TCC7xx_USB_SYS_STAT_ERRORS
);
471 TCC7xx_USB_SYS_STAT
= sys_stat
& TCC7xx_USB_SYS_STAT_ERRORS
;
474 // TCC7xx_USB_SYS_STAT = sys_stat;
476 index_save
= TCC7xx_USB_INDEX
;
478 ep_irq
= TCC7xx_USB_EPIF
& global_ep_irq_mask
;
480 while (ep_irq
& TCC7xx_USB_EPIF_IRQ_MASK
) {
483 /* is that really needed, btw not a problem for rockbox */
485 ep_irq
= TCC7xx_USB_EPIF
& global_ep_irq_mask
;
488 TCC7xx_USB_INDEX
= index_save
;
491 void usb_drv_set_address(int address
)
493 DEBUG(2, "setting address %d %d", address
, TCC7xx_USB_FUNC
);
496 int usb_drv_port_speed(void)
498 return (TCC7xx_USB_SYS_STAT
& 0x10) ? 1 : 0;
501 static int usb_drv_write_packet(volatile unsigned short *buf
, unsigned char *data
, int len
, int max
)
503 uint16_t *wbuf
= (uint16_t *) data
;
507 count
= (len
+ 1) / 2;
509 TCC7xx_USB_EP_BWCR
= len
;
511 for (i
= 0; i
< count
; i
++)
517 static bool usb_drv_write_ep(struct tcc_ep
*ep
)
521 if (ep
->max_len
== 0)
524 count
= usb_drv_write_packet(ep
->ep
, ep
->buf
, ep
->max_len
, 512);
525 TCC7xx_USB_EP_STAT
= 0x2; /* Clear TX stat */
529 ep
->max_len
-= count
;
531 if (ep
->max_len
== 0) {
532 usb_core_transfer_complete(ep
->id
, USB_DIR_IN
, 0, ep
->count
);
540 int usb_drv_send(int endpoint
, void *ptr
, int length
)
542 int flags
= disable_irq_save();
544 char *data
= (unsigned char*) ptr
;
546 DEBUG(2, "%s(%d,%d)" , __func__
, endpoint
, length
);
549 panicf_my("%s(%d,%d)", __func__
, endpoint
, length
);
551 TCC7xx_USB_INDEX
= 0;
555 ret
= usb_drv_write_packet(&TCC7xx_USB_EP0_BUF
, data
, length
, 64);
559 while (0 == (TCC7xx_USB_EP0_STAT
& 0x2))
561 TCC7xx_USB_EP0_STAT
= 0x2;
569 int usb_drv_send_nonblocking(int endpoint
, void *ptr
, int length
)
572 int rc
= 0, count
= length
;
573 char *data
= (unsigned char*) ptr
;
574 struct tcc_ep
*ep
= &tcc_endpoints
[endpoint
& 0x7f];
576 if (ep
->dir
!= USB_DIR_IN
|| length
== 0)
577 panicf_my("%s(%d,%d): Not supported", __func__
, endpoint
, length
);
579 DEBUG(2, "%s(%d,%d):", __func__
, endpoint
, length
);
581 flags
= disable_irq_save();
583 if(ep
->buf
!= NULL
) {
584 panicf_my("%s: ep is already busy", __func__
);
588 ep
->max_len
= length
;
591 TCC7xx_USB_INDEX
= ep
->id
;
593 TCC7xx_USB_EP_STAT
= 0x2;
594 /* TODO: use interrupts instead */
595 while (!usb_drv_write_ep(ep
)) {
596 while (0==(TCC7xx_USB_EP_STAT
& 0x2))
600 if (!usb_drv_write_ep(ep
)) {
601 TCC7xx_USB_EPIE
|= ep
->mask
;
602 global_ep_irq_mask
|= ep
->mask
;
607 DEBUG(2, "%s end", __func__
);
612 int usb_drv_recv(int endpoint
, void* ptr
, int length
)
614 volatile struct tcc_ep
*tcc_ep
= &tcc_endpoints
[endpoint
& 0x7f];
619 panicf_my("%s(%d,%d) zero length?", __func__
, endpoint
, length
);
623 if (tcc_ep
->dir
!= USB_DIR_OUT
)
624 panicf_my("%s(%d,%d)", __func__
, endpoint
, length
);
626 DEBUG(2, "%s(%d,%d)", __func__
, endpoint
, length
);
628 flags
= disable_irq_save();
631 panicf_my("%s: overrun: %x %x", __func__
, tcc_ep
->buf
, tcc_ep
);
635 tcc_ep
->max_len
= length
;
638 TCC7xx_USB_INDEX
= tcc_ep
->id
;
640 TCC7xx_USB_EP_CTRL
&= ~TCC7xx_USB_EP_CTRL_OUTHD
;
641 TCC7xx_USB_EPIE
|= tcc_ep
->mask
;
642 global_ep_irq_mask
|= tcc_ep
->mask
;
649 void usb_drv_cancel_all_transfers(void)
654 DEBUG(2, "%s", __func__
);
656 flags
= disable_irq_save();
657 for (endpoint
= 0; endpoint
< 4; endpoint
++) {
658 if (tcc_endpoints
[endpoint
].buf
) {
659 /* usb_core_transfer_complete(tcc_endpoints[endpoint].id,
660 tcc_endpoints[endpoint].dir, -1, 0); */
661 tcc_endpoints
[endpoint
].buf
= NULL
;
665 global_ep_irq_mask
= 1;
666 TCC7xx_USB_EPIE
= global_ep_irq_mask
;
667 TCC7xx_USB_EPIF
= TCC7xx_USB_EPIF_IRQ_MASK
;
671 void usb_drv_set_test_mode(int mode
)
673 panicf_my("%s(%d)", __func__
, mode
);
676 bool usb_drv_stalled(int endpoint
, bool in
)
678 panicf_my("%s(%d,%d)", __func__
, endpoint
, in
);
681 void usb_drv_stall(int endpoint
, bool stall
,bool in
)
683 printf("%s(%d,%d,%d)", __func__
, endpoint
, stall
, in
);
686 void usb_drv_init(void)
690 DEBUG(2, "%s", __func__
);
692 for (i
= 0; i
< sizeof(tcc_endpoints
)/sizeof(struct tcc_ep
); i
++) {
693 tcc_endpoints
[i
].id
= i
;
694 tcc_endpoints
[i
].mask
= 1 << i
;
695 tcc_endpoints
[i
].buf
= NULL
;
696 tcc_endpoints
[i
].busy
= false;
697 tcc_endpoints
[i
].dir
= -1;
700 /* Enable USB clock */
703 /* switch USB to host and then reset */
704 TCC7xx_USB_PHY_CFG
= 0x3e4c;
707 SWRESET
&= ~DEV_USBD
;
712 CREQ
= USBD_IRQ_MASK
;
713 IRQSEL
|= USBD_IRQ_MASK
;
714 TMODE
&= ~USBD_IRQ_MASK
;
715 IEN
|= USBD_IRQ_MASK
;
718 void usb_drv_exit(void)
721 BCLKCTR
&= ~DEV_USBD
;
725 SWRESET
&= ~DEV_USBD
;
730 void usb_init_device(void)
734 void usb_enable(bool on
)
742 void usb_attach(void)
749 /* TODO: not correct for all targets, we should poll VBUS
750 signal on USB bus. */
751 if (charger_inserted())
753 return USB_EXTRACTED
;
766 panicf("ata_init failed");
770 usb_start_monitoring();
771 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
775 // usb_serial_send("Hello\r\n", 7);
780 void usb_init_device(void)
782 /* simply switch USB off for now */
784 TCC7xx_USB_PHY_CFG
= 0x3e4c;
785 BCLKCTR
&= ~DEV_USBD
;
788 void usb_enable(bool on
)
793 /* Always return false for now */
796 return USB_EXTRACTED
;