]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/dma/mxs-dma.c
Merge tag 'dt2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[mirror_ubuntu-zesty-kernel.git] / drivers / dma / mxs-dma.c
index 3db3a48d3f01e23d58d060b326cf65ec783ff335..c96ab15319f245c363bf1ed693c5a61e0669fcef 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <linux/fsl/mxs-dma.h>
+#include <linux/stmp_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <mach/mxs.h>
-#include <mach/common.h>
 
 #include "dmaengine.h"
 
  * dma can program the controller registers of peripheral devices.
  */
 
-#define MXS_DMA_APBH           0
-#define MXS_DMA_APBX           1
-#define dma_is_apbh()          (mxs_dma->dev_id == MXS_DMA_APBH)
-
-#define APBH_VERSION_LATEST    3
-#define apbh_is_old()          (mxs_dma->version < APBH_VERSION_LATEST)
+#define dma_is_apbh(mxs_dma)   ((mxs_dma)->type == MXS_DMA_APBH)
+#define apbh_is_old(mxs_dma)   ((mxs_dma)->dev_id == IMX23_DMA)
 
 #define HW_APBHX_CTRL0                         0x000
 #define BM_APBH_CTRL0_APB_BURST8_EN            (1 << 29)
 #define HW_APBHX_CTRL2                         0x020
 #define HW_APBHX_CHANNEL_CTRL                  0x030
 #define BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL    16
-#define HW_APBH_VERSION                                (cpu_is_mx23() ? 0x3f0 : 0x800)
-#define HW_APBX_VERSION                                0x800
-#define BP_APBHX_VERSION_MAJOR                 24
-#define HW_APBHX_CHn_NXTCMDAR(n) \
-       (((dma_is_apbh() && apbh_is_old()) ? 0x050 : 0x110) + (n) * 0x70)
-#define HW_APBHX_CHn_SEMA(n) \
-       (((dma_is_apbh() && apbh_is_old()) ? 0x080 : 0x140) + (n) * 0x70)
+/*
+ * The offset of NXTCMDAR register is different per both dma type and version,
+ * while stride for each channel is all the same 0x70.
+ */
+#define HW_APBHX_CHn_NXTCMDAR(d, n) \
+       (((dma_is_apbh(d) && apbh_is_old(d)) ? 0x050 : 0x110) + (n) * 0x70)
+#define HW_APBHX_CHn_SEMA(d, n) \
+       (((dma_is_apbh(d) && apbh_is_old(d)) ? 0x080 : 0x140) + (n) * 0x70)
 
 /*
  * ccw bits definitions
@@ -121,9 +121,19 @@ struct mxs_dma_chan {
 #define MXS_DMA_CHANNELS               16
 #define MXS_DMA_CHANNELS_MASK          0xffff
 
+enum mxs_dma_devtype {
+       MXS_DMA_APBH,
+       MXS_DMA_APBX,
+};
+
+enum mxs_dma_id {
+       IMX23_DMA,
+       IMX28_DMA,
+};
+
 struct mxs_dma_engine {
-       int                             dev_id;
-       unsigned int                    version;
+       enum mxs_dma_id                 dev_id;
+       enum mxs_dma_devtype            type;
        void __iomem                    *base;
        struct clk                      *clk;
        struct dma_device               dma_device;
@@ -131,17 +141,86 @@ struct mxs_dma_engine {
        struct mxs_dma_chan             mxs_chans[MXS_DMA_CHANNELS];
 };
 
+struct mxs_dma_type {
+       enum mxs_dma_id id;
+       enum mxs_dma_devtype type;
+};
+
+static struct mxs_dma_type mxs_dma_types[] = {
+       {
+               .id = IMX23_DMA,
+               .type = MXS_DMA_APBH,
+       }, {
+               .id = IMX23_DMA,
+               .type = MXS_DMA_APBX,
+       }, {
+               .id = IMX28_DMA,
+               .type = MXS_DMA_APBH,
+       }, {
+               .id = IMX28_DMA,
+               .type = MXS_DMA_APBX,
+       }
+};
+
+static struct platform_device_id mxs_dma_ids[] = {
+       {
+               .name = "imx23-dma-apbh",
+               .driver_data = (kernel_ulong_t) &mxs_dma_types[0],
+       }, {
+               .name = "imx23-dma-apbx",
+               .driver_data = (kernel_ulong_t) &mxs_dma_types[1],
+       }, {
+               .name = "imx28-dma-apbh",
+               .driver_data = (kernel_ulong_t) &mxs_dma_types[2],
+       }, {
+               .name = "imx28-dma-apbx",
+               .driver_data = (kernel_ulong_t) &mxs_dma_types[3],
+       }, {
+               /* end of list */
+       }
+};
+
+static const struct of_device_id mxs_dma_dt_ids[] = {
+       { .compatible = "fsl,imx23-dma-apbh", .data = &mxs_dma_ids[0], },
+       { .compatible = "fsl,imx23-dma-apbx", .data = &mxs_dma_ids[1], },
+       { .compatible = "fsl,imx28-dma-apbh", .data = &mxs_dma_ids[2], },
+       { .compatible = "fsl,imx28-dma-apbx", .data = &mxs_dma_ids[3], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_dma_dt_ids);
+
+static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct mxs_dma_chan, chan);
+}
+
+int mxs_dma_is_apbh(struct dma_chan *chan)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+
+       return dma_is_apbh(mxs_dma);
+}
+
+int mxs_dma_is_apbx(struct dma_chan *chan)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+
+       return !dma_is_apbh(mxs_dma);
+}
+
 static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
 {
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
        int chan_id = mxs_chan->chan.chan_id;
 
-       if (dma_is_apbh() && apbh_is_old())
+       if (dma_is_apbh(mxs_dma) && apbh_is_old(mxs_dma))
                writel(1 << (chan_id + BP_APBH_CTRL0_RESET_CHANNEL),
-                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+                       mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
        else
                writel(1 << (chan_id + BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL),
-                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_SET);
 }
 
 static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
@@ -151,10 +230,10 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
 
        /* set cmd_addr up */
        writel(mxs_chan->ccw_phys,
-               mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id));
+               mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(mxs_dma, chan_id));
 
        /* write 1 to SEMA to kick off the channel */
-       writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id));
+       writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(mxs_dma, chan_id));
 }
 
 static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
@@ -168,12 +247,12 @@ static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan)
        int chan_id = mxs_chan->chan.chan_id;
 
        /* freeze the channel */
-       if (dma_is_apbh() && apbh_is_old())
+       if (dma_is_apbh(mxs_dma) && apbh_is_old(mxs_dma))
                writel(1 << chan_id,
-                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+                       mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
        else
                writel(1 << chan_id,
-                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_SET);
 
        mxs_chan->status = DMA_PAUSED;
 }
@@ -184,21 +263,16 @@ static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
        int chan_id = mxs_chan->chan.chan_id;
 
        /* unfreeze the channel */
-       if (dma_is_apbh() && apbh_is_old())
+       if (dma_is_apbh(mxs_dma) && apbh_is_old(mxs_dma))
                writel(1 << chan_id,
-                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+                       mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_CLR);
        else
                writel(1 << chan_id,
-                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_CLR_ADDR);
+                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_CLR);
 
        mxs_chan->status = DMA_IN_PROGRESS;
 }
 
-static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
-{
-       return container_of(chan, struct mxs_dma_chan, chan);
-}
-
 static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
 {
        return dma_cookie_assign(tx);
@@ -220,11 +294,11 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
        /* completion status */
        stat1 = readl(mxs_dma->base + HW_APBHX_CTRL1);
        stat1 &= MXS_DMA_CHANNELS_MASK;
-       writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + MXS_CLR_ADDR);
+       writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_CLR);
 
        /* error status */
        stat2 = readl(mxs_dma->base + HW_APBHX_CTRL2);
-       writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + MXS_CLR_ADDR);
+       writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + STMP_OFFSET_REG_CLR);
 
        /*
         * When both completion and error of termination bits set at the
@@ -567,27 +641,21 @@ static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
        if (ret)
                return ret;
 
-       ret = mxs_reset_block(mxs_dma->base);
+       ret = stmp_reset_block(mxs_dma->base);
        if (ret)
                goto err_out;
 
-       /* only major version matters */
-       mxs_dma->version = readl(mxs_dma->base +
-                               ((mxs_dma->dev_id == MXS_DMA_APBX) ?
-                               HW_APBX_VERSION : HW_APBH_VERSION)) >>
-                               BP_APBHX_VERSION_MAJOR;
-
        /* enable apbh burst */
-       if (dma_is_apbh()) {
+       if (dma_is_apbh(mxs_dma)) {
                writel(BM_APBH_CTRL0_APB_BURST_EN,
-                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+                       mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
                writel(BM_APBH_CTRL0_APB_BURST8_EN,
-                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+                       mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
        }
 
        /* enable irq for all the channels */
        writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
-               mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR);
+               mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_SET);
 
 err_out:
        clk_disable_unprepare(mxs_dma->clk);
@@ -596,8 +664,9 @@ err_out:
 
 static int __init mxs_dma_probe(struct platform_device *pdev)
 {
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(pdev);
+       const struct platform_device_id *id_entry;
+       const struct of_device_id *of_id;
+       const struct mxs_dma_type *dma_type;
        struct mxs_dma_engine *mxs_dma;
        struct resource *iores;
        int ret, i;
@@ -606,7 +675,15 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
        if (!mxs_dma)
                return -ENOMEM;
 
-       mxs_dma->dev_id = id_entry->driver_data;
+       of_id = of_match_device(mxs_dma_dt_ids, &pdev->dev);
+       if (of_id)
+               id_entry = of_id->data;
+       else
+               id_entry = platform_get_device_id(pdev);
+
+       dma_type = (struct mxs_dma_type *)id_entry->driver_data;
+       mxs_dma->type = dma_type->type;
+       mxs_dma->dev_id = dma_type->id;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
@@ -689,23 +766,12 @@ err_request_region:
        return ret;
 }
 
-static struct platform_device_id mxs_dma_type[] = {
-       {
-               .name = "mxs-dma-apbh",
-               .driver_data = MXS_DMA_APBH,
-       }, {
-               .name = "mxs-dma-apbx",
-               .driver_data = MXS_DMA_APBX,
-       }, {
-               /* end of list */
-       }
-};
-
 static struct platform_driver mxs_dma_driver = {
        .driver         = {
                .name   = "mxs-dma",
+               .of_match_table = mxs_dma_dt_ids,
        },
-       .id_table       = mxs_dma_type,
+       .id_table       = mxs_dma_ids,
 };
 
 static int __init mxs_dma_module_init(void)