From: Dave Airlie <airl...@redhat.com>

Add new verbs GET_DP_STREAM_ID and SET_DP_STREAM_ID from Intel docs.
get stream id and print in proc
split ELD to be per device not per pin
handle pd/eldv per device not per pin
setup codec->dp_mst earlier.

Signed-off-by: Dave Airlie <airl...@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

Reply via email to