aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurentiu Tudor <laurentiu.tudor@nxp.com>2019-01-18 05:06:23 -0500
committerVinod Koul <vkoul@kernel.org>2019-02-04 02:02:53 -0500
commit0fa89f972da607540497f11afbb47af6fea5bce0 (patch)
treeb5280ac2761f300c28447ff595ae46088ab92ee8
parentde1fa4f61be71725581c8e30f3665aaa20d1610e (diff)
dmaengine: fsl-edma: dma map slave device address
This mapping needs to be created in order for slave dma transfers to work on systems with SMMU. The implementation mostly mimics the one in pl330 dma driver, authored by Robin Murphy. Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com> Suggested-by: Robin Murphy <robin.murphy@arm.com> Tested-by: Angelo Dureghello <angelo@sysam.it> Signed-off-by: Vinod Koul <vkoul@kernel.org>
-rw-r--r--drivers/dma/fsl-edma-common.c66
-rw-r--r--drivers/dma/fsl-edma-common.h4
-rw-r--r--drivers/dma/fsl-edma.c1
-rw-r--r--drivers/dma/mcf-edma.c1
4 files changed, 68 insertions, 4 deletions
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index fe529100674f..680b2a00a953 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -6,6 +6,7 @@
6#include <linux/dmapool.h> 6#include <linux/dmapool.h>
7#include <linux/module.h> 7#include <linux/module.h>
8#include <linux/slab.h> 8#include <linux/slab.h>
9#include <linux/dma-mapping.h>
9 10
10#include "fsl-edma-common.h" 11#include "fsl-edma-common.h"
11 12
@@ -173,12 +174,62 @@ int fsl_edma_resume(struct dma_chan *chan)
173} 174}
174EXPORT_SYMBOL_GPL(fsl_edma_resume); 175EXPORT_SYMBOL_GPL(fsl_edma_resume);
175 176
177static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan)
178{
179 if (fsl_chan->dma_dir != DMA_NONE)
180 dma_unmap_resource(fsl_chan->vchan.chan.device->dev,
181 fsl_chan->dma_dev_addr,
182 fsl_chan->dma_dev_size,
183 fsl_chan->dma_dir, 0);
184 fsl_chan->dma_dir = DMA_NONE;
185}
186
187static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan,
188 enum dma_transfer_direction dir)
189{
190 struct device *dev = fsl_chan->vchan.chan.device->dev;
191 enum dma_data_direction dma_dir;
192 phys_addr_t addr = 0;
193 u32 size = 0;
194
195 switch (dir) {
196 case DMA_MEM_TO_DEV:
197 dma_dir = DMA_FROM_DEVICE;
198 addr = fsl_chan->cfg.dst_addr;
199 size = fsl_chan->cfg.dst_maxburst;
200 break;
201 case DMA_DEV_TO_MEM:
202 dma_dir = DMA_TO_DEVICE;
203 addr = fsl_chan->cfg.src_addr;
204 size = fsl_chan->cfg.src_maxburst;
205 break;
206 default:
207 dma_dir = DMA_NONE;
208 break;
209 }
210
211 /* Already mapped for this config? */
212 if (fsl_chan->dma_dir == dma_dir)
213 return true;
214
215 fsl_edma_unprep_slave_dma(fsl_chan);
216
217 fsl_chan->dma_dev_addr = dma_map_resource(dev, addr, size, dma_dir, 0);
218 if (dma_mapping_error(dev, fsl_chan->dma_dev_addr))
219 return false;
220 fsl_chan->dma_dev_size = size;
221 fsl_chan->dma_dir = dma_dir;
222
223 return true;
224}
225
176int fsl_edma_slave_config(struct dma_chan *chan, 226int fsl_edma_slave_config(struct dma_chan *chan,
177 struct dma_slave_config *cfg) 227 struct dma_slave_config *cfg)
178{ 228{
179 struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); 229 struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
180 230
181 memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg)); 231 memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg));
232 fsl_edma_unprep_slave_dma(fsl_chan);
182 233
183 return 0; 234 return 0;
184} 235}
@@ -376,6 +427,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
376 if (!is_slave_direction(direction)) 427 if (!is_slave_direction(direction))
377 return NULL; 428 return NULL;
378 429
430 if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
431 return NULL;
432
379 sg_len = buf_len / period_len; 433 sg_len = buf_len / period_len;
380 fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len); 434 fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
381 if (!fsl_desc) 435 if (!fsl_desc)
@@ -407,11 +461,11 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
407 461
408 if (direction == DMA_MEM_TO_DEV) { 462 if (direction == DMA_MEM_TO_DEV) {
409 src_addr = dma_buf_next; 463 src_addr = dma_buf_next;
410 dst_addr = fsl_chan->cfg.dst_addr; 464 dst_addr = fsl_chan->dma_dev_addr;
411 soff = fsl_chan->cfg.dst_addr_width; 465 soff = fsl_chan->cfg.dst_addr_width;
412 doff = 0; 466 doff = 0;
413 } else { 467 } else {
414 src_addr = fsl_chan->cfg.src_addr; 468 src_addr = fsl_chan->dma_dev_addr;
415 dst_addr = dma_buf_next; 469 dst_addr = dma_buf_next;
416 soff = 0; 470 soff = 0;
417 doff = fsl_chan->cfg.src_addr_width; 471 doff = fsl_chan->cfg.src_addr_width;
@@ -442,6 +496,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
442 if (!is_slave_direction(direction)) 496 if (!is_slave_direction(direction))
443 return NULL; 497 return NULL;
444 498
499 if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
500 return NULL;
501
445 fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len); 502 fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
446 if (!fsl_desc) 503 if (!fsl_desc)
447 return NULL; 504 return NULL;
@@ -466,11 +523,11 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
466 523
467 if (direction == DMA_MEM_TO_DEV) { 524 if (direction == DMA_MEM_TO_DEV) {
468 src_addr = sg_dma_address(sg); 525 src_addr = sg_dma_address(sg);
469 dst_addr = fsl_chan->cfg.dst_addr; 526 dst_addr = fsl_chan->dma_dev_addr;
470 soff = fsl_chan->cfg.dst_addr_width; 527 soff = fsl_chan->cfg.dst_addr_width;
471 doff = 0; 528 doff = 0;
472 } else { 529 } else {
473 src_addr = fsl_chan->cfg.src_addr; 530 src_addr = fsl_chan->dma_dev_addr;
474 dst_addr = sg_dma_address(sg); 531 dst_addr = sg_dma_address(sg);
475 soff = 0; 532 soff = 0;
476 doff = fsl_chan->cfg.src_addr_width; 533 doff = fsl_chan->cfg.src_addr_width;
@@ -553,6 +610,7 @@ void fsl_edma_free_chan_resources(struct dma_chan *chan)
553 fsl_edma_chan_mux(fsl_chan, 0, false); 610 fsl_edma_chan_mux(fsl_chan, 0, false);
554 fsl_chan->edesc = NULL; 611 fsl_chan->edesc = NULL;
555 vchan_get_all_descriptors(&fsl_chan->vchan, &head); 612 vchan_get_all_descriptors(&fsl_chan->vchan, &head);
613 fsl_edma_unprep_slave_dma(fsl_chan);
556 spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); 614 spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
557 615
558 vchan_dma_desc_free_list(&fsl_chan->vchan, &head); 616 vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
index 8917e8865959..b435d8e1e3a1 100644
--- a/drivers/dma/fsl-edma-common.h
+++ b/drivers/dma/fsl-edma-common.h
@@ -6,6 +6,7 @@
6#ifndef _FSL_EDMA_COMMON_H_ 6#ifndef _FSL_EDMA_COMMON_H_
7#define _FSL_EDMA_COMMON_H_ 7#define _FSL_EDMA_COMMON_H_
8 8
9#include <linux/dma-direction.h>
9#include "virt-dma.h" 10#include "virt-dma.h"
10 11
11#define EDMA_CR_EDBG BIT(1) 12#define EDMA_CR_EDBG BIT(1)
@@ -120,6 +121,9 @@ struct fsl_edma_chan {
120 struct dma_slave_config cfg; 121 struct dma_slave_config cfg;
121 u32 attr; 122 u32 attr;
122 struct dma_pool *tcd_pool; 123 struct dma_pool *tcd_pool;
124 dma_addr_t dma_dev_addr;
125 u32 dma_dev_size;
126 enum dma_data_direction dma_dir;
123}; 127};
124 128
125struct fsl_edma_desc { 129struct fsl_edma_desc {
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 34d70112fcc9..75e8a7ba3a22 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -254,6 +254,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
254 fsl_chan->pm_state = RUNNING; 254 fsl_chan->pm_state = RUNNING;
255 fsl_chan->slave_id = 0; 255 fsl_chan->slave_id = 0;
256 fsl_chan->idle = true; 256 fsl_chan->idle = true;
257 fsl_chan->dma_dir = DMA_NONE;
257 fsl_chan->vchan.desc_free = fsl_edma_free_desc; 258 fsl_chan->vchan.desc_free = fsl_edma_free_desc;
258 vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev); 259 vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
259 260
diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c
index 5de1b07eddff..7de54b2fafdb 100644
--- a/drivers/dma/mcf-edma.c
+++ b/drivers/dma/mcf-edma.c
@@ -214,6 +214,7 @@ static int mcf_edma_probe(struct platform_device *pdev)
214 mcf_chan->edma = mcf_edma; 214 mcf_chan->edma = mcf_edma;
215 mcf_chan->slave_id = i; 215 mcf_chan->slave_id = i;
216 mcf_chan->idle = true; 216 mcf_chan->idle = true;
217 mcf_chan->dma_dir = DMA_NONE;
217 mcf_chan->vchan.desc_free = fsl_edma_free_desc; 218 mcf_chan->vchan.desc_free = fsl_edma_free_desc;
218 vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev); 219 vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev);
219 iowrite32(0x0, &regs->tcd[i].csr); 220 iowrite32(0x0, &regs->tcd[i].csr);