@@ -3,7 +3,7 @@
#
# Common support
-obj-y := io.o id.o sram.o irq.o mux.o flash.o serial.o devices.o
+obj-y := io.o id.o sram.o irq.o mux.o flash.o serial.o devices.o dma.o
obj-y += clock.o clock_data.o opp_data.o
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
@@ -35,6 +35,81 @@
#include <plat/tc.h>
#define OMAP1_DMA_BASE (0xfffed800)
+#define OMAP1_LOGICAL_DMA_CH_COUNT 17
+
+static u32 errata;
+static u32 enable_1510_mode;
+
+enum {
+ GCR1 = 0, GSCR, GRST, HW_ID,
+ PCH2_ID, PCH0_ID, PCH1_ID, PCHG_ID,
+ PCHD_ID, CAPS_0_U, CAPS_0_L, CAPS_1_U,
+ CAPS_1_L, CAPS_2, CAPS_3, CAPS_4,
+ PCH2_SR, PCH0_SR, PCH1_SR, PCHD_SR,
+
+ CH_COMMON_START,
+
+ /* Common Registers */
+ CSDP1, CCR1, CICR1, CSR1,
+ CEN1, CFN1, CSFI1, CSEI1,
+ CPC, CSAC1, CDAC1, CDEI1,
+ CDFI1, CLNK_CTRL1,
+
+ /* Channel specific register offsets */
+ CSSA_L, CSSA_U, CDSA_L, CDSA_U,
+ COLOR_L, COLOR_U, CCR1_2, LCH_CTRL,
+
+ CH_COMMON_END,
+};
+
+static u16 reg_map[] = {
+ [GCR1] = 0x400,
+ [GSCR] = 0x404,
+ [GRST] = 0x408,
+ [HW_ID] = 0x442,
+ [PCH2_ID] = 0x444,
+ [PCH0_ID] = 0x446,
+ [PCH1_ID] = 0x448,
+ [PCHG_ID] = 0x44a,
+ [PCHD_ID] = 0x44c,
+ [CAPS_0_U] = 0x44e,
+ [CAPS_0_L] = 0x450,
+ [CAPS_1_U] = 0x452,
+ [CAPS_1_L] = 0x454,
+ [CAPS_2] = 0x456,
+ [CAPS_3] = 0x458,
+ [CAPS_4] = 0x45a,
+ [PCH2_SR] = 0x460,
+ [PCH0_SR] = 0x480,
+ [PCH1_SR] = 0x482,
+ [PCHD_SR] = 0x4c0,
+
+ /* Common Registers */
+ [CSDP1] = 0x00,
+ [CCR1] = 0x02,
+ [CICR1] = 0x04,
+ [CSR1] = 0x06,
+ [CEN1] = 0x10,
+ [CFN1] = 0x12,
+ [CSFI1] = 0x14,
+ [CSEI1] = 0x16,
+ [CPC] = 0x18, /* 15xx only */
+ [CSAC1] = 0x18,
+ [CDAC1] = 0x1a,
+ [CDEI1] = 0x1c,
+ [CDFI1] = 0x1e,
+ [CLNK_CTRL1] = 0x28,
+
+ /* Channel specific register offsets */
+ [CSSA_L] = 0x08,
+ [CSSA_U] = 0x0a,
+ [CDSA_L] = 0x0c,
+ [CDSA_U] = 0x0e,
+ [COLOR_L] = 0x20,
+ [COLOR_U] = 0x22,
+ [CCR1_2] = 0x24,
+ [LCH_CTRL] = 0x2a,
+};
static struct resource res[] __initdata = {
[0] = {
@@ -130,9 +205,64 @@ static struct resource res[] __initdata = {
},
};
+static void __iomem *dma_base;
+static inline void dma_write(u16 val, int reg, int lch)
+{
+ if (reg > CH_COMMON_START)
+ __raw_writew(val, dma_base + (reg_map[reg] + 0x40 * lch));
+ else
+ __raw_writew(val, dma_base + reg_map[reg]);
+}
+
+static inline u16 dma_read(int reg, int lch)
+{
+ if (reg > CH_COMMON_START)
+ return __raw_readw(dma_base + (reg_map[reg] + 0x40 * lch));
+ else
+ return __raw_readw(dma_base + reg_map[reg]);
+}
+
+static void omap1_show_dma_caps(void)
+{
+ if (enable_1510_mode) {
+ printk(KERN_INFO "DMA support for OMAP15xx initialized\n");
+ } else {
+ u16 w;
+ printk(KERN_INFO "OMAP DMA hardware version %d\n",
+ dma_read(HW_ID, 0));
+ printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
+ (dma_read(CAPS_0_U, 0) << 16) |
+ dma_read(CAPS_0_L, 0),
+ (dma_read(CAPS_1_U, 0) << 16) |
+ dma_read(CAPS_1_L, 0),
+ dma_read(CAPS_2, 0), dma_read(CAPS_3, 0),
+ dma_read(CAPS_4, 0));
+
+ /* Disable OMAP 3.0/3.1 compatibility mode. */
+ w = dma_read(GSCR, 0);
+ w |= 1 << 3;
+ dma_write(w, GSCR, 0);
+ }
+ return;
+}
+
+static u32 configure_dma_errata(void)
+{
+
+ /*
+ * Errata 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is
+ * read before the DMA controller finished disabling the channel.
+ */
+ if (!cpu_is_omap15xx())
+ SET_DMA_ERRATA(DMA_ERRATA_3_3);
+
+ return errata;
+}
+
static int __init omap1_system_dma_init(void)
{
struct omap_system_dma_plat_info *p;
+ struct omap_dma_dev_attr *d;
struct platform_device *pdev;
int ret;
@@ -158,20 +288,66 @@ static int __init omap1_system_dma_init(void)
goto exit_device_put;
}
+ d = p->dma_attr;
+ d->chan = kzalloc(sizeof(struct omap_dma_lch) *
+ (d->lch_count), GFP_KERNEL);
+ if (!d->chan) {
+ dev_err(&pdev->dev, "%s: Memory allocation failed"
+ "for d->chan!!!\n", __func__);
+ goto exit_release_p;
+ }
+
+ /* Valid attributes for omap1 plus processors */
+ if (cpu_is_omap15xx())
+ d->dev_caps = ENABLE_1510_MODE;
+ enable_1510_mode = d->dev_caps & ENABLE_1510_MODE;
+
+ d->dev_caps |= SRC_PORT;
+ d->dev_caps |= DST_PORT;
+ d->dev_caps |= SRC_INDEX;
+ d->dev_caps |= DST_INDEX;
+ d->dev_caps |= IS_BURST_ONLY4;
+ d->dev_caps |= CLEAR_CSR_ON_READ;
+ d->dev_caps |= IS_WORD_16;
+
+ d->lch_count = OMAP1_LOGICAL_DMA_CH_COUNT;
+
+ if (cpu_is_omap15xx())
+ d->chan_count = 9;
+ else if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
+ if (!(d->dev_caps & ENABLE_1510_MODE))
+ d->chan_count = 16;
+ else
+ d->chan_count = 9;
+ }
+
+ p->omap_dma_base = (void __iomem *)res[0].start;
+ dma_base = p->omap_dma_base;
+
+ p->show_dma_caps = omap1_show_dma_caps;
+ p->disable_irq_lch = NULL;
+
+ /* Configure errata handling for all omap1+ */
+ p->errata = configure_dma_errata();
+
ret = platform_device_add_data(pdev, p, sizeof(*p));
if (ret) {
dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
__func__, pdev->name, pdev->id);
- goto exit_device_put;
+ goto exit_release_chan;
}
ret = platform_device_add(pdev);
if (ret) {
dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
__func__, pdev->name, pdev->id);
- goto exit_device_put;
+ goto exit_release_chan;
}
return ret;
+exit_release_chan:
+ kfree(d->chan);
+exit_release_p:
+ kfree(p);
exit_device_put:
platform_device_put(pdev);
exit_device_del:
@@ -4,7 +4,7 @@
# Common support
obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o \
- common.o
+ common.o dma.o
omap-2-3-common = irq.o sdrc.o prm2xxx_3xxx.o
hwmod-common = omap_hwmod.o \
@@ -39,6 +39,79 @@
#include <plat/omap_device.h>
#include <plat/dma.h>
+static u32 errata;
+static struct omap_dma_dev_attr *d;
+
+enum {
+ REVISION = 0, GCR2, IRQSTATUS_L0, IRQSTATUS_L1,
+ IRQSTATUS_L2, IRQSTATUS_L3, IRQENABLE_L0, IRQENABLE_L1,
+ IRQENABLE_L2, IRQENABLE_L3, SYSSTATUS, OCP_SYSCONFIG,
+ CAPS_0, CAPS_2, CAPS_3, CAPS_4,
+
+ CH_COMMON_START,
+
+ /* Common register offsets */
+ CCR2, CLNK_CTRL2, CICR2, CSR2,
+ CSDP2, CEN2, CFN2, CSEI2,
+ CSFI2, CDEI2, CDFI2, CSAC2,
+ CDAC2,
+
+ /* Channel specific register offsets */
+ CSSA, CDSA, CCEN, CCFN,
+ COLOR,
+
+ /* OMAP4 specific registers */
+ CDP, CNDP, CCDN,
+
+ CH_COMMON_END,
+};
+
+static u16 reg_map[] = {
+ [REVISION] = 0x00,
+ [GCR2] = 0x78,
+ [IRQSTATUS_L0] = 0x08,
+ [IRQSTATUS_L1] = 0x0c,
+ [IRQSTATUS_L2] = 0x10,
+ [IRQSTATUS_L3] = 0x14,
+ [IRQENABLE_L0] = 0x18,
+ [IRQENABLE_L1] = 0x1c,
+ [IRQENABLE_L2] = 0x20,
+ [IRQENABLE_L3] = 0x24,
+ [SYSSTATUS] = 0x28,
+ [OCP_SYSCONFIG] = 0x2c,
+ [CAPS_0] = 0x64,
+ [CAPS_2] = 0x6c,
+ [CAPS_3] = 0x70,
+ [CAPS_4] = 0x74,
+
+ /* Common register offsets */
+ [CCR2] = 0x80,
+ [CLNK_CTRL2] = 0x84,
+ [CICR2] = 0x88,
+ [CSR2] = 0x8c,
+ [CSDP2] = 0x90,
+ [CEN2] = 0x94,
+ [CFN2] = 0x98,
+ [CSEI2] = 0xa4,
+ [CSFI2] = 0xa8,
+ [CDEI2] = 0xac,
+ [CDFI2] = 0xb0,
+ [CSAC2] = 0xb4,
+ [CDAC2] = 0xb8,
+
+ /* Channel specific register offsets */
+ [CSSA] = 0x9c,
+ [CDSA] = 0xa0,
+ [CCEN] = 0xbc,
+ [CCFN] = 0xc0,
+ [COLOR] = 0xc4,
+
+ /* OMAP4 specific registers */
+ [CDP] = 0xd0,
+ [CNDP] = 0xd4,
+ [CCDN] = 0xd8,
+};
+
static struct omap_device_pm_latency omap2_dma_latency[] = {
{
.deactivate_func = omap_device_idle_hwmods,
@@ -47,12 +120,118 @@ static struct omap_device_pm_latency omap2_dma_latency[] = {
},
};
+static void __iomem *dma_base;
+static inline void dma_write(u32 val, int reg, int lch)
+{
+ if (reg > CH_COMMON_START)
+ __raw_writel(val, dma_base + (reg_map[reg] + 0x60 * lch));
+ else
+ __raw_writel(val, dma_base + reg_map[reg]);
+}
+
+static inline u32 dma_read(int reg, int lch)
+{
+ if (reg > CH_COMMON_START)
+ return __raw_readl(dma_base + (reg_map[reg] + 0x60 * lch));
+ else
+ return __raw_readl(dma_base + reg_map[reg]);
+}
+
+static inline void disable_irq_lch(int lch)
+{
+ u32 val;
+
+ val = dma_read(IRQENABLE_L0, lch);
+ val &= ~(1 << lch);
+ dma_write(val, IRQENABLE_L0, lch);
+}
+
+static void omap2_show_dma_caps(void)
+{
+ u8 revision = dma_read(REVISION, 0) & 0xff;
+ printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n",
+ revision >> 4, revision & 0xf);
+ return;
+}
+
+static u32 configure_dma_errata(void)
+{
+
+ /*
+ * Erratas applicable for OMAP2430ES1.0 and all omap2420
+ *
+ * I.
+ * Errata ID: XX Inter Frame DMA buffering issue DMA will wrongly
+ * buffer elements if packing and bursting is enabled. This might
+ * result in data gets stalled in FIFO at the end of the block.
+ * Workaround: DMA channels must have BUFFERING_DISABLED bit set to
+ * guarantee no data will stay in the DMA FIFO in case inter frame
+ * buffering occurs
+ *
+ * II.
+ * Errata ID: XX DMA may hang when several channels are used in parallel
+ * In the following configuration, DMA channel hanging can occur:
+ * a. Channel i, hardware synchronized, is enabled
+ * b. Another channel (Channel x), software synchronized, is enabled.
+ * c. Channel i is disabled before end of transfer
+ * d. Channel i is reenabled.
+ * e. Steps 1 to 4 are repeated a certain number of times.
+ * f. A third channel (Channel y), software synchronized, is enabled.
+ * Channel x and Channel y may hang immediately after step 'f'.
+ * Workaround:
+ * For any channel used - make sure NextLCH_ID is set to the value j.
+ */
+ if (cpu_is_omap2420() || (cpu_is_omap2430() &&
+ (omap_type() == OMAP2430_REV_ES1_0))) {
+
+ SET_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING);
+ SET_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS);
+ }
+
+ /*
+ * Errata ID: i378: OMAP2plus: sDMA Channel is not disabled
+ * after a transaction error.
+ * Workaround: SW should explicitely disable the channel.
+ */
+ if (cpu_class_is_omap2())
+ SET_DMA_ERRATA(DMA_ERRATA_i378);
+
+ /*
+ * Errata ID: i541: sDMA FIFO draining does not finish
+ * If sDMA channel is disabled on the fly, sDMA enters standby even
+ * through FIFO Drain is still in progress
+ * Workaround: Put sDMA in NoStandby more before a logical channel is
+ * disabled, then put it back to SmartStandby right after the channel
+ * finishes FIFO draining.
+ */
+ if (cpu_is_omap34xx())
+ SET_DMA_ERRATA(DMA_ERRATA_i541);
+
+ /*
+ * Errata ID: i88 : Special programming model needed to disable DMA
+ * before end of block.
+ * Workaround: software must ensure that the DMA is configured in No
+ * Standby mode(DMAx_OCP_SYSCONFIG.MIDLEMODE = "01")
+ */
+ if (omap_type() == OMAP3430_REV_ES1_0)
+ SET_DMA_ERRATA(DMA_ERRATA_i88);
+
+ /*
+ * Errata 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is
+ * read before the DMA controller finished disabling the channel.
+ */
+ SET_DMA_ERRATA(DMA_ERRATA_3_3);
+
+ return errata;
+}
+
/* One time initializations */
static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
{
struct omap_device *od;
struct omap_system_dma_plat_info *p;
- char *name = "omap_system_dma";
+ struct resource *mem;
+ char *name = "omap_dma_system";
p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL);
if (!p) {
@@ -60,6 +239,14 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
__func__, name, oh->name);
return -ENOMEM;
}
+ p->regs = reg_map;
+ p->dma_attr = (struct omap_dma_dev_attr *)oh->dev_attr;
+ p->disable_irq_lch = disable_irq_lch;
+ p->show_dma_caps = omap2_show_dma_caps;
+
+ /* Configure errata handling for all omap2+'s */
+ p->errata = configure_dma_errata();
+
od = omap_device_build(name, 0, oh, p, sizeof(*p),
omap2_dma_latency, ARRAY_SIZE(omap2_dma_latency), 0);
@@ -71,6 +258,26 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
}
kfree(p);
+ mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&od->pdev.dev, "%s: no mem resource\n", __func__);
+ return -EINVAL;
+ }
+
+ dma_base = ioremap(mem->start, resource_size(mem));
+ if (!dma_base) {
+ dev_err(&od->pdev.dev, "%s: ioremap fail\n", __func__);
+ return -ENOMEM;
+ }
+
+ d = oh->dev_attr;
+ d->chan = kzalloc(sizeof(struct omap_dma_lch) *
+ (d->lch_count), GFP_KERNEL);
+
+ if (!d->chan) {
+ dev_err(&od->pdev.dev, "%s: kzalloc fail\n", __func__);
+ return -ENOMEM;
+ }
return 0;
}
@@ -29,4 +29,7 @@
#ifndef __ASM_ARCH_OMAP2_DMA_H
#define __ASM_ARCH_OMAP2_DMA_H
+/* Should be part of hwmod data base ? */
+#define OMAP_DMA4_LOGICAL_DMA_CH_COUNT 32 /* REVISIT: Is this 32 + 2? */
+
#endif /* __ASM_ARCH_OMAP2_DMA_H */
@@ -15,6 +15,10 @@
*
* Support functions for the OMAP internal DMA channels.
*
+ * Copyright (C) 2010 Texas Instruments
+ * Converted DMA library into DMA platform driver.
+ * - G, Manjunath Kondaiah <manjugk@ti.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -194,6 +198,9 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED };
#define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec)
+static struct omap_system_dma_plat_info *p;
+static struct omap_dma_dev_attr *d;
+static u16 *reg_map;
static int enable_1510_mode;
static u32 errata;
@@ -203,27 +210,6 @@ static struct omap_dma_global_context_registers {
u32 dma_gcr;
} omap_dma_global_context;
-struct omap_dma_lch {
- int next_lch;
- int dev_id;
- u16 saved_csr;
- u16 enabled_irqs;
- const char *dev_name;
- void (*callback)(int lch, u16 ch_status, void *data);
- void *data;
-
-#ifndef CONFIG_ARCH_OMAP1
- /* required for Dynamic chaining */
- int prev_linked_ch;
- int next_linked_ch;
- int state;
- int chain_id;
-
- int status;
-#endif
- long flags;
-};
-
struct dma_link_info {
int *linked_dmach_q;
int no_of_lchs_linked;
@@ -280,15 +266,6 @@ static int omap_dma_reserve_channels;
static spinlock_t dma_chan_lock;
static struct omap_dma_lch *dma_chan;
static void __iomem *dma_base;
-
-static const u8 omap1_dma_irq[OMAP1_LOGICAL_DMA_CH_COUNT] = {
- INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3,
- INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7,
- INT_1610_DMA_CH8, INT_1610_DMA_CH9, INT_1610_DMA_CH10,
- INT_1610_DMA_CH11, INT_1610_DMA_CH12, INT_1610_DMA_CH13,
- INT_1610_DMA_CH14, INT_1610_DMA_CH15, INT_DMA_LCD
-};
-
static inline void disable_lnk(int lch);
static void omap_disable_channel_irq(int lch);
static inline void omap_enable_channel_irq(int lch);
@@ -1195,7 +1172,7 @@ void omap_start_dma(int lch)
if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
int next_lch, cur_lch;
- char dma_chan_link_map[OMAP_DMA4_LOGICAL_DMA_CH_COUNT];
+ char dma_chan_link_map[dma_chan_count];
dma_chan_link_map[lch] = 1;
/* Set the link register of the first channel */
@@ -1288,7 +1265,7 @@ void omap_stop_dma(int lch)
if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
int next_lch, cur_lch = lch;
- char dma_chan_link_map[OMAP_DMA4_LOGICAL_DMA_CH_COUNT];
+ char dma_chan_link_map[dma_chan_count];
memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
do {
@@ -1494,8 +1471,6 @@ void omap_dma_unlink_lch(int lch_head, int lch_queue)
}
EXPORT_SYMBOL(omap_dma_unlink_lch);
-/*----------------------------------------------------------------------------*/
-
#ifndef CONFIG_ARCH_OMAP1
/* Create chain of DMA channesls */
static void create_dma_lch_chain(int lch_head, int lch_queue)
@@ -2309,159 +2284,59 @@ void omap_dma_global_context_restore(void)
omap_clear_dma(ch);
}
-static void configure_dma_errata(void)
+static int __devinit omap_system_dma_probe(struct platform_device *pdev)
{
-
- /*
- * Erratas applicable for OMAP2430ES1.0 and all omap2420
- *
- * I.
- * Errata ID: XX Inter Frame DMA buffering issue DMA will wrongly
- * buffer elements if packing and bursting is enabled. This might
- * result in data gets stalled in FIFO at the end of the block.
- * Workaround: DMA channels must have BUFFERING_DISABLED bit set to
- * guarantee no data will stay in the DMA FIFO in case inter frame
- * buffering occurs
- *
- * II.
- * Errata ID: XX DMA may hang when several channels are used in parallel
- * In the following configuration, DMA channel hanging can occur:
- * a. Channel i, hardware synchronized, is enabled
- * b. Another channel (Channel x), software synchronized, is enabled.
- * c. Channel i is disabled before end of transfer
- * d. Channel i is reenabled.
- * e. Steps 1 to 4 are repeated a certain number of times.
- * f. A third channel (Channel y), software synchronized, is enabled.
- * Channel x and Channel y may hang immediately after step 'f'.
- * Workaround:
- * For any channel used - make sure NextLCH_ID is set to the value j.
- */
- if (cpu_is_omap2420() || (cpu_is_omap2430() &&
- (omap_type() == OMAP2430_REV_ES1_0))) {
-
- SET_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING);
- SET_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS);
+ struct omap_system_dma_plat_info *pdata = pdev->dev.platform_data;
+ struct resource *mem;
+ int ch, ret = 0;
+ int dma_irq;
+ char irq_name[4];
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s: System DMA initialized without"
+ "platform data\n", __func__);
+ return -EINVAL;
}
- /*
- * Errata ID: i378: OMAP2plus: sDMA Channel is not disabled
- * after a transaction error.
- * Workaround: SW should explicitely disable the channel.
- */
- if (cpu_class_is_omap2())
- SET_DMA_ERRATA(DMA_ERRATA_i378);
-
- /*
- * Errata ID: i541: sDMA FIFO draining does not finish
- * If sDMA channel is disabled on the fly, sDMA enters standby even
- * through FIFO Drain is still in progress
- * Workaround: Put sDMA in NoStandby more before a logical channel is
- * disabled, then put it back to SmartStandby right after the channel
- * finishes FIFO draining.
- */
- if (cpu_is_omap34xx())
- SET_DMA_ERRATA(DMA_ERRATA_i541);
-
- /*
- * Errata ID: i88 : Special programming model needed to disable DMA
- * before end of block.
- * Workaround: software must ensure that the DMA is configured in No
- * Standby mode(DMAx_OCP_SYSCONFIG.MIDLEMODE = "01")
- */
- if (omap_type() == OMAP3430_REV_ES1_0)
- SET_DMA_ERRATA(DMA_ERRATA_i88);
-
- /*
- * Errata 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is
- * read before the DMA controller finished disabling the channel.
- */
- if (!cpu_is_omap15xx())
- SET_DMA_ERRATA(DMA_ERRATA_3_3);
-}
+ p = pdata;
+ d = p->dma_attr;
+ reg_map = pdata->regs;
+ errata = p->errata;
-/*----------------------------------------------------------------------------*/
-
-static int __init omap_init_dma(void)
-{
- unsigned long base;
- int ch, r;
-
- if (cpu_class_is_omap1()) {
- base = OMAP1_DMA_BASE;
- dma_lch_count = OMAP1_LOGICAL_DMA_CH_COUNT;
- } else if (cpu_is_omap24xx()) {
- base = OMAP24XX_DMA4_BASE;
- dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
- } else if (cpu_is_omap34xx()) {
- base = OMAP34XX_DMA4_BASE;
- dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
- } else if (cpu_is_omap44xx()) {
- base = OMAP44XX_DMA4_BASE;
- dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
- } else {
- pr_err("DMA init failed for unsupported omap\n");
- return -ENODEV;
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
+ return -EINVAL;
}
- dma_base = ioremap(base, SZ_4K);
- BUG_ON(!dma_base);
+ dma_base = ioremap(mem->start, resource_size(mem));
+ if (!dma_base) {
+ dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
+ ret = -ENOMEM;
+ goto exit_release_region;
+ }
if (cpu_class_is_omap2() && omap_dma_reserve_channels
&& (omap_dma_reserve_channels <= dma_lch_count))
- dma_lch_count = omap_dma_reserve_channels;
+ d->lch_count = omap_dma_reserve_channels;
- dma_chan = kzalloc(sizeof(struct omap_dma_lch) * dma_lch_count,
- GFP_KERNEL);
- if (!dma_chan) {
- r = -ENOMEM;
- goto out_unmap;
- }
+ dma_lch_count = d->lch_count;
+ dma_chan_count = dma_lch_count;
+ dma_chan = d->chan;
if (cpu_class_is_omap2()) {
dma_linked_lch = kzalloc(sizeof(struct dma_link_info) *
dma_lch_count, GFP_KERNEL);
if (!dma_linked_lch) {
- r = -ENOMEM;
- goto out_free;
+ ret = -ENOMEM;
+ goto exit_dma_chan;
}
}
+ enable_1510_mode = d->dev_caps & ENABLE_1510_MODE;
- if (cpu_is_omap15xx()) {
- printk(KERN_INFO "DMA support for OMAP15xx initialized\n");
- dma_chan_count = 9;
- enable_1510_mode = 1;
- } else if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
- printk(KERN_INFO "OMAP DMA hardware version %d\n",
- dma_read(HW_ID, 0));
- printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
- (dma_read(CAPS1_0_U, 0) << 16) |
- dma_read(CAPS1_0_L, 0),
- (dma_read(CAPS1_1_U, 0) << 16) |
- dma_read(CAPS1_1_L, 0),
- dma_read(CAPS1_2, 0), dma_read(CAPS1_3, 0),
- dma_read(CAPS1_4, 0));
- if (!enable_1510_mode) {
- u16 w;
-
- /* Disable OMAP 3.0/3.1 compatibility mode. */
- w = dma_read(GSCR, 0);
- w |= 1 << 3;
- dma_write(w, GSCR, 0);
- dma_chan_count = 16;
- } else
- dma_chan_count = 9;
- } else if (cpu_class_is_omap2()) {
- u8 revision = dma_read(REVISION, 0) & 0xff;
- printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n",
- revision >> 4, revision & 0xf);
- dma_chan_count = dma_lch_count;
- } else {
- dma_chan_count = 0;
- return 0;
- }
+ p->show_dma_caps();
spin_lock_init(&dma_chan_lock);
-
for (ch = 0; ch < dma_chan_count; ch++) {
omap_clear_dma(ch);
if (cpu_class_is_omap2())
@@ -2478,19 +2353,30 @@ static int __init omap_init_dma(void)
* request_irq() doesn't like dev_id (ie. ch) being
* zero, so we have to kludge around this.
*/
- r = request_irq(omap1_dma_irq[ch],
+ sprintf(&irq_name[0], "%d", ch);
+ dma_irq = platform_get_irq_byname(pdev, irq_name);
+
+ if (dma_irq < 0) {
+ dev_err(&pdev->dev, "%s:unable to get irq\n",
+ __func__);
+ ret = dma_irq;
+ goto exit_unmap;
+ }
+ ret = request_irq(dma_irq,
omap1_dma_irq_handler, 0, "DMA",
(void *) (ch + 1));
- if (r != 0) {
- int i;
-
- printk(KERN_ERR "unable to request IRQ %d "
- "for DMA (error %d)\n",
- omap1_dma_irq[ch], r);
- for (i = 0; i < ch; i++)
- free_irq(omap1_dma_irq[i],
- (void *) (i + 1));
- goto out_free;
+ if (ret != 0) {
+ int irq_rel;
+ dev_err(&pdev->dev, "unable to request IRQ %d"
+ "for DMA (error %d)\n", dma_irq, ret);
+ for (irq_rel = 0; irq_rel < ch;
+ irq_rel++) {
+ dma_irq = platform_get_irq(pdev,
+ irq_rel);
+ free_irq(dma_irq, (void *)
+ (irq_rel + 1));
+ goto exit_dma_chan;
+ }
}
}
}
@@ -2500,49 +2386,62 @@ static int __init omap_init_dma(void)
DMA_DEFAULT_FIFO_DEPTH, 0);
if (cpu_class_is_omap2()) {
- int irq;
- if (cpu_is_omap44xx())
- irq = OMAP44XX_IRQ_SDMA_0;
- else
- irq = INT_24XX_SDMA_IRQ0;
- setup_irq(irq, &omap24xx_dma_irq);
- }
-
- if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
- /* Enable smartidle idlemodes and autoidle */
- u32 v = dma_read(OCP_SYSCONFIG, 0);
- v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK |
- DMA_SYSCONFIG_SIDLEMODE_MASK |
- DMA_SYSCONFIG_AUTOIDLE);
- v |= (DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
- DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
- DMA_SYSCONFIG_AUTOIDLE);
- dma_write(v , OCP_SYSCONFIG, 0);
- /* reserve dma channels 0 and 1 in high security devices */
- if (cpu_is_omap34xx() &&
- (omap_type() != OMAP2_DEVICE_TYPE_GP)) {
- printk(KERN_INFO "Reserving DMA channels 0 and 1 for "
- "HS ROM code\n");
- dma_chan[0].dev_id = 0;
- dma_chan[1].dev_id = 1;
- }
+ strcpy(irq_name, "0");
+ dma_irq = platform_get_irq_byname(pdev, irq_name);
+ setup_irq(dma_irq, &omap24xx_dma_irq);
}
- /* Configure errata handling for all omap's */
- configure_dma_errata();
-
+ /* reserve dma channels 0 and 1 in high security devices */
+ if (cpu_is_omap34xx() &&
+ (omap_type() != OMAP2_DEVICE_TYPE_GP)) {
+ printk(KERN_INFO "Reserving DMA channels 0 and 1 for "
+ "HS ROM code\n");
+ dma_chan[0].dev_id = 0;
+ dma_chan[1].dev_id = 1;
+ }
return 0;
-out_free:
+exit_dma_chan:
kfree(dma_chan);
+exit_unmap:
+ iounmap(dma_base);
+exit_release_region:
+ release_mem_region(mem->start, resource_size(mem));
+ return ret;
+}
-out_unmap:
+static int __devexit omap_system_dma_remove(struct platform_device *pdev)
+{
+ struct resource *mem;
iounmap(dma_base);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ return 0;
+}
+
+static struct platform_driver omap_system_dma_driver = {
+ .probe = omap_system_dma_probe,
+ .remove = omap_system_dma_remove,
+ .driver = {
+ .name = "omap_dma_system"
+ },
+};
- return r;
+static int __init omap_system_dma_init(void)
+{
+ return platform_driver_register(&omap_system_dma_driver);
+}
+arch_initcall(omap_system_dma_init);
+
+static void __exit omap_system_dma_exit(void)
+{
+ platform_driver_unregister(&omap_system_dma_driver);
}
-arch_initcall(omap_init_dma);
+MODULE_DESCRIPTION("OMAP SYSTEM DMA DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
/*
* Reserve the omap SDMA channels using cmdline bootarg
@@ -21,21 +21,15 @@
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H
-/* Move omap4 specific defines to dma-44xx.h */
-#include "dma-44xx.h"
-
-/* Hardware registers for omap1 */
-#define OMAP1_DMA_BASE (0xfffed800)
-
-/* Hardware registers for omap2 and omap3 */
-#define OMAP24XX_DMA4_BASE (L4_24XX_BASE + 0x56000)
-#define OMAP34XX_DMA4_BASE (L4_34XX_BASE + 0x56000)
-#define OMAP44XX_DMA4_BASE (L4_44XX_BASE + 0x56000)
+#include <linux/platform_device.h>
-#define OMAP1_LOGICAL_DMA_CH_COUNT 17
-#define OMAP_DMA4_LOGICAL_DMA_CH_COUNT 32 /* REVISIT: Is this 32 + 2? */
+/*
+ * TODO: These dma channel defines should go away once all
+ * the omap drivers hwmod adapted.
+ */
-/*----------------------------------------------------------------------------*/
+/* Move omap4 specific defines to dma-44xx.h */
+#include "dma-44xx.h"
/* DMA channels for omap1 */
#define OMAP_DMA_NO_DEVICE 0
@@ -377,9 +371,39 @@ struct omap_dma_channel_params {
#endif
};
+#include <mach/dma.h>
+struct omap_dma_lch {
+ int next_lch;
+ int dev_id;
+ u16 saved_csr;
+ u16 enabled_irqs;
+ const char *dev_name;
+ void (*callback)(int lch, u16 ch_status, void *data);
+ void *data;
+ long flags;
+ /* required for Dynamic chaining */
+ int prev_linked_ch;
+ int next_linked_ch;
+ int state;
+ int chain_id;
+ int status;
+};
+
struct omap_dma_dev_attr {
u32 dev_caps;
u16 lch_count;
+ u16 chan_count;
+ struct omap_dma_lch *chan;
+};
+
+/* System DMA platform data structure */
+struct omap_system_dma_plat_info {
+ struct omap_dma_dev_attr *dma_attr;
+ void __iomem *omap_dma_base;
+ u32 errata;
+ u16 *regs;
+ void (*disable_irq_lch)(int lch);
+ void (*show_dma_caps)(void);
};
extern void omap_set_dma_priority(int lch, int dst_port, int priority);