mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ALSA: hda - add DP MST audio support
This patch adds the DP MST audio support on i915 platform and
it will enable dyn_pcm_assign feature.
DP MST supports several device entry on the same port and each
device entry can map to one pcm stream. For example, on i915,
there are 3 pins, and each pin has 3 device entries. This means
there should be 3x3 pcms. However, there is only 3 pipe lines in
i915. This means 3 pcms are actived at most at the same moment.
We will create 5 pcms (pin number + dev entry num - 1) in this case.
For the details, please refer commit a76056f2e5
("ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug")
Each device entry is a virtual pin. It is described by pin_nid and dev_id
in struct hdmi_spec_per_pin.
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1484208294-8637-3-git-send-email-libin.yang@intel.com
			
			
This commit is contained in:
		
							parent
							
								
									13800f397e
								
							
						
					
					
						commit
						9152085def
					
				
					 2 changed files with 197 additions and 52 deletions
				
			
		| 
						 | 
					@ -467,6 +467,10 @@ static int read_pin_defaults(struct hda_codec *codec)
 | 
				
			||||||
		pin->nid = nid;
 | 
							pin->nid = nid;
 | 
				
			||||||
		pin->cfg = snd_hda_codec_read(codec, nid, 0,
 | 
							pin->cfg = snd_hda_codec_read(codec, nid, 0,
 | 
				
			||||||
					      AC_VERB_GET_CONFIG_DEFAULT, 0);
 | 
										      AC_VERB_GET_CONFIG_DEFAULT, 0);
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * all device entries are the same widget control so far
 | 
				
			||||||
 | 
							 * fixme: if any codec is different, need fix here
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		pin->ctrl = snd_hda_codec_read(codec, nid, 0,
 | 
							pin->ctrl = snd_hda_codec_read(codec, nid, 0,
 | 
				
			||||||
					       AC_VERB_GET_PIN_WIDGET_CONTROL,
 | 
										       AC_VERB_GET_PIN_WIDGET_CONTROL,
 | 
				
			||||||
					       0);
 | 
										       0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,6 +76,7 @@ struct hdmi_spec_per_cvt {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct hdmi_spec_per_pin {
 | 
					struct hdmi_spec_per_pin {
 | 
				
			||||||
	hda_nid_t pin_nid;
 | 
						hda_nid_t pin_nid;
 | 
				
			||||||
 | 
						int dev_id;
 | 
				
			||||||
	/* pin idx, different device entries on the same pin use the same idx */
 | 
						/* pin idx, different device entries on the same pin use the same idx */
 | 
				
			||||||
	int pin_nid_idx;
 | 
						int pin_nid_idx;
 | 
				
			||||||
	int num_mux_nids;
 | 
						int num_mux_nids;
 | 
				
			||||||
| 
						 | 
					@ -130,7 +131,23 @@ struct hdmi_spec {
 | 
				
			||||||
	struct snd_array cvts; /* struct hdmi_spec_per_cvt */
 | 
						struct snd_array cvts; /* struct hdmi_spec_per_cvt */
 | 
				
			||||||
	hda_nid_t cvt_nids[4]; /* only for haswell fix */
 | 
						hda_nid_t cvt_nids[4]; /* only for haswell fix */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * num_pins is the number of virtual pins
 | 
				
			||||||
 | 
						 * for example, there are 3 pins, and each pin
 | 
				
			||||||
 | 
						 * has 4 device entries, then the num_pins is 12
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	int num_pins;
 | 
						int num_pins;
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * num_nids is the number of real pins
 | 
				
			||||||
 | 
						 * In the above example, num_nids is 3
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int num_nids;
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * dev_num is the number of device entries
 | 
				
			||||||
 | 
						 * on each pin.
 | 
				
			||||||
 | 
						 * In the above example, dev_num is 4
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int dev_num;
 | 
				
			||||||
	struct snd_array pins; /* struct hdmi_spec_per_pin */
 | 
						struct snd_array pins; /* struct hdmi_spec_per_pin */
 | 
				
			||||||
	struct hdmi_pcm pcm_rec[16];
 | 
						struct hdmi_pcm pcm_rec[16];
 | 
				
			||||||
	struct mutex pcm_lock;
 | 
						struct mutex pcm_lock;
 | 
				
			||||||
| 
						 | 
					@ -217,14 +234,26 @@ union audio_infoframe {
 | 
				
			||||||
/* obtain hda_pcm object assigned to idx */
 | 
					/* obtain hda_pcm object assigned to idx */
 | 
				
			||||||
#define get_pcm_rec(spec, idx)	(get_hdmi_pcm(spec, idx)->pcm)
 | 
					#define get_pcm_rec(spec, idx)	(get_hdmi_pcm(spec, idx)->pcm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
 | 
					static int pin_id_to_pin_index(struct hda_codec *codec,
 | 
				
			||||||
 | 
								       hda_nid_t pin_nid, int dev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hdmi_spec *spec = codec->spec;
 | 
						struct hdmi_spec *spec = codec->spec;
 | 
				
			||||||
	int pin_idx;
 | 
						int pin_idx;
 | 
				
			||||||
 | 
						struct hdmi_spec_per_pin *per_pin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
 | 
						/*
 | 
				
			||||||
		if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
 | 
						 * (dev_id == -1) means it is NON-MST pin
 | 
				
			||||||
 | 
						 * return the first virtual pin on this port
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dev_id == -1)
 | 
				
			||||||
 | 
							dev_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 | 
				
			||||||
 | 
							per_pin = get_pin(spec, pin_idx);
 | 
				
			||||||
 | 
							if ((per_pin->pin_nid == pin_nid) &&
 | 
				
			||||||
 | 
								(per_pin->dev_id == dev_id))
 | 
				
			||||||
			return pin_idx;
 | 
								return pin_idx;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid);
 | 
						codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid);
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -724,10 +753,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 | 
					static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
 | 
					static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
 | 
				
			||||||
 | 
									      int dev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hdmi_spec *spec = codec->spec;
 | 
						struct hdmi_spec *spec = codec->spec;
 | 
				
			||||||
	int pin_idx = pin_nid_to_pin_index(codec, nid);
 | 
						int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pin_idx < 0)
 | 
						if (pin_idx < 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -738,7 +768,8 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
 | 
				
			||||||
static void jack_callback(struct hda_codec *codec,
 | 
					static void jack_callback(struct hda_codec *codec,
 | 
				
			||||||
			  struct hda_jack_callback *jack)
 | 
								  struct hda_jack_callback *jack)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	check_presence_and_report(codec, jack->nid);
 | 
						/* hda_jack don't support DP MST */
 | 
				
			||||||
 | 
						check_presence_and_report(codec, jack->nid, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 | 
					static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 | 
				
			||||||
| 
						 | 
					@ -747,6 +778,12 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 | 
				
			||||||
	struct hda_jack_tbl *jack;
 | 
						struct hda_jack_tbl *jack;
 | 
				
			||||||
	int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
 | 
						int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * assume DP MST uses dyn_pcm_assign and acomp and
 | 
				
			||||||
 | 
						 * never comes here
 | 
				
			||||||
 | 
						 * if DP MST supports unsol event, below code need
 | 
				
			||||||
 | 
						 * consider dev_entry
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
 | 
						jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
 | 
				
			||||||
	if (!jack)
 | 
						if (!jack)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -757,7 +794,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 | 
				
			||||||
		codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
 | 
							codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
 | 
				
			||||||
		!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
 | 
							!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	check_presence_and_report(codec, jack->nid);
 | 
						/* hda_jack don't support DP MST */
 | 
				
			||||||
 | 
						check_presence_and_report(codec, jack->nid, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 | 
					static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 | 
				
			||||||
| 
						 | 
					@ -970,28 +1008,60 @@ static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
 | 
				
			||||||
 * by any other pins.
 | 
					 * by any other pins.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void intel_not_share_assigned_cvt(struct hda_codec *codec,
 | 
					static void intel_not_share_assigned_cvt(struct hda_codec *codec,
 | 
				
			||||||
			hda_nid_t pin_nid, int mux_idx)
 | 
										 hda_nid_t pin_nid,
 | 
				
			||||||
 | 
										 int dev_id, int mux_idx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hdmi_spec *spec = codec->spec;
 | 
						struct hdmi_spec *spec = codec->spec;
 | 
				
			||||||
	hda_nid_t nid;
 | 
						hda_nid_t nid;
 | 
				
			||||||
	int cvt_idx, curr;
 | 
						int cvt_idx, curr;
 | 
				
			||||||
	struct hdmi_spec_per_cvt *per_cvt;
 | 
						struct hdmi_spec_per_cvt *per_cvt;
 | 
				
			||||||
 | 
						struct hdmi_spec_per_pin *per_pin;
 | 
				
			||||||
 | 
						int pin_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* configure all pins, including "no physical connection" ones */
 | 
						/* configure the pins connections */
 | 
				
			||||||
	for_each_hda_codec_node(nid, codec) {
 | 
						for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 | 
				
			||||||
		unsigned int wid_caps = get_wcaps(codec, nid);
 | 
							int dev_id_saved;
 | 
				
			||||||
		unsigned int wid_type = get_wcaps_type(wid_caps);
 | 
							int dev_num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (wid_type != AC_WID_PIN)
 | 
							per_pin = get_pin(spec, pin_idx);
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * pin not connected to monitor
 | 
				
			||||||
 | 
							 * no need to operate on it
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (!per_pin->pcm)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (nid == pin_nid)
 | 
							if ((per_pin->pin_nid == pin_nid) &&
 | 
				
			||||||
 | 
								(per_pin->dev_id == dev_id))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * if per_pin->dev_id >= dev_num,
 | 
				
			||||||
 | 
							 * snd_hda_get_dev_select() will fail,
 | 
				
			||||||
 | 
							 * and the following operation is unpredictable.
 | 
				
			||||||
 | 
							 * So skip this situation.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
 | 
				
			||||||
 | 
							if (per_pin->dev_id >= dev_num)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nid = per_pin->pin_nid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Calling this function should not impact
 | 
				
			||||||
 | 
							 * on the device entry selection
 | 
				
			||||||
 | 
							 * So let's save the dev id for each pin,
 | 
				
			||||||
 | 
							 * and restore it when return
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							dev_id_saved = snd_hda_get_dev_select(codec, nid);
 | 
				
			||||||
 | 
							snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
 | 
				
			||||||
		curr = snd_hda_codec_read(codec, nid, 0,
 | 
							curr = snd_hda_codec_read(codec, nid, 0,
 | 
				
			||||||
					  AC_VERB_GET_CONNECT_SEL, 0);
 | 
										  AC_VERB_GET_CONNECT_SEL, 0);
 | 
				
			||||||
		if (curr != mux_idx)
 | 
							if (curr != mux_idx) {
 | 
				
			||||||
 | 
								snd_hda_set_dev_select(codec, nid, dev_id_saved);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* choose an unassigned converter. The conveters in the
 | 
							/* choose an unassigned converter. The conveters in the
 | 
				
			||||||
		 * connection list are in the same order as in the codec.
 | 
							 * connection list are in the same order as in the codec.
 | 
				
			||||||
| 
						 | 
					@ -1008,12 +1078,13 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec,
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							snd_hda_set_dev_select(codec, nid, dev_id_saved);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* A wrapper of intel_not_share_asigned_cvt() */
 | 
					/* A wrapper of intel_not_share_asigned_cvt() */
 | 
				
			||||||
static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
 | 
					static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
 | 
				
			||||||
			hda_nid_t pin_nid, hda_nid_t cvt_nid)
 | 
								hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int mux_idx;
 | 
						int mux_idx;
 | 
				
			||||||
	struct hdmi_spec *spec = codec->spec;
 | 
						struct hdmi_spec *spec = codec->spec;
 | 
				
			||||||
| 
						 | 
					@ -1025,7 +1096,7 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
 | 
						mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
 | 
				
			||||||
	if (mux_idx >= 0)
 | 
						if (mux_idx >= 0)
 | 
				
			||||||
		intel_not_share_assigned_cvt(codec, pin_nid, mux_idx);
 | 
							intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* skeleton caller of pin_cvt_fixup ops */
 | 
					/* skeleton caller of pin_cvt_fixup ops */
 | 
				
			||||||
| 
						 | 
					@ -1140,6 +1211,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 | 
				
			||||||
	per_pin->cvt_nid = per_cvt->cvt_nid;
 | 
						per_pin->cvt_nid = per_cvt->cvt_nid;
 | 
				
			||||||
	hinfo->nid = per_cvt->cvt_nid;
 | 
						hinfo->nid = per_cvt->cvt_nid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
 | 
				
			||||||
	snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
 | 
						snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
 | 
				
			||||||
			    AC_VERB_SET_CONNECT_SEL,
 | 
								    AC_VERB_SET_CONNECT_SEL,
 | 
				
			||||||
			    per_pin->mux_idx);
 | 
								    per_pin->mux_idx);
 | 
				
			||||||
| 
						 | 
					@ -1198,6 +1270,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* all the device entries on the same pin have the same conn list */
 | 
				
			||||||
	per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
 | 
						per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
 | 
				
			||||||
							per_pin->mux_nids,
 | 
												per_pin->mux_nids,
 | 
				
			||||||
							HDA_MAX_CONNECTIONS);
 | 
												HDA_MAX_CONNECTIONS);
 | 
				
			||||||
| 
						 | 
					@ -1215,13 +1288,13 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
 | 
				
			||||||
		return per_pin->pin_nid_idx;
 | 
							return per_pin->pin_nid_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* have a second try; check the "reserved area" over num_pins */
 | 
						/* have a second try; check the "reserved area" over num_pins */
 | 
				
			||||||
	for (i = spec->num_pins; i < spec->pcm_used; i++) {
 | 
						for (i = spec->num_nids; i < spec->pcm_used; i++) {
 | 
				
			||||||
		if (!test_bit(i, &spec->pcm_bitmap))
 | 
							if (!test_bit(i, &spec->pcm_bitmap))
 | 
				
			||||||
			return i;
 | 
								return i;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* the last try; check the empty slots in pins */
 | 
						/* the last try; check the empty slots in pins */
 | 
				
			||||||
	for (i = 0; i < spec->num_pins; i++) {
 | 
						for (i = 0; i < spec->num_nids; i++) {
 | 
				
			||||||
		if (!test_bit(i, &spec->pcm_bitmap))
 | 
							if (!test_bit(i, &spec->pcm_bitmap))
 | 
				
			||||||
			return i;
 | 
								return i;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1296,10 +1369,13 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
 | 
				
			||||||
	per_pin->cvt_nid = hinfo->nid;
 | 
						per_pin->cvt_nid = hinfo->nid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
 | 
						mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
 | 
				
			||||||
	if (mux_idx < per_pin->num_mux_nids)
 | 
						if (mux_idx < per_pin->num_mux_nids) {
 | 
				
			||||||
 | 
							snd_hda_set_dev_select(codec, per_pin->pin_nid,
 | 
				
			||||||
 | 
									   per_pin->dev_id);
 | 
				
			||||||
		snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
 | 
							snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
 | 
				
			||||||
				AC_VERB_SET_CONNECT_SEL,
 | 
									AC_VERB_SET_CONNECT_SEL,
 | 
				
			||||||
				mux_idx);
 | 
									mux_idx);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
 | 
						snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
 | 
						non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
 | 
				
			||||||
| 
						 | 
					@ -1467,6 +1543,11 @@ static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
 | 
				
			||||||
	if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
 | 
						if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
 | 
				
			||||||
		jack = spec->pcm_rec[per_pin->pcm_idx].jack;
 | 
							jack = spec->pcm_rec[per_pin->pcm_idx].jack;
 | 
				
			||||||
	else if (!spec->dyn_pcm_assign) {
 | 
						else if (!spec->dyn_pcm_assign) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * jack tbl doesn't support DP MST
 | 
				
			||||||
 | 
							 * DP MST will use dyn_pcm_assign,
 | 
				
			||||||
 | 
							 * so DP MST will never come here
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		jack_tbl = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
 | 
							jack_tbl = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
 | 
				
			||||||
		if (jack_tbl)
 | 
							if (jack_tbl)
 | 
				
			||||||
			jack = jack_tbl->jack;
 | 
								jack = jack_tbl->jack;
 | 
				
			||||||
| 
						 | 
					@ -1485,9 +1566,9 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&per_pin->lock);
 | 
						mutex_lock(&per_pin->lock);
 | 
				
			||||||
	eld->monitor_present = false;
 | 
						eld->monitor_present = false;
 | 
				
			||||||
	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,
 | 
						size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
 | 
				
			||||||
				      &eld->monitor_present, eld->eld_buffer,
 | 
									      per_pin->dev_id, &eld->monitor_present,
 | 
				
			||||||
				      ELD_MAX_SIZE);
 | 
									      eld->eld_buffer, ELD_MAX_SIZE);
 | 
				
			||||||
	if (size > 0) {
 | 
						if (size > 0) {
 | 
				
			||||||
		size = min(size, ELD_MAX_SIZE);
 | 
							size = min(size, ELD_MAX_SIZE);
 | 
				
			||||||
		if (snd_hdmi_parse_eld(codec, &eld->info,
 | 
							if (snd_hdmi_parse_eld(codec, &eld->info,
 | 
				
			||||||
| 
						 | 
					@ -1565,38 +1646,81 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 | 
				
			||||||
	int pin_idx;
 | 
						int pin_idx;
 | 
				
			||||||
	struct hdmi_spec_per_pin *per_pin;
 | 
						struct hdmi_spec_per_pin *per_pin;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
						int dev_num, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	caps = snd_hda_query_pin_caps(codec, pin_nid);
 | 
						caps = snd_hda_query_pin_caps(codec, pin_nid);
 | 
				
			||||||
	if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
 | 
						if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * For DP MST audio, Configuration Default is the same for
 | 
				
			||||||
 | 
						 * all device entries on the same pin
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	config = snd_hda_codec_get_pincfg(codec, pin_nid);
 | 
						config = snd_hda_codec_get_pincfg(codec, pin_nid);
 | 
				
			||||||
	if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
 | 
						if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (is_haswell_plus(codec))
 | 
						/*
 | 
				
			||||||
		intel_haswell_fixup_connect_list(codec, pin_nid);
 | 
						 * To simplify the implementation, malloc all
 | 
				
			||||||
 | 
						 * the virtual pins in the initialization statically
 | 
				
			||||||
	pin_idx = spec->num_pins;
 | 
						 */
 | 
				
			||||||
	per_pin = snd_array_new(&spec->pins);
 | 
						if (is_haswell_plus(codec)) {
 | 
				
			||||||
	if (!per_pin)
 | 
							/*
 | 
				
			||||||
		return -ENOMEM;
 | 
							 * On Intel platforms, device entries number is
 | 
				
			||||||
 | 
							 * changed dynamically. If there is a DP MST
 | 
				
			||||||
	per_pin->pin_nid = pin_nid;
 | 
							 * hub connected, the device entries number is 3.
 | 
				
			||||||
	per_pin->non_pcm = false;
 | 
							 * Otherwise, it is 1.
 | 
				
			||||||
	if (spec->dyn_pcm_assign)
 | 
							 * Here we manually set dev_num to 3, so that
 | 
				
			||||||
		per_pin->pcm_idx = -1;
 | 
							 * we can initialize all the device entries when
 | 
				
			||||||
	else {
 | 
							 * bootup statically.
 | 
				
			||||||
		per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
 | 
							 */
 | 
				
			||||||
		per_pin->pcm_idx = pin_idx;
 | 
							dev_num = 3;
 | 
				
			||||||
 | 
							spec->dev_num = 3;
 | 
				
			||||||
 | 
						} else if (spec->dyn_pcm_assign && codec->dp_mst) {
 | 
				
			||||||
 | 
							dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * spec->dev_num is the maxinum number of device entries
 | 
				
			||||||
 | 
							 * among all the pins
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							spec->dev_num = (spec->dev_num > dev_num) ?
 | 
				
			||||||
 | 
								spec->dev_num : dev_num;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If the platform doesn't support DP MST,
 | 
				
			||||||
 | 
							 * manually set dev_num to 1. This means
 | 
				
			||||||
 | 
							 * the pin has only one device entry.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							dev_num = 1;
 | 
				
			||||||
 | 
							spec->dev_num = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	per_pin->pin_nid_idx = pin_idx;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = hdmi_read_pin_conn(codec, pin_idx);
 | 
						for (i = 0; i < dev_num; i++) {
 | 
				
			||||||
	if (err < 0)
 | 
							pin_idx = spec->num_pins;
 | 
				
			||||||
		return err;
 | 
							per_pin = snd_array_new(&spec->pins);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spec->num_pins++;
 | 
							if (!per_pin)
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (spec->dyn_pcm_assign) {
 | 
				
			||||||
 | 
								per_pin->pcm = NULL;
 | 
				
			||||||
 | 
								per_pin->pcm_idx = -1;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
 | 
				
			||||||
 | 
								per_pin->pcm_idx = pin_idx;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							per_pin->pin_nid = pin_nid;
 | 
				
			||||||
 | 
							per_pin->pin_nid_idx = spec->num_nids;
 | 
				
			||||||
 | 
							per_pin->dev_id = i;
 | 
				
			||||||
 | 
							per_pin->non_pcm = false;
 | 
				
			||||||
 | 
							snd_hda_set_dev_select(codec, pin_nid, i);
 | 
				
			||||||
 | 
							if (is_haswell_plus(codec))
 | 
				
			||||||
 | 
								intel_haswell_fixup_connect_list(codec, pin_nid);
 | 
				
			||||||
 | 
							err = hdmi_read_pin_conn(codec, pin_idx);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							spec->num_pins++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spec->num_nids++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1744,7 +1868,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 | 
				
			||||||
	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
 | 
						/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
 | 
				
			||||||
	/* Todo: add DP1.2 MST audio support later */
 | 
						/* Todo: add DP1.2 MST audio support later */
 | 
				
			||||||
	if (codec_has_acomp(codec))
 | 
						if (codec_has_acomp(codec))
 | 
				
			||||||
		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,
 | 
							snd_hdac_sync_audio_rate(&codec->core, pin_nid, per_pin->dev_id,
 | 
				
			||||||
					 runtime->rate);
 | 
										 runtime->rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
 | 
						non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
 | 
				
			||||||
| 
						 | 
					@ -1762,6 +1886,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 | 
				
			||||||
				    pinctl | PIN_OUT);
 | 
									    pinctl | PIN_OUT);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* snd_hda_set_dev_select() has been called before */
 | 
				
			||||||
	err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
 | 
						err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
 | 
				
			||||||
				 stream_tag, format);
 | 
									 stream_tag, format);
 | 
				
			||||||
	mutex_unlock(&spec->pcm_lock);
 | 
						mutex_unlock(&spec->pcm_lock);
 | 
				
			||||||
| 
						 | 
					@ -1897,17 +2022,23 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
 | 
				
			||||||
static int generic_hdmi_build_pcms(struct hda_codec *codec)
 | 
					static int generic_hdmi_build_pcms(struct hda_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hdmi_spec *spec = codec->spec;
 | 
						struct hdmi_spec *spec = codec->spec;
 | 
				
			||||||
	int pin_idx;
 | 
						int idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 | 
						/*
 | 
				
			||||||
 | 
						 * for non-mst mode, pcm number is the same as before
 | 
				
			||||||
 | 
						 * for DP MST mode, pcm number is (nid number + dev_num - 1)
 | 
				
			||||||
 | 
						 *  dev_num is the device entry number in a pin
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for (idx = 0; idx < spec->num_nids + spec->dev_num - 1; idx++) {
 | 
				
			||||||
		struct hda_pcm *info;
 | 
							struct hda_pcm *info;
 | 
				
			||||||
		struct hda_pcm_stream *pstr;
 | 
							struct hda_pcm_stream *pstr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
 | 
							info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
 | 
				
			||||||
		if (!info)
 | 
							if (!info)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spec->pcm_rec[pin_idx].pcm = info;
 | 
							spec->pcm_rec[idx].pcm = info;
 | 
				
			||||||
		spec->pcm_used++;
 | 
							spec->pcm_used++;
 | 
				
			||||||
		info->pcm_type = HDA_PCM_TYPE_HDMI;
 | 
							info->pcm_type = HDA_PCM_TYPE_HDMI;
 | 
				
			||||||
		info->own_chmap = true;
 | 
							info->own_chmap = true;
 | 
				
			||||||
| 
						 | 
					@ -1915,6 +2046,9 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
 | 
				
			||||||
		pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
 | 
							pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
 | 
				
			||||||
		pstr->substreams = 1;
 | 
							pstr->substreams = 1;
 | 
				
			||||||
		pstr->ops = generic_ops;
 | 
							pstr->ops = generic_ops;
 | 
				
			||||||
 | 
							/* pcm number is less than 16 */
 | 
				
			||||||
 | 
							if (spec->pcm_used >= 16)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		/* other pstr fields are set in open */
 | 
							/* other pstr fields are set in open */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2070,7 +2204,9 @@ static int generic_hdmi_init(struct hda_codec *codec)
 | 
				
			||||||
	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 | 
						for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 | 
				
			||||||
		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 | 
							struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 | 
				
			||||||
		hda_nid_t pin_nid = per_pin->pin_nid;
 | 
							hda_nid_t pin_nid = per_pin->pin_nid;
 | 
				
			||||||
 | 
							int dev_id = per_pin->dev_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							snd_hda_set_dev_select(codec, pin_nid, dev_id);
 | 
				
			||||||
		hdmi_init_pin(codec, pin_nid);
 | 
							hdmi_init_pin(codec, pin_nid);
 | 
				
			||||||
		if (!codec_has_acomp(codec))
 | 
							if (!codec_has_acomp(codec))
 | 
				
			||||||
			snd_hda_jack_detect_enable_callback(codec, pin_nid,
 | 
								snd_hda_jack_detect_enable_callback(codec, pin_nid,
 | 
				
			||||||
| 
						 | 
					@ -2178,6 +2314,7 @@ static int alloc_generic_hdmi(struct hda_codec *codec)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spec->ops = generic_standard_hdmi_ops;
 | 
						spec->ops = generic_standard_hdmi_ops;
 | 
				
			||||||
 | 
						spec->dev_num = 1;	/* initialize to 1 */
 | 
				
			||||||
	mutex_init(&spec->pcm_lock);
 | 
						mutex_init(&spec->pcm_lock);
 | 
				
			||||||
	snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
 | 
						snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2295,6 +2432,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hda_codec *codec = audio_ptr;
 | 
						struct hda_codec *codec = audio_ptr;
 | 
				
			||||||
	int pin_nid;
 | 
						int pin_nid;
 | 
				
			||||||
 | 
						int dev_id = pipe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* we assume only from port-B to port-D */
 | 
						/* we assume only from port-B to port-D */
 | 
				
			||||||
	if (port < 1 || port > 3)
 | 
						if (port < 1 || port > 3)
 | 
				
			||||||
| 
						 | 
					@ -2321,7 +2459,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snd_hdac_i915_set_bclk(&codec->bus->core);
 | 
						snd_hdac_i915_set_bclk(&codec->bus->core);
 | 
				
			||||||
	check_presence_and_report(codec, pin_nid);
 | 
						check_presence_and_report(codec, pin_nid, dev_id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* register i915 component pin_eld_notify callback */
 | 
					/* register i915 component pin_eld_notify callback */
 | 
				
			||||||
| 
						 | 
					@ -2354,11 +2492,13 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec,
 | 
				
			||||||
			       hda_nid_t cvt_nid)
 | 
								       hda_nid_t cvt_nid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (per_pin) {
 | 
						if (per_pin) {
 | 
				
			||||||
 | 
							snd_hda_set_dev_select(codec, per_pin->pin_nid,
 | 
				
			||||||
 | 
								       per_pin->dev_id);
 | 
				
			||||||
		intel_verify_pin_cvt_connect(codec, per_pin);
 | 
							intel_verify_pin_cvt_connect(codec, per_pin);
 | 
				
			||||||
		intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
 | 
							intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
 | 
				
			||||||
					     per_pin->mux_idx);
 | 
									     per_pin->dev_id, per_pin->mux_idx);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
 | 
							intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2378,6 +2518,8 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	spec = codec->spec;
 | 
						spec = codec->spec;
 | 
				
			||||||
 | 
						codec->dp_mst = true;
 | 
				
			||||||
 | 
						spec->dyn_pcm_assign = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	intel_haswell_enable_all_pins(codec, true);
 | 
						intel_haswell_enable_all_pins(codec, true);
 | 
				
			||||||
	intel_haswell_fixup_enable_dp12(codec);
 | 
						intel_haswell_fixup_enable_dp12(codec);
 | 
				
			||||||
| 
						 | 
					@ -2389,7 +2531,6 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
 | 
				
			||||||
		codec->core.link_power_control = 1;
 | 
							codec->core.link_power_control = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	codec->patch_ops.set_power_state = haswell_set_power_state;
 | 
						codec->patch_ops.set_power_state = haswell_set_power_state;
 | 
				
			||||||
	codec->dp_mst = true;
 | 
					 | 
				
			||||||
	codec->depop_delay = 0;
 | 
						codec->depop_delay = 0;
 | 
				
			||||||
	codec->auto_runtime_pm = 1;
 | 
						codec->auto_runtime_pm = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue