Commit ae0502f8 authored by David Brownell's avatar David Brownell Committed by Kevin Hilman

edma: move setup to dm<soc>.c

Move EDMA platform device creation into SoC-specific init code,
and provide it with platform_data to parameterize some of the
key differences.

Handle some key dm646x differences.  Ones that can change the
behavior including supporting all the DMA slots (512 vs just 128)
and a different set of no-events channels.

This doesn't yet ioremap(), or support using more than the first
two TCs on platforms like dm646x or dm365.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent e0db1357
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <mach/dm355.h> #include <mach/dm355.h>
#include <mach/clock.h> #include <mach/clock.h>
#include <mach/cpu.h>
#include <mach/edma.h>
#include <mach/psc.h> #include <mach/psc.h>
#include <mach/mux.h> #include <mach/mux.h>
#include <mach/irqs.h> #include <mach/irqs.h>
...@@ -463,8 +465,75 @@ EVT_CFG(DM355, EVT9_ASP1_RX, 1, 1, 0, false) ...@@ -463,8 +465,75 @@ EVT_CFG(DM355, EVT9_ASP1_RX, 1, 1, 0, false)
EVT_CFG(DM355, EVT26_MMC0_RX, 2, 1, 0, false) EVT_CFG(DM355, EVT26_MMC0_RX, 2, 1, 0, false)
}; };
/*----------------------------------------------------------------------*/
static const s8 dma_chan_dm355_no_event[] = {
12, 13, 24, 56, 57,
58, 59, 60, 61, 62,
63,
-1
};
static struct edma_soc_info dm355_edma_info = {
.n_channel = 64,
.n_region = 4,
.n_slot = 128,
.n_tc = 2,
.noevent = dma_chan_dm355_no_event,
};
static struct resource edma_resources[] = {
{
.start = 0x01c00000,
.end = 0x01c00000 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc0",
.start = 0x01c10000,
.end = 0x01c10000 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc1",
.start = 0x01c10400,
.end = 0x01c10400 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_CCINT0,
.flags = IORESOURCE_IRQ,
},
{
.start = IRQ_CCERRINT,
.flags = IORESOURCE_IRQ,
},
/* not using (or muxing) TC*_ERR */
};
static struct platform_device dm355_edma_device = {
.name = "edma",
.id = -1,
.dev.platform_data = &dm355_edma_info,
.num_resources = ARRAY_SIZE(edma_resources),
.resource = edma_resources,
};
/*----------------------------------------------------------------------*/
void __init dm355_init(void) void __init dm355_init(void)
{ {
davinci_clk_init(dm355_clks); davinci_clk_init(dm355_clks);
davinci_mux_register(dm355_pins, ARRAY_SIZE(dm355_pins));; davinci_mux_register(dm355_pins, ARRAY_SIZE(dm355_pins));;
} }
static int __init dm355_init_devices(void)
{
if (!cpu_is_davinci_dm355())
return 0;
davinci_cfg_reg(DM355_INT_EDMA_CC);
platform_device_register(&dm355_edma_device);
return 0;
}
postcore_initcall(dm355_init_devices);
...@@ -11,9 +11,13 @@ ...@@ -11,9 +11,13 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_device.h>
#include <mach/dm644x.h> #include <mach/dm644x.h>
#include <mach/clock.h> #include <mach/clock.h>
#include <mach/cpu.h>
#include <mach/edma.h>
#include <mach/irqs.h>
#include <mach/psc.h> #include <mach/psc.h>
#include <mach/mux.h> #include <mach/mux.h>
...@@ -358,8 +362,76 @@ MUX_CFG(DM644X, LFLDEN, 0, 25, 1, 1, false) ...@@ -358,8 +362,76 @@ MUX_CFG(DM644X, LFLDEN, 0, 25, 1, 1, false)
}; };
/*----------------------------------------------------------------------*/
static const s8 dma_chan_dm644x_no_event[] = {
0, 1, 12, 13, 14,
15, 25, 30, 31, 45,
46, 47, 55, 56, 57,
58, 59, 60, 61, 62,
63,
-1
};
static struct edma_soc_info dm644x_edma_info = {
.n_channel = 64,
.n_region = 4,
.n_slot = 128,
.n_tc = 2,
.noevent = dma_chan_dm644x_no_event,
};
static struct resource edma_resources[] = {
{
.start = 0x01c00000,
.end = 0x01c00000 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc0",
.start = 0x01c10000,
.end = 0x01c10000 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc1",
.start = 0x01c10400,
.end = 0x01c10400 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_CCINT0,
.flags = IORESOURCE_IRQ,
},
{
.start = IRQ_CCERRINT,
.flags = IORESOURCE_IRQ,
},
/* not using TC*_ERR */
};
static struct platform_device dm644x_edma_device = {
.name = "edma",
.id = -1,
.dev.platform_data = &dm644x_edma_info,
.num_resources = ARRAY_SIZE(edma_resources),
.resource = edma_resources,
};
/*----------------------------------------------------------------------*/
void __init dm644x_init(void) void __init dm644x_init(void)
{ {
davinci_clk_init(dm644x_clks); davinci_clk_init(dm644x_clks);
davinci_mux_register(dm644x_pins, ARRAY_SIZE(dm644x_pins)); davinci_mux_register(dm644x_pins, ARRAY_SIZE(dm644x_pins));
} }
static int __init dm644x_init_devices(void)
{
if (!cpu_is_davinci_dm644x())
return 0;
platform_device_register(&dm644x_edma_device);
return 0;
}
postcore_initcall(dm644x_init_devices);
...@@ -11,9 +11,13 @@ ...@@ -11,9 +11,13 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_device.h>
#include <mach/dm646x.h> #include <mach/dm646x.h>
#include <mach/clock.h> #include <mach/clock.h>
#include <mach/cpu.h>
#include <mach/edma.h>
#include <mach/irqs.h>
#include <mach/psc.h> #include <mach/psc.h>
#include <mach/mux.h> #include <mach/mux.h>
...@@ -273,8 +277,88 @@ MUX_CFG(DM646X, AUDCK1, 0, 29, 1, 0, false) ...@@ -273,8 +277,88 @@ MUX_CFG(DM646X, AUDCK1, 0, 29, 1, 0, false)
MUX_CFG(DM646X, AUDCK0, 0, 28, 1, 0, false) MUX_CFG(DM646X, AUDCK0, 0, 28, 1, 0, false)
}; };
/*----------------------------------------------------------------------*/
static const s8 dma_chan_dm646x_no_event[] = {
0, 1, 2, 3, 13,
14, 15, 24, 25, 26,
27, 30, 31, 54, 55,
56,
-1
};
static struct edma_soc_info dm646x_edma_info = {
.n_channel = 64,
.n_region = 6, /* 0-1, 4-7 */
.n_slot = 512,
.n_tc = 4,
.noevent = dma_chan_dm646x_no_event,
};
static struct resource edma_resources[] = {
{
.start = 0x01c00000,
.end = 0x01c00000 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc0",
.start = 0x01c10000,
.end = 0x01c10000 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc1",
.start = 0x01c10400,
.end = 0x01c10400 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc2",
.start = 0x01c10800,
.end = 0x01c10800 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc3",
.start = 0x01c10c00,
.end = 0x01c10c00 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_CCINT0,
.flags = IORESOURCE_IRQ,
},
{
.start = IRQ_CCERRINT,
.flags = IORESOURCE_IRQ,
},
/* not using TC*_ERR */
};
static struct platform_device dm646x_edma_device = {
.name = "edma",
.id = -1,
.dev.platform_data = &dm646x_edma_info,
.num_resources = ARRAY_SIZE(edma_resources),
.resource = edma_resources,
};
/*----------------------------------------------------------------------*/
void __init dm646x_init(void) void __init dm646x_init(void)
{ {
davinci_clk_init(dm646x_clks); davinci_clk_init(dm646x_clks);
davinci_mux_register(dm646x_pins, ARRAY_SIZE(dm646x_pins)); davinci_mux_register(dm646x_pins, ARRAY_SIZE(dm646x_pins));
} }
static int __init dm646x_init_devices(void)
{
if (!cpu_is_davinci_dm646x())
return 0;
platform_device_register(&dm646x_edma_device);
return 0;
}
postcore_initcall(dm646x_init_devices);
...@@ -104,6 +104,12 @@ ...@@ -104,6 +104,12 @@
#define edmacc_regs_base IO_ADDRESS(DAVINCI_DMA_3PCC_BASE) #define edmacc_regs_base IO_ADDRESS(DAVINCI_DMA_3PCC_BASE)
#define EDMA_MAX_DMACH 64
#define EDMA_MAX_PARAMENTRY 512
#define EDMA_MAX_EVQUE 2 /* FIXME too small */
/*****************************************************************************/ /*****************************************************************************/
static inline unsigned int edma_read(int offset) static inline unsigned int edma_read(int offset)
...@@ -199,55 +205,25 @@ static inline void edma_parm_or(int offset, int param_no, unsigned or) ...@@ -199,55 +205,25 @@ static inline void edma_parm_or(int offset, int param_no, unsigned or)
/*****************************************************************************/ /*****************************************************************************/
static struct platform_driver edma_driver = { /* actual number of DMA channels and slots on this silicon */
.driver.name = "edma", static unsigned num_channels;
}; static unsigned num_slots;
static struct resource edma_resources[] = {
{
.start = DAVINCI_DMA_3PCC_BASE,
.end = DAVINCI_DMA_3PCC_BASE + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc0",
.start = 0x01c10000,
.end = 0x01c10000 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "edma_tc1",
.start = 0x01c10400,
.end = 0x01c10400 + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device edma_dev = {
.name = "edma",
.id = -1,
.dev.driver = &edma_driver.driver,
.num_resources = ARRAY_SIZE(edma_resources),
.resource = edma_resources,
};
/*****************************************************************************/
static struct dma_interrupt_data { static struct dma_interrupt_data {
void (*callback)(unsigned channel, unsigned short ch_status, void *data); void (*callback)(unsigned channel, unsigned short ch_status, void *data);
void *data; void *data;
} intr_data[DAVINCI_EDMA_NUM_DMACH]; } intr_data[EDMA_MAX_DMACH];
/* The edma_inuse bit for each PaRAM slot is clear unless the /* The edma_inuse bit for each PaRAM slot is clear unless the
* channel is in use ... by ARM or DSP, for QDMA, or whatever. * channel is in use ... by ARM or DSP, for QDMA, or whatever.
*/ */
static DECLARE_BITMAP(edma_inuse, DAVINCI_EDMA_NUM_PARAMENTRY); static DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY);
/* The edma_noevent bit for each channel is clear unless /* The edma_noevent bit for each channel is clear unless
* it doesn't trigger DMA events on this platform. It uses a * it doesn't trigger DMA events on this platform. It uses a
* bit of SOC-specific initialization code. * bit of SOC-specific initialization code.
*/ */
static DECLARE_BITMAP(edma_noevent, DAVINCI_EDMA_NUM_DMACH); static DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH);
/* dummy param set used to (re)initialize parameter RAM slots */ /* dummy param set used to (re)initialize parameter RAM slots */
static const struct edmacc_param dummy_paramset = { static const struct edmacc_param dummy_paramset = {
...@@ -255,16 +231,8 @@ static const struct edmacc_param dummy_paramset = { ...@@ -255,16 +231,8 @@ static const struct edmacc_param dummy_paramset = {
.ccnt = 1, .ccnt = 1,
}; };
static const s8 __initconst dma_chan_dm644x_no_event[] = {
0, 1, 12, 13, 14, 15, 25, 30, 31, 45, 46, 47, 55, 56, 57, 58, 59, 60,
61, 62, 63, -1
};
static const s8 __initconst dma_chan_dm355_no_event[] = {
12, 13, 24, 56, 57, 58, 59, 60, 61, 62, 63, -1
};
static const int __initconst static const int __initconst
queue_tc_mapping[DAVINCI_EDMA_NUM_EVQUE + 1][2] = { queue_tc_mapping[EDMA_MAX_EVQUE + 1][2] = {
/* {event queue no, TC no} */ /* {event queue no, TC no} */
{0, 0}, {0, 0},
{1, 1}, {1, 1},
...@@ -272,7 +240,7 @@ queue_tc_mapping[DAVINCI_EDMA_NUM_EVQUE + 1][2] = { ...@@ -272,7 +240,7 @@ queue_tc_mapping[DAVINCI_EDMA_NUM_EVQUE + 1][2] = {
}; };
static const int __initconst static const int __initconst
queue_priority_mapping[DAVINCI_EDMA_NUM_EVQUE + 1][2] = { queue_priority_mapping[EDMA_MAX_EVQUE + 1][2] = {
/* {event queue no, Priority} */ /* {event queue no, Priority} */
{0, 3}, {0, 3},
{1, 7}, {1, 7},
...@@ -337,7 +305,7 @@ static irqreturn_t dma_irq_handler(int irq, void *data) ...@@ -337,7 +305,7 @@ static irqreturn_t dma_irq_handler(int irq, void *data)
int i; int i;
unsigned int cnt = 0; unsigned int cnt = 0;
dev_dbg(&edma_dev.dev, "dma_irq_handler\n"); dev_dbg(data, "dma_irq_handler\n");
if ((edma_shadow0_read_array(SH_IPR, 0) == 0) if ((edma_shadow0_read_array(SH_IPR, 0) == 0)
&& (edma_shadow0_read_array(SH_IPR, 1) == 0)) && (edma_shadow0_read_array(SH_IPR, 1) == 0))
...@@ -351,7 +319,7 @@ static irqreturn_t dma_irq_handler(int irq, void *data) ...@@ -351,7 +319,7 @@ static irqreturn_t dma_irq_handler(int irq, void *data)
j = 1; j = 1;
else else
break; break;
dev_dbg(&edma_dev.dev, "IPR%d %08x\n", j, dev_dbg(data, "IPR%d %08x\n", j,
edma_shadow0_read_array(SH_IPR, j)); edma_shadow0_read_array(SH_IPR, j));
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
int k = (j << 5) + i; int k = (j << 5) + i;
...@@ -382,7 +350,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) ...@@ -382,7 +350,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
int i; int i;
unsigned int cnt = 0; unsigned int cnt = 0;
dev_dbg(&edma_dev.dev, "dma_ccerr_handler\n"); dev_dbg(data, "dma_ccerr_handler\n");
if ((edma_read_array(EDMA_EMR, 0) == 0) && if ((edma_read_array(EDMA_EMR, 0) == 0) &&
(edma_read_array(EDMA_EMR, 1) == 0) && (edma_read_array(EDMA_EMR, 1) == 0) &&
...@@ -396,7 +364,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) ...@@ -396,7 +364,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
else if (edma_read_array(EDMA_EMR, 1)) else if (edma_read_array(EDMA_EMR, 1))
j = 1; j = 1;
if (j >= 0) { if (j >= 0) {
dev_dbg(&edma_dev.dev, "EMR%d %08x\n", j, dev_dbg(data, "EMR%d %08x\n", j,
edma_read_array(EDMA_EMR, j)); edma_read_array(EDMA_EMR, j));
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
int k = (j << 5) + i; int k = (j << 5) + i;
...@@ -415,7 +383,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) ...@@ -415,7 +383,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
} }
} }
} else if (edma_read(EDMA_QEMR)) { } else if (edma_read(EDMA_QEMR)) {
dev_dbg(&edma_dev.dev, "QEMR %02x\n", dev_dbg(data, "QEMR %02x\n",
edma_read(EDMA_QEMR)); edma_read(EDMA_QEMR));
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (edma_read(EDMA_QEMR) & (1 << i)) { if (edma_read(EDMA_QEMR) & (1 << i)) {
...@@ -427,7 +395,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) ...@@ -427,7 +395,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
} }
} }
} else if (edma_read(EDMA_CCERR)) { } else if (edma_read(EDMA_CCERR)) {
dev_dbg(&edma_dev.dev, "CCERR %08x\n", dev_dbg(data, "CCERR %08x\n",
edma_read(EDMA_CCERR)); edma_read(EDMA_CCERR));
/* FIXME: CCERR.BIT(16) ignored! much better /* FIXME: CCERR.BIT(16) ignored! much better
* to just write CCERRCLR with CCERR value... * to just write CCERRCLR with CCERR value...
...@@ -465,116 +433,16 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) ...@@ -465,116 +433,16 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
static irqreturn_t dma_tc0err_handler(int irq, void *data) static irqreturn_t dma_tc0err_handler(int irq, void *data)
{ {
dev_dbg(&edma_dev.dev, "dma_tc0err_handler\n"); dev_dbg(data, "dma_tc0err_handler\n");
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static irqreturn_t dma_tc1err_handler(int irq, void *data) static irqreturn_t dma_tc1err_handler(int irq, void *data)
{ {
dev_dbg(&edma_dev.dev, "dma_tc1err_handler\n"); dev_dbg(data, "dma_tc1err_handler\n");
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/******************************************************************************
*
* DMA initialisation on davinci
*
*****************************************************************************/
static int __init davinci_dma_init(void)
{
int i;
int status;
const s8 *noevent;
platform_driver_register(&edma_driver);
platform_device_register(&edma_dev);
dev_dbg(&edma_dev.dev, "DMA REG BASE ADDR=%p\n", edmacc_regs_base);
for (i = 0; i < DAVINCI_EDMA_NUM_PARAMENTRY; i++)
memcpy_toio(edmacc_regs_base + PARM_OFFSET(i),
&dummy_paramset, PARM_SIZE);
if (cpu_is_davinci_dm355()) {
/* NOTE conflicts with SPI1_INT{0,1} and SPI2_INT0 */
davinci_cfg_reg(DM355_INT_EDMA_CC);
if (tc_errs_handled) {
davinci_cfg_reg(DM355_INT_EDMA_TC0_ERR);
davinci_cfg_reg(DM355_INT_EDMA_TC1_ERR);
}
noevent = dma_chan_dm355_no_event;
} else if (cpu_is_davinci_dm644x()) {
noevent = dma_chan_dm644x_no_event;
} else {
/* alloc_channel(EDMA_CHANNEL_ANY) fails */
noevent = NULL;
}
if (noevent) {
while (*noevent != -1)
set_bit(*noevent++, edma_noevent);
}
status = request_irq(IRQ_CCINT0, dma_irq_handler, 0, "edma", NULL);
if (status < 0) {
dev_dbg(&edma_dev.dev, "request_irq %d failed --> %d\n",
IRQ_CCINT0, status);
return status;
}
status = request_irq(IRQ_CCERRINT, dma_ccerr_handler, 0,
"edma_error", NULL);
if (status < 0) {
dev_dbg(&edma_dev.dev, "request_irq %d failed --> %d\n",
IRQ_CCERRINT, status);
return status;
}
if (tc_errs_handled) {
status = request_irq(IRQ_TCERRINT0, dma_tc0err_handler, 0,
"edma_tc0", NULL);
if (status < 0) {
dev_dbg(&edma_dev.dev, "request_irq %d failed --> %d\n",
IRQ_TCERRINT0, status);
return status;
}
status = request_irq(IRQ_TCERRINT, dma_tc1err_handler, 0,
"edma_tc1", NULL);
if (status < 0) {
dev_dbg(&edma_dev.dev, "request_irq %d --> %d\n",
IRQ_TCERRINT, status);
return status;
}
}
/* Everything lives on transfer controller 1 until otherwise specified.
* This way, long transfers on the low priority queue
* started by the codec engine will not cause audio defects.
*/
for (i = 0; i < DAVINCI_EDMA_NUM_DMACH; i++)
map_dmach_queue(i, EVENTQ_1);
i = 0;
/* Event queue to TC mapping */
while (queue_tc_mapping[i][0] != -1) {
map_queue_tc(queue_tc_mapping[i][0], queue_tc_mapping[i][1]);
i++;
}
i = 0;
/* Event queue priority mapping */
while (queue_priority_mapping[i][0] != -1) {
assign_priority_to_queue(queue_priority_mapping[i][0],
queue_priority_mapping[i][1]);
i++;
}
for (i = 0; i < DAVINCI_EDMA_NUM_REGIONS; i++) {
edma_write_array2(EDMA_DRAE, i, 0, 0x0);
edma_write_array2(EDMA_DRAE, i, 1, 0x0);
edma_write_array(EDMA_QRAE, i, 0x0);
}
return 0;
}
arch_initcall(davinci_dma_init);
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Resource alloc/free: dma channels, parameter RAM slots */ /* Resource alloc/free: dma channels, parameter RAM slots */
...@@ -618,13 +486,13 @@ int edma_alloc_channel(int channel, ...@@ -618,13 +486,13 @@ int edma_alloc_channel(int channel,
channel = 0; channel = 0;
for (;;) { for (;;) {
channel = find_next_zero_bit(edma_inuse, channel = find_next_zero_bit(edma_inuse,
DAVINCI_EDMA_NUM_DMACH, channel); num_channels, channel);
if (channel == DAVINCI_EDMA_NUM_DMACH) if (channel == num_channels)
return -ENOMEM; return -ENOMEM;
if (!test_and_set_bit(channel, edma_inuse)) if (!test_and_set_bit(channel, edma_inuse))
break; break;
} }
} else if (channel >= DAVINCI_EDMA_NUM_DMACH) { } else if (channel >= num_channels) {
return -EINVAL; return -EINVAL;
} else if (test_and_set_bit(channel, edma_inuse)) { } else if (test_and_set_bit(channel, edma_inuse)) {
return -EBUSY; return -EBUSY;
...@@ -661,7 +529,7 @@ EXPORT_SYMBOL(edma_alloc_channel); ...@@ -661,7 +529,7 @@ EXPORT_SYMBOL(edma_alloc_channel);
*/ */
void edma_free_channel(unsigned channel) void edma_free_channel(unsigned channel)
{ {
if (channel >= DAVINCI_EDMA_NUM_DMACH) if (channel >= num_channels)
return; return;
setup_dma_interrupt(channel, NULL, NULL); setup_dma_interrupt(channel, NULL, NULL);
...@@ -690,17 +558,16 @@ EXPORT_SYMBOL(edma_free_channel); ...@@ -690,17 +558,16 @@ EXPORT_SYMBOL(edma_free_channel);
int edma_alloc_slot(int slot) int edma_alloc_slot(int slot)
{ {
if (slot < 0) { if (slot < 0) {
slot = DAVINCI_EDMA_NUM_DMACH; slot = num_channels;
for (;;) { for (;;) {
slot = find_next_zero_bit(edma_inuse, slot = find_next_zero_bit(edma_inuse,
DAVINCI_EDMA_NUM_PARAMENTRY, slot); num_slots, slot);
if (slot == DAVINCI_EDMA_NUM_PARAMENTRY) if (slot == num_slots)
return -ENOMEM; return -ENOMEM;
if (!test_and_set_bit(slot, edma_inuse)) if (!test_and_set_bit(slot, edma_inuse))
break; break;
} }
} else if (slot < DAVINCI_EDMA_NUM_DMACH } else if (slot < num_channels || slot >= num_slots) {
|| slot >= DAVINCI_EDMA_NUM_PARAMENTRY) {
return -EINVAL; return -EINVAL;
} else if (test_and_set_bit(slot, edma_inuse)) { } else if (test_and_set_bit(slot, edma_inuse)) {
return -EBUSY; return -EBUSY;
...@@ -723,8 +590,7 @@ EXPORT_SYMBOL(edma_alloc_slot); ...@@ -723,8 +590,7 @@ EXPORT_SYMBOL(edma_alloc_slot);
*/ */
void edma_free_slot(unsigned slot) void edma_free_slot(unsigned slot)
{ {
if (slot < DAVINCI_EDMA_NUM_DMACH if (slot < num_channels || slot >= num_slots)
|| slot >= DAVINCI_EDMA_NUM_PARAMENTRY)
return; return;
memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot), memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot),
...@@ -751,7 +617,7 @@ EXPORT_SYMBOL(edma_free_slot); ...@@ -751,7 +617,7 @@ EXPORT_SYMBOL(edma_free_slot);
void edma_set_src(unsigned slot, dma_addr_t src_port, void edma_set_src(unsigned slot, dma_addr_t src_port,
enum address_mode mode, enum fifo_width width) enum address_mode mode, enum fifo_width width)
{ {
if (slot < DAVINCI_EDMA_NUM_PARAMENTRY) { if (slot < num_slots) {
unsigned int i = edma_parm_read(PARM_OPT, slot); unsigned int i = edma_parm_read(PARM_OPT, slot);
if (mode) { if (mode) {
...@@ -784,7 +650,7 @@ EXPORT_SYMBOL(edma_set_src); ...@@ -784,7 +650,7 @@ EXPORT_SYMBOL(edma_set_src);
void edma_set_dest(unsigned slot, dma_addr_t dest_port, void edma_set_dest(unsigned slot, dma_addr_t dest_port,
enum address_mode mode, enum fifo_width width) enum address_mode mode, enum fifo_width width)
{ {
if (slot < DAVINCI_EDMA_NUM_PARAMENTRY) { if (slot < num_slots) {
unsigned int i = edma_parm_read(PARM_OPT, slot); unsigned int i = edma_parm_read(PARM_OPT, slot);
if (mode) { if (mode) {
...@@ -835,7 +701,7 @@ EXPORT_SYMBOL(edma_get_position); ...@@ -835,7 +701,7 @@ EXPORT_SYMBOL(edma_get_position);
*/ */
void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx) void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx)
{ {
if (slot < DAVINCI_EDMA_NUM_PARAMENTRY) { if (slot < num_slots) {
edma_parm_modify(PARM_SRC_DST_BIDX, slot, edma_parm_modify(PARM_SRC_DST_BIDX, slot,
0xffff0000, src_bidx); 0xffff0000, src_bidx);
edma_parm_modify(PARM_SRC_DST_CIDX, slot, edma_parm_modify(PARM_SRC_DST_CIDX, slot,
...@@ -856,7 +722,7 @@ EXPORT_SYMBOL(edma_set_src_index); ...@@ -856,7 +722,7 @@ EXPORT_SYMBOL(edma_set_src_index);
*/ */
void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx) void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx)
{ {
if (slot < DAVINCI_EDMA_NUM_PARAMENTRY) { if (slot < num_slots) {
edma_parm_modify(PARM_SRC_DST_BIDX, slot, edma_parm_modify(PARM_SRC_DST_BIDX, slot,
0x0000ffff, dest_bidx << 16); 0x0000ffff, dest_bidx << 16);
edma_parm_modify(PARM_SRC_DST_CIDX, slot, edma_parm_modify(PARM_SRC_DST_CIDX, slot,
...@@ -898,7 +764,7 @@ void edma_set_transfer_params(unsigned slot, ...@@ -898,7 +764,7 @@ void edma_set_transfer_params(unsigned slot,
u16 acnt, u16 bcnt, u16 ccnt, u16 acnt, u16 bcnt, u16 ccnt,
u16 bcnt_rld, enum sync_dimension sync_mode) u16 bcnt_rld, enum sync_dimension sync_mode)
{ {
if (slot < DAVINCI_EDMA_NUM_PARAMENTRY) { if (slot < num_slots) {
edma_parm_modify(PARM_LINK_BCNTRLD, slot, edma_parm_modify(PARM_LINK_BCNTRLD, slot,
0x0000ffff, bcnt_rld << 16); 0x0000ffff, bcnt_rld << 16);
if (sync_mode == ASYNC) if (sync_mode == ASYNC)
...@@ -921,9 +787,9 @@ EXPORT_SYMBOL(edma_set_transfer_params); ...@@ -921,9 +787,9 @@ EXPORT_SYMBOL(edma_set_transfer_params);
*/ */
void edma_link(unsigned from, unsigned to) void edma_link(unsigned from, unsigned to)
{ {
if (from >= DAVINCI_EDMA_NUM_PARAMENTRY) if (from >= num_slots)
return; return;
if (to >= DAVINCI_EDMA_NUM_PARAMENTRY) if (to >= num_slots)
return; return;
edma_parm_modify(PARM_LINK_BCNTRLD, from, 0xffff0000, PARM_OFFSET(to)); edma_parm_modify(PARM_LINK_BCNTRLD, from, 0xffff0000, PARM_OFFSET(to));
} }
...@@ -938,7 +804,7 @@ EXPORT_SYMBOL(edma_link); ...@@ -938,7 +804,7 @@ EXPORT_SYMBOL(edma_link);
*/ */
void edma_unlink(unsigned from) void edma_unlink(unsigned from)
{ {
if (from >= DAVINCI_EDMA_NUM_PARAMENTRY) if (from >= num_slots)
return; return;
edma_parm_or(PARM_LINK_BCNTRLD, from, 0xffff); edma_parm_or(PARM_LINK_BCNTRLD, from, 0xffff);
} }
...@@ -960,7 +826,7 @@ EXPORT_SYMBOL(edma_unlink); ...@@ -960,7 +826,7 @@ EXPORT_SYMBOL(edma_unlink);
*/ */
void edma_write_slot(unsigned slot, const struct edmacc_param *param) void edma_write_slot(unsigned slot, const struct edmacc_param *param)
{ {
if (slot >= DAVINCI_EDMA_NUM_PARAMENTRY) if (slot >= num_slots)
return; return;
memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot), param, PARM_SIZE); memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot), param, PARM_SIZE);
} }
...@@ -976,7 +842,7 @@ EXPORT_SYMBOL(edma_write_slot); ...@@ -976,7 +842,7 @@ EXPORT_SYMBOL(edma_write_slot);
*/ */
void edma_read_slot(unsigned slot, struct edmacc_param *param) void edma_read_slot(unsigned slot, struct edmacc_param *param)
{ {
if (slot >= DAVINCI_EDMA_NUM_PARAMENTRY) if (slot >= num_slots)
return; return;
memcpy_fromio(param, edmacc_regs_base + PARM_OFFSET(slot), PARM_SIZE); memcpy_fromio(param, edmacc_regs_base + PARM_OFFSET(slot), PARM_SIZE);
} }
...@@ -995,7 +861,7 @@ EXPORT_SYMBOL(edma_read_slot); ...@@ -995,7 +861,7 @@ EXPORT_SYMBOL(edma_read_slot);
*/ */
void edma_pause(unsigned channel) void edma_pause(unsigned channel)
{ {
if (channel < DAVINCI_EDMA_NUM_DMACH) { if (channel < num_channels) {
unsigned int mask = (1 << (channel & 0x1f)); unsigned int mask = (1 << (channel & 0x1f));
edma_shadow0_write_array(SH_EECR, channel >> 5, mask); edma_shadow0_write_array(SH_EECR, channel >> 5, mask);
...@@ -1011,7 +877,7 @@ EXPORT_SYMBOL(edma_pause); ...@@ -1011,7 +877,7 @@ EXPORT_SYMBOL(edma_pause);
*/ */
void edma_resume(unsigned channel) void edma_resume(unsigned channel)
{ {
if (channel < DAVINCI_EDMA_NUM_DMACH) { if (channel < num_channels) {
unsigned int mask = (1 << (channel & 0x1f)); unsigned int mask = (1 << (channel & 0x1f));
edma_shadow0_write_array(SH_EESR, channel >> 5, mask); edma_shadow0_write_array(SH_EESR, channel >> 5, mask);
...@@ -1032,27 +898,27 @@ EXPORT_SYMBOL(edma_resume); ...@@ -1032,27 +898,27 @@ EXPORT_SYMBOL(edma_resume);
*/ */
int edma_start(unsigned channel) int edma_start(unsigned channel)
{ {
if (channel < DAVINCI_EDMA_NUM_DMACH) { if (channel < num_channels) {
int j = channel >> 5; int j = channel >> 5;
unsigned int mask = (1 << (channel & 0x1f)); unsigned int mask = (1 << (channel & 0x1f));
/* EDMA channels without event association */ /* EDMA channels without event association */
if (test_bit(channel, edma_noevent)) { if (test_bit(channel, edma_noevent)) {
dev_dbg(&edma_dev.dev, "ESR%d %08x\n", j, pr_debug("EDMA: ESR%d %08x\n", j,
edma_shadow0_read_array(SH_ESR, j)); edma_shadow0_read_array(SH_ESR, j));
edma_shadow0_write_array(SH_ESR, j, mask); edma_shadow0_write_array(SH_ESR, j, mask);
return 0; return 0;
} }
/* EDMA channel with event association */ /* EDMA channel with event association */
dev_dbg(&edma_dev.dev, "ER%d %08x\n", j, pr_debug("EDMA: ER%d %08x\n", j,
edma_shadow0_read_array(SH_ER, j)); edma_shadow0_read_array(SH_ER, j));
/* Clear any pending error */ /* Clear any pending error */
edma_write_array(EDMA_EMCR, j, mask); edma_write_array(EDMA_EMCR, j, mask);
/* Clear any SER */ /* Clear any SER */
edma_shadow0_write_array(SH_SECR, j, mask); edma_shadow0_write_array(SH_SECR, j, mask);
edma_shadow0_write_array(SH_EESR, j, mask); edma_shadow0_write_array(SH_EESR, j, mask);
dev_dbg(&edma_dev.dev, "EER%d %08x\n", j, pr_debug("EDMA: EER%d %08x\n", j,
edma_shadow0_read_array(SH_EER, j)); edma_shadow0_read_array(SH_EER, j));
return 0; return 0;
} }
...@@ -1072,7 +938,7 @@ EXPORT_SYMBOL(edma_start); ...@@ -1072,7 +938,7 @@ EXPORT_SYMBOL(edma_start);
*/ */
void edma_stop(unsigned channel) void edma_stop(unsigned channel)
{ {
if (channel < DAVINCI_EDMA_NUM_DMACH) { if (channel < num_channels) {
int j = channel >> 5; int j = channel >> 5;
unsigned int mask = (1 << (channel & 0x1f)); unsigned int mask = (1 << (channel & 0x1f));
...@@ -1081,7 +947,7 @@ void edma_stop(unsigned channel) ...@@ -1081,7 +947,7 @@ void edma_stop(unsigned channel)
edma_shadow0_write_array(SH_SECR, j, mask); edma_shadow0_write_array(SH_SECR, j, mask);
edma_write_array(EDMA_EMCR, j, mask); edma_write_array(EDMA_EMCR, j, mask);
dev_dbg(&edma_dev.dev, "EER%d %08x\n", j, pr_debug("EDMA: EER%d %08x\n", j,
edma_shadow0_read_array(SH_EER, j)); edma_shadow0_read_array(SH_EER, j));
/* REVISIT: consider guarding against inappropriate event /* REVISIT: consider guarding against inappropriate event
...@@ -1106,11 +972,11 @@ EXPORT_SYMBOL(edma_stop); ...@@ -1106,11 +972,11 @@ EXPORT_SYMBOL(edma_stop);
void edma_clean_channel(unsigned channel) void edma_clean_channel(unsigned channel)
{ {
if (channel < DAVINCI_EDMA_NUM_DMACH) { if (channel < num_channels) {
int j = (channel >> 5); int j = (channel >> 5);
unsigned int mask = 1 << (channel & 0x1f); unsigned int mask = 1 << (channel & 0x1f);
dev_dbg(&edma_dev.dev, "EMR%d %08x\n", j, pr_debug("EDMA: EMR%d %08x\n", j,
edma_read_array(EDMA_EMR, j)); edma_read_array(EDMA_EMR, j));
edma_shadow0_write_array(SH_ECR, j, mask); edma_shadow0_write_array(SH_ECR, j, mask);
/* Clear the corresponding EMR bits */ /* Clear the corresponding EMR bits */
...@@ -1121,3 +987,109 @@ void edma_clean_channel(unsigned channel) ...@@ -1121,3 +987,109 @@ void edma_clean_channel(unsigned channel)
} }
} }
EXPORT_SYMBOL(edma_clean_channel); EXPORT_SYMBOL(edma_clean_channel);
/*-----------------------------------------------------------------------*/
static int __init edma_probe(struct platform_device *pdev)
{
struct edma_soc_info *info = pdev->dev.platform_data;
int i;
int status;
const s8 *noevent;
int irq = 0, err_irq = 0;
if (!info)
return -ENODEV;
num_channels = min_t(unsigned, info->n_channel, EDMA_MAX_DMACH);
num_slots = min_t(unsigned, info->n_slot, EDMA_MAX_PARAMENTRY);
dev_dbg(&pdev->dev, "DMA REG BASE ADDR=%p\n", edmacc_regs_base);
for (i = 0; i < num_slots; i++)
memcpy_toio(edmacc_regs_base + PARM_OFFSET(i),
&dummy_paramset, PARM_SIZE);
noevent = info->noevent;
if (noevent) {
while (*noevent != -1)
set_bit(*noevent++, edma_noevent);
}
irq = platform_get_irq(pdev, 0);
status = request_irq(irq, dma_irq_handler, 0, "edma", &pdev->dev);
if (status < 0) {
dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n",
irq, status);
goto fail;
}
err_irq = platform_get_irq(pdev, 1);
status = request_irq(err_irq, dma_ccerr_handler, 0,
"edma_error", &pdev->dev);
if (status < 0) {
dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n",
err_irq, status);
goto fail;
}
if (tc_errs_handled) {
status = request_irq(IRQ_TCERRINT0, dma_tc0err_handler, 0,
"edma_tc0", &pdev->dev);
if (status < 0) {
dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n",
IRQ_TCERRINT0, status);
return status;
}
status = request_irq(IRQ_TCERRINT, dma_tc1err_handler, 0,
"edma_tc1", &pdev->dev);
if (status < 0) {
dev_dbg(&pdev->dev, "request_irq %d --> %d\n",
IRQ_TCERRINT, status);
return status;
}
}
/* Everything lives on transfer controller 1 until otherwise specified.
* This way, long transfers on the low priority queue
* started by the codec engine will not cause audio defects.
*/
for (i = 0; i < num_channels; i++)
map_dmach_queue(i, EVENTQ_1);
/* Event queue to TC mapping */
for (i = 0; queue_tc_mapping[i][0] != -1; i++)
map_queue_tc(queue_tc_mapping[i][0], queue_tc_mapping[i][1]);
/* Event queue priority mapping */
for (i = 0; queue_priority_mapping[i][0] != -1; i++)
assign_priority_to_queue(queue_priority_mapping[i][0],
queue_priority_mapping[i][1]);
for (i = 0; i < info->n_region; i++) {
edma_write_array2(EDMA_DRAE, i, 0, 0x0);
edma_write_array2(EDMA_DRAE, i, 1, 0x0);
edma_write_array(EDMA_QRAE, i, 0x0);
}
return 0;
fail:
if (err_irq)
free_irq(err_irq, NULL);
if (irq)
free_irq(irq, NULL);
return status;
}
static struct platform_driver edma_driver = {
.driver.name = "edma",
};
static int __init edma_init(void)
{
return platform_driver_probe(&edma_driver, edma_probe);
}
arch_initcall(edma_init);
...@@ -91,16 +91,6 @@ struct edmacc_param { ...@@ -91,16 +91,6 @@ struct edmacc_param {
#define TRWORD (0x7<<2) #define TRWORD (0x7<<2)
#define PAENTRY (0x1ff<<5) #define PAENTRY (0x1ff<<5)
#define DAVINCI_EDMA_NUM_DMACH 64
#define DAVINCI_EDMA_NUM_PARAMENTRY 128
#define DAVINCI_EDMA_NUM_EVQUE 2
#define DAVINCI_EDMA_CHMAPEXIST 0
#define DAVINCI_EDMA_NUM_REGIONS 4
#define DAVINCI_EDMA_MEMPROTECT 0
/* Drivers should avoid using these symbolic names for dm644x /* Drivers should avoid using these symbolic names for dm644x
* channels, and use platform_device IORESOURCE_DMA resources * channels, and use platform_device IORESOURCE_DMA resources
* instead. (Other DaVinci chips have different peripherals * instead. (Other DaVinci chips have different peripherals
...@@ -221,4 +211,18 @@ void edma_resume(unsigned channel); ...@@ -221,4 +211,18 @@ void edma_resume(unsigned channel);
/* UNRELATED TO DMA */ /* UNRELATED TO DMA */
int davinci_alloc_iram(unsigned size); int davinci_alloc_iram(unsigned size);
void davinci_free_iram(unsigned addr, unsigned size); void davinci_free_iram(unsigned addr, unsigned size);
/* platform_data for EDMA driver */
struct edma_soc_info {
/* how many dma resources of each type */
unsigned n_channel;
unsigned n_region;
unsigned n_slot;
unsigned n_tc;
/* list of channels with no even trigger; terminated by "-1" */
const s8 *noevent;
};
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment