Merge branch 'topic/renesas' into for-linus
authorVinod Koul <vkoul@kernel.org>
Wed, 24 Oct 2018 08:16:22 +0000 (09:16 +0100)
committerVinod Koul <vkoul@kernel.org>
Wed, 24 Oct 2018 08:16:22 +0000 (09:16 +0100)
39 files changed:
Documentation/devicetree/bindings/dma/jz4780-dma.txt
arch/mips/boot/dts/ingenic/jz4740.dtsi
arch/mips/boot/dts/ingenic/jz4770.dtsi
arch/mips/boot/dts/ingenic/jz4780.dtsi
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/at_hdmac.c
drivers/dma/at_xdmac.c
drivers/dma/bcm2835-dma.c
drivers/dma/coh901318.c
drivers/dma/dma-jz4740.c
drivers/dma/dma-jz4780.c
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/dw/core.c
drivers/dma/dw/platform.c
drivers/dma/ep93xx_dma.c
drivers/dma/fsl-edma-common.c [new file with mode: 0644]
drivers/dma/fsl-edma-common.h [new file with mode: 0644]
drivers/dma/fsl-edma.c
drivers/dma/fsldma.c
drivers/dma/hsu/hsu.c
drivers/dma/idma64.c
drivers/dma/imx-dma.c
drivers/dma/ioat/init.c
drivers/dma/k3dma.c
drivers/dma/mcf-edma.c [new file with mode: 0644]
drivers/dma/mmp_tdma.c
drivers/dma/mv_xor.c
drivers/dma/mxs-dma.c
drivers/dma/nbpfaxi.c
drivers/dma/owl-dma.c
drivers/dma/ppc4xx/adma.c
drivers/dma/pxa_dma.c
drivers/dma/st_fdma.c
drivers/dma/ste_dma40.c
drivers/dma/stm32-mdma.c
drivers/dma/timb_dma.c
include/linux/platform_data/dma-ep93xx.h
include/linux/platform_data/dma-mcf-edma.h [new file with mode: 0644]

index 03e9cf7..636fcb2 100644 (file)
@@ -2,8 +2,13 @@
 
 Required properties:
 
-- compatible: Should be "ingenic,jz4780-dma"
-- reg: Should contain the DMA controller registers location and length.
+- compatible: Should be one of:
+  * ingenic,jz4740-dma
+  * ingenic,jz4725b-dma
+  * ingenic,jz4770-dma
+  * ingenic,jz4780-dma
+- reg: Should contain the DMA channel registers location and length, followed
+  by the DMA controller registers location and length.
 - interrupts: Should contain the interrupt specifier of the DMA controller.
 - clocks: Should contain a clock specifier for the JZ4780 PDMA clock.
 - #dma-cells: Must be <2>. Number of integer cells in the dmas property of
@@ -19,9 +24,10 @@ Optional properties:
 
 Example:
 
-dma: dma@13420000 {
+dma: dma-controller@13420000 {
        compatible = "ingenic,jz4780-dma";
-       reg = <0x13420000 0x10000>;
+       reg = <0x13420000 0x400
+              0x13421000 0x40>;
 
        interrupt-parent = <&intc>;
        interrupts = <10>;
index 26c6b56..6fb16fd 100644 (file)
                clock-names = "baud", "module";
        };
 
+       dmac: dma-controller@13020000 {
+               compatible = "ingenic,jz4740-dma";
+               reg = <0x13020000 0xbc
+                      0x13020300 0x14>;
+               #dma-cells = <2>;
+
+               interrupt-parent = <&intc>;
+               interrupts = <29>;
+
+               clocks = <&cgu JZ4740_CLK_DMA>;
+
+               /* Disable dmac until we have something that uses it */
+               status = "disabled";
+       };
+
        uhc: uhc@13030000 {
                compatible = "ingenic,jz4740-ohci", "generic-ohci";
                reg = <0x13030000 0x1000>;
index 7c2804f..49ede6c 100644 (file)
                status = "disabled";
        };
 
+       dmac0: dma-controller@13420000 {
+               compatible = "ingenic,jz4770-dma";
+               reg = <0x13420000 0xC0
+                      0x13420300 0x20>;
+
+               #dma-cells = <1>;
+
+               clocks = <&cgu JZ4770_CLK_DMA>;
+               interrupt-parent = <&intc>;
+               interrupts = <24>;
+
+               /* Disable dmac0 until we have something that uses it */
+               status = "disabled";
+       };
+
+       dmac1: dma-controller@13420100 {
+               compatible = "ingenic,jz4770-dma";
+               reg = <0x13420100 0xC0
+                      0x13420400 0x20>;
+
+               #dma-cells = <1>;
+
+               clocks = <&cgu JZ4770_CLK_DMA>;
+               interrupt-parent = <&intc>;
+               interrupts = <23>;
+
+               /* Disable dmac1 until we have something that uses it */
+               status = "disabled";
+       };
+
        uhc: uhc@13430000 {
                compatible = "generic-ohci";
                reg = <0x13430000 0x1000>;
index ce93d57..b03cdec 100644 (file)
 
        dma: dma@13420000 {
                compatible = "ingenic,jz4780-dma";
-               reg = <0x13420000 0x10000>;
+               reg = <0x13420000 0x400
+                      0x13421000 0x40>;
                #dma-cells = <2>;
 
                interrupt-parent = <&intc>;
index dacf3f4..de511db 100644 (file)
@@ -143,7 +143,7 @@ config DMA_JZ4740
 
 config DMA_JZ4780
        tristate "JZ4780 DMA support"
-       depends on MACH_JZ4780 || COMPILE_TEST
+       depends on MIPS || COMPILE_TEST
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
        help
@@ -321,6 +321,17 @@ config LPC18XX_DMAMUX
          Enable support for DMA on NXP LPC18xx/43xx platforms
          with PL080 and multiplexed DMA request lines.
 
+config MCF_EDMA
+       tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs"
+       depends on M5441x || COMPILE_TEST
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Support the Freescale ColdFire eDMA engine, 64-channel
+         implementation that performs complex data transfers with
+         minimal intervention from a host processor.
+         This module can be found on Freescale ColdFire mcf5441x SoCs.
+
 config MMP_PDMA
        bool "MMP PDMA support"
        depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST
index c91702d..7fcc4d8 100644 (file)
@@ -31,7 +31,8 @@ obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/
 obj-$(CONFIG_DW_DMAC_CORE) += dw/
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
 obj-$(CONFIG_FSL_DMA) += fsldma.o
-obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
+obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
+obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o
 obj-$(CONFIG_FSL_RAID) += fsl_raid.o
 obj-$(CONFIG_HSU_DMA) += hsu/
 obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
index 75f38d1..7cbac6e 100644 (file)
@@ -1320,7 +1320,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
        if (unlikely(!is_slave_direction(direction)))
                goto err_out;
 
-       if (sconfig->direction == DMA_MEM_TO_DEV)
+       if (direction == DMA_MEM_TO_DEV)
                reg_width = convert_buswidth(sconfig->dst_addr_width);
        else
                reg_width = convert_buswidth(sconfig->src_addr_width);
index 4bf7256..4e55768 100644 (file)
@@ -1600,7 +1600,7 @@ static void at_xdmac_tasklet(unsigned long data)
                if (atchan->status & AT_XDMAC_CIS_ROIS)
                        dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
 
-               spin_lock_bh(&atchan->lock);
+               spin_lock(&atchan->lock);
                desc = list_first_entry(&atchan->xfers_list,
                                        struct at_xdmac_desc,
                                        xfer_node);
@@ -1610,7 +1610,7 @@ static void at_xdmac_tasklet(unsigned long data)
                txd = &desc->tx_dma_desc;
 
                at_xdmac_remove_xfer(atchan, desc);
-               spin_unlock_bh(&atchan->lock);
+               spin_unlock(&atchan->lock);
 
                if (!at_xdmac_chan_is_cyclic(atchan)) {
                        dma_cookie_complete(txd);
index 847f84a..cad55ab 100644 (file)
@@ -778,14 +778,6 @@ static int bcm2835_dma_slave_config(struct dma_chan *chan,
 {
        struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
 
-       if ((cfg->direction == DMA_DEV_TO_MEM &&
-            cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
-           (cfg->direction == DMA_MEM_TO_DEV &&
-            cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
-           !is_slave_direction(cfg->direction)) {
-               return -EINVAL;
-       }
-
        c->cfg = *cfg;
 
        return 0;
index da74fd7..eebaba3 100644 (file)
@@ -1306,6 +1306,7 @@ struct coh901318_chan {
        unsigned long nbr_active_done;
        unsigned long busy;
 
+       struct dma_slave_config config;
        u32 addr;
        u32 ctrl;
 
@@ -1402,6 +1403,10 @@ static inline struct coh901318_chan *to_coh901318_chan(struct dma_chan *chan)
        return container_of(chan, struct coh901318_chan, chan);
 }
 
+static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
+                                          struct dma_slave_config *config,
+                                          enum dma_transfer_direction direction);
+
 static inline const struct coh901318_params *
 cohc_chan_param(struct coh901318_chan *cohc)
 {
@@ -2360,6 +2365,8 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        if (lli == NULL)
                goto err_dma_alloc;
 
+       coh901318_dma_set_runtimeconfig(chan, &cohc->config, direction);
+
        /* initiate allocated lli list */
        ret = coh901318_lli_fill_sg(&cohc->base->pool, lli, sgl, sg_len,
                                    cohc->addr,
@@ -2499,7 +2506,8 @@ static const struct burst_table burst_sizes[] = {
 };
 
 static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
-                                          struct dma_slave_config *config)
+                                          struct dma_slave_config *config,
+                                          enum dma_transfer_direction direction)
 {
        struct coh901318_chan *cohc = to_coh901318_chan(chan);
        dma_addr_t addr;
@@ -2509,11 +2517,11 @@ static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
        int i = 0;
 
        /* We only support mem to per or per to mem transfers */
-       if (config->direction == DMA_DEV_TO_MEM) {
+       if (direction == DMA_DEV_TO_MEM) {
                addr = config->src_addr;
                addr_width = config->src_addr_width;
                maxburst = config->src_maxburst;
-       } else if (config->direction == DMA_MEM_TO_DEV) {
+       } else if (direction == DMA_MEM_TO_DEV) {
                addr = config->dst_addr;
                addr_width = config->dst_addr_width;
                maxburst = config->dst_maxburst;
@@ -2579,6 +2587,16 @@ static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
        return 0;
 }
 
+static int coh901318_dma_slave_config(struct dma_chan *chan,
+                                          struct dma_slave_config *config)
+{
+       struct coh901318_chan *cohc = to_coh901318_chan(chan);
+
+       memcpy(&cohc->config, config, sizeof(*config));
+
+       return 0;
+}
+
 static void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
                                struct coh901318_base *base)
 {
@@ -2684,7 +2702,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
        base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg;
        base->dma_slave.device_tx_status = coh901318_tx_status;
        base->dma_slave.device_issue_pending = coh901318_issue_pending;
-       base->dma_slave.device_config = coh901318_dma_set_runtimeconfig;
+       base->dma_slave.device_config = coh901318_dma_slave_config;
        base->dma_slave.device_pause = coh901318_pause;
        base->dma_slave.device_resume = coh901318_resume;
        base->dma_slave.device_terminate_all = coh901318_terminate_all;
@@ -2707,7 +2725,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
        base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy;
        base->dma_memcpy.device_tx_status = coh901318_tx_status;
        base->dma_memcpy.device_issue_pending = coh901318_issue_pending;
-       base->dma_memcpy.device_config = coh901318_dma_set_runtimeconfig;
+       base->dma_memcpy.device_config = coh901318_dma_slave_config;
        base->dma_memcpy.device_pause = coh901318_pause;
        base->dma_memcpy.device_resume = coh901318_resume;
        base->dma_memcpy.device_terminate_all = coh901318_terminate_all;
index afd5e10..5253e3c 100644 (file)
@@ -113,6 +113,7 @@ struct jz4740_dma_desc {
 struct jz4740_dmaengine_chan {
        struct virt_dma_chan vchan;
        unsigned int id;
+       struct dma_slave_config config;
 
        dma_addr_t fifo_addr;
        unsigned int transfer_shift;
@@ -203,8 +204,9 @@ static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst)
        return JZ4740_DMA_TRANSFER_SIZE_32BYTE;
 }
 
-static int jz4740_dma_slave_config(struct dma_chan *c,
-                                  struct dma_slave_config *config)
+static int jz4740_dma_slave_config_write(struct dma_chan *c,
+                                  struct dma_slave_config *config,
+                                  enum dma_transfer_direction direction)
 {
        struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
        struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
@@ -214,7 +216,7 @@ static int jz4740_dma_slave_config(struct dma_chan *c,
        enum jz4740_dma_flags flags;
        uint32_t cmd;
 
-       switch (config->direction) {
+       switch (direction) {
        case DMA_MEM_TO_DEV:
                flags = JZ4740_DMA_SRC_AUTOINC;
                transfer_size = jz4740_dma_maxburst(config->dst_maxburst);
@@ -265,6 +267,15 @@ static int jz4740_dma_slave_config(struct dma_chan *c,
        return 0;
 }
 
+static int jz4740_dma_slave_config(struct dma_chan *c,
+                                  struct dma_slave_config *config)
+{
+       struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+
+       memcpy(&chan->config, config, sizeof(*config));
+       return 0;
+}
+
 static int jz4740_dma_terminate_all(struct dma_chan *c)
 {
        struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
@@ -407,6 +418,8 @@ static struct dma_async_tx_descriptor *jz4740_dma_prep_slave_sg(
        desc->direction = direction;
        desc->cyclic = false;
 
+       jz4740_dma_slave_config_write(c, &chan->config, direction);
+
        return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
 }
 
@@ -438,6 +451,8 @@ static struct dma_async_tx_descriptor *jz4740_dma_prep_dma_cyclic(
        desc->direction = direction;
        desc->cyclic = true;
 
+       jz4740_dma_slave_config_write(c, &chan->config, direction);
+
        return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
 }
 
index 85820a2..a8b6225 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_dma.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include "dmaengine.h"
 #include "virt-dma.h"
 
-#define JZ_DMA_NR_CHANNELS     32
-
 /* Global registers. */
-#define JZ_DMA_REG_DMAC                0x1000
-#define JZ_DMA_REG_DIRQP       0x1004
-#define JZ_DMA_REG_DDR         0x1008
-#define JZ_DMA_REG_DDRS                0x100c
-#define JZ_DMA_REG_DMACP       0x101c
-#define JZ_DMA_REG_DSIRQP      0x1020
-#define JZ_DMA_REG_DSIRQM      0x1024
-#define JZ_DMA_REG_DCIRQP      0x1028
-#define JZ_DMA_REG_DCIRQM      0x102c
+#define JZ_DMA_REG_DMAC                0x00
+#define JZ_DMA_REG_DIRQP       0x04
+#define JZ_DMA_REG_DDR         0x08
+#define JZ_DMA_REG_DDRS                0x0c
+#define JZ_DMA_REG_DCKE                0x10
+#define JZ_DMA_REG_DCKES       0x14
+#define JZ_DMA_REG_DCKEC       0x18
+#define JZ_DMA_REG_DMACP       0x1c
+#define JZ_DMA_REG_DSIRQP      0x20
+#define JZ_DMA_REG_DSIRQM      0x24
+#define JZ_DMA_REG_DCIRQP      0x28
+#define JZ_DMA_REG_DCIRQM      0x2c
 
 /* Per-channel registers. */
 #define JZ_DMA_REG_CHAN(n)     (n * 0x20)
-#define JZ_DMA_REG_DSA(n)      (0x00 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DTA(n)      (0x04 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DTC(n)      (0x08 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DRT(n)      (0x0c + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DCS(n)      (0x10 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DCM(n)      (0x14 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DDA(n)      (0x18 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DSD(n)      (0x1c + JZ_DMA_REG_CHAN(n))
+#define JZ_DMA_REG_DSA         0x00
+#define JZ_DMA_REG_DTA         0x04
+#define JZ_DMA_REG_DTC         0x08
+#define JZ_DMA_REG_DRT         0x0c
+#define JZ_DMA_REG_DCS         0x10
+#define JZ_DMA_REG_DCM         0x14
+#define JZ_DMA_REG_DDA         0x18
+#define JZ_DMA_REG_DSD         0x1c
 
 #define JZ_DMA_DMAC_DMAE       BIT(0)
 #define JZ_DMA_DMAC_AR         BIT(2)
 #define JZ_DMA_DMAC_HLT                BIT(3)
+#define JZ_DMA_DMAC_FAIC       BIT(27)
 #define JZ_DMA_DMAC_FMSC       BIT(31)
 
 #define JZ_DMA_DRT_AUTO                0x8
                                 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
                                 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
 
+#define JZ4780_DMA_CTRL_OFFSET 0x1000
+
+/* macros for use with jz4780_dma_soc_data.flags */
+#define JZ_SOC_DATA_ALLOW_LEGACY_DT    BIT(0)
+#define JZ_SOC_DATA_PROGRAMMABLE_DMA   BIT(1)
+#define JZ_SOC_DATA_PER_CHAN_PM                BIT(2)
+#define JZ_SOC_DATA_NO_DCKES_DCKEC     BIT(3)
+
 /**
  * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller.
  * @dcm: value for the DCM (channel command) register
  * @dtc: transfer count (number of blocks of the transfer size specified in DCM
  * to transfer) in the low 24 bits, offset of the next descriptor from the
  * descriptor base address in the upper 8 bits.
- * @sd: target/source stride difference (in stride transfer mode).
- * @drt: request type
  */
 struct jz4780_dma_hwdesc {
        uint32_t dcm;
        uint32_t dsa;
        uint32_t dta;
        uint32_t dtc;
-       uint32_t sd;
-       uint32_t drt;
-       uint32_t reserved[2];
 };
 
 /* Size of allocations for hardware descriptor blocks. */
@@ -135,14 +141,22 @@ struct jz4780_dma_chan {
        unsigned int curr_hwdesc;
 };
 
+struct jz4780_dma_soc_data {
+       unsigned int nb_channels;
+       unsigned int transfer_ord_max;
+       unsigned long flags;
+};
+
 struct jz4780_dma_dev {
        struct dma_device dma_device;
-       void __iomem *base;
+       void __iomem *chn_base;
+       void __iomem *ctrl_base;
        struct clk *clk;
        unsigned int irq;
+       const struct jz4780_dma_soc_data *soc_data;
 
        uint32_t chan_reserved;
-       struct jz4780_dma_chan chan[JZ_DMA_NR_CHANNELS];
+       struct jz4780_dma_chan chan[];
 };
 
 struct jz4780_dma_filter_data {
@@ -169,16 +183,51 @@ static inline struct jz4780_dma_dev *jz4780_dma_chan_parent(
                            dma_device);
 }
 
-static inline uint32_t jz4780_dma_readl(struct jz4780_dma_dev *jzdma,
+static inline uint32_t jz4780_dma_chn_readl(struct jz4780_dma_dev *jzdma,
+       unsigned int chn, unsigned int reg)
+{
+       return readl(jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
+}
+
+static inline void jz4780_dma_chn_writel(struct jz4780_dma_dev *jzdma,
+       unsigned int chn, unsigned int reg, uint32_t val)
+{
+       writel(val, jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
+}
+
+static inline uint32_t jz4780_dma_ctrl_readl(struct jz4780_dma_dev *jzdma,
        unsigned int reg)
 {
-       return readl(jzdma->base + reg);
+       return readl(jzdma->ctrl_base + reg);
 }
 
-static inline void jz4780_dma_writel(struct jz4780_dma_dev *jzdma,
+static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma,
        unsigned int reg, uint32_t val)
 {
-       writel(val, jzdma->base + reg);
+       writel(val, jzdma->ctrl_base + reg);
+}
+
+static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma,
+       unsigned int chn)
+{
+       if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) {
+               unsigned int reg;
+
+               if (jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC)
+                       reg = JZ_DMA_REG_DCKE;
+               else
+                       reg = JZ_DMA_REG_DCKES;
+
+               jz4780_dma_ctrl_writel(jzdma, reg, BIT(chn));
+       }
+}
+
+static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma,
+       unsigned int chn)
+{
+       if ((jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) &&
+                       !(jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC))
+               jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn));
 }
 
 static struct jz4780_dma_desc *jz4780_dma_desc_alloc(
@@ -215,8 +264,10 @@ static void jz4780_dma_desc_free(struct virt_dma_desc *vdesc)
        kfree(desc);
 }
 
-static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift)
+static uint32_t jz4780_dma_transfer_size(struct jz4780_dma_chan *jzchan,
+       unsigned long val, uint32_t *shift)
 {
+       struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
        int ord = ffs(val) - 1;
 
        /*
@@ -228,8 +279,8 @@ static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift)
         */
        if (ord == 3)
                ord = 2;
-       else if (ord > 7)
-               ord = 7;
+       else if (ord > jzdma->soc_data->transfer_ord_max)
+               ord = jzdma->soc_data->transfer_ord_max;
 
        *shift = ord;
 
@@ -262,7 +313,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
                desc->dcm = JZ_DMA_DCM_SAI;
                desc->dsa = addr;
                desc->dta = config->dst_addr;
-               desc->drt = jzchan->transfer_type;
 
                width = config->dst_addr_width;
                maxburst = config->dst_maxburst;
@@ -270,7 +320,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
                desc->dcm = JZ_DMA_DCM_DAI;
                desc->dsa = config->src_addr;
                desc->dta = addr;
-               desc->drt = jzchan->transfer_type;
 
                width = config->src_addr_width;
                maxburst = config->src_maxburst;
@@ -283,7 +332,7 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
         * divisible by the transfer size, and we must not use more than the
         * maximum burst specified by the user.
         */
-       tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst),
+       tsz = jz4780_dma_transfer_size(jzchan, addr | len | (width * maxburst),
                                       &jzchan->transfer_shift);
 
        switch (width) {
@@ -412,12 +461,13 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy(
        if (!desc)
                return NULL;
 
-       tsz = jz4780_dma_transfer_size(dest | src | len,
+       tsz = jz4780_dma_transfer_size(jzchan, dest | src | len,
                                       &jzchan->transfer_shift);
 
+       jzchan->transfer_type = JZ_DMA_DRT_AUTO;
+
        desc->desc[0].dsa = src;
        desc->desc[0].dta = dest;
-       desc->desc[0].drt = JZ_DMA_DRT_AUTO;
        desc->desc[0].dcm = JZ_DMA_DCM_TIE | JZ_DMA_DCM_SAI | JZ_DMA_DCM_DAI |
                            tsz << JZ_DMA_DCM_TSZ_SHIFT |
                            JZ_DMA_WIDTH_32_BIT << JZ_DMA_DCM_SP_SHIFT |
@@ -472,18 +522,34 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
                        (jzchan->curr_hwdesc + 1) % jzchan->desc->count;
        }
 
-       /* Use 8-word descriptors. */
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), JZ_DMA_DCS_DES8);
+       /* Enable the channel's clock. */
+       jz4780_dma_chan_enable(jzdma, jzchan->id);
+
+       /* Use 4-word descriptors. */
+       jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
+
+       /* Set transfer type. */
+       jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT,
+                             jzchan->transfer_type);
+
+       /*
+        * Set the transfer count. This is redundant for a descriptor-driven
+        * transfer. However, there can be a delay between the transfer start
+        * time and when DTCn reg contains the new transfer count. Setting
+        * it explicitly ensures residue is computed correctly at all times.
+        */
+       jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTC,
+                               jzchan->desc->desc[jzchan->curr_hwdesc].dtc);
 
        /* Write descriptor address and initiate descriptor fetch. */
        desc_phys = jzchan->desc->desc_phys +
                    (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc));
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DDA(jzchan->id), desc_phys);
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
+       jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DDA, desc_phys);
+       jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
 
        /* Enable the channel. */
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id),
-                         JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE);
+       jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS,
+                             JZ_DMA_DCS_CTE);
 }
 
 static void jz4780_dma_issue_pending(struct dma_chan *chan)
@@ -509,12 +575,14 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan)
        spin_lock_irqsave(&jzchan->vchan.lock, flags);
 
        /* Clear the DMA status and stop the transfer. */
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0);
+       jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
        if (jzchan->desc) {
                vchan_terminate_vdesc(&jzchan->desc->vdesc);
                jzchan->desc = NULL;
        }
 
+       jz4780_dma_chan_disable(jzdma, jzchan->id);
+
        vchan_get_all_descriptors(&jzchan->vchan, &head);
 
        spin_unlock_irqrestore(&jzchan->vchan.lock, flags);
@@ -526,8 +594,10 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan)
 static void jz4780_dma_synchronize(struct dma_chan *chan)
 {
        struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan);
+       struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
 
        vchan_synchronize(&jzchan->vchan);
+       jz4780_dma_chan_disable(jzdma, jzchan->id);
 }
 
 static int jz4780_dma_config(struct dma_chan *chan,
@@ -549,21 +619,17 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan,
        struct jz4780_dma_desc *desc, unsigned int next_sg)
 {
        struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
-       unsigned int residue, count;
+       unsigned int count = 0;
        unsigned int i;
 
-       residue = 0;
-
        for (i = next_sg; i < desc->count; i++)
-               residue += desc->desc[i].dtc << jzchan->transfer_shift;
+               count += desc->desc[i].dtc & GENMASK(23, 0);
 
-       if (next_sg != 0) {
-               count = jz4780_dma_readl(jzdma,
-                                        JZ_DMA_REG_DTC(jzchan->id));
-               residue += count << jzchan->transfer_shift;
-       }
+       if (next_sg != 0)
+               count += jz4780_dma_chn_readl(jzdma, jzchan->id,
+                                        JZ_DMA_REG_DTC);
 
-       return residue;
+       return count << jzchan->transfer_shift;
 }
 
 static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
@@ -573,6 +639,7 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
        struct virt_dma_desc *vdesc;
        enum dma_status status;
        unsigned long flags;
+       unsigned long residue = 0;
 
        status = dma_cookie_status(chan, cookie, txstate);
        if ((status == DMA_COMPLETE) || (txstate == NULL))
@@ -583,13 +650,13 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
        vdesc = vchan_find_desc(&jzchan->vchan, cookie);
        if (vdesc) {
                /* On the issued list, so hasn't been processed yet */
-               txstate->residue = jz4780_dma_desc_residue(jzchan,
+               residue = jz4780_dma_desc_residue(jzchan,
                                        to_jz4780_dma_desc(vdesc), 0);
        } else if (cookie == jzchan->desc->vdesc.tx.cookie) {
-               txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
-                         (jzchan->curr_hwdesc + 1) % jzchan->desc->count);
-       } else
-               txstate->residue = 0;
+               residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
+                                       jzchan->curr_hwdesc + 1);
+       }
+       dma_set_residue(txstate, residue);
 
        if (vdesc && jzchan->desc && vdesc == &jzchan->desc->vdesc
            && jzchan->desc->status & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT))
@@ -606,8 +673,8 @@ static void jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
 
        spin_lock(&jzchan->vchan.lock);
 
-       dcs = jz4780_dma_readl(jzdma, JZ_DMA_REG_DCS(jzchan->id));
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0);
+       dcs = jz4780_dma_chn_readl(jzdma, jzchan->id, JZ_DMA_REG_DCS);
+       jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
 
        if (dcs & JZ_DMA_DCS_AR) {
                dev_warn(&jzchan->vchan.chan.dev->device,
@@ -646,9 +713,9 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
        uint32_t pending, dmac;
        int i;
 
-       pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP);
+       pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
 
-       for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) {
+       for (i = 0; i < jzdma->soc_data->nb_channels; i++) {
                if (!(pending & (1<<i)))
                        continue;
 
@@ -656,12 +723,12 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
        }
 
        /* Clear halt and address error status of all channels. */
-       dmac = jz4780_dma_readl(jzdma, JZ_DMA_REG_DMAC);
+       dmac = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DMAC);
        dmac &= ~(JZ_DMA_DMAC_HLT | JZ_DMA_DMAC_AR);
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
+       jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
 
        /* Clear interrupt pending status. */
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DIRQP, 0);
+       jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DIRQP, 0);
 
        return IRQ_HANDLED;
 }
@@ -728,7 +795,7 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
        data.channel = dma_spec->args[1];
 
        if (data.channel > -1) {
-               if (data.channel >= JZ_DMA_NR_CHANNELS) {
+               if (data.channel >= jzdma->soc_data->nb_channels) {
                        dev_err(jzdma->dma_device.dev,
                                "device requested non-existent channel %u\n",
                                data.channel);
@@ -755,16 +822,29 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
 static int jz4780_dma_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct jz4780_dma_soc_data *soc_data;
        struct jz4780_dma_dev *jzdma;
        struct jz4780_dma_chan *jzchan;
        struct dma_device *dd;
        struct resource *res;
        int i, ret;
 
-       jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL);
+       if (!dev->of_node) {
+               dev_err(dev, "This driver must be probed from devicetree\n");
+               return -EINVAL;
+       }
+
+       soc_data = device_get_match_data(dev);
+       if (!soc_data)
+               return -EINVAL;
+
+       jzdma = devm_kzalloc(dev, sizeof(*jzdma)
+                               + sizeof(*jzdma->chan) * soc_data->nb_channels,
+                               GFP_KERNEL);
        if (!jzdma)
                return -ENOMEM;
 
+       jzdma->soc_data = soc_data;
        platform_set_drvdata(pdev, jzdma);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -773,9 +853,26 @@ static int jz4780_dma_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       jzdma->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(jzdma->base))
-               return PTR_ERR(jzdma->base);
+       jzdma->chn_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(jzdma->chn_base))
+               return PTR_ERR(jzdma->chn_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res) {
+               jzdma->ctrl_base = devm_ioremap_resource(dev, res);
+               if (IS_ERR(jzdma->ctrl_base))
+                       return PTR_ERR(jzdma->ctrl_base);
+       } else if (soc_data->flags & JZ_SOC_DATA_ALLOW_LEGACY_DT) {
+               /*
+                * On JZ4780, if the second memory resource was not supplied,
+                * assume we're using an old devicetree, and calculate the
+                * offset to the control registers.
+                */
+               jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET;
+       } else {
+               dev_err(dev, "failed to get I/O memory\n");
+               return -EINVAL;
+       }
 
        ret = platform_get_irq(pdev, 0);
        if (ret < 0) {
@@ -833,13 +930,15 @@ static int jz4780_dma_probe(struct platform_device *pdev)
         * Also set the FMSC bit - it increases MSC performance, so it makes
         * little sense not to enable it.
         */
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC,
-                         JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC);
-       jz4780_dma_writel(jzdma, JZ_DMA_REG_DMACP, 0);
+       jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE |
+                              JZ_DMA_DMAC_FAIC | JZ_DMA_DMAC_FMSC);
+
+       if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA)
+               jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0);
 
        INIT_LIST_HEAD(&dd->channels);
 
-       for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) {
+       for (i = 0; i < soc_data->nb_channels; i++) {
                jzchan = &jzdma->chan[i];
                jzchan->id = i;
 
@@ -847,7 +946,7 @@ static int jz4780_dma_probe(struct platform_device *pdev)
                jzchan->vchan.desc_free = jz4780_dma_desc_free;
        }
 
-       ret = dma_async_device_register(dd);
+       ret = dmaenginem_async_device_register(dd);
        if (ret) {
                dev_err(dev, "failed to register device\n");
                goto err_disable_clk;
@@ -858,15 +957,12 @@ static int jz4780_dma_probe(struct platform_device *pdev)
                                         jzdma);
        if (ret) {
                dev_err(dev, "failed to register OF DMA controller\n");
-               goto err_unregister_dev;
+               goto err_disable_clk;
        }
 
        dev_info(dev, "JZ4780 DMA controller initialised\n");
        return 0;
 
-err_unregister_dev:
-       dma_async_device_unregister(dd);
-
 err_disable_clk:
        clk_disable_unprepare(jzdma->clk);
 
@@ -884,15 +980,40 @@ static int jz4780_dma_remove(struct platform_device *pdev)
 
        free_irq(jzdma->irq, jzdma);
 
-       for (i = 0; i < JZ_DMA_NR_CHANNELS; i++)
+       for (i = 0; i < jzdma->soc_data->nb_channels; i++)
                tasklet_kill(&jzdma->chan[i].vchan.task);
 
-       dma_async_device_unregister(&jzdma->dma_device);
        return 0;
 }
 
+static const struct jz4780_dma_soc_data jz4740_dma_soc_data = {
+       .nb_channels = 6,
+       .transfer_ord_max = 5,
+};
+
+static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = {
+       .nb_channels = 6,
+       .transfer_ord_max = 5,
+       .flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC,
+};
+
+static const struct jz4780_dma_soc_data jz4770_dma_soc_data = {
+       .nb_channels = 6,
+       .transfer_ord_max = 6,
+       .flags = JZ_SOC_DATA_PER_CHAN_PM,
+};
+
+static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
+       .nb_channels = 32,
+       .transfer_ord_max = 7,
+       .flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA,
+};
+
 static const struct of_device_id jz4780_dma_dt_match[] = {
-       { .compatible = "ingenic,jz4780-dma", .data = NULL },
+       { .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data },
+       { .compatible = "ingenic,jz4725b-dma", .data = &jz4725b_dma_soc_data },
+       { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data },
+       { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match);
index c4eb55e..b2ac1d2 100644 (file)
@@ -934,7 +934,7 @@ static int dw_probe(struct platform_device *pdev)
 
        pm_runtime_put(chip->dev);
 
-       ret = dma_async_device_register(&dw->dma);
+       ret = dmaenginem_async_device_register(&dw->dma);
        if (ret)
                goto err_pm_disable;
 
@@ -977,8 +977,6 @@ static int dw_remove(struct platform_device *pdev)
                tasklet_kill(&chan->vc.task);
        }
 
-       dma_async_device_unregister(&dw->dma);
-
        return 0;
 }
 
index f43e6da..d0c3e50 100644 (file)
@@ -886,12 +886,7 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
         */
        u32 s = dw->pdata->is_idma32 ? 1 : 2;
 
-       /* Check if chan will be configured for slave transfers */
-       if (!is_slave_direction(sconfig->direction))
-               return -EINVAL;
-
        memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
-       dwc->direction = sconfig->direction;
 
        sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0;
        sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0;
index f62dd09..f01b2c1 100644 (file)
@@ -284,6 +284,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id dw_dma_acpi_id_table[] = {
        { "INTL9C60", 0 },
+       { "80862286", 0 },
+       { "808622C0", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
index a155923..f674eb5 100644 (file)
 #define DMA_MAX_CHAN_DESCRIPTORS       32
 
 struct ep93xx_dma_engine;
+static int ep93xx_dma_slave_config_write(struct dma_chan *chan,
+                                        enum dma_transfer_direction dir,
+                                        struct dma_slave_config *config);
 
 /**
  * struct ep93xx_dma_desc - EP93xx specific transaction descriptor
@@ -180,6 +183,7 @@ struct ep93xx_dma_chan {
        struct list_head                free_list;
        u32                             runtime_addr;
        u32                             runtime_ctrl;
+       struct dma_slave_config         slave_config;
 };
 
 /**
@@ -1051,6 +1055,8 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                return NULL;
        }
 
+       ep93xx_dma_slave_config_write(chan, dir, &edmac->slave_config);
+
        first = NULL;
        for_each_sg(sgl, sg, sg_len, i) {
                size_t len = sg_dma_len(sg);
@@ -1136,6 +1142,8 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
                return NULL;
        }
 
+       ep93xx_dma_slave_config_write(chan, dir, &edmac->slave_config);
+
        /* Split the buffer into period size chunks */
        first = NULL;
        for (offset = 0; offset < buf_len; offset += period_len) {
@@ -1227,6 +1235,17 @@ static int ep93xx_dma_slave_config(struct dma_chan *chan,
                                   struct dma_slave_config *config)
 {
        struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
+
+       memcpy(&edmac->slave_config, config, sizeof(*config));
+
+       return 0;
+}
+
+static int ep93xx_dma_slave_config_write(struct dma_chan *chan,
+                                        enum dma_transfer_direction dir,
+                                        struct dma_slave_config *config)
+{
+       struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
        enum dma_slave_buswidth width;
        unsigned long flags;
        u32 addr, ctrl;
@@ -1234,7 +1253,7 @@ static int ep93xx_dma_slave_config(struct dma_chan *chan,
        if (!edmac->edma->m2m)
                return -EINVAL;
 
-       switch (config->direction) {
+       switch (dir) {
        case DMA_DEV_TO_MEM:
                width = config->src_addr_width;
                addr = config->src_addr;
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
new file mode 100644 (file)
index 0000000..8876c4c
--- /dev/null
@@ -0,0 +1,626 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
+// Copyright (c) 2017 Sysam, Angelo Dureghello  <angelo@sysam.it>
+
+#include <linux/dmapool.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "fsl-edma-common.h"
+
+#define EDMA_CR                        0x00
+#define EDMA_ES                        0x04
+#define EDMA_ERQ               0x0C
+#define EDMA_EEI               0x14
+#define EDMA_SERQ              0x1B
+#define EDMA_CERQ              0x1A
+#define EDMA_SEEI              0x19
+#define EDMA_CEEI              0x18
+#define EDMA_CINT              0x1F
+#define EDMA_CERR              0x1E
+#define EDMA_SSRT              0x1D
+#define EDMA_CDNE              0x1C
+#define EDMA_INTR              0x24
+#define EDMA_ERR               0x2C
+
+#define EDMA64_ERQH            0x08
+#define EDMA64_EEIH            0x10
+#define EDMA64_SERQ            0x18
+#define EDMA64_CERQ            0x19
+#define EDMA64_SEEI            0x1a
+#define EDMA64_CEEI            0x1b
+#define EDMA64_CINT            0x1c
+#define EDMA64_CERR            0x1d
+#define EDMA64_SSRT            0x1e
+#define EDMA64_CDNE            0x1f
+#define EDMA64_INTH            0x20
+#define EDMA64_INTL            0x24
+#define EDMA64_ERRH            0x28
+#define EDMA64_ERRL            0x2c
+
+#define EDMA_TCD               0x1000
+
+static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
+{
+       struct edma_regs *regs = &fsl_chan->edma->regs;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+
+       if (fsl_chan->edma->version == v1) {
+               edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
+               edma_writeb(fsl_chan->edma, ch, regs->serq);
+       } else {
+               /* ColdFire is big endian, and accesses natively
+                * big endian I/O peripherals
+                */
+               iowrite8(EDMA_SEEI_SEEI(ch), regs->seei);
+               iowrite8(ch, regs->serq);
+       }
+}
+
+void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
+{
+       struct edma_regs *regs = &fsl_chan->edma->regs;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+
+       if (fsl_chan->edma->version == v1) {
+               edma_writeb(fsl_chan->edma, ch, regs->cerq);
+               edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
+       } else {
+               /* ColdFire is big endian, and accesses natively
+                * big endian I/O peripherals
+                */
+               iowrite8(ch, regs->cerq);
+               iowrite8(EDMA_CEEI_CEEI(ch), regs->ceei);
+       }
+}
+EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
+
+void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
+                       unsigned int slot, bool enable)
+{
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+       void __iomem *muxaddr;
+       unsigned int chans_per_mux, ch_off;
+
+       chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
+       ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
+       muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
+       slot = EDMAMUX_CHCFG_SOURCE(slot);
+
+       if (enable)
+               iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
+       else
+               iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_chan_mux);
+
+static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
+{
+       switch (addr_width) {
+       case 1:
+               return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
+       case 2:
+               return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
+       case 4:
+               return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+       case 8:
+               return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
+       default:
+               return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+       }
+}
+
+void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
+{
+       struct fsl_edma_desc *fsl_desc;
+       int i;
+
+       fsl_desc = to_fsl_edma_desc(vdesc);
+       for (i = 0; i < fsl_desc->n_tcds; i++)
+               dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
+                             fsl_desc->tcd[i].ptcd);
+       kfree(fsl_desc);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_free_desc);
+
+int fsl_edma_terminate_all(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       fsl_edma_disable_request(fsl_chan);
+       fsl_chan->edesc = NULL;
+       fsl_chan->idle = true;
+       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_terminate_all);
+
+int fsl_edma_pause(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       if (fsl_chan->edesc) {
+               fsl_edma_disable_request(fsl_chan);
+               fsl_chan->status = DMA_PAUSED;
+               fsl_chan->idle = true;
+       }
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_pause);
+
+int fsl_edma_resume(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       if (fsl_chan->edesc) {
+               fsl_edma_enable_request(fsl_chan);
+               fsl_chan->status = DMA_IN_PROGRESS;
+               fsl_chan->idle = false;
+       }
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_resume);
+
+int fsl_edma_slave_config(struct dma_chan *chan,
+                                struct dma_slave_config *cfg)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+       memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_slave_config);
+
+static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
+               struct virt_dma_desc *vdesc, bool in_progress)
+{
+       struct fsl_edma_desc *edesc = fsl_chan->edesc;
+       struct edma_regs *regs = &fsl_chan->edma->regs;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+       enum dma_transfer_direction dir = edesc->dirn;
+       dma_addr_t cur_addr, dma_addr;
+       size_t len, size;
+       int i;
+
+       /* calculate the total size in this desc */
+       for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
+               len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
+                       * le16_to_cpu(edesc->tcd[i].vtcd->biter);
+
+       if (!in_progress)
+               return len;
+
+       if (dir == DMA_MEM_TO_DEV)
+               cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].saddr);
+       else
+               cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].daddr);
+
+       /* figure out the finished and calculate the residue */
+       for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
+               size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
+                       * le16_to_cpu(edesc->tcd[i].vtcd->biter);
+               if (dir == DMA_MEM_TO_DEV)
+                       dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
+               else
+                       dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
+
+               len -= size;
+               if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
+                       len += dma_addr + size - cur_addr;
+                       break;
+               }
+       }
+
+       return len;
+}
+
+enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+               dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       struct virt_dma_desc *vdesc;
+       enum dma_status status;
+       unsigned long flags;
+
+       status = dma_cookie_status(chan, cookie, txstate);
+       if (status == DMA_COMPLETE)
+               return status;
+
+       if (!txstate)
+               return fsl_chan->status;
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
+       if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
+               txstate->residue =
+                       fsl_edma_desc_residue(fsl_chan, vdesc, true);
+       else if (vdesc)
+               txstate->residue =
+                       fsl_edma_desc_residue(fsl_chan, vdesc, false);
+       else
+               txstate->residue = 0;
+
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+       return fsl_chan->status;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_tx_status);
+
+static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
+                                 struct fsl_edma_hw_tcd *tcd)
+{
+       struct fsl_edma_engine *edma = fsl_chan->edma;
+       struct edma_regs *regs = &fsl_chan->edma->regs;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+
+       /*
+        * TCD parameters are stored in struct fsl_edma_hw_tcd in little
+        * endian format. However, we need to load the TCD registers in
+        * big- or little-endian obeying the eDMA engine model endian.
+        */
+       edma_writew(edma, 0,  &regs->tcd[ch].csr);
+       edma_writel(edma, le32_to_cpu(tcd->saddr), &regs->tcd[ch].saddr);
+       edma_writel(edma, le32_to_cpu(tcd->daddr), &regs->tcd[ch].daddr);
+
+       edma_writew(edma, le16_to_cpu(tcd->attr), &regs->tcd[ch].attr);
+       edma_writew(edma, le16_to_cpu(tcd->soff), &regs->tcd[ch].soff);
+
+       edma_writel(edma, le32_to_cpu(tcd->nbytes), &regs->tcd[ch].nbytes);
+       edma_writel(edma, le32_to_cpu(tcd->slast), &regs->tcd[ch].slast);
+
+       edma_writew(edma, le16_to_cpu(tcd->citer), &regs->tcd[ch].citer);
+       edma_writew(edma, le16_to_cpu(tcd->biter), &regs->tcd[ch].biter);
+       edma_writew(edma, le16_to_cpu(tcd->doff), &regs->tcd[ch].doff);
+
+       edma_writel(edma, le32_to_cpu(tcd->dlast_sga),
+                       &regs->tcd[ch].dlast_sga);
+
+       edma_writew(edma, le16_to_cpu(tcd->csr), &regs->tcd[ch].csr);
+}
+
+static inline
+void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
+                      u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
+                      u16 biter, u16 doff, u32 dlast_sga, bool major_int,
+                      bool disable_req, bool enable_sg)
+{
+       u16 csr = 0;
+
+       /*
+        * eDMA hardware SGs require the TCDs to be stored in little
+        * endian format irrespective of the register endian model.
+        * So we put the value in little endian in memory, waiting
+        * for fsl_edma_set_tcd_regs doing the swap.
+        */
+       tcd->saddr = cpu_to_le32(src);
+       tcd->daddr = cpu_to_le32(dst);
+
+       tcd->attr = cpu_to_le16(attr);
+
+       tcd->soff = cpu_to_le16(soff);
+
+       tcd->nbytes = cpu_to_le32(nbytes);
+       tcd->slast = cpu_to_le32(slast);
+
+       tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
+       tcd->doff = cpu_to_le16(doff);
+
+       tcd->dlast_sga = cpu_to_le32(dlast_sga);
+
+       tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
+       if (major_int)
+               csr |= EDMA_TCD_CSR_INT_MAJOR;
+
+       if (disable_req)
+               csr |= EDMA_TCD_CSR_D_REQ;
+
+       if (enable_sg)
+               csr |= EDMA_TCD_CSR_E_SG;
+
+       tcd->csr = cpu_to_le16(csr);
+}
+
+static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,
+               int sg_len)
+{
+       struct fsl_edma_desc *fsl_desc;
+       int i;
+
+       fsl_desc = kzalloc(sizeof(*fsl_desc) +
+                          sizeof(struct fsl_edma_sw_tcd) *
+                          sg_len, GFP_NOWAIT);
+       if (!fsl_desc)
+               return NULL;
+
+       fsl_desc->echan = fsl_chan;
+       fsl_desc->n_tcds = sg_len;
+       for (i = 0; i < sg_len; i++) {
+               fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
+                                       GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
+               if (!fsl_desc->tcd[i].vtcd)
+                       goto err;
+       }
+       return fsl_desc;
+
+err:
+       while (--i >= 0)
+               dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
+                               fsl_desc->tcd[i].ptcd);
+       kfree(fsl_desc);
+       return NULL;
+}
+
+struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
+               struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+               size_t period_len, enum dma_transfer_direction direction,
+               unsigned long flags)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       struct fsl_edma_desc *fsl_desc;
+       dma_addr_t dma_buf_next;
+       int sg_len, i;
+       u32 src_addr, dst_addr, last_sg, nbytes;
+       u16 soff, doff, iter;
+
+       if (!is_slave_direction(direction))
+               return NULL;
+
+       sg_len = buf_len / period_len;
+       fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+       if (!fsl_desc)
+               return NULL;
+       fsl_desc->iscyclic = true;
+       fsl_desc->dirn = direction;
+
+       dma_buf_next = dma_addr;
+       if (direction == DMA_MEM_TO_DEV) {
+               fsl_chan->attr =
+                       fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width);
+               nbytes = fsl_chan->cfg.dst_addr_width *
+                       fsl_chan->cfg.dst_maxburst;
+       } else {
+               fsl_chan->attr =
+                       fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width);
+               nbytes = fsl_chan->cfg.src_addr_width *
+                       fsl_chan->cfg.src_maxburst;
+       }
+
+       iter = period_len / nbytes;
+
+       for (i = 0; i < sg_len; i++) {
+               if (dma_buf_next >= dma_addr + buf_len)
+                       dma_buf_next = dma_addr;
+
+               /* get next sg's physical address */
+               last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+               if (direction == DMA_MEM_TO_DEV) {
+                       src_addr = dma_buf_next;
+                       dst_addr = fsl_chan->cfg.dst_addr;
+                       soff = fsl_chan->cfg.dst_addr_width;
+                       doff = 0;
+               } else {
+                       src_addr = fsl_chan->cfg.src_addr;
+                       dst_addr = dma_buf_next;
+                       soff = 0;
+                       doff = fsl_chan->cfg.src_addr_width;
+               }
+
+               fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
+                                 fsl_chan->attr, soff, nbytes, 0, iter,
+                                 iter, doff, last_sg, true, false, true);
+               dma_buf_next += period_len;
+       }
+
+       return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_prep_dma_cyclic);
+
+struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
+               struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_transfer_direction direction,
+               unsigned long flags, void *context)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       struct fsl_edma_desc *fsl_desc;
+       struct scatterlist *sg;
+       u32 src_addr, dst_addr, last_sg, nbytes;
+       u16 soff, doff, iter;
+       int i;
+
+       if (!is_slave_direction(direction))
+               return NULL;
+
+       fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+       if (!fsl_desc)
+               return NULL;
+       fsl_desc->iscyclic = false;
+       fsl_desc->dirn = direction;
+
+       if (direction == DMA_MEM_TO_DEV) {
+               fsl_chan->attr =
+                       fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width);
+               nbytes = fsl_chan->cfg.dst_addr_width *
+                       fsl_chan->cfg.dst_maxburst;
+       } else {
+               fsl_chan->attr =
+                       fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width);
+               nbytes = fsl_chan->cfg.src_addr_width *
+                       fsl_chan->cfg.src_maxburst;
+       }
+
+       for_each_sg(sgl, sg, sg_len, i) {
+               /* get next sg's physical address */
+               last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+               if (direction == DMA_MEM_TO_DEV) {
+                       src_addr = sg_dma_address(sg);
+                       dst_addr = fsl_chan->cfg.dst_addr;
+                       soff = fsl_chan->cfg.dst_addr_width;
+                       doff = 0;
+               } else {
+                       src_addr = fsl_chan->cfg.src_addr;
+                       dst_addr = sg_dma_address(sg);
+                       soff = 0;
+                       doff = fsl_chan->cfg.src_addr_width;
+               }
+
+               iter = sg_dma_len(sg) / nbytes;
+               if (i < sg_len - 1) {
+                       last_sg = fsl_desc->tcd[(i + 1)].ptcd;
+                       fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
+                                         dst_addr, fsl_chan->attr, soff,
+                                         nbytes, 0, iter, iter, doff, last_sg,
+                                         false, false, true);
+               } else {
+                       last_sg = 0;
+                       fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
+                                         dst_addr, fsl_chan->attr, soff,
+                                         nbytes, 0, iter, iter, doff, last_sg,
+                                         true, true, false);
+               }
+       }
+
+       return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_prep_slave_sg);
+
+void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
+{
+       struct virt_dma_desc *vdesc;
+
+       vdesc = vchan_next_desc(&fsl_chan->vchan);
+       if (!vdesc)
+               return;
+       fsl_chan->edesc = to_fsl_edma_desc(vdesc);
+       fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
+       fsl_edma_enable_request(fsl_chan);
+       fsl_chan->status = DMA_IN_PROGRESS;
+       fsl_chan->idle = false;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_xfer_desc);
+
+void fsl_edma_issue_pending(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+
+       if (unlikely(fsl_chan->pm_state != RUNNING)) {
+               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+               /* cannot submit due to suspend */
+               return;
+       }
+
+       if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
+               fsl_edma_xfer_desc(fsl_chan);
+
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_issue_pending);
+
+int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+       fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+                               sizeof(struct fsl_edma_hw_tcd),
+                               32, 0);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_alloc_chan_resources);
+
+void fsl_edma_free_chan_resources(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       fsl_edma_disable_request(fsl_chan);
+       fsl_edma_chan_mux(fsl_chan, 0, false);
+       fsl_chan->edesc = NULL;
+       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+       dma_pool_destroy(fsl_chan->tcd_pool);
+       fsl_chan->tcd_pool = NULL;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_free_chan_resources);
+
+void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
+{
+       struct fsl_edma_chan *chan, *_chan;
+
+       list_for_each_entry_safe(chan, _chan,
+                               &dmadev->channels, vchan.chan.device_node) {
+               list_del(&chan->vchan.chan.device_node);
+               tasklet_kill(&chan->vchan.task);
+       }
+}
+EXPORT_SYMBOL_GPL(fsl_edma_cleanup_vchan);
+
+/*
+ * On the 32 channels Vybrid/mpc577x edma version (here called "v1"),
+ * register offsets are different compared to ColdFire mcf5441x 64 channels
+ * edma (here called "v2").
+ *
+ * This function sets up register offsets as per proper declared version
+ * so must be called in xxx_edma_probe() just after setting the
+ * edma "version" and "membase" appropriately.
+ */
+void fsl_edma_setup_regs(struct fsl_edma_engine *edma)
+{
+       edma->regs.cr = edma->membase + EDMA_CR;
+       edma->regs.es = edma->membase + EDMA_ES;
+       edma->regs.erql = edma->membase + EDMA_ERQ;
+       edma->regs.eeil = edma->membase + EDMA_EEI;
+
+       edma->regs.serq = edma->membase + ((edma->version == v1) ?
+                       EDMA_SERQ : EDMA64_SERQ);
+       edma->regs.cerq = edma->membase + ((edma->version == v1) ?
+                       EDMA_CERQ : EDMA64_CERQ);
+       edma->regs.seei = edma->membase + ((edma->version == v1) ?
+                       EDMA_SEEI : EDMA64_SEEI);
+       edma->regs.ceei = edma->membase + ((edma->version == v1) ?
+                       EDMA_CEEI : EDMA64_CEEI);
+       edma->regs.cint = edma->membase + ((edma->version == v1) ?
+                       EDMA_CINT : EDMA64_CINT);
+       edma->regs.cerr = edma->membase + ((edma->version == v1) ?
+                       EDMA_CERR : EDMA64_CERR);
+       edma->regs.ssrt = edma->membase + ((edma->version == v1) ?
+                       EDMA_SSRT : EDMA64_SSRT);
+       edma->regs.cdne = edma->membase + ((edma->version == v1) ?
+                       EDMA_CDNE : EDMA64_CDNE);
+       edma->regs.intl = edma->membase + ((edma->version == v1) ?
+                       EDMA_INTR : EDMA64_INTL);
+       edma->regs.errl = edma->membase + ((edma->version == v1) ?
+                       EDMA_ERR : EDMA64_ERRL);
+
+       if (edma->version == v2) {
+               edma->regs.erqh = edma->membase + EDMA64_ERQH;
+               edma->regs.eeih = edma->membase + EDMA64_EEIH;
+               edma->regs.errh = edma->membase + EDMA64_ERRH;
+               edma->regs.inth = edma->membase + EDMA64_INTH;
+       }
+
+       edma->regs.tcd = edma->membase + EDMA_TCD;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_setup_regs);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
new file mode 100644 (file)
index 0000000..8917e88
--- /dev/null
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ * Copyright 2018 Angelo Dureghello <angelo@sysam.it>
+ */
+#ifndef _FSL_EDMA_COMMON_H_
+#define _FSL_EDMA_COMMON_H_
+
+#include "virt-dma.h"
+
+#define EDMA_CR_EDBG           BIT(1)
+#define EDMA_CR_ERCA           BIT(2)
+#define EDMA_CR_ERGA           BIT(3)
+#define EDMA_CR_HOE            BIT(4)
+#define EDMA_CR_HALT           BIT(5)
+#define EDMA_CR_CLM            BIT(6)
+#define EDMA_CR_EMLM           BIT(7)
+#define EDMA_CR_ECX            BIT(16)
+#define EDMA_CR_CX             BIT(17)
+
+#define EDMA_SEEI_SEEI(x)      ((x) & GENMASK(4, 0))
+#define EDMA_CEEI_CEEI(x)      ((x) & GENMASK(4, 0))
+#define EDMA_CINT_CINT(x)      ((x) & GENMASK(4, 0))
+#define EDMA_CERR_CERR(x)      ((x) & GENMASK(4, 0))
+
+#define EDMA_TCD_ATTR_DSIZE(x)         (((x) & GENMASK(2, 0)))
+#define EDMA_TCD_ATTR_DMOD(x)          (((x) & GENMASK(4, 0)) << 3)
+#define EDMA_TCD_ATTR_SSIZE(x)         (((x) & GENMASK(2, 0)) << 8)
+#define EDMA_TCD_ATTR_SMOD(x)          (((x) & GENMASK(4, 0)) << 11)
+#define EDMA_TCD_ATTR_DSIZE_8BIT       0
+#define EDMA_TCD_ATTR_DSIZE_16BIT      BIT(0)
+#define EDMA_TCD_ATTR_DSIZE_32BIT      BIT(1)
+#define EDMA_TCD_ATTR_DSIZE_64BIT      (BIT(0) | BIT(1))
+#define EDMA_TCD_ATTR_DSIZE_32BYTE     (BIT(3) | BIT(0))
+#define EDMA_TCD_ATTR_SSIZE_8BIT       0
+#define EDMA_TCD_ATTR_SSIZE_16BIT      (EDMA_TCD_ATTR_DSIZE_16BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_32BIT      (EDMA_TCD_ATTR_DSIZE_32BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_64BIT      (EDMA_TCD_ATTR_DSIZE_64BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_32BYTE     (EDMA_TCD_ATTR_DSIZE_32BYTE << 8)
+
+#define EDMA_TCD_CITER_CITER(x)                ((x) & GENMASK(14, 0))
+#define EDMA_TCD_BITER_BITER(x)                ((x) & GENMASK(14, 0))
+
+#define EDMA_TCD_CSR_START             BIT(0)
+#define EDMA_TCD_CSR_INT_MAJOR         BIT(1)
+#define EDMA_TCD_CSR_INT_HALF          BIT(2)
+#define EDMA_TCD_CSR_D_REQ             BIT(3)
+#define EDMA_TCD_CSR_E_SG              BIT(4)
+#define EDMA_TCD_CSR_E_LINK            BIT(5)
+#define EDMA_TCD_CSR_ACTIVE            BIT(6)
+#define EDMA_TCD_CSR_DONE              BIT(7)
+
+#define EDMAMUX_CHCFG_DIS              0x0
+#define EDMAMUX_CHCFG_ENBL             0x80
+#define EDMAMUX_CHCFG_SOURCE(n)                ((n) & 0x3F)
+
+#define DMAMUX_NR      2
+
+#define FSL_EDMA_BUSWIDTHS     (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+enum fsl_edma_pm_state {
+       RUNNING = 0,
+       SUSPENDED,
+};
+
+struct fsl_edma_hw_tcd {
+       __le32  saddr;
+       __le16  soff;
+       __le16  attr;
+       __le32  nbytes;
+       __le32  slast;
+       __le32  daddr;
+       __le16  doff;
+       __le16  citer;
+       __le32  dlast_sga;
+       __le16  csr;
+       __le16  biter;
+};
+
+/*
+ * These are iomem pointers, for both v32 and v64.
+ */
+struct edma_regs {
+       void __iomem *cr;
+       void __iomem *es;
+       void __iomem *erqh;
+       void __iomem *erql;     /* aka erq on v32 */
+       void __iomem *eeih;
+       void __iomem *eeil;     /* aka eei on v32 */
+       void __iomem *seei;
+       void __iomem *ceei;
+       void __iomem *serq;
+       void __iomem *cerq;
+       void __iomem *cint;
+       void __iomem *cerr;
+       void __iomem *ssrt;
+       void __iomem *cdne;
+       void __iomem *inth;
+       void __iomem *intl;
+       void __iomem *errh;
+       void __iomem *errl;
+       struct fsl_edma_hw_tcd __iomem *tcd;
+};
+
+struct fsl_edma_sw_tcd {
+       dma_addr_t                      ptcd;
+       struct fsl_edma_hw_tcd          *vtcd;
+};
+
+struct fsl_edma_chan {
+       struct virt_dma_chan            vchan;
+       enum dma_status                 status;
+       enum fsl_edma_pm_state          pm_state;
+       bool                            idle;
+       u32                             slave_id;
+       struct fsl_edma_engine          *edma;
+       struct fsl_edma_desc            *edesc;
+       struct dma_slave_config         cfg;
+       u32                             attr;
+       struct dma_pool                 *tcd_pool;
+};
+
+struct fsl_edma_desc {
+       struct virt_dma_desc            vdesc;
+       struct fsl_edma_chan            *echan;
+       bool                            iscyclic;
+       enum dma_transfer_direction     dirn;
+       unsigned int                    n_tcds;
+       struct fsl_edma_sw_tcd          tcd[];
+};
+
+enum edma_version {
+       v1, /* 32ch, Vybdir, mpc57x, etc */
+       v2, /* 64ch Coldfire */
+};
+
+struct fsl_edma_engine {
+       struct dma_device       dma_dev;
+       void __iomem            *membase;
+       void __iomem            *muxbase[DMAMUX_NR];
+       struct clk              *muxclk[DMAMUX_NR];
+       struct mutex            fsl_edma_mutex;
+       u32                     n_chans;
+       int                     txirq;
+       int                     errirq;
+       bool                    big_endian;
+       enum edma_version       version;
+       struct edma_regs        regs;
+       struct fsl_edma_chan    chans[];
+};
+
+/*
+ * R/W functions for big- or little-endian registers:
+ * The eDMA controller's endian is independent of the CPU core's endian.
+ * For the big-endian IP module, the offset for 8-bit or 16-bit registers
+ * should also be swapped opposite to that in little-endian IP.
+ */
+static inline u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
+{
+       if (edma->big_endian)
+               return ioread32be(addr);
+       else
+               return ioread32(addr);
+}
+
+static inline void edma_writeb(struct fsl_edma_engine *edma,
+                              u8 val, void __iomem *addr)
+{
+       /* swap the reg offset for these in big-endian mode */
+       if (edma->big_endian)
+               iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
+       else
+               iowrite8(val, addr);
+}
+
+static inline void edma_writew(struct fsl_edma_engine *edma,
+                              u16 val, void __iomem *addr)
+{
+       /* swap the reg offset for these in big-endian mode */
+       if (edma->big_endian)
+               iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2));
+       else
+               iowrite16(val, addr);
+}
+
+static inline void edma_writel(struct fsl_edma_engine *edma,
+                              u32 val, void __iomem *addr)
+{
+       if (edma->big_endian)
+               iowrite32be(val, addr);
+       else
+               iowrite32(val, addr);
+}
+
+static inline struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct fsl_edma_chan, vchan.chan);
+}
+
+static inline struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
+{
+       return container_of(vd, struct fsl_edma_desc, vdesc);
+}
+
+void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan);
+void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
+                       unsigned int slot, bool enable);
+void fsl_edma_free_desc(struct virt_dma_desc *vdesc);
+int fsl_edma_terminate_all(struct dma_chan *chan);
+int fsl_edma_pause(struct dma_chan *chan);
+int fsl_edma_resume(struct dma_chan *chan);
+int fsl_edma_slave_config(struct dma_chan *chan,
+                                struct dma_slave_config *cfg);
+enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+               dma_cookie_t cookie, struct dma_tx_state *txstate);
+struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
+               struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+               size_t period_len, enum dma_transfer_direction direction,
+               unsigned long flags);
+struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
+               struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_transfer_direction direction,
+               unsigned long flags, void *context);
+void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan);
+void fsl_edma_issue_pending(struct dma_chan *chan);
+int fsl_edma_alloc_chan_resources(struct dma_chan *chan);
+void fsl_edma_free_chan_resources(struct dma_chan *chan);
+void fsl_edma_cleanup_vchan(struct dma_device *dmadev);
+void fsl_edma_setup_regs(struct fsl_edma_engine *edma);
+
+#endif /* _FSL_EDMA_COMMON_H_ */
index c756886..34d7011 100644 (file)
  * option) any later version.
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_dma.h>
 
-#include "virt-dma.h"
-
-#define EDMA_CR                        0x00
-#define EDMA_ES                        0x04
-#define EDMA_ERQ               0x0C
-#define EDMA_EEI               0x14
-#define EDMA_SERQ              0x1B
-#define EDMA_CERQ              0x1A
-#define EDMA_SEEI              0x19
-#define EDMA_CEEI              0x18
-#define EDMA_CINT              0x1F
-#define EDMA_CERR              0x1E
-#define EDMA_SSRT              0x1D
-#define EDMA_CDNE              0x1C
-#define EDMA_INTR              0x24
-#define EDMA_ERR               0x2C
-
-#define EDMA_TCD_SADDR(x)      (0x1000 + 32 * (x))
-#define EDMA_TCD_SOFF(x)       (0x1004 + 32 * (x))
-#define EDMA_TCD_ATTR(x)       (0x1006 + 32 * (x))
-#define EDMA_TCD_NBYTES(x)     (0x1008 + 32 * (x))
-#define EDMA_TCD_SLAST(x)      (0x100C + 32 * (x))
-#define EDMA_TCD_DADDR(x)      (0x1010 + 32 * (x))
-#define EDMA_TCD_DOFF(x)       (0x1014 + 32 * (x))
-#define EDMA_TCD_CITER_ELINK(x)        (0x1016 + 32 * (x))
-#define EDMA_TCD_CITER(x)      (0x1016 + 32 * (x))
-#define EDMA_TCD_DLAST_SGA(x)  (0x1018 + 32 * (x))
-#define EDMA_TCD_CSR(x)                (0x101C + 32 * (x))
-#define EDMA_TCD_BITER_ELINK(x)        (0x101E + 32 * (x))
-#define EDMA_TCD_BITER(x)      (0x101E + 32 * (x))
-
-#define EDMA_CR_EDBG           BIT(1)
-#define EDMA_CR_ERCA           BIT(2)
-#define EDMA_CR_ERGA           BIT(3)
-#define EDMA_CR_HOE            BIT(4)
-#define EDMA_CR_HALT           BIT(5)
-#define EDMA_CR_CLM            BIT(6)
-#define EDMA_CR_EMLM           BIT(7)
-#define EDMA_CR_ECX            BIT(16)
-#define EDMA_CR_CX             BIT(17)
-
-#define EDMA_SEEI_SEEI(x)      ((x) & 0x1F)
-#define EDMA_CEEI_CEEI(x)      ((x) & 0x1F)
-#define EDMA_CINT_CINT(x)      ((x) & 0x1F)
-#define EDMA_CERR_CERR(x)      ((x) & 0x1F)
-
-#define EDMA_TCD_ATTR_DSIZE(x)         (((x) & 0x0007))
-#define EDMA_TCD_ATTR_DMOD(x)          (((x) & 0x001F) << 3)
-#define EDMA_TCD_ATTR_SSIZE(x)         (((x) & 0x0007) << 8)
-#define EDMA_TCD_ATTR_SMOD(x)          (((x) & 0x001F) << 11)
-#define EDMA_TCD_ATTR_SSIZE_8BIT       (0x0000)
-#define EDMA_TCD_ATTR_SSIZE_16BIT      (0x0100)
-#define EDMA_TCD_ATTR_SSIZE_32BIT      (0x0200)
-#define EDMA_TCD_ATTR_SSIZE_64BIT      (0x0300)
-#define EDMA_TCD_ATTR_SSIZE_32BYTE     (0x0500)
-#define EDMA_TCD_ATTR_DSIZE_8BIT       (0x0000)
-#define EDMA_TCD_ATTR_DSIZE_16BIT      (0x0001)
-#define EDMA_TCD_ATTR_DSIZE_32BIT      (0x0002)
-#define EDMA_TCD_ATTR_DSIZE_64BIT      (0x0003)
-#define EDMA_TCD_ATTR_DSIZE_32BYTE     (0x0005)
-
-#define EDMA_TCD_SOFF_SOFF(x)          (x)
-#define EDMA_TCD_NBYTES_NBYTES(x)      (x)
-#define EDMA_TCD_SLAST_SLAST(x)                (x)
-#define EDMA_TCD_DADDR_DADDR(x)                (x)
-#define EDMA_TCD_CITER_CITER(x)                ((x) & 0x7FFF)
-#define EDMA_TCD_DOFF_DOFF(x)          (x)
-#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)        (x)
-#define EDMA_TCD_BITER_BITER(x)                ((x) & 0x7FFF)
-
-#define EDMA_TCD_CSR_START             BIT(0)
-#define EDMA_TCD_CSR_INT_MAJOR         BIT(1)
-#define EDMA_TCD_CSR_INT_HALF          BIT(2)
-#define EDMA_TCD_CSR_D_REQ             BIT(3)
-#define EDMA_TCD_CSR_E_SG              BIT(4)
-#define EDMA_TCD_CSR_E_LINK            BIT(5)
-#define EDMA_TCD_CSR_ACTIVE            BIT(6)
-#define EDMA_TCD_CSR_DONE              BIT(7)
-
-#define EDMAMUX_CHCFG_DIS              0x0
-#define EDMAMUX_CHCFG_ENBL             0x80
-#define EDMAMUX_CHCFG_SOURCE(n)                ((n) & 0x3F)
-
-#define DMAMUX_NR      2
-
-#define FSL_EDMA_BUSWIDTHS     BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
-                               BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
-                               BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
-                               BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
-enum fsl_edma_pm_state {
-       RUNNING = 0,
-       SUSPENDED,
-};
-
-struct fsl_edma_hw_tcd {
-       __le32  saddr;
-       __le16  soff;
-       __le16  attr;
-       __le32  nbytes;
-       __le32  slast;
-       __le32  daddr;
-       __le16  doff;
-       __le16  citer;
-       __le32  dlast_sga;
-       __le16  csr;
-       __le16  biter;
-};
-
-struct fsl_edma_sw_tcd {
-       dma_addr_t                      ptcd;
-       struct fsl_edma_hw_tcd          *vtcd;
-};
-
-struct fsl_edma_slave_config {
-       enum dma_transfer_direction     dir;
-       enum dma_slave_buswidth         addr_width;
-       u32                             dev_addr;
-       u32                             burst;
-       u32                             attr;
-};
-
-struct fsl_edma_chan {
-       struct virt_dma_chan            vchan;
-       enum dma_status                 status;
-       enum fsl_edma_pm_state          pm_state;
-       bool                            idle;
-       u32                             slave_id;
-       struct fsl_edma_engine          *edma;
-       struct fsl_edma_desc            *edesc;
-       struct fsl_edma_slave_config    fsc;
-       struct dma_pool                 *tcd_pool;
-};
-
-struct fsl_edma_desc {
-       struct virt_dma_desc            vdesc;
-       struct fsl_edma_chan            *echan;
-       bool                            iscyclic;
-       unsigned int                    n_tcds;
-       struct fsl_edma_sw_tcd          tcd[];
-};
-
-struct fsl_edma_engine {
-       struct dma_device       dma_dev;
-       void __iomem            *membase;
-       void __iomem            *muxbase[DMAMUX_NR];
-       struct clk              *muxclk[DMAMUX_NR];
-       struct mutex            fsl_edma_mutex;
-       u32                     n_chans;
-       int                     txirq;
-       int                     errirq;
-       bool                    big_endian;
-       struct fsl_edma_chan    chans[];
-};
-
-/*
- * R/W functions for big- or little-endian registers:
- * The eDMA controller's endian is independent of the CPU core's endian.
- * For the big-endian IP module, the offset for 8-bit or 16-bit registers
- * should also be swapped opposite to that in little-endian IP.
- */
-
-static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
-{
-       if (edma->big_endian)
-               return ioread32be(addr);
-       else
-               return ioread32(addr);
-}
-
-static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr)
-{
-       /* swap the reg offset for these in big-endian mode */
-       if (edma->big_endian)
-               iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
-       else
-               iowrite8(val, addr);
-}
-
-static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr)
-{
-       /* swap the reg offset for these in big-endian mode */
-       if (edma->big_endian)
-               iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2));
-       else
-               iowrite16(val, addr);
-}
-
-static void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr)
-{
-       if (edma->big_endian)
-               iowrite32be(val, addr);
-       else
-               iowrite32(val, addr);
-}
-
-static struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
-{
-       return container_of(chan, struct fsl_edma_chan, vchan.chan);
-}
-
-static struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
-{
-       return container_of(vd, struct fsl_edma_desc, vdesc);
-}
-
-static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
-{
-       void __iomem *addr = fsl_chan->edma->membase;
-       u32 ch = fsl_chan->vchan.chan.chan_id;
-
-       edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
-       edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
-}
-
-static void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
-{
-       void __iomem *addr = fsl_chan->edma->membase;
-       u32 ch = fsl_chan->vchan.chan.chan_id;
-
-       edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
-       edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
-}
-
-static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
-                       unsigned int slot, bool enable)
-{
-       u32 ch = fsl_chan->vchan.chan.chan_id;
-       void __iomem *muxaddr;
-       unsigned chans_per_mux, ch_off;
-
-       chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
-       ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
-       muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
-       slot = EDMAMUX_CHCFG_SOURCE(slot);
-
-       if (enable)
-               iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
-       else
-               iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
-}
-
-static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
-{
-       switch (addr_width) {
-       case 1:
-               return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
-       case 2:
-               return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
-       case 4:
-               return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
-       case 8:
-               return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
-       default:
-               return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
-       }
-}
-
-static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
-{
-       struct fsl_edma_desc *fsl_desc;
-       int i;
-
-       fsl_desc = to_fsl_edma_desc(vdesc);
-       for (i = 0; i < fsl_desc->n_tcds; i++)
-               dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
-                             fsl_desc->tcd[i].ptcd);
-       kfree(fsl_desc);
-}
-
-static int fsl_edma_terminate_all(struct dma_chan *chan)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       unsigned long flags;
-       LIST_HEAD(head);
-
-       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-       fsl_edma_disable_request(fsl_chan);
-       fsl_chan->edesc = NULL;
-       fsl_chan->idle = true;
-       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
-       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
-       return 0;
-}
-
-static int fsl_edma_pause(struct dma_chan *chan)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       unsigned long flags;
-
-       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-       if (fsl_chan->edesc) {
-               fsl_edma_disable_request(fsl_chan);
-               fsl_chan->status = DMA_PAUSED;
-               fsl_chan->idle = true;
-       }
-       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-       return 0;
-}
-
-static int fsl_edma_resume(struct dma_chan *chan)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       unsigned long flags;
-
-       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-       if (fsl_chan->edesc) {
-               fsl_edma_enable_request(fsl_chan);
-               fsl_chan->status = DMA_IN_PROGRESS;
-               fsl_chan->idle = false;
-       }
-       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-       return 0;
-}
-
-static int fsl_edma_slave_config(struct dma_chan *chan,
-                                struct dma_slave_config *cfg)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-
-       fsl_chan->fsc.dir = cfg->direction;
-       if (cfg->direction == DMA_DEV_TO_MEM) {
-               fsl_chan->fsc.dev_addr = cfg->src_addr;
-               fsl_chan->fsc.addr_width = cfg->src_addr_width;
-               fsl_chan->fsc.burst = cfg->src_maxburst;
-               fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
-       } else if (cfg->direction == DMA_MEM_TO_DEV) {
-               fsl_chan->fsc.dev_addr = cfg->dst_addr;
-               fsl_chan->fsc.addr_width = cfg->dst_addr_width;
-               fsl_chan->fsc.burst = cfg->dst_maxburst;
-               fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
-       } else {
-                       return -EINVAL;
-       }
-       return 0;
-}
-
-static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
-               struct virt_dma_desc *vdesc, bool in_progress)
-{
-       struct fsl_edma_desc *edesc = fsl_chan->edesc;
-       void __iomem *addr = fsl_chan->edma->membase;
-       u32 ch = fsl_chan->vchan.chan.chan_id;
-       enum dma_transfer_direction dir = fsl_chan->fsc.dir;
-       dma_addr_t cur_addr, dma_addr;
-       size_t len, size;
-       int i;
-
-       /* calculate the total size in this desc */
-       for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
-               len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
-                       * le16_to_cpu(edesc->tcd[i].vtcd->biter);
-
-       if (!in_progress)
-               return len;
-
-       if (dir == DMA_MEM_TO_DEV)
-               cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
-       else
-               cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
-
-       /* figure out the finished and calculate the residue */
-       for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
-               size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
-                       * le16_to_cpu(edesc->tcd[i].vtcd->biter);
-               if (dir == DMA_MEM_TO_DEV)
-                       dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
-               else
-                       dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
-
-               len -= size;
-               if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
-                       len += dma_addr + size - cur_addr;
-                       break;
-               }
-       }
-
-       return len;
-}
-
-static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
-               dma_cookie_t cookie, struct dma_tx_state *txstate)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       struct virt_dma_desc *vdesc;
-       enum dma_status status;
-       unsigned long flags;
-
-       status = dma_cookie_status(chan, cookie, txstate);
-       if (status == DMA_COMPLETE)
-               return status;
-
-       if (!txstate)
-               return fsl_chan->status;
-
-       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-       vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
-       if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
-               txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, true);
-       else if (vdesc)
-               txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, false);
-       else
-               txstate->residue = 0;
-
-       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-
-       return fsl_chan->status;
-}
-
-static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
-                                 struct fsl_edma_hw_tcd *tcd)
-{
-       struct fsl_edma_engine *edma = fsl_chan->edma;
-       void __iomem *addr = fsl_chan->edma->membase;
-       u32 ch = fsl_chan->vchan.chan.chan_id;
-
-       /*
-        * TCD parameters are stored in struct fsl_edma_hw_tcd in little
-        * endian format. However, we need to load the TCD registers in
-        * big- or little-endian obeying the eDMA engine model endian.
-        */
-       edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch));
-       edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch));
-       edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch));
-
-       edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch));
-       edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch));
-
-       edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch));
-       edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch));
-
-       edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch));
-       edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch));
-       edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch));
-
-       edma_writel(edma, le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch));
-
-       edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch));
-}
-
-static inline
-void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
-                      u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
-                      u16 biter, u16 doff, u32 dlast_sga, bool major_int,
-                      bool disable_req, bool enable_sg)
-{
-       u16 csr = 0;
-
-       /*
-        * eDMA hardware SGs require the TCDs to be stored in little
-        * endian format irrespective of the register endian model.
-        * So we put the value in little endian in memory, waiting
-        * for fsl_edma_set_tcd_regs doing the swap.
-        */
-       tcd->saddr = cpu_to_le32(src);
-       tcd->daddr = cpu_to_le32(dst);
-
-       tcd->attr = cpu_to_le16(attr);
-
-       tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
-
-       tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
-       tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
-
-       tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
-       tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
-
-       tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
-
-       tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
-       if (major_int)
-               csr |= EDMA_TCD_CSR_INT_MAJOR;
-
-       if (disable_req)
-               csr |= EDMA_TCD_CSR_D_REQ;
-
-       if (enable_sg)
-               csr |= EDMA_TCD_CSR_E_SG;
-
-       tcd->csr = cpu_to_le16(csr);
-}
-
-static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,
-               int sg_len)
-{
-       struct fsl_edma_desc *fsl_desc;
-       int i;
-
-       fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma_sw_tcd) * sg_len,
-                               GFP_NOWAIT);
-       if (!fsl_desc)
-               return NULL;
-
-       fsl_desc->echan = fsl_chan;
-       fsl_desc->n_tcds = sg_len;
-       for (i = 0; i < sg_len; i++) {
-               fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
-                                       GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
-               if (!fsl_desc->tcd[i].vtcd)
-                       goto err;
-       }
-       return fsl_desc;
-
-err:
-       while (--i >= 0)
-               dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
-                               fsl_desc->tcd[i].ptcd);
-       kfree(fsl_desc);
-       return NULL;
-}
-
-static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
-               struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-               size_t period_len, enum dma_transfer_direction direction,
-               unsigned long flags)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       struct fsl_edma_desc *fsl_desc;
-       dma_addr_t dma_buf_next;
-       int sg_len, i;
-       u32 src_addr, dst_addr, last_sg, nbytes;
-       u16 soff, doff, iter;
-
-       if (!is_slave_direction(fsl_chan->fsc.dir))
-               return NULL;
-
-       sg_len = buf_len / period_len;
-       fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
-       if (!fsl_desc)
-               return NULL;
-       fsl_desc->iscyclic = true;
-
-       dma_buf_next = dma_addr;
-       nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
-       iter = period_len / nbytes;
-
-       for (i = 0; i < sg_len; i++) {
-               if (dma_buf_next >= dma_addr + buf_len)
-                       dma_buf_next = dma_addr;
-
-               /* get next sg's physical address */
-               last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
-
-               if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
-                       src_addr = dma_buf_next;
-                       dst_addr = fsl_chan->fsc.dev_addr;
-                       soff = fsl_chan->fsc.addr_width;
-                       doff = 0;
-               } else {
-                       src_addr = fsl_chan->fsc.dev_addr;
-                       dst_addr = dma_buf_next;
-                       soff = 0;
-                       doff = fsl_chan->fsc.addr_width;
-               }
-
-               fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
-                                 fsl_chan->fsc.attr, soff, nbytes, 0, iter,
-                                 iter, doff, last_sg, true, false, true);
-               dma_buf_next += period_len;
-       }
-
-       return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
-}
-
-static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
-               struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_transfer_direction direction,
-               unsigned long flags, void *context)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       struct fsl_edma_desc *fsl_desc;
-       struct scatterlist *sg;
-       u32 src_addr, dst_addr, last_sg, nbytes;
-       u16 soff, doff, iter;
-       int i;
-
-       if (!is_slave_direction(fsl_chan->fsc.dir))
-               return NULL;
-
-       fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
-       if (!fsl_desc)
-               return NULL;
-       fsl_desc->iscyclic = false;
-
-       nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
-       for_each_sg(sgl, sg, sg_len, i) {
-               /* get next sg's physical address */
-               last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
-
-               if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
-                       src_addr = sg_dma_address(sg);
-                       dst_addr = fsl_chan->fsc.dev_addr;
-                       soff = fsl_chan->fsc.addr_width;
-                       doff = 0;
-               } else {
-                       src_addr = fsl_chan->fsc.dev_addr;
-                       dst_addr = sg_dma_address(sg);
-                       soff = 0;
-                       doff = fsl_chan->fsc.addr_width;
-               }
-
-               iter = sg_dma_len(sg) / nbytes;
-               if (i < sg_len - 1) {
-                       last_sg = fsl_desc->tcd[(i + 1)].ptcd;
-                       fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
-                                         dst_addr, fsl_chan->fsc.attr, soff,
-                                         nbytes, 0, iter, iter, doff, last_sg,
-                                         false, false, true);
-               } else {
-                       last_sg = 0;
-                       fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
-                                         dst_addr, fsl_chan->fsc.attr, soff,
-                                         nbytes, 0, iter, iter, doff, last_sg,
-                                         true, true, false);
-               }
-       }
-
-       return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
-}
-
-static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
-{
-       struct virt_dma_desc *vdesc;
-
-       vdesc = vchan_next_desc(&fsl_chan->vchan);
-       if (!vdesc)
-               return;
-       fsl_chan->edesc = to_fsl_edma_desc(vdesc);
-       fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
-       fsl_edma_enable_request(fsl_chan);
-       fsl_chan->status = DMA_IN_PROGRESS;
-       fsl_chan->idle = false;
-}
+#include "fsl-edma-common.h"
 
 static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
 {
        struct fsl_edma_engine *fsl_edma = dev_id;
        unsigned int intr, ch;
-       void __iomem *base_addr;
+       struct edma_regs *regs = &fsl_edma->regs;
        struct fsl_edma_chan *fsl_chan;
 
-       base_addr = fsl_edma->membase;
-
-       intr = edma_readl(fsl_edma, base_addr + EDMA_INTR);
+       intr = edma_readl(fsl_edma, regs->intl);
        if (!intr)
                return IRQ_NONE;
 
        for (ch = 0; ch < fsl_edma->n_chans; ch++) {
                if (intr & (0x1 << ch)) {
-                       edma_writeb(fsl_edma, EDMA_CINT_CINT(ch),
-                               base_addr + EDMA_CINT);
+                       edma_writeb(fsl_edma, EDMA_CINT_CINT(ch), regs->cint);
 
                        fsl_chan = &fsl_edma->chans[ch];
 
@@ -705,16 +65,16 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
 {
        struct fsl_edma_engine *fsl_edma = dev_id;
        unsigned int err, ch;
+       struct edma_regs *regs = &fsl_edma->regs;
 
-       err = edma_readl(fsl_edma, fsl_edma->membase + EDMA_ERR);
+       err = edma_readl(fsl_edma, regs->errl);
        if (!err)
                return IRQ_NONE;
 
        for (ch = 0; ch < fsl_edma->n_chans; ch++) {
                if (err & (0x1 << ch)) {
                        fsl_edma_disable_request(&fsl_edma->chans[ch]);
-                       edma_writeb(fsl_edma, EDMA_CERR_CERR(ch),
-                               fsl_edma->membase + EDMA_CERR);
+                       edma_writeb(fsl_edma, EDMA_CERR_CERR(ch), regs->cerr);
                        fsl_edma->chans[ch].status = DMA_ERROR;
                        fsl_edma->chans[ch].idle = true;
                }
@@ -730,25 +90,6 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
        return fsl_edma_err_handler(irq, dev_id);
 }
 
-static void fsl_edma_issue_pending(struct dma_chan *chan)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       unsigned long flags;
-
-       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-
-       if (unlikely(fsl_chan->pm_state != RUNNING)) {
-               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-               /* cannot submit due to suspend */
-               return;
-       }
-
-       if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
-               fsl_edma_xfer_desc(fsl_chan);
-
-       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-}
-
 static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
                struct of_dma *ofdma)
 {
@@ -781,34 +122,6 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
        return NULL;
 }
 
-static int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-
-       fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
-                               sizeof(struct fsl_edma_hw_tcd),
-                               32, 0);
-       return 0;
-}
-
-static void fsl_edma_free_chan_resources(struct dma_chan *chan)
-{
-       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-       unsigned long flags;
-       LIST_HEAD(head);
-
-       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-       fsl_edma_disable_request(fsl_chan);
-       fsl_edma_chan_mux(fsl_chan, 0, false);
-       fsl_chan->edesc = NULL;
-       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
-       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-
-       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
-       dma_pool_destroy(fsl_chan->tcd_pool);
-       fsl_chan->tcd_pool = NULL;
-}
-
 static int
 fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
 {
@@ -876,6 +189,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct fsl_edma_engine *fsl_edma;
        struct fsl_edma_chan *fsl_chan;
+       struct edma_regs *regs;
        struct resource *res;
        int len, chans;
        int ret, i;
@@ -891,6 +205,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
        if (!fsl_edma)
                return -ENOMEM;
 
+       fsl_edma->version = v1;
        fsl_edma->n_chans = chans;
        mutex_init(&fsl_edma->fsl_edma_mutex);
 
@@ -899,6 +214,9 @@ static int fsl_edma_probe(struct platform_device *pdev)
        if (IS_ERR(fsl_edma->membase))
                return PTR_ERR(fsl_edma->membase);
 
+       fsl_edma_setup_regs(fsl_edma);
+       regs = &fsl_edma->regs;
+
        for (i = 0; i < DMAMUX_NR; i++) {
                char clkname[32];
 
@@ -939,11 +257,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
                fsl_chan->vchan.desc_free = fsl_edma_free_desc;
                vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
 
-               edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+               edma_writew(fsl_edma, 0x0, &regs->tcd[i].csr);
                fsl_edma_chan_mux(fsl_chan, 0, false);
        }
 
-       edma_writel(fsl_edma, ~0, fsl_edma->membase + EDMA_INTR);
+       edma_writel(fsl_edma, ~0, regs->intl);
        ret = fsl_edma_irq_init(pdev, fsl_edma);
        if (ret)
                return ret;
@@ -990,22 +308,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
        }
 
        /* enable round robin arbitration */
-       edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, fsl_edma->membase + EDMA_CR);
+       edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
 
        return 0;
 }
 
-static void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
-{
-       struct fsl_edma_chan *chan, *_chan;
-
-       list_for_each_entry_safe(chan, _chan,
-                               &dmadev->channels, vchan.chan.device_node) {
-               list_del(&chan->vchan.chan.device_node);
-               tasklet_kill(&chan->vchan.task);
-       }
-}
-
 static int fsl_edma_remove(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -1048,18 +355,18 @@ static int fsl_edma_resume_early(struct device *dev)
 {
        struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
        struct fsl_edma_chan *fsl_chan;
+       struct edma_regs *regs = &fsl_edma->regs;
        int i;
 
        for (i = 0; i < fsl_edma->n_chans; i++) {
                fsl_chan = &fsl_edma->chans[i];
                fsl_chan->pm_state = RUNNING;
-               edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+               edma_writew(fsl_edma, 0x0, &regs->tcd[i].csr);
                if (fsl_chan->slave_id != 0)
                        fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true);
        }
 
-       edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA,
-                       fsl_edma->membase + EDMA_CR);
+       edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
 
        return 0;
 }
index 1117b51..9d360a3 100644 (file)
@@ -987,7 +987,7 @@ static void dma_do_tasklet(unsigned long data)
 
        chan_dbg(chan, "tasklet entry\n");
 
-       spin_lock_bh(&chan->desc_lock);
+       spin_lock(&chan->desc_lock);
 
        /* the hardware is now idle and ready for more */
        chan->idle = true;
@@ -995,7 +995,7 @@ static void dma_do_tasklet(unsigned long data)
        /* Run all cleanup for descriptors which have been completed */
        fsldma_cleanup_descriptors(chan);
 
-       spin_unlock_bh(&chan->desc_lock);
+       spin_unlock(&chan->desc_lock);
 
        chan_dbg(chan, "tasklet exit\n");
 }
index 202ffa9..e06f202 100644 (file)
@@ -348,10 +348,6 @@ static int hsu_dma_slave_config(struct dma_chan *chan,
 {
        struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan);
 
-       /* Check if chan will be configured for slave transfers */
-       if (!is_slave_direction(config->direction))
-               return -EINVAL;
-
        memcpy(&hsuc->config, config, sizeof(hsuc->config));
 
        return 0;
index 1fbf9cb..0baf979 100644 (file)
@@ -142,9 +142,8 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c,
 {
        struct idma64_chan *idma64c = &idma64->chan[c];
        struct idma64_desc *desc;
-       unsigned long flags;
 
-       spin_lock_irqsave(&idma64c->vchan.lock, flags);
+       spin_lock(&idma64c->vchan.lock);
        desc = idma64c->desc;
        if (desc) {
                if (status_err & (1 << c)) {
@@ -161,7 +160,7 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c,
                if (idma64c->desc == NULL || desc->status == DMA_ERROR)
                        idma64_stop_transfer(idma64c);
        }
-       spin_unlock_irqrestore(&idma64c->vchan.lock, flags);
+       spin_unlock(&idma64c->vchan.lock);
 }
 
 static irqreturn_t idma64_irq(int irq, void *dev)
@@ -408,10 +407,6 @@ static int idma64_slave_config(struct dma_chan *chan,
 {
        struct idma64_chan *idma64c = to_idma64_chan(chan);
 
-       /* Check if chan will be configured for slave transfers */
-       if (!is_slave_direction(config->direction))
-               return -EINVAL;
-
        memcpy(&idma64c->config, config, sizeof(idma64c->config));
 
        convert_burst(&idma64c->config.src_maxburst);
index 75b6ff0..c2fff3f 100644 (file)
@@ -162,6 +162,7 @@ struct imxdma_channel {
        bool                            enabled_2d;
        int                             slot_2d;
        unsigned int                    irq;
+       struct dma_slave_config         config;
 };
 
 enum imx_dma_type {
@@ -675,14 +676,15 @@ static int imxdma_terminate_all(struct dma_chan *chan)
        return 0;
 }
 
-static int imxdma_config(struct dma_chan *chan,
-                        struct dma_slave_config *dmaengine_cfg)
+static int imxdma_config_write(struct dma_chan *chan,
+                              struct dma_slave_config *dmaengine_cfg,
+                              enum dma_transfer_direction direction)
 {
        struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
        struct imxdma_engine *imxdma = imxdmac->imxdma;
        unsigned int mode = 0;
 
-       if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+       if (direction == DMA_DEV_TO_MEM) {
                imxdmac->per_address = dmaengine_cfg->src_addr;
                imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
                imxdmac->word_size = dmaengine_cfg->src_addr_width;
@@ -723,6 +725,16 @@ static int imxdma_config(struct dma_chan *chan,
        return 0;
 }
 
+static int imxdma_config(struct dma_chan *chan,
+                        struct dma_slave_config *dmaengine_cfg)
+{
+       struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+
+       memcpy(&imxdmac->config, dmaengine_cfg, sizeof(*dmaengine_cfg));
+
+       return 0;
+}
+
 static enum dma_status imxdma_tx_status(struct dma_chan *chan,
                                            dma_cookie_t cookie,
                                            struct dma_tx_state *txstate)
@@ -905,6 +917,8 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
        desc->desc.callback = NULL;
        desc->desc.callback_param = NULL;
 
+       imxdma_config_write(chan, &imxdmac->config, direction);
+
        return &desc->desc;
 }
 
index 4fa4c06..0fec3c5 100644 (file)
@@ -129,7 +129,7 @@ static void
 ioat_init_channel(struct ioatdma_device *ioat_dma,
                  struct ioatdma_chan *ioat_chan, int idx);
 static void ioat_intr_quirk(struct ioatdma_device *ioat_dma);
-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
+static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
 static int ioat3_dma_self_test(struct ioatdma_device *ioat_dma);
 
 static int ioat_dca_enabled = 1;
@@ -575,7 +575,7 @@ static void ioat_dma_remove(struct ioatdma_device *ioat_dma)
  * ioat_enumerate_channels - find and initialize the device's channels
  * @ioat_dma: the ioat dma device to be enumerated
  */
-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
+static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
 {
        struct ioatdma_chan *ioat_chan;
        struct device *dev = &ioat_dma->pdev->dev;
@@ -594,7 +594,7 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
        xfercap_log = readb(ioat_dma->reg_base + IOAT_XFERCAP_OFFSET);
        xfercap_log &= 0x1f; /* bits [4:0] valid */
        if (xfercap_log == 0)
-               return 0;
+               return;
        dev_dbg(dev, "%s: xfercap = %d\n", __func__, 1 << xfercap_log);
 
        for (i = 0; i < dma->chancnt; i++) {
@@ -611,7 +611,6 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
                }
        }
        dma->chancnt = i;
-       return i;
 }
 
 /**
@@ -1205,8 +1204,15 @@ static void ioat_shutdown(struct pci_dev *pdev)
 
                spin_lock_bh(&ioat_chan->prep_lock);
                set_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
-               del_timer_sync(&ioat_chan->timer);
                spin_unlock_bh(&ioat_chan->prep_lock);
+               /*
+                * Synchronization rule for del_timer_sync():
+                *  - The caller must not hold locks which would prevent
+                *    completion of the timer's handler.
+                * So prep_lock cannot be held before calling it.
+                */
+               del_timer_sync(&ioat_chan->timer);
+
                /* this should quiesce then reset */
                ioat_reset_hw(ioat_chan);
        }
index 6bfa217..fdec2b6 100644 (file)
@@ -87,10 +87,10 @@ struct k3_dma_chan {
        struct virt_dma_chan    vc;
        struct k3_dma_phy       *phy;
        struct list_head        node;
-       enum dma_transfer_direction dir;
        dma_addr_t              dev_addr;
        enum dma_status         status;
        bool                    cyclic;
+       struct dma_slave_config slave_config;
 };
 
 struct k3_dma_phy {
@@ -118,6 +118,10 @@ struct k3_dma_dev {
 
 #define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
 
+static int k3_dma_config_write(struct dma_chan *chan,
+                              enum dma_transfer_direction dir,
+                              struct dma_slave_config *cfg);
+
 static struct k3_dma_chan *to_k3_chan(struct dma_chan *chan)
 {
        return container_of(chan, struct k3_dma_chan, vc.chan);
@@ -501,14 +505,8 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
                copy = min_t(size_t, len, DMA_MAX_SIZE);
                k3_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
 
-               if (c->dir == DMA_MEM_TO_DEV) {
-                       src += copy;
-               } else if (c->dir == DMA_DEV_TO_MEM) {
-                       dst += copy;
-               } else {
-                       src += copy;
-                       dst += copy;
-               }
+               src += copy;
+               dst += copy;
                len -= copy;
        } while (len);
 
@@ -542,6 +540,7 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
        if (!ds)
                return NULL;
        num = 0;
+       k3_dma_config_write(chan, dir, &c->slave_config);
 
        for_each_sg(sgl, sg, sglen, i) {
                addr = sg_dma_address(sg);
@@ -602,6 +601,7 @@ k3_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
        avail = buf_len;
        total = avail;
        num = 0;
+       k3_dma_config_write(chan, dir, &c->slave_config);
 
        if (period_len < modulo)
                modulo = period_len;
@@ -642,18 +642,26 @@ static int k3_dma_config(struct dma_chan *chan,
                         struct dma_slave_config *cfg)
 {
        struct k3_dma_chan *c = to_k3_chan(chan);
+
+       memcpy(&c->slave_config, cfg, sizeof(*cfg));
+
+       return 0;
+}
+
+static int k3_dma_config_write(struct dma_chan *chan,
+                              enum dma_transfer_direction dir,
+                              struct dma_slave_config *cfg)
+{
+       struct k3_dma_chan *c = to_k3_chan(chan);
        u32 maxburst = 0, val = 0;
        enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
 
-       if (cfg == NULL)
-               return -EINVAL;
-       c->dir = cfg->direction;
-       if (c->dir == DMA_DEV_TO_MEM) {
+       if (dir == DMA_DEV_TO_MEM) {
                c->ccfg = CX_CFG_DSTINCR;
                c->dev_addr = cfg->src_addr;
                maxburst = cfg->src_maxburst;
                width = cfg->src_addr_width;
-       } else if (c->dir == DMA_MEM_TO_DEV) {
+       } else if (dir == DMA_MEM_TO_DEV) {
                c->ccfg = CX_CFG_SRCINCR;
                c->dev_addr = cfg->dst_addr;
                maxburst = cfg->dst_maxburst;
diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c
new file mode 100644 (file)
index 0000000..5de1b07
--- /dev/null
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
+// Copyright (c) 2017 Sysam, Angelo Dureghello  <angelo@sysam.it>
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dma-mcf-edma.h>
+
+#include "fsl-edma-common.h"
+
+#define EDMA_CHANNELS          64
+#define EDMA_MASK_CH(x)                ((x) & GENMASK(5, 0))
+
+static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
+{
+       struct fsl_edma_engine *mcf_edma = dev_id;
+       struct edma_regs *regs = &mcf_edma->regs;
+       unsigned int ch;
+       struct fsl_edma_chan *mcf_chan;
+       u64 intmap;
+
+       intmap = ioread32(regs->inth);
+       intmap <<= 32;
+       intmap |= ioread32(regs->intl);
+       if (!intmap)
+               return IRQ_NONE;
+
+       for (ch = 0; ch < mcf_edma->n_chans; ch++) {
+               if (intmap & BIT(ch)) {
+                       iowrite8(EDMA_MASK_CH(ch), regs->cint);
+
+                       mcf_chan = &mcf_edma->chans[ch];
+
+                       spin_lock(&mcf_chan->vchan.lock);
+                       if (!mcf_chan->edesc->iscyclic) {
+                               list_del(&mcf_chan->edesc->vdesc.node);
+                               vchan_cookie_complete(&mcf_chan->edesc->vdesc);
+                               mcf_chan->edesc = NULL;
+                               mcf_chan->status = DMA_COMPLETE;
+                               mcf_chan->idle = true;
+                       } else {
+                               vchan_cyclic_callback(&mcf_chan->edesc->vdesc);
+                       }
+
+                       if (!mcf_chan->edesc)
+                               fsl_edma_xfer_desc(mcf_chan);
+
+                       spin_unlock(&mcf_chan->vchan.lock);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
+{
+       struct fsl_edma_engine *mcf_edma = dev_id;
+       struct edma_regs *regs = &mcf_edma->regs;
+       unsigned int err, ch;
+
+       err = ioread32(regs->errl);
+       if (!err)
+               return IRQ_NONE;
+
+       for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) {
+               if (err & BIT(ch)) {
+                       fsl_edma_disable_request(&mcf_edma->chans[ch]);
+                       iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
+                       mcf_edma->chans[ch].status = DMA_ERROR;
+                       mcf_edma->chans[ch].idle = true;
+               }
+       }
+
+       err = ioread32(regs->errh);
+       if (!err)
+               return IRQ_NONE;
+
+       for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) {
+               if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) {
+                       fsl_edma_disable_request(&mcf_edma->chans[ch]);
+                       iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
+                       mcf_edma->chans[ch].status = DMA_ERROR;
+                       mcf_edma->chans[ch].idle = true;
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int mcf_edma_irq_init(struct platform_device *pdev,
+                               struct fsl_edma_engine *mcf_edma)
+{
+       int ret = 0, i;
+       struct resource *res;
+
+       res = platform_get_resource_byname(pdev,
+                               IORESOURCE_IRQ, "edma-tx-00-15");
+       if (!res)
+               return -1;
+
+       for (ret = 0, i = res->start; i <= res->end; ++i)
+               ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
+       if (ret)
+               return ret;
+
+       res = platform_get_resource_byname(pdev,
+                       IORESOURCE_IRQ, "edma-tx-16-55");
+       if (!res)
+               return -1;
+
+       for (ret = 0, i = res->start; i <= res->end; ++i)
+               ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
+       if (ret)
+               return ret;
+
+       ret = platform_get_irq_byname(pdev, "edma-tx-56-63");
+       if (ret != -ENXIO) {
+               ret = request_irq(ret, mcf_edma_tx_handler,
+                                 0, "eDMA", mcf_edma);
+               if (ret)
+                       return ret;
+       }
+
+       ret = platform_get_irq_byname(pdev, "edma-err");
+       if (ret != -ENXIO) {
+               ret = request_irq(ret, mcf_edma_err_handler,
+                                 0, "eDMA", mcf_edma);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void mcf_edma_irq_free(struct platform_device *pdev,
+                               struct fsl_edma_engine *mcf_edma)
+{
+       int irq;
+       struct resource *res;
+
+       res = platform_get_resource_byname(pdev,
+                       IORESOURCE_IRQ, "edma-tx-00-15");
+       if (res) {
+               for (irq = res->start; irq <= res->end; irq++)
+                       free_irq(irq, mcf_edma);
+       }
+
+       res = platform_get_resource_byname(pdev,
+                       IORESOURCE_IRQ, "edma-tx-16-55");
+       if (res) {
+               for (irq = res->start; irq <= res->end; irq++)
+                       free_irq(irq, mcf_edma);
+       }
+
+       irq = platform_get_irq_byname(pdev, "edma-tx-56-63");
+       if (irq != -ENXIO)
+               free_irq(irq, mcf_edma);
+
+       irq = platform_get_irq_byname(pdev, "edma-err");
+       if (irq != -ENXIO)
+               free_irq(irq, mcf_edma);
+}
+
+static int mcf_edma_probe(struct platform_device *pdev)
+{
+       struct mcf_edma_platform_data *pdata;
+       struct fsl_edma_engine *mcf_edma;
+       struct fsl_edma_chan *mcf_chan;
+       struct edma_regs *regs;
+       struct resource *res;
+       int ret, i, len, chans;
+
+       pdata = dev_get_platdata(&pdev->dev);
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data supplied\n");
+               return -EINVAL;
+       }
+
+       chans = pdata->dma_channels;
+       len = sizeof(*mcf_edma) + sizeof(*mcf_chan) * chans;
+       mcf_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+       if (!mcf_edma)
+               return -ENOMEM;
+
+       mcf_edma->n_chans = chans;
+
+       /* Set up version for ColdFire edma */
+       mcf_edma->version = v2;
+       mcf_edma->big_endian = 1;
+
+       if (!mcf_edma->n_chans) {
+               dev_info(&pdev->dev, "setting default channel number to 64");
+               mcf_edma->n_chans = 64;
+       }
+
+       mutex_init(&mcf_edma->fsl_edma_mutex);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       mcf_edma->membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mcf_edma->membase))
+               return PTR_ERR(mcf_edma->membase);
+
+       fsl_edma_setup_regs(mcf_edma);
+       regs = &mcf_edma->regs;
+
+       INIT_LIST_HEAD(&mcf_edma->dma_dev.channels);
+       for (i = 0; i < mcf_edma->n_chans; i++) {
+               struct fsl_edma_chan *mcf_chan = &mcf_edma->chans[i];
+
+               mcf_chan->edma = mcf_edma;
+               mcf_chan->slave_id = i;
+               mcf_chan->idle = true;
+               mcf_chan->vchan.desc_free = fsl_edma_free_desc;
+               vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev);
+               iowrite32(0x0, &regs->tcd[i].csr);
+       }
+
+       iowrite32(~0, regs->inth);
+       iowrite32(~0, regs->intl);
+
+       ret = mcf_edma_irq_init(pdev, mcf_edma);
+       if (ret)
+               return ret;
+
+       dma_cap_set(DMA_PRIVATE, mcf_edma->dma_dev.cap_mask);
+       dma_cap_set(DMA_SLAVE, mcf_edma->dma_dev.cap_mask);
+       dma_cap_set(DMA_CYCLIC, mcf_edma->dma_dev.cap_mask);
+
+       mcf_edma->dma_dev.dev = &pdev->dev;
+       mcf_edma->dma_dev.device_alloc_chan_resources =
+                       fsl_edma_alloc_chan_resources;
+       mcf_edma->dma_dev.device_free_chan_resources =
+                       fsl_edma_free_chan_resources;
+       mcf_edma->dma_dev.device_config = fsl_edma_slave_config;
+       mcf_edma->dma_dev.device_prep_dma_cyclic =
+                       fsl_edma_prep_dma_cyclic;
+       mcf_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
+       mcf_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
+       mcf_edma->dma_dev.device_pause = fsl_edma_pause;
+       mcf_edma->dma_dev.device_resume = fsl_edma_resume;
+       mcf_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all;
+       mcf_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
+
+       mcf_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
+       mcf_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
+       mcf_edma->dma_dev.directions =
+                       BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+
+       mcf_edma->dma_dev.filter.fn = mcf_edma_filter_fn;
+       mcf_edma->dma_dev.filter.map = pdata->slave_map;
+       mcf_edma->dma_dev.filter.mapcnt = pdata->slavecnt;
+
+       platform_set_drvdata(pdev, mcf_edma);
+
+       ret = dma_async_device_register(&mcf_edma->dma_dev);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Can't register Freescale eDMA engine. (%d)\n", ret);
+               return ret;
+       }
+
+       /* Enable round robin arbitration */
+       iowrite32(EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
+
+       return 0;
+}
+
+static int mcf_edma_remove(struct platform_device *pdev)
+{
+       struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev);
+
+       mcf_edma_irq_free(pdev, mcf_edma);
+       fsl_edma_cleanup_vchan(&mcf_edma->dma_dev);
+       dma_async_device_unregister(&mcf_edma->dma_dev);
+
+       return 0;
+}
+
+static struct platform_driver mcf_edma_driver = {
+       .driver         = {
+               .name   = "mcf-edma",
+       },
+       .probe          = mcf_edma_probe,
+       .remove         = mcf_edma_remove,
+};
+
+bool mcf_edma_filter_fn(struct dma_chan *chan, void *param)
+{
+       if (chan->device->dev->driver == &mcf_edma_driver.driver) {
+               struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan);
+
+               return (mcf_chan->slave_id == (uintptr_t)param);
+       }
+
+       return false;
+}
+EXPORT_SYMBOL(mcf_edma_filter_fn);
+
+static int __init mcf_edma_init(void)
+{
+       return platform_driver_register(&mcf_edma_driver);
+}
+subsys_initcall(mcf_edma_init);
+
+static void __exit mcf_edma_exit(void)
+{
+       platform_driver_unregister(&mcf_edma_driver);
+}
+module_exit(mcf_edma_exit);
+
+MODULE_ALIAS("platform:mcf-edma");
+MODULE_DESCRIPTION("Freescale eDMA engine driver, ColdFire family");
+MODULE_LICENSE("GPL v2");
index 13c68b6..0c56faa 100644 (file)
@@ -116,6 +116,7 @@ struct mmp_tdma_chan {
        u32                             burst_sz;
        enum dma_slave_buswidth         buswidth;
        enum dma_status                 status;
+       struct dma_slave_config         slave_config;
 
        int                             idx;
        enum mmp_tdma_type              type;
@@ -139,6 +140,10 @@ struct mmp_tdma_device {
 
 #define to_mmp_tdma_chan(dchan) container_of(dchan, struct mmp_tdma_chan, chan)
 
+static int mmp_tdma_config_write(struct dma_chan *chan,
+                                enum dma_transfer_direction dir,
+                                struct dma_slave_config *dmaengine_cfg);
+
 static void mmp_tdma_chan_set_desc(struct mmp_tdma_chan *tdmac, dma_addr_t phys)
 {
        writel(phys, tdmac->reg_base + TDNDPR);
@@ -442,6 +447,8 @@ static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
        if (!desc)
                goto err_out;
 
+       mmp_tdma_config_write(chan, direction, &tdmac->slave_config);
+
        while (buf < buf_len) {
                desc = &tdmac->desc_arr[i];
 
@@ -495,7 +502,18 @@ static int mmp_tdma_config(struct dma_chan *chan,
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
 
-       if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+       memcpy(&tdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
+
+       return 0;
+}
+
+static int mmp_tdma_config_write(struct dma_chan *chan,
+                                enum dma_transfer_direction dir,
+                                struct dma_slave_config *dmaengine_cfg)
+{
+       struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+       if (dir == DMA_DEV_TO_MEM) {
                tdmac->dev_addr = dmaengine_cfg->src_addr;
                tdmac->burst_sz = dmaengine_cfg->src_maxburst;
                tdmac->buswidth = dmaengine_cfg->src_addr_width;
@@ -504,7 +522,7 @@ static int mmp_tdma_config(struct dma_chan *chan,
                tdmac->burst_sz = dmaengine_cfg->dst_maxburst;
                tdmac->buswidth = dmaengine_cfg->dst_addr_width;
        }
-       tdmac->dir = dmaengine_cfg->direction;
+       tdmac->dir = dir;
 
        return mmp_tdma_config_chan(chan);
 }
@@ -530,9 +548,6 @@ static void mmp_tdma_issue_pending(struct dma_chan *chan)
 
 static int mmp_tdma_remove(struct platform_device *pdev)
 {
-       struct mmp_tdma_device *tdev = platform_get_drvdata(pdev);
-
-       dma_async_device_unregister(&tdev->device);
        return 0;
 }
 
@@ -696,7 +711,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
        dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
        platform_set_drvdata(pdev, tdev);
 
-       ret = dma_async_device_register(&tdev->device);
+       ret = dmaenginem_async_device_register(&tdev->device);
        if (ret) {
                dev_err(tdev->device.dev, "unable to register\n");
                return ret;
@@ -708,7 +723,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(tdev->device.dev,
                                "failed to register controller\n");
-                       dma_async_device_unregister(&tdev->device);
+                       return ret;
                }
        }
 
index 969534c..7f59535 100644 (file)
@@ -348,9 +348,9 @@ static void mv_xor_tasklet(unsigned long data)
 {
        struct mv_xor_chan *chan = (struct mv_xor_chan *) data;
 
-       spin_lock_bh(&chan->lock);
+       spin_lock(&chan->lock);
        mv_chan_slot_cleanup(chan);
-       spin_unlock_bh(&chan->lock);
+       spin_unlock(&chan->lock);
 }
 
 static struct mv_xor_desc_slot *
index ae5182f..35193b3 100644 (file)
@@ -847,7 +847,7 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
        mxs_dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
        mxs_dma->dma_device.device_issue_pending = mxs_dma_enable_chan;
 
-       ret = dma_async_device_register(&mxs_dma->dma_device);
+       ret = dmaenginem_async_device_register(&mxs_dma->dma_device);
        if (ret) {
                dev_err(mxs_dma->dma_device.dev, "unable to register\n");
                return ret;
@@ -857,7 +857,6 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(mxs_dma->dma_device.dev,
                        "failed to register controller\n");
-               dma_async_device_unregister(&mxs_dma->dma_device);
        }
 
        dev_info(mxs_dma->dma_device.dev, "initialized\n");
index 38d251b..a67b292 100644 (file)
@@ -1092,8 +1092,8 @@ static struct dma_chan *nbpf_of_xlate(struct of_phandle_args *dma_spec,
        if (!dchan)
                return NULL;
 
-       dev_dbg(dchan->device->dev, "Entry %s(%s)\n", __func__,
-               dma_spec->np->name);
+       dev_dbg(dchan->device->dev, "Entry %s(%pOFn)\n", __func__,
+               dma_spec->np);
 
        chan = nbpf_to_chan(dchan);
 
index 7812a63..90bbcef 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_dma.h>
 #include <linux/slab.h>
 #include "virt-dma.h"
 
@@ -161,10 +162,12 @@ struct owl_dma_lli {
  * struct owl_dma_txd - Wrapper for struct dma_async_tx_descriptor
  * @vd: virtual DMA descriptor
  * @lli_list: link list of lli nodes
+ * @cyclic: flag to indicate cyclic transfers
  */
 struct owl_dma_txd {
        struct virt_dma_desc    vd;
        struct list_head        lli_list;
+       bool                    cyclic;
 };
 
 /**
@@ -186,11 +189,15 @@ struct owl_dma_pchan {
  * @vc: wrappped virtual channel
  * @pchan: the physical channel utilized by this channel
  * @txd: active transaction on this channel
+ * @cfg: slave configuration for this channel
+ * @drq: physical DMA request ID for this channel
  */
 struct owl_dma_vchan {
        struct virt_dma_chan    vc;
        struct owl_dma_pchan    *pchan;
        struct owl_dma_txd      *txd;
+       struct dma_slave_config cfg;
+       u8                      drq;
 };
 
 /**
@@ -200,6 +207,7 @@ struct owl_dma_vchan {
  * @clk: clock for the DMA controller
  * @lock: a lock to use when change DMA controller global register
  * @lli_pool: a pool for the LLI descriptors
+ * @irq: interrupt ID for the DMA controller
  * @nr_pchans: the number of physical channels
  * @pchans: array of data for the physical channels
  * @nr_vchans: the number of physical channels
@@ -336,9 +344,11 @@ static struct owl_dma_lli *owl_dma_alloc_lli(struct owl_dma *od)
 
 static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd,
                                           struct owl_dma_lli *prev,
-                                          struct owl_dma_lli *next)
+                                          struct owl_dma_lli *next,
+                                          bool is_cyclic)
 {
-       list_add_tail(&next->node, &txd->lli_list);
+       if (!is_cyclic)
+               list_add_tail(&next->node, &txd->lli_list);
 
        if (prev) {
                prev->hw.next_lli = next->phys;
@@ -351,7 +361,9 @@ static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd,
 static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
                                  struct owl_dma_lli *lli,
                                  dma_addr_t src, dma_addr_t dst,
-                                 u32 len, enum dma_transfer_direction dir)
+                                 u32 len, enum dma_transfer_direction dir,
+                                 struct dma_slave_config *sconfig,
+                                 bool is_cyclic)
 {
        struct owl_dma_lli_hw *hw = &lli->hw;
        u32 mode;
@@ -364,6 +376,32 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
                        OWL_DMA_MODE_DT_DCU | OWL_DMA_MODE_SAM_INC |
                        OWL_DMA_MODE_DAM_INC;
 
+               break;
+       case DMA_MEM_TO_DEV:
+               mode |= OWL_DMA_MODE_TS(vchan->drq)
+                       | OWL_DMA_MODE_ST_DCU | OWL_DMA_MODE_DT_DEV
+                       | OWL_DMA_MODE_SAM_INC | OWL_DMA_MODE_DAM_CONST;
+
+               /*
+                * Hardware only supports 32bit and 8bit buswidth. Since the
+                * default is 32bit, select 8bit only when requested.
+                */
+               if (sconfig->dst_addr_width == DMA_SLAVE_BUSWIDTH_1_BYTE)
+                       mode |= OWL_DMA_MODE_NDDBW_8BIT;
+
+               break;
+       case DMA_DEV_TO_MEM:
+                mode |= OWL_DMA_MODE_TS(vchan->drq)
+                       | OWL_DMA_MODE_ST_DEV | OWL_DMA_MODE_DT_DCU
+                       | OWL_DMA_MODE_SAM_CONST | OWL_DMA_MODE_DAM_INC;
+
+               /*
+                * Hardware only supports 32bit and 8bit buswidth. Since the
+                * default is 32bit, select 8bit only when requested.
+                */
+               if (sconfig->src_addr_width == DMA_SLAVE_BUSWIDTH_1_BYTE)
+                       mode |= OWL_DMA_MODE_NDDBW_8BIT;
+
                break;
        default:
                return -EINVAL;
@@ -381,7 +419,10 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
                                 OWL_DMA_LLC_SAV_LOAD_NEXT |
                                 OWL_DMA_LLC_DAV_LOAD_NEXT);
 
-       hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK);
+       if (is_cyclic)
+               hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_BLOCK);
+       else
+               hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK);
 
        return 0;
 }
@@ -443,6 +484,16 @@ static void owl_dma_terminate_pchan(struct owl_dma *od,
        spin_unlock_irqrestore(&od->lock, flags);
 }
 
+static void owl_dma_pause_pchan(struct owl_dma_pchan *pchan)
+{
+       pchan_writel(pchan, 1, OWL_DMAX_PAUSE);
+}
+
+static void owl_dma_resume_pchan(struct owl_dma_pchan *pchan)
+{
+       pchan_writel(pchan, 0, OWL_DMAX_PAUSE);
+}
+
 static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan)
 {
        struct owl_dma *od = to_owl_dma(vchan->vc.chan.device);
@@ -464,7 +515,10 @@ static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan)
        lli = list_first_entry(&txd->lli_list,
                               struct owl_dma_lli, node);
 
-       int_ctl = OWL_DMA_INTCTL_SUPER_BLOCK;
+       if (txd->cyclic)
+               int_ctl = OWL_DMA_INTCTL_BLOCK;
+       else
+               int_ctl = OWL_DMA_INTCTL_SUPER_BLOCK;
 
        pchan_writel(pchan, OWL_DMAX_MODE, OWL_DMA_MODE_LME);
        pchan_writel(pchan, OWL_DMAX_LINKLIST_CTL,
@@ -627,6 +681,54 @@ static int owl_dma_terminate_all(struct dma_chan *chan)
        return 0;
 }
 
+static int owl_dma_config(struct dma_chan *chan,
+                         struct dma_slave_config *config)
+{
+       struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+
+       /* Reject definitely invalid configurations */
+       if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
+           config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
+               return -EINVAL;
+
+       memcpy(&vchan->cfg, config, sizeof(struct dma_slave_config));
+
+       return 0;
+}
+
+static int owl_dma_pause(struct dma_chan *chan)
+{
+       struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&vchan->vc.lock, flags);
+
+       owl_dma_pause_pchan(vchan->pchan);
+
+       spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+       return 0;
+}
+
+static int owl_dma_resume(struct dma_chan *chan)
+{
+       struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+       unsigned long flags;
+
+       if (!vchan->pchan && !vchan->txd)
+               return 0;
+
+       dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
+
+       spin_lock_irqsave(&vchan->vc.lock, flags);
+
+       owl_dma_resume_pchan(vchan->pchan);
+
+       spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+       return 0;
+}
+
 static u32 owl_dma_getbytes_chan(struct owl_dma_vchan *vchan)
 {
        struct owl_dma_pchan *pchan;
@@ -754,13 +856,14 @@ static struct dma_async_tx_descriptor
                bytes = min_t(size_t, (len - offset), OWL_DMA_FRAME_MAX_LENGTH);
 
                ret = owl_dma_cfg_lli(vchan, lli, src + offset, dst + offset,
-                                     bytes, DMA_MEM_TO_MEM);
+                                     bytes, DMA_MEM_TO_MEM,
+                                     &vchan->cfg, txd->cyclic);
                if (ret) {
                        dev_warn(chan2dev(chan), "failed to config lli\n");
                        goto err_txd_free;
                }
 
-               prev = owl_dma_add_lli(txd, prev, lli);
+               prev = owl_dma_add_lli(txd, prev, lli, false);
        }
 
        return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
@@ -770,6 +873,133 @@ err_txd_free:
        return NULL;
 }
 
+static struct dma_async_tx_descriptor
+               *owl_dma_prep_slave_sg(struct dma_chan *chan,
+                                      struct scatterlist *sgl,
+                                      unsigned int sg_len,
+                                      enum dma_transfer_direction dir,
+                                      unsigned long flags, void *context)
+{
+       struct owl_dma *od = to_owl_dma(chan->device);
+       struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+       struct dma_slave_config *sconfig = &vchan->cfg;
+       struct owl_dma_txd *txd;
+       struct owl_dma_lli *lli, *prev = NULL;
+       struct scatterlist *sg;
+       dma_addr_t addr, src = 0, dst = 0;
+       size_t len;
+       int ret, i;
+
+       txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+       if (!txd)
+               return NULL;
+
+       INIT_LIST_HEAD(&txd->lli_list);
+
+       for_each_sg(sgl, sg, sg_len, i) {
+               addr = sg_dma_address(sg);
+               len = sg_dma_len(sg);
+
+               if (len > OWL_DMA_FRAME_MAX_LENGTH) {
+                       dev_err(od->dma.dev,
+                               "frame length exceeds max supported length");
+                       goto err_txd_free;
+               }
+
+               lli = owl_dma_alloc_lli(od);
+               if (!lli) {
+                       dev_err(chan2dev(chan), "failed to allocate lli");
+                       goto err_txd_free;
+               }
+
+               if (dir == DMA_MEM_TO_DEV) {
+                       src = addr;
+                       dst = sconfig->dst_addr;
+               } else {
+                       src = sconfig->src_addr;
+                       dst = addr;
+               }
+
+               ret = owl_dma_cfg_lli(vchan, lli, src, dst, len, dir, sconfig,
+                                     txd->cyclic);
+               if (ret) {
+                       dev_warn(chan2dev(chan), "failed to config lli");
+                       goto err_txd_free;
+               }
+
+               prev = owl_dma_add_lli(txd, prev, lli, false);
+       }
+
+       return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+
+err_txd_free:
+       owl_dma_free_txd(od, txd);
+
+       return NULL;
+}
+
+static struct dma_async_tx_descriptor
+               *owl_prep_dma_cyclic(struct dma_chan *chan,
+                                    dma_addr_t buf_addr, size_t buf_len,
+                                    size_t period_len,
+                                    enum dma_transfer_direction dir,
+                                    unsigned long flags)
+{
+       struct owl_dma *od = to_owl_dma(chan->device);
+       struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+       struct dma_slave_config *sconfig = &vchan->cfg;
+       struct owl_dma_txd *txd;
+       struct owl_dma_lli *lli, *prev = NULL, *first = NULL;
+       dma_addr_t src = 0, dst = 0;
+       unsigned int periods = buf_len / period_len;
+       int ret, i;
+
+       txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+       if (!txd)
+               return NULL;
+
+       INIT_LIST_HEAD(&txd->lli_list);
+       txd->cyclic = true;
+
+       for (i = 0; i < periods; i++) {
+               lli = owl_dma_alloc_lli(od);
+               if (!lli) {
+                       dev_warn(chan2dev(chan), "failed to allocate lli");
+                       goto err_txd_free;
+               }
+
+               if (dir == DMA_MEM_TO_DEV) {
+                       src = buf_addr + (period_len * i);
+                       dst = sconfig->dst_addr;
+               } else if (dir == DMA_DEV_TO_MEM) {
+                       src = sconfig->src_addr;
+                       dst = buf_addr + (period_len * i);
+               }
+
+               ret = owl_dma_cfg_lli(vchan, lli, src, dst, period_len,
+                                     dir, sconfig, txd->cyclic);
+               if (ret) {
+                       dev_warn(chan2dev(chan), "failed to config lli");
+                       goto err_txd_free;
+               }
+
+               if (!first)
+                       first = lli;
+
+               prev = owl_dma_add_lli(txd, prev, lli, false);
+       }
+
+       /* close the cyclic list */
+       owl_dma_add_lli(txd, prev, first, true);
+
+       return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+
+err_txd_free:
+       owl_dma_free_txd(od, txd);
+
+       return NULL;
+}
+
 static void owl_dma_free_chan_resources(struct dma_chan *chan)
 {
        struct owl_dma_vchan *vchan = to_owl_vchan(chan);
@@ -790,6 +1020,27 @@ static inline void owl_dma_free(struct owl_dma *od)
        }
 }
 
+static struct dma_chan *owl_dma_of_xlate(struct of_phandle_args *dma_spec,
+                                        struct of_dma *ofdma)
+{
+       struct owl_dma *od = ofdma->of_dma_data;
+       struct owl_dma_vchan *vchan;
+       struct dma_chan *chan;
+       u8 drq = dma_spec->args[0];
+
+       if (drq > od->nr_vchans)
+               return NULL;
+
+       chan = dma_get_any_slave_channel(&od->dma);
+       if (!chan)
+               return NULL;
+
+       vchan = to_owl_vchan(chan);
+       vchan->drq = drq;
+
+       return chan;
+}
+
 static int owl_dma_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -833,12 +1084,19 @@ static int owl_dma_probe(struct platform_device *pdev)
        spin_lock_init(&od->lock);
 
        dma_cap_set(DMA_MEMCPY, od->dma.cap_mask);
+       dma_cap_set(DMA_SLAVE, od->dma.cap_mask);
+       dma_cap_set(DMA_CYCLIC, od->dma.cap_mask);
 
        od->dma.dev = &pdev->dev;
        od->dma.device_free_chan_resources = owl_dma_free_chan_resources;
        od->dma.device_tx_status = owl_dma_tx_status;
        od->dma.device_issue_pending = owl_dma_issue_pending;
        od->dma.device_prep_dma_memcpy = owl_dma_prep_memcpy;
+       od->dma.device_prep_slave_sg = owl_dma_prep_slave_sg;
+       od->dma.device_prep_dma_cyclic = owl_prep_dma_cyclic;
+       od->dma.device_config = owl_dma_config;
+       od->dma.device_pause = owl_dma_pause;
+       od->dma.device_resume = owl_dma_resume;
        od->dma.device_terminate_all = owl_dma_terminate_all;
        od->dma.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
        od->dma.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
@@ -910,8 +1168,18 @@ static int owl_dma_probe(struct platform_device *pdev)
                goto err_pool_free;
        }
 
+       /* Device-tree DMA controller registration */
+       ret = of_dma_controller_register(pdev->dev.of_node,
+                                        owl_dma_of_xlate, od);
+       if (ret) {
+               dev_err(&pdev->dev, "of_dma_controller_register failed\n");
+               goto err_dma_unregister;
+       }
+
        return 0;
 
+err_dma_unregister:
+       dma_async_device_unregister(&od->dma);
 err_pool_free:
        clk_disable_unprepare(od->clk);
        dma_pool_destroy(od->lli_pool);
@@ -923,6 +1191,7 @@ static int owl_dma_remove(struct platform_device *pdev)
 {
        struct owl_dma *od = platform_get_drvdata(pdev);
 
+       of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&od->dma);
 
        /* Mask all interrupts for this execution environment */
index 4cf0d4d..2561028 100644 (file)
@@ -4360,7 +4360,7 @@ static ssize_t enable_store(struct device_driver *dev, const char *buf,
 }
 static DRIVER_ATTR_RW(enable);
 
-static ssize_t poly_store(struct device_driver *dev, char *buf)
+static ssize_t poly_show(struct device_driver *dev, char *buf)
 {
        ssize_t size = 0;
        u32 reg;
index b31c28b..8257250 100644 (file)
@@ -1285,7 +1285,6 @@ static int pxad_remove(struct platform_device *op)
 
        pxad_cleanup_debugfs(pdev);
        pxad_free_channels(&pdev->slave);
-       dma_async_device_unregister(&pdev->slave);
        return 0;
 }
 
@@ -1396,7 +1395,7 @@ static int pxad_init_dmadev(struct platform_device *op,
                init_waitqueue_head(&c->wq_state);
        }
 
-       return dma_async_device_register(&pdev->slave);
+       return dmaenginem_async_device_register(&pdev->slave);
 }
 
 static int pxad_probe(struct platform_device *op)
@@ -1433,7 +1432,7 @@ static int pxad_probe(struct platform_device *op)
                                 "#dma-requests set to default 32 as missing in OF: %d",
                                 ret);
                        nb_requestors = 32;
-               };
+               }
        } else if (pdata && pdata->dma_channels) {
                dma_channels = pdata->dma_channels;
                nb_requestors = pdata->nb_requestors;
index bfb79bd..07c20aa 100644 (file)
@@ -833,7 +833,7 @@ static int st_fdma_probe(struct platform_device *pdev)
        fdev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
        fdev->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
 
-       ret = dma_async_device_register(&fdev->dma_device);
+       ret = dmaenginem_async_device_register(&fdev->dma_device);
        if (ret) {
                dev_err(&pdev->dev,
                        "Failed to register DMA device (%d)\n", ret);
@@ -844,15 +844,13 @@ static int st_fdma_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev,
                        "Failed to register controller (%d)\n", ret);
-               goto err_dma_dev;
+               goto err_rproc;
        }
 
        dev_info(&pdev->dev, "ST FDMA engine driver, irq:%d\n", fdev->irq);
 
        return 0;
 
-err_dma_dev:
-       dma_async_device_unregister(&fdev->dma_device);
 err_rproc:
        st_fdma_free(fdev);
        st_slim_rproc_put(fdev->slim_rproc);
@@ -867,7 +865,6 @@ static int st_fdma_remove(struct platform_device *pdev)
        devm_free_irq(&pdev->dev, fdev->irq, fdev);
        st_slim_rproc_put(fdev->slim_rproc);
        of_dma_controller_free(pdev->dev.of_node);
-       dma_async_device_unregister(&fdev->dma_device);
 
        return 0;
 }
index f4edfc5..5e328bd 100644 (file)
@@ -2839,7 +2839,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
 
        d40_ops_init(base, &base->dma_slave);
 
-       err = dma_async_device_register(&base->dma_slave);
+       err = dmaenginem_async_device_register(&base->dma_slave);
 
        if (err) {
                d40_err(base->dev, "Failed to register slave channels\n");
@@ -2854,12 +2854,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
 
        d40_ops_init(base, &base->dma_memcpy);
 
-       err = dma_async_device_register(&base->dma_memcpy);
+       err = dmaenginem_async_device_register(&base->dma_memcpy);
 
        if (err) {
                d40_err(base->dev,
                        "Failed to register memcpy only channels\n");
-               goto unregister_slave;
+               goto exit;
        }
 
        d40_chan_init(base, &base->dma_both, base->phy_chans,
@@ -2871,18 +2871,14 @@ static int __init d40_dmaengine_init(struct d40_base *base,
        dma_cap_set(DMA_CYCLIC, base->dma_slave.cap_mask);
 
        d40_ops_init(base, &base->dma_both);
-       err = dma_async_device_register(&base->dma_both);
+       err = dmaenginem_async_device_register(&base->dma_both);
 
        if (err) {
                d40_err(base->dev,
                        "Failed to register logical and physical capable channels\n");
-               goto unregister_memcpy;
+               goto exit;
        }
        return 0;
- unregister_memcpy:
-       dma_async_device_unregister(&base->dma_memcpy);
- unregister_slave:
-       dma_async_device_unregister(&base->dma_slave);
  exit:
        return err;
 }
index 06dd172..390e4ca 100644 (file)
@@ -1656,7 +1656,7 @@ static int stm32_mdma_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = dma_async_device_register(dd);
+       ret = dmaenginem_async_device_register(dd);
        if (ret)
                return ret;
 
@@ -1674,8 +1674,6 @@ static int stm32_mdma_probe(struct platform_device *pdev)
        return 0;
 
 err_unregister:
-       dma_async_device_unregister(dd);
-
        return ret;
 }
 
index 395c698..fc0f9c8 100644 (file)
@@ -545,7 +545,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
        }
 
        dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys,
-               td_desc->desc_list_len, DMA_MEM_TO_DEV);
+               td_desc->desc_list_len, DMA_TO_DEVICE);
 
        return &td_desc->txd;
 }
index f8f1f6b..eb9805b 100644 (file)
@@ -85,7 +85,7 @@ static inline enum dma_transfer_direction
 ep93xx_dma_chan_direction(struct dma_chan *chan)
 {
        if (!ep93xx_dma_chan_is_m2p(chan))
-               return DMA_NONE;
+               return DMA_TRANS_NONE;
 
        /* even channels are for TX, odd for RX */
        return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
diff --git a/include/linux/platform_data/dma-mcf-edma.h b/include/linux/platform_data/dma-mcf-edma.h
new file mode 100644 (file)
index 0000000..d718ccf
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Freescale eDMA platform data, ColdFire SoC's family.
+ *
+ * Copyright (c) 2017 Angelo Dureghello <angelo@sysam.it>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_MCF_EDMA_H__
+#define __LINUX_PLATFORM_DATA_MCF_EDMA_H__
+
+struct dma_slave_map;
+
+bool mcf_edma_filter_fn(struct dma_chan *chan, void *param);
+
+#define MCF_EDMA_FILTER_PARAM(ch)      ((void *)ch)
+
+/**
+ * struct mcf_edma_platform_data - platform specific data for eDMA engine
+ *
+ * @ver                        The eDMA module version.
+ * @dma_channels       The number of eDMA channels.
+ */
+struct mcf_edma_platform_data {
+       int dma_channels;
+       const struct dma_slave_map *slave_map;
+       int slavecnt;
+};
+
+#endif /* __LINUX_PLATFORM_DATA_MCF_EDMA_H__ */