intel_adsp: ace20_lnl: ssp: Program new HW registers

In LNL platform GPDMA and ALH is no longer used. SSP uses LINK HDA
as a DMA engine. Therefore new shim, new register definitions and new
programming flows were defined.

This patch implements new SSP 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 <Jaroslaw.Stelter@intel.com>
This commit is contained in:
Jaroslaw Stelter 2022-11-08 12:49:44 +01:00 committed by Anas Nashif
commit 1e5550d262
2 changed files with 63 additions and 3 deletions

View file

@ -29,6 +29,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN);
#define dai_base(dai) dai->plat_data.base
#define dai_ip_base(dai) dai->plat_data.ip_base
#define dai_shim_base(dai) dai->plat_data.shim_base
#define dai_shim2_base(dai) dai->plat_data.shim2_base
#define DAI_DIR_PLAYBACK 0
#define DAI_DIR_CAPTURE 1
@ -715,7 +716,7 @@ static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t i
int ret;
LOG_INF("%s en_ssp_power index %d", __func__, index);
#if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS
sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(index),
dai_ip_base(dp) + I2SLCTL_OFFSET);
@ -723,7 +724,17 @@ static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t i
ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
I2SLCTL_CPA(index), 0,
DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
#elif CONFIG_SOC_INTEL_ACE20_LNL
sys_write32(sys_read32(dai_shim2_base(dp) + I2SLCTL_OFFSET) |
I2SLCTL_SPA(index) | I2SLCTL_OFLEN,
dai_shim2_base(dp) + I2SLCTL_OFFSET);
/* Check if powered on. */
ret = dai_ssp_poll_for_register_delay(dai_shim2_base(dp) + I2SLCTL_OFFSET,
I2SLCTL_CPA(index), 0,
DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
#else
#error need to define SOC
#endif
if (ret) {
LOG_WRN("%s warning: timeout", __func__);
}
@ -741,7 +752,7 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t
int ret;
LOG_INF("%s index %d", __func__, index);
#if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS
sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)),
dai_ip_base(dp) + I2SLCTL_OFFSET);
@ -749,7 +760,17 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t
ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
I2SLCTL_CPA(index), I2SLCTL_CPA(index),
DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
#elif CONFIG_SOC_INTEL_ACE20_LNL
sys_write32(sys_read32(dai_shim2_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)) &
(~I2SLCTL_OFLEN), dai_shim2_base(dp) + I2SLCTL_OFFSET);
/* Check if powered off. */
ret = dai_ssp_poll_for_register_delay(dai_shim2_base(dp) + I2SLCTL_OFFSET,
I2SLCTL_CPA(index), I2SLCTL_CPA(index),
DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
#else
#error need to define SOC
#endif
if (ret) {
LOG_WRN("%s warning: timeout", __func__);
}
@ -761,6 +782,28 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t
#endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */
}
static void dai_ssp_program_channel_map(struct dai_intel_ssp *dp,
const struct dai_config *cfg, uint32_t index)
{
#ifdef CONFIG_SOC_INTEL_ACE20_LNL
uint16_t pcmsycm = cfg->link_config;
if (DAI_INTEL_SSP_IS_BIT_SET(pcmsycm, 15)) {
uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS0CM_OFFSET;
/* Program HDA output stream parameters */
sys_write16((pcmsycm & 0xffff), reg_add);
} else {
uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS1CM_OFFSET;
/* Program HDA input stream parameters */
sys_write16((pcmsycm & 0xffff), reg_add);
}
#else
ARG_UNUSED(dp);
ARG_UNUSED(cfg);
ARG_UNUSED(index);
#endif /* CONFIG_SOC_INTEL_ACE20_LNL */
}
/* empty SSP transmit FIFO */
static void dai_ssp_empty_tx_fifo(struct dai_intel_ssp *dp)
{
@ -2041,8 +2084,10 @@ static int dai_ssp_config_set(const struct device *dev, const struct dai_config
struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
if (cfg->type == DAI_INTEL_SSP) {
dai_ssp_program_channel_map(dp, cfg, dp->index);
return dai_ssp_set_config_tplg(dp, cfg, bespoke_cfg);
} else {
dai_ssp_program_channel_map(dp, cfg, dp->index);
return dai_ssp_set_config_blob(dp, cfg, bespoke_cfg);
}
}
@ -2197,6 +2242,8 @@ static const char irq_name_level5_z[] = "level5";
IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(sspbase)), \
(.ip_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(sspbase), 0),)) \
.shim_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(shim), 0), \
IF_ENABLED(CONFIG_SOC_INTEL_ACE20_LNL, \
(.shim2_base = DT_INST_PROP_BY_IDX(n, shim2, 0),))\
.irq = n, \
.irq_name = irq_name_level5_z, \
.fifo[DAI_DIR_PLAYBACK].offset = \

View file

@ -21,6 +21,7 @@
(((x) & (1ULL << (b))) >> (b))
#define DAI_INTEL_SSP_GET_BITS(b_hi, b_lo, x) \
(((x) & MASK(b_hi, b_lo)) >> (b_lo))
#define DAI_INTEL_SSP_IS_BIT_SET(reg, bit) (((reg >> bit) & (0x1)) != 0)
/* ssp_freq array constants */
#define DAI_INTEL_SSP_NUM_FREQ 3
@ -216,9 +217,18 @@
#define SSP_CLK_BCLK_ACTIVE BIT(3)
#define I2SLCTL_OFFSET 0x04
#ifdef CONFIG_SOC_INTEL_ACE15_MTPM
#define I2SLCTL_SPA(x) BIT(0 + x)
#define I2SLCTL_CPA(x) BIT(8 + x)
#define I2CLCTL_MLCS(x) DAI_INTEL_SSP_SET_BITS(30, 27, x)
#else /* CONFIG_SOC_INTEL_ACE20_LNL */
#define I2SLCTL_OFLEN BIT(4)
#define I2SLCTL_SPA(x) BIT(16 + x)
#define I2SLCTL_CPA(x) BIT(23 + x)
#define PCMS0CM_OFFSET 0x16
#define PCMS1CM_OFFSET 0x1A
#endif /* CONFIG_SOC_INTEL_ACE15_MTPM */
#define SHIM_CLKCTL 0x78
#define SHIM_CLKCTL_I2SFDCGB(x) BIT(20 + x)
@ -307,6 +317,9 @@ struct dai_intel_ssp_plat_data {
uint32_t base;
uint32_t ip_base;
uint32_t shim_base;
#ifdef CONFIG_SOC_INTEL_ACE20_LNL
uint32_t shim2_base;
#endif
int irq;
const char *irq_name;
uint32_t flags;