diff options
author | Shengjiu Wang <b02247@freescale.com> | 2013-08-09 14:41:11 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 08:01:12 -0500 |
commit | 61cadfef966e6fc6e416c2f097891bd6ff61eddb (patch) | |
tree | 754031550a5784e63117eed58895c3d8c1f2f420 /drivers/dma | |
parent | e6ced15860c52eab111b8b4c7e9a9f8e60f87d1f (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.c | 103 |
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); } |