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);