From 6b32afdfcb6137de32421416ae80f63f902ede65 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 3 Jan 2024 15:49:34 +0800 Subject: [PATCH 1/4] drivers: dma: intel-adsp-hda: add delay to stop host dma According to hardware spec, host dma needs some delay to completely stop. In the bug the host dma is disabled in different path in a few microseonds. The first setting disabled the host dma and called pm_device_runtime_put to power off it. The second setting found the host dma was still alive and calle pm_device_runtime_put again. This results to pm->usage checking failed. BugLink: https://github.com/thesofproject/sof/issues/8686 Signed-off-by: Rander Wang (cherry picked from commit e021ccfc745221c685ea338f6ac2dd282e060434) --- drivers/dma/dma_intel_adsp_hda.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 7a131db2216d..7717013fddce 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -326,6 +326,14 @@ int intel_adsp_hda_dma_stop(const struct device *dev, uint32_t channel) intel_adsp_hda_disable(cfg->base, cfg->regblock_size, channel); + /* host dma needs some cycles to completely stop */ + if (cfg->direction == HOST_TO_MEMORY || cfg->direction == MEMORY_TO_HOST) { + if (!WAIT_FOR(!(*DGCS(cfg->base, cfg->regblock_size, channel) & DGCS_GBUSY), 1000, + k_busy_wait(1))) { + return -EBUSY; + } + } + return pm_device_runtime_put(dev); } From 34415256a53dc81b25da2bf6d0d1bff3c7f98f3f Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 1 Feb 2024 14:53:15 +0200 Subject: [PATCH 2/4] drivers: dma: intel-adsp-hda: modify stop dma logic Commit b2eaa6448076 ("drivers: dma: intel-adsp-hda: add delay to stop host dma") added a wait on GBUSY state to host DMA stop. This is problematic as in some case (like SOF chain-DMA usage), the host DMA side RUN bit is not cleared when intel_adsp_hda_dma_stop() is called. It is not possible to wait on GBUSY bit as there are valid cases where it can remain set. Address the original problem described in SOF bug #8686 and add a polling check for intel_adsp_hda_is_enabled(). As per the bug description, in some cases the GEN/FIFORDY bits are not cleared immediately and if a new call to intel_adsp_hda_dma_stop() is made, the PM refcounting will go haywire. Link: https://github.com/thesofproject/sof/issues/8686 Signed-off-by: Kai Vehmanen (cherry picked from commit 00d4661273fea5d1dddafd3a6957540c76ce0fcf) --- drivers/dma/dma_intel_adsp_hda.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 7717013fddce..fe86b8ca61fc 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -326,12 +326,9 @@ int intel_adsp_hda_dma_stop(const struct device *dev, uint32_t channel) intel_adsp_hda_disable(cfg->base, cfg->regblock_size, channel); - /* host dma needs some cycles to completely stop */ - if (cfg->direction == HOST_TO_MEMORY || cfg->direction == MEMORY_TO_HOST) { - if (!WAIT_FOR(!(*DGCS(cfg->base, cfg->regblock_size, channel) & DGCS_GBUSY), 1000, - k_busy_wait(1))) { - return -EBUSY; - } + if (!WAIT_FOR(!intel_adsp_hda_is_enabled(cfg->base, cfg->regblock_size, channel), 1000, + k_busy_wait(1))) { + return -EBUSY; } return pm_device_runtime_put(dev); From 684fe0d4b476d0238560909e0bd5826fd774beb9 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 12 Feb 2024 17:51:18 +0200 Subject: [PATCH 3/4] soc: xtensa: intel_adsp: restore bootctl with per-core state When exiting PM_STATE_SOFT_OFF, the primary core state is always used to restore bootctl register and the clock and power gating settings. This can lead to problems if non-primary core is powered up and down many times before primary core 0 is powered down the first time. The saved state in core_desc[0].bctl will be null, and as a result- power gating and clock gating is not disabled correctly for non-primary cores. Link: https://github.com/thesofproject/sof/issues/8642 Signed-off-by: Kai Vehmanen (cherry picked from commit a8af622f682c55889e13fd4e7eb21481ba87c44e) --- soc/xtensa/intel_adsp/ace/power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index cee8047d4a27..a48ec5ae0dba 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -326,7 +326,7 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) if (state == PM_STATE_SOFT_OFF) { /* restore clock gating state */ DSPCS.bootctl[cpu].bctl |= - (core_desc[0].bctl & DSPBR_BCTL_WAITIPCG); + (core_desc[cpu].bctl & DSPBR_BCTL_WAITIPCG); #ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE if (cpu == 0) { From 3f063f20acdfa44d53a82c0d3a0d541f0fc936ba Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 12 Jan 2024 21:45:25 +0000 Subject: [PATCH 4/4] dai: intel: dmic: demote spurious LOG_ERR in dai_nhlt_get_clock_div() Fix the log level of two LOG_ERR() statements which should have always been LOG_INF(). As confirmed by the author Adrian in #60172 Fixes commit 3fbaed4de9b2 ("dai: intel: ace: dmic: Refactor of dai_nhlt_dmic_dai_params_get function") Signed-off-by: Marc Herbert (cherry picked from commit 8042e73915c46e14891991810006537a46e1f5ac) --- drivers/dai/intel/dmic/dmic_nhlt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index 17a8f385a023..3d803da33b9c 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -139,12 +139,12 @@ static int dai_nhlt_get_clock_div(const struct dai_intel_dmic *dmic, const int p val = dai_dmic_read(dmic, dmic_base[pdm] + FIR_CHANNEL_REGS_SIZE * dmic->dai_config_params.dai_index + FIR_CONFIG); - LOG_ERR("pdm = %d, FIR_CONFIG = 0x%08X", pdm, val); + LOG_INF("pdm = %d, FIR_CONFIG = 0x%08X", pdm, val); p_mfir = FIELD_GET(FIR_CONFIG_FIR_DECIMATION, val) + 1; rate_div = p_clkdiv * p_mcic * p_mfir; - LOG_ERR("dai_index = %d, rate_div = %d, p_clkdiv = %d, p_mcic = %d, p_mfir = %d", + LOG_INF("dai_index = %d, rate_div = %d, p_clkdiv = %d, p_mcic = %d, p_mfir = %d", dmic->dai_config_params.dai_index, rate_div, p_clkdiv, p_mcic, p_mfir); if (!rate_div) {