diff options
author | Kyungmin Park <kyungmin.park@samsung.com> | 2007-11-21 18:13:15 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-01 17:34:48 -0500 |
commit | 527ea73eaea4600120117edd19ac88864a488d57 (patch) | |
tree | 4317766b607ea1353e3aaa47c744c61378c92224 /drivers/usb/gadget/omap_udc.c | |
parent | 568fdade1415196a4835a9add48586e36a044d82 (diff) |
USB: device DMA support on OMAP2
The current omap udc dosen't support the DMA mode and it has some problem
at setup time on OMAP2 with previous patch file. I found that the code
assumes bulk out required the big data transfer. But MODE SELECT(6) sent
the only 24 bytes. it makes a problem. So I implement the small packets
handling for it.
It is tested with both linux and windows.
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Tony Lindgren <tony@atomide.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget/omap_udc.c')
-rw-r--r-- | drivers/usb/gadget/omap_udc.c | 71 |
1 files changed, 49 insertions, 22 deletions
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index d377154658b5..7d6bef56cb01 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright (C) 2004 Texas Instruments, Inc. | 4 | * Copyright (C) 2004 Texas Instruments, Inc. |
5 | * Copyright (C) 2004-2005 David Brownell | 5 | * Copyright (C) 2004-2005 David Brownell |
6 | * | 6 | * |
7 | * OMAP2 & DMA support by Kyungmin Park <kyungmin.park@samsung.com> | ||
8 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or | 11 | * the Free Software Foundation; either version 2 of the License, or |
@@ -60,11 +62,6 @@ | |||
60 | /* bulk DMA seems to be behaving for both IN and OUT */ | 62 | /* bulk DMA seems to be behaving for both IN and OUT */ |
61 | #define USE_DMA | 63 | #define USE_DMA |
62 | 64 | ||
63 | /* FIXME: OMAP2 currently has some problem in DMA mode */ | ||
64 | #ifdef CONFIG_ARCH_OMAP2 | ||
65 | #undef USE_DMA | ||
66 | #endif | ||
67 | |||
68 | /* ISO too */ | 65 | /* ISO too */ |
69 | #define USE_ISO | 66 | #define USE_ISO |
70 | 67 | ||
@@ -73,6 +70,8 @@ | |||
73 | 70 | ||
74 | #define DMA_ADDR_INVALID (~(dma_addr_t)0) | 71 | #define DMA_ADDR_INVALID (~(dma_addr_t)0) |
75 | 72 | ||
73 | #define OMAP2_DMA_CH(ch) (((ch) - 1) << 1) | ||
74 | #define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch)) | ||
76 | 75 | ||
77 | /* | 76 | /* |
78 | * The OMAP UDC needs _very_ early endpoint setup: before enabling the | 77 | * The OMAP UDC needs _very_ early endpoint setup: before enabling the |
@@ -571,20 +570,25 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) | |||
571 | const int sync_mode = cpu_is_omap15xx() | 570 | const int sync_mode = cpu_is_omap15xx() |
572 | ? OMAP_DMA_SYNC_FRAME | 571 | ? OMAP_DMA_SYNC_FRAME |
573 | : OMAP_DMA_SYNC_ELEMENT; | 572 | : OMAP_DMA_SYNC_ELEMENT; |
573 | int dma_trigger = 0; | ||
574 | |||
575 | if (cpu_is_omap24xx()) | ||
576 | dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel); | ||
574 | 577 | ||
575 | /* measure length in either bytes or packets */ | 578 | /* measure length in either bytes or packets */ |
576 | if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) | 579 | if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) |
580 | || (cpu_is_omap24xx() && length < ep->maxpacket) | ||
577 | || (cpu_is_omap15xx() && length < ep->maxpacket)) { | 581 | || (cpu_is_omap15xx() && length < ep->maxpacket)) { |
578 | txdma_ctrl = UDC_TXN_EOT | length; | 582 | txdma_ctrl = UDC_TXN_EOT | length; |
579 | omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, | 583 | omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, |
580 | length, 1, sync_mode, 0, 0); | 584 | length, 1, sync_mode, dma_trigger, 0); |
581 | } else { | 585 | } else { |
582 | length = min(length / ep->maxpacket, | 586 | length = min(length / ep->maxpacket, |
583 | (unsigned) UDC_TXN_TSC + 1); | 587 | (unsigned) UDC_TXN_TSC + 1); |
584 | txdma_ctrl = length; | 588 | txdma_ctrl = length; |
585 | omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, | 589 | omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, |
586 | ep->ep.maxpacket >> 1, length, sync_mode, | 590 | ep->ep.maxpacket >> 1, length, sync_mode, |
587 | 0, 0); | 591 | dma_trigger, 0); |
588 | length *= ep->maxpacket; | 592 | length *= ep->maxpacket; |
589 | } | 593 | } |
590 | omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, | 594 | omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, |
@@ -622,20 +626,31 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) | |||
622 | 626 | ||
623 | static void next_out_dma(struct omap_ep *ep, struct omap_req *req) | 627 | static void next_out_dma(struct omap_ep *ep, struct omap_req *req) |
624 | { | 628 | { |
625 | unsigned packets; | 629 | unsigned packets = req->req.length - req->req.actual; |
630 | int dma_trigger = 0; | ||
631 | |||
632 | if (cpu_is_omap24xx()) | ||
633 | dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel); | ||
626 | 634 | ||
627 | /* NOTE: we filtered out "short reads" before, so we know | 635 | /* NOTE: we filtered out "short reads" before, so we know |
628 | * the buffer has only whole numbers of packets. | 636 | * the buffer has only whole numbers of packets. |
637 | * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode | ||
629 | */ | 638 | */ |
630 | 639 | if (cpu_is_omap24xx() && packets < ep->maxpacket) { | |
631 | /* set up this DMA transfer, enable the fifo, start */ | 640 | omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, |
632 | packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; | 641 | packets, 1, OMAP_DMA_SYNC_ELEMENT, |
633 | packets = min(packets, (unsigned)UDC_RXN_TC + 1); | 642 | dma_trigger, 0); |
634 | req->dma_bytes = packets * ep->ep.maxpacket; | 643 | req->dma_bytes = packets; |
635 | omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, | 644 | } else { |
636 | ep->ep.maxpacket >> 1, packets, | 645 | /* set up this DMA transfer, enable the fifo, start */ |
637 | OMAP_DMA_SYNC_ELEMENT, | 646 | packets /= ep->ep.maxpacket; |
638 | 0, 0); | 647 | packets = min(packets, (unsigned)UDC_RXN_TC + 1); |
648 | req->dma_bytes = packets * ep->ep.maxpacket; | ||
649 | omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, | ||
650 | ep->ep.maxpacket >> 1, packets, | ||
651 | OMAP_DMA_SYNC_ELEMENT, | ||
652 | dma_trigger, 0); | ||
653 | } | ||
639 | omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, | 654 | omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, |
640 | OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, | 655 | OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, |
641 | 0, 0); | 656 | 0, 0); |
@@ -743,6 +758,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) | |||
743 | { | 758 | { |
744 | u16 reg; | 759 | u16 reg; |
745 | int status, restart, is_in; | 760 | int status, restart, is_in; |
761 | int dma_channel; | ||
746 | 762 | ||
747 | is_in = ep->bEndpointAddress & USB_DIR_IN; | 763 | is_in = ep->bEndpointAddress & USB_DIR_IN; |
748 | if (is_in) | 764 | if (is_in) |
@@ -769,11 +785,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) | |||
769 | ep->dma_channel = channel; | 785 | ep->dma_channel = channel; |
770 | 786 | ||
771 | if (is_in) { | 787 | if (is_in) { |
772 | status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel, | 788 | if (cpu_is_omap24xx()) |
789 | dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel); | ||
790 | else | ||
791 | dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel; | ||
792 | status = omap_request_dma(dma_channel, | ||
773 | ep->ep.name, dma_error, ep, &ep->lch); | 793 | ep->ep.name, dma_error, ep, &ep->lch); |
774 | if (status == 0) { | 794 | if (status == 0) { |
775 | UDC_TXDMA_CFG_REG = reg; | 795 | UDC_TXDMA_CFG_REG = reg; |
776 | /* EMIFF */ | 796 | /* EMIFF or SDRC */ |
777 | omap_set_dma_src_burst_mode(ep->lch, | 797 | omap_set_dma_src_burst_mode(ep->lch, |
778 | OMAP_DMA_DATA_BURST_4); | 798 | OMAP_DMA_DATA_BURST_4); |
779 | omap_set_dma_src_data_pack(ep->lch, 1); | 799 | omap_set_dma_src_data_pack(ep->lch, 1); |
@@ -785,7 +805,12 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) | |||
785 | 0, 0); | 805 | 0, 0); |
786 | } | 806 | } |
787 | } else { | 807 | } else { |
788 | status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel, | 808 | if (cpu_is_omap24xx()) |
809 | dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel); | ||
810 | else | ||
811 | dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel; | ||
812 | |||
813 | status = omap_request_dma(dma_channel, | ||
789 | ep->ep.name, dma_error, ep, &ep->lch); | 814 | ep->ep.name, dma_error, ep, &ep->lch); |
790 | if (status == 0) { | 815 | if (status == 0) { |
791 | UDC_RXDMA_CFG_REG = reg; | 816 | UDC_RXDMA_CFG_REG = reg; |
@@ -795,7 +820,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) | |||
795 | OMAP_DMA_AMODE_CONSTANT, | 820 | OMAP_DMA_AMODE_CONSTANT, |
796 | (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), | 821 | (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), |
797 | 0, 0); | 822 | 0, 0); |
798 | /* EMIFF */ | 823 | /* EMIFF or SDRC */ |
799 | omap_set_dma_dest_burst_mode(ep->lch, | 824 | omap_set_dma_dest_burst_mode(ep->lch, |
800 | OMAP_DMA_DATA_BURST_4); | 825 | OMAP_DMA_DATA_BURST_4); |
801 | omap_set_dma_dest_data_pack(ep->lch, 1); | 826 | omap_set_dma_dest_data_pack(ep->lch, 1); |
@@ -808,7 +833,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) | |||
808 | omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); | 833 | omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); |
809 | 834 | ||
810 | /* channel type P: hw synch (fifo) */ | 835 | /* channel type P: hw synch (fifo) */ |
811 | if (!cpu_is_omap15xx()) | 836 | if (cpu_class_is_omap1() && !cpu_is_omap15xx()) |
812 | OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2; | 837 | OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2; |
813 | } | 838 | } |
814 | 839 | ||
@@ -926,11 +951,13 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) | |||
926 | 951 | ||
927 | /* this isn't bogus, but OMAP DMA isn't the only hardware to | 952 | /* this isn't bogus, but OMAP DMA isn't the only hardware to |
928 | * have a hard time with partial packet reads... reject it. | 953 | * have a hard time with partial packet reads... reject it. |
954 | * Except OMAP2 can handle the small packets. | ||
929 | */ | 955 | */ |
930 | if (use_dma | 956 | if (use_dma |
931 | && ep->has_dma | 957 | && ep->has_dma |
932 | && ep->bEndpointAddress != 0 | 958 | && ep->bEndpointAddress != 0 |
933 | && (ep->bEndpointAddress & USB_DIR_IN) == 0 | 959 | && (ep->bEndpointAddress & USB_DIR_IN) == 0 |
960 | && !cpu_class_is_omap2() | ||
934 | && (req->req.length % ep->ep.maxpacket) != 0) { | 961 | && (req->req.length % ep->ep.maxpacket) != 0) { |
935 | DBG("%s, no partial packet OUT reads\n", __FUNCTION__); | 962 | DBG("%s, no partial packet OUT reads\n", __FUNCTION__); |
936 | return -EMSGSIZE; | 963 | return -EMSGSIZE; |