summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorShengjiu Wang <b02247@freescale.com>2013-08-09 14:41:11 +0800
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 08:01:12 -0500
commit61cadfef966e6fc6e416c2f097891bd6ff61eddb (patch)
tree754031550a5784e63117eed58895c3d8c1f2f420 /drivers/dma
parente6ced15860c52eab111b8b4c7e9a9f8e60f87d1f (diff)
ENGR00274585-1 dma: imx-sdma: update sdma to support p2p
For the sake of support asrc p2p, the sdma driver need to be updated. 1. Add another dma_request, p2p need two dma_request. 2. There are some cases which need to change the config after the dma_request_channel. add dma_request config in dmaengine_slave_config(). 3. add dma_request0 and dma_request1 in dma_slave_config for runtime config in dmaengine_slave_config. Signed-off-by: Shengjiu Wang <b02247@freescale.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/imx-sdma.c103
1 files changed, 88 insertions, 15 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 190506ce15c5..174c98913b73 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -260,8 +260,9 @@ struct sdma_channel {
struct sdma_buffer_descriptor *bd;
dma_addr_t bd_phys;
unsigned int pc_from_device, pc_to_device;
+ unsigned int device_to_device;
unsigned long flags;
- dma_addr_t per_address;
+ dma_addr_t per_address, per_address2;
unsigned long event_mask[2];
unsigned long watermark_level;
u32 shp_addr, per_addr;
@@ -593,6 +594,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
sdmac->pc_from_device = 0;
sdmac->pc_to_device = 0;
+ sdmac->device_to_device = 0;
switch (peripheral_type) {
case IMX_DMATYPE_MEMORY:
@@ -661,6 +663,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
sdmac->pc_from_device = per_2_emi;
sdmac->pc_to_device = emi_2_per;
+ sdmac->device_to_device = per_2_per;
}
static int sdma_load_context(struct sdma_channel *sdmac)
@@ -673,11 +676,12 @@ static int sdma_load_context(struct sdma_channel *sdmac)
int ret;
unsigned long flags;
- if (sdmac->direction == DMA_DEV_TO_MEM) {
+ if (sdmac->direction == DMA_DEV_TO_MEM)
load_address = sdmac->pc_from_device;
- } else {
+ else if (sdmac->direction == DMA_DEV_TO_DEV)
+ load_address = sdmac->device_to_device;
+ else
load_address = sdmac->pc_to_device;
- }
if (load_address < 0)
return load_address;
@@ -740,6 +744,11 @@ static int sdma_config_channel(struct sdma_channel *sdmac)
return -EINVAL;
sdma_event_enable(sdmac, sdmac->event_id0);
}
+ if (sdmac->event_id1) {
+ if (sdmac->event_id1 >= sdmac->sdma->num_events)
+ return -EINVAL;
+ sdma_event_enable(sdmac, sdmac->event_id1);
+ }
switch (sdmac->peripheral_type) {
case IMX_DMATYPE_DSP:
@@ -759,19 +768,68 @@ static int sdma_config_channel(struct sdma_channel *sdmac)
(sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
/* Handle multiple event channels differently */
if (sdmac->event_id1) {
- sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32);
- if (sdmac->event_id1 > 31)
- __set_bit(31, &sdmac->watermark_level);
- sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32);
- if (sdmac->event_id0 > 31)
- __set_bit(30, &sdmac->watermark_level);
+ if (sdmac->event_id0 > 31) {
+ sdmac->event_mask[0] |= 0;
+ __set_bit(28, &sdmac->watermark_level);
+ sdmac->event_mask[1] |=
+ BIT(sdmac->event_id0 % 32);
+ } else {
+ sdmac->event_mask[1] |= 0;
+ sdmac->event_mask[0] |=
+ BIT(sdmac->event_id0 % 32);
+ }
+ if (sdmac->event_id1 > 31) {
+ sdmac->event_mask[0] |= 0;
+ __set_bit(29, &sdmac->watermark_level);
+ sdmac->event_mask[1] |=
+ BIT(sdmac->event_id1 % 32);
+ } else {
+ sdmac->event_mask[1] |= 0;
+ sdmac->event_mask[0] |=
+ BIT(sdmac->event_id1 % 32);
+ }
+ /* BIT 11:
+ * 1 : Source on SPBA
+ * 0 : Source on AIPS
+ */
+ __set_bit(11, &sdmac->watermark_level);
+ /* BIT 12:
+ * 1 : Destination on SPBA
+ * 0 : Destination on AIPS
+ */
+ __set_bit(12, &sdmac->watermark_level);
+ __set_bit(31, &sdmac->watermark_level);
+ /* BIT 31:
+ * 1 : Amount of samples to be transferred is
+ * unknown and script will keep on transferring
+ * samples as long as both events are detected
+ * and script must be manually stopped by the
+ * application.
+ * 0 : The amount of samples to be is equal to
+ * the count field of mode word
+ * */
+ __set_bit(25, &sdmac->watermark_level);
+ __clear_bit(24, &sdmac->watermark_level);
} else {
- __set_bit(sdmac->event_id0, sdmac->event_mask);
+ if (sdmac->event_id0 > 31) {
+ sdmac->event_mask[0] = 0;
+ sdmac->event_mask[1] |=
+ BIT(sdmac->event_id0 % 32);
+ } else {
+ sdmac->event_mask[0] |=
+ BIT(sdmac->event_id0 % 32);
+ sdmac->event_mask[1] = 0;
+ }
}
/* Watermark Level */
sdmac->watermark_level |= sdmac->watermark_level;
/* Address */
- sdmac->shp_addr = sdmac->per_address;
+ if (sdmac->direction == DMA_DEV_TO_DEV) {
+ sdmac->shp_addr = sdmac->per_address2;
+ sdmac->per_addr = sdmac->per_address;
+ } else {
+ sdmac->shp_addr = sdmac->per_address;
+ }
} else {
sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
}
@@ -867,7 +925,8 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
}
sdmac->peripheral_type = data->peripheral_type;
- sdmac->event_id0 = data->dma_request;
+ sdmac->event_id0 = data->dma_request0;
+ sdmac->event_id1 = data->dma_request1;
clk_enable(sdmac->sdma->clk_ipg);
clk_enable(sdmac->sdma->clk_ahb);
@@ -1102,7 +1161,16 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
sdma_disable_channel(sdmac);
return 0;
case DMA_SLAVE_CONFIG:
- if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+ if (dmaengine_cfg->direction == DMA_DEV_TO_DEV) {
+ sdmac->per_address = dmaengine_cfg->src_addr;
+ sdmac->per_address2 = dmaengine_cfg->dst_addr;
+ sdmac->watermark_level = 0;
+ sdmac->watermark_level |=
+ dmaengine_cfg->src_maxburst;
+ sdmac->watermark_level |=
+ dmaengine_cfg->dst_maxburst << 16;
+ sdmac->word_size = dmaengine_cfg->dst_addr_width;
+ } else if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
sdmac->per_address = dmaengine_cfg->src_addr;
sdmac->watermark_level = dmaengine_cfg->src_maxburst *
dmaengine_cfg->src_addr_width;
@@ -1114,6 +1182,10 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
sdmac->word_size = dmaengine_cfg->dst_addr_width;
}
sdmac->direction = dmaengine_cfg->direction;
+ if (dmaengine_cfg->dma_request0)
+ sdmac->event_id0 = dmaengine_cfg->dma_request0;
+ if (dmaengine_cfg->dma_request1)
+ sdmac->event_id1 = dmaengine_cfg->dma_request1;
return sdma_config_channel(sdmac);
default:
return -ENOSYS;
@@ -1337,9 +1409,10 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
if (dma_spec->args_count != 3)
return NULL;
- data.dma_request = dma_spec->args[0];
+ data.dma_request0 = dma_spec->args[0];
data.peripheral_type = dma_spec->args[1];
data.priority = dma_spec->args[2];
+ data.dma_request1 = 0;
return dma_request_channel(mask, sdma_filter_fn, &data);
}