diff options
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.patch | 80 |
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); |