diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/usb-designware.c | 546 |
1 files changed, 407 insertions, 139 deletions
diff --git a/firmware/drivers/usb-designware.c b/firmware/drivers/usb-designware.c index 58b6a75180..37e96aa557 100644 --- a/firmware/drivers/usb-designware.c +++ b/firmware/drivers/usb-designware.c | |||
@@ -53,13 +53,31 @@ | |||
53 | #define COMMIT_DCACHE_RANGE(b,s) commit_dcache_range(b,s) | 53 | #define COMMIT_DCACHE_RANGE(b,s) commit_dcache_range(b,s) |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | /* On some platforms, virtual addresses must be mangled to | 56 | /* USB_DW_PHYSADDR(x) converts the address of buffer x to one usable with DMA. |
57 | * get a physical address for DMA | 57 | * For example, converting a virtual address to a physical address. |
58 | * | ||
59 | * USB_DW_UNCACHEDADDR(x) is used to get an uncached pointer to a buffer. | ||
60 | * If the platform doesn't support this, define NO_UNCACHED_ADDR instead. | ||
61 | * | ||
62 | * Define POST_DMA_FLUSH if the driver should discard DMA RX buffers after a | ||
63 | * transfer completes. Needed if the CPU can speculatively fetch cache lines | ||
64 | * in any way, eg. due to speculative execution / prefetching. | ||
58 | */ | 65 | */ |
59 | #if CONFIG_CPU == X1000 | 66 | #if CONFIG_CPU == X1000 |
60 | # define DMA_ADDR2PHYS(x) PHYSADDR(x) | 67 | # define USB_DW_PHYSADDR(x) PHYSADDR(x) |
61 | #else | 68 | # define USB_DW_UNCACHEDADDR(x) ((typeof(x))UNCACHEDADDR(x)) |
62 | # define DMA_ADDR2PHYS(x) x | 69 | # define POST_DMA_FLUSH |
70 | #elif CONFIG_CPU == AS3525v2 | ||
71 | # define USB_DW_PHYSADDR(x) AS3525_PHYSICAL_ADDR(x) | ||
72 | # define USB_DW_UNCACHEDADDR(x) AS3525_UNCACHED_ADDR(x) | ||
73 | #elif CONFIG_CPU == S5L8701 | ||
74 | # define USB_DW_PHYSADDR(x) x | ||
75 | # define NO_UNCACHED_ADDR /* Not known how to form uncached addresses */ | ||
76 | #elif CONFIG_CPU == S5L8702 | ||
77 | # define USB_DW_PHYSADDR(x) S5L8702_PHYSICAL_ADDR(x) | ||
78 | # define USB_DW_UNCACHEDADDR(x) S5L8702_UNCACHED_ADDR(x) | ||
79 | #elif !defined(USB_DW_ARCH_SLAVE) | ||
80 | # error "Must define USB_DW_PHYSADDR / USB_DW_UNCACHEDADDR!" | ||
63 | #endif | 81 | #endif |
64 | 82 | ||
65 | #ifndef USB_DW_TOUTCAL | 83 | #ifndef USB_DW_TOUTCAL |
@@ -77,19 +95,33 @@ enum usb_dw_epdir | |||
77 | USB_DW_EPDIR_OUT = 1, | 95 | USB_DW_EPDIR_OUT = 1, |
78 | }; | 96 | }; |
79 | 97 | ||
80 | union usb_ep0_buffer | 98 | enum usb_dw_ep0_state |
81 | { | 99 | { |
82 | struct usb_ctrlrequest setup; | 100 | /* Waiting for a setup packet to arrive. This is the default state. */ |
83 | uint8_t raw[64]; | 101 | EP0_SETUP, |
84 | }; | 102 | |
103 | /* Request wait states -- after submitting a request, we enter EP0_REQ | ||
104 | * (or EP0_REQ_CTRLWRITE for control writes). EP0_REQ is also used for | ||
105 | * the 2nd phase of a control write. */ | ||
106 | EP0_REQ, | ||
107 | EP0_REQ_CTRLWRITE, | ||
108 | |||
109 | /* Waiting for a data phase to complete. */ | ||
110 | EP0_DATA_IN, EP0_FIRST_CNAK_STATE = EP0_DATA_IN, | ||
111 | EP0_DATA_OUT, | ||
85 | 112 | ||
86 | static union usb_ep0_buffer ep0_buffer USB_DEVBSS_ATTR; | 113 | /* Waiting for the status phase */ |
114 | EP0_STATUS_IN, | ||
115 | EP0_STATUS_OUT, | ||
116 | |||
117 | EP0_NUM_STATES | ||
118 | }; | ||
87 | 119 | ||
88 | /* Internal EP state/info */ | 120 | /* Internal EP state/info */ |
89 | struct usb_dw_ep | 121 | struct usb_dw_ep |
90 | { | 122 | { |
91 | struct semaphore complete; | 123 | struct semaphore complete; |
92 | uint32_t* req_addr; | 124 | void* req_addr; |
93 | uint32_t req_size; | 125 | uint32_t req_size; |
94 | uint32_t* addr; | 126 | uint32_t* addr; |
95 | uint32_t sizeleft; | 127 | uint32_t sizeleft; |
@@ -99,7 +131,42 @@ struct usb_dw_ep | |||
99 | uint8_t busy; | 131 | uint8_t busy; |
100 | }; | 132 | }; |
101 | 133 | ||
134 | /* Additional state for EP0 */ | ||
135 | struct usb_dw_ep0 | ||
136 | { | ||
137 | enum usb_dw_ep0_state state; | ||
138 | struct usb_ctrlrequest active_req; | ||
139 | struct usb_ctrlrequest pending_req; | ||
140 | }; | ||
141 | |||
142 | static const char* const dw_dir_str[USB_DW_NUM_DIRS] = | ||
143 | { | ||
144 | [USB_DW_EPDIR_IN] = "IN", | ||
145 | [USB_DW_EPDIR_OUT] = "OUT", | ||
146 | }; | ||
147 | |||
148 | static const char* const dw_state_str[EP0_NUM_STATES] = | ||
149 | { | ||
150 | [EP0_SETUP] = "setup", | ||
151 | [EP0_REQ] = "req", | ||
152 | [EP0_REQ_CTRLWRITE] = "req_cw", | ||
153 | [EP0_DATA_IN] = "dat_in", | ||
154 | [EP0_DATA_OUT] = "dat_out", | ||
155 | [EP0_STATUS_IN] = "sts_in", | ||
156 | [EP0_STATUS_OUT] = "sts_out", | ||
157 | }; | ||
158 | |||
159 | static const char* const dw_resp_str[3] = | ||
160 | { | ||
161 | [USB_CONTROL_ACK] = "ACK", | ||
162 | [USB_CONTROL_RECEIVE] = "RECV", | ||
163 | [USB_CONTROL_STALL] = "STALL", | ||
164 | }; | ||
165 | |||
102 | static struct usb_dw_ep usb_dw_ep_list[USB_NUM_ENDPOINTS][USB_DW_NUM_DIRS]; | 166 | static struct usb_dw_ep usb_dw_ep_list[USB_NUM_ENDPOINTS][USB_DW_NUM_DIRS]; |
167 | static struct usb_dw_ep0 ep0; | ||
168 | uint8_t _ep0_buffer[64] USB_DEVBSS_ATTR __attribute__((aligned(32))); | ||
169 | uint8_t* ep0_buffer; /* Uncached, unless NO_UNCACHED_ADDR is defined */ | ||
103 | 170 | ||
104 | static uint32_t usb_endpoints; /* available EPs mask */ | 171 | static uint32_t usb_endpoints; /* available EPs mask */ |
105 | 172 | ||
@@ -117,35 +184,30 @@ static uint32_t epmis_msk; | |||
117 | static uint32_t ep_periodic_msk; | 184 | static uint32_t ep_periodic_msk; |
118 | #endif | 185 | #endif |
119 | 186 | ||
120 | static const char *dw_dir_str[USB_DW_NUM_DIRS] = | ||
121 | { | ||
122 | [USB_DW_EPDIR_IN] = "IN", | ||
123 | [USB_DW_EPDIR_OUT] = "OUT", | ||
124 | }; | ||
125 | |||
126 | |||
127 | static struct usb_dw_ep *usb_dw_get_ep(int epnum, enum usb_dw_epdir epdir) | 187 | static struct usb_dw_ep *usb_dw_get_ep(int epnum, enum usb_dw_epdir epdir) |
128 | { | 188 | { |
129 | return &usb_dw_ep_list[epnum][epdir]; | 189 | return &usb_dw_ep_list[epnum][epdir]; |
130 | } | 190 | } |
131 | 191 | ||
132 | static int usb_dw_maxpktsize(int epnum, enum usb_dw_epdir epdir) | 192 | static uint32_t usb_dw_maxpktsize(int epnum, enum usb_dw_epdir epdir) |
133 | { | 193 | { |
134 | return epnum ? DWC_EPCTL(epnum, epdir) & 0x3ff : 64; | 194 | return epnum ? DWC_EPCTL(epnum, epdir) & 0x3ff : 64; |
135 | } | 195 | } |
136 | 196 | ||
137 | static int usb_dw_maxxfersize(int epnum, enum usb_dw_epdir epdir) | 197 | static uint32_t usb_dw_maxxfersize(int epnum, enum usb_dw_epdir epdir) |
138 | { | 198 | { |
139 | return epnum ? ALIGN_DOWN_P2(MIN(hw_maxbytes, | 199 | /* EP0 can only transfer one packet at a time. */ |
140 | hw_maxpackets*usb_dw_maxpktsize(epnum, epdir)), CACHEALIGN_BITS) : 64; | 200 | if(epnum == 0) |
201 | return 64; | ||
202 | |||
203 | uint32_t maxpktsize = usb_dw_maxpktsize(epnum, epdir); | ||
204 | return CACHEALIGN_DOWN(MIN(hw_maxbytes, hw_maxpackets * maxpktsize)); | ||
141 | } | 205 | } |
142 | 206 | ||
143 | /* Calculate number of packets (if size == 0 an empty packet will be sent) */ | 207 | /* Calculate number of packets (if size == 0 an empty packet will be sent) */ |
144 | static int usb_dw_calc_packets(uint32_t size, uint32_t maxpktsize) | 208 | static uint32_t usb_dw_calc_packets(uint32_t size, uint32_t maxpktsize) |
145 | { | 209 | { |
146 | int packets = (size + maxpktsize - 1) / maxpktsize; | 210 | return MAX(1, (size + maxpktsize - 1) / maxpktsize); |
147 | if (!packets) packets = 1; | ||
148 | return packets; | ||
149 | } | 211 | } |
150 | 212 | ||
151 | static int usb_dw_get_stall(int epnum, enum usb_dw_epdir epdir) | 213 | static int usb_dw_get_stall(int epnum, enum usb_dw_epdir epdir) |
@@ -184,8 +246,8 @@ static unsigned usb_dw_bytes_in_txfifo(int epnum, uint32_t *sentbytes) | |||
184 | uint32_t dieptsiz = DWC_DIEPTSIZ(epnum); | 246 | uint32_t dieptsiz = DWC_DIEPTSIZ(epnum); |
185 | uint32_t packetsleft = (dieptsiz >> 19) & 0x3ff; | 247 | uint32_t packetsleft = (dieptsiz >> 19) & 0x3ff; |
186 | if (!packetsleft) return 0; | 248 | if (!packetsleft) return 0; |
187 | int maxpktsize = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN); | 249 | uint32_t maxpktsize = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN); |
188 | int packets = usb_dw_calc_packets(size, maxpktsize); | 250 | uint32_t packets = usb_dw_calc_packets(size, maxpktsize); |
189 | uint32_t bytesleft = dieptsiz & 0x7ffff; | 251 | uint32_t bytesleft = dieptsiz & 0x7ffff; |
190 | uint32_t bytespushed = size - bytesleft; | 252 | uint32_t bytespushed = size - bytesleft; |
191 | uint32_t bytespulled = (packets - packetsleft) * maxpktsize; | 253 | uint32_t bytespulled = (packets - packetsleft) * maxpktsize; |
@@ -200,7 +262,7 @@ static unsigned usb_dw_bytes_in_txfifo(int epnum, uint32_t *sentbytes) | |||
200 | static void usb_dw_handle_rxfifo(void) | 262 | static void usb_dw_handle_rxfifo(void) |
201 | { | 263 | { |
202 | uint32_t rxsts = DWC_GRXSTSP; | 264 | uint32_t rxsts = DWC_GRXSTSP; |
203 | int pktsts = (rxsts >> 17) & 0xf; | 265 | uint32_t pktsts = (rxsts >> 17) & 0xf; |
204 | 266 | ||
205 | switch (pktsts) | 267 | switch (pktsts) |
206 | { | 268 | { |
@@ -208,19 +270,31 @@ static void usb_dw_handle_rxfifo(void) | |||
208 | case PKTSTS_SETUPRX: | 270 | case PKTSTS_SETUPRX: |
209 | { | 271 | { |
210 | int ep = rxsts & 0xf; | 272 | int ep = rxsts & 0xf; |
211 | int words = (((rxsts >> 4) & 0x7ff) + 3) >> 2; | 273 | uint32_t words = (((rxsts >> 4) & 0x7ff) + 3) >> 2; |
212 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(ep, USB_DW_EPDIR_OUT); | 274 | |
213 | if (dw_ep->busy) | 275 | /* Annoyingly, we need to special-case EP0. */ |
276 | if(ep == 0) | ||
214 | { | 277 | { |
278 | uint32_t* addr = (uint32_t*)ep0_buffer; | ||
215 | while (words--) | 279 | while (words--) |
216 | *dw_ep->addr++ = DWC_DFIFO(0); | 280 | *addr++ = DWC_DFIFO(0); |
217 | } | 281 | } |
218 | else | 282 | else |
219 | { | 283 | { |
220 | /* Discard data */ | 284 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(ep, USB_DW_EPDIR_OUT); |
221 | while (words--) | 285 | if (dw_ep->busy) |
222 | (void) DWC_DFIFO(0); | 286 | { |
287 | while (words--) | ||
288 | *dw_ep->addr++ = DWC_DFIFO(0); | ||
289 | } | ||
290 | else | ||
291 | { | ||
292 | /* Discard data */ | ||
293 | while (words--) | ||
294 | (void) DWC_DFIFO(0); | ||
295 | } | ||
223 | } | 296 | } |
297 | |||
224 | break; | 298 | break; |
225 | } | 299 | } |
226 | case PKTSTS_OUTDONE: | 300 | case PKTSTS_OUTDONE: |
@@ -292,7 +366,7 @@ static void usb_dw_handle_dtxfifo(int epnum) | |||
292 | { | 366 | { |
293 | /* We push whole packets to read consistent info on DIEPTSIZ | 367 | /* We push whole packets to read consistent info on DIEPTSIZ |
294 | (i.e. when FIFO size is not maxpktsize multiplo). */ | 368 | (i.e. when FIFO size is not maxpktsize multiplo). */ |
295 | int maxpktwords = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN) >> 2; | 369 | uint32_t maxpktwords = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN) >> 2; |
296 | words = (fifospace / maxpktwords) * maxpktwords; | 370 | words = (fifospace / maxpktwords) * maxpktwords; |
297 | } | 371 | } |
298 | 372 | ||
@@ -458,7 +532,7 @@ static void usb_dw_nptx_unqueue(int epnum) | |||
458 | dw_ep->addr -= (bytesinfifo + 3) >> 2; | 532 | dw_ep->addr -= (bytesinfifo + 3) >> 2; |
459 | #else | 533 | #else |
460 | (void) bytesinfifo; | 534 | (void) bytesinfifo; |
461 | DWC_DIEPDMA(ep) = DMA_ADDR2PHYS((uint32_t)(dw_ep->addr) + sentbytes); | 535 | DWC_DIEPDMA(ep) = USB_DW_PHYSADDR((uint32_t)(dw_ep->addr) + sentbytes); |
462 | #endif | 536 | #endif |
463 | DWC_DIEPTSIZ(ep) = PKTCNT(packetsleft) | (dw_ep->size - sentbytes); | 537 | DWC_DIEPTSIZ(ep) = PKTCNT(packetsleft) | (dw_ep->size - sentbytes); |
464 | 538 | ||
@@ -664,57 +738,72 @@ static void usb_dw_reset_endpoints(void) | |||
664 | #endif | 738 | #endif |
665 | } | 739 | } |
666 | 740 | ||
667 | static void usb_dw_start_xfer(int epnum, | 741 | static void usb_dw_epstart(int epnum, enum usb_dw_epdir epdir, |
668 | enum usb_dw_epdir epdir, const void* buf, int size) | 742 | void* buf, uint32_t size) |
669 | { | 743 | { |
670 | if ((uint32_t)buf & ((epdir == USB_DW_EPDIR_IN) ? 3 : CACHEALIGN_SIZE-1)) | 744 | if ((uint32_t)buf & ((epdir == USB_DW_EPDIR_IN) ? 3 : CACHEALIGN_SIZE-1)) |
671 | logf("%s: %s%d %p unaligned", __func__, dw_dir_str[epdir], epnum, buf); | 745 | logf("%s: %s%d %p unaligned", __func__, dw_dir_str[epdir], epnum, buf); |
672 | 746 | ||
673 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir); | 747 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir); |
748 | uint32_t xfersize = MIN(size, usb_dw_maxxfersize(epnum, epdir)); | ||
674 | 749 | ||
675 | dw_ep->busy = true; | 750 | dw_ep->addr = (uint32_t*)buf; |
676 | dw_ep->status = -1; | 751 | dw_ep->size = xfersize; |
677 | dw_ep->sizeleft = size; | 752 | dw_ep->sizeleft = size; |
678 | size = MIN(size, usb_dw_maxxfersize(epnum, epdir)); | 753 | dw_ep->status = -1; |
679 | dw_ep->size = size; | 754 | dw_ep->busy = true; |
680 | 755 | ||
681 | int packets = usb_dw_calc_packets(size, usb_dw_maxpktsize(epnum, epdir)); | 756 | if (epnum == 0 && epdir == USB_DW_EPDIR_OUT) |
682 | uint32_t eptsiz = PKTCNT(packets) | size; | 757 | { |
683 | uint32_t nak; | 758 | /* FIXME: there's an extremely rare race condition here. |
759 | * | ||
760 | * 1. Host sends a control write. | ||
761 | * 2. We process the request. | ||
762 | * 3. (time passes) | ||
763 | * 4. This function is called via USB_CONTROL_RECEIVE response. | ||
764 | * 5. Right before we set CNAK, host sends another control write. | ||
765 | * | ||
766 | * So we may unintentionally receive data from the second request. | ||
767 | * It's possible to detect this when we see a setup packet because | ||
768 | * EP0 OUT will be busy. In principle it should even be possible to | ||
769 | * handle the 2nd request correctly. Currently we don't attempt to | ||
770 | * detect or recover from this error. | ||
771 | */ | ||
772 | DWC_DOEPCTL(0) |= CNAK; | ||
773 | return; | ||
774 | } | ||
684 | 775 | ||
685 | /* Set up data source */ | 776 | uint32_t maxpktsize = usb_dw_maxpktsize(epnum, epdir); |
686 | dw_ep->addr = (uint32_t*)buf; | 777 | uint32_t packets = usb_dw_calc_packets(xfersize, maxpktsize); |
687 | #ifndef USB_DW_ARCH_SLAVE | 778 | uint32_t eptsiz = PKTCNT(packets) | xfersize; |
688 | DWC_EPDMA(epnum, epdir) = DMA_ADDR2PHYS((uint32_t)buf); | 779 | uint32_t nak = CNAK; |
689 | #endif | ||
690 | 780 | ||
691 | if (epdir == USB_DW_EPDIR_IN) | 781 | if (epdir == USB_DW_EPDIR_IN) |
692 | { | 782 | { |
693 | #ifndef USB_DW_ARCH_SLAVE | 783 | #ifndef USB_DW_ARCH_SLAVE |
694 | COMMIT_DCACHE_RANGE(buf, size); | 784 | COMMIT_DCACHE_RANGE(buf, xfersize); |
695 | #endif | 785 | #endif |
696 | #ifdef USB_DW_SHARED_FIFO | 786 | #ifdef USB_DW_SHARED_FIFO |
697 | eptsiz |= MCCNT((ep_periodic_msk >> epnum) & 1); | 787 | eptsiz |= MCCNT((ep_periodic_msk >> epnum) & 1); |
698 | #endif | 788 | #endif |
699 | nak = CNAK; | 789 | |
700 | } | 790 | } |
701 | else | 791 | else |
702 | { | 792 | { |
703 | #ifndef USB_DW_ARCH_SLAVE | 793 | #ifndef USB_DW_ARCH_SLAVE |
704 | DISCARD_DCACHE_RANGE(buf, size); | 794 | DISCARD_DCACHE_RANGE(buf, xfersize); |
705 | #endif | 795 | #endif |
706 | eptsiz |= STUPCNT(!epnum); | ||
707 | nak = epnum ? CNAK : SNAK; | ||
708 | } | 796 | } |
709 | 797 | ||
798 | #ifndef USB_DW_ARCH_SLAVE | ||
799 | DWC_EPDMA(epnum, epdir) = USB_DW_PHYSADDR((uint32_t)buf); | ||
800 | #endif | ||
710 | DWC_EPTSIZ(epnum, epdir) = eptsiz; | 801 | DWC_EPTSIZ(epnum, epdir) = eptsiz; |
711 | |||
712 | /* Enable the endpoint */ | ||
713 | DWC_EPCTL(epnum, epdir) |= EPENA | nak; | 802 | DWC_EPCTL(epnum, epdir) |= EPENA | nak; |
714 | 803 | ||
715 | #ifdef USB_DW_ARCH_SLAVE | 804 | #ifdef USB_DW_ARCH_SLAVE |
716 | /* Enable interrupts to start pushing data into the FIFO */ | 805 | /* Enable interrupts to start pushing data into the FIFO */ |
717 | if ((epdir == USB_DW_EPDIR_IN) && size) | 806 | if ((epdir == USB_DW_EPDIR_IN) && dw_ep->size > 0) |
718 | #ifdef USB_DW_SHARED_FIFO | 807 | #ifdef USB_DW_SHARED_FIFO |
719 | DWC_GINTMSK |= ((ep_periodic_msk & (1 << epnum)) ? PTXFE : NPTXFE); | 808 | DWC_GINTMSK |= ((ep_periodic_msk & (1 << epnum)) ? PTXFE : NPTXFE); |
720 | #else | 809 | #else |
@@ -723,25 +812,31 @@ static void usb_dw_start_xfer(int epnum, | |||
723 | #endif | 812 | #endif |
724 | } | 813 | } |
725 | 814 | ||
726 | static void usb_dw_ep0_wait_setup(void) | 815 | static void usb_dw_transfer(int epnum, enum usb_dw_epdir epdir, |
816 | void* buf, uint32_t size) | ||
727 | { | 817 | { |
728 | usb_dw_start_xfer(0, USB_DW_EPDIR_OUT, ep0_buffer.raw, 64); | 818 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir); |
729 | } | ||
730 | |||
731 | static void usb_dw_handle_setup_received(void) | ||
732 | { | ||
733 | static struct usb_ctrlrequest usb_ctrlsetup; | ||
734 | |||
735 | usb_dw_flush_endpoint(0, USB_DW_EPDIR_IN); | ||
736 | 819 | ||
737 | memcpy(&usb_ctrlsetup, ep0_buffer.raw, sizeof(usb_ctrlsetup)); | 820 | if (!dw_ep->active) |
821 | logf("%s: %s%d inactive", __func__, dw_dir_str[epdir], epnum); | ||
822 | if (dw_ep->busy) | ||
823 | logf("%s: %s%d busy", __func__, dw_dir_str[epdir], epnum); | ||
738 | 824 | ||
739 | if (((usb_ctrlsetup.bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) | 825 | dw_ep->req_addr = buf; |
740 | && ((usb_ctrlsetup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) | 826 | dw_ep->req_size = size; |
741 | && (usb_ctrlsetup.bRequest == USB_REQ_SET_ADDRESS)) | 827 | usb_dw_epstart(epnum, epdir, buf, size); |
742 | usb_dw_set_address(usb_ctrlsetup.wValue); | 828 | } |
743 | 829 | ||
744 | usb_core_legacy_control_request(&usb_ctrlsetup); | 830 | static void usb_dw_ep0_recv(void) |
831 | { | ||
832 | #ifndef USB_DW_ARCH_SLAVE | ||
833 | #ifdef NO_UNCACHED_ADDR | ||
834 | DISCARD_DCACHE_RANGE(&_ep0_buffer[0], 64); | ||
835 | #endif | ||
836 | DWC_DOEPDMA(0) = USB_DW_PHYSADDR((uint32_t)&_ep0_buffer[0]); | ||
837 | #endif | ||
838 | DWC_DOEPTSIZ(0) = STUPCNT(1) | PKTCNT(1) | 64; | ||
839 | DWC_DOEPCTL(0) |= EPENA | SNAK; | ||
745 | } | 840 | } |
746 | 841 | ||
747 | static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir) | 842 | static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir) |
@@ -755,60 +850,223 @@ static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir) | |||
755 | } | 850 | } |
756 | } | 851 | } |
757 | 852 | ||
853 | static void usb_dw_control_received(struct usb_ctrlrequest* req) | ||
854 | { | ||
855 | logf("%s(%p) state=%s", __func__, req, dw_state_str[ep0.state]); | ||
856 | logf(" bRequestType=%02x bRequest=%02x", req->bRequestType, req->bRequest); | ||
857 | logf(" wValue=%04x wIndex=%u wLength=%u", req->wValue, req->wIndex, req->wLength); | ||
858 | |||
859 | /* FIXME: This will implode if we receive a setup packet while waiting | ||
860 | * for a response from the USB stack to a previous packet. | ||
861 | */ | ||
862 | |||
863 | switch(ep0.state) { | ||
864 | case EP0_DATA_IN: | ||
865 | case EP0_STATUS_IN: | ||
866 | case EP0_DATA_OUT: | ||
867 | case EP0_STATUS_OUT: | ||
868 | usb_core_control_complete(-1); | ||
869 | /* fallthrough */ | ||
870 | |||
871 | case EP0_SETUP: | ||
872 | /* Save the request */ | ||
873 | memcpy(&ep0.active_req, req, sizeof(*req)); | ||
874 | req = &ep0.active_req; | ||
875 | |||
876 | /* Check for a SET ADDRESS request, which we must handle here */ | ||
877 | if ((req->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE && | ||
878 | (req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD && | ||
879 | (req->bRequest == USB_REQ_SET_ADDRESS)) | ||
880 | usb_dw_set_address(req->wValue); | ||
881 | |||
882 | /* Check for control writes */ | ||
883 | if (req->wLength > 0 && !(req->bRequestType & USB_DIR_IN)) | ||
884 | ep0.state = EP0_REQ_CTRLWRITE; | ||
885 | else | ||
886 | ep0.state = EP0_REQ; | ||
887 | |||
888 | usb_dw_flush_endpoint(0, USB_DW_EPDIR_IN); | ||
889 | usb_core_control_request(req, NULL); | ||
890 | break; | ||
891 | |||
892 | default: | ||
893 | panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]); | ||
894 | } | ||
895 | } | ||
896 | |||
897 | static void usb_dw_control_response(enum usb_control_response resp, | ||
898 | void* data, int length) | ||
899 | { | ||
900 | struct usb_ctrlrequest* req = &ep0.active_req; | ||
901 | |||
902 | switch(ep0.state) { | ||
903 | case EP0_REQ: | ||
904 | case EP0_REQ_CTRLWRITE: | ||
905 | switch(resp) { | ||
906 | case USB_CONTROL_ACK: | ||
907 | if(req->wLength > 0 && (req->bRequestType & USB_DIR_IN)) | ||
908 | ep0.state = EP0_DATA_IN; /* control read */ | ||
909 | else | ||
910 | ep0.state = EP0_STATUS_IN; /* non-data or write */ | ||
911 | |||
912 | usb_dw_transfer(0, USB_DW_EPDIR_IN, data, length); | ||
913 | break; | ||
914 | |||
915 | case USB_CONTROL_RECEIVE: | ||
916 | if(ep0.state != EP0_REQ_CTRLWRITE) | ||
917 | panicf("%s: bad response", __func__); | ||
918 | |||
919 | ep0.state = EP0_DATA_OUT; | ||
920 | usb_dw_transfer(0, USB_DW_EPDIR_OUT, data, length); | ||
921 | break; | ||
922 | |||
923 | case USB_CONTROL_STALL: | ||
924 | if(ep0.state == EP0_REQ_CTRLWRITE) | ||
925 | usb_dw_set_stall(0, USB_DW_EPDIR_OUT, 1); | ||
926 | else | ||
927 | usb_dw_set_stall(0, USB_DW_EPDIR_IN, 1); | ||
928 | |||
929 | ep0.state = EP0_SETUP; | ||
930 | break; | ||
931 | } | ||
932 | break; | ||
933 | |||
934 | default: | ||
935 | panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]); | ||
936 | } | ||
937 | } | ||
938 | |||
939 | static void usb_dw_ep0_xfer_complete(enum usb_dw_epdir epdir, | ||
940 | int status, int transferred) | ||
941 | { | ||
942 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(0, epdir); | ||
943 | |||
944 | switch((ep0.state << 1) | epdir) | ||
945 | { | ||
946 | case (EP0_DATA_IN << 1) | USB_DW_EPDIR_IN: | ||
947 | ep0.state = EP0_STATUS_OUT; | ||
948 | usb_dw_transfer(0, USB_DW_EPDIR_OUT, NULL, 0); | ||
949 | break; | ||
950 | |||
951 | case (EP0_DATA_OUT << 1) | USB_DW_EPDIR_OUT: | ||
952 | ep0.state = EP0_REQ; | ||
953 | usb_core_control_request(&ep0.active_req, dw_ep->req_addr); | ||
954 | break; | ||
955 | |||
956 | case (EP0_STATUS_IN << 1) | USB_DW_EPDIR_IN: | ||
957 | case (EP0_STATUS_OUT << 1) | USB_DW_EPDIR_OUT: | ||
958 | if(status != 0 || transferred != 0) | ||
959 | usb_core_control_complete(-2); | ||
960 | else | ||
961 | usb_core_control_complete(0); | ||
962 | |||
963 | ep0.state = EP0_SETUP; | ||
964 | break; | ||
965 | |||
966 | default: | ||
967 | panicf("%s: state=%s dir=%s", __func__, | ||
968 | dw_state_str[ep0.state], dw_dir_str[epdir]); | ||
969 | } | ||
970 | } | ||
971 | |||
758 | static void usb_dw_handle_xfer_complete(int epnum, enum usb_dw_epdir epdir) | 972 | static void usb_dw_handle_xfer_complete(int epnum, enum usb_dw_epdir epdir) |
759 | { | 973 | { |
760 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir); | 974 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir); |
975 | bool is_ep0out = (epnum == 0 && epdir == USB_DW_EPDIR_OUT); | ||
761 | 976 | ||
762 | if (!dw_ep->busy) | 977 | if (!dw_ep->busy) |
978 | { | ||
979 | if(is_ep0out) | ||
980 | usb_dw_ep0_recv(); | ||
763 | return; | 981 | return; |
982 | } | ||
764 | 983 | ||
765 | uint32_t bytesleft = DWC_EPTSIZ(epnum, epdir) & 0x7ffff; | 984 | uint32_t bytes_left = DWC_EPTSIZ(epnum, epdir) & 0x7ffff; |
985 | uint32_t transferred = (is_ep0out ? 64 : dw_ep->size) - bytes_left; | ||
766 | 986 | ||
767 | if (!epnum && (epdir == USB_DW_EPDIR_OUT)) /* OUT0 */ | 987 | if(transferred > dw_ep->sizeleft) |
768 | { | 988 | { |
769 | int recvbytes = 64 - bytesleft; | 989 | /* Host sent more data than expected. |
770 | dw_ep->sizeleft = dw_ep->req_size - recvbytes; | 990 | * Shouldn't happen for IN endpoints. */ |
771 | if (dw_ep->req_addr) | 991 | dw_ep->status = -2; |
772 | memcpy(dw_ep->req_addr, ep0_buffer.raw, dw_ep->req_size); | 992 | goto complete; |
773 | } | 993 | } |
774 | else | 994 | |
995 | if(is_ep0out) | ||
996 | { | ||
997 | #if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH) | ||
998 | DISCARD_DCACHE_RANGE(ep0_buffer, 64); | ||
999 | #endif | ||
1000 | memcpy(dw_ep->addr, ep0_buffer, transferred); | ||
1001 | usb_dw_ep0_recv(); | ||
1002 | } | ||
1003 | |||
1004 | dw_ep->sizeleft -= transferred; | ||
1005 | |||
1006 | /* Start a new transfer if there is still more to go */ | ||
1007 | if(bytes_left == 0 && dw_ep->sizeleft > 0) | ||
775 | { | 1008 | { |
776 | dw_ep->sizeleft -= (dw_ep->size - bytesleft); | ||
777 | if (!bytesleft && dw_ep->sizeleft) | ||
778 | { | ||
779 | #ifndef USB_DW_ARCH_SLAVE | 1009 | #ifndef USB_DW_ARCH_SLAVE |
780 | dw_ep->addr += (dw_ep->size >> 2); /* words */ | 1010 | dw_ep->addr += (dw_ep->size >> 2); /* offset in words */ |
781 | #endif | 1011 | #endif |
782 | usb_dw_start_xfer(epnum, epdir, dw_ep->addr, dw_ep->sizeleft); | 1012 | usb_dw_epstart(epnum, epdir, dw_ep->addr, dw_ep->sizeleft); |
783 | return; | 1013 | return; |
784 | } | 1014 | } |
785 | 1015 | ||
786 | if (epdir == USB_DW_EPDIR_IN) | 1016 | if(epdir == USB_DW_EPDIR_IN) |
787 | { | 1017 | { |
788 | /* SNAK the disabled EP, otherwise IN tokens for this | 1018 | /* SNAK the disabled EP, otherwise IN tokens for this |
789 | EP could raise unwanted EPMIS interrupts. Useful for | 1019 | EP could raise unwanted EPMIS interrupts. Useful for |
790 | usbserial when there is no data to send. */ | 1020 | usbserial when there is no data to send. */ |
791 | DWC_DIEPCTL(epnum) |= SNAK; | 1021 | DWC_DIEPCTL(epnum) |= SNAK; |
792 | 1022 | ||
793 | #ifdef USB_DW_SHARED_FIFO | 1023 | #ifdef USB_DW_SHARED_FIFO |
794 | /* See usb-s5l8701.c */ | 1024 | /* See usb-s5l8701.c */ |
795 | if (usb_dw_config.use_ptxfifo_as_plain_buffer) | 1025 | if (usb_dw_config.use_ptxfifo_as_plain_buffer) |
796 | { | 1026 | { |
797 | int dtxfnum = GET_DTXFNUM(epnum); | 1027 | int dtxfnum = GET_DTXFNUM(epnum); |
798 | if (dtxfnum) | 1028 | if (dtxfnum) |
799 | usb_dw_flush_fifo(TXFFLSH, dtxfnum); | 1029 | usb_dw_flush_fifo(TXFFLSH, dtxfnum); |
800 | } | ||
801 | #endif | ||
802 | } | 1030 | } |
1031 | #endif | ||
1032 | } | ||
1033 | else | ||
1034 | { | ||
1035 | #if !defined(USB_DW_ARCH_SLAVE) && defined(POST_DMA_FLUSH) | ||
1036 | /* On EP0 OUT we do not DMA into the request buffer, | ||
1037 | * so do not discard the cache in this case. */ | ||
1038 | if(!is_ep0out) | ||
1039 | DISCARD_DCACHE_RANGE(dw_ep->req_addr, dw_ep->req_size); | ||
1040 | #endif | ||
803 | } | 1041 | } |
804 | 1042 | ||
805 | dw_ep->busy = false; | ||
806 | dw_ep->status = 0; | 1043 | dw_ep->status = 0; |
1044 | |||
1045 | complete: | ||
1046 | dw_ep->busy = false; | ||
807 | semaphore_release(&dw_ep->complete); | 1047 | semaphore_release(&dw_ep->complete); |
808 | 1048 | ||
809 | int transfered = dw_ep->req_size - dw_ep->sizeleft; | 1049 | int total_bytes = dw_ep->req_size - dw_ep->sizeleft; |
810 | usb_core_transfer_complete(epnum, (epdir == USB_DW_EPDIR_OUT) ? | 1050 | if (epnum == 0) |
811 | USB_DIR_OUT : USB_DIR_IN, dw_ep->status, transfered); | 1051 | { |
1052 | usb_dw_ep0_xfer_complete(epdir, dw_ep->status, total_bytes); | ||
1053 | } | ||
1054 | else | ||
1055 | { | ||
1056 | usb_core_transfer_complete(epnum, (epdir == USB_DW_EPDIR_OUT) ? | ||
1057 | USB_DIR_OUT : USB_DIR_IN, dw_ep->status, total_bytes); | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | static void usb_dw_handle_setup_received(void) | ||
1062 | { | ||
1063 | #if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH) | ||
1064 | DISCARD_DCACHE_RANGE(ep0_buffer, 64); | ||
1065 | #endif | ||
1066 | memcpy(&ep0.pending_req, ep0_buffer, sizeof(struct usb_ctrlrequest)); | ||
1067 | usb_dw_ep0_recv(); | ||
1068 | |||
1069 | usb_dw_control_received(&ep0.pending_req); | ||
812 | } | 1070 | } |
813 | 1071 | ||
814 | #ifdef USB_DW_SHARED_FIFO | 1072 | #ifdef USB_DW_SHARED_FIFO |
@@ -822,7 +1080,7 @@ static int usb_dw_get_epmis(void) | |||
822 | 1080 | ||
823 | /* Get the EP on the top of the queue, 0 < idx < number of available | 1081 | /* Get the EP on the top of the queue, 0 < idx < number of available |
824 | IN endpoints */ | 1082 | IN endpoints */ |
825 | int idx = (gnptxsts >> 27) & 0xf; | 1083 | uint32_t idx = (gnptxsts >> 27) & 0xf; |
826 | for (epmis = 0; epmis < USB_NUM_ENDPOINTS; epmis++) | 1084 | for (epmis = 0; epmis < USB_NUM_ENDPOINTS; epmis++) |
827 | if ((usb_endpoints & (1 << epmis)) && !idx--) | 1085 | if ((usb_endpoints & (1 << epmis)) && !idx--) |
828 | break; | 1086 | break; |
@@ -960,6 +1218,7 @@ static void usb_dw_irq(void) | |||
960 | if (daint & (1 << (ep + 16))) | 1218 | if (daint & (1 << (ep + 16))) |
961 | { | 1219 | { |
962 | uint32_t epints = DWC_DOEPINT(ep); | 1220 | uint32_t epints = DWC_DOEPINT(ep); |
1221 | DWC_DOEPINT(ep) = epints; | ||
963 | 1222 | ||
964 | if (!ep) | 1223 | if (!ep) |
965 | { | 1224 | { |
@@ -967,17 +1226,31 @@ static void usb_dw_irq(void) | |||
967 | { | 1226 | { |
968 | usb_dw_handle_setup_received(); | 1227 | usb_dw_handle_setup_received(); |
969 | } | 1228 | } |
970 | else if (epints & XFRC) | 1229 | |
1230 | if (epints & XFRC) | ||
971 | { | 1231 | { |
972 | usb_dw_handle_xfer_complete(0, USB_DW_EPDIR_OUT); | 1232 | if(epints & STATUSRECVD) |
1233 | { | ||
1234 | /* At the end of a control write's data phase, the | ||
1235 | * controller writes a spurious OUTDONE token to the | ||
1236 | * FIFO and raises StatusRecvd | XferCompl. | ||
1237 | * | ||
1238 | * We do not need or want this -- we've already handled | ||
1239 | * the data phase by this point -- but EP0 is stoppped | ||
1240 | * as a side effect of XferCompl, so we need to restart | ||
1241 | * it to keep receiving packets. */ | ||
1242 | usb_dw_ep0_recv(); | ||
1243 | } | ||
1244 | else if(!(epints & SETUPRECVD)) | ||
1245 | { | ||
1246 | /* Only call this for normal data packets. Setup | ||
1247 | * packets use the STUP interrupt handler instead. */ | ||
1248 | usb_dw_handle_xfer_complete(0, USB_DW_EPDIR_OUT); | ||
1249 | } | ||
973 | } | 1250 | } |
974 | usb_dw_ep0_wait_setup(); | ||
975 | /* Clear interrupt after the current EP0 packet is handled */ | ||
976 | DWC_DOEPINT(0) = epints; | ||
977 | } | 1251 | } |
978 | else | 1252 | else |
979 | { | 1253 | { |
980 | DWC_DOEPINT(ep) = epints; | ||
981 | if (epints & XFRC) | 1254 | if (epints & XFRC) |
982 | { | 1255 | { |
983 | usb_dw_handle_xfer_complete(ep, USB_DW_EPDIR_OUT); | 1256 | usb_dw_handle_xfer_complete(ep, USB_DW_EPDIR_OUT); |
@@ -991,14 +1264,14 @@ static void usb_dw_irq(void) | |||
991 | DWC_GINTSTS = USBRST; | 1264 | DWC_GINTSTS = USBRST; |
992 | usb_dw_set_address(0); | 1265 | usb_dw_set_address(0); |
993 | usb_dw_reset_endpoints(); | 1266 | usb_dw_reset_endpoints(); |
994 | usb_dw_ep0_wait_setup(); | ||
995 | usb_core_bus_reset(); | 1267 | usb_core_bus_reset(); |
996 | } | 1268 | } |
997 | 1269 | ||
998 | if (DWC_GINTSTS & ENUMDNE) | 1270 | if (DWC_GINTSTS & ENUMDNE) |
999 | { | 1271 | { |
1000 | DWC_GINTSTS = ENUMDNE; | 1272 | DWC_GINTSTS = ENUMDNE; |
1001 | /* Nothing to do? */ | 1273 | ep0.state = EP0_SETUP; |
1274 | usb_dw_ep0_recv(); | ||
1002 | } | 1275 | } |
1003 | } | 1276 | } |
1004 | 1277 | ||
@@ -1083,9 +1356,17 @@ static void usb_dw_init(void) | |||
1083 | 1356 | ||
1084 | if (!initialized) | 1357 | if (!initialized) |
1085 | { | 1358 | { |
1359 | #if !defined(USB_DW_ARCH_SLAVE) && !defined(NO_UNCACHED_ADDR) | ||
1360 | ep0_buffer = USB_DW_UNCACHEDADDR(&_ep0_buffer[0]); | ||
1361 | #else | ||
1362 | /* DMA is not used so we can operate on cached addresses */ | ||
1363 | ep0_buffer = &_ep0_buffer[0]; | ||
1364 | #endif | ||
1365 | |||
1086 | for (int ep = 0; ep < USB_NUM_ENDPOINTS; ep++) | 1366 | for (int ep = 0; ep < USB_NUM_ENDPOINTS; ep++) |
1087 | for (int dir = 0; dir < USB_DW_NUM_DIRS; dir++) | 1367 | for (int dir = 0; dir < USB_DW_NUM_DIRS; dir++) |
1088 | semaphore_init(&usb_dw_get_ep(ep, dir)->complete, 1, 0); | 1368 | semaphore_init(&usb_dw_get_ep(ep, dir)->complete, 1, 0); |
1369 | |||
1089 | initialized = true; | 1370 | initialized = true; |
1090 | } | 1371 | } |
1091 | 1372 | ||
@@ -1335,37 +1616,16 @@ void usb_drv_release_endpoint(int endpoint) | |||
1335 | 1616 | ||
1336 | int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length) | 1617 | int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length) |
1337 | { | 1618 | { |
1338 | int epnum = EP_NUM(endpoint); | ||
1339 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, USB_DW_EPDIR_OUT); | ||
1340 | |||
1341 | usb_dw_target_disable_irq(); | 1619 | usb_dw_target_disable_irq(); |
1342 | if (dw_ep->active) | 1620 | usb_dw_transfer(EP_NUM(endpoint), USB_DW_EPDIR_OUT, ptr, length); |
1343 | { | ||
1344 | dw_ep->req_addr = ptr; | ||
1345 | dw_ep->req_size = length; | ||
1346 | /* OUT0 is always launched waiting for SETUP packet, | ||
1347 | it is CNAKed to receive app data */ | ||
1348 | if (epnum == 0) | ||
1349 | DWC_DOEPCTL(0) |= CNAK; | ||
1350 | else | ||
1351 | usb_dw_start_xfer(epnum, USB_DW_EPDIR_OUT, ptr, length); | ||
1352 | } | ||
1353 | usb_dw_target_enable_irq(); | 1621 | usb_dw_target_enable_irq(); |
1354 | return 0; | 1622 | return 0; |
1355 | } | 1623 | } |
1356 | 1624 | ||
1357 | int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) | 1625 | int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) |
1358 | { | 1626 | { |
1359 | int epnum = EP_NUM(endpoint); | ||
1360 | struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, USB_DW_EPDIR_IN); | ||
1361 | |||
1362 | usb_dw_target_disable_irq(); | 1627 | usb_dw_target_disable_irq(); |
1363 | if (dw_ep->active) | 1628 | usb_dw_transfer(EP_NUM(endpoint), USB_DW_EPDIR_IN, ptr, length); |
1364 | { | ||
1365 | dw_ep->req_addr = ptr; | ||
1366 | dw_ep->req_size = length; | ||
1367 | usb_dw_start_xfer(epnum, USB_DW_EPDIR_IN, ptr, length); | ||
1368 | } | ||
1369 | usb_dw_target_enable_irq(); | 1629 | usb_dw_target_enable_irq(); |
1370 | return 0; | 1630 | return 0; |
1371 | } | 1631 | } |
@@ -1388,3 +1648,11 @@ int usb_drv_send(int endpoint, void *ptr, int length) | |||
1388 | 1648 | ||
1389 | return dw_ep->status; | 1649 | return dw_ep->status; |
1390 | } | 1650 | } |
1651 | |||
1652 | void usb_drv_control_response(enum usb_control_response resp, | ||
1653 | void* data, int length) | ||
1654 | { | ||
1655 | usb_dw_target_disable_irq(); | ||
1656 | usb_dw_control_response(resp, data, length); | ||
1657 | usb_dw_target_enable_irq(); | ||
1658 | } | ||