diff options
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.c | 172 |
1 files changed, 50 insertions, 122 deletions
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.c b/firmware/target/arm/as3525/usb-drv-as3525v2.c index 3836825114..c6bade6574 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.c +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.c | |||
@@ -89,7 +89,6 @@ static enum ep0state ep0_state; | |||
89 | 89 | ||
90 | void usb_attach(void) | 90 | void usb_attach(void) |
91 | { | 91 | { |
92 | logf("%s", __func__); | ||
93 | /* Nothing to do */ | 92 | /* Nothing to do */ |
94 | } | 93 | } |
95 | 94 | ||
@@ -108,68 +107,13 @@ static void flush_tx_fifos(void) | |||
108 | 107 | ||
109 | static void prepare_setup_ep0(void) | 108 | static void prepare_setup_ep0(void) |
110 | { | 109 | { |
111 | logf("%s", __func__); | ||
112 | /* setup DMA */ | ||
113 | DEPDMA(0, true) = (void*)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt); | 110 | DEPDMA(0, true) = (void*)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt); |
114 | |||
115 | /* Setup EP0 OUT with the following parameters: | ||
116 | * packet count = 1 | ||
117 | * setup packet count = 1 | ||
118 | * transfer size = 8 (setup packet) | ||
119 | */ | ||
120 | DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp) | 111 | DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp) |
121 | | (1 << DEPTSIZ0_pkcnt_bitp) | 112 | | (1 << DEPTSIZ0_pkcnt_bitp) |
122 | | 8; | 113 | | 8; |
123 | |||
124 | /* Enable endpoint, clear nak */ | ||
125 | ep0_state = EP0_WAIT_SETUP; | ||
126 | DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak; | 114 | DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak; |
127 | } | ||
128 | 115 | ||
129 | static void handle_ep0_complete(bool is_ack) | 116 | ep0_state = EP0_WAIT_SETUP; |
130 | { | ||
131 | switch(ep0_state) | ||
132 | { | ||
133 | case EP0_WAIT_SETUP: | ||
134 | panicf("usb-drv: EP0 completion while waiting for SETUP"); | ||
135 | case EP0_WAIT_ACK: | ||
136 | if(is_ack) | ||
137 | /* everything is done, prepare next setup */ | ||
138 | prepare_setup_ep0(); | ||
139 | else | ||
140 | panicf("usb-drv: EP0 data completion while waiting for ACK"); | ||
141 | break; | ||
142 | case EP0_WAIT_DATA: | ||
143 | if(is_ack) | ||
144 | panicf("usb-drv: EP0 ACK while waiting for data completion"); | ||
145 | else | ||
146 | /* everything is done, prepare next setup */ | ||
147 | prepare_setup_ep0(); | ||
148 | break; | ||
149 | case EP0_WAIT_DATA_ACK: | ||
150 | ep0_state = is_ack ? EP0_WAIT_DATA : EP0_WAIT_ACK; | ||
151 | break; | ||
152 | default: | ||
153 | panicf("usb-drv: invalid EP0 state"); | ||
154 | } | ||
155 | logf("usb-drv: EP0 state updated to %d", ep0_state); | ||
156 | } | ||
157 | |||
158 | static void handle_ep0_setup(void) | ||
159 | { | ||
160 | if(ep0_state != EP0_WAIT_SETUP) | ||
161 | { | ||
162 | logf("usb-drv: EP0 SETUP while in state %d", ep0_state); | ||
163 | return; | ||
164 | } | ||
165 | /* determine is there is a data phase */ | ||
166 | if(ep0_setup_pkt->wLength == 0) | ||
167 | /* no: wait for ack */ | ||
168 | ep0_state = EP0_WAIT_ACK; | ||
169 | else | ||
170 | /* yes: wait ack and data */ | ||
171 | ep0_state = EP0_WAIT_DATA_ACK; | ||
172 | logf("usb-drv: EP0 state updated to %d", ep0_state); | ||
173 | } | 117 | } |
174 | 118 | ||
175 | static void reset_endpoints(void) | 119 | static void reset_endpoints(void) |
@@ -200,11 +144,12 @@ static void reset_endpoints(void) | |||
200 | int next_ep = in_ep_list[(i + 1) % sizeof(in_ep_list)]; | 144 | int next_ep = in_ep_list[(i + 1) % sizeof(in_ep_list)]; |
201 | DEPCTL(ep, false) = (DEPCTL(ep, false) & ~bitm(DEPCTL, nextep)) | (next_ep << DEPCTL_nextep_bitp); | 145 | DEPCTL(ep, false) = (DEPCTL(ep, false) & ~bitm(DEPCTL, nextep)) | (next_ep << DEPCTL_nextep_bitp); |
202 | } | 146 | } |
147 | |||
148 | prepare_setup_ep0(); | ||
203 | } | 149 | } |
204 | 150 | ||
205 | static void cancel_all_transfers(bool cancel_ep0) | 151 | static void cancel_all_transfers(bool cancel_ep0) |
206 | { | 152 | { |
207 | logf("%s", __func__); | ||
208 | int flags = disable_irq_save(); | 153 | int flags = disable_irq_save(); |
209 | 154 | ||
210 | for (int dir = 0; dir < 2; dir++) | 155 | for (int dir = 0; dir < 2; dir++) |
@@ -244,11 +189,10 @@ void usb_drv_init(void) | |||
244 | GRXFSIZ = 512; | 189 | GRXFSIZ = 512; |
245 | GNPTXFSIZ = MAKE_FIFOSIZE_DATA(512); | 190 | GNPTXFSIZ = MAKE_FIFOSIZE_DATA(512); |
246 | 191 | ||
247 | /* fixme: the current code is for internal DMA only, the clip+ architecture | 192 | /* FIXME: the current code is for internal DMA only, the clip+ architecture |
248 | * define the internal DMA model */ | 193 | * defines the internal DMA model */ |
249 | /* Set burstlen and enable DMA*/ | ||
250 | GAHBCFG = (GAHBCFG_INT_DMA_BURST_INCR << GAHBCFG_hburstlen_bitp) | 194 | GAHBCFG = (GAHBCFG_INT_DMA_BURST_INCR << GAHBCFG_hburstlen_bitp) |
251 | | GAHBCFG_dma_enable; | 195 | | GAHBCFG_dma_enable | GAHBCFG_glblintrmsk; |
252 | 196 | ||
253 | /* Select UTMI+ 16 */ | 197 | /* Select UTMI+ 16 */ |
254 | GUSBCFG = GUSBCFG_force_device_mode | GUSBCFG_phy_if | 7 << GUSBCFG_toutcal_bitp; | 198 | GUSBCFG = GUSBCFG_force_device_mode | GUSBCFG_phy_if | 7 << GUSBCFG_toutcal_bitp; |
@@ -291,26 +235,17 @@ void usb_drv_init(void) | |||
291 | 235 | ||
292 | reset_endpoints(); | 236 | reset_endpoints(); |
293 | 237 | ||
294 | prepare_setup_ep0(); | ||
295 | |||
296 | GINTMSK = GINTMSK_usbreset | 238 | GINTMSK = GINTMSK_usbreset |
297 | | GINTMSK_enumdone | 239 | | GINTMSK_enumdone |
298 | | GINTMSK_inepintr | 240 | | GINTMSK_inepintr |
299 | | GINTMSK_outepintr | 241 | | GINTMSK_outepintr |
300 | | GINTMSK_disconnect | 242 | | GINTMSK_disconnect; |
301 | | GINTMSK_usbsuspend | ||
302 | | GINTMSK_wkupintr | ||
303 | | GINTMSK_otgintr; | ||
304 | 243 | ||
305 | VIC_INT_ENABLE = INTERRUPT_USB; | 244 | VIC_INT_ENABLE = INTERRUPT_USB; |
306 | GAHBCFG |= GAHBCFG_glblintrmsk; | ||
307 | } | 245 | } |
308 | 246 | ||
309 | void usb_drv_exit(void) | 247 | void usb_drv_exit(void) |
310 | { | 248 | { |
311 | logf("%s", __func__); | ||
312 | |||
313 | GAHBCFG &= ~GAHBCFG_glblintrmsk; | ||
314 | VIC_INT_EN_CLEAR = INTERRUPT_USB; | 249 | VIC_INT_EN_CLEAR = INTERRUPT_USB; |
315 | 250 | ||
316 | DCTL = DCTL_pwronprgdone | DCTL_sftdiscon; | 251 | DCTL = DCTL_pwronprgdone | DCTL_sftdiscon; |
@@ -335,9 +270,25 @@ static void handle_ep_int(int ep, bool out) | |||
335 | /* works even for EP0 */ | 270 | /* works even for EP0 */ |
336 | int size = (DEPTSIZ(ep, out) & DEPTSIZ_xfersize_bits); | 271 | int size = (DEPTSIZ(ep, out) & DEPTSIZ_xfersize_bits); |
337 | int transfered = endpoint->len - size; | 272 | int transfered = endpoint->len - size; |
338 | /* handle EP0 state if necessary, this is a ack if length is 0 */ | ||
339 | if(ep == 0) | 273 | if(ep == 0) |
340 | handle_ep0_complete(endpoint->len == 0); | 274 | { |
275 | bool is_ack = endpoint->len == 0; | ||
276 | switch(ep0_state) | ||
277 | { | ||
278 | case EP0_WAIT_SETUP: | ||
279 | panicf("usb-drv: EP0 completion while waiting for SETUP"); | ||
280 | case EP0_WAIT_DATA_ACK: | ||
281 | ep0_state = is_ack ? EP0_WAIT_DATA : EP0_WAIT_ACK; | ||
282 | break; | ||
283 | case EP0_WAIT_ACK: | ||
284 | case EP0_WAIT_DATA: | ||
285 | if((!is_ack && ep0_state == EP0_WAIT_ACK) || (is_ack && ep0_state == EP0_WAIT_DATA)) | ||
286 | panicf("usb-drv: bad EP0 state"); | ||
287 | |||
288 | prepare_setup_ep0(); | ||
289 | break; | ||
290 | } | ||
291 | } | ||
341 | if (!out) | 292 | if (!out) |
342 | endpoint->len = size; | 293 | endpoint->len = size; |
343 | usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, transfered); | 294 | usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, transfered); |
@@ -371,81 +322,63 @@ static void handle_ep_int(int ep, bool out) | |||
371 | } | 322 | } |
372 | else | 323 | else |
373 | { | 324 | { |
374 | /* handle EP0 state */ | 325 | if(ep0_state == EP0_WAIT_SETUP) |
375 | handle_ep0_setup(); | 326 | { |
327 | bool data_phase = ep0_setup_pkt->wLength != 0; | ||
328 | ep0_state = data_phase ? EP0_WAIT_DATA_ACK : EP0_WAIT_ACK; | ||
329 | } | ||
330 | |||
376 | logf(" rt=%x r=%x", ep0_setup_pkt->bRequestType, ep0_setup_pkt->bRequest); | 331 | logf(" rt=%x r=%x", ep0_setup_pkt->bRequestType, ep0_setup_pkt->bRequest); |
377 | /* handle set address */ | 332 | |
378 | if(ep0_setup_pkt->bRequestType == USB_TYPE_STANDARD && | 333 | if(ep0_setup_pkt->bRequestType == USB_TYPE_STANDARD && |
379 | ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS) | 334 | ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS) |
380 | { | 335 | { |
381 | /* Set address now */ | 336 | /* Set address */ |
382 | DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp); | 337 | DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp); |
383 | } | 338 | } |
384 | usb_core_control_request(ep0_setup_pkt); | 339 | usb_core_control_request(ep0_setup_pkt); |
385 | } | 340 | } |
386 | } | 341 | } |
387 | 342 | ||
388 | /* clear interrupts */ | ||
389 | DEPINT(ep, out) = sts; | 343 | DEPINT(ep, out) = sts; |
390 | } | 344 | } |
391 | 345 | ||
392 | static void handle_ep_ints(void) | ||
393 | { | ||
394 | logf("usb-drv: ep int"); | ||
395 | |||
396 | unsigned long daint = DAINT; | ||
397 | |||
398 | for (int i = 0; i < USB_NUM_ENDPOINTS; i++) | ||
399 | { | ||
400 | if (daint & DAINT_IN_EP(i)) | ||
401 | handle_ep_int(i, false); | ||
402 | if (daint & DAINT_OUT_EP(i)) | ||
403 | handle_ep_int(i, true); | ||
404 | } | ||
405 | |||
406 | /* write back to clear status */ | ||
407 | DAINT = daint; | ||
408 | } | ||
409 | |||
410 | /* interrupt service routine */ | ||
411 | void INT_USB(void) | 346 | void INT_USB(void) |
412 | { | 347 | { |
413 | /* some bits in GINTSTS can be set even though we didn't enable the interrupt source | 348 | /* some bits in GINTSTS can be set even though we didn't enable the interrupt source |
414 | * so AND it with the actual mask */ | 349 | * so AND it with the actual mask */ |
415 | unsigned long sts = GINTSTS & GINTMSK; | 350 | unsigned long sts = GINTSTS & GINTMSK; |
351 | logf("usb-drv: INT 0x%lx", sts); | ||
416 | 352 | ||
417 | if(sts & GINTMSK_usbreset) | 353 | if(sts & GINTMSK_usbreset) |
418 | { | 354 | { |
419 | logf("usb-drv: bus reset"); | ||
420 | |||
421 | /* Clear the Remote Wakeup Signalling */ | ||
422 | DCTL &= ~DCTL_rmtwkupsig; | 355 | DCTL &= ~DCTL_rmtwkupsig; |
423 | 356 | ||
424 | flush_tx_fifos(); | 357 | flush_tx_fifos(); |
425 | 358 | ||
426 | /* Flush the Learning Queue */ | ||
427 | GRSTCTL = GRSTCTL_intknqflsh; | 359 | GRSTCTL = GRSTCTL_intknqflsh; |
428 | 360 | ||
429 | /* Reset Device Address */ | ||
430 | DCFG &= ~bitm(DCFG, devadr); | 361 | DCFG &= ~bitm(DCFG, devadr); |
431 | 362 | ||
432 | reset_endpoints(); | 363 | reset_endpoints(); |
433 | prepare_setup_ep0(); | ||
434 | 364 | ||
435 | usb_core_bus_reset(); | 365 | usb_core_bus_reset(); |
436 | } | 366 | } |
437 | 367 | ||
438 | if(sts & GINTMSK_enumdone) | 368 | if(sts & (GINTMSK_outepintr | GINTMSK_inepintr)) |
439 | logf("usb-drv: enum done: speed %cS", usb_drv_port_speed() ? 'H' : 'F'); | ||
440 | |||
441 | if(sts & GINTMSK_otgintr) | ||
442 | { | 369 | { |
443 | logf("usb-drv: otg int"); | 370 | unsigned long daint = DAINT; |
444 | GOTGINT = 0xffffffff; | ||
445 | } | ||
446 | 371 | ||
447 | if(sts & (GINTMSK_outepintr | GINTMSK_inepintr)) | 372 | for (int i = 0; i < USB_NUM_ENDPOINTS; i++) |
448 | handle_ep_ints(); | 373 | { |
374 | if (daint & DAINT_IN_EP(i)) | ||
375 | handle_ep_int(i, false); | ||
376 | if (daint & DAINT_OUT_EP(i)) | ||
377 | handle_ep_int(i, true); | ||
378 | } | ||
379 | |||
380 | DAINT = daint; | ||
381 | } | ||
449 | 382 | ||
450 | if(sts & GINTMSK_disconnect) | 383 | if(sts & GINTMSK_disconnect) |
451 | cancel_all_transfers(true); | 384 | cancel_all_transfers(true); |
@@ -484,8 +417,6 @@ static unsigned long usb_drv_mps_by_type(int type) | |||
484 | 417 | ||
485 | int usb_drv_request_endpoint(int type, int dir) | 418 | int usb_drv_request_endpoint(int type, int dir) |
486 | { | 419 | { |
487 | logf("usb-drv: request endpoint (type=%d,dir=%s)", type, dir == USB_DIR_IN ? "IN" : "OUT"); | ||
488 | |||
489 | for (unsigned i = 1; i < sizeof((dir == USB_DIR_IN) ? in_ep_list : out_ep_list); i++) | 420 | for (unsigned i = 1; i < sizeof((dir == USB_DIR_IN) ? in_ep_list : out_ep_list); i++) |
490 | { | 421 | { |
491 | int ep = ((dir == USB_DIR_IN) ? in_ep_list : out_ep_list)[i]; | 422 | int ep = ((dir == USB_DIR_IN) ? in_ep_list : out_ep_list)[i]; |
@@ -499,13 +430,11 @@ int usb_drv_request_endpoint(int type, int dir) | |||
499 | return ep | dir; | 430 | return ep | dir; |
500 | } | 431 | } |
501 | 432 | ||
502 | logf("usb-drv: request failed"); | ||
503 | return -1; | 433 | return -1; |
504 | } | 434 | } |
505 | 435 | ||
506 | void usb_drv_release_endpoint(int ep) | 436 | void usb_drv_release_endpoint(int ep) |
507 | { | 437 | { |
508 | logf("usb-drv: release EP%d %s", EP_NUM(ep), EP_DIR(ep) == USB_DIR_IN ? "IN" : "OUT"); | ||
509 | endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; | 438 | endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; |
510 | } | 439 | } |
511 | 440 | ||
@@ -516,10 +445,9 @@ void usb_drv_cancel_all_transfers() | |||
516 | 445 | ||
517 | static void usb_drv_transfer(int ep, void *ptr, int len, bool dir_in) | 446 | static void usb_drv_transfer(int ep, void *ptr, int len, bool dir_in) |
518 | { | 447 | { |
519 | ep = EP_NUM(ep); | ||
520 | struct usb_endpoint *endpoint = &endpoints[ep][dir_in]; | 448 | struct usb_endpoint *endpoint = &endpoints[ep][dir_in]; |
521 | 449 | ||
522 | logf("usb-drv: xfer EP%d, len=%d, dir_in=%d, busy=%d", ep, len, dir_in, endpoint->busy); | 450 | logf("%s(%d, %d, %d) busy=%d", __func__, ep, len, dir_in, endpoint->busy); |
523 | 451 | ||
524 | /* disable interrupts to avoid any race */ | 452 | /* disable interrupts to avoid any race */ |
525 | int oldlevel = disable_irq_save(); | 453 | int oldlevel = disable_irq_save(); |
@@ -554,12 +482,13 @@ static void usb_drv_transfer(int ep, void *ptr, int len, bool dir_in) | |||
554 | 482 | ||
555 | int usb_drv_recv(int ep, void *ptr, int len) | 483 | int usb_drv_recv(int ep, void *ptr, int len) |
556 | { | 484 | { |
557 | usb_drv_transfer(ep, ptr, len, false); | 485 | usb_drv_transfer(EP_NUM(ep), ptr, len, false); |
558 | return 0; | 486 | return 0; |
559 | } | 487 | } |
560 | 488 | ||
561 | int usb_drv_send(int ep, void *ptr, int len) | 489 | int usb_drv_send(int ep, void *ptr, int len) |
562 | { | 490 | { |
491 | ep = EP_NUM(ep); | ||
563 | struct usb_endpoint *endpoint = &endpoints[ep][1]; | 492 | struct usb_endpoint *endpoint = &endpoints[ep][1]; |
564 | endpoint->done = false; | 493 | endpoint->done = false; |
565 | usb_drv_transfer(ep, ptr, len, true); | 494 | usb_drv_transfer(ep, ptr, len, true); |
@@ -570,7 +499,7 @@ int usb_drv_send(int ep, void *ptr, int len) | |||
570 | 499 | ||
571 | int usb_drv_send_nonblocking(int ep, void *ptr, int len) | 500 | int usb_drv_send_nonblocking(int ep, void *ptr, int len) |
572 | { | 501 | { |
573 | usb_drv_transfer(ep, ptr, len, true); | 502 | usb_drv_transfer(EP_NUM(ep), ptr, len, true); |
574 | return 0; | 503 | return 0; |
575 | } | 504 | } |
576 | 505 | ||
@@ -589,7 +518,6 @@ void usb_drv_set_address(int address) | |||
589 | 518 | ||
590 | void usb_drv_stall(int ep, bool stall, bool in) | 519 | void usb_drv_stall(int ep, bool stall, bool in) |
591 | { | 520 | { |
592 | logf("usb-drv: %sstall EP%d %s", stall ? "" : "un", ep, in ? "IN" : "OUT"); | ||
593 | if (stall) | 521 | if (stall) |
594 | DEPCTL(ep, !in) |= DEPCTL_stall; | 522 | DEPCTL(ep, !in) |= DEPCTL_stall; |
595 | else | 523 | else |