]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/gadget/omap_udc.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / drivers / usb / gadget / omap_udc.c
index 91a27ab0ad1c30cc05cf31148709ba87859b75d3..85a0d1a1b4a349afd86c08797f207e40d374415d 100644 (file)
@@ -4,6 +4,8 @@
  * Copyright (C) 2004 Texas Instruments, Inc.
  * Copyright (C) 2004-2005 David Brownell
  *
+ * OMAP2 & DMA support by Kyungmin Park <kyungmin.park@samsung.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 /* bulk DMA seems to be behaving for both IN and OUT */
 #define        USE_DMA
 
-/* FIXME: OMAP2 currently has some problem in DMA mode */
-#ifdef CONFIG_ARCH_OMAP2
-#undef USE_DMA
-#endif
-
 /* ISO too */
 #define        USE_ISO
 
@@ -74,6 +71,8 @@
 
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 
+#define OMAP2_DMA_CH(ch)       (((ch) - 1) << 1)
+#define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch))
 
 /*
  * The OMAP UDC needs _very_ early endpoint setup:  before enabling the
@@ -572,20 +571,25 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
        const int       sync_mode = cpu_is_omap15xx()
                                ? OMAP_DMA_SYNC_FRAME
                                : OMAP_DMA_SYNC_ELEMENT;
+       int             dma_trigger = 0;
+
+       if (cpu_is_omap24xx())
+               dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel);
 
        /* measure length in either bytes or packets */
        if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
+                       || (cpu_is_omap24xx() && length < ep->maxpacket)
                        || (cpu_is_omap15xx() && length < ep->maxpacket)) {
                txdma_ctrl = UDC_TXN_EOT | length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                               length, 1, sync_mode, 0, 0);
+                               length, 1, sync_mode, dma_trigger, 0);
        } else {
                length = min(length / ep->maxpacket,
                                (unsigned) UDC_TXN_TSC + 1);
                txdma_ctrl = length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
                                ep->ep.maxpacket >> 1, length, sync_mode,
-                               0, 0);
+                               dma_trigger, 0);
                length *= ep->maxpacket;
        }
        omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
@@ -623,20 +627,31 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
 
 static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
 {
-       unsigned packets;
+       unsigned packets = req->req.length - req->req.actual;
+       int dma_trigger = 0;
+
+       if (cpu_is_omap24xx())
+               dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel);
 
        /* NOTE:  we filtered out "short reads" before, so we know
         * the buffer has only whole numbers of packets.
+        * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode
         */
-
-       /* set up this DMA transfer, enable the fifo, start */
-       packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
-       packets = min(packets, (unsigned)UDC_RXN_TC + 1);
-       req->dma_bytes = packets * ep->ep.maxpacket;
-       omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
-                       ep->ep.maxpacket >> 1, packets,
-                       OMAP_DMA_SYNC_ELEMENT,
-                       0, 0);
+       if (cpu_is_omap24xx() && packets < ep->maxpacket) {
+               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
+                               packets, 1, OMAP_DMA_SYNC_ELEMENT,
+                               dma_trigger, 0);
+               req->dma_bytes = packets;
+       } else {
+               /* set up this DMA transfer, enable the fifo, start */
+               packets /= ep->ep.maxpacket;
+               packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+               req->dma_bytes = packets * ep->ep.maxpacket;
+               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+                               ep->ep.maxpacket >> 1, packets,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               dma_trigger, 0);
+       }
        omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
                OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
                0, 0);
@@ -744,6 +759,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
 {
        u16     reg;
        int     status, restart, is_in;
+       int     dma_channel;
 
        is_in = ep->bEndpointAddress & USB_DIR_IN;
        if (is_in)
@@ -770,11 +786,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
        ep->dma_channel = channel;
 
        if (is_in) {
-               status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel,
+               if (cpu_is_omap24xx())
+                       dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel);
+               else
+                       dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
+               status = omap_request_dma(dma_channel,
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_TXDMA_CFG_REG = reg;
-                       /* EMIFF */
+                       /* EMIFF or SDRC */
                        omap_set_dma_src_burst_mode(ep->lch,
                                                OMAP_DMA_DATA_BURST_4);
                        omap_set_dma_src_data_pack(ep->lch, 1);
@@ -786,7 +806,12 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                                0, 0);
                }
        } else {
-               status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
+               if (cpu_is_omap24xx())
+                       dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel);
+               else
+                       dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
+
+               status = omap_request_dma(dma_channel,
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_RXDMA_CFG_REG = reg;
@@ -796,7 +821,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                                OMAP_DMA_AMODE_CONSTANT,
                                (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
                                0, 0);
-                       /* EMIFF */
+                       /* EMIFF or SDRC */
                        omap_set_dma_dest_burst_mode(ep->lch,
                                                OMAP_DMA_DATA_BURST_4);
                        omap_set_dma_dest_data_pack(ep->lch, 1);
@@ -809,7 +834,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
 
                /* channel type P: hw synch (fifo) */
-               if (!cpu_is_omap15xx())
+               if (cpu_class_is_omap1() && !cpu_is_omap15xx())
                        OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
        }
 
@@ -927,11 +952,13 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        /* this isn't bogus, but OMAP DMA isn't the only hardware to
         * have a hard time with partial packet reads...  reject it.
+        * Except OMAP2 can handle the small packets.
         */
        if (use_dma
                        && ep->has_dma
                        && ep->bEndpointAddress != 0
                        && (ep->bEndpointAddress & USB_DIR_IN) == 0
+                       && !cpu_class_is_omap2()
                        && (req->req.length % ep->ep.maxpacket) != 0) {
                DBG("%s, no partial packet OUT reads\n", __FUNCTION__);
                return -EMSGSIZE;
@@ -1002,7 +1029,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
                                /* STATUS for zero length DATA stages is
                                 * always an IN ... even for IN transfers,
-                                * a wierd case which seem to stall OMAP.
+                                * a weird case which seem to stall OMAP.
                                 */
                                UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
                                UDC_CTRL_REG = UDC_CLR_EP;