Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * PCM DRM helpers
4 : : */
5 : : #include <linux/export.h>
6 : : #include <drm/drm_edid.h>
7 : : #include <sound/pcm.h>
8 : : #include <sound/pcm_drm_eld.h>
9 : :
10 : : static const unsigned int eld_rates[] = {
11 : : 32000,
12 : : 44100,
13 : : 48000,
14 : : 88200,
15 : : 96000,
16 : : 176400,
17 : : 192000,
18 : : };
19 : :
20 : : static unsigned int sad_max_channels(const u8 *sad)
21 : : {
22 : 0 : return 1 + (sad[0] & 7);
23 : : }
24 : :
25 : 0 : static int eld_limit_rates(struct snd_pcm_hw_params *params,
26 : : struct snd_pcm_hw_rule *rule)
27 : : {
28 : 0 : struct snd_interval *r = hw_param_interval(params, rule->var);
29 : : const struct snd_interval *c;
30 : : unsigned int rate_mask = 7, i;
31 : 0 : const u8 *sad, *eld = rule->private;
32 : :
33 : : sad = drm_eld_sad(eld);
34 [ # # ]: 0 : if (sad) {
35 : : c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
36 : :
37 [ # # ]: 0 : for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) {
38 : : unsigned max_channels = sad_max_channels(sad);
39 : :
40 : : /*
41 : : * Exclude SADs which do not include the
42 : : * requested number of channels.
43 : : */
44 [ # # ]: 0 : if (c->min <= max_channels)
45 : 0 : rate_mask |= sad[1];
46 : : }
47 : : }
48 : :
49 : 0 : return snd_interval_list(r, ARRAY_SIZE(eld_rates), eld_rates,
50 : : rate_mask);
51 : : }
52 : :
53 : 0 : static int eld_limit_channels(struct snd_pcm_hw_params *params,
54 : : struct snd_pcm_hw_rule *rule)
55 : : {
56 : 0 : struct snd_interval *c = hw_param_interval(params, rule->var);
57 : : const struct snd_interval *r;
58 : 0 : struct snd_interval t = { .min = 1, .max = 2, .integer = 1, };
59 : : unsigned int i;
60 : 0 : const u8 *sad, *eld = rule->private;
61 : :
62 : : sad = drm_eld_sad(eld);
63 [ # # ]: 0 : if (sad) {
64 : : unsigned int rate_mask = 0;
65 : :
66 : : /* Convert the rate interval to a mask */
67 : : r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
68 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(eld_rates); i++)
69 [ # # # # ]: 0 : if (r->min <= eld_rates[i] && r->max >= eld_rates[i])
70 : 0 : rate_mask |= BIT(i);
71 : :
72 [ # # ]: 0 : for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
73 [ # # ]: 0 : if (rate_mask & sad[1])
74 : 0 : t.max = max(t.max, sad_max_channels(sad));
75 : : }
76 : :
77 : 0 : return snd_interval_refine(c, &t);
78 : : }
79 : :
80 : 0 : int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld)
81 : : {
82 : : int ret;
83 : :
84 : 0 : ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
85 : : eld_limit_rates, eld,
86 : : SNDRV_PCM_HW_PARAM_CHANNELS, -1);
87 [ # # ]: 0 : if (ret < 0)
88 : : return ret;
89 : :
90 : 0 : ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
91 : : eld_limit_channels, eld,
92 : : SNDRV_PCM_HW_PARAM_RATE, -1);
93 : :
94 : 0 : return ret;
95 : : }
96 : : EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld);
|