dmaengine: omap-dma: move register read/writes into omap-dma.c
authorRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 10 Dec 2013 11:08:01 +0000 (11:08 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 3 Apr 2014 23:31:49 +0000 (00:31 +0100)
Export the DMA register information from the SoC specific data, such
that we can access the registers directly in omap-dma.c, mapping the
register region ourselves as well.

Rather than calculating the DMA channel register in its entirety for
each access, we pre-calculate an offset base address for the allocated
DMA channel and then just use the appropriate register offset.

Acked-by: Tony Lindgren <tony@atomide.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-omap1/dma.c
arch/arm/mach-omap2/dma.c
drivers/dma/omap-dma.c
include/linux/omap-dma.h

index a8c83ccc36fbae18e7d96386d55887dec39ea9d7..4be601b638d7aa8c0d35b7fa5924eb54aa6e2534 100644 (file)
@@ -261,9 +261,13 @@ static const struct platform_device_info omap_dma_dev_info = {
        .name = "omap-dma-engine",
        .id = -1,
        .dma_mask = DMA_BIT_MASK(32),
+       .res = res,
+       .num_res = 1,
 };
 
 static struct omap_system_dma_plat_info dma_plat_info __initdata = {
+       .reg_map        = reg_map,
+       .channel_stride = 0x40,
        .show_dma_caps  = omap1_show_dma_caps,
        .clear_lch_regs = omap1_clear_lch_regs,
        .clear_dma      = omap1_clear_dma,
index 6331fc4b4054b08552509706d18fca274d001a36..5689c88d986d64214b07c003eb11c8cbddfa05e6 100644 (file)
@@ -205,12 +205,20 @@ static unsigned configure_dma_errata(void)
 }
 
 static struct omap_system_dma_plat_info dma_plat_info __initdata = {
+       .reg_map        = reg_map,
+       .channel_stride = 0x60,
        .show_dma_caps  = omap2_show_dma_caps,
        .clear_dma      = omap2_clear_dma,
        .dma_write      = dma_write,
        .dma_read       = dma_read,
 };
 
+static struct platform_device_info omap_dma_dev_info = {
+       .name = "omap-dma-engine",
+       .id = -1,
+       .dma_mask = DMA_BIT_MASK(32),
+};
+
 /* One time initializations */
 static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
 {
@@ -231,11 +239,15 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
                return PTR_ERR(pdev);
        }
 
+       omap_dma_dev_info.res = pdev->resource;
+       omap_dma_dev_info.num_res = pdev->num_resources;
+
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
                dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
                return -EINVAL;
        }
+
        dma_base = ioremap(mem->start, resource_size(mem));
        if (!dma_base) {
                dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
@@ -256,12 +268,6 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
        return 0;
 }
 
-static const struct platform_device_info omap_dma_dev_info = {
-       .name = "omap-dma-engine",
-       .id = -1,
-       .dma_mask = DMA_BIT_MASK(32),
-};
-
 static int __init omap2_system_dma_init(void)
 {
        struct platform_device *pdev;
index 1e0018f3638460261e2694e9a594031c335e7fa7..00f8e566cf12141b0e38162015ed6d5e57794183 100644 (file)
@@ -27,13 +27,16 @@ struct omap_dmadev {
        spinlock_t lock;
        struct tasklet_struct task;
        struct list_head pending;
+       void __iomem *base;
+       const struct omap_dma_reg *reg_map;
        struct omap_system_dma_plat_info *plat;
 };
 
 struct omap_chan {
        struct virt_dma_chan vc;
        struct list_head node;
-       struct omap_system_dma_plat_info *plat;
+       void __iomem *channel_base;
+       const struct omap_dma_reg *reg_map;
 
        struct dma_slave_config cfg;
        unsigned dma_sig;
@@ -170,24 +173,77 @@ static void omap_dma_desc_free(struct virt_dma_desc *vd)
        kfree(container_of(vd, struct omap_desc, vd));
 }
 
+static void omap_dma_write(uint32_t val, unsigned type, void __iomem *addr)
+{
+       switch (type) {
+       case OMAP_DMA_REG_16BIT:
+               writew_relaxed(val, addr);
+               break;
+       case OMAP_DMA_REG_2X16BIT:
+               writew_relaxed(val, addr);
+               writew_relaxed(val >> 16, addr + 2);
+               break;
+       case OMAP_DMA_REG_32BIT:
+               writel_relaxed(val, addr);
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+
+static unsigned omap_dma_read(unsigned type, void __iomem *addr)
+{
+       unsigned val;
+
+       switch (type) {
+       case OMAP_DMA_REG_16BIT:
+               val = readw_relaxed(addr);
+               break;
+       case OMAP_DMA_REG_2X16BIT:
+               val = readw_relaxed(addr);
+               val |= readw_relaxed(addr + 2) << 16;
+               break;
+       case OMAP_DMA_REG_32BIT:
+               val = readl_relaxed(addr);
+               break;
+       default:
+               WARN_ON(1);
+               val = 0;
+       }
+
+       return val;
+}
+
 static void omap_dma_glbl_write(struct omap_dmadev *od, unsigned reg, unsigned val)
 {
-       od->plat->dma_write(val, reg, 0);
+       const struct omap_dma_reg *r = od->reg_map + reg;
+
+       WARN_ON(r->stride);
+
+       omap_dma_write(val, r->type, od->base + r->offset);
 }
 
 static unsigned omap_dma_glbl_read(struct omap_dmadev *od, unsigned reg)
 {
-       return od->plat->dma_read(reg, 0);
+       const struct omap_dma_reg *r = od->reg_map + reg;
+
+       WARN_ON(r->stride);
+
+       return omap_dma_read(r->type, od->base + r->offset);
 }
 
 static void omap_dma_chan_write(struct omap_chan *c, unsigned reg, unsigned val)
 {
-       c->plat->dma_write(val, reg, c->dma_ch);
+       const struct omap_dma_reg *r = c->reg_map + reg;
+
+       omap_dma_write(val, r->type, c->channel_base + r->offset);
 }
 
 static unsigned omap_dma_chan_read(struct omap_chan *c, unsigned reg)
 {
-       return c->plat->dma_read(reg, c->dma_ch);
+       const struct omap_dma_reg *r = c->reg_map + reg;
+
+       return omap_dma_read(r->type, c->channel_base + r->offset);
 }
 
 static void omap_dma_clear_csr(struct omap_chan *c)
@@ -198,6 +254,12 @@ static void omap_dma_clear_csr(struct omap_chan *c)
                omap_dma_chan_write(c, CSR, ~0);
 }
 
+static void omap_dma_assign(struct omap_dmadev *od, struct omap_chan *c,
+       unsigned lch)
+{
+       c->channel_base = od->base + od->plat->channel_stride * lch;
+}
+
 static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
 {
        struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
@@ -400,18 +462,26 @@ static void omap_dma_sched(unsigned long data)
 
 static int omap_dma_alloc_chan_resources(struct dma_chan *chan)
 {
+       struct omap_dmadev *od = to_omap_dma_dev(chan->device);
        struct omap_chan *c = to_omap_dma_chan(chan);
+       int ret;
+
+       dev_dbg(od->ddev.dev, "allocating channel for %u\n", c->dma_sig);
 
-       dev_dbg(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig);
+       ret = omap_request_dma(c->dma_sig, "DMA engine", omap_dma_callback,
+                              c, &c->dma_ch);
 
-       return omap_request_dma(c->dma_sig, "DMA engine",
-               omap_dma_callback, c, &c->dma_ch);
+       if (ret >= 0)
+               omap_dma_assign(od, c, c->dma_ch);
+
+       return ret;
 }
 
 static void omap_dma_free_chan_resources(struct dma_chan *chan)
 {
        struct omap_chan *c = to_omap_dma_chan(chan);
 
+       c->channel_base = NULL;
        vchan_free_chan_resources(&c->vc);
        omap_free_dma(c->dma_ch);
 
@@ -917,7 +987,7 @@ static int omap_dma_chan_init(struct omap_dmadev *od, int dma_sig)
        if (!c)
                return -ENOMEM;
 
-       c->plat = od->plat;
+       c->reg_map = od->reg_map;
        c->dma_sig = dma_sig;
        c->vc.desc_free = omap_dma_desc_free;
        vchan_init(&c->vc, &od->ddev);
@@ -944,16 +1014,24 @@ static void omap_dma_free(struct omap_dmadev *od)
 static int omap_dma_probe(struct platform_device *pdev)
 {
        struct omap_dmadev *od;
+       struct resource *res;
        int rc, i;
 
        od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
        if (!od)
                return -ENOMEM;
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       od->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(od->base))
+               return PTR_ERR(od->base);
+
        od->plat = omap_get_plat_info();
        if (!od->plat)
                return -EPROBE_DEFER;
 
+       od->reg_map = od->plat->reg_map;
+
        dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
        dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
        od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources;
index 7813636a193da8a3e5a45de51c776336d1e782e9..41a13e70f41f5ade5228404ec6557ea2be7d113c 100644 (file)
@@ -285,6 +285,8 @@ struct omap_dma_reg {
 
 /* System DMA platform data structure */
 struct omap_system_dma_plat_info {
+       const struct omap_dma_reg *reg_map;
+       unsigned channel_stride;
        struct omap_dma_dev_attr *dma_attr;
        u32 errata;
        void (*show_dma_caps)(void);