diff options
-rw-r--r-- | drivers/usb/renesas_usbhs/common.c | 2 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/common.h | 35 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.c | 380 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.h | 24 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_gadget.c | 70 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.c | 4 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.h | 4 | ||||
-rw-r--r-- | include/linux/usb/renesas_usbhs.h | 17 |
8 files changed, 533 insertions, 3 deletions
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index e510b29216b3..665259aec871 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c | |||
@@ -304,6 +304,8 @@ static int __devinit usbhs_probe(struct platform_device *pdev) | |||
304 | priv->dparam->pipe_type = usbhsc_default_pipe_type; | 304 | priv->dparam->pipe_type = usbhsc_default_pipe_type; |
305 | priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); | 305 | priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); |
306 | } | 306 | } |
307 | if (!priv->dparam->pio_dma_border) | ||
308 | priv->dparam->pio_dma_border = 64; /* 64byte */ | ||
307 | 309 | ||
308 | /* FIXME */ | 310 | /* FIXME */ |
309 | /* runtime power control ? */ | 311 | /* runtime power control ? */ |
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 06d7239a044d..b410463a1212 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h | |||
@@ -36,6 +36,12 @@ struct usbhs_priv; | |||
36 | #define CFIFO 0x0014 | 36 | #define CFIFO 0x0014 |
37 | #define CFIFOSEL 0x0020 | 37 | #define CFIFOSEL 0x0020 |
38 | #define CFIFOCTR 0x0022 | 38 | #define CFIFOCTR 0x0022 |
39 | #define D0FIFO 0x0100 | ||
40 | #define D0FIFOSEL 0x0028 | ||
41 | #define D0FIFOCTR 0x002A | ||
42 | #define D1FIFO 0x0120 | ||
43 | #define D1FIFOSEL 0x002C | ||
44 | #define D1FIFOCTR 0x002E | ||
39 | #define INTENB0 0x0030 | 45 | #define INTENB0 0x0030 |
40 | #define INTENB1 0x0032 | 46 | #define INTENB1 0x0032 |
41 | #define BRDYENB 0x0036 | 47 | #define BRDYENB 0x0036 |
@@ -60,6 +66,30 @@ struct usbhs_priv; | |||
60 | #define PIPEMAXP 0x006C | 66 | #define PIPEMAXP 0x006C |
61 | #define PIPEPERI 0x006E | 67 | #define PIPEPERI 0x006E |
62 | #define PIPEnCTR 0x0070 | 68 | #define PIPEnCTR 0x0070 |
69 | #define PIPE1TRE 0x0090 | ||
70 | #define PIPE1TRN 0x0092 | ||
71 | #define PIPE2TRE 0x0094 | ||
72 | #define PIPE2TRN 0x0096 | ||
73 | #define PIPE3TRE 0x0098 | ||
74 | #define PIPE3TRN 0x009A | ||
75 | #define PIPE4TRE 0x009C | ||
76 | #define PIPE4TRN 0x009E | ||
77 | #define PIPE5TRE 0x00A0 | ||
78 | #define PIPE5TRN 0x00A2 | ||
79 | #define PIPEBTRE 0x00A4 | ||
80 | #define PIPEBTRN 0x00A6 | ||
81 | #define PIPECTRE 0x00A8 | ||
82 | #define PIPECTRN 0x00AA | ||
83 | #define PIPEDTRE 0x00AC | ||
84 | #define PIPEDTRN 0x00AE | ||
85 | #define PIPEETRE 0x00B0 | ||
86 | #define PIPEETRN 0x00B2 | ||
87 | #define PIPEFTRE 0x00B4 | ||
88 | #define PIPEFTRN 0x00B6 | ||
89 | #define PIPE9TRE 0x00B8 | ||
90 | #define PIPE9TRN 0x00BA | ||
91 | #define PIPEATRE 0x00BC | ||
92 | #define PIPEATRN 0x00BE | ||
63 | 93 | ||
64 | /* SYSCFG */ | 94 | /* SYSCFG */ |
65 | #define SCKE (1 << 10) /* USB Module Clock Enable */ | 95 | #define SCKE (1 << 10) /* USB Module Clock Enable */ |
@@ -78,6 +108,7 @@ struct usbhs_priv; | |||
78 | #define RHST_HIGH_SPEED 3 /* High-speed connection */ | 108 | #define RHST_HIGH_SPEED 3 /* High-speed connection */ |
79 | 109 | ||
80 | /* CFIFOSEL */ | 110 | /* CFIFOSEL */ |
111 | #define DREQE (1 << 12) /* DMA Transfer Request Enable */ | ||
81 | #define MBW_32 (0x2 << 10) /* CFIFO Port Access Bit Width */ | 112 | #define MBW_32 (0x2 << 10) /* CFIFO Port Access Bit Width */ |
82 | 113 | ||
83 | /* CFIFOCTR */ | 114 | /* CFIFOCTR */ |
@@ -164,6 +195,10 @@ struct usbhs_priv; | |||
164 | 195 | ||
165 | #define CCPL (1 << 2) /* Control Transfer End Enable */ | 196 | #define CCPL (1 << 2) /* Control Transfer End Enable */ |
166 | 197 | ||
198 | /* PIPEnTRE */ | ||
199 | #define TRENB (1 << 9) /* Transaction Counter Enable */ | ||
200 | #define TRCLR (1 << 8) /* Transaction Counter Clear */ | ||
201 | |||
167 | /* FRMNUM */ | 202 | /* FRMNUM */ |
168 | #define FRNM_MASK (0x7FF) | 203 | #define FRNM_MASK (0x7FF) |
169 | 204 | ||
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 14baaad20b79..2016a2448ccb 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include "./pipe.h" | 20 | #include "./pipe.h" |
21 | 21 | ||
22 | #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) | 22 | #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) |
23 | #define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo)) | ||
24 | #define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo)) | ||
23 | 25 | ||
24 | #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ | 26 | #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ |
25 | 27 | ||
@@ -43,6 +45,7 @@ static struct usbhs_pkt_handle usbhsf_null_handler = { | |||
43 | 45 | ||
44 | void usbhs_pkt_init(struct usbhs_pkt *pkt) | 46 | void usbhs_pkt_init(struct usbhs_pkt *pkt) |
45 | { | 47 | { |
48 | pkt->dma = DMA_ADDR_INVALID; | ||
46 | INIT_LIST_HEAD(&pkt->node); | 49 | INIT_LIST_HEAD(&pkt->node); |
47 | } | 50 | } |
48 | 51 | ||
@@ -136,6 +139,9 @@ int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type) | |||
136 | case USBHSF_PKT_TRY_RUN: | 139 | case USBHSF_PKT_TRY_RUN: |
137 | func = pkt->handler->try_run; | 140 | func = pkt->handler->try_run; |
138 | break; | 141 | break; |
142 | case USBHSF_PKT_DMA_DONE: | ||
143 | func = pkt->handler->dma_done; | ||
144 | break; | ||
139 | default: | 145 | default: |
140 | dev_err(dev, "unknown pkt hander\n"); | 146 | dev_err(dev, "unknown pkt hander\n"); |
141 | goto __usbhs_pkt_handler_end; | 147 | goto __usbhs_pkt_handler_end; |
@@ -508,6 +514,330 @@ struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = { | |||
508 | }; | 514 | }; |
509 | 515 | ||
510 | /* | 516 | /* |
517 | * DMA fifo functions | ||
518 | */ | ||
519 | static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, | ||
520 | struct usbhs_pkt *pkt) | ||
521 | { | ||
522 | if (&usbhs_fifo_dma_push_handler == pkt->handler) | ||
523 | return fifo->tx_chan; | ||
524 | |||
525 | if (&usbhs_fifo_dma_pop_handler == pkt->handler) | ||
526 | return fifo->rx_chan; | ||
527 | |||
528 | return NULL; | ||
529 | } | ||
530 | |||
531 | static struct usbhs_fifo *usbhsf_get_dma_fifo(struct usbhs_priv *priv, | ||
532 | struct usbhs_pkt *pkt) | ||
533 | { | ||
534 | struct usbhs_fifo *fifo; | ||
535 | |||
536 | /* DMA :: D0FIFO */ | ||
537 | fifo = usbhsf_get_d0fifo(priv); | ||
538 | if (usbhsf_dma_chan_get(fifo, pkt) && | ||
539 | !usbhsf_fifo_is_busy(fifo)) | ||
540 | return fifo; | ||
541 | |||
542 | /* DMA :: D1FIFO */ | ||
543 | fifo = usbhsf_get_d1fifo(priv); | ||
544 | if (usbhsf_dma_chan_get(fifo, pkt) && | ||
545 | !usbhsf_fifo_is_busy(fifo)) | ||
546 | return fifo; | ||
547 | |||
548 | return NULL; | ||
549 | } | ||
550 | |||
551 | #define usbhsf_dma_start(p, f) __usbhsf_dma_ctrl(p, f, DREQE) | ||
552 | #define usbhsf_dma_stop(p, f) __usbhsf_dma_ctrl(p, f, 0) | ||
553 | static void __usbhsf_dma_ctrl(struct usbhs_pipe *pipe, | ||
554 | struct usbhs_fifo *fifo, | ||
555 | u16 dreqe) | ||
556 | { | ||
557 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | ||
558 | |||
559 | usbhs_bset(priv, fifo->sel, DREQE, dreqe); | ||
560 | } | ||
561 | |||
562 | #define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1) | ||
563 | #define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0) | ||
564 | static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) | ||
565 | { | ||
566 | struct usbhs_pipe *pipe = pkt->pipe; | ||
567 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | ||
568 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); | ||
569 | |||
570 | return info->dma_map_ctrl(pkt, map); | ||
571 | } | ||
572 | |||
573 | static void usbhsf_dma_complete(void *arg); | ||
574 | static void usbhsf_dma_prepare_tasklet(unsigned long data) | ||
575 | { | ||
576 | struct usbhs_pkt *pkt = (struct usbhs_pkt *)data; | ||
577 | struct usbhs_pipe *pipe = pkt->pipe; | ||
578 | struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); | ||
579 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | ||
580 | struct scatterlist sg; | ||
581 | struct dma_async_tx_descriptor *desc; | ||
582 | struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); | ||
583 | struct device *dev = usbhs_priv_to_dev(priv); | ||
584 | enum dma_data_direction dir; | ||
585 | dma_cookie_t cookie; | ||
586 | |||
587 | dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | ||
588 | |||
589 | sg_init_table(&sg, 1); | ||
590 | sg_set_page(&sg, virt_to_page(pkt->dma), | ||
591 | pkt->length, offset_in_page(pkt->dma)); | ||
592 | sg_dma_address(&sg) = pkt->dma + pkt->actual; | ||
593 | sg_dma_len(&sg) = pkt->trans; | ||
594 | |||
595 | desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir, | ||
596 | DMA_PREP_INTERRUPT | | ||
597 | DMA_CTRL_ACK); | ||
598 | if (!desc) | ||
599 | return; | ||
600 | |||
601 | desc->callback = usbhsf_dma_complete; | ||
602 | desc->callback_param = pipe; | ||
603 | |||
604 | cookie = desc->tx_submit(desc); | ||
605 | if (cookie < 0) { | ||
606 | dev_err(dev, "Failed to submit dma descriptor\n"); | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | dev_dbg(dev, " %s %d (%d/ %d)\n", | ||
611 | fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); | ||
612 | |||
613 | usbhsf_dma_start(pipe, fifo); | ||
614 | dma_async_issue_pending(chan); | ||
615 | } | ||
616 | |||
617 | static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) | ||
618 | { | ||
619 | struct usbhs_pipe *pipe = pkt->pipe; | ||
620 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | ||
621 | struct usbhs_fifo *fifo; | ||
622 | int len = pkt->length - pkt->actual; | ||
623 | int ret; | ||
624 | |||
625 | if (usbhs_pipe_is_busy(pipe)) | ||
626 | return 0; | ||
627 | |||
628 | /* use PIO if packet is less than pio_dma_border or pipe is DCP */ | ||
629 | if ((len < usbhs_get_dparam(priv, pio_dma_border)) || | ||
630 | usbhs_pipe_is_dcp(pipe)) | ||
631 | goto usbhsf_pio_prepare_push; | ||
632 | |||
633 | if (len % 4) /* 32bit alignment */ | ||
634 | goto usbhsf_pio_prepare_push; | ||
635 | |||
636 | /* get enable DMA fifo */ | ||
637 | fifo = usbhsf_get_dma_fifo(priv, pkt); | ||
638 | if (!fifo) | ||
639 | goto usbhsf_pio_prepare_push; | ||
640 | |||
641 | if (usbhsf_dma_map(pkt) < 0) | ||
642 | goto usbhsf_pio_prepare_push; | ||
643 | |||
644 | ret = usbhsf_fifo_select(pipe, fifo, 0); | ||
645 | if (ret < 0) | ||
646 | goto usbhsf_pio_prepare_push_unmap; | ||
647 | |||
648 | pkt->trans = len; | ||
649 | |||
650 | tasklet_init(&fifo->tasklet, | ||
651 | usbhsf_dma_prepare_tasklet, | ||
652 | (unsigned long)pkt); | ||
653 | |||
654 | tasklet_schedule(&fifo->tasklet); | ||
655 | |||
656 | return 0; | ||
657 | |||
658 | usbhsf_pio_prepare_push_unmap: | ||
659 | usbhsf_dma_unmap(pkt); | ||
660 | usbhsf_pio_prepare_push: | ||
661 | /* | ||
662 | * change handler to PIO | ||
663 | */ | ||
664 | pkt->handler = &usbhs_fifo_pio_push_handler; | ||
665 | |||
666 | return pkt->handler->prepare(pkt, is_done); | ||
667 | } | ||
668 | |||
669 | static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done) | ||
670 | { | ||
671 | struct usbhs_pipe *pipe = pkt->pipe; | ||
672 | |||
673 | pkt->actual = pkt->trans; | ||
674 | |||
675 | *is_done = !pkt->zero; /* send zero packet ? */ | ||
676 | |||
677 | usbhsf_dma_stop(pipe, pipe->fifo); | ||
678 | usbhsf_dma_unmap(pkt); | ||
679 | usbhsf_fifo_unselect(pipe, pipe->fifo); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = { | ||
685 | .prepare = usbhsf_dma_prepare_push, | ||
686 | .dma_done = usbhsf_dma_push_done, | ||
687 | }; | ||
688 | |||
689 | static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) | ||
690 | { | ||
691 | struct usbhs_pipe *pipe = pkt->pipe; | ||
692 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | ||
693 | struct usbhs_fifo *fifo; | ||
694 | int len, ret; | ||
695 | |||
696 | if (usbhs_pipe_is_busy(pipe)) | ||
697 | return 0; | ||
698 | |||
699 | if (usbhs_pipe_is_dcp(pipe)) | ||
700 | goto usbhsf_pio_prepare_pop; | ||
701 | |||
702 | /* get enable DMA fifo */ | ||
703 | fifo = usbhsf_get_dma_fifo(priv, pkt); | ||
704 | if (!fifo) | ||
705 | goto usbhsf_pio_prepare_pop; | ||
706 | |||
707 | ret = usbhsf_fifo_select(pipe, fifo, 0); | ||
708 | if (ret < 0) | ||
709 | goto usbhsf_pio_prepare_pop; | ||
710 | |||
711 | /* use PIO if packet is less than pio_dma_border */ | ||
712 | len = usbhsf_fifo_rcv_len(priv, fifo); | ||
713 | len = min(pkt->length - pkt->actual, len); | ||
714 | if (len % 4) /* 32bit alignment */ | ||
715 | goto usbhsf_pio_prepare_pop_unselect; | ||
716 | |||
717 | if (len < usbhs_get_dparam(priv, pio_dma_border)) | ||
718 | goto usbhsf_pio_prepare_pop_unselect; | ||
719 | |||
720 | ret = usbhsf_fifo_barrier(priv, fifo); | ||
721 | if (ret < 0) | ||
722 | goto usbhsf_pio_prepare_pop_unselect; | ||
723 | |||
724 | if (usbhsf_dma_map(pkt) < 0) | ||
725 | goto usbhsf_pio_prepare_pop_unselect; | ||
726 | |||
727 | /* DMA */ | ||
728 | |||
729 | /* | ||
730 | * usbhs_fifo_dma_pop_handler :: prepare | ||
731 | * enabled irq to come here. | ||
732 | * but it is no longer needed for DMA. disable it. | ||
733 | */ | ||
734 | usbhsf_rx_irq_ctrl(pipe, 0); | ||
735 | |||
736 | pkt->trans = len; | ||
737 | |||
738 | tasklet_init(&fifo->tasklet, | ||
739 | usbhsf_dma_prepare_tasklet, | ||
740 | (unsigned long)pkt); | ||
741 | |||
742 | tasklet_schedule(&fifo->tasklet); | ||
743 | |||
744 | return 0; | ||
745 | |||
746 | usbhsf_pio_prepare_pop_unselect: | ||
747 | usbhsf_fifo_unselect(pipe, fifo); | ||
748 | usbhsf_pio_prepare_pop: | ||
749 | |||
750 | /* | ||
751 | * change handler to PIO | ||
752 | */ | ||
753 | pkt->handler = &usbhs_fifo_pio_pop_handler; | ||
754 | |||
755 | return pkt->handler->try_run(pkt, is_done); | ||
756 | } | ||
757 | |||
758 | static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done) | ||
759 | { | ||
760 | struct usbhs_pipe *pipe = pkt->pipe; | ||
761 | int maxp = usbhs_pipe_get_maxpacket(pipe); | ||
762 | |||
763 | usbhsf_dma_stop(pipe, pipe->fifo); | ||
764 | usbhsf_dma_unmap(pkt); | ||
765 | usbhsf_fifo_unselect(pipe, pipe->fifo); | ||
766 | |||
767 | pkt->actual += pkt->trans; | ||
768 | |||
769 | if ((pkt->actual == pkt->length) || /* receive all data */ | ||
770 | (pkt->trans < maxp)) { /* short packet */ | ||
771 | *is_done = 1; | ||
772 | } else { | ||
773 | /* re-enable */ | ||
774 | usbhsf_prepare_pop(pkt, is_done); | ||
775 | } | ||
776 | |||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = { | ||
781 | .prepare = usbhsf_prepare_pop, | ||
782 | .try_run = usbhsf_dma_try_pop, | ||
783 | .dma_done = usbhsf_dma_pop_done | ||
784 | }; | ||
785 | |||
786 | /* | ||
787 | * DMA setting | ||
788 | */ | ||
789 | static bool usbhsf_dma_filter(struct dma_chan *chan, void *param) | ||
790 | { | ||
791 | struct sh_dmae_slave *slave = param; | ||
792 | |||
793 | /* | ||
794 | * FIXME | ||
795 | * | ||
796 | * usbhs doesn't recognize id = 0 as valid DMA | ||
797 | */ | ||
798 | if (0 == slave->slave_id) | ||
799 | return false; | ||
800 | |||
801 | chan->private = slave; | ||
802 | |||
803 | return true; | ||
804 | } | ||
805 | |||
806 | static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo) | ||
807 | { | ||
808 | if (fifo->tx_chan) | ||
809 | dma_release_channel(fifo->tx_chan); | ||
810 | if (fifo->rx_chan) | ||
811 | dma_release_channel(fifo->rx_chan); | ||
812 | |||
813 | fifo->tx_chan = NULL; | ||
814 | fifo->rx_chan = NULL; | ||
815 | } | ||
816 | |||
817 | static void usbhsf_dma_init(struct usbhs_priv *priv, | ||
818 | struct usbhs_fifo *fifo) | ||
819 | { | ||
820 | struct device *dev = usbhs_priv_to_dev(priv); | ||
821 | dma_cap_mask_t mask; | ||
822 | |||
823 | dma_cap_zero(mask); | ||
824 | dma_cap_set(DMA_SLAVE, mask); | ||
825 | fifo->tx_chan = dma_request_channel(mask, usbhsf_dma_filter, | ||
826 | &fifo->tx_slave); | ||
827 | |||
828 | dma_cap_zero(mask); | ||
829 | dma_cap_set(DMA_SLAVE, mask); | ||
830 | fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter, | ||
831 | &fifo->rx_slave); | ||
832 | |||
833 | if (fifo->tx_chan || fifo->rx_chan) | ||
834 | dev_info(dev, "enable DMAEngine (%s%s%s)\n", | ||
835 | fifo->name, | ||
836 | fifo->tx_chan ? "[TX]" : " ", | ||
837 | fifo->rx_chan ? "[RX]" : " "); | ||
838 | } | ||
839 | |||
840 | /* | ||
511 | * irq functions | 841 | * irq functions |
512 | */ | 842 | */ |
513 | static int usbhsf_irq_empty(struct usbhs_priv *priv, | 843 | static int usbhsf_irq_empty(struct usbhs_priv *priv, |
@@ -570,6 +900,19 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv, | |||
570 | return 0; | 900 | return 0; |
571 | } | 901 | } |
572 | 902 | ||
903 | static void usbhsf_dma_complete(void *arg) | ||
904 | { | ||
905 | struct usbhs_pipe *pipe = arg; | ||
906 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | ||
907 | struct device *dev = usbhs_priv_to_dev(priv); | ||
908 | int ret; | ||
909 | |||
910 | ret = usbhs_pkt_dmadone(pipe); | ||
911 | if (ret < 0) | ||
912 | dev_err(dev, "dma_complete run_error %d : %d\n", | ||
913 | usbhs_pipe_number(pipe), ret); | ||
914 | } | ||
915 | |||
573 | /* | 916 | /* |
574 | * fifo init | 917 | * fifo init |
575 | */ | 918 | */ |
@@ -577,6 +920,8 @@ void usbhs_fifo_init(struct usbhs_priv *priv) | |||
577 | { | 920 | { |
578 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | 921 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); |
579 | struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); | 922 | struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); |
923 | struct usbhs_fifo *d0fifo = usbhsf_get_d0fifo(priv); | ||
924 | struct usbhs_fifo *d1fifo = usbhsf_get_d1fifo(priv); | ||
580 | 925 | ||
581 | mod->irq_empty = usbhsf_irq_empty; | 926 | mod->irq_empty = usbhsf_irq_empty; |
582 | mod->irq_ready = usbhsf_irq_ready; | 927 | mod->irq_ready = usbhsf_irq_ready; |
@@ -584,6 +929,19 @@ void usbhs_fifo_init(struct usbhs_priv *priv) | |||
584 | mod->irq_brdysts = 0; | 929 | mod->irq_brdysts = 0; |
585 | 930 | ||
586 | cfifo->pipe = NULL; | 931 | cfifo->pipe = NULL; |
932 | cfifo->tx_chan = NULL; | ||
933 | cfifo->rx_chan = NULL; | ||
934 | |||
935 | d0fifo->pipe = NULL; | ||
936 | d0fifo->tx_chan = NULL; | ||
937 | d0fifo->rx_chan = NULL; | ||
938 | |||
939 | d1fifo->pipe = NULL; | ||
940 | d1fifo->tx_chan = NULL; | ||
941 | d1fifo->rx_chan = NULL; | ||
942 | |||
943 | usbhsf_dma_init(priv, usbhsf_get_d0fifo(priv)); | ||
944 | usbhsf_dma_init(priv, usbhsf_get_d1fifo(priv)); | ||
587 | } | 945 | } |
588 | 946 | ||
589 | void usbhs_fifo_quit(struct usbhs_priv *priv) | 947 | void usbhs_fifo_quit(struct usbhs_priv *priv) |
@@ -594,6 +952,9 @@ void usbhs_fifo_quit(struct usbhs_priv *priv) | |||
594 | mod->irq_ready = NULL; | 952 | mod->irq_ready = NULL; |
595 | mod->irq_bempsts = 0; | 953 | mod->irq_bempsts = 0; |
596 | mod->irq_brdysts = 0; | 954 | mod->irq_brdysts = 0; |
955 | |||
956 | usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv)); | ||
957 | usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv)); | ||
597 | } | 958 | } |
598 | 959 | ||
599 | int usbhs_fifo_probe(struct usbhs_priv *priv) | 960 | int usbhs_fifo_probe(struct usbhs_priv *priv) |
@@ -602,10 +963,29 @@ int usbhs_fifo_probe(struct usbhs_priv *priv) | |||
602 | 963 | ||
603 | /* CFIFO */ | 964 | /* CFIFO */ |
604 | fifo = usbhsf_get_cfifo(priv); | 965 | fifo = usbhsf_get_cfifo(priv); |
966 | fifo->name = "CFIFO"; | ||
605 | fifo->port = CFIFO; | 967 | fifo->port = CFIFO; |
606 | fifo->sel = CFIFOSEL; | 968 | fifo->sel = CFIFOSEL; |
607 | fifo->ctr = CFIFOCTR; | 969 | fifo->ctr = CFIFOCTR; |
608 | 970 | ||
971 | /* D0FIFO */ | ||
972 | fifo = usbhsf_get_d0fifo(priv); | ||
973 | fifo->name = "D0FIFO"; | ||
974 | fifo->port = D0FIFO; | ||
975 | fifo->sel = D0FIFOSEL; | ||
976 | fifo->ctr = D0FIFOCTR; | ||
977 | fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id); | ||
978 | fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id); | ||
979 | |||
980 | /* D1FIFO */ | ||
981 | fifo = usbhsf_get_d1fifo(priv); | ||
982 | fifo->name = "D1FIFO"; | ||
983 | fifo->port = D1FIFO; | ||
984 | fifo->sel = D1FIFOSEL; | ||
985 | fifo->ctr = D1FIFOCTR; | ||
986 | fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id); | ||
987 | fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id); | ||
988 | |||
609 | return 0; | 989 | return 0; |
610 | } | 990 | } |
611 | 991 | ||
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index 94db269f84c2..ed6d8e56c13c 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h | |||
@@ -17,18 +17,33 @@ | |||
17 | #ifndef RENESAS_USB_FIFO_H | 17 | #ifndef RENESAS_USB_FIFO_H |
18 | #define RENESAS_USB_FIFO_H | 18 | #define RENESAS_USB_FIFO_H |
19 | 19 | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/sh_dma.h> | ||
22 | #include <asm/dma.h> | ||
20 | #include "pipe.h" | 23 | #include "pipe.h" |
21 | 24 | ||
25 | #define DMA_ADDR_INVALID (~(dma_addr_t)0) | ||
26 | |||
22 | struct usbhs_fifo { | 27 | struct usbhs_fifo { |
28 | char *name; | ||
23 | u32 port; /* xFIFO */ | 29 | u32 port; /* xFIFO */ |
24 | u32 sel; /* xFIFOSEL */ | 30 | u32 sel; /* xFIFOSEL */ |
25 | u32 ctr; /* xFIFOCTR */ | 31 | u32 ctr; /* xFIFOCTR */ |
26 | 32 | ||
27 | struct usbhs_pipe *pipe; | 33 | struct usbhs_pipe *pipe; |
34 | struct tasklet_struct tasklet; | ||
35 | |||
36 | struct dma_chan *tx_chan; | ||
37 | struct dma_chan *rx_chan; | ||
38 | |||
39 | struct sh_dmae_slave tx_slave; | ||
40 | struct sh_dmae_slave rx_slave; | ||
28 | }; | 41 | }; |
29 | 42 | ||
30 | struct usbhs_fifo_info { | 43 | struct usbhs_fifo_info { |
31 | struct usbhs_fifo cfifo; | 44 | struct usbhs_fifo cfifo; |
45 | struct usbhs_fifo d0fifo; | ||
46 | struct usbhs_fifo d1fifo; | ||
32 | }; | 47 | }; |
33 | 48 | ||
34 | struct usbhs_pkt_handle; | 49 | struct usbhs_pkt_handle; |
@@ -36,8 +51,10 @@ struct usbhs_pkt { | |||
36 | struct list_head node; | 51 | struct list_head node; |
37 | struct usbhs_pipe *pipe; | 52 | struct usbhs_pipe *pipe; |
38 | struct usbhs_pkt_handle *handler; | 53 | struct usbhs_pkt_handle *handler; |
54 | dma_addr_t dma; | ||
39 | void *buf; | 55 | void *buf; |
40 | int length; | 56 | int length; |
57 | int trans; | ||
41 | int actual; | 58 | int actual; |
42 | int zero; | 59 | int zero; |
43 | }; | 60 | }; |
@@ -45,6 +62,7 @@ struct usbhs_pkt { | |||
45 | struct usbhs_pkt_handle { | 62 | struct usbhs_pkt_handle { |
46 | int (*prepare)(struct usbhs_pkt *pkt, int *is_done); | 63 | int (*prepare)(struct usbhs_pkt *pkt, int *is_done); |
47 | int (*try_run)(struct usbhs_pkt *pkt, int *is_done); | 64 | int (*try_run)(struct usbhs_pkt *pkt, int *is_done); |
65 | int (*dma_done)(struct usbhs_pkt *pkt, int *is_done); | ||
48 | }; | 66 | }; |
49 | 67 | ||
50 | /* | 68 | /* |
@@ -61,12 +79,17 @@ void usbhs_fifo_quit(struct usbhs_priv *priv); | |||
61 | enum { | 79 | enum { |
62 | USBHSF_PKT_PREPARE, | 80 | USBHSF_PKT_PREPARE, |
63 | USBHSF_PKT_TRY_RUN, | 81 | USBHSF_PKT_TRY_RUN, |
82 | USBHSF_PKT_DMA_DONE, | ||
64 | }; | 83 | }; |
65 | 84 | ||
66 | extern struct usbhs_pkt_handle usbhs_fifo_pio_push_handler; | 85 | extern struct usbhs_pkt_handle usbhs_fifo_pio_push_handler; |
67 | extern struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler; | 86 | extern struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler; |
68 | extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler; | 87 | extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler; |
69 | 88 | ||
89 | extern struct usbhs_pkt_handle usbhs_fifo_dma_push_handler; | ||
90 | extern struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler; | ||
91 | |||
92 | |||
70 | void usbhs_pkt_init(struct usbhs_pkt *pkt); | 93 | void usbhs_pkt_init(struct usbhs_pkt *pkt); |
71 | void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, | 94 | void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, |
72 | struct usbhs_pkt_handle *handler, | 95 | struct usbhs_pkt_handle *handler, |
@@ -76,5 +99,6 @@ int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type); | |||
76 | 99 | ||
77 | #define usbhs_pkt_start(p) __usbhs_pkt_handler(p, USBHSF_PKT_PREPARE) | 100 | #define usbhs_pkt_start(p) __usbhs_pkt_handler(p, USBHSF_PKT_PREPARE) |
78 | #define usbhs_pkt_run(p) __usbhs_pkt_handler(p, USBHSF_PKT_TRY_RUN) | 101 | #define usbhs_pkt_run(p) __usbhs_pkt_handler(p, USBHSF_PKT_TRY_RUN) |
102 | #define usbhs_pkt_dmadone(p) __usbhs_pkt_handler(p, USBHSF_PKT_DMA_DONE) | ||
79 | 103 | ||
80 | #endif /* RENESAS_USB_FIFO_H */ | 104 | #endif /* RENESAS_USB_FIFO_H */ |
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 89d2b16fbb10..31d28dc78aa3 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c | |||
@@ -160,6 +160,71 @@ static void usbhsg_queue_done(struct usbhs_pkt *pkt) | |||
160 | usbhsg_queue_pop(uep, ureq, 0); | 160 | usbhsg_queue_pop(uep, ureq, 0); |
161 | } | 161 | } |
162 | 162 | ||
163 | static int usbhsg_dma_map(struct device *dev, | ||
164 | struct usbhs_pkt *pkt, | ||
165 | enum dma_data_direction dir) | ||
166 | { | ||
167 | struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); | ||
168 | struct usb_request *req = &ureq->req; | ||
169 | |||
170 | if (pkt->dma != DMA_ADDR_INVALID) { | ||
171 | dev_err(dev, "dma is already mapped\n"); | ||
172 | return -EIO; | ||
173 | } | ||
174 | |||
175 | if (req->dma == DMA_ADDR_INVALID) { | ||
176 | pkt->dma = dma_map_single(dev, pkt->buf, pkt->length, dir); | ||
177 | } else { | ||
178 | dma_sync_single_for_device(dev, req->dma, req->length, dir); | ||
179 | pkt->dma = req->dma; | ||
180 | } | ||
181 | |||
182 | if (dma_mapping_error(dev, pkt->dma)) { | ||
183 | dev_err(dev, "dma mapping error %x\n", pkt->dma); | ||
184 | return -EIO; | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int usbhsg_dma_unmap(struct device *dev, | ||
191 | struct usbhs_pkt *pkt, | ||
192 | enum dma_data_direction dir) | ||
193 | { | ||
194 | struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); | ||
195 | struct usb_request *req = &ureq->req; | ||
196 | |||
197 | if (pkt->dma == DMA_ADDR_INVALID) { | ||
198 | dev_err(dev, "dma is not mapped\n"); | ||
199 | return -EIO; | ||
200 | } | ||
201 | |||
202 | if (req->dma == DMA_ADDR_INVALID) | ||
203 | dma_unmap_single(dev, pkt->dma, pkt->length, dir); | ||
204 | else | ||
205 | dma_sync_single_for_cpu(dev, req->dma, req->length, dir); | ||
206 | |||
207 | pkt->dma = DMA_ADDR_INVALID; | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) | ||
213 | { | ||
214 | struct usbhs_pipe *pipe = pkt->pipe; | ||
215 | struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); | ||
216 | struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); | ||
217 | struct device *dev = usbhsg_gpriv_to_dev(gpriv); | ||
218 | enum dma_data_direction dir; | ||
219 | |||
220 | dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | ||
221 | |||
222 | if (map) | ||
223 | return usbhsg_dma_map(dev, pkt, dir); | ||
224 | else | ||
225 | return usbhsg_dma_unmap(dev, pkt, dir); | ||
226 | } | ||
227 | |||
163 | /* | 228 | /* |
164 | * USB_TYPE_STANDARD / clear feature functions | 229 | * USB_TYPE_STANDARD / clear feature functions |
165 | */ | 230 | */ |
@@ -434,6 +499,8 @@ static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, | |||
434 | 499 | ||
435 | usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq)); | 500 | usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq)); |
436 | 501 | ||
502 | ureq->req.dma = DMA_ADDR_INVALID; | ||
503 | |||
437 | return &ureq->req; | 504 | return &ureq->req; |
438 | } | 505 | } |
439 | 506 | ||
@@ -569,7 +636,8 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) | |||
569 | * pipe initialize and enable DCP | 636 | * pipe initialize and enable DCP |
570 | */ | 637 | */ |
571 | usbhs_pipe_init(priv, | 638 | usbhs_pipe_init(priv, |
572 | usbhsg_queue_done); | 639 | usbhsg_queue_done, |
640 | usbhsg_dma_map_ctrl); | ||
573 | usbhs_fifo_init(priv); | 641 | usbhs_fifo_init(priv); |
574 | usbhsg_uep_init(gpriv); | 642 | usbhsg_uep_init(gpriv); |
575 | 643 | ||
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index c0505876fd8c..d0ae846632cd 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c | |||
@@ -532,7 +532,8 @@ static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) | |||
532 | } | 532 | } |
533 | 533 | ||
534 | void usbhs_pipe_init(struct usbhs_priv *priv, | 534 | void usbhs_pipe_init(struct usbhs_priv *priv, |
535 | void (*done)(struct usbhs_pkt *pkt)) | 535 | void (*done)(struct usbhs_pkt *pkt), |
536 | int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) | ||
536 | { | 537 | { |
537 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); | 538 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
538 | struct device *dev = usbhs_priv_to_dev(priv); | 539 | struct device *dev = usbhs_priv_to_dev(priv); |
@@ -572,6 +573,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv, | |||
572 | } | 573 | } |
573 | 574 | ||
574 | info->done = done; | 575 | info->done = done; |
576 | info->dma_map_ctrl = dma_map_ctrl; | ||
575 | } | 577 | } |
576 | 578 | ||
577 | struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, | 579 | struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, |
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 484adbed6dfb..35e100477e55 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h | |||
@@ -44,6 +44,7 @@ struct usbhs_pipe_info { | |||
44 | int bufnmb_last; /* FIXME : driver needs good allocator */ | 44 | int bufnmb_last; /* FIXME : driver needs good allocator */ |
45 | 45 | ||
46 | void (*done)(struct usbhs_pkt *pkt); | 46 | void (*done)(struct usbhs_pkt *pkt); |
47 | int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map); | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -82,7 +83,8 @@ void usbhs_pipe_remove(struct usbhs_priv *priv); | |||
82 | int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe); | 83 | int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe); |
83 | int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe); | 84 | int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe); |
84 | void usbhs_pipe_init(struct usbhs_priv *priv, | 85 | void usbhs_pipe_init(struct usbhs_priv *priv, |
85 | void (*done)(struct usbhs_pkt *pkt)); | 86 | void (*done)(struct usbhs_pkt *pkt), |
87 | int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)); | ||
86 | int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); | 88 | int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); |
87 | void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe); | 89 | void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe); |
88 | int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); | 90 | int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); |
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index 3a7f1d982dd6..8977431259c6 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h | |||
@@ -110,6 +110,23 @@ struct renesas_usbhs_driver_param { | |||
110 | * delay time from notify_hotplug callback | 110 | * delay time from notify_hotplug callback |
111 | */ | 111 | */ |
112 | int detection_delay; | 112 | int detection_delay; |
113 | |||
114 | /* | ||
115 | * option: | ||
116 | * | ||
117 | * dma id for dmaengine | ||
118 | */ | ||
119 | int d0_tx_id; | ||
120 | int d0_rx_id; | ||
121 | int d1_tx_id; | ||
122 | int d1_rx_id; | ||
123 | |||
124 | /* | ||
125 | * option: | ||
126 | * | ||
127 | * pio <--> dma border. | ||
128 | */ | ||
129 | int pio_dma_border; /* default is 64byte */ | ||
113 | }; | 130 | }; |
114 | 131 | ||
115 | /* | 132 | /* |