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>
This commit is contained in:
committed by
Nitin Garg
parent
b013782b64
commit
dc6646b323
@ -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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user