From: Dave Airlie <airlied@gmail.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH 3/4] snd: add support for displayport multi-stream to hda codec.
Date: Wed, 17 Jun 2015 14:01:58 +1000 [thread overview]
Message-ID: <1434513719-3580-4-git-send-email-airlied@gmail.com> (raw)
In-Reply-To: <1434513719-3580-1-git-send-email-airlied@gmail.com>
From: Dave Airlie <airlied@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 <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
next prev parent reply other threads:[~2015-06-17 4:02 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-17 4:01 haswell displayport MST audio support Dave Airlie
2015-06-17 4:01 ` [PATCH 1/4] dp/mst: add SDP stream support Dave Airlie
2015-06-17 4:01 ` [PATCH 2/4] i915: add support for GPU side of MST audio Dave Airlie
2015-06-17 8:07 ` Chris Wilson
2015-06-17 11:54 ` Jani Nikula
2015-06-17 11:56 ` Jani Nikula
2015-06-19 6:27 ` Lin, Mengdong
2015-06-17 11:27 ` Daniel Vetter
2015-06-17 4:01 ` Dave Airlie [this message]
2015-06-19 9:54 ` [PATCH 3/4] snd: add support for displayport multi-stream to hda codec Lin, Mengdong
2015-06-19 10:33 ` Dave Airlie
2015-06-19 11:15 ` Takashi Iwai
2015-06-22 12:54 ` Daniel Vetter
2015-06-22 13:23 ` Takashi Iwai
2015-06-22 13:29 ` Liam Girdwood
2015-06-22 15:21 ` Kaskinen, Tanu
2015-06-22 15:44 ` Takashi Iwai
2015-06-23 7:51 ` [Intel-gfx] " Kaskinen, Tanu
2015-06-23 8:06 ` Takashi Iwai
2015-06-24 12:41 ` [Intel-gfx] " Kaskinen, Tanu
2015-06-24 13:06 ` [alsa-devel] " Liam Girdwood
2015-06-24 20:47 ` Kaskinen, Tanu
2015-06-25 9:44 ` [alsa-devel] " Liam Girdwood
2015-06-26 10:14 ` [alsa-devel] [Intel-gfx] " Kaskinen, Tanu
2015-06-26 10:50 ` Kaskinen, Tanu
2015-06-26 18:45 ` Liam Girdwood
2015-06-26 16:27 ` [Intel-gfx] " Kaskinen, Tanu
2015-06-27 6:09 ` [alsa-devel] " Raymond Yau
2015-06-29 8:00 ` Jani Nikula
2015-07-03 3:45 ` Raymond Yau
2015-07-03 8:54 ` Jani Nikula
2015-06-25 8:22 ` Raymond Yau
2015-06-25 12:52 ` David Weinehall
2015-06-17 4:01 ` [PATCH 4/4] snd/hdmi: hack out haswell codec workaround Dave Airlie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1434513719-3580-4-git-send-email-airlied@gmail.com \
--to=airlied@gmail.com \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.