summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/usb-jz4760.c')
-rw-r--r--firmware/target/mips/ingenic_jz47xx/usb-jz4760.c157
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
93static union 97static 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
603static 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
659exit:
660#endif
661 EPOUT_handler(endpoint);
662}
663
549#ifdef USE_USB_DMA 664#ifdef USE_USB_DMA
550static void EPDMA_handler(int number) 665static 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;