diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525.c | 97 |
1 files changed, 45 insertions, 52 deletions
diff --git a/firmware/target/arm/as3525/usb-drv-as3525.c b/firmware/target/arm/as3525/usb-drv-as3525.c index 61a1265f42..ca484d0395 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525.c +++ b/firmware/target/arm/as3525/usb-drv-as3525.c | |||
@@ -53,7 +53,9 @@ typedef struct { | |||
53 | /* 4 input endpoints */ | 53 | /* 4 input endpoints */ |
54 | #define USB_IEP_CTRL(i) USB_REG(0x0000 + i*0x20) | 54 | #define USB_IEP_CTRL(i) USB_REG(0x0000 + i*0x20) |
55 | #define USB_IEP_STS(i) USB_REG(0x0004 + i*0x20) | 55 | #define USB_IEP_STS(i) USB_REG(0x0004 + i*0x20) |
56 | /* txfsize: bits 0-15 */ | ||
56 | #define USB_IEP_TXFSIZE(i) USB_REG(0x0008 + i*0x20) | 57 | #define USB_IEP_TXFSIZE(i) USB_REG(0x0008 + i*0x20) |
58 | /* mps: bits 0-10 (max 2047) */ | ||
57 | #define USB_IEP_MPS(i) USB_REG(0x000C + i*0x20) | 59 | #define USB_IEP_MPS(i) USB_REG(0x000C + i*0x20) |
58 | #define USB_IEP_DESC_PTR(i) USB_REG(0x0014 + i*0x20) | 60 | #define USB_IEP_DESC_PTR(i) USB_REG(0x0014 + i*0x20) |
59 | #define USB_IEP_STS_MASK(i) USB_REG(0x0018 + i*0x20) | 61 | #define USB_IEP_STS_MASK(i) USB_REG(0x0018 + i*0x20) |
@@ -61,7 +63,9 @@ typedef struct { | |||
61 | /* 4 output endpoints */ | 63 | /* 4 output endpoints */ |
62 | #define USB_OEP_CTRL(i) USB_REG(0x0200 + i*0x20) | 64 | #define USB_OEP_CTRL(i) USB_REG(0x0200 + i*0x20) |
63 | #define USB_OEP_STS(i) USB_REG(0x0204 + i*0x20) | 65 | #define USB_OEP_STS(i) USB_REG(0x0204 + i*0x20) |
66 | /* 'rx packet frame number' */ | ||
64 | #define USB_OEP_RXFR(i) USB_REG(0x0208 + i*0x20) | 67 | #define USB_OEP_RXFR(i) USB_REG(0x0208 + i*0x20) |
68 | /* mps: bits 0-10 (max 2047), bits 23-31 are fifo size */ | ||
65 | #define USB_OEP_MPS(i) USB_REG(0x020C + i*0x20) | 69 | #define USB_OEP_MPS(i) USB_REG(0x020C + i*0x20) |
66 | #define USB_OEP_SUP_PTR(i) USB_REG(0x0210 + i*0x20) | 70 | #define USB_OEP_SUP_PTR(i) USB_REG(0x0210 + i*0x20) |
67 | #define USB_OEP_DESC_PTR(i) USB_REG(0x0214 + i*0x20) | 71 | #define USB_OEP_DESC_PTR(i) USB_REG(0x0214 + i*0x20) |
@@ -298,13 +302,8 @@ static struct usb_endpoint endpoints[USB_NUM_EPS][2]; | |||
298 | * dmadescs may share with each other, since we only access them uncached. | 302 | * dmadescs may share with each other, since we only access them uncached. |
299 | */ | 303 | */ |
300 | static struct usb_dev_dma_desc dmadescs[USB_NUM_EPS][2] __attribute__((aligned(32))); | 304 | static struct usb_dev_dma_desc dmadescs[USB_NUM_EPS][2] __attribute__((aligned(32))); |
301 | 305 | /* reuse unused EP2 OUT descriptor here */ | |
302 | static struct usb_dev_setup_buf setup_desc; | 306 | static struct usb_dev_setup_buf *setup_desc = (void*)&dmadescs[2][1]; |
303 | /* Dummy buffer, to keep rx_buf out of this cacheline */ | ||
304 | static struct usb_dev_setup_buf dummy __attribute__((unused)); | ||
305 | |||
306 | static char rx_buf[1024]; | ||
307 | static char tx_buf[1024]; | ||
308 | 307 | ||
309 | #if AS3525_MCLK_SEL != AS3525_CLK_PLLB | 308 | #if AS3525_MCLK_SEL != AS3525_CLK_PLLB |
310 | static inline void usb_enable_pll(void) | 309 | static inline void usb_enable_pll(void) |
@@ -402,17 +401,12 @@ static void dma_desc_init(int ep, int dir) | |||
402 | 401 | ||
403 | endpoints[ep][dir].uc_desc = uc_desc; | 402 | endpoints[ep][dir].uc_desc = uc_desc; |
404 | 403 | ||
405 | if (dir == 0) { | 404 | uc_desc->status = USB_DMA_DESC_BS_DMA_DONE | \ |
406 | uc_desc->status = USB_DMA_DESC_BS_DMA_DONE | USB_DMA_DESC_LAST | 0x40; | 405 | USB_DMA_DESC_LAST | \ |
407 | uc_desc->resv = 0xffffffff; | 406 | USB_DMA_DESC_ZERO_LEN; |
408 | uc_desc->data_ptr = tx_buf; | 407 | uc_desc->resv = 0xffffffff; |
409 | uc_desc->next_desc = 0; | 408 | uc_desc->data_ptr = 0; |
410 | } else { | 409 | uc_desc->next_desc = 0; |
411 | uc_desc->status = USB_DMA_DESC_BS_HST_RDY | /*USB_DMA_DESC_LAST |*/ 0x40; | ||
412 | uc_desc->resv = 0xffffffff; | ||
413 | uc_desc->data_ptr = rx_buf; | ||
414 | uc_desc->next_desc = 0; | ||
415 | } | ||
416 | } | 410 | } |
417 | 411 | ||
418 | static void reset_endpoints(int init) | 412 | static void reset_endpoints(int init) |
@@ -430,7 +424,13 @@ static void reset_endpoints(int init) | |||
430 | endpoints[2][1].state |= EP_STATE_ALLOCATED; | 424 | endpoints[2][1].state |= EP_STATE_ALLOCATED; |
431 | 425 | ||
432 | for(i = 0; i < USB_NUM_EPS; i++) { | 426 | for(i = 0; i < USB_NUM_EPS; i++) { |
433 | int mps = i == 0 ? 64 : 2048; /* For HS */ | 427 | /* |
428 | * LS: 8 (control), no bulk available | ||
429 | * FS: 64 (control), 64 (bulk) | ||
430 | * HS: 64 (control), 512 (bulk) | ||
431 | * TODO: switch depending on speed. | ||
432 | */ | ||
433 | int mps = i == 0 ? 64 : 512; | ||
434 | 434 | ||
435 | if (init) { | 435 | if (init) { |
436 | endpoints[i][0].state = 0; | 436 | endpoints[i][0].state = 0; |
@@ -448,23 +448,23 @@ static void reset_endpoints(int init) | |||
448 | USB_IEP_MPS (i) = mps; | 448 | USB_IEP_MPS (i) = mps; |
449 | /* We don't care about the 'IN token received' event */ | 449 | /* We don't care about the 'IN token received' event */ |
450 | USB_IEP_STS_MASK(i) = USB_EP_STAT_IN; /* OF: 0x840 */ | 450 | USB_IEP_STS_MASK(i) = USB_EP_STAT_IN; /* OF: 0x840 */ |
451 | USB_IEP_TXFSIZE (i) = 0x20; | 451 | USB_IEP_TXFSIZE (i) = mps/2; |
452 | USB_IEP_STS (i) = 0xffffffff; /* clear status */ | 452 | USB_IEP_STS (i) = 0xffffffff; /* clear status */ |
453 | USB_IEP_DESC_PTR(i) = 0; | 453 | USB_IEP_DESC_PTR(i) = 0; |
454 | 454 | ||
455 | if (i != 2) { /* Skip the OUT EP0 alias */ | 455 | if (i != 2) { /* Skip the OUT EP0 alias */ |
456 | dma_desc_init(i, 1); | 456 | dma_desc_init(i, 1); |
457 | USB_OEP_CTRL (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK; | 457 | USB_OEP_CTRL (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK; |
458 | USB_OEP_MPS (i) = 0x08000000|mps; | 458 | USB_OEP_MPS (i) = (mps/2 << 23) | mps; |
459 | USB_OEP_STS_MASK(i) = 0x0000; /* OF: 0x1800 */ | 459 | USB_OEP_STS_MASK(i) = 0x0000; /* OF: 0x1800 */ |
460 | USB_OEP_RXFR (i) = 0x00; | 460 | USB_OEP_RXFR (i) = 0; /* Always 0 in OF trace? */ |
461 | USB_OEP_STS (i) = 0xffffffff; /* clear status */ | 461 | USB_OEP_STS (i) = 0xffffffff; /* clear status */ |
462 | USB_OEP_DESC_PTR(i) = 0; | 462 | USB_OEP_DESC_PTR(i) = 0; |
463 | } | 463 | } |
464 | } | 464 | } |
465 | 465 | ||
466 | setup_desc_init(&setup_desc); | 466 | setup_desc_init(setup_desc); |
467 | USB_OEP_SUP_PTR(0) = (int)&setup_desc; | 467 | USB_OEP_SUP_PTR(0) = (int)setup_desc; |
468 | } | 468 | } |
469 | 469 | ||
470 | void usb_drv_init(void) | 470 | void usb_drv_init(void) |
@@ -582,7 +582,7 @@ int usb_drv_request_endpoint(int type, int dir) | |||
582 | (type << 4); | 582 | (type << 4); |
583 | USB_DEV_EP_INTR_MASK &= ~(1<<(16+i)); | 583 | USB_DEV_EP_INTR_MASK &= ~(1<<(16+i)); |
584 | } | 584 | } |
585 | logf("usb_drv_request_endpoint(%d, %d): returning %02x\n", type, dir, i | dir); | 585 | /* logf("usb_drv_request_endpoint(%d, %d): returning %02x\n", type, dir, i | dir); */ |
586 | return i | dir; | 586 | return i | dir; |
587 | } | 587 | } |
588 | 588 | ||
@@ -610,7 +610,7 @@ void usb_drv_release_endpoint(int ep) | |||
610 | if (!(endpoints[i][d].state & EP_STATE_ALLOCATED)) | 610 | if (!(endpoints[i][d].state & EP_STATE_ALLOCATED)) |
611 | return; | 611 | return; |
612 | 612 | ||
613 | logf("usb_drv_release_endpoint(%d, %d)\n", i, d); | 613 | /* logf("usb_drv_release_endpoint(%d, %d)\n", i, d); */ |
614 | endpoints[i][d].state = 0; | 614 | endpoints[i][d].state = 0; |
615 | USB_DEV_EP_INTR_MASK |= (1<<(16*d+i)); | 615 | USB_DEV_EP_INTR_MASK |= (1<<(16*d+i)); |
616 | USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK; | 616 | USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK; |
@@ -705,11 +705,6 @@ void ep_send(int ep, void *ptr, int len) | |||
705 | endpoints[ep][0].len = len; | 705 | endpoints[ep][0].len = len; |
706 | endpoints[ep][0].rc = -1; | 706 | endpoints[ep][0].rc = -1; |
707 | 707 | ||
708 | USB_IEP_CTRL(ep) |= USB_EP_CTRL_CNAK; | ||
709 | |||
710 | /* TEST: delay a little here */ | ||
711 | for (i=0; i<1000; i++) asm volatile ("nop\n"); | ||
712 | |||
713 | /* Make sure data is committed to memory */ | 708 | /* Make sure data is committed to memory */ |
714 | clean_dcache(); | 709 | clean_dcache(); |
715 | 710 | ||
@@ -723,11 +718,11 @@ void ep_send(int ep, void *ptr, int len) | |||
723 | 718 | ||
724 | uc_desc->data_ptr = virt_to_bus(ptr); | 719 | uc_desc->data_ptr = virt_to_bus(ptr); |
725 | 720 | ||
726 | USB_IEP_CTRL(ep) |= USB_EP_CTRL_FLUSH; | ||
727 | USB_IEP_DESC_PTR(ep) = (int)&dmadescs[ep][0]; | 721 | USB_IEP_DESC_PTR(ep) = (int)&dmadescs[ep][0]; |
728 | USB_IEP_STS(ep) = 0xffffffff; /* clear status */ | 722 | USB_IEP_STS(ep) = 0xffffffff; /* clear status */ |
729 | /* start transfer */ | 723 | /* start transfer */ |
730 | USB_IEP_CTRL(ep) |= USB_EP_CTRL_PD; | 724 | USB_IEP_CTRL(ep) |= USB_EP_CTRL_CNAK | USB_EP_CTRL_PD; |
725 | /* HW automatically sets NAK bit later */ | ||
731 | } | 726 | } |
732 | 727 | ||
733 | int usb_drv_send(int ep, void *ptr, int len) | 728 | int usb_drv_send(int ep, void *ptr, int len) |
@@ -760,14 +755,17 @@ static void handle_in_ep(int ep) | |||
760 | 755 | ||
761 | USB_IEP_STS(ep) = ep_sts; /* ack */ | 756 | USB_IEP_STS(ep) = ep_sts; /* ack */ |
762 | 757 | ||
758 | if (ep_sts & USB_EP_STAT_BNA) { /* Buffer was not set up */ | ||
759 | logf("ep%d IN, status %x (BNA)\n", ep, ep_sts); | ||
760 | panicf("ep%d IN 0x%x (BNA)", ep, ep_sts); | ||
761 | } | ||
762 | |||
763 | if (ep_sts & USB_EP_STAT_TDC) { | 763 | if (ep_sts & USB_EP_STAT_TDC) { |
764 | ep_sts &= ~USB_EP_STAT_TDC; | 764 | USB_IEP_CTRL(ep) |= USB_EP_CTRL_FLUSH; |
765 | /* OF does SNAK and FLUSH at once here */ | ||
766 | USB_IEP_CTRL(ep) |= USB_EP_CTRL_SNAK | USB_EP_CTRL_FLUSH; | ||
767 | endpoints[ep][0].state &= ~EP_STATE_BUSY; | 765 | endpoints[ep][0].state &= ~EP_STATE_BUSY; |
768 | endpoints[ep][0].rc = 0; | 766 | endpoints[ep][0].rc = 0; |
769 | logf("EP%d %stx done len %x stat %08x\n", | 767 | logf("EP%d %x %stx done len %x stat %08x\n", |
770 | ep, endpoints[ep][0].state & EP_STATE_ASYNC ? "async " :"", | 768 | ep, ep_sts, endpoints[ep][0].state & EP_STATE_ASYNC ? "async " :"", |
771 | endpoints[ep][0].len, | 769 | endpoints[ep][0].len, |
772 | endpoints[ep][0].uc_desc->status); | 770 | endpoints[ep][0].uc_desc->status); |
773 | if (endpoints[ep][0].state & EP_STATE_ASYNC) { | 771 | if (endpoints[ep][0].state & EP_STATE_ASYNC) { |
@@ -776,6 +774,7 @@ static void handle_in_ep(int ep) | |||
776 | } else { | 774 | } else { |
777 | wakeup_signal(&endpoints[ep][0].complete); | 775 | wakeup_signal(&endpoints[ep][0].complete); |
778 | } | 776 | } |
777 | ep_sts &= ~USB_EP_STAT_TDC; | ||
779 | } | 778 | } |
780 | 779 | ||
781 | if (ep_sts) { | 780 | if (ep_sts) { |
@@ -790,7 +789,7 @@ static void handle_in_ep(int ep) | |||
790 | 789 | ||
791 | static void handle_out_ep(int ep) | 790 | static void handle_out_ep(int ep) |
792 | { | 791 | { |
793 | struct usb_ctrlrequest *req = (void*)UNCACHED_ADDR(&setup_desc.data1); | 792 | struct usb_ctrlrequest *req = (void*)UNCACHED_ADDR(&setup_desc->data1); |
794 | int ep_sts = USB_OEP_STS(ep) & ~USB_OEP_STS_MASK(ep); | 793 | int ep_sts = USB_OEP_STS(ep) & ~USB_OEP_STS_MASK(ep); |
795 | struct usb_dev_dma_desc *uc_desc = endpoints[ep][1].uc_desc; | 794 | struct usb_dev_dma_desc *uc_desc = endpoints[ep][1].uc_desc; |
796 | 795 | ||
@@ -810,28 +809,23 @@ static void handle_out_ep(int ep) | |||
810 | int dma_frm = (dma_sts >> 16) & 0x7ff; | 809 | int dma_frm = (dma_sts >> 16) & 0x7ff; |
811 | int dma_mst = dma_sts & 0xf8000000; | 810 | int dma_mst = dma_sts & 0xf8000000; |
812 | 811 | ||
813 | uc_desc->status = USB_DMA_DESC_BS_HST_RDY | | ||
814 | USB_DMA_DESC_LAST | | ||
815 | 0x40; | ||
816 | uc_desc->data_ptr = rx_buf; | ||
817 | USB_OEP_DESC_PTR(ep) = (int)&dmadescs[ep][1]; | ||
818 | |||
819 | if (!(dma_sts & USB_DMA_DESC_ZERO_LEN)) { | 812 | if (!(dma_sts & USB_DMA_DESC_ZERO_LEN)) { |
820 | logf("EP%d OUT token, st:%08x len:%d frm:%x data=%s\n", ep, | 813 | logf("EP%d OUT token, st:%08x len:%d frm:%x data=%s epstate=%d\n", ep, |
821 | dma_mst, dma_len, dma_frm, make_hex(uc_desc->data_ptr, dma_len)); | 814 | dma_mst, dma_len, dma_frm, make_hex(uc_desc->data_ptr, dma_len), |
815 | endpoints[ep][1].state); | ||
822 | /* | 816 | /* |
823 | * If parts of the just dmaed range are in cache, dump them now. | 817 | * If parts of the just dmaed range are in cache, dump them now. |
824 | */ | 818 | */ |
825 | dump_dcache_range(uc_desc->data_ptr, dma_len); | 819 | dump_dcache_range(uc_desc->data_ptr, dma_len); |
826 | } else{ | 820 | } else{ |
827 | logf("EP%d OUT token, st:%08x len:%d frm:%x\n", ep, | 821 | logf("EP%d OUT token, st:%08x frm:%x (no data)\n", ep, |
828 | dma_mst, dma_len, dma_frm); | 822 | dma_mst, dma_frm); |
829 | } | 823 | } |
830 | 824 | ||
831 | if (endpoints[ep][1].state & EP_STATE_BUSY) { | 825 | if (endpoints[ep][1].state & EP_STATE_BUSY) { |
832 | endpoints[ep][1].state &= ~EP_STATE_BUSY; | 826 | endpoints[ep][1].state &= ~EP_STATE_BUSY; |
833 | endpoints[ep][1].rc = 0; | 827 | endpoints[ep][1].rc = 0; |
834 | usb_core_transfer_complete(ep, 0, 0, endpoints[ep][0].len); | 828 | usb_core_transfer_complete(ep, USB_DIR_OUT, 0, dma_len); |
835 | } else { | 829 | } else { |
836 | logf("EP%d OUT, but no one was listening?\n", ep); | 830 | logf("EP%d OUT, but no one was listening?\n", ep); |
837 | } | 831 | } |
@@ -854,7 +848,7 @@ static void handle_out_ep(int ep) | |||
854 | req->wLength); | 848 | req->wLength); |
855 | 849 | ||
856 | usb_core_control_request(&req_copy); | 850 | usb_core_control_request(&req_copy); |
857 | setup_desc_init(&setup_desc); | 851 | setup_desc_init(setup_desc); |
858 | 852 | ||
859 | ep_sts &= ~USB_EP_STAT_SETUP_RCVD; | 853 | ep_sts &= ~USB_EP_STAT_SETUP_RCVD; |
860 | } | 854 | } |
@@ -1029,7 +1023,6 @@ void usb_drv_set_test_mode(int mode) | |||
1029 | (void)mode; | 1023 | (void)mode; |
1030 | } | 1024 | } |
1031 | 1025 | ||
1032 | /* handled internally by controller */ | ||
1033 | void usb_drv_set_address(int address) | 1026 | void usb_drv_set_address(int address) |
1034 | { | 1027 | { |
1035 | (void)address; | 1028 | (void)address; |