diff options
author | Peter Ujfalusi <peter.ujfalusi@nokia.com> | 2010-06-03 00:39:36 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2010-06-03 11:12:40 -0400 |
commit | ddc29b0104d69e3742e6a9f23184fb6184614403 (patch) | |
tree | 653558a4d808b89f20fd0fcacc6c239603ef84ee /sound/soc/omap | |
parent | 3f024039e08598521a2c4c3eaedf8de2119797f4 (diff) |
ASoC: omap-mcbsp: Place correct constraints for streams
OMAP McBSP FIFO is word structured:
McBSP2 has 1024 + 256 = 1280 word long buffer,
McBSP1,3,4,5 has 128 word long buffer
This means, that the size of the FIFO
depends on the McBSP word size configuration.
For example on McBSP3:
16bit samples: size is 128 * 2 = 256 bytes
32bit samples: size is 128 * 4 = 512 bytes
It is simpler to place constraint for buffer and period based on channels.
McBSP3 as example again (16 or 32 bit samples):
1 channel (mono): size is 128 frames (128 words)
2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
Use the second method to place hw_rule on buffer size, and in threshold
mode to period size.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Acked-by: Jarkko Nikula <jhnikula@gmail.com>
Acked-by: Mark Brown <broonie@opensource.wolsfonmicro.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/omap')
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 98 |
1 files changed, 77 insertions, 21 deletions
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index b06d8f1620d7..aebd3af2ab79 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -173,6 +173,50 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) | |||
173 | omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words); | 173 | omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words); |
174 | } | 174 | } |
175 | 175 | ||
176 | static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, | ||
177 | struct snd_pcm_hw_rule *rule) | ||
178 | { | ||
179 | struct snd_interval *buffer_size = hw_param_interval(params, | ||
180 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE); | ||
181 | struct snd_interval *channels = hw_param_interval(params, | ||
182 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
183 | struct omap_mcbsp_data *mcbsp_data = rule->private; | ||
184 | struct snd_interval frames; | ||
185 | int size; | ||
186 | |||
187 | snd_interval_any(&frames); | ||
188 | size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id); | ||
189 | |||
190 | frames.min = size / channels->min; | ||
191 | frames.integer = 1; | ||
192 | return snd_interval_refine(buffer_size, &frames); | ||
193 | } | ||
194 | |||
195 | static int omap_mcbsp_hwrule_max_periodsize(struct snd_pcm_hw_params *params, | ||
196 | struct snd_pcm_hw_rule *rule) | ||
197 | { | ||
198 | struct snd_interval *period_size = hw_param_interval(params, | ||
199 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE); | ||
200 | struct snd_interval *channels = hw_param_interval(params, | ||
201 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
202 | struct snd_pcm_substream *substream = rule->private; | ||
203 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
204 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
205 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | ||
206 | struct snd_interval frames; | ||
207 | int size; | ||
208 | |||
209 | snd_interval_any(&frames); | ||
210 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
211 | size = omap_mcbsp_get_max_tx_threshold(mcbsp_data->bus_id); | ||
212 | else | ||
213 | size = omap_mcbsp_get_max_rx_threshold(mcbsp_data->bus_id); | ||
214 | |||
215 | frames.max = size / channels->min; | ||
216 | frames.integer = 1; | ||
217 | return snd_interval_refine(period_size, &frames); | ||
218 | } | ||
219 | |||
176 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, | 220 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, |
177 | struct snd_soc_dai *dai) | 221 | struct snd_soc_dai *dai) |
178 | { | 222 | { |
@@ -185,33 +229,45 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, | |||
185 | if (!cpu_dai->active) | 229 | if (!cpu_dai->active) |
186 | err = omap_mcbsp_request(bus_id); | 230 | err = omap_mcbsp_request(bus_id); |
187 | 231 | ||
232 | /* | ||
233 | * OMAP3 McBSP FIFO is word structured. | ||
234 | * McBSP2 has 1024 + 256 = 1280 word long buffer, | ||
235 | * McBSP1,3,4,5 has 128 word long buffer | ||
236 | * This means that the size of the FIFO depends on the sample format. | ||
237 | * For example on McBSP3: | ||
238 | * 16bit samples: size is 128 * 2 = 256 bytes | ||
239 | * 32bit samples: size is 128 * 4 = 512 bytes | ||
240 | * It is simpler to place constraint for buffer and period based on | ||
241 | * channels. | ||
242 | * McBSP3 as example again (16 or 32 bit samples): | ||
243 | * 1 channel (mono): size is 128 frames (128 words) | ||
244 | * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) | ||
245 | * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) | ||
246 | */ | ||
188 | if (cpu_is_omap343x()) { | 247 | if (cpu_is_omap343x()) { |
189 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); | 248 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); |
190 | int max_period; | ||
191 | 249 | ||
192 | /* | 250 | /* |
193 | * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. | 251 | * The first rule is for the buffer size, we should not allow |
194 | * Set constraint for minimum buffer size to the same than FIFO | 252 | * smaller buffer than the FIFO size to avoid underruns |
195 | * size in order to avoid underruns in playback startup because | 253 | */ |
196 | * HW is keeping the DMA request active until FIFO is filled. | 254 | snd_pcm_hw_rule_add(substream->runtime, 0, |
197 | */ | 255 | SNDRV_PCM_HW_PARAM_CHANNELS, |
198 | if (bus_id == 1) | 256 | omap_mcbsp_hwrule_min_buffersize, |
199 | snd_pcm_hw_constraint_minmax(substream->runtime, | 257 | mcbsp_data, |
200 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | 258 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); |
201 | 4096, UINT_MAX); | ||
202 | |||
203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
204 | max_period = omap_mcbsp_get_max_tx_threshold(bus_id); | ||
205 | else | ||
206 | max_period = omap_mcbsp_get_max_rx_threshold(bus_id); | ||
207 | |||
208 | max_period++; | ||
209 | max_period <<= 1; | ||
210 | 259 | ||
260 | /* | ||
261 | * In case of threshold mode, the rule will ensure, that the | ||
262 | * period size is not bigger than the maximum allowed threshold | ||
263 | * value. | ||
264 | */ | ||
211 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) | 265 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) |
212 | snd_pcm_hw_constraint_minmax(substream->runtime, | 266 | snd_pcm_hw_rule_add(substream->runtime, 0, |
213 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | 267 | SNDRV_PCM_HW_PARAM_CHANNELS, |
214 | 32, max_period); | 268 | omap_mcbsp_hwrule_max_periodsize, |
269 | substream, | ||
270 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); | ||
215 | } | 271 | } |
216 | 272 | ||
217 | return err; | 273 | return err; |