From 1f93a7dfd1f8d5ff7a5c53246c7534fe2332d6f4 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:46:07 +0000 Subject: [PATCH] add audio --- kernel/sound/pci/hda/patch_hdmi.c | 1197 +++++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 826 insertions(+), 371 deletions(-) diff --git a/kernel/sound/pci/hda/patch_hdmi.c b/kernel/sound/pci/hda/patch_hdmi.c index d21a4eb..b1c57c6 100644 --- a/kernel/sound/pci/hda/patch_hdmi.c +++ b/kernel/sound/pci/hda/patch_hdmi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * * patch_hdmi.c - routines for HDMI/DisplayPort codecs @@ -13,24 +14,11 @@ * * Maintained by: * Wu Fengguang <wfg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <linux/init.h> #include <linux/delay.h> +#include <linux/pci.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/pm_runtime.h> @@ -41,29 +29,23 @@ #include <sound/hdaudio.h> #include <sound/hda_i915.h> #include <sound/hda_chmap.h> -#include "hda_codec.h" +#include <sound/hda_codec.h> #include "hda_local.h" #include "hda_jack.h" +#include "hda_controller.h" static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); -#define is_haswell(codec) ((codec)->core.vendor_id == 0x80862807) -#define is_broadwell(codec) ((codec)->core.vendor_id == 0x80862808) -#define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809) -#define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a) -#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b) -#define is_geminilake(codec) (((codec)->core.vendor_id == 0x8086280d) || \ - ((codec)->core.vendor_id == 0x80862800)) -#define is_cannonlake(codec) ((codec)->core.vendor_id == 0x8086280c) -#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \ - || is_skylake(codec) || is_broxton(codec) \ - || is_kabylake(codec)) || is_geminilake(codec) \ - || is_cannonlake(codec) -#define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882) -#define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883) -#define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec)) +static bool enable_acomp = true; +module_param(enable_acomp, bool, 0444); +MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)"); + +static bool enable_silent_stream = +IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM); +module_param(enable_silent_stream, bool, 0644); +MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices"); struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; @@ -96,6 +78,7 @@ int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */ int repoll_count; bool setup; /* the stream has been set up by prepare callback */ + bool silent_stream; int channels; /* current number of channels */ bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ @@ -108,16 +91,19 @@ /* operations used by generic code that can be overridden by patches */ struct hdmi_ops { int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, - unsigned char *buf, int *eld_size); + int dev_id, unsigned char *buf, int *eld_size); void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, int ca, int active_channels, int conn_type); /* enable/disable HBR (HD passthrough) */ - int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, bool hbr); + int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, + int dev_id, bool hbr); int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format); + hda_nid_t pin_nid, int dev_id, u32 stream_tag, + int format); void (*pin_cvt_fixup)(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, @@ -131,6 +117,7 @@ }; struct hdmi_spec { + struct hda_codec *codec; int num_cvts; struct snd_array cvts; /* struct hdmi_spec_per_cvt */ hda_nid_t cvt_nids[4]; /* only for haswell fix */ @@ -155,6 +142,7 @@ struct snd_array pins; /* struct hdmi_spec_per_pin */ struct hdmi_pcm pcm_rec[16]; struct mutex pcm_lock; + struct mutex bind_lock; /* for audio component binding */ /* pcm_bitmap means which pcms have been assigned to pins*/ unsigned long pcm_bitmap; int pcm_used; /* counter of pcm_rec[] */ @@ -169,18 +157,27 @@ bool dyn_pin_out; bool dyn_pcm_assign; + bool dyn_pcm_no_legacy; + bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */ + + bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ /* * Non-generic VIA/NVIDIA specific */ struct hda_multi_out multiout; struct hda_pcm_stream pcm_playback; - /* i915/powerwell (Haswell+/Valleyview+) specific */ - bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */ + bool use_acomp_notifier; /* use eld_notify callback for hotplug */ + bool acomp_registered; /* audio component registered in this driver */ + bool force_connect; /* force connectivity */ struct drm_audio_component_audio_ops drm_audio_ops; + int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */ struct hdac_chmap chmap; hda_nid_t vendor_nid; + const int *port_map; + int port_num; + bool send_silent_stream; /* Flag to enable silent stream feature */ }; #ifdef CONFIG_SND_HDA_COMPONENT @@ -273,7 +270,7 @@ if (get_pcm_rec(spec, pcm_idx)->stream == hinfo) return pcm_idx; - codec_warn(codec, "HDMI: hinfo %p not registered\n", hinfo); + codec_warn(codec, "HDMI: hinfo %p not tied to a PCM\n", hinfo); return -EINVAL; } @@ -291,7 +288,8 @@ return pin_idx; } - codec_dbg(codec, "HDMI: hinfo %p not registered\n", hinfo); + codec_dbg(codec, "HDMI: hinfo %p (pcm %d) not registered\n", hinfo, + hinfo_to_pcm_index(codec, hinfo)); return -EINVAL; } @@ -389,7 +387,8 @@ } static const struct snd_kcontrol_new eld_bytes_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE | + SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "ELD", .info = hdmi_eld_ctl_info, @@ -657,20 +656,37 @@ return true; } +static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, + int dev_id, unsigned char *buf, int *eld_size) +{ + snd_hda_set_dev_select(codec, nid, dev_id); + + return snd_hdmi_get_eld(codec, nid, buf, eld_size); +} + static void hdmi_pin_setup_infoframe(struct hda_codec *codec, - hda_nid_t pin_nid, + hda_nid_t pin_nid, int dev_id, int ca, int active_channels, int conn_type) { + struct hdmi_spec *spec = codec->spec; union audio_infoframe ai; memset(&ai, 0, sizeof(ai)); - if (conn_type == 0) { /* HDMI */ + if ((conn_type == 0) || /* HDMI */ + /* Nvidia DisplayPort: Nvidia HW expects same layout as HDMI */ + (conn_type == 1 && spec->nv_dp_workaround)) { struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; - hdmi_ai->type = 0x84; - hdmi_ai->ver = 0x01; - hdmi_ai->len = 0x0a; + if (conn_type == 0) { /* HDMI */ + hdmi_ai->type = 0x84; + hdmi_ai->ver = 0x01; + hdmi_ai->len = 0x0a; + } else {/* Nvidia DP */ + hdmi_ai->type = 0x84; + hdmi_ai->ver = 0x1b; + hdmi_ai->len = 0x11 << 2; + } hdmi_ai->CC02_CT47 = active_channels - 1; hdmi_ai->CA = ca; hdmi_checksum_audio_infoframe(hdmi_ai); @@ -687,6 +703,8 @@ pin_nid); return; } + + snd_hda_set_dev_select(codec, pin_nid, dev_id); /* * sizeof(ai) is used instead of sizeof(*hdmi_ai) or @@ -713,6 +731,7 @@ struct hdmi_spec *spec = codec->spec; struct hdac_chmap *chmap = &spec->chmap; hda_nid_t pin_nid = per_pin->pin_nid; + int dev_id = per_pin->dev_id; int channels = per_pin->channels; int active_channels; struct hdmi_eld *eld; @@ -720,6 +739,8 @@ if (!channels) return; + + snd_hda_set_dev_select(codec, pin_nid, dev_id); /* some HW (e.g. HSW+) needs reprogramming the amp at each time */ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) @@ -746,8 +767,8 @@ pin_nid, non_pcm, ca, channels, per_pin->chmap, per_pin->chmap_set); - spec->ops.pin_setup_infoframe(codec, pin_nid, ca, active_channels, - eld->info.conn_type); + spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id, + ca, active_channels, eld->info.conn_type); per_pin->non_pcm = non_pcm; } @@ -756,7 +777,7 @@ * Unsolicited events */ -static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); +static void 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, int dev_id) @@ -767,42 +788,31 @@ if (pin_idx < 0) return; mutex_lock(&spec->pcm_lock); - if (hdmi_present_sense(get_pin(spec, pin_idx), 1)) - snd_hda_jack_report_sync(codec); + hdmi_present_sense(get_pin(spec, pin_idx), 1); mutex_unlock(&spec->pcm_lock); } static void jack_callback(struct hda_codec *codec, struct hda_jack_callback *jack) { - /* hda_jack don't support DP MST */ - check_presence_and_report(codec, jack->nid, 0); + /* stop polling when notification is enabled */ + if (codec_has_acomp(codec)) + return; + + check_presence_and_report(codec, jack->nid, jack->dev_id); } -static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) +static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res, + struct hda_jack_tbl *jack) { - int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - struct hda_jack_tbl *jack; - 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); - if (!jack) - return; jack->jack_dirty = 1; codec_dbg(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), + codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA), !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); - /* hda_jack don't support DP MST */ - check_presence_and_report(codec, jack->nid, 0); + check_presence_and_report(codec, jack->nid, jack->dev_id); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -821,10 +831,12 @@ cp_ready); /* TODO */ - if (cp_state) + if (cp_state) { ; - if (cp_ready) + } + if (cp_ready) { ; + } } @@ -832,14 +844,27 @@ { int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + struct hda_jack_tbl *jack; - if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) { + if (codec_has_acomp(codec)) + return; + + if (codec->dp_mst) { + int dev_entry = + (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; + + jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); + } else { + jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); + } + + if (!jack) { codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag); return; } if (subtag == 0) - hdmi_intrinsic_event(codec, res); + hdmi_intrinsic_event(codec, res, jack); else hdmi_non_intrinsic_event(codec, res); } @@ -874,11 +899,12 @@ ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7) static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, - bool hbr) + int dev_id, bool hbr) { int pinctl, new_pinctl; if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) { + snd_hda_set_dev_select(codec, pin_nid, dev_id); pinctl = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); @@ -908,20 +934,22 @@ } static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) + hda_nid_t pin_nid, int dev_id, + u32 stream_tag, int format) { struct hdmi_spec *spec = codec->spec; unsigned int param; int err; - err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format)); + err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id, + is_hbr_format(format)); if (err) { codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n"); return err; } - if (is_haswell_plus(codec)) { + if (spec->intel_hsw_fixup) { /* * on recent platforms IEC Coding Type is required for HBR @@ -963,6 +991,13 @@ per_pin = NULL; else per_pin = get_pin(spec, pin_idx); + + if (per_pin && per_pin->silent_stream) { + cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid); + if (cvt_id) + *cvt_id = cvt_idx; + return 0; + } /* Dynamically assign converter to stream */ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { @@ -1234,7 +1269,12 @@ set_bit(pcm_idx, &spec->pcm_in_use); per_pin = get_pin(spec, pin_idx); per_pin->cvt_nid = per_cvt->cvt_nid; + per_pin->silent_stream = false; hinfo->nid = per_cvt->cvt_nid; + + /* flip stripe flag for the assigned stream if supported */ + if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE) + azx_stream(get_azx_dev(substream))->stripe = 1; 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, @@ -1288,6 +1328,8 @@ struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; + int dev_id = per_pin->dev_id; + int conns; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { codec_warn(codec, @@ -1296,31 +1338,67 @@ return -EINVAL; } + snd_hda_set_dev_select(codec, pin_nid, dev_id); + + if (spec->intel_hsw_fixup) { + conns = spec->num_cvts; + memcpy(per_pin->mux_nids, spec->cvt_nids, + sizeof(hda_nid_t) * conns); + } else { + conns = snd_hda_get_raw_connections(codec, pin_nid, + per_pin->mux_nids, + HDA_MAX_CONNECTIONS); + } + /* 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->mux_nids, - HDA_MAX_CONNECTIONS); + per_pin->num_mux_nids = conns; return 0; } static int hdmi_find_pcm_slot(struct hdmi_spec *spec, - struct hdmi_spec_per_pin *per_pin) + struct hdmi_spec_per_pin *per_pin) { int i; - /* try the prefer PCM */ - if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) - return per_pin->pin_nid_idx; + /* on the new machines, try to assign the pcm slot dynamically, + * not use the preferred fixed map (legacy way) anymore. + */ + if (spec->dyn_pcm_no_legacy) + goto last_try; - /* have a second try; check the "reserved area" over num_pins */ + /* + * generic_hdmi_build_pcms() may allocate extra PCMs on some + * platforms (with maximum of 'num_nids + dev_num - 1') + * + * The per_pin of pin_nid_idx=n and dev_id=m prefers to get pcm-n + * if m==0. This guarantees that dynamic pcm assignments are compatible + * with the legacy static per_pin-pcm assignment that existed in the + * days before DP-MST. + * + * Intel DP-MST prefers this legacy behavior for compatibility, too. + * + * per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)). + */ + + if (per_pin->dev_id == 0 || spec->intel_hsw_fixup) { + if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) + return per_pin->pin_nid_idx; + } else { + i = spec->num_nids + (per_pin->dev_id - 1); + if (i < spec->pcm_used && !(test_bit(i, &spec->pcm_bitmap))) + return i; + } + + /* have a second try; check the area over num_nids */ for (i = spec->num_nids; i < spec->pcm_used; i++) { if (!test_bit(i, &spec->pcm_bitmap)) return i; } + last_try: /* the last try; check the empty slots in pins */ - for (i = 0; i < spec->num_nids; i++) { + for (i = 0; i < spec->pcm_used; i++) { if (!test_bit(i, &spec->pcm_bitmap)) return i; } @@ -1428,21 +1506,60 @@ per_pin->channels = 0; } +static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + struct hdmi_spec *spec = codec->spec; + + if (per_pin->pcm_idx >= 0) + return spec->pcm_rec[per_pin->pcm_idx].jack; + else + return NULL; +} + /* update per_pin ELD from the given new ELD; * setup info frame and notification accordingly + * also notify ELD kctl and report jack status changes */ static void update_eld(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, - struct hdmi_eld *eld) + struct hdmi_eld *eld, + int repoll) { struct hdmi_eld *pin_eld = &per_pin->sink_eld; struct hdmi_spec *spec = codec->spec; + struct snd_jack *pcm_jack; bool old_eld_valid = pin_eld->eld_valid; bool eld_changed; - int pcm_idx = -1; + int pcm_idx; + + if (eld->eld_valid) { + if (eld->eld_size <= 0 || + snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, + eld->eld_size) < 0) { + eld->eld_valid = false; + if (repoll) { + schedule_delayed_work(&per_pin->work, + msecs_to_jiffies(300)); + return; + } + } + } + + if (!eld->eld_valid || eld->eld_size <= 0) { + eld->eld_valid = false; + eld->eld_size = 0; + } /* for monitor disconnection, save pcm_idx firstly */ pcm_idx = per_pin->pcm_idx; + + /* + * pcm_idx >=0 before update_eld() means it is in monitor + * disconnected event. Jack must be fetched before update_eld(). + */ + pcm_jack = pin_idx_to_pcm_jack(codec, per_pin); + if (spec->dyn_pcm_assign) { if (eld->eld_valid) { hdmi_attach_hda_pcm(spec, per_pin); @@ -1457,23 +1574,29 @@ */ if (pcm_idx == -1) pcm_idx = per_pin->pcm_idx; + if (!pcm_jack) + pcm_jack = pin_idx_to_pcm_jack(codec, per_pin); if (eld->eld_valid) snd_hdmi_show_eld(codec, &eld->info); eld_changed = (pin_eld->eld_valid != eld->eld_valid); - if (eld->eld_valid && pin_eld->eld_valid) + eld_changed |= (pin_eld->monitor_present != eld->monitor_present); + if (!eld_changed && eld->eld_valid && pin_eld->eld_valid) if (pin_eld->eld_size != eld->eld_size || memcmp(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size) != 0) eld_changed = true; - pin_eld->monitor_present = eld->monitor_present; - pin_eld->eld_valid = eld->eld_valid; - pin_eld->eld_size = eld->eld_size; - if (eld->eld_valid) - memcpy(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size); - pin_eld->info = eld->info; + if (eld_changed) { + pin_eld->monitor_present = eld->monitor_present; + pin_eld->eld_valid = eld->eld_valid; + pin_eld->eld_size = eld->eld_size; + if (eld->eld_valid) + memcpy(pin_eld->eld_buffer, eld->eld_buffer, + eld->eld_size); + pin_eld->info = eld->info; + } /* * Re-setup pin and infoframe. This is needed e.g. when @@ -1491,17 +1614,23 @@ SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id); + + if (eld_changed && pcm_jack) + snd_jack_report(pcm_jack, + (eld->monitor_present && eld->eld_valid) ? + SND_JACK_AVOUT : 0); } /* update ELD and jack state via HD-audio verbs */ -static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, +static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, int repoll) { - struct hda_jack_tbl *jack; struct hda_codec *codec = per_pin->codec; struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; + struct device *dev = hda_codec_dev(codec); hda_nid_t pin_nid = per_pin->pin_nid; + int dev_id = per_pin->dev_id; /* * Always execute a GetPinSense verb here, even when called from * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited @@ -1511,10 +1640,18 @@ * the unsolicited response to avoid custom WARs. */ int present; - bool ret; - bool do_repoll = false; + int ret; - present = snd_hda_pin_sense(codec, pin_nid); +#ifdef CONFIG_PM + if (dev->power.runtime_status == RPM_SUSPENDING) + return; +#endif + + ret = snd_hda_power_up_pm(codec); + if (ret < 0 && pm_runtime_suspended(dev)) + goto out; + + present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); mutex_lock(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); @@ -1528,61 +1665,104 @@ codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); if (eld->eld_valid) { - if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer, - &eld->eld_size) < 0) + if (spec->ops.pin_get_eld(codec, pin_nid, dev_id, + eld->eld_buffer, &eld->eld_size) < 0) eld->eld_valid = false; - else { - if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, - eld->eld_size) < 0) - eld->eld_valid = false; - } - if (!eld->eld_valid && repoll) - do_repoll = true; } - if (do_repoll) - schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300)); - else - update_eld(codec, per_pin, eld); - - ret = !repoll || !eld->monitor_present || eld->eld_valid; - - jack = snd_hda_jack_tbl_get(codec, pin_nid); - if (jack) { - jack->block_report = !ret; - jack->pin_sense = (eld->monitor_present && eld->eld_valid) ? - AC_PINSENSE_PRESENCE : 0; - } + update_eld(codec, per_pin, eld, repoll); mutex_unlock(&per_pin->lock); - return ret; + out: + snd_hda_power_down_pm(codec); } -static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec, +#define I915_SILENT_RATE 48000 +#define I915_SILENT_CHANNELS 2 +#define I915_SILENT_FORMAT SNDRV_PCM_FORMAT_S16_LE +#define I915_SILENT_FORMAT_BITS 16 +#define I915_SILENT_FMT_MASK 0xf + +static void silent_stream_enable(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin) { struct hdmi_spec *spec = codec->spec; - struct snd_jack *jack = NULL; - struct hda_jack_tbl *jack_tbl; + struct hdmi_spec_per_cvt *per_cvt; + int cvt_idx, pin_idx, err; + unsigned int format; - /* if !dyn_pcm_assign, get jack from hda_jack_tbl - * in !dyn_pcm_assign case, spec->pcm_rec[].jack is not - * NULL even after snd_hda_jack_tbl_clear() is called to - * free snd_jack. This may cause access invalid memory - * when calling snd_jack_report - */ - if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign) - jack = spec->pcm_rec[per_pin->pcm_idx].jack; - 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); - if (jack_tbl) - jack = jack_tbl->jack; + mutex_lock(&per_pin->lock); + + if (per_pin->setup) { + codec_dbg(codec, "hdmi: PCM already open, no silent stream\n"); + goto unlock_out; } - return jack; + + pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id); + err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx); + if (err) { + codec_err(codec, "hdmi: no free converter to enable silent mode\n"); + goto unlock_out; + } + + per_cvt = get_cvt(spec, cvt_idx); + per_cvt->assigned = 1; + per_pin->cvt_nid = per_cvt->cvt_nid; + per_pin->silent_stream = true; + + codec_dbg(codec, "hdmi: enabling silent stream pin-NID=0x%x cvt-NID=0x%x\n", + per_pin->pin_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, + AC_VERB_SET_CONNECT_SEL, + per_pin->mux_idx); + + /* configure unused pins to choose other converters */ + pin_cvt_fixup(codec, per_pin, 0); + + snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, + per_pin->dev_id, I915_SILENT_RATE); + + /* trigger silent stream generation in hw */ + format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS, + I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, + I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format); + usleep_range(100, 200); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format); + + per_pin->channels = I915_SILENT_CHANNELS; + hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + + unlock_out: + mutex_unlock(&per_pin->lock); +} + +static void silent_stream_disable(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt; + int cvt_idx; + + mutex_lock(&per_pin->lock); + if (!per_pin->silent_stream) + goto unlock_out; + + codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n", + per_pin->pin_nid, per_pin->cvt_nid); + + cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid); + if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) { + per_cvt = get_cvt(spec, cvt_idx); + per_cvt->assigned = 0; + } + + per_pin->cvt_nid = 0; + per_pin->silent_stream = false; + + unlock_out: + mutex_unlock(&per_pin->lock); } /* update ELD and jack state via audio component */ @@ -1591,69 +1771,53 @@ { struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; - struct snd_jack *jack = NULL; - int size; + bool monitor_prev, monitor_next; mutex_lock(&per_pin->lock); eld->monitor_present = false; - size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, + monitor_prev = per_pin->sink_eld.monitor_present; + eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, per_pin->dev_id, &eld->monitor_present, eld->eld_buffer, ELD_MAX_SIZE); - if (size > 0) { - size = min(size, ELD_MAX_SIZE); - if (snd_hdmi_parse_eld(codec, &eld->info, - eld->eld_buffer, size) < 0) - size = -EINVAL; - } - - if (size > 0) { - eld->eld_valid = true; - eld->eld_size = size; - } else { - eld->eld_valid = false; - eld->eld_size = 0; - } - - /* pcm_idx >=0 before update_eld() means it is in monitor - * disconnected event. Jack must be fetched before update_eld() - */ - jack = pin_idx_to_jack(codec, per_pin); - update_eld(codec, per_pin, eld); - if (jack == NULL) - jack = pin_idx_to_jack(codec, per_pin); - if (jack == NULL) - goto unlock; - snd_jack_report(jack, - eld->monitor_present ? SND_JACK_AVOUT : 0); - unlock: + eld->eld_valid = (eld->eld_size > 0); + update_eld(codec, per_pin, eld, 0); + monitor_next = per_pin->sink_eld.monitor_present; mutex_unlock(&per_pin->lock); -} -static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) -{ - struct hda_codec *codec = per_pin->codec; - int ret; + /* + * Power-up will call hdmi_present_sense, so the PM calls + * have to be done without mutex held. + */ - /* no temporary power up/down needed for component notifier */ - if (!codec_has_acomp(codec)) { - ret = snd_hda_power_up_pm(codec); - if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec))) { - snd_hda_power_down_pm(codec); - return false; + if (spec->send_silent_stream) { + int pm_ret; + + if (!monitor_prev && monitor_next) { + pm_ret = snd_hda_power_up_pm(codec); + if (pm_ret < 0) + codec_err(codec, + "Monitor plugged-in, Failed to power up codec ret=[%d]\n", + pm_ret); + silent_stream_enable(codec, per_pin); + } else if (monitor_prev && !monitor_next) { + silent_stream_disable(codec, per_pin); + pm_ret = snd_hda_power_down_pm(codec); + if (pm_ret < 0) + codec_err(codec, + "Monitor plugged-out, Failed to power down codec ret=[%d]\n", + pm_ret); } } +} - if (codec_has_acomp(codec)) { - sync_eld_via_acomp(codec, per_pin); - ret = false; /* don't call snd_hda_jack_report_sync() */ - } else { - ret = hdmi_present_sense_via_verbs(per_pin, repoll); - } +static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) +{ + struct hda_codec *codec = per_pin->codec; if (!codec_has_acomp(codec)) - snd_hda_power_down_pm(codec); - - return ret; + hdmi_present_sense_via_verbs(per_pin, repoll); + else + sync_eld_via_acomp(codec, per_pin); } static void hdmi_repoll_eld(struct work_struct *work) @@ -1664,7 +1828,8 @@ struct hdmi_spec *spec = codec->spec; struct hda_jack_tbl *jack; - jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid); + jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid, + per_pin->dev_id); if (jack) jack->jack_dirty = 1; @@ -1672,13 +1837,9 @@ per_pin->repoll_count = 0; mutex_lock(&spec->pcm_lock); - if (hdmi_present_sense(per_pin, per_pin->repoll_count)) - snd_hda_jack_report_sync(per_pin->codec); + hdmi_present_sense(per_pin, per_pin->repoll_count); mutex_unlock(&spec->pcm_lock); } - -static void intel_haswell_fixup_connect_list(struct hda_codec *codec, - hda_nid_t nid); static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { @@ -1698,14 +1859,15 @@ * all device entries on the same pin */ 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 && + !spec->force_connect) return 0; /* * To simplify the implementation, malloc all * the virtual pins in the initialization statically */ - if (is_haswell_plus(codec)) { + if (spec->intel_hsw_fixup) { /* * On Intel platforms, device entries number is * changed dynamically. If there is a DP MST @@ -1754,8 +1916,6 @@ 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; @@ -1802,35 +1962,59 @@ return 0; } +static const struct snd_pci_quirk force_connect_list[] = { + SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1), + SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1), + SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1), + {} +}; + static int hdmi_parse_codec(struct hda_codec *codec) { - hda_nid_t nid; + struct hdmi_spec *spec = codec->spec; + hda_nid_t start_nid; + unsigned int caps; int i, nodes; + const struct snd_pci_quirk *q; - nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &nid); - if (!nid || nodes < 0) { + nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid); + if (!start_nid || nodes < 0) { codec_warn(codec, "HDMI: failed to get afg sub nodes\n"); return -EINVAL; } - for (i = 0; i < nodes; i++, nid++) { - unsigned int caps; - unsigned int type; + q = snd_pci_quirk_lookup(codec->bus->pci, force_connect_list); + + if (q && q->value) + spec->force_connect = true; + + /* + * hdmi_add_pin() assumes total amount of converters to + * be known, so first discover all converters + */ + for (i = 0; i < nodes; i++) { + hda_nid_t nid = start_nid + i; caps = get_wcaps(codec, nid); - type = get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL)) continue; - switch (type) { - case AC_WID_AUD_OUT: + if (get_wcaps_type(caps) == AC_WID_AUD_OUT) hdmi_add_cvt(codec, nid); - break; - case AC_WID_PIN: + } + + /* discover audio pins */ + for (i = 0; i < nodes; i++) { + hda_nid_t nid = start_nid + i; + + caps = get_wcaps(codec, nid); + + if (!(caps & AC_WCAP_DIGITAL)) + continue; + + if (get_wcaps_type(caps) == AC_WID_PIN) hdmi_add_pin(codec, nid); - break; - } } return 0; @@ -1871,10 +2055,9 @@ struct hdmi_spec *spec = codec->spec; int pin_idx; struct hdmi_spec_per_pin *per_pin; - hda_nid_t pin_nid; struct snd_pcm_runtime *runtime = substream->runtime; bool non_pcm; - int pinctl; + int pinctl, stripe; int err = 0; mutex_lock(&spec->pcm_lock); @@ -1895,7 +2078,6 @@ goto unlock; } per_pin = get_pin(spec, pin_idx); - pin_nid = per_pin->pin_nid; /* Verify pin:cvt selections to avoid silent audio after S3. * After S3, the audio driver restores pin:cvt selections @@ -1910,27 +2092,37 @@ /* Call sync_audio_rate to set the N/CTS/M manually if necessary */ /* Todo: add DP1.2 MST audio support later */ if (codec_has_acomp(codec)) - snd_hdac_sync_audio_rate(&codec->core, pin_nid, per_pin->dev_id, - runtime->rate); + snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, + per_pin->dev_id, runtime->rate); non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); per_pin->channels = substream->runtime->channels; per_pin->setup = true; + if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) { + stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core, + substream); + snd_hda_codec_write(codec, cvt_nid, 0, + AC_VERB_SET_STRIPE_CONTROL, + stripe); + } + hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); mutex_unlock(&per_pin->lock); if (spec->dyn_pin_out) { - pinctl = snd_hda_codec_read(codec, pin_nid, 0, + snd_hda_set_dev_select(codec, per_pin->pin_nid, + per_pin->dev_id); + pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, pin_nid, 0, + snd_hda_codec_write(codec, per_pin->pin_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT); } /* snd_hda_set_dev_select() has been called before */ - err = spec->ops.setup_stream(codec, cvt_nid, pin_nid, - stream_tag, format); + err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid, + per_pin->dev_id, stream_tag, format); unlock: mutex_unlock(&spec->pcm_lock); return err; @@ -1968,9 +2160,10 @@ goto unlock; } per_cvt = get_cvt(spec, cvt_idx); - snd_BUG_ON(!per_cvt->assigned); per_cvt->assigned = 0; hinfo->nid = 0; + + azx_stream(get_azx_dev(substream))->stripe = 0; snd_hda_spdif_ctls_unassign(codec, pcm_idx); clear_bit(pcm_idx, &spec->pcm_in_use); @@ -1985,6 +2178,8 @@ per_pin = get_pin(spec, pin_idx); if (spec->dyn_pin_out) { + snd_hda_set_dev_select(codec, per_pin->pin_nid, + per_pin->dev_id); pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); snd_hda_codec_write(codec, per_pin->pin_nid, 0, @@ -2016,7 +2211,7 @@ static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) { - struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hda_codec *codec = hdac_to_hda_codec(hdac); struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); @@ -2029,7 +2224,7 @@ static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap) { - struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hda_codec *codec = hdac_to_hda_codec(hdac); struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); @@ -2043,7 +2238,7 @@ static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap, int prepared) { - struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hda_codec *codec = hdac_to_hda_codec(hdac); struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); @@ -2059,7 +2254,7 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) { - struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hda_codec *codec = hdac_to_hda_codec(hdac); struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); @@ -2069,15 +2264,26 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int idx; + int idx, pcm_num; /* * 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 DP MST mode without extra PCM, pcm number is same + * for DP MST mode with extra PCMs, 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++) { + + if (spec->dyn_pcm_no_legacy && codec->mst_no_extra_pcms) + pcm_num = spec->num_cvts; + else if (codec->mst_no_extra_pcms) + pcm_num = spec->num_nids; + else + pcm_num = spec->num_nids + spec->dev_num - 1; + + codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num); + + for (idx = 0; idx < pcm_num; idx++) { struct hda_pcm *info; struct hda_pcm_stream *pstr; @@ -2109,15 +2315,23 @@ pcm->jack = NULL; } -static int add_hdmi_jack_kctl(struct hda_codec *codec, - struct hdmi_spec *spec, - int pcm_idx, - const char *name) +static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx) { + char hdmi_str[32] = "HDMI/DP"; + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pcm_idx); struct snd_jack *jack; + int pcmdev = get_pcm_rec(spec, pcm_idx)->device; int err; - err = snd_jack_new(codec->card, name, SND_JACK_AVOUT, &jack, + if (pcmdev > 0) + sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); + if (!spec->dyn_pcm_assign && + !is_jack_detectable(codec, per_pin->pin_nid)) + strncat(hdmi_str, " Phantom", + sizeof(hdmi_str) - strlen(hdmi_str) - 1); + + err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack, true, false); if (err < 0) return err; @@ -2125,46 +2339,6 @@ spec->pcm_rec[pcm_idx].jack = jack; jack->private_data = &spec->pcm_rec[pcm_idx]; jack->private_free = free_hdmi_jack_priv; - return 0; -} - -static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx) -{ - char hdmi_str[32] = "HDMI/DP"; - struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin; - struct hda_jack_tbl *jack; - int pcmdev = get_pcm_rec(spec, pcm_idx)->device; - bool phantom_jack; - int ret; - - if (pcmdev > 0) - sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); - - if (spec->dyn_pcm_assign) - return add_hdmi_jack_kctl(codec, spec, pcm_idx, hdmi_str); - - /* for !dyn_pcm_assign, we still use hda_jack for compatibility */ - /* if !dyn_pcm_assign, it must be non-MST mode. - * This means pcms and pins are statically mapped. - * And pcm_idx is pin_idx. - */ - per_pin = get_pin(spec, pcm_idx); - phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid); - if (phantom_jack) - strncat(hdmi_str, " Phantom", - sizeof(hdmi_str) - strlen(hdmi_str) - 1); - ret = snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, - phantom_jack); - if (ret < 0) - return ret; - jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid); - if (jack == NULL) - return 0; - /* assign jack->jack to pcm_rec[].jack to - * align with dyn_pcm_assign mode - */ - spec->pcm_rec[pcm_idx].jack = jack->jack; return 0; } @@ -2257,6 +2431,7 @@ struct hdmi_spec *spec = codec->spec; int pin_idx; + mutex_lock(&spec->bind_lock); for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; @@ -2264,11 +2439,12 @@ snd_hda_set_dev_select(codec, pin_nid, dev_id); hdmi_init_pin(codec, pin_nid); - if (!codec_has_acomp(codec)) - snd_hda_jack_detect_enable_callback(codec, pin_nid, - codec->jackpoll_interval > 0 ? - jack_callback : NULL); + if (codec_has_acomp(codec)) + continue; + snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id, + jack_callback); } + mutex_unlock(&spec->bind_lock); return 0; } @@ -2301,10 +2477,12 @@ struct hdmi_spec *spec = codec->spec; int pin_idx, pcm_idx; - if (codec_has_acomp(codec)) { + if (spec->acomp_registered) { + snd_hdac_acomp_exit(&codec->bus->core); + } else if (codec_has_acomp(codec)) { snd_hdac_acomp_register_notifier(&codec->bus->core, NULL); - codec->relaxed_resume = 0; } + codec->relaxed_resume = 0; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); @@ -2344,7 +2522,7 @@ int pin_idx; codec->patch_ops.init(codec); - regcache_sync(codec->core.regmap); + snd_hda_regmap_sync(codec); for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); @@ -2367,7 +2545,7 @@ }; static const struct hdmi_ops generic_standard_hdmi_ops = { - .pin_get_eld = snd_hdmi_get_eld, + .pin_get_eld = hdmi_pin_get_eld, .pin_setup_infoframe = hdmi_pin_setup_infoframe, .pin_hbr_setup = hdmi_pin_hbr_setup, .setup_stream = hdmi_setup_stream, @@ -2382,15 +2560,17 @@ if (!spec) return -ENOMEM; + spec->codec = codec; spec->ops = generic_standard_hdmi_ops; spec->dev_num = 1; /* initialize to 1 */ mutex_init(&spec->pcm_lock); + mutex_init(&spec->bind_lock); snd_hdac_register_chmap_ops(&codec->core, &spec->chmap); spec->chmap.ops.get_chmap = hdmi_get_chmap; spec->chmap.ops.set_chmap = hdmi_set_chmap; spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached; - spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc, + spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc; codec->spec = spec; hdmi_array_init(spec, 4); @@ -2420,32 +2600,140 @@ } /* + * generic audio component binding + */ + +/* turn on / off the unsol event jack detection dynamically */ +static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid, + int dev_id, bool use_acomp) +{ + struct hda_jack_tbl *tbl; + + tbl = snd_hda_jack_tbl_get_mst(codec, nid, dev_id); + if (tbl) { + /* clear unsol even if component notifier is used, or re-enable + * if notifier is cleared + */ + unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, val); + } +} + +/* set up / clear component notifier dynamically */ +static void generic_acomp_notifier_set(struct drm_audio_component *acomp, + bool use_acomp) +{ + struct hdmi_spec *spec; + int i; + + spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops); + mutex_lock(&spec->bind_lock); + spec->use_acomp_notifier = use_acomp; + spec->codec->relaxed_resume = use_acomp; + spec->codec->bus->keep_power = 0; + /* reprogram each jack detection logic depending on the notifier */ + for (i = 0; i < spec->num_pins; i++) + reprogram_jack_detect(spec->codec, + get_pin(spec, i)->pin_nid, + get_pin(spec, i)->dev_id, + use_acomp); + mutex_unlock(&spec->bind_lock); +} + +/* enable / disable the notifier via master bind / unbind */ +static int generic_acomp_master_bind(struct device *dev, + struct drm_audio_component *acomp) +{ + generic_acomp_notifier_set(acomp, true); + return 0; +} + +static void generic_acomp_master_unbind(struct device *dev, + struct drm_audio_component *acomp) +{ + generic_acomp_notifier_set(acomp, false); +} + +/* check whether both HD-audio and DRM PCI devices belong to the same bus */ +static int match_bound_vga(struct device *dev, int subtype, void *data) +{ + struct hdac_bus *bus = data; + struct pci_dev *pci, *master; + + if (!dev_is_pci(dev) || !dev_is_pci(bus->dev)) + return 0; + master = to_pci_dev(bus->dev); + pci = to_pci_dev(dev); + return master->bus == pci->bus; +} + +/* audio component notifier for AMD/Nvidia HDMI codecs */ +static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) +{ + struct hda_codec *codec = audio_ptr; + struct hdmi_spec *spec = codec->spec; + hda_nid_t pin_nid = spec->port2pin(codec, port); + + if (!pin_nid) + return; + if (get_wcaps_type(get_wcaps(codec, pin_nid)) != AC_WID_PIN) + return; + /* skip notification during system suspend (but not in runtime PM); + * the state will be updated at resume + */ + if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) + return; + + check_presence_and_report(codec, pin_nid, dev_id); +} + +/* set up the private drm_audio_ops from the template */ +static void setup_drm_audio_ops(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops) +{ + struct hdmi_spec *spec = codec->spec; + + spec->drm_audio_ops.audio_ptr = codec; + /* intel_audio_codec_enable() or intel_audio_codec_disable() + * will call pin_eld_notify with using audio_ptr pointer + * We need make sure audio_ptr is really setup + */ + wmb(); + spec->drm_audio_ops.pin2port = ops->pin2port; + spec->drm_audio_ops.pin_eld_notify = ops->pin_eld_notify; + spec->drm_audio_ops.master_bind = ops->master_bind; + spec->drm_audio_ops.master_unbind = ops->master_unbind; +} + +/* initialize the generic HDMI audio component */ +static void generic_acomp_init(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops, + int (*port2pin)(struct hda_codec *, int)) +{ + struct hdmi_spec *spec = codec->spec; + + if (!enable_acomp) { + codec_info(codec, "audio component disabled by module option\n"); + return; + } + + spec->port2pin = port2pin; + setup_drm_audio_ops(codec, ops); + if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops, + match_bound_vga, 0)) { + spec->acomp_registered = true; + } +} + +/* * Intel codec parsers and helpers */ -static void intel_haswell_fixup_connect_list(struct hda_codec *codec, - hda_nid_t nid) -{ - struct hdmi_spec *spec = codec->spec; - hda_nid_t conns[4]; - int nconns; - - nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns)); - if (nconns == spec->num_cvts && - !memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t))) - return; - - /* override pins connection list */ - codec_dbg(codec, "hdmi: haswell: override pin connection 0x%x\n", nid); - snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids); -} - -#define INTEL_VENDOR_NID 0x08 -#define INTEL_GLK_VENDOR_NID 0x0B -#define INTEL_GET_VENDOR_VERB 0xf81 -#define INTEL_SET_VENDOR_VERB 0x781 -#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ -#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ +#define INTEL_GET_VENDOR_VERB 0xf81 +#define INTEL_SET_VENDOR_VERB 0x781 +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ static void intel_haswell_enable_all_pins(struct hda_codec *codec, bool update_tree) @@ -2525,11 +2813,44 @@ static int intel_pin2port(void *audio_ptr, int pin_nid) { - int base_nid = intel_base_nid(audio_ptr); + struct hda_codec *codec = audio_ptr; + struct hdmi_spec *spec = codec->spec; + int base_nid, i; - if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3)) - return -1; - return pin_nid - base_nid + 1; /* intel port is 1-based */ + if (!spec->port_num) { + base_nid = intel_base_nid(codec); + if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3)) + return -1; + return pin_nid - base_nid + 1; + } + + /* + * looking for the pin number in the mapping table and return + * the index which indicate the port number + */ + for (i = 0; i < spec->port_num; i++) { + if (pin_nid == spec->port_map[i]) + return i; + } + + codec_info(codec, "Can't find the HDMI/DP port for pin %d\n", pin_nid); + return -1; +} + +static int intel_port2pin(struct hda_codec *codec, int port) +{ + struct hdmi_spec *spec = codec->spec; + + if (!spec->port_num) { + /* we assume only from port-B to port-D */ + if (port < 1 || port > 3) + return 0; + return port + intel_base_nid(codec) - 1; + } + + if (port < 0 || port >= spec->port_num) + return 0; + return spec->port_map[port]; } static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) @@ -2538,24 +2859,23 @@ int pin_nid; int dev_id = pipe; - /* we assume only from port-B to port-D */ - if (port < 1 || port > 3) + pin_nid = intel_port2pin(codec, port); + if (!pin_nid) return; - - pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */ - /* skip notification during system suspend (but not in runtime PM); * the state will be updated at resume */ - if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) - return; - /* ditto during suspend/resume process itself */ - if (snd_hdac_is_in_pm(&codec->core)) + if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; snd_hdac_i915_set_bclk(&codec->bus->core); check_presence_and_report(codec, pin_nid, dev_id); } + +static const struct drm_audio_component_audio_ops intel_audio_ops = { + .pin2port = intel_pin2port, + .pin_eld_notify = intel_pin_eld_notify, +}; /* register i915 component pin_eld_notify callback */ static void register_i915_notifier(struct hda_codec *codec) @@ -2563,14 +2883,8 @@ struct hdmi_spec *spec = codec->spec; spec->use_acomp_notifier = true; - spec->drm_audio_ops.audio_ptr = codec; - /* intel_audio_codec_enable() or intel_audio_codec_disable() - * will call pin_eld_notify with using audio_ptr pointer - * We need make sure audio_ptr is really setup - */ - wmb(); - spec->drm_audio_ops.pin2port = intel_pin2port; - spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify; + spec->port2pin = intel_port2pin; + setup_drm_audio_ops(codec, &intel_audio_ops); snd_hdac_acomp_register_notifier(&codec->bus->core, &spec->drm_audio_ops); /* no need for forcible resume for jack check thanks to notifier */ @@ -2579,10 +2893,12 @@ /* setup_stream ops override for HSW+ */ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) + hda_nid_t pin_nid, int dev_id, u32 stream_tag, + int format) { haswell_verify_D0(codec, cvt_nid, pin_nid); - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); + return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, + stream_tag, format); } /* pin_cvt_fixup ops override for HSW+ and VLV+ */ @@ -2643,7 +2959,8 @@ } /* Intel Haswell and onwards; audio component with eld notifier */ -static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) +static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, + const int *port_map, int port_num) { struct hdmi_spec *spec; int err; @@ -2655,15 +2972,14 @@ codec->dp_mst = true; spec->dyn_pcm_assign = true; spec->vendor_nid = vendor_nid; + spec->port_map = port_map; + spec->port_num = port_num; + spec->intel_hsw_fixup = true; intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); - /* For Haswell/Broadwell, the controller is also in the power well and - * can cover the codec power request, and so need not set this flag. - */ - if (!is_haswell(codec) && !is_broadwell(codec)) - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; @@ -2672,17 +2988,54 @@ spec->ops.setup_stream = i915_hsw_setup_stream; spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; + /* + * Enable silent stream feature, if it is enabled via + * module param or Kconfig option + */ + if (enable_silent_stream) + spec->send_silent_stream = true; + return parse_intel_hdmi(codec); } static int patch_i915_hsw_hdmi(struct hda_codec *codec) { - return intel_hsw_common_init(codec, INTEL_VENDOR_NID); + return intel_hsw_common_init(codec, 0x08, NULL, 0); } static int patch_i915_glk_hdmi(struct hda_codec *codec) { - return intel_hsw_common_init(codec, INTEL_GLK_VENDOR_NID); + return intel_hsw_common_init(codec, 0x0b, NULL, 0); +} + +static int patch_i915_icl_hdmi(struct hda_codec *codec) +{ + /* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number. + */ + static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb}; + + return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); +} + +static int patch_i915_tgl_hdmi(struct hda_codec *codec) +{ + /* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number. + */ + static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; + int ret; + + ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); + if (!ret) { + struct hdmi_spec *spec = codec->spec; + + spec->dyn_pcm_no_legacy = true; + } + + return ret; } /* Intel Baytrail and Braswell; with eld notifier */ @@ -2699,7 +3052,7 @@ /* For Valleyview/Cherryview, only the display codec is in the display * power well and can use link_power ops to request/release the power. */ - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->depop_delay = 0; codec->auto_runtime_pm = 1; @@ -2790,7 +3143,7 @@ if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - snd_hda_jack_detect_enable(codec, pin); + snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id); return 0; } @@ -2969,6 +3322,7 @@ if (!spec) return -ENOMEM; + spec->codec = codec; codec->spec = spec; hdmi_array_init(spec, 1); @@ -3180,6 +3534,7 @@ spec->pcm_playback.rates = SUPPORTED_RATES; spec->pcm_playback.maxbps = SUPPORTED_MAXBPS; spec->pcm_playback.formats = SUPPORTED_FORMATS; + spec->nv_dp_workaround = true; return 0; } @@ -3273,7 +3628,62 @@ return 0; } +/* map from pin NID to port; port is 0-based */ +/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */ +static int nvhdmi_pin2port(void *audio_ptr, int pin_nid) +{ + return pin_nid - 4; +} + +/* reverse-map from port to pin NID: see above */ +static int nvhdmi_port2pin(struct hda_codec *codec, int port) +{ + return port + 4; +} + +static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = { + .pin2port = nvhdmi_pin2port, + .pin_eld_notify = generic_acomp_pin_eld_notify, + .master_bind = generic_acomp_master_bind, + .master_unbind = generic_acomp_master_unbind, +}; + static int patch_nvhdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + codec->dp_mst = true; + + spec = codec->spec; + spec->dyn_pcm_assign = true; + + err = hdmi_parse_codec(codec); + if (err < 0) { + generic_spec_free(codec); + return err; + } + + generic_hdmi_init_per_pins(codec); + + spec->dyn_pin_out = true; + + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + spec->nv_dp_workaround = true; + + codec->link_down_at_suspend = 1; + + generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin); + + return 0; +} + +static int patch_nvhdmi_legacy(struct hda_codec *codec) { struct hdmi_spec *spec; int err; @@ -3288,6 +3698,7 @@ spec->chmap.ops.chmap_cea_alloc_validate_get_type = nvhdmi_chmap_cea_alloc_validate_get_type; spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + spec->nv_dp_workaround = true; codec->link_down_at_suspend = 1; @@ -3455,11 +3866,13 @@ if (err) return err; + codec->depop_delay = 10; codec->patch_ops.build_pcms = tegra_hdmi_build_pcms; spec = codec->spec; spec->chmap.ops.chmap_cea_alloc_validate_get_type = nvhdmi_chmap_cea_alloc_validate_get_type; spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + spec->nv_dp_workaround = true; return 0; } @@ -3512,16 +3925,19 @@ #define ATI_HBR_ENABLE 0x10 static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) + int dev_id, unsigned char *buf, int *eld_size) { + WARN_ON(dev_id != 0); /* call hda_eld.c ATI/AMD-specific function */ return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size, is_amdhdmi_rev3_or_later(codec)); } -static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, hda_nid_t pin_nid, int ca, +static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, + hda_nid_t pin_nid, int dev_id, int ca, int active_channels, int conn_type) { + WARN_ON(dev_id != 0); snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca); } @@ -3593,7 +4009,7 @@ static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac, hda_nid_t pin_nid, int hdmi_slot, int stream_channel) { - struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hda_codec *codec = hdac_to_hda_codec(hdac); int verb; int ati_channel_setup = 0; @@ -3629,7 +4045,7 @@ static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac, hda_nid_t pin_nid, int asp_slot) { - struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hda_codec *codec = hdac_to_hda_codec(hdac); bool was_odd = false; int ati_asp_slot = asp_slot; int verb; @@ -3712,9 +4128,11 @@ } static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, - bool hbr) + int dev_id, bool hbr) { int hbr_ctl, hbr_ctl_new; + + WARN_ON(dev_id != 0); hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0); if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) { @@ -3741,9 +4159,9 @@ } static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) + hda_nid_t pin_nid, int dev_id, + u32 stream_tag, int format) { - if (is_amdhdmi_rev3_or_later(codec)) { int ramp_rate = 180; /* default as per AMD spec */ /* disable ramp-up/down for non-pcm as per AMD spec */ @@ -3753,7 +4171,8 @@ snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate); } - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); + return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, + stream_tag, format); } @@ -3779,9 +4198,30 @@ ATI_VERB_SET_MULTICHANNEL_MODE, ATI_MULTICHANNEL_MODE_SINGLE); } + codec->auto_runtime_pm = 1; return 0; } + +/* map from pin NID to port; port is 0-based */ +/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */ +static int atihdmi_pin2port(void *audio_ptr, int pin_nid) +{ + return pin_nid / 2 - 1; +} + +/* reverse-map from port to pin NID: see above */ +static int atihdmi_port2pin(struct hda_codec *codec, int port) +{ + return port * 2 + 3; +} + +static const struct drm_audio_component_audio_ops atihdmi_audio_ops = { + .pin2port = atihdmi_pin2port, + .pin_eld_notify = generic_acomp_pin_eld_notify, + .master_bind = generic_acomp_master_bind, + .master_unbind = generic_acomp_master_unbind, +}; static int patch_atihdmi(struct hda_codec *codec) { @@ -3831,6 +4271,8 @@ */ codec->link_down_at_suspend = 1; + generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin); + return 0; } @@ -3861,29 +4303,33 @@ HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x), -HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy), /* 17 is known to be absent */ -HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi), -HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy), +HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy), HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), @@ -3933,6 +4379,7 @@ HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi), @@ -3946,7 +4393,15 @@ HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), -HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi), +HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi), +HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), +HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), +HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), -- Gitblit v1.6.2