diff options
author | Amaury Pouly <pamaury@rockbox.org> | 2010-06-23 22:03:31 +0000 |
---|---|---|
committer | Amaury Pouly <pamaury@rockbox.org> | 2010-06-23 22:03:31 +0000 |
commit | 237d9666ccd5d35db920df640e493ceec8962aaa (patch) | |
tree | fda1100af5181f9d71927070c24a5a3383c04680 /firmware | |
parent | 58ad1e7c4b7e404d0bcda752914e2878c68feafd (diff) | |
download | rockbox-237d9666ccd5d35db920df640e493ceec8962aaa.tar.gz rockbox-237d9666ccd5d35db920df640e493ceec8962aaa.zip |
as3525v2-usb: define number of enpoints correctly, write interrupt handler
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27098 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/as3525v2.h | 6 | ||||
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.c | 262 | ||||
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.h | 5 |
3 files changed, 156 insertions, 117 deletions
diff --git a/firmware/export/as3525v2.h b/firmware/export/as3525v2.h index d7c188cea8..4b719a905a 100644 --- a/firmware/export/as3525v2.h +++ b/firmware/export/as3525v2.h | |||
@@ -34,4 +34,10 @@ | |||
34 | 34 | ||
35 | #define CGU_SDSLOT (*(volatile unsigned long *)(CGU_BASE + 0x3C)) | 35 | #define CGU_SDSLOT (*(volatile unsigned long *)(CGU_BASE + 0x3C)) |
36 | 36 | ||
37 | #ifdef USB_NUM_ENDPOINTS | ||
38 | #undef USB_NUM_ENDPOINTS | ||
39 | #endif | ||
40 | |||
41 | #define USB_NUM_ENDPOINTS 6 | ||
42 | |||
37 | #endif /* __AS3525V2_H__ */ | 43 | #endif /* __AS3525V2_H__ */ |
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.c b/firmware/target/arm/as3525/usb-drv-as3525v2.c index 5e3a325a02..cea87159a6 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.c +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.c | |||
@@ -38,32 +38,38 @@ | |||
38 | 38 | ||
39 | static int __in_ep_list[NUM_IN_EP] = {IN_EP_LIST}; | 39 | static int __in_ep_list[NUM_IN_EP] = {IN_EP_LIST}; |
40 | static int __out_ep_list[NUM_OUT_EP] = {OUT_EP_LIST}; | 40 | static int __out_ep_list[NUM_OUT_EP] = {OUT_EP_LIST}; |
41 | static int __in_ep_list_ep0[NUM_IN_EP + 1] = {0, IN_EP_LIST}; | ||
42 | static int __out_ep_list_ep0[NUM_OUT_EP + 1] = {0, OUT_EP_LIST}; | ||
41 | 43 | ||
42 | /* iterate through each in/out ep except EP0 | 44 | /* iterate through each in/out ep except EP0 |
43 | * 'counter' is the counter, 'ep' is the actual value */ | 45 | * 'counter' is the counter, 'ep' is the actual value */ |
44 | #define FOR_EACH_IN_EP(counter, ep) \ | 46 | #define FOR_EACH_IN_EP(counter, ep) \ |
45 | for(counter = 0, ep = __in_ep_list[0]; counter < NUM_IN_EP; counter++, ep = __in_ep_list[counter]) | 47 | for(counter = 0, ep = __in_ep_list[0]; counter < NUM_IN_EP; counter++, ep = __in_ep_list[counter]) |
46 | 48 | ||
49 | #define FOR_EACH_IN_EP_AND_EP0(counter, ep) \ | ||
50 | for(counter = 0, ep = __in_ep_list_ep0[0]; counter <= NUM_IN_EP; counter++, ep = __in_ep_list_ep0[counter]) | ||
51 | |||
47 | #define FOR_EACH_OUT_EP(counter, ep) \ | 52 | #define FOR_EACH_OUT_EP(counter, ep) \ |
48 | for(counter = 0, ep = __out_ep_list[0]; counter < NUM_OUT_EP; counter++, ep = __out_ep_list[counter]) | 53 | for(counter = 0, ep = __out_ep_list[0]; counter < NUM_OUT_EP; counter++, ep = __out_ep_list[counter]) |
49 | 54 | ||
55 | #define FOR_EACH_OUT_EP_AND_EP0(counter, ep) \ | ||
56 | for(counter = 0, ep = __out_ep_list_ep0[0]; counter <= NUM_OUT_EP; counter++, ep = __out_ep_list_ep0[counter]) | ||
57 | |||
50 | struct usb_endpoint | 58 | struct usb_endpoint |
51 | { | 59 | { |
52 | void *buf; | ||
53 | unsigned int len; | 60 | unsigned int len; |
54 | union | ||
55 | { | ||
56 | unsigned int sent; | ||
57 | unsigned int received; | ||
58 | }; | ||
59 | bool wait; | 61 | bool wait; |
60 | bool busy; | 62 | bool busy; |
63 | bool done; | ||
64 | int status; | ||
65 | struct wakeup complete; | ||
61 | }; | 66 | }; |
62 | 67 | ||
63 | #if 0 | 68 | /* NOTE: the following structure is not used to EP0 |
64 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2]; | 69 | * and make the assumption that each endpoint is |
65 | #endif | 70 | * either IN or OUT but not bidirectional */ |
66 | static struct usb_ctrlrequest ep0_setup_pkt __attribute__((aligned(16))); | 71 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS]; |
72 | static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR; | ||
67 | 73 | ||
68 | void usb_attach(void) | 74 | void usb_attach(void) |
69 | { | 75 | { |
@@ -175,10 +181,9 @@ static void reset_endpoints(void) | |||
175 | /* Setup EP0 OUT with the following parameters: | 181 | /* Setup EP0 OUT with the following parameters: |
176 | * packet count = 1 | 182 | * packet count = 1 |
177 | * setup packet count = 1 | 183 | * setup packet count = 1 |
178 | * transfer size = 64 | 184 | * transfer size = 8 (setup packet) |
179 | * Setup EP0 IN/OUT with 64 byte maximum packet size and activate both. Enable transfer on EP0 OUT | 185 | * Setup EP0 IN/OUT with 64 byte maximum packet size and activate both. Enable transfer on EP0 OUT |
180 | */ | 186 | */ |
181 | |||
182 | DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) | 187 | DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) |
183 | | (1 << DEPTSIZ0_pkcnt_bitp) | 188 | | (1 << DEPTSIZ0_pkcnt_bitp) |
184 | | 8; | 189 | | 8; |
@@ -305,10 +310,8 @@ static void core_dev_init(void) | |||
305 | 310 | ||
306 | /* Setup interrupt masks for endpoints */ | 311 | /* Setup interrupt masks for endpoints */ |
307 | /* Setup interrupt masks */ | 312 | /* Setup interrupt masks */ |
308 | DOEPMSK = DOEPINT_setup | DOEPINT_xfercompl | DOEPINT_ahberr | 313 | DOEPMSK = DOEPINT_setup | DOEPINT_xfercompl | DOEPINT_ahberr; |
309 | | DOEPINT_epdisabled; | 314 | DIEPMSK = DIEPINT_xfercompl | DIEPINT_timeout | DIEPINT_ahberr; |
310 | DIEPMSK = DIEPINT_xfercompl | DIEPINT_timeout | ||
311 | | DIEPINT_epdisabled | DIEPINT_ahberr; | ||
312 | DAINTMSK = 0xffffffff; | 315 | DAINTMSK = 0xffffffff; |
313 | 316 | ||
314 | reset_endpoints(); | 317 | reset_endpoints(); |
@@ -381,80 +384,95 @@ void usb_drv_exit(void) | |||
381 | disable_global_interrupts(); | 384 | disable_global_interrupts(); |
382 | } | 385 | } |
383 | 386 | ||
384 | static void dump_regs(void) | 387 | static void handle_ep_int(int ep, bool dir_in) |
385 | { | 388 | { |
386 | logf("DSTS: %lx", DSTS); | 389 | if(dir_in) |
387 | logf("DOEPCTL0=%lx", DOEPCTL(0)); | ||
388 | logf("DOEPTSIZ=%lx", DOEPTSIZ(0)); | ||
389 | logf("DIEPCTL0=%lx", DIEPCTL(0)); | ||
390 | logf("DOEPMSK=%lx", DOEPMSK); | ||
391 | logf("DIEPMSK=%lx", DIEPMSK); | ||
392 | logf("DAINTMSK=%lx", DAINTMSK); | ||
393 | logf("DAINT=%lx", DAINT); | ||
394 | logf("GINTSTS=%lx", GINTSTS); | ||
395 | logf("GINTMSK=%lx", GINTMSK); | ||
396 | logf("DCTL=%lx", DCTL); | ||
397 | logf("GAHBCFG=%lx", GAHBCFG); | ||
398 | logf("GUSBCFG=%lx", GUSBCFG); | ||
399 | logf("DCFG=%lx", DCFG); | ||
400 | logf("DTHRCTL=%lx", DTHRCTL); | ||
401 | } | ||
402 | |||
403 | static bool handle_reset(void) | ||
404 | { | ||
405 | logf("usb: bus reset"); | ||
406 | |||
407 | dump_regs(); | ||
408 | /* Clear the Remote Wakeup Signalling */ | ||
409 | DCTL &= ~DCTL_rmtwkupsig; | ||
410 | |||
411 | /* Flush FIFOs */ | ||
412 | flush_tx_fifos(0x10); | ||
413 | |||
414 | reset_endpoints(); | ||
415 | |||
416 | /* Reset Device Address */ | ||
417 | DCFG &= bitm(DCFG, devadr); | ||
418 | |||
419 | usb_core_bus_reset(); | ||
420 | |||
421 | return true; | ||
422 | } | ||
423 | |||
424 | static bool handle_enum_done(void) | ||
425 | { | ||
426 | logf("usb: enum done"); | ||
427 | |||
428 | /* read speed */ | ||
429 | switch(extract(DSTS, enumspd)) | ||
430 | { | 390 | { |
431 | case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: | 391 | if(DIEPINT(ep) & DIEPINT_ahberr) |
432 | logf("usb: HS"); | 392 | panicf("usb: ahb error on EP%d IN", ep); |
433 | break; | 393 | if(DIEPINT(ep) & DIEPINT_xfercompl) |
434 | case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: | 394 | { |
435 | case DSTS_ENUMSPD_FS_PHY_48MHZ: | 395 | logf("usb: xfer complete on EP%d IN", ep); |
436 | logf("usb: FS"); | 396 | if(endpoints[ep].busy) |
437 | break; | 397 | { |
438 | case DSTS_ENUMSPD_LS_PHY_6MHZ: | 398 | endpoints[ep].busy = false; |
439 | panicf("usb: LS is not supported"); | 399 | endpoints[ep].status = 0; |
400 | endpoints[ep].done = true; | ||
401 | /* works even for PE0 */ | ||
402 | int transfered = endpoints[ep].len - (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits); | ||
403 | clean_dcache_range((void *)DIEPDMA(ep), transfered); | ||
404 | usb_core_transfer_complete(ep, USB_DIR_IN, 0, transfered); | ||
405 | } | ||
406 | } | ||
407 | if(DIEPINT(ep) & DIEPINT_timeout) | ||
408 | { | ||
409 | logf("usb: timeout on EP%d IN", ep); | ||
410 | if(endpoints[ep].busy) | ||
411 | { | ||
412 | endpoints[ep].busy = false; | ||
413 | endpoints[ep].status = 1; | ||
414 | endpoints[ep].done = true; | ||
415 | /* for safety, act as if no bytes as been transfered */ | ||
416 | endpoints[ep].len = 0; | ||
417 | usb_core_transfer_complete(ep, USB_DIR_IN, 1, 0); | ||
418 | wakeup_signal(&endpoints[ep].complete); | ||
419 | } | ||
420 | } | ||
421 | /* clear interrupts */ | ||
422 | DIEPINT(ep) = DIEPINT(ep); | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | if(DOEPINT(ep) & DOEPINT_ahberr) | ||
427 | panicf("usb: ahb error on EP%d OUT", ep); | ||
428 | if(DOEPINT(ep) & DOEPINT_xfercompl) | ||
429 | { | ||
430 | logf("usb: xfer complete on EP%d OUT", ep); | ||
431 | if(endpoints[ep].busy) | ||
432 | { | ||
433 | endpoints[ep].busy = false; | ||
434 | endpoints[ep].status = 0; | ||
435 | endpoints[ep].done = true; | ||
436 | /* works even for PE0 */ | ||
437 | int transfered = endpoints[ep].len - (DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits); | ||
438 | clean_dcache_range((void *)DOEPDMA(ep), transfered); | ||
439 | usb_core_transfer_complete(ep, USB_DIR_OUT, 0, transfered); | ||
440 | } | ||
441 | } | ||
442 | if(DOEPINT(ep) & DOEPINT_setup) | ||
443 | { | ||
444 | logf("usb: setup on EP%d OUT", ep); | ||
445 | if(ep != 0) | ||
446 | panicf("usb: setup not on EP0, this is impossible"); | ||
447 | clean_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */ | ||
448 | usb_core_control_request(&ep0_setup_pkt); | ||
449 | } | ||
450 | /* setup EP0 for the next transfer */ | ||
451 | DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) | (1 << DEPTSIZ0_pkcnt_bitp) | 8; | ||
452 | DOEPDMA(0) = (unsigned long)&ep0_setup_pkt; /* virtual address=physical address */ | ||
453 | DOEPCTL(0) |= DEPCTL_epena | DEPCTL_cnak; | ||
454 | |||
455 | /* clear interrupts */ | ||
456 | DOEPINT(ep) = DOEPINT(ep); | ||
440 | } | 457 | } |
441 | |||
442 | /* fixme: change EP0 mps here */ | ||
443 | dump_regs(); | ||
444 | |||
445 | return true; | ||
446 | } | ||
447 | |||
448 | static bool handle_in_ep_int(void) | ||
449 | { | ||
450 | panicf("usb: in ep int"); | ||
451 | return false; | ||
452 | } | 458 | } |
453 | 459 | ||
454 | static bool handle_out_ep_int(void) | 460 | static void handle_ep_ints(void) |
455 | { | 461 | { |
456 | panicf("usb: out ep int"); | 462 | logf("usb: ep int"); |
457 | return false; | 463 | /* we must read it */ |
464 | unsigned long daint = DAINT; | ||
465 | unsigned i, ep; | ||
466 | |||
467 | FOR_EACH_IN_EP_AND_EP0(i, ep) | ||
468 | if(daint & DAINT_IN_EP(ep)) | ||
469 | handle_ep_int(ep, true); | ||
470 | FOR_EACH_OUT_EP_AND_EP0(i, ep) | ||
471 | if(daint & DAINT_OUT_EP(ep)) | ||
472 | handle_ep_int(ep, false); | ||
473 | |||
474 | /* write back to clear status */ | ||
475 | DAINT = daint; | ||
458 | } | 476 | } |
459 | 477 | ||
460 | /* interrupt service routine */ | 478 | /* interrupt service routine */ |
@@ -463,45 +481,59 @@ void INT_USB(void) | |||
463 | /* some bits in GINTSTS can be set even though we didn't enable the interrupt source | 481 | /* some bits in GINTSTS can be set even though we didn't enable the interrupt source |
464 | * so AND it with the actual mask */ | 482 | * so AND it with the actual mask */ |
465 | unsigned long sts = GINTSTS & GINTMSK; | 483 | unsigned long sts = GINTSTS & GINTMSK; |
466 | unsigned long handled_one = 0; /* mask of all listed one (either handled or not) */ | ||
467 | |||
468 | #define HANDLED_CASE(bitmask, callfn) \ | ||
469 | handled_one |= bitmask; \ | ||
470 | if(sts & bitmask) \ | ||
471 | { \ | ||
472 | if(!callfn()) \ | ||
473 | goto Lerr; \ | ||
474 | } | ||
475 | |||
476 | #define UNHANDLED_CASE(bitmask) \ | ||
477 | handled_one |= bitmask; \ | ||
478 | if(sts & bitmask) \ | ||
479 | goto Lunhandled; | ||
480 | 484 | ||
481 | /* device part */ | 485 | /* device part */ |
482 | HANDLED_CASE(GINTMSK_usbreset, handle_reset) | 486 | if(sts & GINTMSK_usbreset) |
483 | HANDLED_CASE(GINTMSK_enumdone, handle_enum_done) | 487 | { |
484 | HANDLED_CASE(GINTMSK_inepintr, handle_in_ep_int) | 488 | logf("usb: bus reset"); |
485 | HANDLED_CASE(GINTMSK_outepintr, handle_out_ep_int) | ||
486 | 489 | ||
487 | /* common part */ | 490 | /* Clear the Remote Wakeup Signalling */ |
488 | UNHANDLED_CASE(GINTMSK_otgintr) | 491 | DCTL &= ~DCTL_rmtwkupsig; |
489 | UNHANDLED_CASE(GINTMSK_conidstschng) | ||
490 | UNHANDLED_CASE(GINTMSK_disconnect) | ||
491 | 492 | ||
492 | /* unlisted ones */ | 493 | /* Flush FIFOs */ |
493 | if(sts & ~handled_one) | 494 | flush_tx_fifos(0x10); |
494 | goto Lunhandled; | ||
495 | 495 | ||
496 | GINTSTS = GINTSTS; | 496 | reset_endpoints(); |
497 | |||
498 | /* Reset Device Address */ | ||
499 | DCFG &= bitm(DCFG, devadr); | ||
500 | |||
501 | usb_core_bus_reset(); | ||
502 | } | ||
503 | |||
504 | if(sts & GINTMSK_enumdone) | ||
505 | { | ||
506 | logf("usb: enum done"); | ||
507 | |||
508 | /* read speed */ | ||
509 | switch(extract(DSTS, enumspd)) | ||
510 | { | ||
511 | case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: | ||
512 | logf("usb: HS"); | ||
513 | break; | ||
514 | case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: | ||
515 | case DSTS_ENUMSPD_FS_PHY_48MHZ: | ||
516 | logf("usb: FS"); | ||
517 | break; | ||
518 | case DSTS_ENUMSPD_LS_PHY_6MHZ: | ||
519 | panicf("usb: LS is not supported"); | ||
520 | } | ||
521 | |||
522 | /* fixme: change EP0 mps here */ | ||
523 | } | ||
497 | 524 | ||
498 | return; | 525 | if(sts & (GINTMSK_outepintr | GINTMSK_inepintr)) |
526 | { | ||
527 | handle_ep_ints(); | ||
528 | } | ||
499 | 529 | ||
500 | Lunhandled: | 530 | /* common part */ |
501 | panicf("unhandled usb int: %lx", sts); | 531 | if(sts & GINTMSK_otgintr) |
532 | { | ||
533 | panicf("usb: otg int"); | ||
534 | } | ||
502 | 535 | ||
503 | Lerr: | 536 | GINTSTS = GINTSTS; |
504 | panicf("error in usb int: %lx", sts); | ||
505 | } | 537 | } |
506 | 538 | ||
507 | int usb_drv_port_speed(void) | 539 | int usb_drv_port_speed(void) |
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.h b/firmware/target/arm/as3525/usb-drv-as3525v2.h index 78df811d11..be4b2da992 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.h +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.h | |||
@@ -421,7 +421,8 @@ | |||
421 | #define DOEPTSIZ(ep) DEV_REG(0x300 + (ep) * 0x20 + 0x10) | 421 | #define DOEPTSIZ(ep) DEV_REG(0x300 + (ep) * 0x20 + 0x10) |
422 | 422 | ||
423 | /* valid for any D{I,O}EPTSIZi with 1<=i<=15, NOT for i=0 ! */ | 423 | /* valid for any D{I,O}EPTSIZi with 1<=i<=15, NOT for i=0 ! */ |
424 | #define DEPTSIZ_xfersize_bits 0x7ffff /** Transfer Size */ | 424 | #define DEPTSIZ_xfersize_bitp 0 /** Transfer Size */ |
425 | #define DEPTSIZ_xfersize_bits 0x7ffff | ||
425 | #define DEPTSIZ_pkcnt_bitp 19 /** Packet Count */ | 426 | #define DEPTSIZ_pkcnt_bitp 19 /** Packet Count */ |
426 | #define DEPTSIZ_pkcnt_bits 0x3ff | 427 | #define DEPTSIZ_pkcnt_bits 0x3ff |
427 | #define DEPTSIZ_mc_bitp 29 /** Multi Count - Periodic IN endpoints */ | 428 | #define DEPTSIZ_mc_bitp 29 /** Multi Count - Periodic IN endpoints */ |
@@ -452,7 +453,7 @@ | |||
452 | /** | 453 | /** |
453 | * Parameters | 454 | * Parameters |
454 | */ | 455 | */ |
455 | #define USE_CUSTOM_FIFO_LAYOUT | 456 | /*#define USE_CUSTOM_FIFO_LAYOUT*/ |
456 | 457 | ||
457 | #ifdef USE_CUSTOM_FIFO_LAYOUT | 458 | #ifdef USE_CUSTOM_FIFO_LAYOUT |
458 | /* Data fifo: includes RX fifo, non period TX fifo and periodic fifos | 459 | /* Data fifo: includes RX fifo, non period TX fifo and periodic fifos |