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 | |
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>
-rw-r--r-- | drivers/dma/imx-sdma.c | 103 | ||||
-rw-r--r-- | include/linux/dmaengine.h | 4 | ||||
-rw-r--r-- | include/linux/platform_data/dma-imx.h | 3 | ||||
-rw-r--r-- | sound/soc/fsl/imx-pcm-dma.c | 56 | ||||
-rw-r--r-- | sound/soc/fsl/imx-pcm.h | 2 |
5 files changed, 150 insertions, 18 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); } diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 96d3e4ab11a9..1b9cdc1fa655 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -341,6 +341,8 @@ enum dma_slave_buswidth { * @slave_id: Slave requester id. Only valid for slave channels. The dma * slave peripheral will have unique id as dma requester which need to be * pass as slave config. + * @dma_request0: this is the first dma request of this dma channel. + * @dma_request1: this is the second dma request of this dma channel. * * This struct is passed in as configuration data to a DMA engine * in order to set up a certain channel for DMA transport at runtime. @@ -369,6 +371,8 @@ struct dma_slave_config { u32 dst_maxburst; bool device_fc; unsigned int slave_id; + int dma_request0; + int dma_request1; }; static inline const char *dma_chan_name(struct dma_chan *chan) diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index 3558f05273a3..ac4e9e958e82 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -48,7 +48,8 @@ enum imx_dma_prio { }; struct imx_dma_data { - int dma_request; /* DMA request line */ + int dma_request0; /* DMA request line */ + int dma_request1; enum sdma_peripheral_type peripheral_type; int priority; }; diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index b9447730f9df..4a8e5d28fd21 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/dmaengine.h> #include <linux/types.h> +#include <linux/platform_data/dma-imx.h> #include <sound/core.h> #include <sound/pcm.h> @@ -53,9 +54,62 @@ static const struct snd_pcm_hardware imx_pcm_hardware = { .fifo_size = 0, }; +static void imx_pcm_dma_set_config_from_dai_data( + const struct snd_pcm_substream *substream, + const struct snd_dmaengine_dai_dma_data *dma_data, + struct dma_slave_config *slave_config) +{ + struct imx_dma_data *filter_data = dma_data->filter_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->dst_addr = dma_data->addr; + slave_config->dst_maxburst = dma_data->maxburst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->dst_addr_width = dma_data->addr_width; + } else { + slave_config->src_addr = dma_data->addr; + slave_config->src_maxburst = dma_data->maxburst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->src_addr_width = dma_data->addr_width; + } + + slave_config->slave_id = dma_data->slave_id; + + /* + * In dma binding mode, there is no filter_data, so dma_request need to be + * set to zero. + */ + if (filter_data) { + slave_config->dma_request0 = filter_data->dma_request0; + slave_config->dma_request1 = filter_data->dma_request1; + } else { + slave_config->dma_request0 = 0; + slave_config->dma_request1 = 0; + } +} + +static int imx_pcm_dma_prepare_slave_config(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_dmaengine_dai_dma_data *dma_data; + int ret; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); + if (ret) + return ret; + + imx_pcm_dma_set_config_from_dai_data(substream, dma_data, + slave_config); + + return 0; +} + static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = { .pcm_hardware = &imx_pcm_hardware, - .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .prepare_slave_config = imx_pcm_dma_prepare_slave_config, .compat_filter_fn = filter, .prealloc_buffer_size = IMX_SSI_DMABUF_SIZE, }; diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 20b46f285d45..233717059de9 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -24,7 +24,7 @@ static inline void imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, int dma, bool shared) { - dma_data->dma_request = dma; + dma_data->dma_request0 = dma; dma_data->priority = DMA_PRIO_HIGH; if (shared) dma_data->peripheral_type = IMX_DMATYPE_SSI_SP; |