diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-12-10 06:08:01 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-04-03 19:31:49 -0400 |
commit | 596c471b69249764d8e241b004736878204daa0f (patch) | |
tree | 9d5b253c7372d0e36965c85617e183418918b4b7 | |
parent | 34a378fcb9273d73dbd6b209952d2f6bf88a3dd0 (diff) |
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>
-rw-r--r-- | arch/arm/mach-omap1/dma.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/dma.c | 18 | ||||
-rw-r--r-- | drivers/dma/omap-dma.c | 96 | ||||
-rw-r--r-- | include/linux/omap-dma.h | 2 |
4 files changed, 105 insertions, 15 deletions
diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c index a8c83ccc36fb..4be601b638d7 100644 --- a/arch/arm/mach-omap1/dma.c +++ b/arch/arm/mach-omap1/dma.c | |||
@@ -261,9 +261,13 @@ static const struct platform_device_info omap_dma_dev_info = { | |||
261 | .name = "omap-dma-engine", | 261 | .name = "omap-dma-engine", |
262 | .id = -1, | 262 | .id = -1, |
263 | .dma_mask = DMA_BIT_MASK(32), | 263 | .dma_mask = DMA_BIT_MASK(32), |
264 | .res = res, | ||
265 | .num_res = 1, | ||
264 | }; | 266 | }; |
265 | 267 | ||
266 | static struct omap_system_dma_plat_info dma_plat_info __initdata = { | 268 | static struct omap_system_dma_plat_info dma_plat_info __initdata = { |
269 | .reg_map = reg_map, | ||
270 | .channel_stride = 0x40, | ||
267 | .show_dma_caps = omap1_show_dma_caps, | 271 | .show_dma_caps = omap1_show_dma_caps, |
268 | .clear_lch_regs = omap1_clear_lch_regs, | 272 | .clear_lch_regs = omap1_clear_lch_regs, |
269 | .clear_dma = omap1_clear_dma, | 273 | .clear_dma = omap1_clear_dma, |
diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c index 6331fc4b4054..5689c88d986d 100644 --- a/arch/arm/mach-omap2/dma.c +++ b/arch/arm/mach-omap2/dma.c | |||
@@ -205,12 +205,20 @@ static unsigned configure_dma_errata(void) | |||
205 | } | 205 | } |
206 | 206 | ||
207 | static struct omap_system_dma_plat_info dma_plat_info __initdata = { | 207 | static struct omap_system_dma_plat_info dma_plat_info __initdata = { |
208 | .reg_map = reg_map, | ||
209 | .channel_stride = 0x60, | ||
208 | .show_dma_caps = omap2_show_dma_caps, | 210 | .show_dma_caps = omap2_show_dma_caps, |
209 | .clear_dma = omap2_clear_dma, | 211 | .clear_dma = omap2_clear_dma, |
210 | .dma_write = dma_write, | 212 | .dma_write = dma_write, |
211 | .dma_read = dma_read, | 213 | .dma_read = dma_read, |
212 | }; | 214 | }; |
213 | 215 | ||
216 | static struct platform_device_info omap_dma_dev_info = { | ||
217 | .name = "omap-dma-engine", | ||
218 | .id = -1, | ||
219 | .dma_mask = DMA_BIT_MASK(32), | ||
220 | }; | ||
221 | |||
214 | /* One time initializations */ | 222 | /* One time initializations */ |
215 | static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) | 223 | static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) |
216 | { | 224 | { |
@@ -231,11 +239,15 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) | |||
231 | return PTR_ERR(pdev); | 239 | return PTR_ERR(pdev); |
232 | } | 240 | } |
233 | 241 | ||
242 | omap_dma_dev_info.res = pdev->resource; | ||
243 | omap_dma_dev_info.num_res = pdev->num_resources; | ||
244 | |||
234 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 245 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
235 | if (!mem) { | 246 | if (!mem) { |
236 | dev_err(&pdev->dev, "%s: no mem resource\n", __func__); | 247 | dev_err(&pdev->dev, "%s: no mem resource\n", __func__); |
237 | return -EINVAL; | 248 | return -EINVAL; |
238 | } | 249 | } |
250 | |||
239 | dma_base = ioremap(mem->start, resource_size(mem)); | 251 | dma_base = ioremap(mem->start, resource_size(mem)); |
240 | if (!dma_base) { | 252 | if (!dma_base) { |
241 | dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); | 253 | 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) | |||
256 | return 0; | 268 | return 0; |
257 | } | 269 | } |
258 | 270 | ||
259 | static const struct platform_device_info omap_dma_dev_info = { | ||
260 | .name = "omap-dma-engine", | ||
261 | .id = -1, | ||
262 | .dma_mask = DMA_BIT_MASK(32), | ||
263 | }; | ||
264 | |||
265 | static int __init omap2_system_dma_init(void) | 271 | static int __init omap2_system_dma_init(void) |
266 | { | 272 | { |
267 | struct platform_device *pdev; | 273 | struct platform_device *pdev; |
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 1e0018f36384..00f8e566cf12 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c | |||
@@ -27,13 +27,16 @@ struct omap_dmadev { | |||
27 | spinlock_t lock; | 27 | spinlock_t lock; |
28 | struct tasklet_struct task; | 28 | struct tasklet_struct task; |
29 | struct list_head pending; | 29 | struct list_head pending; |
30 | void __iomem *base; | ||
31 | const struct omap_dma_reg *reg_map; | ||
30 | struct omap_system_dma_plat_info *plat; | 32 | struct omap_system_dma_plat_info *plat; |
31 | }; | 33 | }; |
32 | 34 | ||
33 | struct omap_chan { | 35 | struct omap_chan { |
34 | struct virt_dma_chan vc; | 36 | struct virt_dma_chan vc; |
35 | struct list_head node; | 37 | struct list_head node; |
36 | struct omap_system_dma_plat_info *plat; | 38 | void __iomem *channel_base; |
39 | const struct omap_dma_reg *reg_map; | ||
37 | 40 | ||
38 | struct dma_slave_config cfg; | 41 | struct dma_slave_config cfg; |
39 | unsigned dma_sig; | 42 | unsigned dma_sig; |
@@ -170,24 +173,77 @@ static void omap_dma_desc_free(struct virt_dma_desc *vd) | |||
170 | kfree(container_of(vd, struct omap_desc, vd)); | 173 | kfree(container_of(vd, struct omap_desc, vd)); |
171 | } | 174 | } |
172 | 175 | ||
176 | static void omap_dma_write(uint32_t val, unsigned type, void __iomem *addr) | ||
177 | { | ||
178 | switch (type) { | ||
179 | case OMAP_DMA_REG_16BIT: | ||
180 | writew_relaxed(val, addr); | ||
181 | break; | ||
182 | case OMAP_DMA_REG_2X16BIT: | ||
183 | writew_relaxed(val, addr); | ||
184 | writew_relaxed(val >> 16, addr + 2); | ||
185 | break; | ||
186 | case OMAP_DMA_REG_32BIT: | ||
187 | writel_relaxed(val, addr); | ||
188 | break; | ||
189 | default: | ||
190 | WARN_ON(1); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static unsigned omap_dma_read(unsigned type, void __iomem *addr) | ||
195 | { | ||
196 | unsigned val; | ||
197 | |||
198 | switch (type) { | ||
199 | case OMAP_DMA_REG_16BIT: | ||
200 | val = readw_relaxed(addr); | ||
201 | break; | ||
202 | case OMAP_DMA_REG_2X16BIT: | ||
203 | val = readw_relaxed(addr); | ||
204 | val |= readw_relaxed(addr + 2) << 16; | ||
205 | break; | ||
206 | case OMAP_DMA_REG_32BIT: | ||
207 | val = readl_relaxed(addr); | ||
208 | break; | ||
209 | default: | ||
210 | WARN_ON(1); | ||
211 | val = 0; | ||
212 | } | ||
213 | |||
214 | return val; | ||
215 | } | ||
216 | |||
173 | static void omap_dma_glbl_write(struct omap_dmadev *od, unsigned reg, unsigned val) | 217 | static void omap_dma_glbl_write(struct omap_dmadev *od, unsigned reg, unsigned val) |
174 | { | 218 | { |
175 | od->plat->dma_write(val, reg, 0); | 219 | const struct omap_dma_reg *r = od->reg_map + reg; |
220 | |||
221 | WARN_ON(r->stride); | ||
222 | |||
223 | omap_dma_write(val, r->type, od->base + r->offset); | ||
176 | } | 224 | } |
177 | 225 | ||
178 | static unsigned omap_dma_glbl_read(struct omap_dmadev *od, unsigned reg) | 226 | static unsigned omap_dma_glbl_read(struct omap_dmadev *od, unsigned reg) |
179 | { | 227 | { |
180 | return od->plat->dma_read(reg, 0); | 228 | const struct omap_dma_reg *r = od->reg_map + reg; |
229 | |||
230 | WARN_ON(r->stride); | ||
231 | |||
232 | return omap_dma_read(r->type, od->base + r->offset); | ||
181 | } | 233 | } |
182 | 234 | ||
183 | static void omap_dma_chan_write(struct omap_chan *c, unsigned reg, unsigned val) | 235 | static void omap_dma_chan_write(struct omap_chan *c, unsigned reg, unsigned val) |
184 | { | 236 | { |
185 | c->plat->dma_write(val, reg, c->dma_ch); | 237 | const struct omap_dma_reg *r = c->reg_map + reg; |
238 | |||
239 | omap_dma_write(val, r->type, c->channel_base + r->offset); | ||
186 | } | 240 | } |
187 | 241 | ||
188 | static unsigned omap_dma_chan_read(struct omap_chan *c, unsigned reg) | 242 | static unsigned omap_dma_chan_read(struct omap_chan *c, unsigned reg) |
189 | { | 243 | { |
190 | return c->plat->dma_read(reg, c->dma_ch); | 244 | const struct omap_dma_reg *r = c->reg_map + reg; |
245 | |||
246 | return omap_dma_read(r->type, c->channel_base + r->offset); | ||
191 | } | 247 | } |
192 | 248 | ||
193 | static void omap_dma_clear_csr(struct omap_chan *c) | 249 | static void omap_dma_clear_csr(struct omap_chan *c) |
@@ -198,6 +254,12 @@ static void omap_dma_clear_csr(struct omap_chan *c) | |||
198 | omap_dma_chan_write(c, CSR, ~0); | 254 | omap_dma_chan_write(c, CSR, ~0); |
199 | } | 255 | } |
200 | 256 | ||
257 | static void omap_dma_assign(struct omap_dmadev *od, struct omap_chan *c, | ||
258 | unsigned lch) | ||
259 | { | ||
260 | c->channel_base = od->base + od->plat->channel_stride * lch; | ||
261 | } | ||
262 | |||
201 | static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) | 263 | static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) |
202 | { | 264 | { |
203 | struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device); | 265 | struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device); |
@@ -400,18 +462,26 @@ static void omap_dma_sched(unsigned long data) | |||
400 | 462 | ||
401 | static int omap_dma_alloc_chan_resources(struct dma_chan *chan) | 463 | static int omap_dma_alloc_chan_resources(struct dma_chan *chan) |
402 | { | 464 | { |
465 | struct omap_dmadev *od = to_omap_dma_dev(chan->device); | ||
403 | struct omap_chan *c = to_omap_dma_chan(chan); | 466 | struct omap_chan *c = to_omap_dma_chan(chan); |
467 | int ret; | ||
468 | |||
469 | dev_dbg(od->ddev.dev, "allocating channel for %u\n", c->dma_sig); | ||
404 | 470 | ||
405 | dev_dbg(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig); | 471 | ret = omap_request_dma(c->dma_sig, "DMA engine", omap_dma_callback, |
472 | c, &c->dma_ch); | ||
406 | 473 | ||
407 | return omap_request_dma(c->dma_sig, "DMA engine", | 474 | if (ret >= 0) |
408 | omap_dma_callback, c, &c->dma_ch); | 475 | omap_dma_assign(od, c, c->dma_ch); |
476 | |||
477 | return ret; | ||
409 | } | 478 | } |
410 | 479 | ||
411 | static void omap_dma_free_chan_resources(struct dma_chan *chan) | 480 | static void omap_dma_free_chan_resources(struct dma_chan *chan) |
412 | { | 481 | { |
413 | struct omap_chan *c = to_omap_dma_chan(chan); | 482 | struct omap_chan *c = to_omap_dma_chan(chan); |
414 | 483 | ||
484 | c->channel_base = NULL; | ||
415 | vchan_free_chan_resources(&c->vc); | 485 | vchan_free_chan_resources(&c->vc); |
416 | omap_free_dma(c->dma_ch); | 486 | omap_free_dma(c->dma_ch); |
417 | 487 | ||
@@ -917,7 +987,7 @@ static int omap_dma_chan_init(struct omap_dmadev *od, int dma_sig) | |||
917 | if (!c) | 987 | if (!c) |
918 | return -ENOMEM; | 988 | return -ENOMEM; |
919 | 989 | ||
920 | c->plat = od->plat; | 990 | c->reg_map = od->reg_map; |
921 | c->dma_sig = dma_sig; | 991 | c->dma_sig = dma_sig; |
922 | c->vc.desc_free = omap_dma_desc_free; | 992 | c->vc.desc_free = omap_dma_desc_free; |
923 | vchan_init(&c->vc, &od->ddev); | 993 | vchan_init(&c->vc, &od->ddev); |
@@ -944,16 +1014,24 @@ static void omap_dma_free(struct omap_dmadev *od) | |||
944 | static int omap_dma_probe(struct platform_device *pdev) | 1014 | static int omap_dma_probe(struct platform_device *pdev) |
945 | { | 1015 | { |
946 | struct omap_dmadev *od; | 1016 | struct omap_dmadev *od; |
1017 | struct resource *res; | ||
947 | int rc, i; | 1018 | int rc, i; |
948 | 1019 | ||
949 | od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); | 1020 | od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); |
950 | if (!od) | 1021 | if (!od) |
951 | return -ENOMEM; | 1022 | return -ENOMEM; |
952 | 1023 | ||
1024 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1025 | od->base = devm_ioremap_resource(&pdev->dev, res); | ||
1026 | if (IS_ERR(od->base)) | ||
1027 | return PTR_ERR(od->base); | ||
1028 | |||
953 | od->plat = omap_get_plat_info(); | 1029 | od->plat = omap_get_plat_info(); |
954 | if (!od->plat) | 1030 | if (!od->plat) |
955 | return -EPROBE_DEFER; | 1031 | return -EPROBE_DEFER; |
956 | 1032 | ||
1033 | od->reg_map = od->plat->reg_map; | ||
1034 | |||
957 | dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); | 1035 | dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); |
958 | dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); | 1036 | dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); |
959 | od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources; | 1037 | od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources; |
diff --git a/include/linux/omap-dma.h b/include/linux/omap-dma.h index 7813636a193d..41a13e70f41f 100644 --- a/include/linux/omap-dma.h +++ b/include/linux/omap-dma.h | |||
@@ -285,6 +285,8 @@ struct omap_dma_reg { | |||
285 | 285 | ||
286 | /* System DMA platform data structure */ | 286 | /* System DMA platform data structure */ |
287 | struct omap_system_dma_plat_info { | 287 | struct omap_system_dma_plat_info { |
288 | const struct omap_dma_reg *reg_map; | ||
289 | unsigned channel_stride; | ||
288 | struct omap_dma_dev_attr *dma_attr; | 290 | struct omap_dma_dev_attr *dma_attr; |
289 | u32 errata; | 291 | u32 errata; |
290 | void (*show_dma_caps)(void); | 292 | void (*show_dma_caps)(void); |