xref: /linux/sound/hda/codecs/hdmi/nvhdmi-mcp.c (revision 177bf8620cf4ed290ee170a6c5966adc0924b336)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Legacy Nvidia HDMI codec support
4  */
5 
6 #include <linux/init.h>
7 #include <linux/slab.h>
8 #include <linux/module.h>
9 #include <sound/core.h>
10 #include <sound/hdaudio.h>
11 #include <sound/hda_codec.h>
12 #include "hda_local.h"
13 #include "hdmi_local.h"
14 
15 enum { MODEL_2CH, MODEL_8CH };
16 
17 #define Nv_VERB_SET_Channel_Allocation          0xF79
18 #define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
19 #define Nv_VERB_SET_Audio_Protection_On         0xF98
20 #define Nv_VERB_SET_Audio_Protection_Off        0xF99
21 
22 #define nvhdmi_master_con_nid_7x	0x04
23 #define nvhdmi_master_pin_nid_7x	0x05
24 
25 static const hda_nid_t nvhdmi_con_nids_7x[4] = {
26 	/*front, rear, clfe, rear_surr */
27 	0x6, 0x8, 0xa, 0xc,
28 };
29 
30 static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
31 	/* set audio protect on */
32 	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
33 	/* enable digital output on pin widget */
34 	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
35 	{} /* terminator */
36 };
37 
38 static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
39 	/* set audio protect on */
40 	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
41 	/* enable digital output on pin widget */
42 	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
43 	{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
44 	{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
45 	{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
46 	{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
47 	{} /* terminator */
48 };
49 
nvhdmi_mcp_init(struct hda_codec * codec)50 static int nvhdmi_mcp_init(struct hda_codec *codec)
51 {
52 	struct hdmi_spec *spec = codec->spec;
53 
54 	if (spec->multiout.max_channels == 2)
55 		snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
56 	else
57 		snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
58 	return 0;
59 }
60 
nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec * codec,int channels)61 static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
62 						    int channels)
63 {
64 	unsigned int chanmask;
65 	int chan = channels ? (channels - 1) : 1;
66 
67 	switch (channels) {
68 	default:
69 	case 0:
70 	case 2:
71 		chanmask = 0x00;
72 		break;
73 	case 4:
74 		chanmask = 0x08;
75 		break;
76 	case 6:
77 		chanmask = 0x0b;
78 		break;
79 	case 8:
80 		chanmask = 0x13;
81 		break;
82 	}
83 
84 	/* Set the audio infoframe channel allocation and checksum fields.  The
85 	 * channel count is computed implicitly by the hardware.
86 	 */
87 	snd_hda_codec_write(codec, 0x1, 0,
88 			Nv_VERB_SET_Channel_Allocation, chanmask);
89 
90 	snd_hda_codec_write(codec, 0x1, 0,
91 			Nv_VERB_SET_Info_Frame_Checksum,
92 			(0x71 - chan - chanmask));
93 }
94 
nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream * hinfo,struct hda_codec * codec,struct snd_pcm_substream * substream)95 static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
96 				   struct hda_codec *codec,
97 				   struct snd_pcm_substream *substream)
98 {
99 	struct hdmi_spec *spec = codec->spec;
100 	int i;
101 
102 	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
103 			0, AC_VERB_SET_CHANNEL_STREAMID, 0);
104 	for (i = 0; i < 4; i++) {
105 		/* set the stream id */
106 		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
107 				AC_VERB_SET_CHANNEL_STREAMID, 0);
108 		/* set the stream format */
109 		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
110 				AC_VERB_SET_STREAM_FORMAT, 0);
111 	}
112 
113 	/* The audio hardware sends a channel count of 0x7 (8ch) when all the
114 	 * streams are disabled.
115 	 */
116 	nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
117 
118 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
119 }
120 
nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream * hinfo,struct hda_codec * codec,unsigned int stream_tag,unsigned int format,struct snd_pcm_substream * substream)121 static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
122 				     struct hda_codec *codec,
123 				     unsigned int stream_tag,
124 				     unsigned int format,
125 				     struct snd_pcm_substream *substream)
126 {
127 	int chs;
128 	unsigned int dataDCC2, channel_id;
129 	int i;
130 	struct hdmi_spec *spec = codec->spec;
131 	struct hda_spdif_out *spdif;
132 	struct hdmi_spec_per_cvt *per_cvt;
133 
134 	mutex_lock(&codec->spdif_mutex);
135 	per_cvt = get_cvt(spec, 0);
136 	spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
137 
138 	chs = substream->runtime->channels;
139 
140 	dataDCC2 = 0x2;
141 
142 	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
143 	if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
144 		snd_hda_codec_write(codec,
145 				nvhdmi_master_con_nid_7x,
146 				0,
147 				AC_VERB_SET_DIGI_CONVERT_1,
148 				spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
149 
150 	/* set the stream id */
151 	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
152 			AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
153 
154 	/* set the stream format */
155 	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
156 			AC_VERB_SET_STREAM_FORMAT, format);
157 
158 	/* turn on again (if needed) */
159 	/* enable and set the channel status audio/data flag */
160 	if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
161 		snd_hda_codec_write(codec,
162 				nvhdmi_master_con_nid_7x,
163 				0,
164 				AC_VERB_SET_DIGI_CONVERT_1,
165 				spdif->ctls & 0xff);
166 		snd_hda_codec_write(codec,
167 				nvhdmi_master_con_nid_7x,
168 				0,
169 				AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
170 	}
171 
172 	for (i = 0; i < 4; i++) {
173 		if (chs == 2)
174 			channel_id = 0;
175 		else
176 			channel_id = i * 2;
177 
178 		/* turn off SPDIF once;
179 		 *otherwise the IEC958 bits won't be updated
180 		 */
181 		if (codec->spdif_status_reset &&
182 		(spdif->ctls & AC_DIG1_ENABLE))
183 			snd_hda_codec_write(codec,
184 				nvhdmi_con_nids_7x[i],
185 				0,
186 				AC_VERB_SET_DIGI_CONVERT_1,
187 				spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
188 		/* set the stream id */
189 		snd_hda_codec_write(codec,
190 				nvhdmi_con_nids_7x[i],
191 				0,
192 				AC_VERB_SET_CHANNEL_STREAMID,
193 				(stream_tag << 4) | channel_id);
194 		/* set the stream format */
195 		snd_hda_codec_write(codec,
196 				nvhdmi_con_nids_7x[i],
197 				0,
198 				AC_VERB_SET_STREAM_FORMAT,
199 				format);
200 		/* turn on again (if needed) */
201 		/* enable and set the channel status audio/data flag */
202 		if (codec->spdif_status_reset &&
203 		(spdif->ctls & AC_DIG1_ENABLE)) {
204 			snd_hda_codec_write(codec,
205 					nvhdmi_con_nids_7x[i],
206 					0,
207 					AC_VERB_SET_DIGI_CONVERT_1,
208 					spdif->ctls & 0xff);
209 			snd_hda_codec_write(codec,
210 					nvhdmi_con_nids_7x[i],
211 					0,
212 					AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
213 		}
214 	}
215 
216 	nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
217 
218 	mutex_unlock(&codec->spdif_mutex);
219 	return 0;
220 }
221 
222 static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
223 	.substreams = 1,
224 	.channels_min = 2,
225 	.channels_max = 8,
226 	.nid = nvhdmi_master_con_nid_7x,
227 	.rates = SUPPORTED_RATES,
228 	.maxbps = SUPPORTED_MAXBPS,
229 	.formats = SUPPORTED_FORMATS,
230 	.ops = {
231 		.open = snd_hda_hdmi_simple_pcm_open,
232 		.close = nvhdmi_8ch_7x_pcm_close,
233 		.prepare = nvhdmi_8ch_7x_pcm_prepare
234 	},
235 };
236 
nvhdmi_mcp_build_pcms(struct hda_codec * codec)237 static int nvhdmi_mcp_build_pcms(struct hda_codec *codec)
238 {
239 	struct hdmi_spec *spec = codec->spec;
240 	int err;
241 
242 	err = snd_hda_hdmi_simple_build_pcms(codec);
243 	if (!err && spec->multiout.max_channels == 8) {
244 		struct hda_pcm *info = get_pcm_rec(spec, 0);
245 
246 		info->own_chmap = true;
247 	}
248 	return err;
249 }
250 
nvhdmi_mcp_build_controls(struct hda_codec * codec)251 static int nvhdmi_mcp_build_controls(struct hda_codec *codec)
252 {
253 	struct hdmi_spec *spec = codec->spec;
254 	struct hda_pcm *info;
255 	struct snd_pcm_chmap *chmap;
256 	int err;
257 
258 	err = snd_hda_hdmi_simple_build_controls(codec);
259 	if (err < 0)
260 		return err;
261 
262 	if (spec->multiout.max_channels != 8)
263 		return 0;
264 
265 	/* add channel maps */
266 	info = get_pcm_rec(spec, 0);
267 	err = snd_pcm_add_chmap_ctls(info->pcm,
268 				     SNDRV_PCM_STREAM_PLAYBACK,
269 				     snd_pcm_alt_chmaps, 8, 0, &chmap);
270 	if (err < 0)
271 		return err;
272 	switch (codec->preset->vendor_id) {
273 	case 0x10de0002:
274 	case 0x10de0003:
275 	case 0x10de0005:
276 	case 0x10de0006:
277 		chmap->channel_mask = (1U << 2) | (1U << 8);
278 		break;
279 	case 0x10de0007:
280 		chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
281 	}
282 	return 0;
283 }
284 
285 static const unsigned int channels_2_6_8[] = {
286 	2, 6, 8
287 };
288 
289 static const unsigned int channels_2_8[] = {
290 	2, 8
291 };
292 
293 static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
294 	.count = ARRAY_SIZE(channels_2_6_8),
295 	.list = channels_2_6_8,
296 	.mask = 0,
297 };
298 
299 static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
300 	.count = ARRAY_SIZE(channels_2_8),
301 	.list = channels_2_8,
302 	.mask = 0,
303 };
304 
nvhdmi_mcp_probe(struct hda_codec * codec,const struct hda_device_id * id)305 static int nvhdmi_mcp_probe(struct hda_codec *codec,
306 			    const struct hda_device_id *id)
307 {
308 	struct hdmi_spec *spec;
309 	int err;
310 
311 	err = snd_hda_hdmi_simple_probe(codec, nvhdmi_master_con_nid_7x,
312 					nvhdmi_master_pin_nid_7x);
313 	if (err < 0)
314 		return err;
315 
316 	/* override the PCM rates, etc, as the codec doesn't give full list */
317 	spec = codec->spec;
318 	spec->pcm_playback.rates = SUPPORTED_RATES;
319 	spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
320 	spec->pcm_playback.formats = SUPPORTED_FORMATS;
321 	spec->nv_dp_workaround = true;
322 
323 	if (id->driver_data == MODEL_2CH)
324 		return 0;
325 
326 	spec->multiout.max_channels = 8;
327 	spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
328 
329 	switch (codec->preset->vendor_id) {
330 	case 0x10de0002:
331 	case 0x10de0003:
332 	case 0x10de0005:
333 	case 0x10de0006:
334 		spec->hw_constraints_channels = &hw_constraints_2_8_channels;
335 		break;
336 	case 0x10de0007:
337 		spec->hw_constraints_channels = &hw_constraints_2_6_8_channels;
338 		break;
339 	default:
340 		break;
341 	}
342 
343 	/* Initialize the audio infoframe channel mask and checksum to something
344 	 * valid
345 	 */
346 	nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
347 
348 	return 0;
349 }
350 
351 static const struct hda_codec_ops nvhdmi_mcp_codec_ops = {
352 	.probe = nvhdmi_mcp_probe,
353 	.remove = snd_hda_hdmi_simple_remove,
354 	.build_controls = nvhdmi_mcp_build_pcms,
355 	.build_pcms = nvhdmi_mcp_build_controls,
356 	.init = nvhdmi_mcp_init,
357 	.unsol_event = snd_hda_hdmi_simple_unsol_event,
358 };
359 
360 static const struct hda_device_id snd_hda_id_nvhdmi_mcp[] = {
361 	HDA_CODEC_ID_MODEL(0x10de0001, "MCP73 HDMI",	MODEL_2CH),
362 	HDA_CODEC_ID_MODEL(0x10de0002, "MCP77/78 HDMI",	MODEL_8CH),
363 	HDA_CODEC_ID_MODEL(0x10de0003, "MCP77/78 HDMI",	MODEL_8CH),
364 	HDA_CODEC_ID_MODEL(0x10de0004, "GPU 04 HDMI",	MODEL_8CH),
365 	HDA_CODEC_ID_MODEL(0x10de0005, "MCP77/78 HDMI",	MODEL_8CH),
366 	HDA_CODEC_ID_MODEL(0x10de0006, "MCP77/78 HDMI",	MODEL_8CH),
367 	HDA_CODEC_ID_MODEL(0x10de0007, "MCP79/7A HDMI",	MODEL_8CH),
368 	HDA_CODEC_ID_MODEL(0x10de0067, "MCP67 HDMI",	MODEL_2CH),
369 	HDA_CODEC_ID_MODEL(0x10de8001, "MCP73 HDMI",	MODEL_2CH),
370 	HDA_CODEC_ID_MODEL(0x10de8067, "MCP67/68 HDMI",	MODEL_2CH),
371 	{} /* terminator */
372 };
373 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi_mcp);
374 
375 MODULE_LICENSE("GPL");
376 MODULE_DESCRIPTION("Legacy Nvidia HDMI HD-audio codec");
377 MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
378 
379 static struct hda_codec_driver nvhdmi_mcp_driver = {
380 	.id = snd_hda_id_nvhdmi_mcp,
381 	.ops = &nvhdmi_mcp_codec_ops,
382 };
383 
384 module_hda_codec_driver(nvhdmi_mcp_driver);
385