USB device DMA support on OMAP2
Subsystems (2)
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.
---
drivers/usb/gadget/omap_udc.c +49 -22
@@ -4,6 +4,8 @@* Copyright (C) 2004 Texas Instruments, Inc. * Copyright (C) 2004-2005 David Brownell * +* OMAP2 & DMA support by Kyungmin Park <[email protected]> +* * 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
@@ -60,11 +62,6 @@/* 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
@@ -73,6 +70,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
@@ -571,20 +570,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,
@@ -622,20 +626,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 );
@@ -743,6 +758,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)
@@ -769,11 +785,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 );
@@ -785,7 +805,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;
@@ -795,7 +820,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 );
@@ -808,7 +833,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 ; }
@@ -926,11 +951,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 ;
Quoted 1 line
The current omap udc dosen't support the DMA mode
It most certainly does!! I think you it has DMA issues on OMAP2.
Quoted 8 lines
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 <[email protected]>
I'll have a look at it, thanks.
Is this aginst the linux-omap tree, or current kernel.org code? (There _shouldn't_ be any differences, but I've not checked in some time now and such issues do creep in from time to time.)
- Dave
Quoted 4 lines · David Brownell
Quoted 1 line
The current omap udc dosen't support the DMA mode
It most certainly does!! I think you it has DMA issues on OMAP2.
Ah, Yes, OMAP1 supports the DMA mode. It means the OMAP2 DMA support.
Quoted 8 lines
Quoted 8 lines
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.
Quoted 8 lines
Quoted 1 line
Signed-off-by Kyungmin Park <[email protected]>I'll have a look at it, thanks.
Is this aginst the linux-omap tree, or current kernel.org code? (There _shouldn't_ be any differences, but I've not checked in some time now and such issues do creep in from time to time.)
There's some difference related with double buffering. It's against the latest kernel code. I checked it.
Thank you,
Kyungmin Park