aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch')
-rw-r--r--target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch80
1 files changed, 80 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch b/target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch
new file mode 100644
index 0000000000..8b18cd6828
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0127-bcm2835-restrict-channels-rate-to-8-960000.patch
@@ -0,0 +1,80 @@
+From 435962380099cafba4db3d3806b8e03cbcb0774e Mon Sep 17 00:00:00 2001
+From: wm4 <wm4@nowhere>
+Date: Wed, 13 Jan 2016 19:42:18 +0100
+Subject: [PATCH 127/232] bcm2835: restrict channels*rate to 8*960000
+
+This is required at least for SPDIF. If the bitrate goes above,
+videocore will either resample the audio or corrupt it due to
+underruns. Supposedly the hardware isn't designed to output
+higher rates, but it can still resample it down to supported
+rates.
+
+Some code is based on ac97_pcm.c.
+---
+ sound/arm/bcm2835-pcm.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -19,6 +19,9 @@
+
+ #include "bcm2835.h"
+
++/* The hardware can not do much more num_channels*samplerate then this value */
++#define MAX_COMBINED_RATE 768000
++
+ /* hardware definition */
+ static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+@@ -107,6 +110,31 @@ static irqreturn_t bcm2835_playback_fifo
+ return IRQ_HANDLED;
+ }
+
++
++static int rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
++ struct snd_pcm_hw_rule *rule)
++{
++ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
++ struct snd_interval rates = {
++ .min = 8000,
++ .max = min(192000u, MAX_COMBINED_RATE / max(channels->min, 1u)),
++ };
++ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
++ return snd_interval_refine(rate, &rates);
++}
++
++static int rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
++ struct snd_pcm_hw_rule *rule)
++{
++ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
++ struct snd_interval channels_interval = {
++ .min = 1,
++ .max = min(8u, MAX_COMBINED_RATE / max(rate->min, 1u)),
++ };
++ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
++ return snd_interval_refine(channels, &channels_interval);
++}
++
+ /* open callback */
+ static int snd_bcm2835_playback_open_generic(
+ struct snd_pcm_substream *substream, int spdif)
+@@ -188,6 +216,19 @@ static int snd_bcm2835_playback_open_gen
+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ 16);
+
++ /* When playing PCM, pretend that we support the full range of channels
++ * and sample rates. The GPU can't output it, but is able to resample
++ * the data to a rate the hardware can handle it. This won't work with
++ * compressed data; the resampler would just destroy it. */
++ if (spdif) {
++ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
++ rate_hw_constraint_rate, NULL,
++ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
++ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
++ rate_hw_constraint_channels, NULL,
++ SNDRV_PCM_HW_PARAM_RATE, -1);
++ }
++
+ chip->alsa_stream[idx] = alsa_stream;
+
+ chip->opened |= (1 << idx);