aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Reichl <hias@horus.com>2016-04-27 09:26:51 -0400
committerMark Brown <broonie@kernel.org>2016-04-27 12:34:11 -0400
commit73fe01cfb3babff01748a9fbc95cc3ea2079cc7f (patch)
treef3f6b72b1fa9e2d0374f9417c9e97f1779d5af4a
parentf55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff)
ASoC: dmaengine_pcm: Add support for packed transfers
dmaengine_pcm currently only supports setups where FIFO reads/writes correspond to exactly one sample, eg 16-bit sample data is transferred via 16-bit FIFO accesses, 32-bit data via 32-bit accesses. This patch adds support for setups with fixed width FIFOs where multiple samples are packed into a larger word. For example setups with a 32-bit wide FIFO register that expect 16-bit sample transfers to be done with the left+right sample data packed into a 32-bit word. Support for packed transfers is controlled via the SND_DMAENGINE_PCM_DAI_FLAG_PACK flag in snd_dmaengine_dai_dma_data.flags If this flag is set dmaengine_pcm doesn't put any restriction on the supported formats and sets the DMA transfer width to undefined. This means control over the constraints is now transferred to the DAI driver and it's responsible to provide proper configuration and check for possible corner cases that aren't handled by the ALSA core. Signed-off-by: Matthias Reichl <hias@horus.com> Acked-by: Lars-Peter Clausen <lars@metafoo.de> Tested-by: Martin Sperl <kernel@martin.sperl.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--include/sound/dmaengine_pcm.h12
-rw-r--r--sound/core/pcm_dmaengine.c11
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c57
3 files changed, 55 insertions, 25 deletions
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index f86ef5ea9b01..67be2445941a 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -51,6 +51,16 @@ struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
51 void *filter_data); 51 void *filter_data);
52struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); 52struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
53 53
54/*
55 * The DAI supports packed transfers, eg 2 16-bit samples in a 32-bit word.
56 * If this flag is set the dmaengine driver won't put any restriction on
57 * the supported sample formats and set the DMA transfer size to undefined.
58 * The DAI driver is responsible to disable any unsupported formats in it's
59 * configuration and catch corner cases that are not already handled in
60 * the ALSA core.
61 */
62#define SND_DMAENGINE_PCM_DAI_FLAG_PACK BIT(0)
63
54/** 64/**
55 * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data 65 * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data
56 * @addr: Address of the DAI data source or destination register. 66 * @addr: Address of the DAI data source or destination register.
@@ -63,6 +73,7 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
63 * requesting the DMA channel. 73 * requesting the DMA channel.
64 * @chan_name: Custom channel name to use when requesting DMA channel. 74 * @chan_name: Custom channel name to use when requesting DMA channel.
65 * @fifo_size: FIFO size of the DAI controller in bytes 75 * @fifo_size: FIFO size of the DAI controller in bytes
76 * @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now
66 */ 77 */
67struct snd_dmaengine_dai_dma_data { 78struct snd_dmaengine_dai_dma_data {
68 dma_addr_t addr; 79 dma_addr_t addr;
@@ -72,6 +83,7 @@ struct snd_dmaengine_dai_dma_data {
72 void *filter_data; 83 void *filter_data;
73 const char *chan_name; 84 const char *chan_name;
74 unsigned int fifo_size; 85 unsigned int fifo_size;
86 unsigned int flags;
75}; 87};
76 88
77void snd_dmaengine_pcm_set_config_from_dai_data( 89void snd_dmaengine_pcm_set_config_from_dai_data(
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index 697c166acf05..8eb58c709b14 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -106,8 +106,9 @@ EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
106 * direction of the substream. If the substream is a playback stream the dst 106 * direction of the substream. If the substream is a playback stream the dst
107 * fields will be initialized, if it is a capture stream the src fields will be 107 * fields will be initialized, if it is a capture stream the src fields will be
108 * initialized. The {dst,src}_addr_width field will only be initialized if the 108 * initialized. The {dst,src}_addr_width field will only be initialized if the
109 * addr_width field of the DAI DMA data struct is not equal to 109 * SND_DMAENGINE_PCM_DAI_FLAG_PACK flag is set or if the addr_width field of
110 * DMA_SLAVE_BUSWIDTH_UNDEFINED. 110 * the DAI DMA data struct is not equal to DMA_SLAVE_BUSWIDTH_UNDEFINED. If
111 * both conditions are met the latter takes priority.
111 */ 112 */
112void snd_dmaengine_pcm_set_config_from_dai_data( 113void snd_dmaengine_pcm_set_config_from_dai_data(
113 const struct snd_pcm_substream *substream, 114 const struct snd_pcm_substream *substream,
@@ -117,11 +118,17 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
117 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 118 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
118 slave_config->dst_addr = dma_data->addr; 119 slave_config->dst_addr = dma_data->addr;
119 slave_config->dst_maxburst = dma_data->maxburst; 120 slave_config->dst_maxburst = dma_data->maxburst;
121 if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)
122 slave_config->dst_addr_width =
123 DMA_SLAVE_BUSWIDTH_UNDEFINED;
120 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) 124 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
121 slave_config->dst_addr_width = dma_data->addr_width; 125 slave_config->dst_addr_width = dma_data->addr_width;
122 } else { 126 } else {
123 slave_config->src_addr = dma_data->addr; 127 slave_config->src_addr = dma_data->addr;
124 slave_config->src_maxburst = dma_data->maxburst; 128 slave_config->src_maxburst = dma_data->maxburst;
129 if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)
130 slave_config->src_addr_width =
131 DMA_SLAVE_BUSWIDTH_UNDEFINED;
125 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) 132 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
126 slave_config->src_addr_width = dma_data->addr_width; 133 slave_config->src_addr_width = dma_data->addr_width;
127 } 134 }
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 6fd1906af387..6cef3977507a 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -163,31 +163,42 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
163 } 163 }
164 164
165 /* 165 /*
166 * Prepare formats mask for valid/allowed sample types. If the dma does 166 * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep
167 * not have support for the given physical word size, it needs to be 167 * hw.formats set to 0, meaning no restrictions are in place.
168 * masked out so user space can not use the format which produces 168 * In this case it's the responsibility of the DAI driver to
169 * corrupted audio. 169 * provide the supported format information.
170 * In case the dma driver does not implement the slave_caps the default
171 * assumption is that it supports 1, 2 and 4 bytes widths.
172 */ 170 */
173 for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { 171 if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK))
174 int bits = snd_pcm_format_physical_width(i); 172 /*
175 173 * Prepare formats mask for valid/allowed sample types. If the
176 /* Enable only samples with DMA supported physical widths */ 174 * dma does not have support for the given physical word size,
177 switch (bits) { 175 * it needs to be masked out so user space can not use the
178 case 8: 176 * format which produces corrupted audio.
179 case 16: 177 * In case the dma driver does not implement the slave_caps the
180 case 24: 178 * default assumption is that it supports 1, 2 and 4 bytes
181 case 32: 179 * widths.
182 case 64: 180 */
183 if (addr_widths & (1 << (bits / 8))) 181 for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
184 hw.formats |= (1LL << i); 182 int bits = snd_pcm_format_physical_width(i);
185 break; 183
186 default: 184 /*
187 /* Unsupported types */ 185 * Enable only samples with DMA supported physical
188 break; 186 * widths
187 */
188 switch (bits) {
189 case 8:
190 case 16:
191 case 24:
192 case 32:
193 case 64:
194 if (addr_widths & (1 << (bits / 8)))
195 hw.formats |= (1LL << i);
196 break;
197 default:
198 /* Unsupported types */
199 break;
200 }
189 } 201 }
190 }
191 202
192 return snd_soc_set_runtime_hwparams(substream, &hw); 203 return snd_soc_set_runtime_hwparams(substream, &hw);
193} 204}