Convert DMA library into DMA platform driver and make use of platform data provided by HWMOD data base for OMAP2PLUS onwards. For OMAP1 processors, the DMA driver in mach-omap uses resource structures for getting platform data. Signed-off-by: G, Manjunath Kondaiah <manjugk@xxxxxx> Cc: Benoit Cousson <b-cousson@xxxxxx> Cc: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx> Cc: Santosh Shilimkar <santosh.shilimkar@xxxxxx> --- arch/arm/mach-omap1/Makefile | 2 +- arch/arm/mach-omap1/dma.c | 180 ++++++++++++++++++- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/dma.c | 209 +++++++++++++++++++++- arch/arm/mach-omap2/include/mach/dma.h | 3 + arch/arm/plat-omap/dma.c | 321 +++++++++++--------------------- arch/arm/plat-omap/include/plat/dma.h | 50 ++++-- 7 files changed, 538 insertions(+), 229 deletions(-) diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 9a304d8..b7dfc54 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -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 diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c index e756069..38a7294 100644 --- a/arch/arm/mach-omap1/dma.c +++ b/arch/arm/mach-omap1/dma.c @@ -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: diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 7352412..5d250c8 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -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 \ diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c index 30b20cd..5ca519b 100644 --- a/arch/arm/mach-omap2/dma.c +++ b/arch/arm/mach-omap2/dma.c @@ -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; } diff --git a/arch/arm/mach-omap2/include/mach/dma.h b/arch/arm/mach-omap2/include/mach/dma.h index d0a7d5b..d13c5c0 100644 --- a/arch/arm/mach-omap2/include/mach/dma.h +++ b/arch/arm/mach-omap2/include/mach/dma.h @@ -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 */ diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 0ff82d0..d8e9886 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -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@xxxxxx> + * * 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 diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h index 9757b22..e3a927d 100644 --- a/arch/arm/plat-omap/include/plat/dma.h +++ b/arch/arm/plat-omap/include/plat/dma.h @@ -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); -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html