From 2547948544ff342ffe5ebd1a8b5ab65bfd4077d9 Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Fri, 21 Oct 2022 09:26:09 +0200 Subject: [PATCH] intel_adsp: ace20_lnl: dmic: Program new HW registers for dmic In LNL platform GPDMA and ALH is no longer used. DMIC uses LINK HDA as a DMA engine. Therefore new shims, new register definitions and new programming flows were defined. This patch implements new DMIC programming requirements for LNL. Since HDA is shared between Host and DSP, link_config field was added to dai_config structure. This one is provided by Host in new IPC4 fields during interface configuration. Signed-off-by: Jaroslaw Stelter --- drivers/dai/intel/dmic/dmic.c | 94 +++++++++++++++++++++++++++-------- drivers/dai/intel/dmic/dmic.h | 27 ++++++++-- 2 files changed, 96 insertions(+), 25 deletions(-) diff --git a/drivers/dai/intel/dmic/dmic.c b/drivers/dai/intel/dmic/dmic.c index 21c08c32e74..8522ca44653 100644 --- a/drivers/dai/intel/dmic/dmic.c +++ b/drivers/dai/intel/dmic/dmic.c @@ -156,44 +156,69 @@ static inline void dai_dmic_release_ownership(const struct dai_intel_dmic *dmic) #endif /* CONFIG_DAI_DMIC_HAS_OWNERSHIP */ +static inline uint32_t dai_dmic_base(const struct dai_intel_dmic *dmic) +{ +#ifdef CONFIG_SOC_INTEL_ACE20_LNL + return dmic->hdamldmic_base; +#else + return dmic->shim_base; +#endif +} + #if CONFIG_DAI_DMIC_HAS_MULTIPLE_LINE_SYNC static inline void dai_dmic_set_sync_period(uint32_t period, const struct dai_intel_dmic *dmic) { uint32_t val = CONFIG_DAI_DMIC_HW_IOCLK / period - 1; - + uint32_t base = dai_dmic_base(dmic); /* DMIC Change sync period */ - sys_write32(sys_read32(dmic->shim_base + DMICSYNC_OFFSET) | DMICSYNC_SYNCPRD(val), - dmic->shim_base + DMICSYNC_OFFSET); - sys_write32(sys_read32(dmic->shim_base + DMICSYNC_OFFSET) | DMICSYNC_CMDSYNC, - dmic->shim_base + DMICSYNC_OFFSET); +#ifdef CONFIG_SOC_INTEL_ACE20_LNL + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_SYNCPRD(val), + base + DMICSYNC_OFFSET); + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_SYNCPU, + base + DMICSYNC_OFFSET); + while (sys_read32(base + DMICSYNC_OFFSET) & DMICSYNC_SYNCPU) { + k_sleep(K_USEC(100)); + } + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_CMDSYNC, + base + DMICSYNC_OFFSET); +#else /* All other CAVS and ACE platforms */ + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_SYNCPRD(val), + base + DMICSYNC_OFFSET); + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_CMDSYNC, + base + DMICSYNC_OFFSET); +#endif } static inline void dai_dmic_clear_sync_period(const struct dai_intel_dmic *dmic) { + uint32_t base = dai_dmic_base(dmic); /* DMIC Clean sync period */ - sys_write32(sys_read32(dmic->shim_base + DMICSYNC_OFFSET) & ~DMICSYNC_SYNCPRD(0x0000), - dmic->shim_base + DMICSYNC_OFFSET); - sys_write32(sys_read32(dmic->shim_base + DMICSYNC_OFFSET) & ~DMICSYNC_CMDSYNC, - dmic->shim_base + DMICSYNC_OFFSET); - + sys_write32(sys_read32(base + DMICSYNC_OFFSET) & ~DMICSYNC_SYNCPRD(0x0000), + base + DMICSYNC_OFFSET); + sys_write32(sys_read32(base + DMICSYNC_OFFSET) & ~DMICSYNC_CMDSYNC, + base + DMICSYNC_OFFSET); } /* Preparing for command synchronization on multiple link segments */ static inline void dai_dmic_sync_prepare(const struct dai_intel_dmic *dmic) { - sys_write32(sys_read32(dmic->shim_base + DMICSYNC_OFFSET) | DMICSYNC_CMDSYNC, - dmic->shim_base + DMICSYNC_OFFSET); + uint32_t base = dai_dmic_base(dmic); + + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_CMDSYNC, + base + DMICSYNC_OFFSET); } /* Trigering synchronization of command execution */ static void dmic_sync_trigger(const struct dai_intel_dmic *dmic) { - __ASSERT_NO_MSG((sys_read32(dmic->shim_base + DMICSYNC_OFFSET) & DMICSYNC_CMDSYNC) != 0); + uint32_t base = dai_dmic_base(dmic); - sys_write32(sys_read32(dmic->shim_base + DMICSYNC_OFFSET) | - DMICSYNC_SYNCGO, dmic->shim_base + DMICSYNC_OFFSET); + __ASSERT_NO_MSG((sys_read32(base + DMICSYNC_OFFSET) & DMICSYNC_CMDSYNC) != 0); + + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | + DMICSYNC_SYNCGO, base + DMICSYNC_OFFSET); /* waiting for CMDSYNC bit clearing */ - while (sys_read32(dmic->shim_base + DMICSYNC_OFFSET) & DMICSYNC_CMDSYNC) { + while (sys_read32(base + DMICSYNC_OFFSET) & DMICSYNC_CMDSYNC) { k_sleep(K_USEC(100)); } } @@ -255,28 +280,52 @@ static void dai_dmic_irq_handler(const void *data) static inline void dai_dmic_dis_clk_gating(const struct dai_intel_dmic *dmic) { /* Disable DMIC clock gating */ +#ifdef CONFIG_SOC_INTEL_ACE20_LNL /* Ace 2.0 */ + sys_write32((sys_read32(dmic->vshim_base + DMICLCTL_OFFSET) | DMIC_DCGD), + dmic->vshim_base + DMICLCTL_OFFSET); +#else sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) | DMIC_DCGD), - dmic->shim_base + DMICLCTL_OFFSET); + dmic->shim_base + DMICLCTL_OFFSET); +#endif } static inline void dai_dmic_en_clk_gating(const struct dai_intel_dmic *dmic) { /* Enable DMIC clock gating */ +#ifdef CONFIG_SOC_INTEL_ACE20_LNL /* Ace 2.0 */ + sys_write32((sys_read32(dmic->vshim_base + DMICLCTL_OFFSET) & ~DMIC_DCGD), + dmic->vshim_base + DMICLCTL_OFFSET); +#else sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) & ~DMIC_DCGD), - dmic->shim_base + DMICLCTL_OFFSET); + dmic->shim_base + DMICLCTL_OFFSET); +#endif + } static inline void dai_dmic_en_power(const struct dai_intel_dmic *dmic) { + uint32_t base = dai_dmic_base(dmic); /* Enable DMIC power */ - sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) | DMICLCTL_SPA), - dmic->shim_base + DMICLCTL_OFFSET); +#ifdef CONFIG_SOC_INTEL_ACE15_MTPM + sys_write32((sys_read32(base + DMICLCTL_OFFSET) | DMICLCTL_SPA), + base + DMICLCTL_OFFSET); +#else /* CONFIG_SOC_INTEL_ACE20_LNL */ + sys_write32((sys_read32(base + DMICLCTL_OFFSET) | + DMICLCTL_SPA | DMICLCTL_OFLEN), + base + DMICLCTL_OFFSET); +#endif /* CONFIG_SOC_INTEL_ACE20_LNL */ + while (!(sys_read32(base + DMICLCTL_OFFSET) & DMICLCTL_CPA)) { + k_sleep(K_USEC(100)); + } + } + static inline void dai_dmic_dis_power(const struct dai_intel_dmic *dmic) { + uint32_t base = dai_dmic_base(dmic); /* Disable DMIC power */ - sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) & (~DMICLCTL_SPA)), - dmic->shim_base + DMICLCTL_OFFSET); + sys_write32((sys_read32(base + DMICLCTL_OFFSET) & (~DMICLCTL_SPA)), + base + DMICLCTL_OFFSET); } static int dai_dmic_probe(struct dai_intel_dmic *dmic) @@ -759,6 +808,7 @@ static int dai_dmic_set_config(const struct device *dev, return -EINVAL; } + __ASSERT_NO_MSG(dmic->created); key = k_spin_lock(&dmic->lock); #if CONFIG_DAI_INTEL_DMIC_TPLG_PARAMS diff --git a/drivers/dai/intel/dmic/dmic.h b/drivers/dai/intel/dmic/dmic.h index 25ac98a50c8..481b369fc88 100644 --- a/drivers/dai/intel/dmic/dmic.h +++ b/drivers/dai/intel/dmic/dmic.h @@ -58,12 +58,32 @@ #define TS_LOCAL_OFFS_CLK GET_BITS(11, 0) /* Digital Mic Shim Registers */ -#define DMICLCTL_OFFSET 0x04 -#define DMICIPPTR_OFFSET 0x08 -#define DMICSYNC_OFFSET 0x0C +#define DMICLCTL_OFFSET 0x04 +#define DMICIPPTR_OFFSET 0x08 +#ifdef CONFIG_SOC_INTEL_ACE20_LNL +#define DMICSYNC_OFFSET 0x1C + +#define DMICLCTL_SPA BIT(16) +#define DMICLCTL_CPA BIT(23) +#define DMICLCTL_OFLEN BIT(4) + +/* DMIC disable clock gating */ +#define DMIC_DCGD BIT(30) + +/* DMIC Command Sync */ +#define DMICSYNC_CMDSYNC BIT(24) +/* DMIC Sync Go */ +#define DMICSYNC_SYNCGO BIT(23) +#define DMICSYNC_SYNCPU BIT(20) +/* DMIC Sync Period */ +#define DMICSYNC_SYNCPRD(x) SET_BITS(19, 0, x) +#define DMICXPCMSyCM_OFFSET 0x16 +#else /* All other CAVS and ACE platforms */ +#define DMICSYNC_OFFSET 0x0C /* DMIC power ON bit */ #define DMICLCTL_SPA BIT(0) +#define DMICLCTL_CPA BIT(8) /* DMIC Owner Select */ #define DMICLCTL_OSEL(x) SET_BITS(25, 24, x) /* DMIC disable clock gating */ @@ -75,6 +95,7 @@ #define DMICSYNC_SYNCGO BIT(24) /* DMIC Sync Period */ #define DMICSYNC_SYNCPRD(x) SET_BITS(14, 0, x) +#endif /* Parameters used in modes computation */ #define DMIC_HW_BITS_CIC 26