diff options
27 files changed, 4295 insertions, 1814 deletions
diff --git a/arch/sh/include/asm/siu.h b/arch/sh/include/asm/siu.h index 1d95c78808d1..580b7ac228b7 100644 --- a/arch/sh/include/asm/siu.h +++ b/arch/sh/include/asm/siu.h @@ -14,7 +14,6 @@ struct device; struct siu_platform { - struct device *dma_dev; unsigned int dma_slave_tx_a; unsigned int dma_slave_rx_a; unsigned int dma_slave_tx_b; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index 0f5a21907da6..65786c7f5ded 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -512,7 +512,6 @@ static struct platform_device tmu2_device = { }; static struct siu_platform siu_platform_data = { - .dma_dev = &dma_device.dev, .dma_slave_tx_a = SHDMA_SLAVE_SIUA_TX, .dma_slave_rx_a = SHDMA_SLAVE_SIUA_RX, .dma_slave_tx_b = SHDMA_SLAVE_SIUB_TX, diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index aadeb5be9dba..d45cf1bcbde5 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -148,6 +148,20 @@ config TXX9_DMAC Support the TXx9 SoC internal DMA controller. This can be integrated in chips such as the Toshiba TX4927/38/39. +config TEGRA20_APB_DMA + bool "NVIDIA Tegra20 APB DMA support" + depends on ARCH_TEGRA + select DMA_ENGINE + help + Support for the NVIDIA Tegra20 APB DMA controller driver. The + DMA controller is having multiple DMA channel which can be + configured for different peripherals like audio, UART, SPI, + I2C etc which is in APB bus. + This DMA controller transfers data from memory to peripheral fifo + or vice versa. It does not support memory to memory data transfer. + + + config SH_DMAE tristate "Renesas SuperH DMAC support" depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE) @@ -237,7 +251,7 @@ config IMX_DMA config MXS_DMA bool "MXS DMA support" - depends on SOC_IMX23 || SOC_IMX28 + depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q select STMP_DEVICE select DMA_ENGINE help @@ -260,6 +274,16 @@ config DMA_SA11X0 SA-1110 SoCs. This DMA engine can only be used with on-chip devices. +config MMP_TDMA + bool "MMP Two-Channel DMA support" + depends on ARCH_MMP + select DMA_ENGINE + help + Support the MMP Two-Channel DMA engine. + This engine used for MMP Audio DMA and pxa910 SQU. + + Say Y here if you enabled MMP ADMA, otherwise say N. + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 86b795baba98..640356add0a3 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_DW_DMAC) += dw_dmac.o obj-$(CONFIG_AT_HDMAC) += at_hdmac.o obj-$(CONFIG_MX3_IPU) += ipu/ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o -obj-$(CONFIG_SH_DMAE) += shdma.o +obj-$(CONFIG_SH_DMAE) += sh/ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/ obj-$(CONFIG_IMX_SDMA) += imx-sdma.o @@ -23,8 +23,10 @@ obj-$(CONFIG_MXS_DMA) += mxs-dma.o obj-$(CONFIG_TIMB_DMA) += timb_dma.o obj-$(CONFIG_SIRF_DMA) += sirf-dma.o obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o +obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o obj-$(CONFIG_PL330_DMA) += pl330.o obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o +obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 7292aa87b2dd..3934fcc4e00b 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -9,10 +9,9 @@ * (at your option) any later version. * * - * This supports the Atmel AHB DMA Controller, - * - * The driver has currently been tested with the Atmel AT91SAM9RL - * and AT91SAM9G45 series. + * This supports the Atmel AHB DMA Controller found in several Atmel SoCs. + * The only Atmel DMA Controller that is not covered by this driver is the one + * found on AT91SAM9263. */ #include <linux/clk.h> @@ -1217,7 +1216,7 @@ static const struct platform_device_id atdma_devtypes[] = { } }; -static inline struct at_dma_platform_data * __init at_dma_get_driver_data( +static inline const struct at_dma_platform_data * __init at_dma_get_driver_data( struct platform_device *pdev) { if (pdev->dev.of_node) { @@ -1255,7 +1254,7 @@ static int __init at_dma_probe(struct platform_device *pdev) int irq; int err; int i; - struct at_dma_platform_data *plat_dat; + const struct at_dma_platform_data *plat_dat; /* setup platform data for each SoC */ dma_cap_set(DMA_MEMCPY, at91sam9rl_config.cap_mask); diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index e67b4e06a918..aa384e53b7ac 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -1438,34 +1438,32 @@ static int __init coh901318_probe(struct platform_device *pdev) io = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!io) - goto err_get_resource; + return -ENODEV; /* Map DMA controller registers to virtual memory */ - if (request_mem_region(io->start, - resource_size(io), - pdev->dev.driver->name) == NULL) { - err = -EBUSY; - goto err_request_mem; - } + if (devm_request_mem_region(&pdev->dev, + io->start, + resource_size(io), + pdev->dev.driver->name) == NULL) + return -ENOMEM; pdata = pdev->dev.platform_data; if (!pdata) - goto err_no_platformdata; + return -ENODEV; - base = kmalloc(ALIGN(sizeof(struct coh901318_base), 4) + - pdata->max_channels * - sizeof(struct coh901318_chan), - GFP_KERNEL); + base = devm_kzalloc(&pdev->dev, + ALIGN(sizeof(struct coh901318_base), 4) + + pdata->max_channels * + sizeof(struct coh901318_chan), + GFP_KERNEL); if (!base) - goto err_alloc_coh_dma_channels; + return -ENOMEM; base->chans = ((void *)base) + ALIGN(sizeof(struct coh901318_base), 4); - base->virtbase = ioremap(io->start, resource_size(io)); - if (!base->virtbase) { - err = -ENOMEM; - goto err_no_ioremap; - } + base->virtbase = devm_ioremap(&pdev->dev, io->start, resource_size(io)); + if (!base->virtbase) + return -ENOMEM; base->dev = &pdev->dev; base->platform = pdata; @@ -1474,25 +1472,20 @@ static int __init coh901318_probe(struct platform_device *pdev) COH901318_DEBUGFS_ASSIGN(debugfs_dma_base, base); - platform_set_drvdata(pdev, base); - irq = platform_get_irq(pdev, 0); if (irq < 0) - goto err_no_irq; - - err = request_irq(irq, dma_irq_handler, IRQF_DISABLED, - "coh901318", base); - if (err) { - dev_crit(&pdev->dev, - "Cannot allocate IRQ for DMA controller!\n"); - goto err_request_irq; - } + return irq; + + err = devm_request_irq(&pdev->dev, irq, dma_irq_handler, IRQF_DISABLED, + "coh901318", base); + if (err) + return err; err = coh901318_pool_create(&base->pool, &pdev->dev, sizeof(struct coh901318_lli), 32); if (err) - goto err_pool_create; + return err; /* init channels for device transfers */ coh901318_base_init(&base->dma_slave, base->platform->chans_slave, @@ -1538,6 +1531,7 @@ static int __init coh901318_probe(struct platform_device *pdev) if (err) goto err_register_memcpy; + platform_set_drvdata(pdev, base); dev_info(&pdev->dev, "Initialized COH901318 DMA on virtual base 0x%08x\n", (u32) base->virtbase); @@ -1547,19 +1541,6 @@ static int __init coh901318_probe(struct platform_device *pdev) dma_async_device_unregister(&base->dma_slave); err_register_slave: coh901318_pool_destroy(&base->pool); - err_pool_create: - free_irq(platform_get_irq(pdev, 0), base); - err_request_irq: - err_no_irq: - iounmap(base->virtbase); - err_no_ioremap: - kfree(base); - err_alloc_coh_dma_channels: - err_no_platformdata: - release_mem_region(pdev->resource->start, - resource_size(pdev->resource)); - err_request_mem: - err_get_resource: return err; } @@ -1570,11 +1551,6 @@ static int __exit coh901318_remove(struct platform_device *pdev) dma_async_device_unregister(&base->dma_memcpy); dma_async_device_unregister(&base->dma_slave); coh901318_pool_destroy(&base->pool); - free_irq(platform_get_irq(pdev, 0), base); - iounmap(base->virtbase); - kfree(base); - release_mem_region(pdev->resource->start, - resource_size(pdev->resource)); return 0; } diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 2397f6f451b1..3491654cdf7b 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -45,6 +45,8 @@ * See Documentation/dmaengine.txt for more details */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/dma-mapping.h> #include <linux/init.h> #include <linux/module.h> @@ -261,7 +263,7 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) do { status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); if (time_after_eq(jiffies, dma_sync_wait_timeout)) { - printk(KERN_ERR "dma_sync_wait_timeout!\n"); + pr_err("%s: timeout!\n", __func__); return DMA_ERROR; } } while (status == DMA_IN_PROGRESS); @@ -312,7 +314,7 @@ static int __init dma_channel_table_init(void) } if (err) { - pr_err("dmaengine: initialization failure\n"); + pr_err("initialization failure\n"); for_each_dma_cap_mask(cap, dma_cap_mask_all) if (channel_table[cap]) free_percpu(channel_table[cap]); @@ -520,12 +522,12 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v err = dma_chan_get(chan); if (err == -ENODEV) { - pr_debug("%s: %s module removed\n", __func__, - dma_chan_name(chan)); + pr_debug("%s: %s module removed\n", + __func__, dma_chan_name(chan)); list_del_rcu(&device->global_node); } else if (err) pr_debug("%s: failed to get %s: (%d)\n", - __func__, dma_chan_name(chan), err); + __func__, dma_chan_name(chan), err); else break; if (--device->privatecnt == 0) @@ -535,7 +537,9 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v } mutex_unlock(&dma_list_mutex); - pr_debug("%s: %s (%s)\n", __func__, chan ? "success" : "fail", + pr_debug("%s: %s (%s)\n", + __func__, + chan ? "success" : "fail", chan ? dma_chan_name(chan) : NULL); return chan; @@ -579,7 +583,7 @@ void dmaengine_get(void) break; } else if (err) pr_err("%s: failed to get %s: (%d)\n", - __func__, dma_chan_name(chan), err); + __func__, dma_chan_name(chan), err); } } @@ -1015,7 +1019,7 @@ dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) while (tx->cookie == -EBUSY) { if (time_after_eq(jiffies, dma_sync_wait_timeout)) { pr_err("%s timeout waiting for descriptor submission\n", - __func__); + __func__); return DMA_ERROR; } cpu_relax(); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 721296157577..d3c5a5a88f1e 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -105,13 +105,13 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc) spin_lock_irqsave(&dwc->lock, flags); list_for_each_entry_safe(desc, _desc, &dwc->free_list, desc_node) { + i++; if (async_tx_test_ack(&desc->txd)) { list_del(&desc->desc_node); ret = desc; break; } dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc); - i++; } spin_unlock_irqrestore(&dwc->lock, flags); @@ -191,6 +191,42 @@ static void dwc_initialize(struct dw_dma_chan *dwc) /*----------------------------------------------------------------------*/ +static inline unsigned int dwc_fast_fls(unsigned long long v) +{ + /* + * We can be a lot more clever here, but this should take care + * of the most common optimization. + */ + if (!(v & 7)) + return 3; + else if (!(v & 3)) + return 2; + else if (!(v & 1)) + return 1; + return 0; +} + +static void dwc_dump_chan_regs(struct dw_dma_chan *dwc) +{ + dev_err(chan2dev(&dwc->chan), + " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", + channel_readl(dwc, SAR), + channel_readl(dwc, DAR), + channel_readl(dwc, LLP), + channel_readl(dwc, CTL_HI), + channel_readl(dwc, CTL_LO)); +} + + +static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc) +{ + channel_clear_bit(dw, CH_EN, dwc->mask); + while (dma_readl(dw, CH_EN) & dwc->mask) + cpu_relax(); +} + +/*----------------------------------------------------------------------*/ + /* Called with dwc->lock held and bh disabled */ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) { @@ -200,13 +236,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) if (dma_readl(dw, CH_EN) & dwc->mask) { dev_err(chan2dev(&dwc->chan), "BUG: Attempted to start non-idle channel\n"); - dev_err(chan2dev(&dwc->chan), - " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", - channel_readl(dwc, SAR), - channel_readl(dwc, DAR), - channel_readl(dwc, LLP), - channel_readl(dwc, CTL_HI), - channel_readl(dwc, CTL_LO)); + dwc_dump_chan_regs(dwc); /* The tasklet will hopefully advance the queue... */ return; @@ -290,9 +320,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc) "BUG: XFER bit set, but channel not idle!\n"); /* Try to continue after resetting the channel... */ - channel_clear_bit(dw, CH_EN, dwc->mask); - while (dma_readl(dw, CH_EN) & dwc->mask) - cpu_relax(); + dwc_chan_disable(dw, dwc); } /* @@ -337,7 +365,8 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) return; } - dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp); + dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__, + (unsigned long long)llp); list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { /* check first descriptors addr */ @@ -373,9 +402,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) "BUG: All descriptors done, but channel not idle!\n"); /* Try to continue after resetting the channel... */ - channel_clear_bit(dw, CH_EN, dwc->mask); - while (dma_readl(dw, CH_EN) & dwc->mask) - cpu_relax(); + dwc_chan_disable(dw, dwc); if (!list_empty(&dwc->queue)) { list_move(dwc->queue.next, &dwc->active_list); @@ -384,12 +411,11 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) spin_unlock_irqrestore(&dwc->lock, flags); } -static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli) +static inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli) { dev_printk(KERN_CRIT, chan2dev(&dwc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n", - lli->sar, lli->dar, lli->llp, - lli->ctlhi, lli->ctllo); + lli->sar, lli->dar, lli->llp, lli->ctlhi, lli->ctllo); } static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc) @@ -487,17 +513,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, spin_lock_irqsave(&dwc->lock, flags); - dev_err(chan2dev(&dwc->chan), - " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", - channel_readl(dwc, SAR), - channel_readl(dwc, DAR), - channel_readl(dwc, LLP), - channel_readl(dwc, CTL_HI), - channel_readl(dwc, CTL_LO)); + dwc_dump_chan_regs(dwc); - channel_clear_bit(dw, CH_EN, dwc->mask); - while (dma_readl(dw, CH_EN) & dwc->mask) - cpu_relax(); + dwc_chan_disable(dw, dwc); /* make sure DMA does not restart by loading a new list */ channel_writel(dwc, LLP, 0); @@ -527,7 +545,7 @@ static void dw_dma_tasklet(unsigned long data) status_xfer = dma_readl(dw, RAW.XFER); status_err = dma_readl(dw, RAW.ERROR); - dev_vdbg(dw->dma.dev, "tasklet: status_err=%x\n", status_err); + dev_vdbg(dw->dma.dev, "%s: status_err=%x\n", __func__, status_err); for (i = 0; i < dw->dma.chancnt; i++) { dwc = &dw->chan[i]; @@ -551,7 +569,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id) struct dw_dma *dw = dev_id; u32 status; - dev_vdbg(dw->dma.dev, "interrupt: status=0x%x\n", + dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, dma_readl(dw, STATUS_INT)); /* @@ -597,12 +615,12 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx) * for DMA. But this is hard to do in a race-free manner. */ if (list_empty(&dwc->active_list)) { - dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n", + dev_vdbg(chan2dev(tx->chan), "%s: started %u\n", __func__, desc->txd.cookie); list_add_tail(&desc->desc_node, &dwc->active_list); dwc_dostart(dwc, dwc_first_active(dwc)); } else { - dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n", + dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__, desc->txd.cookie); list_add_tail(&desc->desc_node, &dwc->queue); @@ -627,26 +645,17 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, unsigned int dst_width; u32 ctllo; - dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n", - dest, src, len, flags); + dev_vdbg(chan2dev(chan), + "%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__, + (unsigned long long)dest, (unsigned long long)src, + len, flags); if (unlikely(!len)) { - dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); + dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__); return NULL; } - /* - * We can be a lot more clever here, but this should take care - * of the most common optimization. - */ - if (!((src | dest | len) & 7)) - src_width = dst_width = 3; - else if (!((src | dest | len) & 3)) - src_width = dst_width = 2; - else if (!((src | dest | len) & 1)) - src_width = dst_width = 1; - else - src_width = dst_width = 0; + src_width = dst_width = dwc_fast_fls(src | dest | len); ctllo = DWC_DEFAULT_CTLLO(chan) | DWC_CTLL_DST_WIDTH(dst_width) @@ -720,7 +729,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct scatterlist *sg; size_t total_len = 0; - dev_vdbg(chan2dev(chan), "prep_dma_slave\n"); + dev_vdbg(chan2dev(chan), "%s\n", __func__); if (unlikely(!dws || !sg_len)) return NULL; @@ -746,14 +755,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, mem = sg_dma_address(sg); len = sg_dma_len(sg); - if (!((mem | len) & 7)) - mem_width = 3; - else if (!((mem | len) & 3)) - mem_width = 2; - else if (!((mem | len) & 1)) - mem_width = 1; - else - mem_width = 0; + mem_width = dwc_fast_fls(mem | len); slave_sg_todev_fill_desc: desc = dwc_desc_get(dwc); @@ -813,14 +815,7 @@ slave_sg_todev_fill_desc: mem = sg_dma_address(sg); len = sg_dma_len(sg); - if (!((mem | len) & 7)) - mem_width = 3; - else if (!((mem | len) & 3)) - mem_width = 2; - else if (!((mem | len) & 1)) - mem_width = 1; - else - mem_width = 0; + mem_width = dwc_fast_fls(mem | len); slave_sg_fromdev_fill_desc: desc = dwc_desc_get(dwc); @@ -950,9 +945,7 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, } else if (cmd == DMA_TERMINATE_ALL) { spin_lock_irqsave(&dwc->lock, flags); - channel_clear_bit(dw, CH_EN, dwc->mask); - while (dma_readl(dw, CH_EN) & dwc->mask) - cpu_relax(); + dwc_chan_disable(dw, dwc); dwc->paused = false; @@ -1014,7 +1007,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) int i; unsigned long flags; - dev_vdbg(chan2dev(chan), "alloc_chan_resources\n"); + dev_vdbg(chan2dev(chan), "%s\n", __func__); /* ASSERT: channel is idle */ if (dma_readl(dw, CH_EN) & dwc->mask) { @@ -1057,8 +1050,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&dwc->lock, flags); - dev_dbg(chan2dev(chan), - "alloc_chan_resources allocated %d descriptors\n", i); + dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i); return i; } @@ -1071,7 +1063,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) unsigned long flags; LIST_HEAD(list); - dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n", + dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__, dwc->descs_allocated); /* ASSERT: channel is idle */ @@ -1097,7 +1089,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) kfree(desc); } - dev_vdbg(chan2dev(chan), "free_chan_resources done\n"); + dev_vdbg(chan2dev(chan), "%s: done\n", __func__); } /* --------------------- Cyclic DMA API extensions -------------------- */ @@ -1126,13 +1118,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan) if (dma_readl(dw, CH_EN) & dwc->mask) { dev_err(chan2dev(&dwc->chan), "BUG: Attempted to start non-idle channel\n"); - dev_err(chan2dev(&dwc->chan), - " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", - channel_readl(dwc, SAR), - channel_readl(dwc, DAR), - channel_readl(dwc, LLP), - channel_readl(dwc, CTL_HI), - channel_readl(dwc, CTL_LO)); + dwc_dump_chan_regs(dwc); spin_unlock_irqrestore(&dwc->lock, flags); return -EBUSY; } @@ -1167,9 +1153,7 @@ void dw_dma_cyclic_stop(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); - channel_clear_bit(dw, CH_EN, dwc->mask); - while (dma_readl(dw, CH_EN) & dwc->mask) - cpu_relax(); + dwc_chan_disable(dw, dwc); spin_unlock_irqrestore(&dwc->lock, flags); } @@ -1308,9 +1292,9 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, dma_sync_single_for_device(chan2parent(chan), last->txd.phys, sizeof(last->lli), DMA_TO_DEVICE); - dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%08x len %zu " - "period %zu periods %d\n", buf_addr, buf_len, - period_len, periods); + dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu " + "period %zu periods %d\n", (unsigned long long)buf_addr, + buf_len, period_len, periods); cdesc->periods = periods; dwc->cdesc = cdesc; @@ -1340,16 +1324,14 @@ void dw_dma_cyclic_free(struct dma_chan *chan) int i; unsigned long flags; - dev_dbg(chan2dev(&dwc->chan), "cyclic free\n"); + dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__); if (!cdesc) return; spin_lock_irqsave(&dwc->lock, flags); - channel_clear_bit(dw, CH_EN, dwc->mask); - while (dma_readl(dw, CH_EN) & dwc->mask) - cpu_relax(); + dwc_chan_disable(dw, dwc); dma_writel(dw, CLEAR.ERROR, dwc->mask); dma_writel(dw, CLEAR.XFER, dwc->mask); @@ -1386,7 +1368,7 @@ static void dw_dma_off(struct dw_dma *dw) dw->chan[i].initialized = false; } -static int __init dw_probe(struct platform_device *pdev) +static int __devinit dw_probe(struct platform_device *pdev) { struct dw_dma_platform_data *pdata; struct resource *io; @@ -1432,9 +1414,15 @@ static int __init dw_probe(struct platform_device *pdev) } clk_prepare_enable(dw->clk); + /* Calculate all channel mask before DMA setup */ + dw->all_chan_mask = (1 << pdata->nr_channels) - 1; + /* force dma off, just in case */ dw_dma_off(dw); + /* disable BLOCK interrupts as well */ + channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); + err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw); if (err) goto err_irq; @@ -1443,8 +1431,6 @@ static int __init dw_probe(struct platform_device *pdev) tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw); - dw->all_chan_mask = (1 << pdata->nr_channels) - 1; - INIT_LIST_HEAD(&dw->dma.channels); for (i = 0; i < pdata->nr_channels; i++) { struct dw_dma_chan *dwc = &dw->chan[i]; @@ -1474,17 +1460,13 @@ static int __init dw_probe(struct platform_device *pdev) channel_clear_bit(dw, CH_EN, dwc->mask); } - /* Clear/disable all interrupts on all channels. */ + /* Clear all interrupts on all channels. */ dma_writel(dw, CLEAR.XFER, dw->all_chan_mask); + dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask); dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask); dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask); dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask); - channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); - channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask); - channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask); - channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask); - dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask); dma_cap_set(DMA_SLAVE, dw->dma.cap_mask); if (pdata->is_private) @@ -1523,7 +1505,7 @@ err_kfree: return err; } -static int __exit dw_remove(struct platform_device *pdev) +static int __devexit dw_remove(struct platform_device *pdev) { struct dw_dma *dw = platform_get_drvdata(pdev); struct dw_dma_chan *dwc, *_dwc; @@ -1602,7 +1584,7 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table); #endif static struct platform_driver dw_driver = { - .remove = __exit_p(dw_remove), + .remove = __devexit_p(dw_remove), .shutdown = dw_shutdown, .driver = { .name = "dw_dmac", diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index f298f69ecbf9..50830bee087a 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -82,7 +82,7 @@ struct dw_dma_regs { DW_REG(ID); DW_REG(TEST); - /* optional encoded params, 0x3c8..0x3 */ + /* optional encoded params, 0x3c8..0x3f7 */ }; /* Bitfields in CTL_LO */ @@ -219,9 +219,9 @@ static inline struct dw_dma *to_dw_dma(struct dma_device *ddev) /* LLI == Linked List Item; a.k.a. DMA block descriptor */ struct dw_lli { /* values that are not changed by hardware */ - dma_addr_t sar; - dma_addr_t dar; - dma_addr_t llp; /* chain to next lli */ + u32 sar; + u32 dar; + u32 llp; /* chain to next lli */ u32 ctllo; /* values that may get written back: */ u32 ctlhi; diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c new file mode 100644 index 000000000000..8a15cf2163dc --- /dev/null +++ b/drivers/dma/mmp_tdma.c @@ -0,0 +1,610 @@ +/* + * Driver For Marvell Two-channel DMA Engine + * + * Copyright: Marvell International Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/dmaengine.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <mach/regs-icu.h> +#include <mach/sram.h> + +#include "dmaengine.h" + +/* + * Two-Channel DMA registers + */ +#define TDBCR 0x00 /* Byte Count */ +#define TDSAR 0x10 /* Src Addr */ +#define TDDAR 0x20 /* Dst Addr */ +#define TDNDPR 0x30 /* Next Desc */ +#define TDCR 0x40 /* Control */ +#define TDCP 0x60 /* Priority*/ +#define TDCDPR 0x70 /* Current Desc */ +#define TDIMR 0x80 /* Int Mask */ +#define TDISR 0xa0 /* Int Status */ + +/* Two-Channel DMA Control Register */ +#define TDCR_SSZ_8_BITS (0x0 << 22) /* Sample Size */ +#define TDCR_SSZ_12_BITS (0x1 << 22) +#define TDCR_SSZ_16_BITS (0x2 << 22) +#define TDCR_SSZ_20_BITS (0x3 << 22) +#define TDCR_SSZ_24_BITS (0x4 << 22) +#define TDCR_SSZ_32_BITS (0x5 << 22) +#define TDCR_SSZ_SHIFT (0x1 << 22) +#define TDCR_SSZ_MASK (0x7 << 22) +#define TDCR_SSPMOD (0x1 << 21) /* SSP MOD */ +#define TDCR_ABR (0x1 << 20) /* Channel Abort */ +#define TDCR_CDE (0x1 << 17) /* Close Desc Enable */ +#define TDCR_PACKMOD (0x1 << 16) /* Pack Mode (ADMA Only) */ +#define TDCR_CHANACT (0x1 << 14) /* Channel Active */ +#define TDCR_FETCHND (0x1 << 13) /* Fetch Next Desc */ +#define TDCR_CHANEN (0x1 << 12) /* Channel Enable */ +#define TDCR_INTMODE (0x1 << 10) /* Interrupt Mode */ +#define TDCR_CHAINMOD (0x1 << 9) /* Chain Mode */ +#define TDCR_BURSTSZ_MSK (0x7 << 6) /* Burst Size */ +#define TDCR_BURSTSZ_4B (0x0 << 6) +#define TDCR_BURSTSZ_8B (0x1 << 6) +#define TDCR_BURSTSZ_16B (0x3 << 6) +#define TDCR_BURSTSZ_32B (0x6 << 6) +#define TDCR_BURSTSZ_64B (0x7 << 6) +#define TDCR_BURSTSZ_SQU_32B (0x7 << 6) +#define TDCR_BURSTSZ_128B (0x5 << 6) +#define TDCR_DSTDIR_MSK (0x3 << 4) /* Dst Direction */ +#define TDCR_DSTDIR_ADDR_HOLD (0x2 << 4) /* Dst Addr Hold */ +#define TDCR_DSTDIR_ADDR_INC (0x0 << 4) /* Dst Addr Increment */ +#define TDCR_SRCDIR_MSK (0x3 << 2) /* Src Direction */ +#define TDCR_SRCDIR_ADDR_HOLD (0x2 << 2) /* Src Addr Hold */ +#define TDCR_SRCDIR_ADDR_INC (0x0 << 2) /* Src Addr Increment */ +#define TDCR_DSTDESCCONT (0x1 << 1) +#define TDCR_SRCDESTCONT (0x1 << 0) + +/* Two-Channel DMA Int Mask Register */ +#define TDIMR_COMP (0x1 << 0) + +/* Two-Channel DMA Int Status Register */ +#define TDISR_COMP (0x1 << 0) + +/* |