Re: [PATCH 3/4] snd: add support for displayport multi-stream to hda codec.

Takashi Iwai
2015-06-19T11:15:59Z

At Fri, 19 Jun 2015 20:33:39 +1000,
Dave Airlie wrote:
>
> On 19 June 2015 at 19:54, Lin, Mengdong <mengdong.lin@intel.com> wrote:
> > Hi Takashi/Dave,
> >
> > Shall we move or cc this discussion on audio driver side to ALSA ML?
>
> Oops I thought I had cc'ed these patches to alsa-devel as well when I sent them.
>
> > I think we also need to decide how to manage PCM devices for DP MST.
> > Now the HD-A driver create a PCM device for each pin, and the substream
> > number is 1 for each PCM. Now with DP MST enabled, each pin can support
> > multiple streams (e.g. 3 on Intel HSW/BDW/SKL).
> >
> > There may be 2 options:
> > -#1: Let an HDMI codec specify number of substreams, same as the number
> > of device entries on a pin. We can specify 3 for HSW/BDW/SKL. Other
> > vendors can also specify a value according to actual HW capabilities.
> >
> > So for HSW, we have 3x3 subtreams totally. But we only have 3 convertors
> > (for 3 display pipelines), so we can open up to 3 substreams at the same
> > time. When the audio driver finds all 3 convertors are used when opening
> > a new substream, it will fail.
>
> One thing I noticed is the number of devices on a PIN is only updated when
> the MST device is plugged in so normally pins 5,6,7 have 0 devices, and when
> I plug in MST device, I get the 3 devices on port 6. So it seems dynamic
> enough at this point, though I guess it'll always be 0 or 3.
> >
> > - #2: Create PCM device dynamically. Only create a PCM devices for a device
> > entry which connects to monitor with audio support. When the monitor
> > is removed, the PCM device will be disconnected, closed and removed,
> > similar to the USB case.
> >
> > This will change ALSA core. But there will be less PCM devices and
> > substreams, since the number of connected monitors Is decided by the
> > actual GPU display pipeline.
>
> I like this option more, since I think it should be more like USB, but I've
> no idea how much work it would be from the alsa side, this patch was
> probably as deep into alsa as I've gone.

Two things have to be considered for compatibility:
- ELD, channel map and jack detection: these are created per PCM
device, and extending to substream would confuse user space a lot.
In theory, it can be extended using subdevice number, but in anyway
this won't work with PulseAudio as is.

- The per-pin assignment provides a more or less persistent route to a
certain device. Changing the assignment method may break the
previous setup.

Also, the dynamic PCM creation / removal is an issue that has been
discussed many times. Unfortunately it won't work as is, at lest for
PA. Currently PA does probing of devices only at the card probe time.
The hotplug of USB-audio works because it's always tied with the
card. But in this case, the card remains while only the PCM devices
will be created / removed, thus the probe in PA won't be triggered.

Takashi

>
> Dave.
>
> >> Signed-off-by: Dave Airlie <airlied@redhat.com>
> >> ---
> >> include/sound/hda_verbs.h | 2 +
> >> sound/pci/hda/hda_codec.c | 1 +
> >> sound/pci/hda/hda_proc.c | 5 +-
> >> sound/pci/hda/patch_hdmi.c | 181
> >> +++++++++++++++++++++++++++++++--------------
> >> 4 files changed, 131 insertions(+), 58 deletions(-)
> >>
> >> diff --git a/include/sound/hda_verbs.h b/include/sound/hda_verbs.h index
> >> d0509db..3b62ac5 100644
> >> --- a/include/sound/hda_verbs.h
> >> +++ b/include/sound/hda_verbs.h
> >> @@ -75,6 +75,7 @@ enum {
> >> #define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34
> >> #define AC_VERB_GET_DEVICE_SEL 0xf35
> >> #define AC_VERB_GET_DEVICE_LIST 0xf36
> >> +#define AC_VERB_GET_DP_STREAM_ID 0xf3c
> >>
> >> /*
> >> * SET verbs
> >> @@ -115,6 +116,7 @@ enum {
> >> #define AC_VERB_SET_HDMI_CP_CTRL 0x733
> >> #define AC_VERB_SET_HDMI_CHAN_SLOT 0x734
> >> #define AC_VERB_SET_DEVICE_SEL 0x735
> >> +#define AC_VERB_SET_DP_STREAM_ID 0x73C
> >>
> >> /*
> >> * Parameter IDs
> >> diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index
> >> 5645481..3981c63 100644
> >> --- a/sound/pci/hda/hda_codec.c
> >> +++ b/sound/pci/hda/hda_codec.c
> >> @@ -482,6 +482,7 @@ int snd_hda_get_devices(struct hda_codec *codec,
> >> hda_nid_t nid,
> >> }
> >> return devices;
> >> }
> >> +EXPORT_SYMBOL_GPL(snd_hda_get_devices);
> >>
> >> /*
> >> * destructor
> >> diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index
> >> baaf7ed0..39fac53 100644
> >> --- a/sound/pci/hda/hda_proc.c
> >> +++ b/sound/pci/hda/hda_proc.c
> >> @@ -644,10 +644,13 @@ static void print_device_list(struct snd_info_buffer
> >> *buffer,
> >> int i, curr = -1;
> >> u8 dev_list[AC_MAX_DEV_LIST_LEN];
> >> int devlist_len;
> >> + int dp_s_id;
> >>
> >> + dp_s_id = snd_hda_codec_read(codec, nid, 0,
> >> + AC_VERB_GET_DP_STREAM_ID, 0);
> >> devlist_len = snd_hda_get_devices(codec, nid, dev_list,
> >> AC_MAX_DEV_LIST_LEN);
> >> - snd_iprintf(buffer, " Devices: %d\n", devlist_len);
> >> + snd_iprintf(buffer, " Devices: %d: 0x%x\n", devlist_len, dp_s_id);
> >> if (devlist_len <= 0)
> >> return;
> >>
> >> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index
> >> 5f44f60..8272656 100644
> >> --- a/sound/pci/hda/patch_hdmi.c
> >> +++ b/sound/pci/hda/patch_hdmi.c
> >> @@ -68,6 +68,17 @@ struct hdmi_spec_per_cvt {
> >> /* max. connections to a widget */
> >> #define HDA_MAX_CONNECTIONS 32
> >>
> >> +struct hdmi_spec_per_pin;
> >> +#define HDA_MAX_DEVICES 3
> >> +struct hdmi_spec_per_device {
> >> + struct hdmi_spec_per_pin *pin;
> >> + int device_idx;
> >> + struct hdmi_eld sink_eld;
> >> +#ifdef CONFIG_PROC_FS
> >> + struct snd_info_entry *proc_entry;
> >> +#endif
> >> +};
> >> +
> >> struct hdmi_spec_per_pin {
> >> hda_nid_t pin_nid;
> >> int num_mux_nids;
> >> @@ -76,7 +87,11 @@ struct hdmi_spec_per_pin {
> >> hda_nid_t cvt_nid;
> >>
> >> struct hda_codec *codec;
> >> - struct hdmi_eld sink_eld;
> >> +
> >> + int num_devices;
> >> + u8 dev_list[AC_MAX_DEV_LIST_LEN];
> >> + struct hdmi_spec_per_device devices[HDA_MAX_DEVICES];
> >> +
> >> struct mutex lock;
> >> struct delayed_work work;
> >> struct snd_kcontrol *eld_ctl;
> >> @@ -86,9 +101,6 @@ struct hdmi_spec_per_pin {
> >> bool non_pcm;
> >> bool chmap_set; /* channel-map override by ALSA API? */
> >> unsigned char chmap[8]; /* ALSA API channel-map */ -#ifdef
> >> CONFIG_PROC_FS
> >> - struct snd_info_entry *proc_entry;
> >> -#endif
> >> };
> >>
> >> struct cea_channel_speaker_allocation;
> >> @@ -409,7 +421,7 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol
> >> *kcontrol,
> >>
> >> pin_idx = kcontrol->private_value;
> >> per_pin = get_pin(spec, pin_idx);
> >> - eld = &per_pin->sink_eld;
> >> + eld = &per_pin->devices[0].sink_eld;
> >>
> >> mutex_lock(&per_pin->lock);
> >> uinfo->count = eld->eld_valid ? eld->eld_size : 0; @@ -429,7 +441,7 @@
> >> static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
> >>
> >> pin_idx = kcontrol->private_value;
> >> per_pin = get_pin(spec, pin_idx);
> >> - eld = &per_pin->sink_eld;
> >> + eld = &per_pin->devices[0].sink_eld;
> >>
> >> mutex_lock(&per_pin->lock);
> >> if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) { @@ -549,60
> >> +561,63 @@ static void hdmi_set_channel_count(struct hda_codec *codec,
> >> */
> >>
> >> #ifdef CONFIG_PROC_FS
> >> -static void print_eld_info(struct snd_info_entry *entry,
> >> - struct snd_info_buffer *buffer)
> >> +static void print_eld_info_device(struct snd_info_entry *entry,
> >> + struct snd_info_buffer *buffer)
> >> {
> >> - struct hdmi_spec_per_pin *per_pin = entry->private_data;
> >> + struct hdmi_spec_per_device *per_device = entry->private_data;
> >>
> >> - mutex_lock(&per_pin->lock);
> >> - snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer);
> >> - mutex_unlock(&per_pin->lock);
> >> + mutex_lock(&per_device->pin->lock);
> >> + snd_hdmi_print_eld_info(&per_device->sink_eld, buffer);
> >> + mutex_unlock(&per_device->pin->lock);
> >> }
> >>
> >> -static void write_eld_info(struct snd_info_entry *entry,
> >> - struct snd_info_buffer *buffer)
> >> +static void write_eld_info_device(struct snd_info_entry *entry,
> >> + struct snd_info_buffer *buffer)
> >> {
> >> - struct hdmi_spec_per_pin *per_pin = entry->private_data;
> >> + struct hdmi_spec_per_device *per_device = entry->private_data;
> >>
> >> - mutex_lock(&per_pin->lock);
> >> - snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer);
> >> - mutex_unlock(&per_pin->lock);
> >> + mutex_lock(&per_device->pin->lock);
> >> + snd_hdmi_write_eld_info(&per_device->sink_eld, buffer);
> >> + mutex_unlock(&per_device->pin->lock);
> >> }
> >>
> >> -static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
> >> +static int eld_device_proc_new(struct hdmi_spec_per_device *per_device,
> >> +int pin_idx, int dev_idx)
> >> {
> >> char name[32];
> >> - struct hda_codec *codec = per_pin->codec;
> >> + struct hda_codec *codec = per_device->pin->codec;
> >> struct snd_info_entry *entry;
> >> int err;
> >>
> >> - snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
> >> + if (dev_idx == -1)
> >> + snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, pin_idx);
> >> + else
> >> + snprintf(name, sizeof(name), "eld#%d.%d.%d", codec->addr,
> >> pin_idx,
> >> +dev_idx);
> >> err = snd_card_proc_new(codec->card, name, &entry);
> >> if (err < 0)
> >> return err;
> >>
> >> - snd_info_set_text_ops(entry, per_pin, print_eld_info);
> >> - entry->c.text.write = write_eld_info;
> >> + snd_info_set_text_ops(entry, per_device, print_eld_info_device);
> >> + entry->c.text.write = write_eld_info_device;
> >> entry->mode |= S_IWUSR;
> >> - per_pin->proc_entry = entry;
> >> + per_device->proc_entry = entry;
> >>
> >> return 0;
> >> }
> >>
> >> -static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
> >> +static void eld_device_proc_free(struct hdmi_spec_per_device
> >> +*per_device)
> >> {
> >> - if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) {
> >> - snd_device_free(per_pin->codec->card, per_pin->proc_entry);
> >> - per_pin->proc_entry = NULL;
> >> + if (!per_device->pin->codec->bus->shutdown && per_device->proc_entry)
> >> {
> >> + snd_device_free(per_device->pin->codec->card,
> >> per_device->proc_entry);
> >> + per_device->proc_entry = NULL;
> >> }
> >> }
> >> #else
> >> -static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin,
> >> - int index)
> >> +static inline int eld_device_proc_new(struct hdmi_spec_per_device
> >> *per_device,
> >> + int pin_idx, int dev_idx)
> >> {
> >> return 0;
> >> }
> >> -static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
> >> +static inline void eld_device_proc_free(struct hdmi_spec_per_device
> >> +*per_device)
> >> {
> >> }
> >> #endif
> >> @@ -1112,13 +1127,13 @@ static void hdmi_pin_setup_infoframe(struct
> >> hda_codec *codec,
> >>
> >> static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
> >> struct hdmi_spec_per_pin *per_pin,
> >> + struct hdmi_eld *eld,
> >> bool non_pcm)
> >> {
> >> struct hdmi_spec *spec = codec->spec;
> >> hda_nid_t pin_nid = per_pin->pin_nid;
> >> int channels = per_pin->channels;
> >> int active_channels;
> >> - struct hdmi_eld *eld;
> >> int ca, ordered_ca;
> >>
> >> if (!channels)
> >> @@ -1129,7 +1144,8 @@ static void hdmi_setup_audio_infoframe(struct
> >> hda_codec *codec,
> >> AC_VERB_SET_AMP_GAIN_MUTE,
> >> AMP_OUT_UNMUTE);
> >>
> >> - eld = &per_pin->sink_eld;
> >> + if (!eld)
> >> + eld = &per_pin->devices[0].sink_eld;
> >>
> >> if (!non_pcm && per_pin->chmap_set)
> >> ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
> >> @@ -1191,7 +1207,7 @@ static void hdmi_intrinsic_event(struct hda_codec
> >> *codec, unsigned int res)
> >> return;
> >> jack->jack_dirty = 1;
> >>
> >> - codec_dbg(codec,
> >> + codec_info(codec,
> >> "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d
> >> Presence_Detect=%d ELD_Valid=%d\n",
> >> codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
> >> !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); @@
> >> -1449,7 +1465,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream
> >> *hinfo,
> >> if (snd_BUG_ON(pin_idx < 0))
> >> return -EINVAL;
> >> per_pin = get_pin(spec, pin_idx);
> >> - eld = &per_pin->sink_eld;
> >> + eld = &per_pin->devices[0].sink_eld;
> >>
> >> err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx);
> >> if (err < 0)
> >> @@ -1530,7 +1546,7 @@ static bool hdmi_present_sense(struct
> >> hdmi_spec_per_pin *per_pin, int repoll)
> >> struct hda_codec *codec = per_pin->codec;
> >> struct hdmi_spec *spec = codec->spec;
> >> struct hdmi_eld *eld = &spec->temp_eld;
> >> - struct hdmi_eld *pin_eld = &per_pin->sink_eld;
> >> + struct hdmi_eld *pin_eld;
> >> hda_nid_t pin_nid = per_pin->pin_nid;
> >> /*
> >> * Always execute a GetPinSense verb here, even when called from @@
> >> -1544,20 +1560,41 @@ static bool hdmi_present_sense(struct
> >> hdmi_spec_per_pin *per_pin, int repoll)
> >> bool update_eld = false;
> >> bool eld_changed = false;
> >> bool ret;
> >> + int device_num = 0;
> >> + bool need_repoll = false;
> >> + bool any_eld_valid = false;
> >>
> >> snd_hda_power_up_pm(codec);
> >> present = snd_hda_pin_sense(codec, pin_nid);
> >>
> >> mutex_lock(&per_pin->lock);
> >> - pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
> >> - if (pin_eld->monitor_present)
> >> - eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
> >> - else
> >> - eld->eld_valid = false;
> >>
> >> - codec_dbg(codec,
> >> - "HDMI status: Codec=%d Pin=%d Presence_Detect=%d
> >> ELD_Valid=%d\n",
> >> - codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid);
> >> + if (codec->dp_mst)
> >> + per_pin->num_devices = snd_hda_get_devices(codec, pin_nid,
> >> per_pin->dev_list,
> >> + AC_MAX_DEV_LIST_LEN);
> >> +next_device:
> >> + pin_eld = &per_pin->devices[device_num].sink_eld;
> >> + eld_changed = false;
> >> + update_eld = false;
> >> + if (per_pin->num_devices) {
> >> + pin_eld->monitor_present = !!(per_pin->dev_list[device_num] &
> >> AC_DE_PD);
> >> + if (pin_eld->monitor_present)
> >> + eld->eld_valid = !!(per_pin->dev_list[device_num] &
> >> AC_DE_ELDV);
> >> + else
> >> + eld->eld_valid = false;
> >> + if (eld->eld_valid)
> >> + snd_hda_codec_write(codec, pin_nid, 0,
> >> AC_VERB_SET_DEVICE_SEL, device_num);
> >> + } else {
> >> + pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
> >> + if (pin_eld->monitor_present)
> >> + eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
> >> + else
> >> + eld->eld_valid = false;
> >> + }
> >> +
> >> + codec_info(codec,
> >> + "HDMI status: Codec=%d Pin=%d Device=%d Presence_Detect=%d
> >> ELD_Valid=%d\n",
> >> + codec->addr, pin_nid, device_num, pin_eld->monitor_present,
> >> +eld->eld_valid);
> >>
> >> if (eld->eld_valid) {
> >> if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer, @@
> >> -1573,11 +1610,11 @@ static bool hdmi_present_sense(struct
> >> hdmi_spec_per_pin *per_pin, int repoll)
> >> if (eld->eld_valid) {
> >> snd_hdmi_show_eld(codec, &eld->info);
> >> update_eld = true;
> >> + any_eld_valid = true;
> >> }
> >> else if (repoll) {
> >> - schedule_delayed_work(&per_pin->work,
> >> - msecs_to_jiffies(300));
> >> - goto unlock;
> >> + need_repoll = true;
> >> + goto skip_to_next_device;
> >> }
> >> }
> >>
> >> @@ -1614,7 +1651,7 @@ static bool hdmi_present_sense(struct
> >> hdmi_spec_per_pin *per_pin, int repoll)
> >> per_pin->mux_idx);
> >> }
> >>
> >> - hdmi_setup_audio_infoframe(codec, per_pin,
> >> + hdmi_setup_audio_infoframe(codec, per_pin, eld,
> >> per_pin->non_pcm);
> >> }
> >> }
> >> @@ -1623,8 +1660,19 @@ static bool hdmi_present_sense(struct
> >> hdmi_spec_per_pin *per_pin, int repoll)
> >> snd_ctl_notify(codec->card,
> >> SNDRV_CTL_EVENT_MASK_VALUE |
> >> SNDRV_CTL_EVENT_MASK_INFO,
> >> &per_pin->eld_ctl->id);
> >> - unlock:
> >> - ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid;
> >> +skip_to_next_device:
> >> + if (codec->dp_mst) {
> >> + device_num++;
> >> + if (device_num < per_pin->num_devices)
> >> + goto next_device;
> >> + }
> >> +
> >> + if (need_repoll) {
> >> + schedule_delayed_work(&per_pin->work,
> >> + msecs_to_jiffies(300));
> >> + repoll = true;
> >> + }
> >> + ret = !repoll || any_eld_valid;
> >>
> >> jack = snd_hda_jack_tbl_get(codec, pin_nid);
> >> if (jack)
> >> @@ -1807,7 +1855,7 @@ static int
> >> generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
> >> per_pin->channels = substream->runtime->channels;
> >> per_pin->setup = true;
> >>
> >> - hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
> >> + hdmi_setup_audio_infoframe(codec, per_pin, NULL, non_pcm);
> >> mutex_unlock(&per_pin->lock);
> >>
> >> if (spec->dyn_pin_out) {
> >> @@ -2035,7 +2083,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol
> >> *kcontrol,
> >> per_pin->chmap_set = true;
> >> memcpy(per_pin->chmap, chmap, sizeof(chmap));
> >> if (prepared)
> >> - hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
> >> + hdmi_setup_audio_infoframe(codec, per_pin, NULL,
> >> per_pin->non_pcm);
> >> mutex_unlock(&per_pin->lock);
> >>
> >> return 0;
> >> @@ -2147,7 +2195,7 @@ static int generic_hdmi_build_controls(struct
> >> hda_codec *codec) static int generic_hdmi_init_per_pins(struct hda_codec
> >> *codec) {
> >> struct hdmi_spec *spec = codec->spec;
> >> - int pin_idx;
> >> + int pin_idx, dev_idx;
> >>
> >> for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
> >> struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); @@
> >> -2155,7 +2203,20 @@ static int generic_hdmi_init_per_pins(struct hda_codec
> >> *codec)
> >> per_pin->codec = codec;
> >> mutex_init(&per_pin->lock);
> >> INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
> >> - eld_proc_new(per_pin, pin_idx);
> >> +
> >> + if (codec->dp_mst) {
> >> + for (dev_idx = 0; dev_idx < HDA_MAX_DEVICES; dev_idx++) {
> >> + per_pin->devices[dev_idx].device_idx = dev_idx;
> >> + per_pin->devices[dev_idx].pin = per_pin;
> >> +
> >> + eld_device_proc_new(&per_pin->devices[dev_idx], pin_idx,
> >> dev_idx);
> >> + }
> >> + } else {
> >> + per_pin->num_devices = 0;
> >> + per_pin->devices[0].device_idx = 0;
> >> + per_pin->devices[0].pin = per_pin;
> >> + eld_device_proc_new(&per_pin->devices[0], pin_idx, -1);
> >> + }
> >> }
> >> return 0;
> >> }
> >> @@ -2191,13 +2252,19 @@ static void hdmi_array_free(struct hdmi_spec
> >> *spec) static void generic_hdmi_free(struct hda_codec *codec) {
> >> struct hdmi_spec *spec = codec->spec;
> >> - int pin_idx;
> >> + int pin_idx, dev_idx;
> >>
> >> for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
> >> struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
> >>
> >> cancel_delayed_work_sync(&per_pin->work);
> >> - eld_proc_free(per_pin);
> >> + if (per_pin->num_devices) {
> >> + for (dev_idx = 0; dev_idx < per_pin->num_devices; dev_idx++) {
> >> + struct hdmi_spec_per_device *per_device =
> >> &per_pin->devices[dev_idx];
> >> + eld_device_proc_free(per_device);
> >> + }
> >> + } else
> >> + eld_device_proc_free(&per_pin->devices[0]);
> >> }
> >>
> >> hdmi_array_free(spec);
> >> @@ -2333,6 +2400,7 @@ static int patch_generic_hdmi(struct hda_codec
> >> *codec)
> >> if (is_haswell_plus(codec)) {
> >> intel_haswell_enable_all_pins(codec, true);
> >> intel_haswell_fixup_enable_dp12(codec);
> >> + codec->dp_mst = true;
> >> }
> >>
> >> if (is_haswell_plus(codec) || is_valleyview_plus(codec)) @@ -2346,7
> >> +2414,6 @@ static int patch_generic_hdmi(struct hda_codec *codec)
> >> codec->patch_ops = generic_hdmi_patch_ops;
> >> if (is_haswell_plus(codec)) {
> >> codec->patch_ops.set_power_state = haswell_set_power_state;
> >> - codec->dp_mst = true;
> >> }
> >>
> >> generic_hdmi_init_per_pins(codec);
> >> --
> >> 2.4.1
> >>
> >> _______________________________________________
> >> Intel-gfx mailing list
> >> Intel-gfx@lists.freedesktop.org
> >> http://lists.freedesktop.org/mailman/listinfo/intel-gfx