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:
Libin Yang 2017-01-12 16:04:53 +08:00 коммит произвёл Daniel Vetter
Родитель 13800f397e
Коммит 9152085def
2 изменённых файлов: 197 добавлений и 52 удалений

Просмотреть файл

@ -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;