From bd5863f9ef12e26c2cfdce9c0adbf0222c731a3c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2024 14:03:54 -0500 Subject: [PATCH 1/4] ASoC: SOF: Intel: hda-ctrl: add missing WAKE_STS clear MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason, the programming sequences in the SOF driver do not include a clear of the WAKE_STS bits before resetting the controller. This clear is not formally required by the HDaudio specification, but was added to harden the snd-hda-reset back in 2007. Adding this sequence back avoids an issue reported by the Intel CI. Closes: https://github.com/thesofproject/linux/issues/4889 Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240404190357.138073-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 84bf01bd360a..b4f0756e21f6 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -184,6 +184,7 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *stream; int sd_offset, ret = 0; + u32 gctl; if (bus->chip_init) return 0; @@ -192,6 +193,12 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) hda_dsp_ctrl_misc_clock_gating(sdev, false); + /* clear WAKE_STS if not in reset */ + gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); + if (gctl & SOF_HDA_GCTL_RESET) + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_WAKESTS, SOF_HDA_WAKESTS_INT_MASK); + /* reset HDA controller */ ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { From ab9182441ee5a94dd6f47743ed1b7b6b07b63cb2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2024 14:03:55 -0500 Subject: [PATCH 2/4] ASoC: SOF: Intel: lnl: add helper to detect SoundWire wakes The global STATESTS register will provide information on all links. Rather than iterate on all possible links, the helpers only filters the range of possible bits for a quick lookup. The process_wakeen() helper will walk through all the links and deal with wakes. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://msgid.link/r/20240404190357.138073-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/lnl.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 8e7193344341..8aa5430e9576 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -189,6 +189,23 @@ static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } +static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + u16 wake_sts; + + /* + * we need to use the global HDaudio WAKEEN/STS to be able to + * detect wakes in low-power modes. The link-specific information + * is handled in the process_wakeen() helper, this helper only + * detects a SoundWire wake without identifying the link. + */ + wake_sts = snd_hdac_chip_readw(bus, STATESTS); + + /* filter out the range of SDIs that can be set for SoundWire */ + return wake_sts & GENMASK(SDW_MAX_DEVICES, SDW_INTEL_DEV_NUM_IDA_MIN); +} + const struct sof_intel_dsp_desc lnl_chip_info = { .cores_num = 5, .init_core_mask = BIT(0), @@ -205,6 +222,7 @@ const struct sof_intel_dsp_desc lnl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_ext, .enable_sdw_irq = lnl_enable_sdw_irq, .check_sdw_irq = lnl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, .power_down_dsp = mtl_power_down_dsp, From b69480edf4eb71c6f754e3c4020e8dd72a330558 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2024 14:03:56 -0500 Subject: [PATCH 3/4] ASoC: SOF: Intel: hda-codec: preserve WAKEEN values Since LunarLake, we use the HDadio WAKEEN/WAKESTS to detect wakes for SoundWire codecs. Unfortunately, the existing code in hda_codec_jack_wake_enable() unconditionally resets the WAKEEN bits. This patch changes the initialization to preserve SoundWire WAKEEN bits. For HDAudio codecs the same strategy is used, WAKEEN is only set when the jacktbl.used property is set. Closes: https://github.com/thesofproject/linux/issues/4687 Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Reviewed-by: Keqiao Zhang Reviewed-by: Bard Liao Link: https://msgid.link/r/20240404190357.138073-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-codec.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 9f84b0d287a5..6a13f38a8d21 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -79,18 +79,27 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) struct hdac_bus *bus = sof_to_bus(sdev); struct hda_codec *codec; unsigned int mask = 0; + unsigned int val = 0; if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) return; if (enable) { - list_for_each_codec(codec, hbus) + list_for_each_codec(codec, hbus) { + /* only set WAKEEN when needed for HDaudio codecs */ + mask |= BIT(codec->core.addr); if (codec->jacktbl.used) - mask |= BIT(codec->core.addr); + val |= BIT(codec->core.addr); + } + } else { + list_for_each_codec(codec, hbus) { + /* reset WAKEEN only HDaudio codecs */ + mask |= BIT(codec->core.addr); + } } - snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); + snd_hdac_chip_updatew(bus, WAKEEN, mask & STATESTS_INT_MASK, val); } EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC); From 35b5806e2edee1741f6bd2de2a5c149a876c4a60 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2024 14:03:57 -0500 Subject: [PATCH 4/4] ASoC: SOF: Intel: hda-ctrl: only clear WAKESTS for HDaudio codecs When a PME wake happens due to a SoundWire wake, we currently clear all WAKESTS bits during the resume operation initiated by the PCI subsystem. As a result, we are unable to identify which SoundWire links need to be resumed and don't properly handle jack detection. This patch only clears the WAKESTS bits for the HDaudio codecs detected earlier. Note that we still clear all WAKESTS bits unconditionally in hda_dsp_ctrl_stop_chip(). The existing behavior is potentially racy if e.g. a jack event happens during a suspend routine, but there's a risk of breaking shutdown or reboot sequences so the code is left as is for now. Closes: https://github.com/thesofproject/linux/issues/4687 Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Reviewed-by: Keqiao Zhang Reviewed-by: Bard Liao Link: https://msgid.link/r/20240404190357.138073-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index b4f0756e21f6..6d941209847f 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -228,7 +228,7 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) /* clear WAKESTS */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK); + bus->codec_mask); hda_codec_rirb_status_clear(sdev);