brcm2708: update linux 4.4 patches to latest version
[openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0129-bcm2835-restrict-channels-rate-to-8-960000.patch
1 From 7e634c8f8fe70286e0b8b404494d3143aa7bc3fc Mon Sep 17 00:00:00 2001
2 From: wm4 <wm4@nowhere>
3 Date: Wed, 13 Jan 2016 19:42:18 +0100
4 Subject: [PATCH 129/170] bcm2835: restrict channels*rate to 8*960000
5
6 This is required at least for SPDIF. If the bitrate goes above,
7 videocore will either resample the audio or corrupt it due to
8 underruns. Supposedly the hardware isn't designed to output
9 higher rates, but it can still resample it down to supported
10 rates.
11
12 Some code is based on ac97_pcm.c.
13 ---
14  sound/arm/bcm2835-pcm.c | 41 +++++++++++++++++++++++++++++++++++++++++
15  1 file changed, 41 insertions(+)
16
17 --- a/sound/arm/bcm2835-pcm.c
18 +++ b/sound/arm/bcm2835-pcm.c
19 @@ -19,6 +19,9 @@
20  
21  #include "bcm2835.h"
22  
23 +/* The hardware can not do much more num_channels*samplerate then this value */
24 +#define MAX_COMBINED_RATE 768000
25 +
26  /* hardware definition */
27  static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
28         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
29 @@ -107,6 +110,31 @@ static irqreturn_t bcm2835_playback_fifo
30         return IRQ_HANDLED;
31  }
32  
33 +
34 +static int rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
35 +                                  struct snd_pcm_hw_rule *rule)
36 +{
37 +       struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
38 +       struct snd_interval rates = {
39 +               .min = 8000,
40 +               .max = min(192000u, MAX_COMBINED_RATE / max(channels->min, 1u)),
41 +       };
42 +       struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
43 +       return snd_interval_refine(rate, &rates);
44 +}
45 +
46 +static int rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
47 +                                      struct snd_pcm_hw_rule *rule)
48 +{
49 +       struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
50 +       struct snd_interval channels_interval = {
51 +               .min = 1,
52 +               .max = min(8u, MAX_COMBINED_RATE / max(rate->min, 1u)),
53 +       };
54 +       struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
55 +       return snd_interval_refine(channels, &channels_interval);
56 +}
57 +
58  /* open callback */
59  static int snd_bcm2835_playback_open_generic(
60                 struct snd_pcm_substream *substream, int spdif)
61 @@ -188,6 +216,19 @@ static int snd_bcm2835_playback_open_gen
62         snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
63                                    16);
64  
65 +       /* When playing PCM, pretend that we support the full range of channels
66 +        * and sample rates. The GPU can't output it, but is able to resample
67 +        * the data to a rate the hardware can handle it. This won't work with
68 +        * compressed data; the resampler would just destroy it. */
69 +       if (spdif) {
70 +               err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
71 +                                         rate_hw_constraint_rate, NULL,
72 +                                         SNDRV_PCM_HW_PARAM_CHANNELS, -1);
73 +               err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
74 +                                         rate_hw_constraint_channels, NULL,
75 +                                         SNDRV_PCM_HW_PARAM_RATE, -1);
76 +       }
77 +
78         chip->alsa_stream[idx] = alsa_stream;
79  
80         chip->opened |= (1 << idx);