From patchwork Wed Aug 12 05:58:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343508 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJtd1Rdqz9sTb; Wed, 12 Aug 2020 15:59:20 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jn9-0001sZ-5O; Wed, 12 Aug 2020 05:59:15 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jn5-0001s9-Ci for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:11 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jn4-0006E9-Ey for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:11 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 1/9] ALSA: hda - Rename snd_hda_pin_sense to snd_hda_jack_pin_sense Date: Wed, 12 Aug 2020 13:58:14 +0800 Message-Id: <20200812055822.5853-2-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Nikhil Mahale BugLink: https://bugs.launchpad.net/bugs/1867704 s/snd_hda_pin_sense/snd_hda_jack_pin_sense/g This aligns the snd_hda_pin_sense function name with the names of other functions in hda_jack.h. Signed-off-by: Nikhil Mahale Reviewed-by: Aaron Plattner Link: https://lore.kernel.org/r/20191119084710.29267-2-nmahale@nvidia.com Signed-off-by: Takashi Iwai (cherry picked from commit 80b917a8dd8f62ca00178d5a74d05d7471f21b47) Signed-off-by: Hui Wang --- sound/pci/hda/hda_jack.c | 8 ++++---- sound/pci/hda/hda_jack.h | 2 +- sound/pci/hda/patch_hdmi.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 1fb7b06457ae..1ea42447278f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -191,14 +191,14 @@ void snd_hda_jack_set_dirty_all(struct hda_codec *codec) EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); /** - * snd_hda_pin_sense - execute pin sense measurement + * snd_hda_jack_pin_sense - execute pin sense measurement * @codec: the CODEC to sense * @nid: the pin NID to sense * * Execute necessary pin sense measurement and return its Presence Detect, * Impedance, ELD Valid etc. status bits. */ -u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid) { struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); if (jack) { @@ -207,7 +207,7 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) } return read_pin_sense(codec, nid); } -EXPORT_SYMBOL_GPL(snd_hda_pin_sense); +EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); /** * snd_hda_jack_detect_state - query pin Presence Detect status @@ -222,7 +222,7 @@ int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); if (jack && jack->phantom_jack) return HDA_JACK_PHANTOM; - else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) + else if (snd_hda_jack_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) return HDA_JACK_PRESENT; else return HDA_JACK_NOT_PRESENT; diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 22fe7ee43e82..cd9b47f51fab 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -65,7 +65,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); -u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid); /* the jack state returned from snd_hda_jack_detect_state() */ enum { diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index f6ce9a7363dd..41ca22ed514e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1532,7 +1532,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, bool ret; bool do_repoll = false; - present = snd_hda_pin_sense(codec, pin_nid); + present = snd_hda_jack_pin_sense(codec, pin_nid); mutex_lock(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); From patchwork Wed Aug 12 05:58:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343511 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJtg27b2z9sTs; Wed, 12 Aug 2020 15:59:23 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnD-0001tj-Bw; Wed, 12 Aug 2020 05:59:19 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jn7-0001sS-GZ for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:13 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jn6-0006E9-73 for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:13 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 2/9] ALSA: hda - Add DP-MST jack support Date: Wed, 12 Aug 2020 13:58:15 +0800 Message-Id: <20200812055822.5853-3-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Nikhil Mahale BugLink: https://bugs.launchpad.net/bugs/1867704 This patch adds DP-MST jack support which will be used on NVIDIA platforms. Today, DP-MST audio is supported only if the codec has acomp support. This patch makes it possible to add DP-MST support for non-acomp codecs. For the codecs supporting DP-MST audio, each pin can contain several device entries. Each device entry is a virtual pin, described by pin_nid and dev_id in struct hdmi_spec_per_pin. For monitor hotplug event handling, non-acomp codecs enable and register jack-detection for every hdmi_spec_per_pin. This patch updates every relevant function in hda_jack.h and its implementation in hda_jack.c, to consider dev_id along with pin_nid. Changes to the HD Audio specification to support DP-MST audio are described in the Intel Document Change Notification (DCN) number HDA040-A. From HDA040-A, "For the case of multi stream capable Digital Display Pin Widget, [the Get Pin Sense verb] can be used to read a specific Device Entry state as reported in Get Device List Entry verb." This patch updates the read_pin_sense() function to take the dev_id as an argument and pass it as a parameter to the Get Pin Sense verb. Bits 15 through 20 from the Unsolicited Response for intrinsic events contain the index of the Device Entry that generated the event. This patch updates the Unsolicited Response event handlers to extract the device entry index from the response and pass it to snd_hda_jack_tbl_get_from_tag(). This patch updates snd_hda_jack_tbl_new() to take a dev_id argument and store it in the jack structure, and to make sure not to generate a different tag when called more than once for the same nid. Signed-off-by: Nikhil Mahale Link: https://lore.kernel.org/r/20191119084710.29267-3-nmahale@nvidia.com Signed-off-by: Takashi Iwai (cherry picked from commit 5204a05d70d9354e6dd27219275c4b6725443dc4) Signed-off-by: Hui Wang --- sound/pci/hda/hda_jack.c | 147 ++++++++++++++++++++++++++----------- sound/pci/hda/hda_jack.h | 107 ++++++++++++++++++++++++--- sound/pci/hda/patch_hdmi.c | 70 +++++++++++------- 3 files changed, 244 insertions(+), 80 deletions(-) diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 1ea42447278f..bf0255cb0515 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -43,7 +43,7 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) EXPORT_SYMBOL_GPL(is_jack_detectable); /* execute pin sense measurement */ -static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) +static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) { u32 pincap; u32 val; @@ -55,19 +55,20 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) AC_VERB_SET_PIN_SENSE, 0); } val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + AC_VERB_GET_PIN_SENSE, dev_id); if (codec->inv_jack_detect) val ^= AC_PINSENSE_PRESENCE; return val; } /** - * snd_hda_jack_tbl_get - query the jack-table entry for the given NID + * snd_hda_jack_tbl_get_mst - query the jack-table entry for the given NID * @codec: the HDA codec * @nid: pin NID to refer to + * @dev_id: pin device entry id */ struct hda_jack_tbl * -snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) +snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) { struct hda_jack_tbl *jack = codec->jacktbl.list; int i; @@ -75,19 +76,21 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) if (!nid || !jack) return NULL; for (i = 0; i < codec->jacktbl.used; i++, jack++) - if (jack->nid == nid) + if (jack->nid == nid && jack->dev_id == dev_id) return jack; return NULL; } -EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get); +EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst); /** * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag * @codec: the HDA codec * @tag: tag value to refer to + * @dev_id: pin device entry id */ struct hda_jack_tbl * -snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag) +snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, + unsigned char tag, int dev_id) { struct hda_jack_tbl *jack = codec->jacktbl.list; int i; @@ -95,29 +98,62 @@ snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag) if (!tag || !jack) return NULL; for (i = 0; i < codec->jacktbl.used; i++, jack++) - if (jack->tag == tag) + if (jack->tag == tag && jack->dev_id == dev_id) return jack; return NULL; } EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); +static struct hda_jack_tbl * +any_jack_tbl_get_from_nid(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i; + + if (!nid || !jack) + return NULL; + for (i = 0; i < codec->jacktbl.used; i++, jack++) + if (jack->nid == nid) + return jack; + return NULL; +} + /** * snd_hda_jack_tbl_new - create a jack-table entry for the given NID * @codec: the HDA codec * @nid: pin NID to assign */ static struct hda_jack_tbl * -snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) +snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) { - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + struct hda_jack_tbl *jack = + snd_hda_jack_tbl_get_mst(codec, nid, dev_id); + struct hda_jack_tbl *existing_nid_jack = + any_jack_tbl_get_from_nid(codec, nid); + + WARN_ON(dev_id != 0 && !codec->dp_mst); + if (jack) return jack; jack = snd_array_new(&codec->jacktbl); if (!jack) return NULL; jack->nid = nid; + jack->dev_id = dev_id; jack->jack_dirty = 1; - jack->tag = codec->jacktbl.used; + if (existing_nid_jack) { + jack->tag = existing_nid_jack->tag; + + /* + * Copy jack_detect from existing_nid_jack to avoid + * snd_hda_jack_detect_enable_callback_mst() making multiple + * SET_UNSOLICITED_ENABLE calls on the same pin. + */ + jack->jack_detect = existing_nid_jack->jack_detect; + } else { + jack->tag = codec->jacktbl.used; + } + return jack; } @@ -153,10 +189,12 @@ static void jack_detect_update(struct hda_codec *codec, if (jack->phantom_jack) jack->pin_sense = AC_PINSENSE_PRESENCE; else - jack->pin_sense = read_pin_sense(codec, jack->nid); + jack->pin_sense = read_pin_sense(codec, jack->nid, + jack->dev_id); /* A gating jack indicates the jack is invalid if gating is unplugged */ - if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) + if (jack->gating_jack && + !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) jack->pin_sense &= ~AC_PINSENSE_PRESENCE; jack->jack_dirty = 0; @@ -164,7 +202,8 @@ static void jack_detect_update(struct hda_codec *codec, /* If a jack is gated by this one update it. */ if (jack->gated_jack) { struct hda_jack_tbl *gated = - snd_hda_jack_tbl_get(codec, jack->gated_jack); + snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, + jack->dev_id); if (gated) { gated->jack_dirty = 1; jack_detect_update(codec, gated); @@ -198,56 +237,62 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); * Execute necessary pin sense measurement and return its Presence Detect, * Impedance, ELD Valid etc. status bits. */ -u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid) +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) { - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + struct hda_jack_tbl *jack = + snd_hda_jack_tbl_get_mst(codec, nid, dev_id); if (jack) { jack_detect_update(codec, jack); return jack->pin_sense; } - return read_pin_sense(codec, nid); + return read_pin_sense(codec, nid, dev_id); } EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); /** - * snd_hda_jack_detect_state - query pin Presence Detect status + * snd_hda_jack_detect_state_mst - query pin Presence Detect status * @codec: the CODEC to sense * @nid: the pin NID to sense + * @dev_id: pin device entry id * * Query and return the pin's Presence Detect status, as either * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. */ -int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) +int snd_hda_jack_detect_state_mst(struct hda_codec *codec, + hda_nid_t nid, int dev_id) { - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + struct hda_jack_tbl *jack = + snd_hda_jack_tbl_get_mst(codec, nid, dev_id); if (jack && jack->phantom_jack) return HDA_JACK_PHANTOM; - else if (snd_hda_jack_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) + else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & + AC_PINSENSE_PRESENCE) return HDA_JACK_PRESENT; else return HDA_JACK_NOT_PRESENT; } -EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); +EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); /** - * snd_hda_jack_detect_enable - enable the jack-detection + * snd_hda_jack_detect_enable_mst - enable the jack-detection * @codec: the HDA codec * @nid: pin NID to enable * @func: callback function to register + * @dev_id: pin device entry id * * In the case of error, the return value will be a pointer embedded with * errno. Check and handle the return value appropriately with standard * macros such as @IS_ERR() and @PTR_ERR(). */ struct hda_jack_callback * -snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback_fn func) +snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, hda_jack_callback_fn func) { struct hda_jack_tbl *jack; struct hda_jack_callback *callback = NULL; int err; - jack = snd_hda_jack_tbl_new(codec, nid); + jack = snd_hda_jack_tbl_new(codec, nid, dev_id); if (!jack) return ERR_PTR(-ENOMEM); if (func) { @@ -256,6 +301,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, return ERR_PTR(-ENOMEM); callback->func = func; callback->nid = jack->nid; + callback->dev_id = jack->dev_id; callback->next = jack->callback; jack->callback = callback; } @@ -272,19 +318,24 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, return ERR_PTR(err); return callback; } -EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); +EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); /** * snd_hda_jack_detect_enable - Enable the jack detection on the given pin * @codec: the HDA codec * @nid: pin NID to enable jack detection + * @dev_id: pin device entry id * * Enable the jack detection with the default callback. Returns zero if * successful or a negative error code. */ -int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid) +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, + int dev_id) { - return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL)); + return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, + nid, + dev_id, + NULL)); } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); @@ -299,8 +350,11 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid) { - struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid); - struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid); + struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); + struct hda_jack_tbl *gating = + snd_hda_jack_tbl_new(codec, gating_nid, 0); + + WARN_ON(codec->dp_mst); if (!gated || !gating) return -EINVAL; @@ -376,9 +430,10 @@ static void hda_free_jack_priv(struct snd_jack *jack) } /** - * snd_hda_jack_add_kctl - Add a kctl for the given pin + * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin * @codec: the HDA codec * @nid: pin NID to assign + * @dev_id : pin device entry id * @name: string name for the jack * @phantom_jack: flag to deal as a phantom jack * @type: jack type bits to be reported, 0 for guessing from pincfg @@ -387,15 +442,15 @@ static void hda_free_jack_priv(struct snd_jack *jack) * This assigns a jack-detection kctl to the given pin. The kcontrol * will have the given name and index. */ -int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack, - int type, const struct hda_jack_keymap *keymap) +int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap) { struct hda_jack_tbl *jack; const struct hda_jack_keymap *map; int err, state, buttons; - jack = snd_hda_jack_tbl_new(codec, nid); + jack = snd_hda_jack_tbl_new(codec, nid, dev_id); if (!jack) return 0; if (jack->jack) @@ -425,12 +480,12 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, snd_jack_set_key(jack->jack, map->type, map->key); } - state = snd_hda_jack_detect(codec, nid); + state = snd_hda_jack_detect_mst(codec, nid, dev_id); snd_jack_report(jack->jack, state ? jack->type : 0); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl); +EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, const struct auto_pin_cfg *cfg, @@ -441,6 +496,8 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, int err; bool phantom_jack; + WARN_ON(codec->dp_mst); + if (!nid) return 0; def_conf = snd_hda_codec_get_pincfg(codec, nid); @@ -462,7 +519,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, return err; if (!phantom_jack) - return snd_hda_jack_detect_enable(codec, nid); + return snd_hda_jack_detect_enable(codec, nid, 0); return 0; } @@ -540,7 +597,8 @@ static void call_jack_callback(struct hda_codec *codec, unsigned int res, } if (jack->gated_jack) { struct hda_jack_tbl *gated = - snd_hda_jack_tbl_get(codec, jack->gated_jack); + snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, + jack->dev_id); if (gated) { for (cb = gated->callback; cb; cb = cb->next) { cb->jack = gated; @@ -561,7 +619,14 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) struct hda_jack_tbl *event; int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; - event = snd_hda_jack_tbl_get_from_tag(codec, tag); + if (codec->dp_mst) { + int dev_entry = + (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; + + event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); + } else { + event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); + } if (!event) return; event->jack_dirty = 1; diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index cd9b47f51fab..727b6d3ba454 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -19,6 +19,7 @@ typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callba struct hda_jack_callback { hda_nid_t nid; + int dev_id; hda_jack_callback_fn func; unsigned int private_data; /* arbitrary data */ unsigned int unsol_res; /* unsolicited event bits */ @@ -28,6 +29,7 @@ struct hda_jack_callback { struct hda_jack_tbl { hda_nid_t nid; + int dev_id; unsigned char tag; /* unsol event tag */ struct hda_jack_callback *callback; /* jack-detection stuff */ @@ -49,46 +51,129 @@ struct hda_jack_keymap { }; struct hda_jack_tbl * -snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid); +snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id); + +/** + * snd_hda_jack_tbl_get - query the jack-table entry for the given NID + * @codec: the HDA codec + * @nid: pin NID to refer to + */ +static inline struct hda_jack_tbl * +snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_jack_tbl_get_mst(codec, nid, 0); +} + struct hda_jack_tbl * -snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag); +snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, + unsigned char tag, int dev_id); void snd_hda_jack_tbl_clear(struct hda_codec *codec); void snd_hda_jack_set_dirty_all(struct hda_codec *codec); -int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, + int dev_id); + struct hda_jack_callback * +snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, hda_jack_callback_fn cb); + +/** + * snd_hda_jack_detect_enable - enable the jack-detection + * @codec: the HDA codec + * @nid: pin NID to enable + * @func: callback function to register + * + * In the case of error, the return value will be a pointer embedded with + * errno. Check and handle the return value appropriately with standard + * macros such as @IS_ERR() and @PTR_ERR(). + */ +static inline struct hda_jack_callback * snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback_fn cb); + hda_jack_callback_fn cb) +{ + return snd_hda_jack_detect_enable_callback_mst(codec, nid, 0, cb); +} int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); -u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid); +u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id); /* the jack state returned from snd_hda_jack_detect_state() */ enum { HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM, }; -int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_jack_detect_state_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id); + +/** + * snd_hda_jack_detect_state - query pin Presence Detect status + * @codec: the CODEC to sense + * @nid: the pin NID to sense + * + * Query and return the pin's Presence Detect status, as either + * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. + */ +static inline int +snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_jack_detect_state_mst(codec, nid, 0); +} + +/** + * snd_hda_jack_detect_mst - Detect the jack + * @codec: the HDA codec + * @nid: pin NID to check jack detection + * @dev_id: pin device entry id + */ +static inline bool +snd_hda_jack_detect_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) +{ + return snd_hda_jack_detect_state_mst(codec, nid, dev_id) != + HDA_JACK_NOT_PRESENT; +} /** * snd_hda_jack_detect - Detect the jack * @codec: the HDA codec * @nid: pin NID to check jack detection */ -static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) +static inline bool +snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) { - return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT; + return snd_hda_jack_detect_mst(codec, nid, 0); } bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack, - int type, const struct hda_jack_keymap *keymap); +int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap); + +/** + * snd_hda_jack_add_kctl - Add a kctl for the given pin + * @codec: the HDA codec + * @nid: pin NID to assign + * @name: string name for the jack + * @phantom_jack: flag to deal as a phantom jack + * @type: jack type bits to be reported, 0 for guessing from pincfg + * @keymap: optional jack / key mapping + * + * This assigns a jack-detection kctl to the given pin. The kcontrol + * will have the given name and index. + */ +static inline int +snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, + const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap) +{ + return snd_hda_jack_add_kctl_mst(codec, nid, 0, + name, phantom_jack, type, keymap); +} + int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 41ca22ed514e..87d74f1c8444 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -781,34 +781,32 @@ static void jack_callback(struct hda_codec *codec, if (codec_has_acomp(codec)) return; - /* 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_intrinsic_event(struct hda_codec *codec, unsigned int res) { 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 (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) 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) @@ -838,11 +836,21 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) { 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 (codec_has_acomp(codec)) return; - if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) { + 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; } @@ -1532,7 +1540,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, bool ret; bool do_repoll = false; - present = snd_hda_jack_pin_sense(codec, pin_nid); + present = snd_hda_jack_pin_sense(codec, pin_nid, per_pin->dev_id); mutex_lock(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); @@ -1565,7 +1573,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, ret = !repoll || !eld->monitor_present || eld->eld_valid; - jack = snd_hda_jack_tbl_get(codec, pin_nid); + jack = snd_hda_jack_tbl_get_mst(codec, pin_nid, per_pin->dev_id); if (jack) { jack->block_report = !ret; jack->pin_sense = (eld->monitor_present && eld->eld_valid) ? @@ -1596,7 +1604,8 @@ static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec, * 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); + jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid, + per_pin->dev_id); if (jack_tbl) jack = jack_tbl->jack; } @@ -1677,7 +1686,8 @@ static void hdmi_repoll_eld(struct work_struct *work) 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; @@ -2182,11 +2192,13 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx) 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, 0, NULL); + ret = snd_hda_jack_add_kctl_mst(codec, per_pin->pin_nid, + per_pin->dev_id, hdmi_str, phantom_jack, + 0, NULL); if (ret < 0) return ret; - 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 == NULL) return 0; /* assign jack->jack to pcm_rec[].jack to @@ -2297,10 +2309,11 @@ static int generic_hdmi_init(struct hda_codec *codec) if (codec_has_acomp(codec)) continue; if (spec->use_jack_detect) - snd_hda_jack_detect_enable(codec, pin_nid); + snd_hda_jack_detect_enable(codec, pin_nid, dev_id); else - snd_hda_jack_detect_enable_callback(codec, pin_nid, - jack_callback); + snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, + dev_id, + jack_callback); } mutex_unlock(&spec->bind_lock); return 0; @@ -2450,11 +2463,11 @@ static int patch_generic_hdmi(struct hda_codec *codec) /* turn on / off the unsol event jack detection dynamically */ static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid, - bool use_acomp) + int dev_id, bool use_acomp) { struct hda_jack_tbl *tbl; - tbl = snd_hda_jack_tbl_get(codec, nid); + 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 @@ -2467,7 +2480,7 @@ static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid, * at need (i.e. only when notifier is cleared) */ if (!use_acomp) - snd_hda_jack_detect_enable(codec, nid); + snd_hda_jack_detect_enable(codec, nid, dev_id); } } @@ -2487,6 +2500,7 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp, 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); @@ -3002,7 +3016,7 @@ static int simple_playback_init(struct hda_codec *codec) 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; } From patchwork Wed Aug 12 05:58:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343513 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJtj2XWxz9sTg; Wed, 12 Aug 2020 15:59:25 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnF-0001vh-RB; Wed, 12 Aug 2020 05:59:21 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jn9-0001sY-6a for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:15 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jn8-0006E9-AP for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:15 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 3/9] ALSA: hda - Add DP-MST support for non-acomp codecs Date: Wed, 12 Aug 2020 13:58:16 +0800 Message-Id: <20200812055822.5853-4-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Nikhil Mahale BugLink: https://bugs.launchpad.net/bugs/1867704 This patch make it possible for non-acomp codecs to set dyn_pcm_assign/dp_mst and get DP-MST audio support. Document change notification HDA040-A for the Intel High Definition Audio 1.0a specification introduces a Device Select verb for Digital Display Pin Widgets that are multi-stream capable. This verb selects a Device Entry that is used by subsequent Pin Widget verbs. Once the Device Entry is selected, all subsequent Pin Widget verbs controlling the sink device will be directed to the selected Device Entry until the Device Select verb is updated with a new value. These Pin Widget verbs include: * Connection Select * Get Connection List Entry * Amplifier Gain/Mute * Power State * Pin Widget Control * ELD Data * DIP-Size * DIP-Index * DIP-Data * DIP-XmitCtrl * Content Protection Control * ASP Channel Mapping This patch adds calls to snd_hda_set_dev_select() to direct each of these Pin Widget control verbs to the correct Device Entry. snd_hda_get_connections() does not return per-device connection list, therefore make use snd_hda_get_raw_connections() instead of snd_hda_get_connections(). Signed-off-by: Nikhil Mahale Reviewed-by: Aaron Plattner Link: https://lore.kernel.org/r/20191119084710.29267-4-nmahale@nvidia.com Signed-off-by: Takashi Iwai (cherry picked from commit 9c32fea836928d7a25a83b337f268e533cfc5c3d) Signed-off-by: Hui Wang --- sound/pci/hda/patch_hdmi.c | 100 +++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 87d74f1c8444..0df766ee3872 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -104,16 +104,19 @@ struct hdmi_spec_per_pin { /* 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, @@ -659,8 +662,16 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, 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) { @@ -690,6 +701,8 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, return; } + snd_hda_set_dev_select(codec, pin_nid, dev_id); + /* * sizeof(ai) is used instead of sizeof(*hdmi_ai) or * sizeof(*dp_ai) to avoid partial match/update problems when @@ -715,6 +728,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, 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; @@ -723,6 +737,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, 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) snd_hda_codec_write(codec, pin_nid, 0, @@ -748,8 +764,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, 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; } @@ -891,11 +907,12 @@ static void haswell_verify_D0(struct hda_codec *codec, ((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); @@ -925,13 +942,15 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, } 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"); @@ -1309,6 +1328,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) 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; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { codec_warn(codec, @@ -1317,10 +1337,12 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return -EINVAL; } + snd_hda_set_dev_select(codec, pin_nid, dev_id); + /* 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 = + snd_hda_get_raw_connections(codec, pin_nid, per_pin->mux_nids, + HDA_MAX_CONNECTIONS); return 0; } @@ -1528,6 +1550,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; 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 @@ -1540,7 +1563,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, bool ret; bool do_repoll = false; - present = snd_hda_jack_pin_sense(codec, pin_nid, per_pin->dev_id); + present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); mutex_lock(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); @@ -1554,8 +1577,8 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, 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, @@ -1894,7 +1917,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 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, stripe; @@ -1918,7 +1940,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 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 @@ -1933,8 +1954,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, /* 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); @@ -1952,16 +1973,18 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 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; @@ -2015,6 +2038,8 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, 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, @@ -2403,7 +2428,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { }; 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, @@ -2606,7 +2631,8 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, hda_nid_t conns[4]; int nconns; - nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns)); + nconns = snd_hda_get_raw_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; @@ -2784,10 +2810,12 @@ static void register_i915_notifier(struct hda_codec *codec) /* 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+ */ @@ -3734,16 +3762,19 @@ static int patch_tegra_hdmi(struct hda_codec *codec) #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); } @@ -3934,10 +3965,12 @@ static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, } 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)) { if (hbr) @@ -3963,9 +3996,9 @@ static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, } 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 */ @@ -3975,7 +4008,8 @@ static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, 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); } From patchwork Wed Aug 12 05:58:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343510 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJtg0BFqz9sTq; Wed, 12 Aug 2020 15:59:22 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnD-0001uA-Me; Wed, 12 Aug 2020 05:59:19 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnB-0001tF-1B for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:17 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnA-0006E9-2S for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:16 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 4/9] ALSA: hda - Add DP-MST support for NVIDIA codecs Date: Wed, 12 Aug 2020 13:58:17 +0800 Message-Id: <20200812055822.5853-5-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Nikhil Mahale BugLink: https://bugs.launchpad.net/bugs/1867704 This patch adds DP-MST support for GK104+ NVIDIA codecs. GK104+ NVIDIA codecs support DP-MST audio. These codecs have 4 output converters and 4 pin widgets, with 4 device entries per pin widget for a total of 16 device entries. This patch moves the existing patch_nvhdmi() definition to patch_nvhdmi_legacy(), used by pre-GK104 NVIDIA codecs. Redefine patch_nvhdmi() to enable DP-MST support by setting codec->dp_mst and spec->dyn_pcm_assign. Introduce fresh logic for dynamic pcm assignment, making sure that new pcm assignments are compatible with the legacy static per_pin-pmc assignment that existed in the days before DP-MST. Signed-off-by: Nikhil Mahale Reviewed-by: Aaron Plattner Link: https://lore.kernel.org/r/20191119084710.29267-5-nmahale@nvidia.com Signed-off-by: Takashi Iwai (backported from commit 5398e94fb753d022301825ebfa5f7cf8a660d8eb) Signed-off-by: Hui Wang --- sound/pci/hda/patch_hdmi.c | 93 +++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 0df766ee3872..dbdd10af681b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1348,15 +1348,32 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) } 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)) + /* + * generic_hdmi_build_pcms() allocates (num_nids + dev_num - 1) + * number of pcms. + * + * 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-pmc assignment that existed in the + * days before DP-MST. + * + * per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)). + */ + if (per_pin->dev_id == 0 && + !test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) return per_pin->pin_nid_idx; - /* have a second try; check the "reserved area" over num_pins */ + if (per_pin->dev_id != 0 && + !(test_bit(spec->num_nids + (per_pin->dev_id - 1), + &spec->pcm_bitmap))) { + return spec->num_nids + (per_pin->dev_id - 1); + } + + /* 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; @@ -3533,6 +3550,38 @@ 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; + + codec->link_down_at_suspend = 1; + + return 0; +} + +static int patch_nvhdmi_legacy(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + err = patch_generic_hdmi(codec); if (err) return err; @@ -4139,25 +4188,25 @@ HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x), 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), From patchwork Wed Aug 12 05:58:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343514 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJtq71jkz9sTW; Wed, 12 Aug 2020 15:59:31 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnK-000208-QU; Wed, 12 Aug 2020 05:59:26 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnC-0001tW-Pz for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:18 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnB-0006E9-SQ for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:18 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 5/9] ALSA: hda: hdmi - fix regression in connect list handling Date: Wed, 12 Aug 2020 13:58:18 +0800 Message-Id: <20200812055822.5853-6-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Kai Vehmanen BugLink: https://bugs.launchpad.net/bugs/1867704 Fix regression in how intel_haswell_fixup_connect_list() results are used in hda_read_pin_conn(). Use of snd_hda_get_raw_connections() in hda_read_pin_conn() bypasses the cache and thus also bypasses the overridden pin connection list. On platforms that require the connection list fixup, mux list will be empty and HDMI playback will fail to -EBUSY at open. Fix the regression in hda_read_pinn_conn(). Simplify code as suggested by Takashi Iwai to remove old intel_haswell_fixup_connect_list() and copy the cvt_nid list directly and not use snd_hda_override_conn_list() at all. Fixes: 9c32fea83692 ("ALSA: hda - Add DP-MST support for non-acomp codecs") BugLink: https://github.com/thesofproject/linux/issues/1537 Cc: Nikhil Mahale Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20191127161240.17026-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai (backported from commit ae254888f3c39f66d09920b459112ba3eadf1dc4) Signed-off-by: Hui Wang --- sound/pci/hda/patch_hdmi.c | 39 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index dbdd10af681b..d11fe291bd0d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1329,6 +1329,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) 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, @@ -1339,10 +1340,18 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) snd_hda_set_dev_select(codec, pin_nid, dev_id); + if (is_haswell_plus(codec)) { + 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_raw_connections(codec, pin_nid, per_pin->mux_nids, - HDA_MAX_CONNECTIONS); + per_pin->num_mux_nids = conns; return 0; } @@ -1740,9 +1749,6 @@ static void hdmi_repoll_eld(struct work_struct *work) 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) { struct hdmi_spec *spec = codec->spec; @@ -1817,8 +1823,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) 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; @@ -2641,24 +2646,6 @@ static void generic_acomp_init(struct hda_codec *codec, * 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_raw_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_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ From patchwork Wed Aug 12 05:58:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343512 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJth5bC6z9sTN; Wed, 12 Aug 2020 15:59:24 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnG-0001w4-4D; Wed, 12 Aug 2020 05:59:22 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnE-0001uz-Pe for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:20 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnD-0006E9-LH for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:20 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 6/9] ALSA: hda: hdmi - fix kernel oops caused by invalid PCM idx Date: Wed, 12 Aug 2020 13:58:19 +0800 Message-Id: <20200812055822.5853-7-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Kai Vehmanen BugLink: https://bugs.launchpad.net/bugs/1867704 Add additional check in hdmi_find_pcm_slot() to not return a pcm index that points to unallocated pcm. This could happen if codec driver is set up in codec->mst_no_extra_pcms mode. On some platforms, this leads to a kernel oops in snd_ctl_notify(), called via update_eld(). BugLink: https://github.com/thesofproject/linux/issues/1536 Fixes: 5398e94fb753 ALSA: hda - Add DP-MST support for NVIDIA codecs Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20191129143756.23941-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai (cherry picked from commit 0c0fe9e6b95ce2e9e2c83bef5563cf223e849eda) Signed-off-by: Hui Wang --- sound/pci/hda/patch_hdmi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d11fe291bd0d..2c34ce878929 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1362,24 +1362,24 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec, int i; /* - * generic_hdmi_build_pcms() allocates (num_nids + dev_num - 1) - * number of pcms. + * 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-pmc assignment that existed in the + * with the legacy static per_pin-pcm assignment that existed in the * days before DP-MST. * * per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)). */ - if (per_pin->dev_id == 0 && - !test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) - return per_pin->pin_nid_idx; - - if (per_pin->dev_id != 0 && - !(test_bit(spec->num_nids + (per_pin->dev_id - 1), - &spec->pcm_bitmap))) { - return spec->num_nids + (per_pin->dev_id - 1); + + if (per_pin->dev_id == 0) { + 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 */ From patchwork Wed Aug 12 05:58:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343516 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJts1HxJz9sTN; Wed, 12 Aug 2020 15:59:33 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnL-00020t-Qu; Wed, 12 Aug 2020 05:59:27 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnG-0001wS-JT for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:22 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnF-0006E9-DM for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:22 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 7/9] ALSA: hda: hdmi - preserve non-MST PCM routing for Intel platforms Date: Wed, 12 Aug 2020 13:58:20 +0800 Message-Id: <20200812055822.5853-8-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Kai Vehmanen BugLink: https://bugs.launchpad.net/bugs/1867704 Commit 5398e94fb753 ("ALSA: hda - Add DP-MST support for NVIDIA codecs") introduced a slight change of behaviour how non-MST monitors are assigned to PCMs on Intel platforms. In the drm_audio_component.h interface, the third parameter to pin_eld_notify() is pipe number. On Intel platforms, this value is -1 for MST. On other platforms, a non-zero pipe id is used to signal MST use. This difference leads to some subtle differences in hdmi_find_pcm_slot() with regards to how non-MST monitors are assigned to PCMs. This patch restores the original behaviour on Intel platforms while keeping the new allocation policy on other platforms. Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20191129143756.23941-2-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai (backported from commit 609f5485344b05a7eaffe9fdd09d42ad1c501cdf) Signed-off-by: Hui Wang --- sound/pci/hda/patch_hdmi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2c34ce878929..f48d3e8ae689 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1380,6 +1380,11 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec, i = spec->num_nids + (per_pin->dev_id - 1); if (i < spec->pcm_used && !(test_bit(i, &spec->pcm_bitmap))) return i; + + /* keep legacy assignment for dev_id>0 on Intel platforms */ + if (is_haswell_plus(per_pin->codec)) + if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) + return per_pin->pin_nid_idx; } /* have a second try; check the area over num_nids */ From patchwork Wed Aug 12 05:58:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343515 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJtr4PPHz9sTg; Wed, 12 Aug 2020 15:59:32 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnM-00021i-P0; Wed, 12 Aug 2020 05:59:28 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnI-0001yC-Bv for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:24 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnH-0006E9-5N for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:23 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 8/9] ALSA: hda: hdmi - Keep old slot assignment behavior for Intel platforms Date: Wed, 12 Aug 2020 13:58:21 +0800 Message-Id: <20200812055822.5853-9-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Takashi Iwai BugLink: https://bugs.launchpad.net/bugs/1867704 The commit 609f5485344b ("ALSA: hda: hdmi - preserve non-MST PCM routing for Intel platforms") tried to restore the old behavior wrt assignment of the PCM slot for Intel platforms, but this didn't do it right. As found in the later discussion, a positive pipe id on Intel platforms can be passed for single monitor attachment case. This patch reverts the previous attempt and applies a simpler workaround instead. Actually, for Intel platforms, we can handle as if per_pin->dev_id=0, assign the primary slot at the first try. This assures the compatible behavior with the previous versions regarding the slot assignment. Fixes: 609f5485344b ("ALSA: hda: hdmi - preserve non-MST PCM routing for Intel platforms") Link: https://lore.kernel.org/r/20191203154105.30414-1-tiwai@suse.de Signed-off-by: Takashi Iwai (backported from commit 643a2cc99b53c13d90c02dc344f780ba9a89e012) Signed-off-by: Hui Wang --- sound/pci/hda/patch_hdmi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index f48d3e8ae689..2e6d3e48d73b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1370,21 +1370,18 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec, * 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) { + if (per_pin->dev_id == 0 || is_haswell_plus(per_pin->codec)) { 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; - - /* keep legacy assignment for dev_id>0 on Intel platforms */ - if (is_haswell_plus(per_pin->codec)) - if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) - return per_pin->pin_nid_idx; } /* have a second try; check the area over num_nids */ From patchwork Wed Aug 12 05:58:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hui Wang X-Patchwork-Id: 1343517 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRJtt0YWXz9sTS; Wed, 12 Aug 2020 15:59:34 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1k5jnN-00022U-9h; Wed, 12 Aug 2020 05:59:29 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnK-0001zZ-4U for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:26 +0000 Received: from [114.253.245.60] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1k5jnI-0006E9-U7 for kernel-team@lists.ubuntu.com; Wed, 12 Aug 2020 05:59:25 +0000 From: Hui Wang To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 9/9] ALSA: hda - Fix DP-MST support for NVIDIA codecs Date: Wed, 12 Aug 2020 13:58:22 +0800 Message-Id: <20200812055822.5853-10-hui.wang@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200812055822.5853-1-hui.wang@canonical.com> References: <20200812055822.5853-1-hui.wang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Nikhil Mahale BugLink: https://bugs.launchpad.net/bugs/1867704 If dyn_pcm_assign is set, different jack objects are being created for pcm and pins. If dyn_pcm_assign is set, generic_hdmi_build_jack() calls into add_hdmi_jack_kctl() to create and track separate jack object for pcm. Like sync_eld_via_acomp(), hdmi_present_sense_via_verbs() also need to report status change of the pcm jack. Rename pin_idx_to_jack() to pin_idx_to_pcm_jack(). Update hdmi_present_sense_via_verbs() to report plug state of pcm jack object. Unlike sync_eld_via_acomp(), for !acomp drivers the pcm jack's plug state must be consistent with plug state of pin's jack. Fixes: 5398e94fb753 ("ALSA: hda - Add DP-MST support for NVIDIA codecs") Reported-and-tested-by: Martin Regner Signed-off-by: Nikhil Mahale Reviewed-by: Kai Vehmanen Cc: Link: https://lore.kernel.org/r/20200204102746.1356-1-nmahale@nvidia.com Signed-off-by: Takashi Iwai (cherry picked from commit c7e661a1c2ae98a4754db6a85fc686b4a89322ad) Signed-off-by: Hui Wang --- sound/pci/hda/patch_hdmi.c | 94 +++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2e6d3e48d73b..af3855091647 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1569,6 +1569,34 @@ static bool update_eld(struct hda_codec *codec, return eld_changed; } +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; + struct snd_jack *jack = NULL; + struct hda_jack_tbl *jack_tbl; + + /* 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_mst(codec, per_pin->pin_nid, + per_pin->dev_id); + if (jack_tbl) + jack = jack_tbl->jack; + } + return jack; +} /* update ELD and jack state via HD-audio verbs */ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, int repoll) @@ -1590,6 +1618,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, int present; bool ret; bool do_repoll = false; + struct snd_jack *pcm_jack = NULL; present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); @@ -1617,10 +1646,19 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, do_repoll = true; } - if (do_repoll) + if (do_repoll) { schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300)); - else + } else { + /* + * 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); update_eld(codec, per_pin, eld); + if (!pcm_jack) + pcm_jack = pin_idx_to_pcm_jack(codec, per_pin); + } ret = !repoll || !eld->monitor_present || eld->eld_valid; @@ -1629,38 +1667,32 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, jack->block_report = !ret; jack->pin_sense = (eld->monitor_present && eld->eld_valid) ? AC_PINSENSE_PRESENCE : 0; - } - mutex_unlock(&per_pin->lock); - return ret; -} -static struct snd_jack *pin_idx_to_jack(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; + if (spec->dyn_pcm_assign && pcm_jack && !do_repoll) { + int state = 0; + + if (jack->pin_sense & AC_PINSENSE_PRESENCE) + state = SND_JACK_AVOUT; + snd_jack_report(pcm_jack, state); + } - /* 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 + * snd_hda_jack_pin_sense() call at the beginning of this + * function, updates jack->pins_sense and clears + * jack->jack_dirty, therefore snd_hda_jack_report_sync() will + * not override the jack->pin_sense. + * + * snd_hda_jack_report_sync() is superfluous for dyn_pcm_assign + * case. The jack->pin_sense update was already performed, and + * hda_jack->jack is NULL for dyn_pcm_assign. + * + * Don't call snd_hda_jack_report_sync() for + * dyn_pcm_assign. */ - jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid, - per_pin->dev_id); - if (jack_tbl) - jack = jack_tbl->jack; + ret = ret && !spec->dyn_pcm_assign; } - return jack; + mutex_unlock(&per_pin->lock); + return ret; } /* update ELD and jack state via audio component */ @@ -1696,10 +1728,10 @@ static void sync_eld_via_acomp(struct hda_codec *codec, /* 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); + jack = pin_idx_to_pcm_jack(codec, per_pin); changed = update_eld(codec, per_pin, eld); if (jack == NULL) - jack = pin_idx_to_jack(codec, per_pin); + jack = pin_idx_to_pcm_jack(codec, per_pin); if (changed && jack) snd_jack_report(jack, (eld->monitor_present && eld->eld_valid) ?