From patchwork Wed Jun 17 04:01:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Airlie X-Patchwork-Id: 6621751 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 1AC0EC0020 for ; Wed, 17 Jun 2015 04:02:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A5DD420802 for ; Wed, 17 Jun 2015 04:02:16 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2B6A7207E8 for ; Wed, 17 Jun 2015 04:02:15 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id ABAA97A0F9; Tue, 16 Jun 2015 21:02:14 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by gabe.freedesktop.org (Postfix) with ESMTP id 61D2E7A013 for ; Tue, 16 Jun 2015 21:02:13 -0700 (PDT) Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 3536436507A for ; Wed, 17 Jun 2015 04:02:13 +0000 (UTC) Received: from dreadlord-bne-redhat-com.bne.redhat.com (dhcp-40-179.bne.redhat.com [10.64.40.179]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t5H421Jo010302 for ; Wed, 17 Jun 2015 00:02:11 -0400 From: Dave Airlie To: intel-gfx@lists.freedesktop.org Date: Wed, 17 Jun 2015 14:01:58 +1000 Message-Id: <1434513719-3580-4-git-send-email-airlied@gmail.com> In-Reply-To: <1434513719-3580-1-git-send-email-airlied@gmail.com> References: <1434513719-3580-1-git-send-email-airlied@gmail.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 Subject: [Intel-gfx] [PATCH 3/4] snd: add support for displayport multi-stream to hda codec. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, FREEMAIL_FROM,RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Dave Airlie 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 --- 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);