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)
48 #define printf(...) do {} while (0)
49 #define panicf_my panicf
51 int printf(const char *fmt
, ...);
52 #define panicf_my(fmt, args...) { \
53 int flags = disable_irq_save(); \
54 printf("*** PANIC ***"); \
55 printf(fmt, ## args); \
56 printf("*** PANIC ***"); \
57 while (usb_detect() == USB_INSERTED) \
66 unsigned char dir
; /* endpoint direction */
67 volatile uint16_t *ep
; /* hw ep buffer */
68 int id
; /* Endpoint id */
69 int mask
; /* Endpoint bit mask */
70 char *buf
; /* user buffer to store data */
71 int max_len
; /* how match data will fit */
72 int count
; /* actual data count */
76 static struct tcc_ep tcc_endpoints
[] = {
80 .ep
= &TCC7xx_USB_EP0_BUF
,
83 .ep
= &TCC7xx_USB_EP1_BUF
,
86 .ep
= &TCC7xx_USB_EP2_BUF
,
89 .ep
= &TCC7xx_USB_EP3_BUF
,
93 static bool usb_drv_write_ep(struct tcc_ep
*ep
);
94 static void usb_set_speed(int);
96 int usb_drv_request_endpoint(int type
, int dir
)
98 int flags
= disable_irq_save();
102 if (type
!= USB_ENDPOINT_XFER_BULK
)
105 if (dir
== USB_DIR_IN
)
110 if (!tcc_endpoints
[ep
].busy
) {
111 tcc_endpoints
[ep
].busy
= true;
112 tcc_endpoints
[ep
].dir
= dir
;
122 void usb_drv_release_endpoint(int ep
)
127 if (ep
< 1 || ep
> USB_NUM_ENDPOINTS
)
130 flags
= disable_irq_save();
132 tcc_endpoints
[ep
].busy
= false;
133 tcc_endpoints
[ep
].dir
= -1;
138 static inline void pullup_on(void)
140 TCC7xx_USB_PHY_CFG
= 0x000c;
143 static inline void pullup_off(void)
145 TCC7xx_USB_PHY_CFG
= 0x3e4c;
150 char *dump_data(char *data
, int count
)
152 static char buf
[1024];
156 for (i
= 0; i
< count
; i
++)
157 dump
+= snprintf(dump
, sizeof(buf
) - (dump
- buf
), "%02x", data
[i
]);
163 void handle_control(void)
165 /* control are always 8 bytes len */
166 static unsigned char ep_control
[8];
167 struct usb_ctrlrequest
*req
=
168 (struct usb_ctrlrequest
*) ep_control
;
170 unsigned short count
= 0;
174 /* select control endpoint */
175 TCC7xx_USB_INDEX
= 0x00;
176 stat
= TCC7xx_USB_EP0_STAT
;
180 TCC7xx_USB_EP0_STAT
= 0x10;
183 if (TCC7xx_USB_EP0_STAT
& 0x01) { /* RX */
184 uint16_t *ptr
= (uint16_t *) ep_control
;
186 count
= TCC7xx_USB_EP_BRCR
;
188 if (TCC7xx_USB_EP0_STAT
& 0x2)
189 TCC7xx_USB_EP0_STAT
= 0x02;
191 if (count
!= 4) { /* bad control? */
192 unsigned short dummy
;
195 dummy
= TCC7xx_USB_EP0_BUF
;
196 DEBUG(1, "WTF: count = %d", count
);
198 /* simply read control packet */
199 for (i
= 0; i
< count
; i
++)
200 ptr
[i
] = TCC7xx_USB_EP0_BUF
;
204 TCC7xx_USB_EP0_STAT
= 0x01;
205 DEBUG(1, "CTRL: len = %d %04x", count
, stat
);
206 } else if (TCC7xx_USB_EP0_STAT
& 0x02) { /* TX */
207 TCC7xx_USB_EP0_STAT
= 0x02;
208 DEBUG(2, "TX Done\n");
210 DEBUG(1, "stat: %04x", stat
);
215 if (0 == (stat
& 0x1) || count
!= 8)
217 #if 1 /* TODO: remove me someday */
220 uint16_t *ptr
= (uint16_t *) ep_control
;
221 for (i
= 1; i
< (count
>>1); i
++) {
222 if (ptr
[i
] != ptr
[0])
225 if (i
== (count
>>1)) {
226 /*DEBUG(2, */panicf_my("sanity failed");
231 type
= req
->bRequestType
;
233 /* TODO: don't pass some kinds of requests to upper level */
234 switch (req
->bRequest
) {
235 case USB_REQ_CLEAR_FEATURE
:
236 DEBUG(2, "USB_REQ_CLEAR_FEATURE");
237 DEBUG(2, "...%04x %04x", req
->wValue
, req
->wIndex
);
239 case USB_REQ_SET_ADDRESS
:
240 //DEBUG(2, "USB_REQ_SET_ADDRESS, %d %d", req->wValue, TCC7xx_USB_FUNC);
241 /* seems we don't have to set it manually
242 TCC7xx_USB_FUNC = req->wValue; */
244 case USB_REQ_GET_DESCRIPTOR
:
245 DEBUG(2, "gd, %02x %02x", req
->wValue
, req
->wIndex
);
247 case USB_REQ_GET_CONFIGURATION
:
248 DEBUG(2, "USB_REQ_GET_CONFIGURATION");
251 DEBUG(2, "req: %02x %02d", req
->bRequestType
, req
->bRequest
);
254 usb_core_control_request(req
);
258 void handle_ep_in(struct tcc_ep
*tcc_ep
, uint16_t stat
)
260 uint8_t *buf
= tcc_ep
->buf
;
261 uint16_t *wbuf
= (uint16_t *) buf
;
266 if (tcc_ep
->dir
!= USB_DIR_OUT
) {
267 panicf_my("ep%d: is input only", tcc_ep
->id
);
270 wcount
= TCC7xx_USB_EP_BRCR
;
272 DEBUG(2, "ep%d: %04x %04x", tcc_ep
->id
, stat
, wcount
);
276 if (stat
& TCC7xx_USP_EP_STAT_LWO
) {
282 panicf_my("ep%d: Unexpected packet! %d %x", tcc_ep
->id
, count
, TCC7xx_USB_EP_CTRL
);
283 if (tcc_ep
->max_len
< count
)
284 panicf_my("Too big packet: %d excepted %d %x", count
, tcc_ep
->max_len
, TCC7xx_USB_EP_CTRL
);
286 for (i
= 0; i
< wcount
; i
++)
287 wbuf
[i
] = *tcc_ep
->ep
;
289 if (count
& 1) { /* lwo */
290 uint16_t tmp
= *tcc_ep
->ep
;
291 buf
[count
- 1] = tmp
& 0xff;
296 TCC7xx_USB_EP_STAT
= TCC7xx_USB_EP_STAT
;
297 TCC7xx_USB_EPIF
= tcc_ep
->mask
;
298 TCC7xx_USB_EPIE
&= ~tcc_ep
->mask
; /* TODO: use INGLD? */
299 global_ep_irq_mask
&= ~tcc_ep
->mask
;
301 if (TCC7xx_USB_EP_STAT
& 0x1)
302 panicf_my("One more packet?");
304 TCC7xx_USB_EP_CTRL
|= TCC7xx_USB_EP_CTRL_OUTHD
;
306 usb_core_transfer_complete(tcc_ep
->id
, USB_DIR_OUT
, 0, count
);
310 void handle_ep_out(struct tcc_ep
*tcc_ep
, uint16_t stat
)
315 if (tcc_ep
->dir
!= USB_DIR_IN
) {
316 panicf_my("ep%d: is out only", tcc_ep
->id
);
319 // if (tcc_ep->buf == NULL) {
320 // panicf_my("%s:%d", __FILE__, __LINE__);
323 done
= usb_drv_write_ep(tcc_ep
);
325 // TCC7xx_USB_EP_STAT = 0x2; /* Clear TX stat */
326 TCC7xx_USB_EPIF
= tcc_ep
->mask
;
328 if (done
) { // tcc_ep->buf == NULL) {
329 TCC7xx_USB_EPIE
&= ~tcc_ep
->mask
;
330 global_ep_irq_mask
&= ~tcc_ep
->mask
;
332 // usb_core_transfer_complete(tcc_ep->id, USB_DIR_IN, 0, tcc_ep->count);
337 void handle_ep(unsigned short ep_irq
)
346 for (endpoint
= 1; endpoint
< 4; endpoint
++) {
347 struct tcc_ep
*tcc_ep
= &tcc_endpoints
[endpoint
];
350 if (0 == (ep_irq
& (1 << endpoint
)))
353 panicf_my("ep%d: wasn't requested", endpoint
);
355 TCC7xx_USB_INDEX
= endpoint
;
356 stat
= TCC7xx_USB_EP_STAT
;
358 DEBUG(1, "ep%d: %04x", endpoint
, stat
);
361 handle_ep_in(tcc_ep
, stat
);
363 handle_ep_out(tcc_ep
, stat
);
364 else /* TODO: remove me? */
365 panicf_my("Unhandled ep%d state: %x, %d", endpoint
, TCC7xx_USB_EP_STAT
, TCC7xx_USB_INDEX
);
370 static void usb_set_speed(int high_speed
)
372 TCC7xx_USB_EP_DIR
= 0x0000;
374 /* control endpoint */
375 TCC7xx_USB_INDEX
= 0;
376 TCC7xx_USB_EP0_CTRL
= 0x0000;
377 TCC7xx_USB_EP_MAXP
= 64;
378 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
| TCC7xx_USB_EP_CTRL_FLUSH
;
380 /* ep1: bulk-in, to host */
381 TCC7xx_USB_INDEX
= 1;
382 TCC7xx_USB_EP_DIR
|= (1 << 1);
383 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
;
386 TCC7xx_USB_EP_MAXP
= 512;
388 TCC7xx_USB_EP_MAXP
= 64;
390 TCC7xx_USB_EP_DMA_CTRL
= 0x0;
392 /* ep2: bulk-out, from host */
393 TCC7xx_USB_INDEX
= 2;
394 TCC7xx_USB_EP_DIR
&= ~(1 << 2);
395 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
;
398 TCC7xx_USB_EP_MAXP
= 512;
400 TCC7xx_USB_EP_MAXP
= 64;
402 TCC7xx_USB_EP_DMA_CTRL
= 0x0;
404 /* ep3: interrupt in */
405 TCC7xx_USB_INDEX
= 3;
406 TCC7xx_USB_EP_DIR
&= ~(1 << 3);
407 TCC7xx_USB_EP_CTRL
= TCC7xx_USB_EP_CTRL_CDP
;
408 TCC7xx_USB_EP_MAXP
= 64;
410 TCC7xx_USB_EP_DMA_CTRL
= 0x0;
414 Reset TCC7xx usb device
416 static void usb_reset(void)
420 TCC7xx_USB_DELAY_CTRL
|= 0x81;
422 TCC7xx_USB_SYS_CTRL
= 0xa000 |
423 TCC7xx_USB_SYS_CTRL_RESET
|
424 TCC7xx_USB_SYS_CTRL_RFRE
|
425 TCC7xx_USB_SYS_CTRL_SPDEN
|
426 TCC7xx_USB_SYS_CTRL_VBONE
|
427 TCC7xx_USB_SYS_CTRL_VBOFE
;
432 TCC7xx_USB_EPIF
= TCC7xx_USB_EPIF_IRQ_MASK
;
433 global_ep_irq_mask
= 0x1;
434 TCC7xx_USB_EPIE
= global_ep_irq_mask
;
436 usb_core_bus_reset();
440 void USB_DEVICE(void)
442 unsigned short sys_stat
;
443 unsigned short ep_irq
;
444 unsigned short index_save
;
446 sys_stat
= TCC7xx_USB_SYS_STAT
;
448 if (sys_stat
& TCC7xx_USB_SYS_STAT_RESET
) {
449 TCC7xx_USB_SYS_STAT
= TCC7xx_USB_SYS_STAT_RESET
;
451 TCC7xx_USB_SYS_CTRL
|= TCC7xx_USB_SYS_CTRL_SUSPEND
;
455 if (sys_stat
& TCC7xx_USB_SYS_STAT_RESUME
) {
456 TCC7xx_USB_SYS_STAT
= TCC7xx_USB_SYS_STAT_RESUME
;
458 TCC7xx_USB_SYS_CTRL
|= TCC7xx_USB_SYS_CTRL_SUSPEND
;
462 if (sys_stat
& TCC7xx_USB_SYS_STAT_SPD_END
) {
464 TCC7xx_USB_SYS_STAT
= TCC7xx_USB_SYS_STAT_SPD_END
;
468 if (sys_stat
& TCC7xx_USB_SYS_STAT_ERRORS
) {
469 DEBUG(2, "errors: %4x", sys_stat
& TCC7xx_USB_SYS_STAT_ERRORS
);
470 TCC7xx_USB_SYS_STAT
= sys_stat
& TCC7xx_USB_SYS_STAT_ERRORS
;
473 // TCC7xx_USB_SYS_STAT = sys_stat;
475 index_save
= TCC7xx_USB_INDEX
;
477 ep_irq
= TCC7xx_USB_EPIF
& global_ep_irq_mask
;
479 while (ep_irq
& TCC7xx_USB_EPIF_IRQ_MASK
) {
482 /* is that really needed, btw not a problem for rockbox */
484 ep_irq
= TCC7xx_USB_EPIF
& global_ep_irq_mask
;
487 TCC7xx_USB_INDEX
= index_save
;
490 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__
,
632 (unsigned int)tcc_ep
->buf
, (unsigned int)tcc_ep
);
636 tcc_ep
->max_len
= length
;
639 TCC7xx_USB_INDEX
= tcc_ep
->id
;
641 TCC7xx_USB_EP_CTRL
&= ~TCC7xx_USB_EP_CTRL_OUTHD
;
642 TCC7xx_USB_EPIE
|= tcc_ep
->mask
;
643 global_ep_irq_mask
|= tcc_ep
->mask
;
650 void usb_drv_cancel_all_transfers(void)
655 DEBUG(2, "%s", __func__
);
657 flags
= disable_irq_save();
658 for (endpoint
= 0; endpoint
< 4; endpoint
++) {
659 if (tcc_endpoints
[endpoint
].buf
) {
660 /* usb_core_transfer_complete(tcc_endpoints[endpoint].id,
661 tcc_endpoints[endpoint].dir, -1, 0); */
662 tcc_endpoints
[endpoint
].buf
= NULL
;
666 global_ep_irq_mask
= 1;
667 TCC7xx_USB_EPIE
= global_ep_irq_mask
;
668 TCC7xx_USB_EPIF
= TCC7xx_USB_EPIF_IRQ_MASK
;
672 void usb_drv_set_test_mode(int mode
)
674 panicf_my("%s(%d)", __func__
, mode
);
677 bool usb_drv_stalled(int endpoint
, bool in
)
679 panicf_my("%s(%d,%d)", __func__
, endpoint
, in
);
683 void usb_drv_stall(int endpoint
, bool stall
,bool in
)
688 printf("%s(%d,%d,%d)", __func__
, endpoint
, stall
, in
);
691 void usb_drv_init(void)
695 DEBUG(2, "%s", __func__
);
697 for (i
= 0; i
< sizeof(tcc_endpoints
)/sizeof(struct tcc_ep
); i
++) {
698 tcc_endpoints
[i
].id
= i
;
699 tcc_endpoints
[i
].mask
= 1 << i
;
700 tcc_endpoints
[i
].buf
= NULL
;
701 tcc_endpoints
[i
].busy
= false;
702 tcc_endpoints
[i
].dir
= -1;
705 /* Enable USB clock */
708 /* switch USB to host and then reset */
709 TCC7xx_USB_PHY_CFG
= 0x3e4c;
712 SWRESET
&= ~DEV_USBD
;
717 CREQ
= USBD_IRQ_MASK
;
718 IRQSEL
|= USBD_IRQ_MASK
;
719 TMODE
&= ~USBD_IRQ_MASK
;
720 IEN
|= USBD_IRQ_MASK
;
723 void usb_drv_exit(void)
726 BCLKCTR
&= ~DEV_USBD
;
730 SWRESET
&= ~DEV_USBD
;
735 void usb_init_device(void)
739 void usb_enable(bool on
)
747 void usb_attach(void)
754 /* TODO: not correct for all targets, we should poll VBUS
755 signal on USB bus. */
756 if (charger_inserted())
758 return USB_EXTRACTED
;
771 panicf("ata_init failed");
775 usb_start_monitoring();
776 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
780 // usb_serial_send("Hello\r\n", 7);
785 void usb_init_device(void)
787 /* simply switch USB off for now */
789 TCC7xx_USB_PHY_CFG
= 0x3e4c;
790 BCLKCTR
&= ~DEV_USBD
;
793 void usb_enable(bool on
)
798 /* Always return false for now */
801 return USB_EXTRACTED
;