diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2020-09-14 20:36:24 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2020-09-17 11:26:04 -0400 |
commit | ec413f7692de3e33254d79a84c46bd036fd27d0a (patch) | |
tree | d5853dd677c5d39233a067a9d7f1dc2d3290a8ae /firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | |
parent | a66b9088014fd77d08c34fc07a4e701051e1525a (diff) | |
download | rockbox-ec413f7692de3e33254d79a84c46bd036fd27d0a.tar.gz rockbox-ec413f7692de3e33254d79a84c46bd036fd27d0a.zip |
jz4760: Heavily rework USB driver to add working DMA support
* DMA Bulk IN (ie our TX) results in sequential transfers 33-68% faster.
* DMA Bulk OUT (ie RX) is mostly stripped out due to complete brokenness.
* Interrupt and control endpoints remain PIO-driven.
Other improvements:
1) Use consistent endpoint references (no magic numbers)
2) Greatly enhanced logging
3) DMA support can be compiled out completely
4) Setting lockswitch will disable all DMA operations at runtime
5) Much more robust error checking and recovery
Change-Id: I57b82e655e55ced0dfe289e379b0b61d8fe443b4
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/usb-jz4760.c')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | 383 |
1 files changed, 244 insertions, 139 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c index 275fd3fd2b..8562d9253c 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | |||
@@ -7,7 +7,8 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2016 by Roman Stolyarov | 10 | * Copyright (C) 2016 Roman Stolyarov |
11 | * Copyright (C) 2020 Solomon Peachy | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
@@ -20,7 +21,7 @@ | |||
20 | ****************************************************************************/ | 21 | ****************************************************************************/ |
21 | 22 | ||
22 | #include "config.h" | 23 | #include "config.h" |
23 | /*#define LOGF_ENABLE*/ | 24 | //#define LOGF_ENABLE |
24 | #include "logf.h" | 25 | #include "logf.h" |
25 | #include "system.h" | 26 | #include "system.h" |
26 | #include "usb_ch9.h" | 27 | #include "usb_ch9.h" |
@@ -29,6 +30,8 @@ | |||
29 | #include "cpu.h" | 30 | #include "cpu.h" |
30 | #include "thread.h" | 31 | #include "thread.h" |
31 | 32 | ||
33 | #define USE_USB_DMA | ||
34 | |||
32 | #define PIN_USB_DET (32*4+19) | 35 | #define PIN_USB_DET (32*4+19) |
33 | #define IRQ_USB_DET GPIO_IRQ(PIN_USB_DET) | 36 | #define IRQ_USB_DET GPIO_IRQ(PIN_USB_DET) |
34 | #define GPIO_USB_DET GPIO147 | 37 | #define GPIO_USB_DET GPIO147 |
@@ -43,6 +46,13 @@ | |||
43 | #define TOTAL_EP() (sizeof(endpoints)/sizeof(struct usb_endpoint)) | 46 | #define TOTAL_EP() (sizeof(endpoints)/sizeof(struct usb_endpoint)) |
44 | #define EP_IS_IN(ep) (EP_NUMBER((ep))%2) | 47 | #define EP_IS_IN(ep) (EP_NUMBER((ep))%2) |
45 | 48 | ||
49 | #define TXCSR_WZC_BITS (USB_INCSR_SENTSTALL | USB_INCSR_UNDERRUN | USB_INCSR_FFNOTEMPT | USB_INCSR_INCOMPTX) | ||
50 | |||
51 | /* NOTE: IN/OUT is from the HOST perspective. We're a peripheral, so: | ||
52 | IN = DEV->HOST, (ie we send) | ||
53 | OUT = HOST->DEV, (ie we recv) | ||
54 | */ | ||
55 | |||
46 | enum ep_type | 56 | enum ep_type |
47 | { | 57 | { |
48 | ep_control, | 58 | ep_control, |
@@ -53,6 +63,16 @@ enum ep_type | |||
53 | 63 | ||
54 | struct usb_endpoint | 64 | struct usb_endpoint |
55 | { | 65 | { |
66 | const enum ep_type type; | ||
67 | const long fifo_addr; | ||
68 | unsigned short fifo_size; | ||
69 | bool allocated; | ||
70 | int use_dma; /* -1 = no, 0 = mode_0, 1 = mode_1 */ | ||
71 | |||
72 | struct semaphore complete; | ||
73 | |||
74 | uint8_t config; | ||
75 | |||
56 | volatile void *buf; | 76 | volatile void *buf; |
57 | volatile size_t length; | 77 | volatile size_t length; |
58 | union | 78 | union |
@@ -60,24 +80,14 @@ struct usb_endpoint | |||
60 | volatile size_t sent; | 80 | volatile size_t sent; |
61 | volatile size_t received; | 81 | volatile size_t received; |
62 | }; | 82 | }; |
83 | volatile int rc; | ||
63 | volatile bool busy; | 84 | volatile bool busy; |
64 | |||
65 | const enum ep_type type; | ||
66 | const bool use_dma; | ||
67 | |||
68 | const long fifo_addr; | ||
69 | unsigned short fifo_size; | ||
70 | |||
71 | volatile bool wait; | 85 | volatile bool wait; |
72 | struct semaphore complete; | ||
73 | |||
74 | volatile int rc; | ||
75 | bool allocated; | ||
76 | }; | 86 | }; |
77 | 87 | ||
78 | #define EP_INIT(_type, _fifo_addr, _fifo_size, _buf, _use_dma) \ | 88 | #define EP_INIT(_type, _fifo_addr, _fifo_size, _buf) \ |
79 | { .type = (_type), .fifo_addr = (_fifo_addr), .fifo_size = (_fifo_size), \ | 89 | { .type = (_type), .fifo_addr = (_fifo_addr), .fifo_size = (_fifo_size), \ |
80 | .buf = (_buf), .use_dma = (_use_dma), \ | 90 | .buf = (_buf), .use_dma = -1, \ |
81 | .length = 0, .busy = false, .wait = false, .allocated = false } | 91 | .length = 0, .busy = false, .wait = false, .allocated = false } |
82 | 92 | ||
83 | static union | 93 | static union |
@@ -91,12 +101,12 @@ static volatile bool ep0_data_requested = false; | |||
91 | 101 | ||
92 | static struct usb_endpoint endpoints[] = | 102 | static struct usb_endpoint endpoints[] = |
93 | { | 103 | { |
94 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL, false), | 104 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL), |
95 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, &ep0_rx.buf, false), | 105 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, &ep0_rx.buf), |
96 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false), | 106 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL), |
97 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false), | 107 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL), |
98 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL, false), | 108 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL), |
99 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL, false), | 109 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL), |
100 | }; | 110 | }; |
101 | 111 | ||
102 | static inline void select_endpoint(int ep) | 112 | static inline void select_endpoint(int ep) |
@@ -329,7 +339,8 @@ static void EP0_handler(void) | |||
329 | EP0_send(); | 339 | EP0_send(); |
330 | } | 340 | } |
331 | 341 | ||
332 | static void EPIN_handler(unsigned int endpoint) | 342 | /* Does new work */ |
343 | static void EPIN_send(unsigned int endpoint) | ||
333 | { | 344 | { |
334 | struct usb_endpoint* ep = &endpoints[endpoint*2]; | 345 | struct usb_endpoint* ep = &endpoints[endpoint*2]; |
335 | unsigned int length, csr; | 346 | unsigned int length, csr; |
@@ -338,45 +349,153 @@ static void EPIN_handler(unsigned int endpoint) | |||
338 | csr = REG_USB_INCSR; | 349 | csr = REG_USB_INCSR; |
339 | logf("%s(%d): 0x%x", __func__, endpoint, csr); | 350 | logf("%s(%d): 0x%x", __func__, endpoint, csr); |
340 | 351 | ||
341 | if(!ep->busy) | 352 | if (!ep->busy) { |
342 | { | ||
343 | logf("Entered EPIN handler without work!"); | 353 | logf("Entered EPIN handler without work!"); |
344 | return; | 354 | return; |
345 | } | 355 | } |
346 | 356 | ||
347 | if(csr & USB_INCSR_SENTSTALL) | 357 | if (csr & USB_INCSR_INPKTRDY) { |
348 | { | 358 | logf("PKTRDY %d", endpoint); |
349 | REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; | ||
350 | return; | 359 | return; |
351 | } | 360 | } |
352 | 361 | ||
353 | if(ep->use_dma) | 362 | if (csr & USB_INCSR_SENTSTALL) { |
363 | logf("SENDSTALL %d", endpoint); | ||
364 | REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; | ||
354 | return; | 365 | return; |
366 | } | ||
355 | 367 | ||
356 | if(csr & USB_INCSR_FFNOTEMPT) | 368 | if (csr & USB_INCSR_FFNOTEMPT) { |
357 | { | ||
358 | logf("FIFO is not empty! 0x%x", csr); | 369 | logf("FIFO is not empty! 0x%x", csr); |
359 | return; | 370 | return; |
360 | } | 371 | } |
361 | 372 | ||
373 | #ifdef USE_USB_DMA | ||
374 | if(ep->use_dma >= 0) { | ||
375 | logf("DMA busy(%x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKIN), REG_USB_COUNT(USB_INTR_DMA_BULKIN),REG_USB_CNTL(USB_INTR_DMA_BULKIN)); | ||
376 | |||
377 | return; | ||
378 | } | ||
379 | #endif | ||
380 | |||
362 | logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length); | 381 | logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length); |
363 | 382 | ||
383 | #ifdef USE_USB_DMA | ||
384 | /* Can we use DMA? */ | ||
385 | if (ep->type == ep_bulk && ep->length && (!(((unsigned long)ep->buf + ep->sent) % 4)) && !button_hold()) { | ||
386 | if (ep->length >= ep->fifo_size) | ||
387 | ep->use_dma = 1; | ||
388 | else | ||
389 | ep->use_dma = 0; | ||
390 | } else { | ||
391 | ep->use_dma = -1; | ||
392 | } | ||
393 | |||
394 | if (ep->use_dma >= 0) { | ||
395 | commit_discard_dcache_range((void*)ep->buf + ep->sent, ep->length - ep->sent); | ||
396 | /* Set up DMA */ | ||
397 | uint16_t dmacr = USB_CNTL_BURST_16 | USB_CNTL_EP(EP_NUMBER2(ep)) | USB_CNTL_ENA | USB_CNTL_INTR_EN | USB_CNTL_DIR_IN ; | ||
398 | if (ep->use_dma > 0) | ||
399 | dmacr |= USB_CNTL_MODE_1; | ||
400 | |||
401 | REG_USB_ADDR(USB_INTR_DMA_BULKIN) = PHYSADDR((unsigned long)ep->buf + ep->sent); | ||
402 | REG_USB_COUNT(USB_INTR_DMA_BULKIN) = ep->length - ep->sent; | ||
403 | REG_USB_CNTL(USB_INTR_DMA_BULKIN) = dmacr; | ||
404 | |||
405 | uint16_t csr = REG_USB_INCSR; | ||
406 | if (ep->use_dma == 0) { | ||
407 | csr &= ~((USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQENAB) << 8); | ||
408 | REG_USB_INCSR = csr | TXCSR_WZC_BITS; | ||
409 | csr &= ~((USB_INCSRH_DMAREQMODE) << 8); | ||
410 | csr |= ((USB_INCSRH_DMAREQENAB | USB_INCSRH_MODE) << 8); | ||
411 | } else { | ||
412 | csr |= ((USB_INCSRH_DMAREQENAB | USB_INCSRH_MODE | USB_INCSRH_DMAREQMODE) << 8); | ||
413 | csr |= ((USB_INCSRH_AUTOSET) << 8); | ||
414 | } | ||
415 | csr &= ~USB_INCSR_UNDERRUN; | ||
416 | |||
417 | logf("DMA setup(%d: %x %x %x %x - %d)", EP_NUMBER2(ep), (unsigned int)PHYSADDR((unsigned long)ep->buf), ep->length, dmacr, csr, ep->use_dma); | ||
418 | |||
419 | REG_USB_INCSR = csr; | ||
420 | |||
421 | return; | ||
422 | } | ||
423 | #endif | ||
424 | |||
425 | /* Non-DMA code */ | ||
364 | if(ep->sent == 0) | 426 | if(ep->sent == 0) |
365 | length = MIN(ep->length, ep->fifo_size); | 427 | length = MIN(ep->length, ep->fifo_size); |
366 | else | 428 | else |
367 | length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); | 429 | length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); |
368 | 430 | ||
369 | writeFIFO(ep, length); | 431 | writeFIFO(ep, length); |
370 | REG_USB_INCSR = csr | USB_INCSR_INPKTRDY; | ||
371 | ep->sent += length; | 432 | ep->sent += length; |
433 | csr &= ~USB_INCSR_UNDERRUN; | ||
434 | csr |= USB_INCSR_INPKTRDY; | ||
435 | logf("Non-DMA TX %x", csr); | ||
436 | REG_USB_INCSR = csr; | ||
437 | } | ||
372 | 438 | ||
373 | if(ep->sent >= ep->length) | 439 | static void EPIN_complete(unsigned int endpoint) |
374 | { | 440 | { |
441 | struct usb_endpoint* ep = &endpoints[endpoint*2]; | ||
442 | uint16_t csr; | ||
443 | |||
444 | select_endpoint(endpoint); | ||
445 | csr = REG_USB_INCSR; | ||
446 | logf("%s(%d): 0x%x", __func__, endpoint, csr); | ||
447 | |||
448 | if (csr & USB_INCSR_SENTSTALL) { | ||
449 | logf("SENDSTALL %d\n", endpoint); | ||
450 | REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; // XXX TXCSR_P_WZC_BITS | ||
451 | return; | ||
452 | } | ||
453 | |||
454 | if (csr & USB_INCSR_UNDERRUN) { | ||
455 | csr |= TXCSR_WZC_BITS; | ||
456 | csr &= ~(USB_INCSR_UNDERRUN | USB_INCSR_INPKTRDY); | ||
457 | REG_USB_INCSR = csr; | ||
458 | logf("underrun! %x", csr); | ||
459 | } | ||
460 | |||
461 | if (!ep->busy) { | ||
462 | logf("Entered EPIN_complete without work!"); | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | if (ep->use_dma >= 0) { | ||
467 | logf("DMA status (%x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKIN), REG_USB_COUNT(USB_INTR_DMA_BULKIN),REG_USB_CNTL(USB_INTR_DMA_BULKIN)); | ||
468 | return; | ||
469 | } | ||
470 | |||
471 | /* If we get here, the operation is completed, and we need to clean up */ | ||
472 | |||
473 | /* Make sure DMA engine is idle */ | ||
474 | if (csr & (USB_INCSRH_DMAREQENAB << 8)) { | ||
475 | csr |= TXCSR_WZC_BITS; | ||
476 | csr &= ~(USB_INCSR_UNDERRUN | USB_INCSR_INPKTRDY | | ||
477 | ((USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET) << 8)); | ||
478 | REG_USB_INCSR = csr; | ||
479 | csr = REG_USB_INCSR; | ||
480 | logf("DMA cleanup %x", csr); | ||
481 | } | ||
482 | |||
483 | // XXX send a zero-length packet if necessary. | ||
484 | // if tx complete, and ep->length > 0 and ep->length % fifo == 0, | ||
485 | // REG_USB_INCSR = MODE | PKTRDY; | ||
486 | // Not needed for mass storage as it counts packets but | ||
487 | // if we ever enable other protocls... | ||
488 | |||
489 | logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length); | ||
490 | |||
491 | if(ep->sent >= ep->length) { | ||
375 | if (!ep->wait) | 492 | if (!ep->wait) |
376 | usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent); | 493 | usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent); |
377 | ep->rc = 0; | 494 | ep->rc = 0; |
378 | ep_transfer_completed(ep); | 495 | ep_transfer_completed(ep); |
379 | logf("sent complete"); | 496 | logf("send complete"); |
497 | } else { | ||
498 | EPIN_send(endpoint); | ||
380 | } | 499 | } |
381 | } | 500 | } |
382 | 501 | ||
@@ -403,9 +522,6 @@ static void EPOUT_handler(unsigned int endpoint) | |||
403 | return; | 522 | return; |
404 | } | 523 | } |
405 | 524 | ||
406 | if(ep->use_dma) | ||
407 | return; | ||
408 | |||
409 | if(csr & USB_OUTCSR_OUTPKTRDY) /* There is a packet in the fifo */ | 525 | if(csr & USB_OUTCSR_OUTPKTRDY) /* There is a packet in the fifo */ |
410 | { | 526 | { |
411 | size = REG_USB_OUTCOUNT; | 527 | size = REG_USB_OUTCOUNT; |
@@ -430,59 +546,55 @@ static void EPOUT_handler(unsigned int endpoint) | |||
430 | } | 546 | } |
431 | } | 547 | } |
432 | 548 | ||
549 | #ifdef USE_USB_DMA | ||
433 | static void EPDMA_handler(int number) | 550 | static void EPDMA_handler(int number) |
434 | { | 551 | { |
435 | int endpoint = -1; | 552 | int endpoint = -1; |
436 | unsigned int size = 0; | 553 | int size = 0; |
437 | struct usb_endpoint* ep = NULL; | 554 | struct usb_endpoint* ep = NULL; |
438 | 555 | ||
439 | if(number == USB_INTR_DMA_BULKIN) | 556 | endpoint = (REG_USB_CNTL(number) >> 4) & 0xF; |
440 | { | 557 | ep = &endpoints[endpoint*2]; |
441 | endpoint = (REG_USB_CNTL(0) >> 4) & 0xF; | 558 | if (!(REG_USB_CNTL(number) & USB_CNTL_DIR_IN)) |
442 | ep = &endpoints[endpoint*2]; | 559 | ep++; /* RX endpoint is +1 in the array */ |
443 | size = (unsigned int)ep->buf - REG_USB_ADDR(0); | 560 | size = VIRTADDR(REG_USB_ADDR(number)) - ((unsigned int)ep->buf + ep->sent); |
444 | } | 561 | |
445 | else if(number == USB_INTR_DMA_BULKOUT) | 562 | if (number == USB_INTR_DMA_BULKIN) { |
446 | { | 563 | if ((ep->use_dma == 0) || (size % ep->fifo_size)) { |
447 | endpoint = (REG_USB_CNTL(1) >> 4) & 0xF; | 564 | /* DMA is completed, but the final (short) packet needs to |
448 | ep = &endpoints[endpoint*2+1]; | 565 | be manually initiated! */ |
449 | size = (unsigned int)ep->buf - REG_USB_ADDR(1); | 566 | uint16_t incsr; |
450 | } | 567 | select_endpoint(endpoint); |
451 | 568 | incsr = REG_USB_INCSR; | |
452 | logf("DMA_BULK%d %d", number, endpoint); | 569 | |
453 | 570 | if (ep->use_dma == 1) { | |
454 | if(number == USB_INTR_DMA_BULKOUT) | 571 | /* Switch to Mode 0 DMA */ |
455 | { | 572 | incsr &= ~((USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQENAB) << 8); |
456 | /* Disable DMA */ | 573 | REG_USB_INCSR = incsr; |
457 | REG_USB_CNTL(1) = 0; | 574 | incsr &= ~((USB_INCSRH_DMAREQMODE) << 8); |
458 | 575 | incsr |= ((USB_INCSRH_DMAREQENAB) << 8); | |
459 | commit_discard_dcache(); // XXX range? | 576 | } |
460 | 577 | incsr |= USB_INCSR_INPKTRDY; | |
461 | select_endpoint(endpoint); | 578 | logf("DMA dangling %x", incsr); |
462 | /* Read out last packet manually */ | 579 | REG_USB_INCSR = incsr; |
463 | unsigned int lpack_size = REG_USB_OUTCOUNT; | ||
464 | if(lpack_size > 0) | ||
465 | { | ||
466 | ep->buf += ep->length - lpack_size; | ||
467 | readFIFO(ep, lpack_size); | ||
468 | REG_USB_OUTCSR &= ~USB_OUTCSR_OUTPKTRDY; | ||
469 | } | 580 | } |
470 | } | 581 | logf("DMA TX%d %d @%d/%d", number, size, ep->sent, ep->length); |
471 | else if(number == USB_INTR_DMA_BULKIN && size % ep->fifo_size) | 582 | ep->sent += size; |
472 | { | 583 | ep->use_dma = -1; /* DMA is complete, mark channel as idle */ |
473 | /* If the last packet is less than MAXP, set INPKTRDY manually */ | 584 | |
474 | REG_USB_INCSR |= USB_INCSR_INPKTRDY; | 585 | EPIN_complete(endpoint); |
475 | } | 586 | } else if (number == USB_INTR_DMA_BULKOUT) { |
476 | 587 | /* RX DMA completed */ | |
477 | if (ep) | 588 | logf("DMA RX%d %d @%d/%d", number, size, ep->received, ep->length); |
478 | { | 589 | ep->received += size; |
479 | int dir = EP_IS_IN(ep) ? USB_DIR_IN : USB_DIR_OUT; | 590 | ep->use_dma = -1; |
480 | if ((dir == USB_DIR_OUT) || !ep->wait) | 591 | |
481 | usb_core_transfer_complete(endpoint, dir, 0, ep->length); | 592 | EPOUT_handler(endpoint); |
482 | ep->rc = 0; | 593 | } else if (ep) { |
483 | ep_transfer_completed(ep); | 594 | ep->use_dma = -1; |
484 | } | 595 | } |
485 | } | 596 | } |
597 | #endif | ||
486 | 598 | ||
487 | static void setup_endpoint(struct usb_endpoint *ep) | 599 | static void setup_endpoint(struct usb_endpoint *ep) |
488 | { | 600 | { |
@@ -510,14 +622,13 @@ static void setup_endpoint(struct usb_endpoint *ep) | |||
510 | if(ep->type != ep_control) | 622 | if(ep->type != ep_control) |
511 | ep->fifo_size = usb_drv_port_speed() ? 512 : 64; | 623 | ep->fifo_size = usb_drv_port_speed() ? 512 : 64; |
512 | 624 | ||
625 | ep->config = REG_USB_CONFIGDATA; | ||
626 | |||
513 | if(EP_IS_IN(ep)) | 627 | if(EP_IS_IN(ep)) |
514 | { | 628 | { |
515 | csr = (USB_INCSR_FF | USB_INCSR_CDT); | 629 | csr = (USB_INCSR_FF | USB_INCSR_CDT); |
516 | csrh = USB_INCSRH_MODE; | 630 | csrh = USB_INCSRH_MODE; |
517 | 631 | ||
518 | if(ep->use_dma) | ||
519 | csrh |= (USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE); | ||
520 | |||
521 | if(ep->type == ep_interrupt) | 632 | if(ep->type == ep_interrupt) |
522 | csrh |= USB_INCSRH_FRCDATATOG; | 633 | csrh |= USB_INCSRH_FRCDATATOG; |
523 | 634 | ||
@@ -525,6 +636,8 @@ static void setup_endpoint(struct usb_endpoint *ep) | |||
525 | REG_USB_INCSR = csr; | 636 | REG_USB_INCSR = csr; |
526 | REG_USB_INCSRH = csrh; | 637 | REG_USB_INCSRH = csrh; |
527 | 638 | ||
639 | logf("IN %d (%x %x %x)", endpoint, ep->fifo_size, csr, csrh); | ||
640 | |||
528 | if (ep->allocated) | 641 | if (ep->allocated) |
529 | REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); | 642 | REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); |
530 | } | 643 | } |
@@ -536,13 +649,12 @@ static void setup_endpoint(struct usb_endpoint *ep) | |||
536 | if(ep->type == ep_interrupt) | 649 | if(ep->type == ep_interrupt) |
537 | csrh |= USB_OUTCSRH_DNYT; | 650 | csrh |= USB_OUTCSRH_DNYT; |
538 | 651 | ||
539 | if(ep->use_dma) | ||
540 | csrh |= (USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE); | ||
541 | |||
542 | REG_USB_OUTMAXP = ep->fifo_size; | 652 | REG_USB_OUTMAXP = ep->fifo_size; |
543 | REG_USB_OUTCSR = csr; | 653 | REG_USB_OUTCSR = csr; |
544 | REG_USB_OUTCSRH = csrh; | 654 | REG_USB_OUTCSRH = csrh; |
545 | 655 | ||
656 | logf("OUT %d (%x %x %x)", endpoint, ep->fifo_size, csr, csrh); | ||
657 | |||
546 | if (ep->allocated) | 658 | if (ep->allocated) |
547 | REG_USB_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep)); | 659 | REG_USB_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep)); |
548 | } | 660 | } |
@@ -574,8 +686,8 @@ static void udc_reset(void) | |||
574 | REG_USB_INTRUSBE = 0; | 686 | REG_USB_INTRUSBE = 0; |
575 | 687 | ||
576 | /* Disable DMA */ | 688 | /* Disable DMA */ |
577 | REG_USB_CNTL(0) = 0; | 689 | REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0; |
578 | REG_USB_CNTL(1) = 0; | 690 | REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0; |
579 | 691 | ||
580 | /* High speed, softconnect */ | 692 | /* High speed, softconnect */ |
581 | REG_USB_POWER = (USB_POWER_SOFTCONN | USB_POWER_HSENAB); | 693 | REG_USB_POWER = (USB_POWER_SOFTCONN | USB_POWER_HSENAB); |
@@ -584,6 +696,9 @@ static void udc_reset(void) | |||
584 | select_endpoint(0); | 696 | select_endpoint(0); |
585 | REG_USB_CSR0 = (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_SVDSETUPEND | USB_CSR0_FLUSHFIFO); | 697 | REG_USB_CSR0 = (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_SVDSETUPEND | USB_CSR0_FLUSHFIFO); |
586 | 698 | ||
699 | endpoints[0].config = REG_USB_CONFIGDATA; | ||
700 | endpoints[1].config = REG_USB_CONFIGDATA; | ||
701 | |||
587 | if (endpoints[0].busy) | 702 | if (endpoints[0].busy) |
588 | { | 703 | { |
589 | if (endpoints[0].wait) | 704 | if (endpoints[0].wait) |
@@ -627,17 +742,19 @@ void OTG(void) | |||
627 | unsigned char intrUSB = REG_USB_INTRUSB; | 742 | unsigned char intrUSB = REG_USB_INTRUSB; |
628 | unsigned short intrIn = REG_USB_INTRIN; | 743 | unsigned short intrIn = REG_USB_INTRIN; |
629 | unsigned short intrOut = REG_USB_INTROUT; | 744 | unsigned short intrOut = REG_USB_INTROUT; |
745 | #ifdef USE_USB_DMA | ||
630 | unsigned char intrDMA = REG_USB_INTR; | 746 | unsigned char intrDMA = REG_USB_INTR; |
747 | #endif | ||
631 | 748 | ||
632 | logf("%x %x %x %x", intrUSB, intrIn, intrOut, intrDMA); | 749 | logf("IRQ %x %x %x %x", intrUSB, intrIn, intrOut, intrDMA); |
633 | 750 | ||
634 | /* EPIN & EPOUT are all handled in DMA */ | 751 | /* EPIN & EPOUT are all handled in DMA */ |
635 | if(intrIn & USB_INTR_EP(0)) | 752 | if(intrIn & USB_INTR_EP(0)) |
636 | EP0_handler(); | 753 | EP0_handler(); |
637 | if(intrIn & USB_INTR_EP(1)) | 754 | if(intrIn & USB_INTR_EP(1)) |
638 | EPIN_handler(1); | 755 | EPIN_complete(1); |
639 | if(intrIn & USB_INTR_EP(2)) | 756 | if(intrIn & USB_INTR_EP(2)) |
640 | EPIN_handler(2); | 757 | EPIN_complete(2); |
641 | if(intrOut & USB_INTR_EP(1)) | 758 | if(intrOut & USB_INTR_EP(1)) |
642 | EPOUT_handler(1); | 759 | EPOUT_handler(1); |
643 | if(intrOut & USB_INTR_EP(2)) | 760 | if(intrOut & USB_INTR_EP(2)) |
@@ -648,10 +765,12 @@ void OTG(void) | |||
648 | logf("USB suspend"); | 765 | logf("USB suspend"); |
649 | if(intrUSB & USB_INTR_RESUME) | 766 | if(intrUSB & USB_INTR_RESUME) |
650 | logf("USB resume"); | 767 | logf("USB resume"); |
651 | if(intrDMA & USB_INTR_DMA_BULKIN) | 768 | #ifdef USE_USB_DMA |
769 | if(intrDMA & (1<<USB_INTR_DMA_BULKIN)) | ||
652 | EPDMA_handler(USB_INTR_DMA_BULKIN); | 770 | EPDMA_handler(USB_INTR_DMA_BULKIN); |
653 | if(intrDMA & USB_INTR_DMA_BULKOUT) | 771 | if(intrDMA & (1<<USB_INTR_DMA_BULKOUT)) |
654 | EPDMA_handler(USB_INTR_DMA_BULKOUT); | 772 | EPDMA_handler(USB_INTR_DMA_BULKOUT); |
773 | #endif | ||
655 | } | 774 | } |
656 | 775 | ||
657 | bool usb_drv_stalled(int endpoint, bool in) | 776 | bool usb_drv_stalled(int endpoint, bool in) |
@@ -790,6 +909,10 @@ void usb_drv_exit(void) | |||
790 | { | 909 | { |
791 | logf("%s()", __func__); | 910 | logf("%s()", __func__); |
792 | 911 | ||
912 | select_endpoint(1); | ||
913 | |||
914 | logf("DMA X (%x %x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKIN), REG_USB_COUNT(USB_INTR_DMA_BULKIN),REG_USB_CNTL(USB_INTR_DMA_BULKIN), REG_USB_INCSR); | ||
915 | |||
793 | REG_USB_FADDR = 0; | 916 | REG_USB_FADDR = 0; |
794 | REG_USB_INDEX = 0; | 917 | REG_USB_INDEX = 0; |
795 | 918 | ||
@@ -798,9 +921,11 @@ void usb_drv_exit(void) | |||
798 | REG_USB_INTROUTE = 0; | 921 | REG_USB_INTROUTE = 0; |
799 | REG_USB_INTRUSBE = 0; | 922 | REG_USB_INTRUSBE = 0; |
800 | 923 | ||
924 | #ifdef USE_USB_DMA | ||
801 | /* Disable DMA */ | 925 | /* Disable DMA */ |
802 | REG_USB_CNTL(0) = 0; | 926 | REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0; |
803 | REG_USB_CNTL(1) = 0; | 927 | REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0; |
928 | #endif | ||
804 | 929 | ||
805 | /* Disconnect from USB */ | 930 | /* Disconnect from USB */ |
806 | REG_USB_POWER &= ~USB_POWER_SOFTCONN; | 931 | REG_USB_POWER &= ~USB_POWER_SOFTCONN; |
@@ -817,10 +942,8 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length | |||
817 | { | 942 | { |
818 | int flags = disable_irq_save(); | 943 | int flags = disable_irq_save(); |
819 | 944 | ||
820 | if(ep->type == ep_control) | 945 | if (ep->type == ep_control) { |
821 | { | 946 | if ((ptr == NULL && length == 0) || !ep0_data_requested) { |
822 | if ((ptr == NULL && length == 0) || !ep0_data_requested) | ||
823 | { | ||
824 | restore_irq(flags); | 947 | restore_irq(flags); |
825 | return; | 948 | return; |
826 | } | 949 | } |
@@ -831,36 +954,22 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length | |||
831 | ep->sent = 0; | 954 | ep->sent = 0; |
832 | ep->length = length; | 955 | ep->length = length; |
833 | ep->busy = true; | 956 | ep->busy = true; |
834 | if(blocking) | 957 | if(blocking) { |
835 | { | ||
836 | ep->rc = -1; | 958 | ep->rc = -1; |
837 | ep->wait = true; | 959 | ep->wait = true; |
960 | } else { | ||
961 | ep->rc = 0; | ||
838 | } | 962 | } |
839 | else ep->rc = 0; | ||
840 | 963 | ||
841 | if(ep->type == ep_control) | 964 | if (ep->type == ep_control) { |
842 | { | ||
843 | EP0_send(); | 965 | EP0_send(); |
844 | } | 966 | } else { |
845 | else | 967 | EPIN_send(EP_NUMBER2(ep)); |
846 | { | ||
847 | if(ep->use_dma) | ||
848 | { | ||
849 | commit_discard_dcache_range(ptr, length); | ||
850 | REG_USB_ADDR(0) = PHYSADDR((unsigned long)ptr); | ||
851 | REG_USB_COUNT(0) = length; | ||
852 | REG_USB_CNTL(0) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | | ||
853 | USB_CNTL_DIR_IN | USB_CNTL_ENA | | ||
854 | USB_CNTL_EP(EP_NUMBER2(ep)) | USB_CNTL_BURST_16); | ||
855 | } | ||
856 | else | ||
857 | EPIN_handler(EP_NUMBER2(ep)); | ||
858 | } | 968 | } |
859 | 969 | ||
860 | restore_irq(flags); | 970 | restore_irq(flags); |
861 | 971 | ||
862 | if(blocking) | 972 | if(blocking) { |
863 | { | ||
864 | semaphore_wait(&ep->complete, HZ); | 973 | semaphore_wait(&ep->complete, HZ); |
865 | ep->wait = false; | 974 | ep->wait = false; |
866 | } | 975 | } |
@@ -918,23 +1027,12 @@ int usb_drv_recv(int endpoint, void* ptr, int length) | |||
918 | ep->received = 0; | 1027 | ep->received = 0; |
919 | ep->length = length; | 1028 | ep->length = length; |
920 | ep->busy = true; | 1029 | ep->busy = true; |
921 | if(ep->use_dma) | 1030 | |
922 | { | 1031 | if (endpoint == EP_CONTROL) { |
923 | discard_dcache_range(ptr, length); | 1032 | ep0_data_supplied = false; |
924 | REG_USB_ADDR(1) = PHYSADDR((unsigned long)ptr); | 1033 | EP0_handler(); |
925 | REG_USB_COUNT(1) = length; | 1034 | } else { |
926 | REG_USB_CNTL(1) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | | 1035 | EPOUT_handler(endpoint); |
927 | USB_CNTL_ENA | USB_CNTL_EP(endpoint) | | ||
928 | USB_CNTL_BURST_16); | ||
929 | } | ||
930 | else | ||
931 | { | ||
932 | if (endpoint == EP_CONTROL) | ||
933 | { | ||
934 | ep0_data_supplied = false; | ||
935 | EP0_handler(); | ||
936 | } | ||
937 | else EPOUT_handler(endpoint); | ||
938 | } | 1036 | } |
939 | 1037 | ||
940 | restore_irq(flags); | 1038 | restore_irq(flags); |
@@ -976,6 +1074,12 @@ void usb_drv_cancel_all_transfers(void) | |||
976 | 1074 | ||
977 | unsigned int i, flags = disable_irq_save(); | 1075 | unsigned int i, flags = disable_irq_save(); |
978 | 1076 | ||
1077 | #ifdef USE_USB_DMA | ||
1078 | /* Disable DMA */ | ||
1079 | REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0; | ||
1080 | REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0; | ||
1081 | #endif | ||
1082 | |||
979 | for(i=0; i<TOTAL_EP(); i++) | 1083 | for(i=0; i<TOTAL_EP(); i++) |
980 | { | 1084 | { |
981 | if (endpoints[i].busy) | 1085 | if (endpoints[i].busy) |
@@ -996,6 +1100,7 @@ void usb_drv_cancel_all_transfers(void) | |||
996 | select_endpoint(i/2); | 1100 | select_endpoint(i/2); |
997 | flushFIFO(&endpoints[i]); | 1101 | flushFIFO(&endpoints[i]); |
998 | } | 1102 | } |
1103 | |||
999 | restore_irq(flags); | 1104 | restore_irq(flags); |
1000 | } | 1105 | } |
1001 | 1106 | ||