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 guard(mutex)(&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 return 0;
219 }
220
221 static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
222 .substreams = 1,
223 .channels_min = 2,
224 .channels_max = 8,
225 .nid = nvhdmi_master_con_nid_7x,
226 .rates = SUPPORTED_RATES,
227 .maxbps = SUPPORTED_MAXBPS,
228 .formats = SUPPORTED_FORMATS,
229 .ops = {
230 .open = snd_hda_hdmi_simple_pcm_open,
231 .close = nvhdmi_8ch_7x_pcm_close,
232 .prepare = nvhdmi_8ch_7x_pcm_prepare
233 },
234 };
235
nvhdmi_mcp_build_pcms(struct hda_codec * codec)236 static int nvhdmi_mcp_build_pcms(struct hda_codec *codec)
237 {
238 struct hdmi_spec *spec = codec->spec;
239 int err;
240
241 err = snd_hda_hdmi_simple_build_pcms(codec);
242 if (!err && spec->multiout.max_channels == 8) {
243 struct hda_pcm *info = get_pcm_rec(spec, 0);
244
245 info->own_chmap = true;
246 }
247 return err;
248 }
249
nvhdmi_mcp_build_controls(struct hda_codec * codec)250 static int nvhdmi_mcp_build_controls(struct hda_codec *codec)
251 {
252 struct hdmi_spec *spec = codec->spec;
253 struct hda_pcm *info;
254 struct snd_pcm_chmap *chmap;
255 int err;
256
257 err = snd_hda_hdmi_simple_build_controls(codec);
258 if (err < 0)
259 return err;
260
261 if (spec->multiout.max_channels != 8)
262 return 0;
263
264 /* add channel maps */
265 info = get_pcm_rec(spec, 0);
266 err = snd_pcm_add_chmap_ctls(info->pcm,
267 SNDRV_PCM_STREAM_PLAYBACK,
268 snd_pcm_alt_chmaps, 8, 0, &chmap);
269 if (err < 0)
270 return err;
271 switch (codec->preset->vendor_id) {
272 case 0x10de0002:
273 case 0x10de0003:
274 case 0x10de0005:
275 case 0x10de0006:
276 chmap->channel_mask = (1U << 2) | (1U << 8);
277 break;
278 case 0x10de0007:
279 chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
280 }
281 return 0;
282 }
283
284 static const unsigned int channels_2_6_8[] = {
285 2, 6, 8
286 };
287
288 static const unsigned int channels_2_8[] = {
289 2, 8
290 };
291
292 static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
293 .count = ARRAY_SIZE(channels_2_6_8),
294 .list = channels_2_6_8,
295 .mask = 0,
296 };
297
298 static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
299 .count = ARRAY_SIZE(channels_2_8),
300 .list = channels_2_8,
301 .mask = 0,
302 };
303
nvhdmi_mcp_probe(struct hda_codec * codec,const struct hda_device_id * id)304 static int nvhdmi_mcp_probe(struct hda_codec *codec,
305 const struct hda_device_id *id)
306 {
307 struct hdmi_spec *spec;
308 int err;
309
310 err = snd_hda_hdmi_simple_probe(codec, nvhdmi_master_con_nid_7x,
311 nvhdmi_master_pin_nid_7x);
312 if (err < 0)
313 return err;
314
315 /* override the PCM rates, etc, as the codec doesn't give full list */
316 spec = codec->spec;
317 spec->pcm_playback.rates = SUPPORTED_RATES;
318 spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
319 spec->pcm_playback.formats = SUPPORTED_FORMATS;
320 spec->nv_dp_workaround = true;
321
322 if (id->driver_data == MODEL_2CH)
323 return 0;
324
325 spec->multiout.max_channels = 8;
326 spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
327
328 switch (codec->preset->vendor_id) {
329 case 0x10de0002:
330 case 0x10de0003:
331 case 0x10de0005:
332 case 0x10de0006:
333 spec->hw_constraints_channels = &hw_constraints_2_8_channels;
334 break;
335 case 0x10de0007:
336 spec->hw_constraints_channels = &hw_constraints_2_6_8_channels;
337 break;
338 default:
339 break;
340 }
341
342 /* Initialize the audio infoframe channel mask and checksum to something
343 * valid
344 */
345 nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
346
347 return 0;
348 }
349
350 static const struct hda_codec_ops nvhdmi_mcp_codec_ops = {
351 .probe = nvhdmi_mcp_probe,
352 .remove = snd_hda_hdmi_simple_remove,
353 .build_pcms = nvhdmi_mcp_build_pcms,
354 .build_controls = nvhdmi_mcp_build_controls,
355 .init = nvhdmi_mcp_init,
356 .unsol_event = snd_hda_hdmi_simple_unsol_event,
357 };
358
359 static const struct hda_device_id snd_hda_id_nvhdmi_mcp[] = {
360 HDA_CODEC_ID_MODEL(0x10de0001, "MCP73 HDMI", MODEL_2CH),
361 HDA_CODEC_ID_MODEL(0x10de0002, "MCP77/78 HDMI", MODEL_8CH),
362 HDA_CODEC_ID_MODEL(0x10de0003, "MCP77/78 HDMI", MODEL_8CH),
363 HDA_CODEC_ID_MODEL(0x10de0004, "GPU 04 HDMI", MODEL_8CH),
364 HDA_CODEC_ID_MODEL(0x10de0005, "MCP77/78 HDMI", MODEL_8CH),
365 HDA_CODEC_ID_MODEL(0x10de0006, "MCP77/78 HDMI", MODEL_8CH),
366 HDA_CODEC_ID_MODEL(0x10de0007, "MCP79/7A HDMI", MODEL_8CH),
367 HDA_CODEC_ID_MODEL(0x10de0067, "MCP67 HDMI", MODEL_2CH),
368 HDA_CODEC_ID_MODEL(0x10de8001, "MCP73 HDMI", MODEL_2CH),
369 HDA_CODEC_ID_MODEL(0x10de8067, "MCP67/68 HDMI", MODEL_2CH),
370 {} /* terminator */
371 };
372 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi_mcp);
373
374 MODULE_LICENSE("GPL");
375 MODULE_DESCRIPTION("Legacy Nvidia HDMI HD-audio codec");
376 MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
377
378 static struct hda_codec_driver nvhdmi_mcp_driver = {
379 .id = snd_hda_id_nvhdmi_mcp,
380 .ops = &nvhdmi_mcp_codec_ops,
381 };
382
383 module_hda_codec_driver(nvhdmi_mcp_driver);
384