summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2010-06-23 22:03:31 +0000
committerAmaury Pouly <pamaury@rockbox.org>2010-06-23 22:03:31 +0000
commit237d9666ccd5d35db920df640e493ceec8962aaa (patch)
treefda1100af5181f9d71927070c24a5a3383c04680
parent58ad1e7c4b7e404d0bcda752914e2878c68feafd (diff)
downloadrockbox-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
-rw-r--r--firmware/export/as3525v2.h6
-rw-r--r--firmware/target/arm/as3525/usb-drv-as3525v2.c262
-rw-r--r--firmware/target/arm/as3525/usb-drv-as3525v2.h5
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
39static int __in_ep_list[NUM_IN_EP] = {IN_EP_LIST}; 39static int __in_ep_list[NUM_IN_EP] = {IN_EP_LIST};
40static int __out_ep_list[NUM_OUT_EP] = {OUT_EP_LIST}; 40static int __out_ep_list[NUM_OUT_EP] = {OUT_EP_LIST};
41static int __in_ep_list_ep0[NUM_IN_EP + 1] = {0, IN_EP_LIST};
42static 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
50struct usb_endpoint 58struct 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
64static 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 */
66static struct usb_ctrlrequest ep0_setup_pkt __attribute__((aligned(16))); 71static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS];
72static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR;
67 73
68void usb_attach(void) 74void 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
384static void dump_regs(void) 387static 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
403static 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
424static 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
448static bool handle_in_ep_int(void)
449{
450 panicf("usb: in ep int");
451 return false;
452} 458}
453 459
454static bool handle_out_ep_int(void) 460static 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
507int usb_drv_port_speed(void) 539int 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