diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2020-09-17 22:49:31 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2020-09-18 17:48:31 -0400 |
commit | e404026308081dd1aef79e891326040747fef9d6 (patch) | |
tree | 54f747b54ba41c8247b356facd305e4100b19fd0 | |
parent | 2df3a5b04c40d548391c69c18780fefd420fac02 (diff) | |
download | rockbox-e404026308081dd1aef79e891326040747fef9d6.tar.gz rockbox-e404026308081dd1aef79e891326040747fef9d6.zip |
jz4760: Implement USB DMA RX
Can be disabled at runtime by setting hold switch.
Boosts sysbench sequential write performance by 34-58%
Change-Id: I060c9d7dddc1b448f18aa46af8f8aff046e07843
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | 157 |
1 files changed, 135 insertions, 22 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c index 8562d9253c..37df1b3bb6 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #define EP_IS_IN(ep) (EP_NUMBER((ep))%2) | 47 | #define EP_IS_IN(ep) (EP_NUMBER((ep))%2) |
48 | 48 | ||
49 | #define TXCSR_WZC_BITS (USB_INCSR_SENTSTALL | USB_INCSR_UNDERRUN | USB_INCSR_FFNOTEMPT | USB_INCSR_INCOMPTX) | 49 | #define TXCSR_WZC_BITS (USB_INCSR_SENTSTALL | USB_INCSR_UNDERRUN | USB_INCSR_FFNOTEMPT | USB_INCSR_INCOMPTX) |
50 | #define RXCSR_WZC_BITS (USB_OUTCSR_SENTSTALL | USB_OUTCSR_OVERRUN | USB_OUTCSR_OUTPKTRDY) | ||
50 | 51 | ||
51 | /* NOTE: IN/OUT is from the HOST perspective. We're a peripheral, so: | 52 | /* NOTE: IN/OUT is from the HOST perspective. We're a peripheral, so: |
52 | IN = DEV->HOST, (ie we send) | 53 | IN = DEV->HOST, (ie we send) |
@@ -90,6 +91,9 @@ struct usb_endpoint | |||
90 | .buf = (_buf), .use_dma = -1, \ | 91 | .buf = (_buf), .use_dma = -1, \ |
91 | .length = 0, .busy = false, .wait = false, .allocated = false } | 92 | .length = 0, .busy = false, .wait = false, .allocated = false } |
92 | 93 | ||
94 | #define short_not_ok 1 /* only works for mass storage.. */ | ||
95 | #define ep_doublebuf(__ep) 0 | ||
96 | |||
93 | static union | 97 | static union |
94 | { | 98 | { |
95 | int buf[64 / sizeof(int)]; | 99 | int buf[64 / sizeof(int)]; |
@@ -360,7 +364,7 @@ static void EPIN_send(unsigned int endpoint) | |||
360 | } | 364 | } |
361 | 365 | ||
362 | if (csr & USB_INCSR_SENTSTALL) { | 366 | if (csr & USB_INCSR_SENTSTALL) { |
363 | logf("SENDSTALL %d", endpoint); | 367 | logf("TX SENTSTALL %d", endpoint); |
364 | REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; | 368 | REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; |
365 | return; | 369 | return; |
366 | } | 370 | } |
@@ -446,7 +450,7 @@ static void EPIN_complete(unsigned int endpoint) | |||
446 | logf("%s(%d): 0x%x", __func__, endpoint, csr); | 450 | logf("%s(%d): 0x%x", __func__, endpoint, csr); |
447 | 451 | ||
448 | if (csr & USB_INCSR_SENTSTALL) { | 452 | if (csr & USB_INCSR_SENTSTALL) { |
449 | logf("SENDSTALL %d\n", endpoint); | 453 | logf("TX SENTSTALL %d", endpoint); |
450 | REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; // XXX TXCSR_P_WZC_BITS | 454 | REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL; // XXX TXCSR_P_WZC_BITS |
451 | return; | 455 | return; |
452 | } | 456 | } |
@@ -504,26 +508,77 @@ static void EPOUT_handler(unsigned int endpoint) | |||
504 | struct usb_endpoint* ep = &endpoints[endpoint*2+1]; | 508 | struct usb_endpoint* ep = &endpoints[endpoint*2+1]; |
505 | unsigned int size, csr; | 509 | unsigned int size, csr; |
506 | 510 | ||
507 | if(!ep->busy) | 511 | if(!ep->busy) { |
508 | { | ||
509 | logf("Entered EPOUT handler without work!"); | 512 | logf("Entered EPOUT handler without work!"); |
510 | return; | 513 | return; |
511 | } | 514 | } |
512 | 515 | ||
513 | select_endpoint(endpoint); | 516 | select_endpoint(endpoint); |
514 | while((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) | 517 | while((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) { |
515 | { | ||
516 | logf("%s(%d): 0x%x", __func__, endpoint, csr); | 518 | logf("%s(%d): 0x%x", __func__, endpoint, csr); |
517 | if(csr & USB_OUTCSR_SENTSTALL) | 519 | if(csr & USB_OUTCSR_SENTSTALL) { |
518 | { | ||
519 | logf("stall sent, flushing fifo.."); | 520 | logf("stall sent, flushing fifo.."); |
520 | flushFIFO(ep); | 521 | flushFIFO(ep); |
521 | REG_USB_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL; | 522 | REG_USB_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL; |
522 | return; | 523 | return; |
523 | } | 524 | } |
524 | 525 | ||
525 | if(csr & USB_OUTCSR_OUTPKTRDY) /* There is a packet in the fifo */ | 526 | #ifdef USE_USB_DMA |
526 | { | 527 | if (ep->use_dma >= 0) { |
528 | logf("DMA busy(%x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKOUT), REG_USB_COUNT(USB_INTR_DMA_BULKOUT),REG_USB_CNTL(USB_INTR_DMA_BULKOUT)); | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | /* Can we use DMA? */ | ||
533 | if (ep->type == ep_bulk && ep->length && (!(((unsigned long)ep->buf + ep->received) % 4)) && !button_hold()) { | ||
534 | if (ep->length >= ep->fifo_size && short_not_ok) | ||
535 | ep->use_dma = 1; | ||
536 | else | ||
537 | ep->use_dma = 0; | ||
538 | } else { | ||
539 | ep->use_dma = -1; | ||
540 | } | ||
541 | logf("RX DMA? %d", ep->use_dma); | ||
542 | |||
543 | /* Set up RX side for DMA */ | ||
544 | if (ep->use_dma == 1) { | ||
545 | csr |= (USB_OUTCSRH_AUTOCLR) << 8; | ||
546 | REG_USB_OUTCSR = csr; | ||
547 | csr |= USB_OUTCSRH_DMAREQENAB << 8; | ||
548 | REG_USB_OUTCSR = csr; | ||
549 | |||
550 | csr |= (USB_OUTCSRH_DMAREQMODE << 8); // XXX | ||
551 | // /* Work around HW quirk; write and clear DMAMODE */ | ||
552 | // REG_USB_OUTCSR = csr | (USB_OUTCSRH_DMAREQMODE << 8); | ||
553 | |||
554 | } else if (ep->use_dma == 0) { | ||
555 | if (ep_doublebuf(ep)) // XXX or isoc.. | ||
556 | csr |= ((USB_OUTCSRH_AUTOCLR) << 8); | ||
557 | csr |= USB_OUTCSRH_DMAREQENAB << 8; | ||
558 | } | ||
559 | /* Set up DMA engine */ | ||
560 | if (ep->use_dma >= 0) { | ||
561 | REG_USB_OUTCSR = csr; | ||
562 | logf("DMA RX %d csr %x", ep->use_dma, csr); | ||
563 | discard_dcache_range((void*)ep->buf + ep->received, ep->length - ep->received); | ||
564 | |||
565 | /* Program actual DMA channel */ | ||
566 | uint16_t dmacr = USB_CNTL_BURST_16 | USB_CNTL_EP(EP_NUMBER2(ep)) | USB_CNTL_ENA | USB_CNTL_INTR_EN; | ||
567 | if (ep->use_dma > 0) | ||
568 | dmacr |= USB_CNTL_MODE_1; | ||
569 | |||
570 | REG_USB_ADDR(USB_INTR_DMA_BULKOUT) = PHYSADDR((unsigned long)ep->buf + ep->received); | ||
571 | REG_USB_COUNT(USB_INTR_DMA_BULKOUT) = ep->length - ep->received; | ||
572 | REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = dmacr; | ||
573 | logf("DMA RX start %x %d %x", (unsigned int)ep->buf + ep->received, | ||
574 | (ep->length - ep->received), dmacr); | ||
575 | |||
576 | return; /* ie wait for DMA to complete */ | ||
577 | } | ||
578 | #endif | ||
579 | |||
580 | /* There is a packet in the fifo, copy it out via PIO */ | ||
581 | if (csr & USB_OUTCSR_OUTPKTRDY) { | ||
527 | size = REG_USB_OUTCOUNT; | 582 | size = REG_USB_OUTCOUNT; |
528 | 583 | ||
529 | readFIFO(ep, size); | 584 | readFIFO(ep, size); |
@@ -536,8 +591,7 @@ static void EPOUT_handler(unsigned int endpoint) | |||
536 | 591 | ||
537 | logf("received: %d max length: %d", ep->received, ep->length); | 592 | logf("received: %d max length: %d", ep->received, ep->length); |
538 | 593 | ||
539 | if(size < ep->fifo_size || ep->received >= ep->length) | 594 | if(size < ep->fifo_size || ep->received >= ep->length) { |
540 | { | ||
541 | usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received); | 595 | usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received); |
542 | ep_transfer_completed(ep); | 596 | ep_transfer_completed(ep); |
543 | logf("receive transfer_complete"); | 597 | logf("receive transfer_complete"); |
@@ -546,6 +600,67 @@ static void EPOUT_handler(unsigned int endpoint) | |||
546 | } | 600 | } |
547 | } | 601 | } |
548 | 602 | ||
603 | static void EPOUT_ready(unsigned int endpoint) | ||
604 | { | ||
605 | logf("%s(%d)", __func__, endpoint); | ||
606 | |||
607 | #ifdef USE_USB_DMA | ||
608 | struct usb_endpoint* ep = &endpoints[endpoint*2+1]; | ||
609 | unsigned int csr; | ||
610 | |||
611 | select_endpoint(endpoint); | ||
612 | csr = REG_USB_OUTCSR; | ||
613 | |||
614 | if(!ep->busy) | ||
615 | { | ||
616 | logf("Entered EPOUT handler without work!"); | ||
617 | return; | ||
618 | } | ||
619 | |||
620 | // check for stall | ||
621 | // check for overrun | ||
622 | // check for incomprx | ||
623 | |||
624 | /* If DMA engine is enabled, handle and clean up */ | ||
625 | if (ep->use_dma >= 0 && csr & (USB_OUTCSRH_DMAREQENAB << 8)) { | ||
626 | int size = VIRTADDR(REG_USB_ADDR(USB_INTR_DMA_BULKOUT)) - ((unsigned int)ep->buf + ep->received); | ||
627 | |||
628 | csr &= ~((USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_DMAREQMODE) << 8); | ||
629 | REG_USB_OUTCSR = csr | RXCSR_WZC_BITS; | ||
630 | logf("EPOUT DMA RX %x %d @%d/%d", csr, size, ep->received, ep->length); | ||
631 | ep->received += size; | ||
632 | |||
633 | /* Autoclear doesn't clear OutPktRdy for short packets.. */ | ||
634 | if ((ep->use_dma == 0 && !ep_doublebuf(ep)) || size % ep->fifo_size) { | ||
635 | csr &= ~USB_OUTCSR_OUTPKTRDY; | ||
636 | REG_USB_OUTCSR = csr; | ||
637 | logf("Cleanup after short RX %x", csr); | ||
638 | } | ||
639 | // XXX what about 0-length transfers? | ||
640 | |||
641 | /* If we're incomplete, wait for the next one.. */ | ||
642 | if (ep->received < ep->length && size == ep->fifo_size) { | ||
643 | csr = REG_USB_OUTCSR; | ||
644 | if (csr & USB_OUTCSR_OUTPKTRDY && ep_doublebuf(ep)) | ||
645 | goto exit; | ||
646 | return; | ||
647 | } | ||
648 | |||
649 | /* It we're done, clean up */ | ||
650 | if (size < ep->fifo_size || ep->received >= ep->length) { | ||
651 | ep->use_dma = -1; | ||
652 | usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received); | ||
653 | ep_transfer_completed(ep); | ||
654 | logf("DMA RX transfer_complete"); | ||
655 | return; | ||
656 | } | ||
657 | } | ||
658 | |||
659 | exit: | ||
660 | #endif | ||
661 | EPOUT_handler(endpoint); | ||
662 | } | ||
663 | |||
549 | #ifdef USE_USB_DMA | 664 | #ifdef USE_USB_DMA |
550 | static void EPDMA_handler(int number) | 665 | static void EPDMA_handler(int number) |
551 | { | 666 | { |
@@ -586,10 +701,7 @@ static void EPDMA_handler(int number) | |||
586 | } else if (number == USB_INTR_DMA_BULKOUT) { | 701 | } else if (number == USB_INTR_DMA_BULKOUT) { |
587 | /* RX DMA completed */ | 702 | /* RX DMA completed */ |
588 | logf("DMA RX%d %d @%d/%d", number, size, ep->received, ep->length); | 703 | logf("DMA RX%d %d @%d/%d", number, size, ep->received, ep->length); |
589 | ep->received += size; | 704 | EPOUT_ready(endpoint); |
590 | ep->use_dma = -1; | ||
591 | |||
592 | EPOUT_handler(endpoint); | ||
593 | } else if (ep) { | 705 | } else if (ep) { |
594 | ep->use_dma = -1; | 706 | ep->use_dma = -1; |
595 | } | 707 | } |
@@ -756,9 +868,9 @@ void OTG(void) | |||
756 | if(intrIn & USB_INTR_EP(2)) | 868 | if(intrIn & USB_INTR_EP(2)) |
757 | EPIN_complete(2); | 869 | EPIN_complete(2); |
758 | if(intrOut & USB_INTR_EP(1)) | 870 | if(intrOut & USB_INTR_EP(1)) |
759 | EPOUT_handler(1); | 871 | EPOUT_ready(1); |
760 | if(intrOut & USB_INTR_EP(2)) | 872 | if(intrOut & USB_INTR_EP(2)) |
761 | EPOUT_handler(2); | 873 | EPOUT_ready(2); |
762 | if(intrUSB & USB_INTR_RESET) | 874 | if(intrUSB & USB_INTR_RESET) |
763 | udc_reset(); | 875 | udc_reset(); |
764 | if(intrUSB & USB_INTR_SUSPEND) | 876 | if(intrUSB & USB_INTR_SUSPEND) |
@@ -909,10 +1021,6 @@ void usb_drv_exit(void) | |||
909 | { | 1021 | { |
910 | logf("%s()", __func__); | 1022 | logf("%s()", __func__); |
911 | 1023 | ||
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 | |||
916 | REG_USB_FADDR = 0; | 1024 | REG_USB_FADDR = 0; |
917 | REG_USB_INDEX = 0; | 1025 | REG_USB_INDEX = 0; |
918 | 1026 | ||
@@ -922,6 +1030,11 @@ void usb_drv_exit(void) | |||
922 | REG_USB_INTRUSBE = 0; | 1030 | REG_USB_INTRUSBE = 0; |
923 | 1031 | ||
924 | #ifdef USE_USB_DMA | 1032 | #ifdef USE_USB_DMA |
1033 | select_endpoint(1); | ||
1034 | |||
1035 | logf("X DMA RX (%x %x %x %x)", REG_USB_ADDR(USB_INTR_DMA_BULKOUT), REG_USB_COUNT(USB_INTR_DMA_BULKOUT),REG_USB_CNTL(USB_INTR_DMA_BULKOUT), REG_USB_OUTCSR); | ||
1036 | logf("X DMA TX (%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); | ||
1037 | |||
925 | /* Disable DMA */ | 1038 | /* Disable DMA */ |
926 | REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0; | 1039 | REG_USB_CNTL(USB_INTR_DMA_BULKIN) = 0; |
927 | REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0; | 1040 | REG_USB_CNTL(USB_INTR_DMA_BULKOUT) = 0; |