PageRenderTime 37ms CodeModel.GetById 11ms app.highlight 21ms RepoModel.GetById 0ms app.codeStats 0ms

/sound/pci/hda/patch_nvhdmi.c

https://bitbucket.org/abioy/linux
C | 595 lines | 452 code | 88 blank | 55 comment | 39 complexity | dea66c672b36d92ae4b6a0a82cf86ae6 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 * Universal Interface for Intel High Definition Audio Codec
  3 *
  4 * HD audio interface patch for NVIDIA HDMI codecs
  5 *
  6 * Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
  7 * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
  8 *
  9 *
 10 *  This driver is free software; you can redistribute it and/or modify
 11 *  it under the terms of the GNU General Public License as published by
 12 *  the Free Software Foundation; either version 2 of the License, or
 13 *  (at your option) any later version.
 14 *
 15 *  This driver is distributed in the hope that it will be useful,
 16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 *  GNU General Public License for more details.
 19 *
 20 *  You should have received a copy of the GNU General Public License
 21 *  along with this program; if not, write to the Free Software
 22 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 23 */
 24
 25#include <linux/init.h>
 26#include <linux/delay.h>
 27#include <linux/slab.h>
 28#include <sound/core.h>
 29#include "hda_codec.h"
 30#include "hda_local.h"
 31
 32#define MAX_HDMI_CVTS	1
 33#define MAX_HDMI_PINS	1
 34
 35#include "patch_hdmi.c"
 36
 37static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = {
 38	"NVIDIA HDMI",
 39};
 40
 41/* define below to restrict the supported rates and formats */
 42/* #define LIMITED_RATE_FMT_SUPPORT */
 43
 44enum HDACodec {
 45	HDA_CODEC_NVIDIA_MCP7X,
 46	HDA_CODEC_NVIDIA_MCP89,
 47	HDA_CODEC_NVIDIA_GT21X,
 48	HDA_CODEC_INVALID
 49};
 50
 51#define Nv_VERB_SET_Channel_Allocation          0xF79
 52#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
 53#define Nv_VERB_SET_Audio_Protection_On         0xF98
 54#define Nv_VERB_SET_Audio_Protection_Off        0xF99
 55
 56#define nvhdmi_master_con_nid_7x	0x04
 57#define nvhdmi_master_pin_nid_7x	0x05
 58
 59#define nvhdmi_master_con_nid_89	0x04
 60#define nvhdmi_master_pin_nid_89	0x05
 61
 62static hda_nid_t nvhdmi_con_nids_7x[4] = {
 63	/*front, rear, clfe, rear_surr */
 64	0x6, 0x8, 0xa, 0xc,
 65};
 66
 67static struct hda_verb nvhdmi_basic_init_7x[] = {
 68	/* set audio protect on */
 69	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
 70	/* enable digital output on pin widget */
 71	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
 72	{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
 73	{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
 74	{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
 75	{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
 76	{} /* terminator */
 77};
 78
 79#ifdef LIMITED_RATE_FMT_SUPPORT
 80/* support only the safe format and rate */
 81#define SUPPORTED_RATES		SNDRV_PCM_RATE_48000
 82#define SUPPORTED_MAXBPS	16
 83#define SUPPORTED_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
 84#else
 85/* support all rates and formats */
 86#define SUPPORTED_RATES \
 87	(SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
 88	SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
 89	 SNDRV_PCM_RATE_192000)
 90#define SUPPORTED_MAXBPS	24
 91#define SUPPORTED_FORMATS \
 92	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 93#endif
 94
 95/*
 96 * Controls
 97 */
 98static int nvhdmi_build_controls(struct hda_codec *codec)
 99{
100	struct hdmi_spec *spec = codec->spec;
101	int err;
102	int i;
103
104	if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
105	|| (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
106		for (i = 0; i < codec->num_pcms; i++) {
107			err = snd_hda_create_spdif_out_ctls(codec,
108							    spec->cvt[i]);
109			if (err < 0)
110				return err;
111		}
112	} else {
113		err = snd_hda_create_spdif_out_ctls(codec,
114						    spec->multiout.dig_out_nid);
115		if (err < 0)
116			return err;
117	}
118
119	return 0;
120}
121
122static int nvhdmi_init(struct hda_codec *codec)
123{
124	struct hdmi_spec *spec = codec->spec;
125	int i;
126	if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
127	|| (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
128		for (i = 0; spec->pin[i]; i++) {
129			hdmi_enable_output(codec, spec->pin[i]);
130			snd_hda_codec_write(codec, spec->pin[i], 0,
131					    AC_VERB_SET_UNSOLICITED_ENABLE,
132					    AC_USRSP_EN | spec->pin[i]);
133		}
134	} else {
135		snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
136	}
137	return 0;
138}
139
140static void nvhdmi_free(struct hda_codec *codec)
141{
142	struct hdmi_spec *spec = codec->spec;
143	int i;
144
145	if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
146	|| (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
147		for (i = 0; i < spec->num_pins; i++)
148			snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
149	}
150
151	kfree(spec);
152}
153
154/*
155 * Digital out
156 */
157static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
158					struct hda_codec *codec,
159					struct snd_pcm_substream *substream)
160{
161	struct hdmi_spec *spec = codec->spec;
162	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
163}
164
165static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo,
166					struct hda_codec *codec,
167					struct snd_pcm_substream *substream)
168{
169	struct hdmi_spec *spec = codec->spec;
170	int i;
171
172	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
173			0, AC_VERB_SET_CHANNEL_STREAMID, 0);
174	for (i = 0; i < 4; i++) {
175		/* set the stream id */
176		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
177				AC_VERB_SET_CHANNEL_STREAMID, 0);
178		/* set the stream format */
179		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
180				AC_VERB_SET_STREAM_FORMAT, 0);
181	}
182
183	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
184}
185
186static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
187					struct hda_codec *codec,
188					struct snd_pcm_substream *substream)
189{
190	struct hdmi_spec *spec = codec->spec;
191	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
192}
193
194static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
195					struct hda_codec *codec,
196					unsigned int stream_tag,
197					unsigned int format,
198					struct snd_pcm_substream *substream)
199{
200	hdmi_set_channel_count(codec, hinfo->nid,
201			       substream->runtime->channels);
202
203	hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
204
205	hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
206	return 0;
207}
208
209static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
210					struct hda_codec *codec,
211					unsigned int stream_tag,
212					unsigned int format,
213					struct snd_pcm_substream *substream)
214{
215	int chs;
216	unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
217	int i;
218
219	mutex_lock(&codec->spdif_mutex);
220
221	chs = substream->runtime->channels;
222	chan = chs ? (chs - 1) : 1;
223
224	switch (chs) {
225	default:
226	case 0:
227	case 2:
228		chanmask = 0x00;
229		break;
230	case 4:
231		chanmask = 0x08;
232		break;
233	case 6:
234		chanmask = 0x0b;
235		break;
236	case 8:
237		chanmask = 0x13;
238		break;
239	}
240	dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
241	dataDCC2 = 0x2;
242
243	/* set the Audio InforFrame Channel Allocation */
244	snd_hda_codec_write(codec, 0x1, 0,
245			Nv_VERB_SET_Channel_Allocation, chanmask);
246
247	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
248	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
249		snd_hda_codec_write(codec,
250				nvhdmi_master_con_nid_7x,
251				0,
252				AC_VERB_SET_DIGI_CONVERT_1,
253				codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
254
255	/* set the stream id */
256	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
257			AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
258
259	/* set the stream format */
260	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
261			AC_VERB_SET_STREAM_FORMAT, format);
262
263	/* turn on again (if needed) */
264	/* enable and set the channel status audio/data flag */
265	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
266		snd_hda_codec_write(codec,
267				nvhdmi_master_con_nid_7x,
268				0,
269				AC_VERB_SET_DIGI_CONVERT_1,
270				codec->spdif_ctls & 0xff);
271		snd_hda_codec_write(codec,
272				nvhdmi_master_con_nid_7x,
273				0,
274				AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
275	}
276
277	for (i = 0; i < 4; i++) {
278		if (chs == 2)
279			channel_id = 0;
280		else
281			channel_id = i * 2;
282
283		/* turn off SPDIF once;
284		 *otherwise the IEC958 bits won't be updated
285		 */
286		if (codec->spdif_status_reset &&
287		(codec->spdif_ctls & AC_DIG1_ENABLE))
288			snd_hda_codec_write(codec,
289				nvhdmi_con_nids_7x[i],
290				0,
291				AC_VERB_SET_DIGI_CONVERT_1,
292				codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
293		/* set the stream id */
294		snd_hda_codec_write(codec,
295				nvhdmi_con_nids_7x[i],
296				0,
297				AC_VERB_SET_CHANNEL_STREAMID,
298				(stream_tag << 4) | channel_id);
299		/* set the stream format */
300		snd_hda_codec_write(codec,
301				nvhdmi_con_nids_7x[i],
302				0,
303				AC_VERB_SET_STREAM_FORMAT,
304				format);
305		/* turn on again (if needed) */
306		/* enable and set the channel status audio/data flag */
307		if (codec->spdif_status_reset &&
308		(codec->spdif_ctls & AC_DIG1_ENABLE)) {
309			snd_hda_codec_write(codec,
310					nvhdmi_con_nids_7x[i],
311					0,
312					AC_VERB_SET_DIGI_CONVERT_1,
313					codec->spdif_ctls & 0xff);
314			snd_hda_codec_write(codec,
315					nvhdmi_con_nids_7x[i],
316					0,
317					AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
318		}
319	}
320
321	/* set the Audio Info Frame Checksum */
322	snd_hda_codec_write(codec, 0x1, 0,
323			Nv_VERB_SET_Info_Frame_Checksum,
324			(0x71 - chan - chanmask));
325
326	mutex_unlock(&codec->spdif_mutex);
327	return 0;
328}
329
330static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
331					   struct hda_codec *codec,
332					   struct snd_pcm_substream *substream)
333{
334	return 0;
335}
336
337static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
338					struct hda_codec *codec,
339					unsigned int stream_tag,
340					unsigned int format,
341					struct snd_pcm_substream *substream)
342{
343	struct hdmi_spec *spec = codec->spec;
344	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
345					format, substream);
346}
347
348static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = {
349	.substreams = 1,
350	.channels_min = 2,
351	.rates = SUPPORTED_RATES,
352	.maxbps = SUPPORTED_MAXBPS,
353	.formats = SUPPORTED_FORMATS,
354	.ops = {
355		.prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89,
356		.cleanup = nvhdmi_playback_pcm_cleanup,
357	},
358};
359
360static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = {
361	.substreams = 1,
362	.channels_min = 2,
363	.channels_max = 8,
364	.nid = nvhdmi_master_con_nid_7x,
365	.rates = SUPPORTED_RATES,
366	.maxbps = SUPPORTED_MAXBPS,
367	.formats = SUPPORTED_FORMATS,
368	.ops = {
369		.open = nvhdmi_dig_playback_pcm_open,
370		.close = nvhdmi_dig_playback_pcm_close_8ch_7x,
371		.prepare = nvhdmi_dig_playback_pcm_prepare_8ch
372	},
373};
374
375static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
376	.substreams = 1,
377	.channels_min = 2,
378	.channels_max = 2,
379	.nid = nvhdmi_master_con_nid_7x,
380	.rates = SUPPORTED_RATES,
381	.maxbps = SUPPORTED_MAXBPS,
382	.formats = SUPPORTED_FORMATS,
383	.ops = {
384		.open = nvhdmi_dig_playback_pcm_open,
385		.close = nvhdmi_dig_playback_pcm_close_2ch,
386		.prepare = nvhdmi_dig_playback_pcm_prepare_2ch
387	},
388};
389
390static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec)
391{
392	struct hdmi_spec *spec = codec->spec;
393	struct hda_pcm *info = spec->pcm_rec;
394	int i;
395
396	codec->num_pcms = spec->num_cvts;
397	codec->pcm_info = info;
398
399	for (i = 0; i < codec->num_pcms; i++, info++) {
400		unsigned int chans;
401
402		chans = get_wcaps(codec, spec->cvt[i]);
403		chans = get_wcaps_channels(chans);
404
405		info->name = nvhdmi_pcm_names[i];
406		info->pcm_type = HDA_PCM_TYPE_HDMI;
407		info->stream[SNDRV_PCM_STREAM_PLAYBACK]
408					= nvhdmi_pcm_digital_playback_8ch_89;
409		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
410		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
411	}
412
413	return 0;
414}
415
416static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec)
417{
418	struct hdmi_spec *spec = codec->spec;
419	struct hda_pcm *info = spec->pcm_rec;
420
421	codec->num_pcms = 1;
422	codec->pcm_info = info;
423
424	info->name = "NVIDIA HDMI";
425	info->pcm_type = HDA_PCM_TYPE_HDMI;
426	info->stream[SNDRV_PCM_STREAM_PLAYBACK]
427					= nvhdmi_pcm_digital_playback_8ch_7x;
428
429	return 0;
430}
431
432static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
433{
434	struct hdmi_spec *spec = codec->spec;
435	struct hda_pcm *info = spec->pcm_rec;
436
437	codec->num_pcms = 1;
438	codec->pcm_info = info;
439
440	info->name = "NVIDIA HDMI";
441	info->pcm_type = HDA_PCM_TYPE_HDMI;
442	info->stream[SNDRV_PCM_STREAM_PLAYBACK]
443					= nvhdmi_pcm_digital_playback_2ch;
444
445	return 0;
446}
447
448static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = {
449	.build_controls = nvhdmi_build_controls,
450	.build_pcms = nvhdmi_build_pcms_8ch_89,
451	.init = nvhdmi_init,
452	.free = nvhdmi_free,
453	.unsol_event = hdmi_unsol_event,
454};
455
456static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
457	.build_controls = nvhdmi_build_controls,
458	.build_pcms = nvhdmi_build_pcms_8ch_7x,
459	.init = nvhdmi_init,
460	.free = nvhdmi_free,
461};
462
463static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
464	.build_controls = nvhdmi_build_controls,
465	.build_pcms = nvhdmi_build_pcms_2ch,
466	.init = nvhdmi_init,
467	.free = nvhdmi_free,
468};
469
470static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
471{
472	struct hdmi_spec *spec;
473	int i;
474
475	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
476	if (spec == NULL)
477		return -ENOMEM;
478
479	codec->spec = spec;
480	spec->codec_type = HDA_CODEC_NVIDIA_MCP89;
481
482	if (hdmi_parse_codec(codec) < 0) {
483		codec->spec = NULL;
484		kfree(spec);
485		return -EINVAL;
486	}
487	codec->patch_ops = nvhdmi_patch_ops_8ch_89;
488
489	for (i = 0; i < spec->num_pins; i++)
490		snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
491
492	init_channel_allocations();
493
494	return 0;
495}
496
497static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
498{
499	struct hdmi_spec *spec;
500
501	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
502	if (spec == NULL)
503		return -ENOMEM;
504
505	codec->spec = spec;
506
507	spec->multiout.num_dacs = 0;  /* no analog */
508	spec->multiout.max_channels = 8;
509	spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
510	spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
511
512	codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
513
514	return 0;
515}
516
517static int patch_nvhdmi_2ch(struct hda_codec *codec)
518{
519	struct hdmi_spec *spec;
520
521	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
522	if (spec == NULL)
523		return -ENOMEM;
524
525	codec->spec = spec;
526
527	spec->multiout.num_dacs = 0;  /* no analog */
528	spec->multiout.max_channels = 2;
529	spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
530	spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
531
532	codec->patch_ops = nvhdmi_patch_ops_2ch;
533
534	return 0;
535}
536
537/*
538 * patch entries
539 */
540static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
541	{ .id = 0x10de0002, .name = "MCP77/78 HDMI",
542	  .patch = patch_nvhdmi_8ch_7x },
543	{ .id = 0x10de0003, .name = "MCP77/78 HDMI",
544	  .patch = patch_nvhdmi_8ch_7x },
545	{ .id = 0x10de0005, .name = "MCP77/78 HDMI",
546	  .patch = patch_nvhdmi_8ch_7x },
547	{ .id = 0x10de0006, .name = "MCP77/78 HDMI",
548	  .patch = patch_nvhdmi_8ch_7x },
549	{ .id = 0x10de0007, .name = "MCP79/7A HDMI",
550	  .patch = patch_nvhdmi_8ch_7x },
551	{ .id = 0x10de000a, .name = "GT220 HDMI",
552	  .patch = patch_nvhdmi_8ch_89 },
553	{ .id = 0x10de000b, .name = "GT21x HDMI",
554	  .patch = patch_nvhdmi_8ch_89 },
555	{ .id = 0x10de000c, .name = "MCP89 HDMI",
556	  .patch = patch_nvhdmi_8ch_89 },
557	{ .id = 0x10de000d, .name = "GT240 HDMI",
558	  .patch = patch_nvhdmi_8ch_89 },
559	{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
560	{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
561	{} /* terminator */
562};
563
564MODULE_ALIAS("snd-hda-codec-id:10de0002");
565MODULE_ALIAS("snd-hda-codec-id:10de0003");
566MODULE_ALIAS("snd-hda-codec-id:10de0005");
567MODULE_ALIAS("snd-hda-codec-id:10de0006");
568MODULE_ALIAS("snd-hda-codec-id:10de0007");
569MODULE_ALIAS("snd-hda-codec-id:10de000a");
570MODULE_ALIAS("snd-hda-codec-id:10de000b");
571MODULE_ALIAS("snd-hda-codec-id:10de000c");
572MODULE_ALIAS("snd-hda-codec-id:10de000d");
573MODULE_ALIAS("snd-hda-codec-id:10de0067");
574MODULE_ALIAS("snd-hda-codec-id:10de8001");
575
576MODULE_LICENSE("GPL");
577MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec");
578
579static struct hda_codec_preset_list nvhdmi_list = {
580	.preset = snd_hda_preset_nvhdmi,
581	.owner = THIS_MODULE,
582};
583
584static int __init patch_nvhdmi_init(void)
585{
586	return snd_hda_add_codec_preset(&nvhdmi_list);
587}
588
589static void __exit patch_nvhdmi_exit(void)
590{
591	snd_hda_delete_codec_preset(&nvhdmi_list);
592}
593
594module_init(patch_nvhdmi_init)
595module_exit(patch_nvhdmi_exit)