Skip to content

Commit

Permalink
dmaengine: omap-dma: move register read/writes into omap-dma.c
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Vinod Koul <[email protected]>
Signed-off-by: Russell King <[email protected]>
  • Loading branch information
Russell King committed Apr 3, 2014
1 parent 34a378f commit 596c471
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 15 deletions.
4 changes: 4 additions & 0 deletions arch/arm/mach-omap1/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
18 changes: 12 additions & 6 deletions arch/arm/mach-omap2/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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__);
Expand All @@ -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;
Expand Down
96 changes: 87 additions & 9 deletions drivers/dma/omap-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions include/linux/omap-dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 596c471

Please sign in to comment.