]>
Commit | Line | Data |
---|---|---|
d0fa1179 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
7f4a9f43 WF |
2 | /* |
3 | * Generic routines and proc interface for ELD(EDID Like Data) information | |
4 | * | |
5 | * Copyright(c) 2008 Intel Corporation. | |
89250f84 | 6 | * Copyright (c) 2013 Anssi Hannula <[email protected]> |
7f4a9f43 WF |
7 | * |
8 | * Authors: | |
9 | * Wu Fengguang <[email protected]> | |
7f4a9f43 WF |
10 | */ |
11 | ||
12 | #include <linux/init.h> | |
5a0e3ad6 | 13 | #include <linux/slab.h> |
7f4a9f43 | 14 | #include <sound/core.h> |
5f60d5f6 | 15 | #include <linux/unaligned.h> |
2f6e8a85 | 16 | #include <sound/hda_chmap.h> |
be57bfff | 17 | #include <sound/hda_codec.h> |
7f4a9f43 WF |
18 | #include "hda_local.h" |
19 | ||
20 | enum eld_versions { | |
21 | ELD_VER_CEA_861D = 2, | |
22 | ELD_VER_PARTIAL = 31, | |
23 | }; | |
24 | ||
7f4a9f43 WF |
25 | enum cea_edid_versions { |
26 | CEA_EDID_VER_NONE = 0, | |
27 | CEA_EDID_VER_CEA861 = 1, | |
28 | CEA_EDID_VER_CEA861A = 2, | |
29 | CEA_EDID_VER_CEA861BCD = 3, | |
30 | CEA_EDID_VER_RESERVED = 4, | |
31 | }; | |
32 | ||
d5cf00c7 | 33 | static const char * const eld_connection_type_names[4] = { |
7f4a9f43 | 34 | "HDMI", |
9415e1c4 | 35 | "DisplayPort", |
7f4a9f43 WF |
36 | "2-reserved", |
37 | "3-reserved" | |
38 | }; | |
39 | ||
40 | enum cea_audio_coding_types { | |
41 | AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, | |
42 | AUDIO_CODING_TYPE_LPCM = 1, | |
43 | AUDIO_CODING_TYPE_AC3 = 2, | |
44 | AUDIO_CODING_TYPE_MPEG1 = 3, | |
45 | AUDIO_CODING_TYPE_MP3 = 4, | |
46 | AUDIO_CODING_TYPE_MPEG2 = 5, | |
47 | AUDIO_CODING_TYPE_AACLC = 6, | |
48 | AUDIO_CODING_TYPE_DTS = 7, | |
49 | AUDIO_CODING_TYPE_ATRAC = 8, | |
50 | AUDIO_CODING_TYPE_SACD = 9, | |
51 | AUDIO_CODING_TYPE_EAC3 = 10, | |
52 | AUDIO_CODING_TYPE_DTS_HD = 11, | |
53 | AUDIO_CODING_TYPE_MLP = 12, | |
54 | AUDIO_CODING_TYPE_DST = 13, | |
55 | AUDIO_CODING_TYPE_WMAPRO = 14, | |
56 | AUDIO_CODING_TYPE_REF_CXT = 15, | |
57 | /* also include valid xtypes below */ | |
58 | AUDIO_CODING_TYPE_HE_AAC = 15, | |
59 | AUDIO_CODING_TYPE_HE_AAC2 = 16, | |
60 | AUDIO_CODING_TYPE_MPEG_SURROUND = 17, | |
61 | }; | |
62 | ||
63 | enum cea_audio_coding_xtypes { | |
64 | AUDIO_CODING_XTYPE_HE_REF_CT = 0, | |
65 | AUDIO_CODING_XTYPE_HE_AAC = 1, | |
66 | AUDIO_CODING_XTYPE_HE_AAC2 = 2, | |
67 | AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, | |
68 | AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, | |
69 | }; | |
70 | ||
d5cf00c7 | 71 | static const char * const cea_audio_coding_type_names[] = { |
7f4a9f43 WF |
72 | /* 0 */ "undefined", |
73 | /* 1 */ "LPCM", | |
74 | /* 2 */ "AC-3", | |
75 | /* 3 */ "MPEG1", | |
76 | /* 4 */ "MP3", | |
77 | /* 5 */ "MPEG2", | |
78 | /* 6 */ "AAC-LC", | |
79 | /* 7 */ "DTS", | |
80 | /* 8 */ "ATRAC", | |
06f69d17 | 81 | /* 9 */ "DSD (One Bit Audio)", |
7f4a9f43 WF |
82 | /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", |
83 | /* 11 */ "DTS-HD", | |
84 | /* 12 */ "MLP (Dolby TrueHD)", | |
85 | /* 13 */ "DST", | |
86 | /* 14 */ "WMAPro", | |
87 | /* 15 */ "HE-AAC", | |
88 | /* 16 */ "HE-AACv2", | |
89 | /* 17 */ "MPEG Surround", | |
90 | }; | |
91 | ||
92 | /* | |
93 | * The following two lists are shared between | |
94 | * - HDMI audio InfoFrame (source to sink) | |
4e19c58f | 95 | * - CEA E-EDID Extension (sink to source) |
7f4a9f43 WF |
96 | */ |
97 | ||
98 | /* | |
99 | * SS1:SS0 index => sample size | |
100 | */ | |
bf82326f | 101 | static const int cea_sample_sizes[4] = { |
7f4a9f43 WF |
102 | 0, /* 0: Refer to Stream Header */ |
103 | AC_SUPPCM_BITS_16, /* 1: 16 bits */ | |
104 | AC_SUPPCM_BITS_20, /* 2: 20 bits */ | |
105 | AC_SUPPCM_BITS_24, /* 3: 24 bits */ | |
106 | }; | |
107 | ||
108 | /* | |
109 | * SF2:SF1:SF0 index => sampling frequency | |
110 | */ | |
bf82326f | 111 | static const int cea_sampling_frequencies[8] = { |
7f4a9f43 WF |
112 | 0, /* 0: Refer to Stream Header */ |
113 | SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ | |
114 | SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ | |
115 | SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ | |
116 | SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ | |
117 | SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ | |
118 | SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ | |
119 | SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ | |
120 | }; | |
121 | ||
b6acf013 | 122 | static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, |
7f4a9f43 WF |
123 | int byte_index) |
124 | { | |
125 | unsigned int val; | |
126 | ||
127 | val = snd_hda_codec_read(codec, nid, 0, | |
128 | AC_VERB_GET_HDMI_ELDD, byte_index); | |
7f4a9f43 | 129 | #ifdef BE_PARANOID |
4e76a883 | 130 | codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); |
7f4a9f43 | 131 | #endif |
b6acf013 | 132 | return val; |
7f4a9f43 WF |
133 | } |
134 | ||
135 | #define GRAB_BITS(buf, byte, lowbit, bits) \ | |
136 | ({ \ | |
137 | BUILD_BUG_ON(lowbit > 7); \ | |
138 | BUILD_BUG_ON(bits > 8); \ | |
139 | BUILD_BUG_ON(bits <= 0); \ | |
140 | \ | |
141 | (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ | |
142 | }) | |
143 | ||
79514d47 TI |
144 | static void hdmi_update_short_audio_desc(struct hda_codec *codec, |
145 | struct cea_sad *a, | |
7f4a9f43 WF |
146 | const unsigned char *buf) |
147 | { | |
148 | int i; | |
149 | int val; | |
150 | ||
151 | val = GRAB_BITS(buf, 1, 0, 7); | |
152 | a->rates = 0; | |
153 | for (i = 0; i < 7; i++) | |
154 | if (val & (1 << i)) | |
155 | a->rates |= cea_sampling_frequencies[i + 1]; | |
156 | ||
157 | a->channels = GRAB_BITS(buf, 0, 0, 3); | |
158 | a->channels++; | |
159 | ||
0bbaee3a AH |
160 | a->sample_bits = 0; |
161 | a->max_bitrate = 0; | |
162 | ||
7f4a9f43 WF |
163 | a->format = GRAB_BITS(buf, 0, 3, 4); |
164 | switch (a->format) { | |
165 | case AUDIO_CODING_TYPE_REF_STREAM_HEADER: | |
79514d47 | 166 | codec_info(codec, "HDMI: audio coding type 0 not expected\n"); |
7f4a9f43 WF |
167 | break; |
168 | ||
169 | case AUDIO_CODING_TYPE_LPCM: | |
170 | val = GRAB_BITS(buf, 2, 0, 3); | |
7f4a9f43 WF |
171 | for (i = 0; i < 3; i++) |
172 | if (val & (1 << i)) | |
173 | a->sample_bits |= cea_sample_sizes[i + 1]; | |
174 | break; | |
175 | ||
176 | case AUDIO_CODING_TYPE_AC3: | |
177 | case AUDIO_CODING_TYPE_MPEG1: | |
178 | case AUDIO_CODING_TYPE_MP3: | |
179 | case AUDIO_CODING_TYPE_MPEG2: | |
180 | case AUDIO_CODING_TYPE_AACLC: | |
181 | case AUDIO_CODING_TYPE_DTS: | |
182 | case AUDIO_CODING_TYPE_ATRAC: | |
183 | a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); | |
184 | a->max_bitrate *= 8000; | |
185 | break; | |
186 | ||
187 | case AUDIO_CODING_TYPE_SACD: | |
188 | break; | |
189 | ||
190 | case AUDIO_CODING_TYPE_EAC3: | |
191 | break; | |
192 | ||
193 | case AUDIO_CODING_TYPE_DTS_HD: | |
194 | break; | |
195 | ||
196 | case AUDIO_CODING_TYPE_MLP: | |
197 | break; | |
198 | ||
199 | case AUDIO_CODING_TYPE_DST: | |
200 | break; | |
201 | ||
202 | case AUDIO_CODING_TYPE_WMAPRO: | |
203 | a->profile = GRAB_BITS(buf, 2, 0, 3); | |
204 | break; | |
205 | ||
206 | case AUDIO_CODING_TYPE_REF_CXT: | |
207 | a->format = GRAB_BITS(buf, 2, 3, 5); | |
208 | if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || | |
209 | a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { | |
79514d47 TI |
210 | codec_info(codec, |
211 | "HDMI: audio coding xtype %d not expected\n", | |
212 | a->format); | |
7f4a9f43 WF |
213 | a->format = 0; |
214 | } else | |
215 | a->format += AUDIO_CODING_TYPE_HE_AAC - | |
216 | AUDIO_CODING_XTYPE_HE_AAC; | |
217 | break; | |
218 | } | |
219 | } | |
220 | ||
221 | /* | |
222 | * Be careful, ELD buf could be totally rubbish! | |
223 | */ | |
79514d47 | 224 | int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, |
1613d6b4 | 225 | const unsigned char *buf, int size) |
7f4a9f43 WF |
226 | { |
227 | int mnl; | |
228 | int i; | |
229 | ||
18014fd7 | 230 | memset(e, 0, sizeof(*e)); |
7f4a9f43 WF |
231 | e->eld_ver = GRAB_BITS(buf, 0, 3, 5); |
232 | if (e->eld_ver != ELD_VER_CEA_861D && | |
233 | e->eld_ver != ELD_VER_PARTIAL) { | |
79514d47 | 234 | codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver); |
7f4a9f43 WF |
235 | goto out_fail; |
236 | } | |
237 | ||
7f4a9f43 WF |
238 | e->baseline_len = GRAB_BITS(buf, 2, 0, 8); |
239 | mnl = GRAB_BITS(buf, 4, 0, 5); | |
240 | e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); | |
241 | ||
242 | e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); | |
243 | e->support_ai = GRAB_BITS(buf, 5, 1, 1); | |
244 | e->conn_type = GRAB_BITS(buf, 5, 2, 2); | |
245 | e->sad_count = GRAB_BITS(buf, 5, 4, 4); | |
246 | ||
247 | e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; | |
248 | e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); | |
249 | ||
250 | e->port_id = get_unaligned_le64(buf + 8); | |
251 | ||
252 | /* not specified, but the spec's tendency is little endian */ | |
253 | e->manufacture_id = get_unaligned_le16(buf + 16); | |
254 | e->product_id = get_unaligned_le16(buf + 18); | |
255 | ||
256 | if (mnl > ELD_MAX_MNL) { | |
79514d47 | 257 | codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl); |
7f4a9f43 WF |
258 | goto out_fail; |
259 | } else if (ELD_FIXED_BYTES + mnl > size) { | |
79514d47 | 260 | codec_info(codec, "HDMI: out of range MNL %d\n", mnl); |
7f4a9f43 WF |
261 | goto out_fail; |
262 | } else | |
75b1a8f9 | 263 | strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); |
7f4a9f43 WF |
264 | |
265 | for (i = 0; i < e->sad_count; i++) { | |
266 | if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { | |
79514d47 | 267 | codec_info(codec, "HDMI: out of range SAD %d\n", i); |
7f4a9f43 WF |
268 | goto out_fail; |
269 | } | |
79514d47 | 270 | hdmi_update_short_audio_desc(codec, e->sad + i, |
7f4a9f43 WF |
271 | buf + ELD_FIXED_BYTES + mnl + 3 * i); |
272 | } | |
273 | ||
2d1b439b WF |
274 | /* |
275 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. | |
276 | * in console or for audio devices. Assume the highest speakers | |
277 | * configuration, to _not_ prohibit multi-channel audio playback. | |
278 | */ | |
279 | if (!e->spk_alloc) | |
280 | e->spk_alloc = 0xffff; | |
281 | ||
7f4a9f43 WF |
282 | return 0; |
283 | ||
284 | out_fail: | |
7f4a9f43 WF |
285 | return -EINVAL; |
286 | } | |
287 | ||
7f4a9f43 WF |
288 | int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) |
289 | { | |
290 | return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, | |
291 | AC_DIPSIZE_ELD_BUF); | |
292 | } | |
293 | ||
1613d6b4 DH |
294 | int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, |
295 | unsigned char *buf, int *eld_size) | |
7f4a9f43 WF |
296 | { |
297 | int i; | |
2ef5692e | 298 | int ret = 0; |
7f4a9f43 | 299 | int size; |
7f4a9f43 | 300 | |
14bc52b8 PLB |
301 | /* |
302 | * ELD size is initialized to zero in caller function. If no errors and | |
1613d6b4 | 303 | * ELD is valid, actual eld_size is assigned. |
14bc52b8 PLB |
304 | */ |
305 | ||
7f4a9f43 WF |
306 | size = snd_hdmi_get_eld_size(codec, nid); |
307 | if (size == 0) { | |
308 | /* wfg: workaround for ASUS P5E-VM HDMI board */ | |
4e76a883 | 309 | codec_info(codec, "HDMI: ELD buf size is 0, force 128\n"); |
7f4a9f43 WF |
310 | size = 128; |
311 | } | |
14bc52b8 | 312 | if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { |
4e76a883 | 313 | codec_info(codec, "HDMI: invalid ELD buf size %d\n", size); |
7f4a9f43 WF |
314 | return -ERANGE; |
315 | } | |
316 | ||
14bc52b8 | 317 | /* set ELD buffer */ |
b6acf013 TI |
318 | for (i = 0; i < size; i++) { |
319 | unsigned int val = hdmi_get_eld_data(codec, nid, i); | |
a370fc62 WF |
320 | /* |
321 | * Graphics driver might be writing to ELD buffer right now. | |
322 | * Just abort. The caller will repoll after a while. | |
323 | */ | |
b6acf013 | 324 | if (!(val & AC_ELDD_ELD_VALID)) { |
4e76a883 | 325 | codec_info(codec, "HDMI: invalid ELD data byte %d\n", i); |
a370fc62 WF |
326 | ret = -EINVAL; |
327 | goto error; | |
328 | } | |
329 | val &= AC_ELDD_ELD_DATA; | |
330 | /* | |
331 | * The first byte cannot be zero. This can happen on some DVI | |
332 | * connections. Some Intel chips may also need some 250ms delay | |
333 | * to return non-zero ELD data, even when the graphics driver | |
334 | * correctly writes ELD content before setting ELD_valid bit. | |
335 | */ | |
336 | if (!val && !i) { | |
4e76a883 | 337 | codec_dbg(codec, "HDMI: 0 ELD data\n"); |
a370fc62 WF |
338 | ret = -EINVAL; |
339 | goto error; | |
340 | } | |
b6acf013 TI |
341 | buf[i] = val; |
342 | } | |
7f4a9f43 | 343 | |
1613d6b4 | 344 | *eld_size = size; |
b6acf013 | 345 | error: |
7f4a9f43 WF |
346 | return ret; |
347 | } | |
348 | ||
a11e9b16 | 349 | /* |
af65cbf2 PLB |
350 | * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with |
351 | * hdmi-specific routine. | |
352 | */ | |
353 | static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) | |
354 | { | |
bf82326f | 355 | static const unsigned int alsa_rates[] = { |
25dc16f6 AH |
356 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, |
357 | 88200, 96000, 176400, 192000, 384000 | |
af65cbf2 PLB |
358 | }; |
359 | int i, j; | |
360 | ||
361 | for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) | |
362 | if (pcm & (1 << i)) | |
44eeb081 | 363 | j += scnprintf(buf + j, buflen - j, " %d", |
af65cbf2 PLB |
364 | alsa_rates[i]); |
365 | ||
366 | buf[j] = '\0'; /* necessary when j == 0 */ | |
367 | } | |
368 | ||
f71ff0d7 TI |
369 | #define SND_PRINT_RATES_ADVISED_BUFSIZE 80 |
370 | ||
79514d47 TI |
371 | static void hdmi_show_short_audio_desc(struct hda_codec *codec, |
372 | struct cea_sad *a) | |
7f4a9f43 WF |
373 | { |
374 | char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; | |
ae8cb4ca | 375 | char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; |
7f4a9f43 | 376 | |
ae8cb4ca WF |
377 | if (!a->format) |
378 | return; | |
7f4a9f43 | 379 | |
af65cbf2 | 380 | hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); |
7f4a9f43 WF |
381 | |
382 | if (a->format == AUDIO_CODING_TYPE_LPCM) | |
d757534e | 383 | snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); |
ae8cb4ca WF |
384 | else if (a->max_bitrate) |
385 | snprintf(buf2, sizeof(buf2), | |
386 | ", max bitrate = %d", a->max_bitrate); | |
387 | else | |
388 | buf2[0] = '\0'; | |
389 | ||
79514d47 TI |
390 | codec_dbg(codec, |
391 | "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", | |
392 | cea_audio_coding_type_names[a->format], | |
393 | a->channels, buf, buf2); | |
7f4a9f43 WF |
394 | } |
395 | ||
79514d47 | 396 | void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) |
7f4a9f43 WF |
397 | { |
398 | int i; | |
ae8cb4ca | 399 | |
79514d47 | 400 | codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n", |
ae8cb4ca WF |
401 | e->monitor_name, |
402 | eld_connection_type_names[e->conn_type]); | |
403 | ||
404 | if (e->spk_alloc) { | |
405 | char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; | |
bb63f726 | 406 | snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); |
79514d47 | 407 | codec_dbg(codec, "HDMI: available speakers:%s\n", buf); |
ae8cb4ca | 408 | } |
7f4a9f43 WF |
409 | |
410 | for (i = 0; i < e->sad_count; i++) | |
79514d47 | 411 | hdmi_show_short_audio_desc(codec, e->sad + i); |
7f4a9f43 | 412 | } |
5f1e71b1 | 413 | |
cd6a6503 | 414 | #ifdef CONFIG_SND_PROC_FS |
5f1e71b1 WF |
415 | |
416 | static void hdmi_print_sad_info(int i, struct cea_sad *a, | |
417 | struct snd_info_buffer *buffer) | |
418 | { | |
d39b4352 | 419 | char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; |
5f1e71b1 WF |
420 | |
421 | snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", | |
422 | i, a->format, cea_audio_coding_type_names[a->format]); | |
423 | snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); | |
424 | ||
af65cbf2 | 425 | hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); |
06f69d17 | 426 | snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); |
5f1e71b1 | 427 | |
d39b4352 WF |
428 | if (a->format == AUDIO_CODING_TYPE_LPCM) { |
429 | snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); | |
430 | snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", | |
431 | i, a->sample_bits, buf); | |
432 | } | |
5f1e71b1 WF |
433 | |
434 | if (a->max_bitrate) | |
435 | snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", | |
436 | i, a->max_bitrate); | |
437 | ||
438 | if (a->profile) | |
439 | snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); | |
440 | } | |
441 | ||
a4e9a38b | 442 | void snd_hdmi_print_eld_info(struct hdmi_eld *eld, |
2fa22c3c JK |
443 | struct snd_info_buffer *buffer, |
444 | hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid) | |
5f1e71b1 | 445 | { |
1613d6b4 | 446 | struct parsed_hdmi_eld *e = &eld->info; |
903b21d8 | 447 | char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; |
5f1e71b1 | 448 | int i; |
d5cf00c7 | 449 | static const char * const eld_version_names[32] = { |
4805286b WF |
450 | "reserved", |
451 | "reserved", | |
452 | "CEA-861D or below", | |
453 | [3 ... 30] = "reserved", | |
454 | [31] = "partial" | |
455 | }; | |
d5cf00c7 | 456 | static const char * const cea_edid_version_names[8] = { |
4805286b WF |
457 | "no CEA EDID Timing Extension block present", |
458 | "CEA-861", | |
459 | "CEA-861-A", | |
460 | "CEA-861-B, C or D", | |
461 | [4 ... 7] = "reserved" | |
462 | }; | |
5f1e71b1 | 463 | |
1613d6b4 DH |
464 | snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present); |
465 | snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid); | |
2fa22c3c JK |
466 | snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid); |
467 | snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id); | |
468 | snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid); | |
a4e9a38b | 469 | if (!eld->eld_valid) |
5d44f927 | 470 | return; |
db742104 | 471 | snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); |
5f1e71b1 WF |
472 | snd_iprintf(buffer, "connection_type\t\t%s\n", |
473 | eld_connection_type_names[e->conn_type]); | |
474 | snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, | |
1613d6b4 | 475 | eld_version_names[e->eld_ver]); |
5f1e71b1 WF |
476 | snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, |
477 | cea_edid_version_names[e->cea_edid_ver]); | |
478 | snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); | |
479 | snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); | |
480 | snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); | |
481 | snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); | |
482 | snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); | |
483 | snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); | |
484 | ||
bb63f726 | 485 | snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); |
06f69d17 | 486 | snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); |
5f1e71b1 WF |
487 | |
488 | snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); | |
489 | ||
490 | for (i = 0; i < e->sad_count; i++) | |
491 | hdmi_print_sad_info(i, e->sad + i, buffer); | |
492 | } | |
493 | ||
a4e9a38b TI |
494 | void snd_hdmi_write_eld_info(struct hdmi_eld *eld, |
495 | struct snd_info_buffer *buffer) | |
acdda791 | 496 | { |
1613d6b4 | 497 | struct parsed_hdmi_eld *e = &eld->info; |
acdda791 WF |
498 | char line[64]; |
499 | char name[64]; | |
500 | char *sname; | |
501 | long long val; | |
78735cff | 502 | unsigned int n; |
acdda791 WF |
503 | |
504 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | |
505 | if (sscanf(line, "%s %llx", name, &val) != 2) | |
506 | continue; | |
acb05993 WF |
507 | /* |
508 | * We don't allow modification to these fields: | |
509 | * monitor_name manufacture_id product_id | |
510 | * eld_version edid_version | |
511 | */ | |
23ccc2bd | 512 | if (!strcmp(name, "monitor_present")) |
1613d6b4 | 513 | eld->monitor_present = val; |
23ccc2bd | 514 | else if (!strcmp(name, "eld_valid")) |
1613d6b4 | 515 | eld->eld_valid = val; |
23ccc2bd | 516 | else if (!strcmp(name, "connection_type")) |
acdda791 WF |
517 | e->conn_type = val; |
518 | else if (!strcmp(name, "port_id")) | |
519 | e->port_id = val; | |
520 | else if (!strcmp(name, "support_hdcp")) | |
521 | e->support_hdcp = val; | |
522 | else if (!strcmp(name, "support_ai")) | |
523 | e->support_ai = val; | |
524 | else if (!strcmp(name, "audio_sync_delay")) | |
525 | e->aud_synch_delay = val; | |
526 | else if (!strcmp(name, "speakers")) | |
527 | e->spk_alloc = val; | |
528 | else if (!strcmp(name, "sad_count")) | |
529 | e->sad_count = val; | |
530 | else if (!strncmp(name, "sad", 3)) { | |
531 | sname = name + 4; | |
532 | n = name[3] - '0'; | |
533 | if (name[4] >= '0' && name[4] <= '9') { | |
534 | sname++; | |
535 | n = 10 * n + name[4] - '0'; | |
536 | } | |
78735cff | 537 | if (n >= ELD_MAX_SAD) |
acdda791 WF |
538 | continue; |
539 | if (!strcmp(sname, "_coding_type")) | |
540 | e->sad[n].format = val; | |
541 | else if (!strcmp(sname, "_channels")) | |
542 | e->sad[n].channels = val; | |
543 | else if (!strcmp(sname, "_rates")) | |
544 | e->sad[n].rates = val; | |
545 | else if (!strcmp(sname, "_bits")) | |
546 | e->sad[n].sample_bits = val; | |
547 | else if (!strcmp(sname, "_max_bitrate")) | |
548 | e->sad[n].max_bitrate = val; | |
acb05993 WF |
549 | else if (!strcmp(sname, "_profile")) |
550 | e->sad[n].profile = val; | |
acdda791 WF |
551 | if (n >= e->sad_count) |
552 | e->sad_count = n + 1; | |
553 | } | |
554 | } | |
f208dba9 | 555 | } |
cd6a6503 | 556 | #endif /* CONFIG_SND_PROC_FS */ |
274714f5 | 557 | |
bbbe3390 | 558 | /* update PCM info based on ELD */ |
1613d6b4 | 559 | void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, |
2def8172 | 560 | struct hda_pcm_stream *hinfo) |
bbbe3390 | 561 | { |
2def8172 SW |
562 | u32 rates; |
563 | u64 formats; | |
564 | unsigned int maxbps; | |
565 | unsigned int channels_max; | |
bbbe3390 TI |
566 | int i; |
567 | ||
3dc86429 AH |
568 | /* assume basic audio support (the basic audio flag is not in ELD; |
569 | * however, all audio capable sinks are required to support basic | |
570 | * audio) */ | |
2def8172 SW |
571 | rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
572 | SNDRV_PCM_RATE_48000; | |
573 | formats = SNDRV_PCM_FMTBIT_S16_LE; | |
574 | maxbps = 16; | |
575 | channels_max = 2; | |
1613d6b4 DH |
576 | for (i = 0; i < e->sad_count; i++) { |
577 | struct cea_sad *a = &e->sad[i]; | |
2def8172 SW |
578 | rates |= a->rates; |
579 | if (a->channels > channels_max) | |
580 | channels_max = a->channels; | |
bbbe3390 | 581 | if (a->format == AUDIO_CODING_TYPE_LPCM) { |
bbbe3390 | 582 | if (a->sample_bits & AC_SUPPCM_BITS_20) { |
2def8172 SW |
583 | formats |= SNDRV_PCM_FMTBIT_S32_LE; |
584 | if (maxbps < 20) | |
585 | maxbps = 20; | |
bbbe3390 TI |
586 | } |
587 | if (a->sample_bits & AC_SUPPCM_BITS_24) { | |
2def8172 SW |
588 | formats |= SNDRV_PCM_FMTBIT_S32_LE; |
589 | if (maxbps < 24) | |
590 | maxbps = 24; | |
bbbe3390 TI |
591 | } |
592 | } | |
593 | } | |
594 | ||
bbbe3390 | 595 | /* restrict the parameters by the values the codec provides */ |
2def8172 SW |
596 | hinfo->rates &= rates; |
597 | hinfo->formats &= formats; | |
598 | hinfo->maxbps = min(hinfo->maxbps, maxbps); | |
599 | hinfo->channels_max = min(hinfo->channels_max, channels_max); | |
bbbe3390 | 600 | } |
89250f84 AH |
601 | |
602 | ||
603 | /* ATI/AMD specific stuff (ELD emulation) */ | |
604 | ||
605 | #define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776 | |
606 | #define ATI_VERB_SET_SINK_INFO_INDEX 0x780 | |
607 | #define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70 | |
608 | #define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76 | |
609 | #define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b | |
610 | #define ATI_VERB_GET_SINK_INFO_INDEX 0xf80 | |
611 | #define ATI_VERB_GET_SINK_INFO_DATA 0xf81 | |
612 | ||
613 | #define ATI_SPKALLOC_SPKALLOC 0x007f | |
614 | #define ATI_SPKALLOC_TYPE_HDMI 0x0100 | |
615 | #define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200 | |
616 | ||
617 | /* first three bytes are just standard SAD */ | |
618 | #define ATI_AUDIODESC_CHANNELS 0x00000007 | |
619 | #define ATI_AUDIODESC_RATES 0x0000ff00 | |
620 | #define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000 | |
621 | ||
622 | /* in standard HDMI VSDB format */ | |
623 | #define ATI_DELAY_VIDEO_LATENCY 0x000000ff | |
624 | #define ATI_DELAY_AUDIO_LATENCY 0x0000ff00 | |
625 | ||
626 | enum ati_sink_info_idx { | |
627 | ATI_INFO_IDX_MANUFACTURER_ID = 0, | |
628 | ATI_INFO_IDX_PRODUCT_ID = 1, | |
629 | ATI_INFO_IDX_SINK_DESC_LEN = 2, | |
630 | ATI_INFO_IDX_PORT_ID_LOW = 3, | |
631 | ATI_INFO_IDX_PORT_ID_HIGH = 4, | |
632 | ATI_INFO_IDX_SINK_DESC_FIRST = 5, | |
633 | ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */ | |
634 | }; | |
635 | ||
636 | int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, | |
637 | unsigned char *buf, int *eld_size, bool rev3_or_later) | |
638 | { | |
639 | int spkalloc, ati_sad, aud_synch; | |
640 | int sink_desc_len = 0; | |
641 | int pos, i; | |
642 | ||
643 | /* ATI/AMD does not have ELD, emulate it */ | |
644 | ||
645 | spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0); | |
646 | ||
13122e6e | 647 | if (spkalloc <= 0) { |
4e76a883 | 648 | codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n"); |
89250f84 AH |
649 | return -EINVAL; |
650 | } | |
651 | ||
652 | memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3); | |
653 | ||
654 | /* version */ | |
655 | buf[0] = ELD_VER_CEA_861D << 3; | |
656 | ||
657 | /* speaker allocation from EDID */ | |
658 | buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC; | |
659 | ||
660 | /* is DisplayPort? */ | |
661 | if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT) | |
662 | buf[5] |= 0x04; | |
663 | ||
664 | pos = ELD_FIXED_BYTES; | |
665 | ||
666 | if (rev3_or_later) { | |
667 | int sink_info; | |
668 | ||
669 | snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW); | |
670 | sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); | |
671 | put_unaligned_le32(sink_info, buf + 8); | |
672 | ||
673 | snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH); | |
674 | sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); | |
675 | put_unaligned_le32(sink_info, buf + 12); | |
676 | ||
677 | snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID); | |
678 | sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); | |
679 | put_unaligned_le16(sink_info, buf + 16); | |
680 | ||
681 | snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID); | |
682 | sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); | |
683 | put_unaligned_le16(sink_info, buf + 18); | |
684 | ||
685 | snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN); | |
686 | sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); | |
687 | ||
688 | if (sink_desc_len > ELD_MAX_MNL) { | |
4e76a883 | 689 | codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n", |
89250f84 AH |
690 | sink_desc_len); |
691 | sink_desc_len = ELD_MAX_MNL; | |
692 | } | |
693 | ||
694 | buf[4] |= sink_desc_len; | |
695 | ||
696 | for (i = 0; i < sink_desc_len; i++) { | |
697 | snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i); | |
698 | buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); | |
699 | } | |
700 | } | |
701 | ||
702 | for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) { | |
703 | if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST) | |
704 | continue; /* not handled by ATI/AMD */ | |
705 | ||
706 | snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3); | |
707 | ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0); | |
708 | ||
13122e6e AH |
709 | if (ati_sad <= 0) |
710 | continue; | |
711 | ||
89250f84 AH |
712 | if (ati_sad & ATI_AUDIODESC_RATES) { |
713 | /* format is supported, copy SAD as-is */ | |
714 | buf[pos++] = (ati_sad & 0x0000ff) >> 0; | |
715 | buf[pos++] = (ati_sad & 0x00ff00) >> 8; | |
716 | buf[pos++] = (ati_sad & 0xff0000) >> 16; | |
717 | } | |
718 | ||
719 | if (i == AUDIO_CODING_TYPE_LPCM | |
720 | && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) | |
721 | && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) { | |
722 | /* for PCM there is a separate stereo rate mask */ | |
723 | buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1; | |
724 | /* rates from the extra byte */ | |
725 | buf[pos++] = (ati_sad & 0xff000000) >> 24; | |
726 | buf[pos++] = (ati_sad & 0x00ff0000) >> 16; | |
727 | } | |
728 | } | |
729 | ||
730 | if (pos == ELD_FIXED_BYTES + sink_desc_len) { | |
4e76a883 | 731 | codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n"); |
89250f84 AH |
732 | return -EINVAL; |
733 | } | |
734 | ||
a5666824 AH |
735 | /* |
736 | * HDMI VSDB latency format: | |
737 | * separately for both audio and video: | |
738 | * 0 field not valid or unknown latency | |
739 | * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb) | |
740 | * 255 audio/video not supported | |
741 | * | |
742 | * HDA latency format: | |
743 | * single value indicating video latency relative to audio: | |
744 | * 0 unknown or 0ms | |
745 | * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa) | |
746 | * [251..255] reserved | |
747 | */ | |
89250f84 AH |
748 | aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0); |
749 | if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) { | |
a5666824 AH |
750 | int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY); |
751 | int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8; | |
89250f84 | 752 | |
a5666824 AH |
753 | if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb && |
754 | video_latency_hdmi > audio_latency_hdmi) | |
755 | buf[6] = video_latency_hdmi - audio_latency_hdmi; | |
756 | /* else unknown/invalid or 0ms or video ahead of audio, so use zero */ | |
89250f84 AH |
757 | } |
758 | ||
89250f84 AH |
759 | /* SAD count */ |
760 | buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4; | |
761 | ||
679605c7 AH |
762 | /* Baseline ELD block length is 4-byte aligned */ |
763 | pos = round_up(pos, 4); | |
764 | ||
765 | /* Baseline ELD length (4-byte header is not counted in) */ | |
766 | buf[2] = (pos - 4) / 4; | |
767 | ||
89250f84 AH |
768 | *eld_size = pos; |
769 | ||
770 | return 0; | |
771 | } |