dmaengine: omap-dma: move register read/writes into omap-dma.c

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>
This commit is contained in:
Russell King 2013-12-10 11:08:01 +00:00
parent 34a378fcb9
commit 596c471b69
4 changed files with 105 additions and 15 deletions

View file

@ -261,9 +261,13 @@ static const struct platform_device_info omap_dma_dev_info = {
.name = "omap-dma-engine", .name = "omap-dma-engine",
.id = -1, .id = -1,
.dma_mask = DMA_BIT_MASK(32), .dma_mask = DMA_BIT_MASK(32),
.res = res,
.num_res = 1,
}; };
static struct omap_system_dma_plat_info dma_plat_info __initdata = { 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, .show_dma_caps = omap1_show_dma_caps,
.clear_lch_regs = omap1_clear_lch_regs, .clear_lch_regs = omap1_clear_lch_regs,
.clear_dma = omap1_clear_dma, .clear_dma = omap1_clear_dma,

View file

@ -205,12 +205,20 @@ static unsigned configure_dma_errata(void)
} }
static struct omap_system_dma_plat_info dma_plat_info __initdata = { 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, .show_dma_caps = omap2_show_dma_caps,
.clear_dma = omap2_clear_dma, .clear_dma = omap2_clear_dma,
.dma_write = dma_write, .dma_write = dma_write,
.dma_read = dma_read, .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 */ /* One time initializations */
static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) 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); 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); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) { if (!mem) {
dev_err(&pdev->dev, "%s: no mem resource\n", __func__); dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
return -EINVAL; return -EINVAL;
} }
dma_base = ioremap(mem->start, resource_size(mem)); dma_base = ioremap(mem->start, resource_size(mem));
if (!dma_base) { if (!dma_base) {
dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); 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; 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) static int __init omap2_system_dma_init(void)
{ {
struct platform_device *pdev; struct platform_device *pdev;

View file

@ -27,13 +27,16 @@ struct omap_dmadev {
spinlock_t lock; spinlock_t lock;
struct tasklet_struct task; struct tasklet_struct task;
struct list_head pending; struct list_head pending;
void __iomem *base;
const struct omap_dma_reg *reg_map;
struct omap_system_dma_plat_info *plat; struct omap_system_dma_plat_info *plat;
}; };
struct omap_chan { struct omap_chan {
struct virt_dma_chan vc; struct virt_dma_chan vc;
struct list_head node; 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; struct dma_slave_config cfg;
unsigned dma_sig; 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)); 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) 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) 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) 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) 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) 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); 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) 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); 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) 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); struct omap_chan *c = to_omap_dma_chan(chan);
int ret;
dev_dbg(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig); dev_dbg(od->ddev.dev, "allocating channel for %u\n", c->dma_sig);
return omap_request_dma(c->dma_sig, "DMA engine", ret = omap_request_dma(c->dma_sig, "DMA engine", omap_dma_callback,
omap_dma_callback, c, &c->dma_ch); 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) static void omap_dma_free_chan_resources(struct dma_chan *chan)
{ {
struct omap_chan *c = to_omap_dma_chan(chan); struct omap_chan *c = to_omap_dma_chan(chan);
c->channel_base = NULL;
vchan_free_chan_resources(&c->vc); vchan_free_chan_resources(&c->vc);
omap_free_dma(c->dma_ch); 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) if (!c)
return -ENOMEM; return -ENOMEM;
c->plat = od->plat; c->reg_map = od->reg_map;
c->dma_sig = dma_sig; c->dma_sig = dma_sig;
c->vc.desc_free = omap_dma_desc_free; c->vc.desc_free = omap_dma_desc_free;
vchan_init(&c->vc, &od->ddev); 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) static int omap_dma_probe(struct platform_device *pdev)
{ {
struct omap_dmadev *od; struct omap_dmadev *od;
struct resource *res;
int rc, i; int rc, i;
od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
if (!od) if (!od)
return -ENOMEM; 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(); od->plat = omap_get_plat_info();
if (!od->plat) if (!od->plat)
return -EPROBE_DEFER; return -EPROBE_DEFER;
od->reg_map = od->plat->reg_map;
dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources; od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources;

View file

@ -285,6 +285,8 @@ struct omap_dma_reg {
/* System DMA platform data structure */ /* System DMA platform data structure */
struct omap_system_dma_plat_info { struct omap_system_dma_plat_info {
const struct omap_dma_reg *reg_map;
unsigned channel_stride;
struct omap_dma_dev_attr *dma_attr; struct omap_dma_dev_attr *dma_attr;
u32 errata; u32 errata;
void (*show_dma_caps)(void); void (*show_dma_caps)(void);