mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	[ARM] 5414/2: ep93xx m2p dma core
Add m2p dma support to the ep93xx Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> Acked-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									1c8daabe1d
								
							
						
					
					
						commit
						6d831c6554
					
				
					 4 changed files with 463 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
#
 | 
			
		||||
# Makefile for the linux kernel.
 | 
			
		||||
#
 | 
			
		||||
obj-y			:= core.o clock.o gpio.o
 | 
			
		||||
obj-y			:= core.o clock.o dma-m2p.o gpio.o
 | 
			
		||||
obj-m			:=
 | 
			
		||||
obj-n			:=
 | 
			
		||||
obj-			:=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										408
									
								
								arch/arm/mach-ep93xx/dma-m2p.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										408
									
								
								arch/arm/mach-ep93xx/dma-m2p.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,408 @@
 | 
			
		|||
/*
 | 
			
		||||
 * arch/arm/mach-ep93xx/dma-m2p.c
 | 
			
		||||
 * M2P DMA handling for Cirrus EP93xx chips.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
 | 
			
		||||
 * Copyright (C) 2006 Applied Data Systems
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2009 Ryan Mallon <ryan@bluewatersys.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 (at
 | 
			
		||||
 * your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * On the EP93xx chip the following peripherals my be allocated to the 10
 | 
			
		||||
 * Memory to Internal Peripheral (M2P) channels (5 transmit + 5 receive).
 | 
			
		||||
 *
 | 
			
		||||
 *	I2S	contains 3 Tx and 3 Rx DMA Channels
 | 
			
		||||
 *	AAC	contains 3 Tx and 3 Rx DMA Channels
 | 
			
		||||
 *	UART1	contains 1 Tx and 1 Rx DMA Channels
 | 
			
		||||
 *	UART2	contains 1 Tx and 1 Rx DMA Channels
 | 
			
		||||
 *	UART3	contains 1 Tx and 1 Rx DMA Channels
 | 
			
		||||
 *	IrDA	contains 1 Tx and 1 Rx DMA Channels
 | 
			
		||||
 *
 | 
			
		||||
 * SSP and IDE use the Memory to Memory (M2M) channels and are not covered
 | 
			
		||||
 * with this implementation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <mach/dma.h>
 | 
			
		||||
#include <mach/hardware.h>
 | 
			
		||||
 | 
			
		||||
#define M2P_CONTROL			0x00
 | 
			
		||||
#define  M2P_CONTROL_STALL_IRQ_EN	(1 << 0)
 | 
			
		||||
#define  M2P_CONTROL_NFB_IRQ_EN		(1 << 1)
 | 
			
		||||
#define  M2P_CONTROL_ERROR_IRQ_EN	(1 << 3)
 | 
			
		||||
#define  M2P_CONTROL_ENABLE		(1 << 4)
 | 
			
		||||
#define M2P_INTERRUPT			0x04
 | 
			
		||||
#define  M2P_INTERRUPT_STALL		(1 << 0)
 | 
			
		||||
#define  M2P_INTERRUPT_NFB		(1 << 1)
 | 
			
		||||
#define  M2P_INTERRUPT_ERROR		(1 << 3)
 | 
			
		||||
#define M2P_PPALLOC			0x08
 | 
			
		||||
#define M2P_STATUS			0x0c
 | 
			
		||||
#define M2P_REMAIN			0x14
 | 
			
		||||
#define M2P_MAXCNT0			0x20
 | 
			
		||||
#define M2P_BASE0			0x24
 | 
			
		||||
#define M2P_MAXCNT1			0x30
 | 
			
		||||
#define M2P_BASE1			0x34
 | 
			
		||||
 | 
			
		||||
#define STATE_IDLE	0	/* Channel is inactive.  */
 | 
			
		||||
#define STATE_STALL	1	/* Channel is active, no buffers pending.  */
 | 
			
		||||
#define STATE_ON	2	/* Channel is active, one buffer pending.  */
 | 
			
		||||
#define STATE_NEXT	3	/* Channel is active, two buffers pending.  */
 | 
			
		||||
 | 
			
		||||
struct m2p_channel {
 | 
			
		||||
	char				*name;
 | 
			
		||||
	void __iomem			*base;
 | 
			
		||||
	int				irq;
 | 
			
		||||
 | 
			
		||||
	struct clk			*clk;
 | 
			
		||||
	spinlock_t			lock;
 | 
			
		||||
 | 
			
		||||
	void				*client;
 | 
			
		||||
	unsigned			next_slot:1;
 | 
			
		||||
	struct ep93xx_dma_buffer	*buffer_xfer;
 | 
			
		||||
	struct ep93xx_dma_buffer	*buffer_next;
 | 
			
		||||
	struct list_head		buffers_pending;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct m2p_channel m2p_rx[] = {
 | 
			
		||||
	{"m2p1", EP93XX_DMA_BASE + 0x0040, IRQ_EP93XX_DMAM2P1},
 | 
			
		||||
	{"m2p3", EP93XX_DMA_BASE + 0x00c0, IRQ_EP93XX_DMAM2P3},
 | 
			
		||||
	{"m2p5", EP93XX_DMA_BASE + 0x0200, IRQ_EP93XX_DMAM2P5},
 | 
			
		||||
	{"m2p7", EP93XX_DMA_BASE + 0x0280, IRQ_EP93XX_DMAM2P7},
 | 
			
		||||
	{"m2p9", EP93XX_DMA_BASE + 0x0300, IRQ_EP93XX_DMAM2P9},
 | 
			
		||||
	{NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct m2p_channel m2p_tx[] = {
 | 
			
		||||
	{"m2p0", EP93XX_DMA_BASE + 0x0000, IRQ_EP93XX_DMAM2P0},
 | 
			
		||||
	{"m2p2", EP93XX_DMA_BASE + 0x0080, IRQ_EP93XX_DMAM2P2},
 | 
			
		||||
	{"m2p4", EP93XX_DMA_BASE + 0x0240, IRQ_EP93XX_DMAM2P4},
 | 
			
		||||
	{"m2p6", EP93XX_DMA_BASE + 0x02c0, IRQ_EP93XX_DMAM2P6},
 | 
			
		||||
	{"m2p8", EP93XX_DMA_BASE + 0x0340, IRQ_EP93XX_DMAM2P8},
 | 
			
		||||
	{NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void feed_buf(struct m2p_channel *ch, struct ep93xx_dma_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	if (ch->next_slot == 0) {
 | 
			
		||||
		writel(buf->size, ch->base + M2P_MAXCNT0);
 | 
			
		||||
		writel(buf->bus_addr, ch->base + M2P_BASE0);
 | 
			
		||||
	} else {
 | 
			
		||||
		writel(buf->size, ch->base + M2P_MAXCNT1);
 | 
			
		||||
		writel(buf->bus_addr, ch->base + M2P_BASE1);
 | 
			
		||||
	}
 | 
			
		||||
	ch->next_slot ^= 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void choose_buffer_xfer(struct m2p_channel *ch)
 | 
			
		||||
{
 | 
			
		||||
	struct ep93xx_dma_buffer *buf;
 | 
			
		||||
 | 
			
		||||
	ch->buffer_xfer = NULL;
 | 
			
		||||
	if (!list_empty(&ch->buffers_pending)) {
 | 
			
		||||
		buf = list_entry(ch->buffers_pending.next,
 | 
			
		||||
				 struct ep93xx_dma_buffer, list);
 | 
			
		||||
		list_del(&buf->list);
 | 
			
		||||
		feed_buf(ch, buf);
 | 
			
		||||
		ch->buffer_xfer = buf;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void choose_buffer_next(struct m2p_channel *ch)
 | 
			
		||||
{
 | 
			
		||||
	struct ep93xx_dma_buffer *buf;
 | 
			
		||||
 | 
			
		||||
	ch->buffer_next = NULL;
 | 
			
		||||
	if (!list_empty(&ch->buffers_pending)) {
 | 
			
		||||
		buf = list_entry(ch->buffers_pending.next,
 | 
			
		||||
				 struct ep93xx_dma_buffer, list);
 | 
			
		||||
		list_del(&buf->list);
 | 
			
		||||
		feed_buf(ch, buf);
 | 
			
		||||
		ch->buffer_next = buf;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void m2p_set_control(struct m2p_channel *ch, u32 v)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * The control register must be read immediately after being written so
 | 
			
		||||
	 * that the internal state machine is correctly updated. See the ep93xx
 | 
			
		||||
	 * users' guide for details.
 | 
			
		||||
	 */
 | 
			
		||||
	writel(v, ch->base + M2P_CONTROL);
 | 
			
		||||
	readl(ch->base + M2P_CONTROL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int m2p_channel_state(struct m2p_channel *ch)
 | 
			
		||||
{
 | 
			
		||||
	return (readl(ch->base + M2P_STATUS) >> 4) & 0x3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static irqreturn_t m2p_irq(int irq, void *dev_id)
 | 
			
		||||
{
 | 
			
		||||
	struct m2p_channel *ch = dev_id;
 | 
			
		||||
	struct ep93xx_dma_m2p_client *cl;
 | 
			
		||||
	u32 irq_status, v;
 | 
			
		||||
	int error = 0;
 | 
			
		||||
 | 
			
		||||
	cl = ch->client;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&ch->lock);
 | 
			
		||||
	irq_status = readl(ch->base + M2P_INTERRUPT);
 | 
			
		||||
 | 
			
		||||
	if (irq_status & M2P_INTERRUPT_ERROR) {
 | 
			
		||||
		writel(M2P_INTERRUPT_ERROR, ch->base + M2P_INTERRUPT);
 | 
			
		||||
		error = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((irq_status & (M2P_INTERRUPT_STALL | M2P_INTERRUPT_NFB)) == 0) {
 | 
			
		||||
		spin_unlock(&ch->lock);
 | 
			
		||||
		return IRQ_NONE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (m2p_channel_state(ch)) {
 | 
			
		||||
	case STATE_IDLE:
 | 
			
		||||
		pr_crit("m2p_irq: dma interrupt without a dma buffer\n");
 | 
			
		||||
		BUG();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case STATE_STALL:
 | 
			
		||||
		cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error);
 | 
			
		||||
		if (ch->buffer_next != NULL) {
 | 
			
		||||
			cl->buffer_finished(cl->cookie, ch->buffer_next,
 | 
			
		||||
					    0, error);
 | 
			
		||||
		}
 | 
			
		||||
		choose_buffer_xfer(ch);
 | 
			
		||||
		choose_buffer_next(ch);
 | 
			
		||||
		if (ch->buffer_xfer != NULL)
 | 
			
		||||
			cl->buffer_started(cl->cookie, ch->buffer_xfer);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case STATE_ON:
 | 
			
		||||
		cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error);
 | 
			
		||||
		ch->buffer_xfer = ch->buffer_next;
 | 
			
		||||
		choose_buffer_next(ch);
 | 
			
		||||
		cl->buffer_started(cl->cookie, ch->buffer_xfer);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case STATE_NEXT:
 | 
			
		||||
		pr_crit("m2p_irq: dma interrupt while next\n");
 | 
			
		||||
		BUG();
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v = readl(ch->base + M2P_CONTROL) & ~(M2P_CONTROL_STALL_IRQ_EN |
 | 
			
		||||
					      M2P_CONTROL_NFB_IRQ_EN);
 | 
			
		||||
	if (ch->buffer_xfer != NULL)
 | 
			
		||||
		v |= M2P_CONTROL_STALL_IRQ_EN;
 | 
			
		||||
	if (ch->buffer_next != NULL)
 | 
			
		||||
		v |= M2P_CONTROL_NFB_IRQ_EN;
 | 
			
		||||
	m2p_set_control(ch, v);
 | 
			
		||||
 | 
			
		||||
	spin_unlock(&ch->lock);
 | 
			
		||||
	return IRQ_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct m2p_channel *find_free_channel(struct ep93xx_dma_m2p_client *cl)
 | 
			
		||||
{
 | 
			
		||||
	struct m2p_channel *ch;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (cl->flags & EP93XX_DMA_M2P_RX)
 | 
			
		||||
		ch = m2p_rx;
 | 
			
		||||
	else
 | 
			
		||||
		ch = m2p_tx;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; ch[i].base; i++) {
 | 
			
		||||
		struct ep93xx_dma_m2p_client *client;
 | 
			
		||||
 | 
			
		||||
		client = ch[i].client;
 | 
			
		||||
		if (client != NULL) {
 | 
			
		||||
			int port;
 | 
			
		||||
 | 
			
		||||
			port = cl->flags & EP93XX_DMA_M2P_PORT_MASK;
 | 
			
		||||
			if (port == (client->flags &
 | 
			
		||||
				     EP93XX_DMA_M2P_PORT_MASK)) {
 | 
			
		||||
				pr_warning("DMA channel already used by %s\n",
 | 
			
		||||
					   cl->name ? : "unknown client");
 | 
			
		||||
				return ERR_PTR(-EBUSY);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; ch[i].base; i++) {
 | 
			
		||||
		if (ch[i].client == NULL)
 | 
			
		||||
			return ch + i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_warning("No free DMA channel for %s\n",
 | 
			
		||||
		   cl->name ? : "unknown client");
 | 
			
		||||
	return ERR_PTR(-ENODEV);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void channel_enable(struct m2p_channel *ch)
 | 
			
		||||
{
 | 
			
		||||
	struct ep93xx_dma_m2p_client *cl = ch->client;
 | 
			
		||||
	u32 v;
 | 
			
		||||
 | 
			
		||||
	clk_enable(ch->clk);
 | 
			
		||||
 | 
			
		||||
	v = cl->flags & EP93XX_DMA_M2P_PORT_MASK;
 | 
			
		||||
	writel(v, ch->base + M2P_PPALLOC);
 | 
			
		||||
 | 
			
		||||
	v = cl->flags & EP93XX_DMA_M2P_ERROR_MASK;
 | 
			
		||||
	v |= M2P_CONTROL_ENABLE | M2P_CONTROL_ERROR_IRQ_EN;
 | 
			
		||||
	m2p_set_control(ch, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void channel_disable(struct m2p_channel *ch)
 | 
			
		||||
{
 | 
			
		||||
	u32 v;
 | 
			
		||||
 | 
			
		||||
	v = readl(ch->base + M2P_CONTROL);
 | 
			
		||||
	v &= ~(M2P_CONTROL_STALL_IRQ_EN | M2P_CONTROL_NFB_IRQ_EN);
 | 
			
		||||
	m2p_set_control(ch, v);
 | 
			
		||||
 | 
			
		||||
	while (m2p_channel_state(ch) == STATE_ON)
 | 
			
		||||
		cpu_relax();
 | 
			
		||||
 | 
			
		||||
	m2p_set_control(ch, 0x0);
 | 
			
		||||
 | 
			
		||||
	while (m2p_channel_state(ch) == STATE_STALL)
 | 
			
		||||
		cpu_relax();
 | 
			
		||||
 | 
			
		||||
	clk_disable(ch->clk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *cl)
 | 
			
		||||
{
 | 
			
		||||
	struct m2p_channel *ch;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	ch = find_free_channel(cl);
 | 
			
		||||
	if (IS_ERR(ch))
 | 
			
		||||
		return PTR_ERR(ch);
 | 
			
		||||
 | 
			
		||||
	err = request_irq(ch->irq, m2p_irq, 0, cl->name ? : "dma-m2p", ch);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	ch->client = cl;
 | 
			
		||||
	ch->next_slot = 0;
 | 
			
		||||
	ch->buffer_xfer = NULL;
 | 
			
		||||
	ch->buffer_next = NULL;
 | 
			
		||||
	INIT_LIST_HEAD(&ch->buffers_pending);
 | 
			
		||||
 | 
			
		||||
	cl->channel = ch;
 | 
			
		||||
 | 
			
		||||
	channel_enable(ch);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_register);
 | 
			
		||||
 | 
			
		||||
void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *cl)
 | 
			
		||||
{
 | 
			
		||||
	struct m2p_channel *ch = cl->channel;
 | 
			
		||||
 | 
			
		||||
	channel_disable(ch);
 | 
			
		||||
	free_irq(ch->irq, ch);
 | 
			
		||||
	ch->client = NULL;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_unregister);
 | 
			
		||||
 | 
			
		||||
void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *cl,
 | 
			
		||||
			   struct ep93xx_dma_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct m2p_channel *ch = cl->channel;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	u32 v;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ch->lock, flags);
 | 
			
		||||
	v = readl(ch->base + M2P_CONTROL);
 | 
			
		||||
	if (ch->buffer_xfer == NULL) {
 | 
			
		||||
		ch->buffer_xfer = buf;
 | 
			
		||||
		feed_buf(ch, buf);
 | 
			
		||||
		cl->buffer_started(cl->cookie, buf);
 | 
			
		||||
 | 
			
		||||
		v |= M2P_CONTROL_STALL_IRQ_EN;
 | 
			
		||||
		m2p_set_control(ch, v);
 | 
			
		||||
 | 
			
		||||
	} else if (ch->buffer_next == NULL) {
 | 
			
		||||
		ch->buffer_next = buf;
 | 
			
		||||
		feed_buf(ch, buf);
 | 
			
		||||
 | 
			
		||||
		v |= M2P_CONTROL_NFB_IRQ_EN;
 | 
			
		||||
		m2p_set_control(ch, v);
 | 
			
		||||
	} else {
 | 
			
		||||
		list_add_tail(&buf->list, &ch->buffers_pending);
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_irqrestore(&ch->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit);
 | 
			
		||||
 | 
			
		||||
void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *cl,
 | 
			
		||||
				     struct ep93xx_dma_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct m2p_channel *ch = cl->channel;
 | 
			
		||||
 | 
			
		||||
	list_add_tail(&buf->list, &ch->buffers_pending);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit_recursive);
 | 
			
		||||
 | 
			
		||||
void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *cl)
 | 
			
		||||
{
 | 
			
		||||
	struct m2p_channel *ch = cl->channel;
 | 
			
		||||
 | 
			
		||||
	channel_disable(ch);
 | 
			
		||||
	ch->next_slot = 0;
 | 
			
		||||
	ch->buffer_xfer = NULL;
 | 
			
		||||
	ch->buffer_next = NULL;
 | 
			
		||||
	INIT_LIST_HEAD(&ch->buffers_pending);
 | 
			
		||||
	channel_enable(ch);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_flush);
 | 
			
		||||
 | 
			
		||||
static int init_channel(struct m2p_channel *ch)
 | 
			
		||||
{
 | 
			
		||||
	ch->clk = clk_get(NULL, ch->name);
 | 
			
		||||
	if (IS_ERR(ch->clk))
 | 
			
		||||
		return PTR_ERR(ch->clk);
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&ch->lock);
 | 
			
		||||
	ch->client = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init ep93xx_dma_m2p_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; m2p_rx[i].base; i++) {
 | 
			
		||||
		ret = init_channel(m2p_rx + i);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; m2p_tx[i].base; i++) {
 | 
			
		||||
		ret = init_channel(m2p_tx + i);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_info("M2P DMA subsystem initialized\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
arch_initcall(ep93xx_dma_m2p_init);
 | 
			
		||||
							
								
								
									
										52
									
								
								arch/arm/mach-ep93xx/include/mach/dma.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								arch/arm/mach-ep93xx/include/mach/dma.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
#ifndef __ASM_ARCH_DMA_H
 | 
			
		||||
#define __ASM_ARCH_DMA_H
 | 
			
		||||
 | 
			
		||||
#include <linux/list.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
struct ep93xx_dma_buffer {
 | 
			
		||||
	struct list_head	list;
 | 
			
		||||
	u32			bus_addr;
 | 
			
		||||
	u16			size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ep93xx_dma_m2p_client {
 | 
			
		||||
	char			*name;
 | 
			
		||||
	u8			flags;
 | 
			
		||||
	void			*cookie;
 | 
			
		||||
	void			(*buffer_started)(void *cookie,
 | 
			
		||||
					struct ep93xx_dma_buffer *buf);
 | 
			
		||||
	void			(*buffer_finished)(void *cookie,
 | 
			
		||||
					struct ep93xx_dma_buffer *buf,
 | 
			
		||||
					int bytes, int error);
 | 
			
		||||
 | 
			
		||||
	/* Internal to the DMA code.  */
 | 
			
		||||
	void			*channel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_I2S1	0x00
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_I2S2	0x01
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_AAC1	0x02
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_AAC2	0x03
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_AAC3	0x04
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_I2S3	0x05
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_UART1	0x06
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_UART2	0x07
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_UART3	0x08
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_IRDA	0x09
 | 
			
		||||
#define EP93XX_DMA_M2P_PORT_MASK	0x0f
 | 
			
		||||
#define EP93XX_DMA_M2P_TX		0x00
 | 
			
		||||
#define EP93XX_DMA_M2P_RX		0x10
 | 
			
		||||
#define EP93XX_DMA_M2P_ABORT_ON_ERROR	0x20
 | 
			
		||||
#define EP93XX_DMA_M2P_IGNORE_ERROR	0x40
 | 
			
		||||
#define EP93XX_DMA_M2P_ERROR_MASK	0x60
 | 
			
		||||
 | 
			
		||||
int  ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *m2p);
 | 
			
		||||
void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *m2p);
 | 
			
		||||
void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *m2p,
 | 
			
		||||
			   struct ep93xx_dma_buffer *buf);
 | 
			
		||||
void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *m2p,
 | 
			
		||||
				     struct ep93xx_dma_buffer *buf);
 | 
			
		||||
void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *m2p);
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_ARCH_DMA_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +58,8 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
/* AHB peripherals */
 | 
			
		||||
#define EP93XX_DMA_BASE			(EP93XX_AHB_VIRT_BASE + 0x00000000)
 | 
			
		||||
#define EP93XX_DMA_BASE			((void __iomem *)		\
 | 
			
		||||
					 (EP93XX_AHB_VIRT_BASE + 0x00000000))
 | 
			
		||||
 | 
			
		||||
#define EP93XX_ETHERNET_BASE		(EP93XX_AHB_VIRT_BASE + 0x00010000)
 | 
			
		||||
#define EP93XX_ETHERNET_PHYS_BASE	(EP93XX_AHB_PHYS_BASE + 0x00010000)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue