File Index
Files and directories
Sign in
FILE

eld.c

File preview with syntax highlighting.

linux-6.19.14/sound/hda/codecs/hdmi/eld.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Generic routines and proc interface for ELD(EDID Like Data) information
  4 *
  5 * Copyright(c) 2008 Intel Corporation.
  6 * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
  7 *
  8 * Authors:
  9 * 		Wu Fengguang <wfg@linux.intel.com>
 10 */
 11
 12#include <linux/init.h>
 13#include <linux/slab.h>
 14#include <sound/core.h>
 15#include <sound/hda_chmap.h>
 16#include <sound/hda_codec.h>
 17#include "hda_local.h"
 18
 19enum cea_edid_versions {
 20	CEA_EDID_VER_NONE	= 0,
 21	CEA_EDID_VER_CEA861	= 1,
 22	CEA_EDID_VER_CEA861A	= 2,
 23	CEA_EDID_VER_CEA861BCD	= 3,
 24	CEA_EDID_VER_RESERVED	= 4,
 25};
 26
 27/*
 28 * The following two lists are shared between
 29 * 	- HDMI audio InfoFrame (source to sink)
 30 * 	- CEA E-EDID Extension (sink to source)
 31 */
 32
 33static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
 34					int byte_index)
 35{
 36	unsigned int val;
 37
 38	val = snd_hda_codec_read(codec, nid, 0,
 39					AC_VERB_GET_HDMI_ELDD, byte_index);
 40#ifdef BE_PARANOID
 41	codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
 42#endif
 43	return val;
 44}
 45
 46int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
 47{
 48	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
 49						 AC_DIPSIZE_ELD_BUF);
 50}
 51
 52int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
 53		     unsigned char *buf, int *eld_size)
 54{
 55	int i;
 56	int ret = 0;
 57	int size;
 58
 59	/*
 60	 * ELD size is initialized to zero in caller function. If no errors and
 61	 * ELD is valid, actual eld_size is assigned.
 62	 */
 63
 64	size = snd_hdmi_get_eld_size(codec, nid);
 65	if (size == 0) {
 66		/* wfg: workaround for ASUS P5E-VM HDMI board */
 67		codec_info(codec, "HDMI: ELD buf size is 0, force 128\n");
 68		size = 128;
 69	}
 70	if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
 71		codec_info(codec, "HDMI: invalid ELD buf size %d\n", size);
 72		return -ERANGE;
 73	}
 74
 75	/* set ELD buffer */
 76	for (i = 0; i < size; i++) {
 77		unsigned int val = hdmi_get_eld_data(codec, nid, i);
 78		/*
 79		 * Graphics driver might be writing to ELD buffer right now.
 80		 * Just abort. The caller will repoll after a while.
 81		 */
 82		if (!(val & AC_ELDD_ELD_VALID)) {
 83			codec_info(codec, "HDMI: invalid ELD data byte %d\n", i);
 84			ret = -EINVAL;
 85			goto error;
 86		}
 87		val &= AC_ELDD_ELD_DATA;
 88		/*
 89		 * The first byte cannot be zero. This can happen on some DVI
 90		 * connections. Some Intel chips may also need some 250ms delay
 91		 * to return non-zero ELD data, even when the graphics driver
 92		 * correctly writes ELD content before setting ELD_valid bit.
 93		 */
 94		if (!val && !i) {
 95			codec_dbg(codec, "HDMI: 0 ELD data\n");
 96			ret = -EINVAL;
 97			goto error;
 98		}
 99		buf[i] = val;
100	}
101
102	*eld_size = size;
103error:
104	return ret;
105}
106
107#ifdef CONFIG_SND_PROC_FS
108void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
109			     struct snd_info_buffer *buffer,
110			     hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
111{
112	snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
113	snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
114	snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid);
115	snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id);
116	snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid);
117
118	if (!eld->eld_valid)
119		return;
120
121	snd_print_eld_info(&eld->info, buffer);
122}
123
124void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
125			     struct snd_info_buffer *buffer)
126{
127	struct snd_parsed_hdmi_eld *e = &eld->info;
128	char line[64];
129	char name[64];
130	char *sname;
131	long long val;
132	unsigned int n;
133
134	while (!snd_info_get_line(buffer, line, sizeof(line))) {
135		if (sscanf(line, "%s %llx", name, &val) != 2)
136			continue;
137		/*
138		 * We don't allow modification to these fields:
139		 * 	monitor_name manufacture_id product_id
140		 * 	eld_version edid_version
141		 */
142		if (!strcmp(name, "monitor_present"))
143			eld->monitor_present = val;
144		else if (!strcmp(name, "eld_valid"))
145			eld->eld_valid = val;
146		else if (!strcmp(name, "connection_type"))
147			e->conn_type = val;
148		else if (!strcmp(name, "port_id"))
149			e->port_id = val;
150		else if (!strcmp(name, "support_hdcp"))
151			e->support_hdcp = val;
152		else if (!strcmp(name, "support_ai"))
153			e->support_ai = val;
154		else if (!strcmp(name, "audio_sync_delay"))
155			e->aud_synch_delay = val;
156		else if (!strcmp(name, "speakers"))
157			e->spk_alloc = val;
158		else if (!strcmp(name, "sad_count"))
159			e->sad_count = val;
160		else if (!strncmp(name, "sad", 3)) {
161			sname = name + 4;
162			n = name[3] - '0';
163			if (name[4] >= '0' && name[4] <= '9') {
164				sname++;
165				n = 10 * n + name[4] - '0';
166			}
167			if (n >= ELD_MAX_SAD)
168				continue;
169			if (!strcmp(sname, "_coding_type"))
170				e->sad[n].format = val;
171			else if (!strcmp(sname, "_channels"))
172				e->sad[n].channels = val;
173			else if (!strcmp(sname, "_rates"))
174				e->sad[n].rates = val;
175			else if (!strcmp(sname, "_bits"))
176				e->sad[n].sample_bits = val;
177			else if (!strcmp(sname, "_max_bitrate"))
178				e->sad[n].max_bitrate = val;
179			else if (!strcmp(sname, "_profile"))
180				e->sad[n].profile = val;
181			if (n >= e->sad_count)
182				e->sad_count = n + 1;
183		}
184	}
185}
186#endif /* CONFIG_SND_PROC_FS */
187
188/* update PCM info based on ELD */
189void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
190			      struct hda_pcm_stream *hinfo)
191{
192	u32 rates;
193	u64 formats;
194	unsigned int maxbps;
195	unsigned int channels_max;
196	int i;
197
198	/* assume basic audio support (the basic audio flag is not in ELD;
199	 * however, all audio capable sinks are required to support basic
200	 * audio) */
201	rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
202		SNDRV_PCM_RATE_48000;
203	formats = SNDRV_PCM_FMTBIT_S16_LE;
204	maxbps = 16;
205	channels_max = 2;
206	for (i = 0; i < e->sad_count; i++) {
207		struct snd_cea_sad *a = &e->sad[i];
208		rates |= a->rates;
209		if (a->channels > channels_max)
210			channels_max = a->channels;
211		if (a->format == AUDIO_CODING_TYPE_LPCM) {
212			if (a->sample_bits & ELD_PCM_BITS_20) {
213				formats |= SNDRV_PCM_FMTBIT_S32_LE;
214				if (maxbps < 20)
215					maxbps = 20;
216			}
217			if (a->sample_bits & ELD_PCM_BITS_24) {
218				formats |= SNDRV_PCM_FMTBIT_S32_LE;
219				if (maxbps < 24)
220					maxbps = 24;
221			}
222		}
223	}
224
225	/* restrict the parameters by the values the codec provides */
226	hinfo->rates &= rates;
227	hinfo->formats &= formats;
228	hinfo->maxbps = min(hinfo->maxbps, maxbps);
229	hinfo->channels_max = min(hinfo->channels_max, channels_max);
230}
~/ Read-only file preview.