Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 527ea73e authored by Kyungmin Park's avatar Kyungmin Park Committed by Greg Kroah-Hartman
Browse files

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: default avatarKyungmin Park <kyungmin.park@samsung.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Tony Lindgren <tony@atomide.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 568fdade
Loading
Loading
Loading
Loading
+49 −22
Original line number Diff line number Diff line
@@ -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
@@ -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
	 */

	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 = (req->req.length - req->req.actual) / ep->ep.maxpacket;
		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,
			0, 0);
				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;