Blame view

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