From e90b5c70bb7f7cc119bd66bff1635854af623576 Mon Sep 17 00:00:00 2001 From: Damian Nikodem Date: Sun, 24 Mar 2024 19:13:13 +0100 Subject: [PATCH] driver: ssp: update Intel SSP DAI driver to support dynamic SSP link management This commit refactors the Intel SSP DAI driver to support dynamic management of SSP links. The changes include the introduction of a new structure `intel_ssp_link` to encapsulate SSP link-specific data. Key changes: - Add new static functions to manage SSP link power. - Update the DAI SSP configuration functions to use the new link management approach. - Update device tree bindings and instances to reflect the new SSP link management mechanism. The new approach allows for more flexible and maintainable management of SSP links. Signed-off-by: Damian Nikodem --- drivers/dai/intel/ssp/ssp.c | 665 +++++++++++--------- drivers/dai/intel/ssp/ssp.h | 17 +- dts/bindings/i2s/intel,ssp-dai.yaml | 20 +- dts/bindings/i2s/intel,ssp-link.yaml | 32 + dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi | 78 ++- dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi | 76 ++- dts/xtensa/intel/intel_adsp_cavs25.dtsi | 77 ++- tests/boards/intel_adsp/ssp/src/main.c | 2 +- 8 files changed, 630 insertions(+), 337 deletions(-) create mode 100644 dts/bindings/i2s/intel,ssp-link.yaml diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index 447a31c235f872..4744c90404c3e5 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -18,24 +18,119 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include "ssp.h" -#define DT_DRV_COMPAT intel_ssp_dai #define dai_set_drvdata(dai, data) (dai->priv_data = data) #define dai_get_drvdata(dai) dai->priv_data -#define dai_get_mn(dai) dai->plat_data.mn_inst -#define dai_get_ftable(dai) dai->plat_data.ftable -#define dai_get_fsources(dai) dai->plat_data.fsources -#define dai_mn_base(dai) dai->plat_data.mn_inst->base -#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_hdamlssp_base(dai) dai->plat_data.hdamlssp_base -#define dai_i2svss_base(dai) dai->plat_data.i2svss_base +#define dai_get_ssp_link(dai) dai->ssp_link +#define dai_get_mn(dai) dai->ssp_link->ssp_plat_data.mn_inst +#define dai_get_ftable(dai) dai->ssp_link->ssp_plat_data.ftable +#define dai_get_fsources(dai) dai->ssp_link->ssp_plat_data.fsources +#define dai_mn_base(dai) dai->ssp_link->ssp_plat_data.mn_inst->base +#define dai_base(dai) dai->ssp_link->ssp_plat_data.base +#define dai_ip_base(dai) dai->ssp_link->ssp_plat_data.ip_base +#define dai_shim_base(dai) dai->ssp_link->ssp_plat_data.shim_base +#define dai_hdamlssp_base(dai) dai->ssp_link->ssp_plat_data.hdamlssp_base +#define dai_i2svss_base(dai) dai->ssp_link->ssp_plat_data.i2svss_base #define DAI_DIR_PLAYBACK 0 #define DAI_DIR_CAPTURE 1 #define SSP_ARRAY_INDEX(dir) dir == DAI_DIR_RX ? DAI_DIR_CAPTURE : DAI_DIR_PLAYBACK +static const char irq_name_level5_z[] = "level5"; + +static struct dai_intel_ssp_freq_table ssp_freq_table[] = { + { DT_PROP(DT_NODELABEL(audioclk), clock_frequency), + DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000}, + { DT_PROP(DT_NODELABEL(sysclk), clock_frequency), + DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000}, + { DT_PROP(DT_NODELABEL(pllclk), clock_frequency), + DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000}, +}; + +static uint32_t ssp_freq_sources[] = { + DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL, + DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR, + DAI_INTEL_SSP_CLOCK_PLL_FIXED, +}; + +static struct dai_intel_ssp_mn ssp_mn_divider = { + .base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssplink0), 1), +}; + +#define INTEL_SSP_LINK_INST_DEFINE(node_id) { \ + .link_index = DT_PROP(node_id, link), \ + .acquire_count = 0, \ + .is_power_en = 0, \ + .is_initialized = false, \ + .ssp_plat_data = { \ + .base = DT_REG_ADDR_BY_IDX(node_id, 0), \ + 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(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)), \ + (.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),)) \ + IF_ENABLED(DT_PROP_HAS_IDX(node_id, i2svss, 0), \ + (.i2svss_base = DT_PROP_BY_IDX(node_id, i2svss, 0),)) \ + .irq = DT_NUM_IRQS(node_id), \ + .irq_name = irq_name_level5_z, \ + .fifo[DAI_DIR_PLAYBACK].offset = \ + DT_REG_ADDR_BY_IDX(node_id, 0) + SSDR, \ + .fifo[DAI_DIR_PLAYBACK].handshake = \ + DT_DMAS_CELL_BY_NAME(node_id, tx, channel), \ + .fifo[DAI_DIR_CAPTURE].offset = \ + DT_REG_ADDR_BY_IDX(node_id, 0) + SSDR, \ + .fifo[DAI_DIR_CAPTURE].handshake = \ + DT_DMAS_CELL_BY_NAME(node_id, rx, channel), \ + .mn_inst = &ssp_mn_divider, \ + .ftable = ssp_freq_table, \ + .fsources = ssp_freq_sources, \ + .clk_active = 0, \ + }, \ +}, + +static struct intel_ssp_link ssp_link_table[] = { + DT_FOREACH_STATUS_OKAY(intel_ssp_link, INTEL_SSP_LINK_INST_DEFINE) +}; + +static uint32_t ssp_get_link_count(void) +{ + return ARRAY_SIZE(ssp_link_table); +} + + +static struct intel_ssp_link *ssp_get_link(uint32_t link_index) +{ + uint32_t link_count = ssp_get_link_count(); + uint32_t i; + + for (i = 0; i < link_count; i++) { + if (ssp_link_table[i].link_index == link_index) { + return &ssp_link_table[i]; + } + } + + return NULL; +} + +static void ssp_acquire_link(struct intel_ssp_link *link) +{ + link->acquire_count++; +} + +static void ssp_release_link(struct intel_ssp_link *link) +{ + if (link->acquire_count == 0) { + return; + } + + --link->acquire_count; +} + +static bool ssp_link_is_acquired(struct intel_ssp_link *link) +{ + return (link->acquire_count != 0); +} + static void dai_ssp_update_bits(struct dai_intel_ssp *dp, uint32_t reg, uint32_t mask, uint32_t val) { uint32_t dest = dai_base(dp) + reg; @@ -629,14 +724,14 @@ static int dai_ssp_mn_set_bclk(struct dai_intel_ssp *dp, uint32_t dai_index, uin return ret; } -static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t dai_index) +static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t link_index) { struct dai_intel_ssp_mn *mp = dai_get_mn(dp); k_spinlock_key_t key; bool mn_in_use; key = k_spin_lock(&mp->lock); - mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE; + mp->bclk_sources[link_index] = MN_BCLK_SOURCE_NONE; mn_in_use = dai_ssp_is_bclk_source_in_use(dp, MN_BCLK_SOURCE_MN); /* release the M/N clock source if not used */ @@ -647,15 +742,15 @@ static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t dai_index k_spin_unlock(&mp->lock, key); } -static void dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp *dp, uint32_t dai_index) +static void dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp *dp, uint32_t link_index) { struct dai_intel_ssp_mn *mp = dai_get_mn(dp); k_spinlock_key_t key; key = k_spin_lock(&mp->lock); - sys_write32(1, dai_mn_base(dp) + MN_MDIV_M_VAL(dai_index)); - sys_write32(1, dai_mn_base(dp) + MN_MDIV_N_VAL(dai_index)); + sys_write32(1, dai_mn_base(dp) + MN_MDIV_M_VAL(link_index)); + sys_write32(1, dai_mn_base(dp) + MN_MDIV_N_VAL(link_index)); k_spin_unlock(&mp->lock, key); } @@ -672,131 +767,131 @@ static int dai_ssp_poll_for_register_delay(uint32_t reg, uint32_t mask, return 0; } -static inline void dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index) +static inline void dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp *dp, + uint32_t link_index) { #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING uint32_t shim_reg; shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) | - (index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? - SHIM_CLKCTL_I2SFDCGB(index) : - SHIM_CLKCTL_I2SEFDCGB(index - + (link_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? + SHIM_CLKCTL_I2SFDCGB(link_index) : + SHIM_CLKCTL_I2SEFDCGB(link_index - CONFIG_DAI_INTEL_SSP_NUM_BASE)); sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL); - LOG_INF("index %d CLKCTL %08x", index, shim_reg); + LOG_INF("link_index %d CLKCTL %08x", link_index, shim_reg); #endif } -static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index) +static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp, + uint32_t link_index) { #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING uint32_t shim_reg; shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) & - ~(index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? - SHIM_CLKCTL_I2SFDCGB(index) : - SHIM_CLKCTL_I2SEFDCGB(index - + ~(link_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? + SHIM_CLKCTL_I2SFDCGB(link_index) : + SHIM_CLKCTL_I2SEFDCGB(link_index - CONFIG_DAI_INTEL_SSP_NUM_BASE)); sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL); - LOG_INF("index %d CLKCTL %08x", index, shim_reg); + LOG_INF("link_index %d CLKCTL %08x", link_index, shim_reg); #endif } -static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t index) +static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t link_index) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP link %d", link_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), + sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(link_index), dai_ip_base(dp) + I2SLCTL_OFFSET); /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(link_index), I2SLCTL_CPA(link_index), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) | - I2SLCTL_SPA(index), + I2SLCTL_SPA(link_index), dai_hdamlssp_base(dp) + I2SLCTL_OFFSET); /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(link_index), I2SLCTL_CPA(link_index), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC #endif if (ret) { - LOG_WRN("SSP%d: timeout", dp->index); + LOG_WRN("SSP link %d: timeout", link_index); } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(link_index); #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */ } -static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t index) +static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t link_index) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP link %d", link_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)), + sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(link_index)), dai_ip_base(dp) + I2SLCTL_OFFSET); /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(link_index), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL - sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)), + sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(link_index)), dai_hdamlssp_base(dp) + I2SLCTL_OFFSET); /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(link_index), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC #endif if (ret) { - LOG_WRN("SSP%d: timeout", dp->index); + LOG_WRN("SSP link %d: timeout", link_index); } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(link_index); #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) + const struct dai_config *cfg, uint32_t link_index) { #ifdef CONFIG_SOC_INTEL_ACE20_LNL uint16_t pcmsycm = cfg->link_config; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + /* Set upper slot number from configuration */ + pcmsycm = pcmsycm | (dp->ssp_link->params.tdm_slots - 1) << 4; - /* Set upper slot number from configuration */ - pcmsycm = pcmsycm | (ssp->params.tdm_slots - 1) << 4; - - if (DAI_INTEL_SSP_IS_BIT_SET(pcmsycm, 15)) { - uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS0CM_OFFSET; + if (DAI_INTEL_SSP_IS_BIT_SET(cfg->link_config, 15)) { + uint32_t reg_add = dai_ip_base(dp) + 0x1000 * link_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; + uint32_t reg_add = dai_ip_base(dp) + 0x1000 * link_index + PCMS1CM_OFFSET; /* Program HDA input stream parameters */ sys_write16((pcmsycm & 0xffff), reg_add); } #else ARG_UNUSED(dp); ARG_UNUSED(cfg); - ARG_UNUSED(index); + ARG_UNUSED(link_index); #endif /* CONFIG_SOC_INTEL_ACE20_LNL */ } @@ -859,8 +954,9 @@ static void ssp_empty_rx_fifo_on_start(struct dai_intel_ssp *dp) static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - uint64_t sample_ticks = ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0; + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); + uint64_t sample_ticks = ssp_link->params.fsync_rate ? + 1000000 / ssp_link->params.fsync_rate : 0; uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX; uint32_t entries[2]; uint32_t i, sssr; @@ -900,20 +996,20 @@ static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp) static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); int ret; - if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE) { + if (ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ACTIVE) { return 0; } /* MCLK config */ - ret = dai_ssp_mn_set_mclk(dp, ssp->params.mclk_id, ssp->params.mclk_rate); + ret = dai_ssp_mn_set_mclk(dp, ssp_link->params.mclk_id, ssp_link->params.mclk_rate); if (ret < 0) { - LOG_ERR("invalid mclk_rate = %d for mclk_id = %d", ssp->params.mclk_rate, - ssp->params.mclk_id); + LOG_ERR("invalid mclk_rate = %d for mclk_id = %d", ssp_link->params.mclk_rate, + ssp_link->params.mclk_id); } else { - ssp->clk_active |= SSP_CLK_MCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_MCLK_ACTIVE; } return ret; @@ -921,15 +1017,15 @@ static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp) static void dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); - if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ACTIVE)) { return; } - dai_ssp_mn_release_mclk(dp, ssp->params.mclk_id); + dai_ssp_mn_release_mclk(dp, ssp_link->params.mclk_id); - ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_MCLK_ACTIVE; } static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) @@ -937,14 +1033,13 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) #if !(CONFIG_INTEL_MN) struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp); #endif - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - struct dai_config *config = &ssp->config; + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); uint32_t sscr0; uint32_t mdiv; bool need_ecs = false; int ret = 0; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE) { return 0; } @@ -952,22 +1047,22 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) #if CONFIG_INTEL_MN /* BCLK config */ - ret = dai_ssp_mn_set_bclk(dp, config->dai_index, ssp->params.bclk_rate, + ret = dai_ssp_mn_set_bclk(dp, dp->link_index, ssp_link->params.bclk_rate, &mdiv, &need_ecs); if (ret < 0) { - LOG_ERR("invalid bclk_rate = %d for dai_index = %d", - ssp->params.bclk_rate, config->dai_index); + LOG_ERR("invalid bclk_rate = %d for link_index = %d", + ssp_link->params.bclk_rate, dp->link_index); goto out; } #else - if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp->params.bclk_rate != 0) { - LOG_ERR("invalid bclk_rate = %d for dai_index = %d", - ssp->params.bclk_rate, config->dai_index); + if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp_link->params.bclk_rate != 0) { + LOG_ERR("invalid bclk_rate = %d for link_index = %d", + ssp_link->params.bclk_rate, dp->link_index); ret = -EINVAL; goto out; } - mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp->params.bclk_rate; + mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp_link->params.bclk_rate; #endif if (need_ecs) { @@ -993,7 +1088,7 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) LOG_INF("sscr0 = 0x%08x", sscr0); out: if (!ret) { - ssp->clk_active |= SSP_CLK_BCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_BCLK_ACTIVE; } return ret; @@ -1001,29 +1096,30 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) static void dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE)) { return; } #if CONFIG_INTEL_MN - dai_ssp_mn_release_bclk(dp, dp->index); + dai_ssp_mn_release_bclk(dp, ssp_link->link_index); #endif - ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_BCLK_ACTIVE; } static void dai_ssp_log_ssp_data(struct dai_intel_ssp *dp) { - LOG_INF("dai index: %u", dp->index); - LOG_INF("plat_data base: %u", dp->plat_data.base); - LOG_INF("plat_data irq: %u", dp->plat_data.irq); - LOG_INF("plat_data fifo playback offset: %u", dp->plat_data.fifo[DAI_DIR_PLAYBACK].offset); + LOG_INF("dai index: %u", dp->dai_index); + LOG_INF("plat_data base: %u", dp->ssp_link->ssp_plat_data.base); + LOG_INF("plat_data irq: %u", dp->ssp_link->ssp_plat_data.irq); + LOG_INF("plat_data fifo playback offset: %u", + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_PLAYBACK].offset); LOG_INF("plat_data fifo playback handshake: %u", - dp->plat_data.fifo[DAI_DIR_PLAYBACK].handshake); + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_PLAYBACK].handshake); LOG_INF("plat_data fifo capture offset: %u", - dp->plat_data.fifo[DAI_DIR_CAPTURE].offset); + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_CAPTURE].offset); LOG_INF("plat_data fifo capture handshake: %u", - dp->plat_data.fifo[DAI_DIR_CAPTURE].handshake); + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_CAPTURE].handshake); } /* Digital Audio interface formatting */ @@ -1031,6 +1127,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co const void *bespoke_cfg) { struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp); uint32_t sscr0; uint32_t sscr1; @@ -1066,14 +1163,16 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co key = k_spin_lock(&dp->lock); /* ignore config if SSP is already configured */ - if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || - ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) { - if (!memcmp(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params))) { + if (dp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || + dp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) { + if (!memcmp(&ssp_link->params, bespoke_cfg, + sizeof(struct dai_intel_ipc3_ssp_params))) { LOG_INF("Already configured. Ignore config"); goto clk; } - if (ssp->clk_active & (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) { + if (ssp_link->ssp_plat_data.clk_active & + (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) { LOG_WRN("SSP active, cannot change config"); goto clk; } @@ -1081,7 +1180,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* safe to proceed and change HW config */ } - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP%d", dp->dai_index); /* reset SSP settings */ /* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */ @@ -1104,7 +1203,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sspsp = 0; ssp->config = *config; - memcpy(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params)); + memcpy(&ssp_link->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params)); /* sspsp2 no dynamic setting */ sspsp2 = 0x0; @@ -1116,10 +1215,10 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co ssto = 0x0; /* sstsa dynamic setting is TTSA, default 2 slots */ - sstsa = SSTSA_SSTSA(ssp->params.tx_slots); + sstsa = SSTSA_SSTSA(ssp_link->params.tx_slots); /* ssrsa dynamic setting is RTSA, default 2 slots */ - ssrsa = SSRSA_SSRSA(ssp->params.rx_slots); + ssrsa = SSRSA_SSRSA(ssp_link->params.rx_slots); switch (config->format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) { case DAI_INTEL_IPC3_SSP_FMT_CBP_CFP: @@ -1166,7 +1265,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co } /* supporting bclk idle state */ - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) { + if (ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) { /* bclk idle state high */ sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3); } else { @@ -1179,20 +1278,20 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* Additional hardware settings */ /* Receiver Time-out Interrupt Disabled/Enabled */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ? + sscr1 |= (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ? SSCR1_TINTE : 0; /* Peripheral Trailing Byte Interrupts Disable/Enable */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ? + sscr1 |= (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ? SSCR1_PINTE : 0; /* Enable/disable internal loopback. Output of transmit serial * shifter connected to input of receive serial shifter, internally. */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ? + sscr1 |= (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ? SSCR1_LBM : 0; - if (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { + if (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { LOG_INF("going for loopback!"); } else { LOG_INF("no loopback!"); @@ -1201,69 +1300,70 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* Transmit data are driven at the same/opposite clock edge specified * in SSPSP.SCMODE[1:0] */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ? + sscr2 |= (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ? SSCR2_SMTATF : 0; /* Receive data are sampled at the same/opposite clock edge specified * in SSPSP.SCMODE[1:0] */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ? + sscr2 |= (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ? SSCR2_MMRATF : 0; /* Enable/disable the fix for PSP consumer mode TXD wait for frame * de-assertion before starting the second channel */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ? + sscr2 |= (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ? SSCR2_PSPSTWFDFD : 0; /* Enable/disable the fix for PSP provider mode FSRT with dummy stop & * frame end padding capability */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ? + sscr2 |= (ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ? SSCR2_PSPSRWFDFD : 0; - if (!ssp->params.mclk_rate || - ssp->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) { - LOG_ERR("invalid MCLK = %d Hz (valid < %d)", ssp->params.mclk_rate, + if (!ssp_link->params.mclk_rate || + ssp_link->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) { + LOG_ERR("invalid MCLK = %d Hz (valid < %d)", ssp_link->params.mclk_rate, ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq); ret = -EINVAL; goto out; } - if (!ssp->params.bclk_rate || ssp->params.bclk_rate > ssp->params.mclk_rate) { - LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", ssp->params.bclk_rate, - ssp->params.mclk_rate); + if (!ssp_link->params.bclk_rate || + ssp_link->params.bclk_rate > ssp_link->params.mclk_rate) { + LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", ssp_link->params.bclk_rate, + ssp_link->params.mclk_rate); ret = -EINVAL; goto out; } /* calc frame width based on BCLK and rate - must be divisible */ - if (ssp->params.bclk_rate % ssp->params.fsync_rate) { - LOG_ERR("BCLK %d is not divisible by rate %d", ssp->params.bclk_rate, - ssp->params.fsync_rate); + if (ssp_link->params.bclk_rate % ssp_link->params.fsync_rate) { + LOG_ERR("BCLK %d is not divisible by rate %d", ssp_link->params.bclk_rate, + ssp_link->params.fsync_rate); ret = -EINVAL; goto out; } /* must be enough BCLKs for data */ - bdiv = ssp->params.bclk_rate / ssp->params.fsync_rate; - if (bdiv < ssp->params.tdm_slot_width * ssp->params.tdm_slots) { + bdiv = ssp_link->params.bclk_rate / ssp_link->params.fsync_rate; + if (bdiv < ssp_link->params.tdm_slot_width * ssp_link->params.tdm_slots) { LOG_ERR("not enough BCLKs need %d", - ssp->params.tdm_slot_width * ssp->params.tdm_slots); + ssp_link->params.tdm_slot_width * ssp_link->params.tdm_slots); ret = -EINVAL; goto out; } /* tdm_slot_width must be <= 38 for SSP */ - if (ssp->params.tdm_slot_width > 38) { - LOG_ERR("tdm_slot_width %d > 38", ssp->params.tdm_slot_width); + if (ssp_link->params.tdm_slot_width > 38) { + LOG_ERR("tdm_slot_width %d > 38", ssp_link->params.tdm_slot_width); ret = -EINVAL; goto out; } - bdiv_min = ssp->params.tdm_slots * - (ssp->params.tdm_per_slot_padding_flag ? - ssp->params.tdm_slot_width : ssp->params.sample_valid_bits); + bdiv_min = ssp_link->params.tdm_slots * + (ssp_link->params.tdm_per_slot_padding_flag ? + ssp_link->params.tdm_slot_width : ssp_link->params.sample_valid_bits); if (bdiv < bdiv_min) { LOG_ERR("bdiv(%d) < bdiv_min(%d)", bdiv, bdiv_min); ret = -EINVAL; @@ -1283,7 +1383,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co start_delay = true; - sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_FRDC(ssp_link->params.tdm_slots); if (bdiv % 2) { LOG_ERR("bdiv %d is not divisible by 2", bdiv); @@ -1331,7 +1431,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* default start_delay value is set to false */ - sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_FRDC(ssp_link->params.tdm_slots); /* LJDFD enable */ sscr2 &= ~SSCR2_LJDFD; @@ -1387,19 +1487,19 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* default start_delay value is set to false */ - sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp_link->params.tdm_slots); /* set asserted frame length */ frame_len = 1; /* default */ - if (cfs && ssp->params.frame_pulse_width > 0 && - ssp->params.frame_pulse_width <= + if (cfs && ssp_link->params.frame_pulse_width > 0 && + ssp_link->params.frame_pulse_width <= DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) { - frame_len = ssp->params.frame_pulse_width; + frame_len = ssp_link->params.frame_pulse_width; } /* frame_pulse_width must less or equal 38 */ - if (ssp->params.frame_pulse_width > + if (ssp_link->params.frame_pulse_width > DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) { LOG_ERR("frame_pulse_width > %d", DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX); ret = -EINVAL; @@ -1413,20 +1513,20 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co */ sspsp |= SSPSP_SFRMP(!inverted_frame); - active_tx_slots = POPCOUNT(ssp->params.tx_slots); - active_rx_slots = POPCOUNT(ssp->params.rx_slots); + active_tx_slots = POPCOUNT(ssp_link->params.tx_slots); + active_rx_slots = POPCOUNT(ssp_link->params.rx_slots); /* * handle TDM mode, TDM mode has padding at the end of * each slot. The amount of padding is equal to result of * subtracting slot width and valid bits per slot. */ - if (ssp->params.tdm_per_slot_padding_flag) { - frame_end_padding = bdiv - ssp->params.tdm_slots * - ssp->params.tdm_slot_width; + if (ssp_link->params.tdm_per_slot_padding_flag) { + frame_end_padding = bdiv - ssp_link->params.tdm_slots * + ssp_link->params.tdm_slot_width; - slot_end_padding = ssp->params.tdm_slot_width - - ssp->params.sample_valid_bits; + slot_end_padding = ssp_link->params.tdm_slot_width - + ssp_link->params.sample_valid_bits; if (slot_end_padding > DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) { @@ -1456,7 +1556,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sspsp |= SSPSP_SFRMWDTH(frame_len); - data_size = ssp->params.sample_valid_bits; + data_size = ssp_link->params.sample_valid_bits; if (data_size > 16) { sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16)); @@ -1465,7 +1565,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co } /* setting TFT and RFT */ - switch (ssp->params.sample_valid_bits) { + switch (ssp_link->params.sample_valid_bits) { case 16: /* use 2 bytes for each slot */ sample_width = 2; @@ -1476,7 +1576,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sample_width = 4; break; default: - LOG_ERR("sample_valid_bits %d", ssp->params.sample_valid_bits); + LOG_ERR("sample_valid_bits %d", ssp_link->params.sample_valid_bits); ret = -EINVAL; goto out; } @@ -1506,27 +1606,28 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co LOG_INF("ssrsa = 0x%08x, sstsa = 0x%08x", ssrsa, sstsa); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; clk: switch (config->options & DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_CMD_MASK) { case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS: - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { + if (ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { ret = dai_ssp_mclk_prepare_enable(dp); if (ret < 0) { goto out; } - ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_MCLK_ES_REQ; - LOG_INF("hw_params stage: enabled MCLK clocks for SSP%d...", dp->index); + LOG_INF("hw_params stage: enabled MCLK clocks for SSP link %d...", + dp->link_index); } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + if (ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { bool enable_sse = false; - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE)) { enable_sse = true; } @@ -1535,39 +1636,43 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co goto out; } - ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_BCLK_ES_REQ; if (enable_sse) { /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); - LOG_INF("SSE set for SSP%d", dp->index); + LOG_INF("SSE set for SSP%d", ssp_link->link_index); } - LOG_INF("hw_params stage: enabled BCLK clocks for SSP%d...", dp->index); + LOG_INF("hw_params stage: enabled BCLK clocks for SSP link %d...", + ssp_link->link_index); } break; case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_FREE: /* disable SSP port if no users */ - if (ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING || - ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { - LOG_INF("hw_free stage: ignore since SSP%d still in use", dp->index); + if (dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING || + dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + LOG_INF("hw_free stage: ignore since link SSP%d still in use", + ssp_link->link_index); break; } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { - LOG_INF("hw_free stage: releasing BCLK clocks for SSP%d...", dp->index); - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + LOG_INF("hw_free stage: releasing BCLK clocks for SSP link %d...", + ssp_link->link_index); + if (ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE) { dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); - LOG_INF("SSE clear for SSP%d", dp->index); + LOG_INF("SSE clear for link SSP%d", ssp_link->link_index); } dai_ssp_bclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_BCLK_ES_REQ; } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { - LOG_INF("hw_free stage: releasing MCLK clocks for SSP%d...", dp->index); + if (ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { + LOG_INF("hw_free stage: releasing MCLK clocks for link SSP%d...", + ssp_link->link_index); dai_ssp_mclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_MCLK_ES_REQ; } break; default: @@ -1756,7 +1861,6 @@ static int dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp *dp, static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_config *cfg, const struct dai_intel_ipc4_ssp_config *regs) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); uint32_t ssc0, sstsa, ssrsa, sscr1; ssc0 = regs->ssc0; @@ -1764,7 +1868,7 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co ssrsa = SSRSA_GET(regs->ssrsa); sscr1 = regs->ssc1 & ~(SSCR1_RSRE | SSCR1_TSRE); - LOG_ERR("SSP%d configuration:", dp->index); + LOG_ERR("SSP%d configuration:", dp->dai_index); if (regs->sstsa & SSTSA_TXEN || regs->ssrsa & SSRSA_RXEN || regs->ssc1 & (SSCR1_RSRE | SSCR1_TSRE)) { LOG_INF(" Ignoring %s%s%s%sfrom blob", @@ -1794,18 +1898,18 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co LOG_INF(" ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x", regs->ssioc, ssrsa, sstsa); - ssp->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0); + dp->ssp_link->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0); if (ssc0 & SSCR0_EDSS) { - ssp->params.sample_valid_bits += 16; + dp->ssp_link->params.sample_valid_bits += 16; } - ssp->params.tdm_slots = SSCR0_FRDC_GET(ssc0); - ssp->params.tx_slots = SSTSA_GET(sstsa); - ssp->params.rx_slots = SSRSA_GET(ssrsa); - ssp->params.fsync_rate = cfg->rate; + dp->ssp_link->params.tdm_slots = SSCR0_FRDC_GET(ssc0); + dp->ssp_link->params.tx_slots = SSTSA_GET(sstsa); + dp->ssp_link->params.rx_slots = SSRSA_GET(ssrsa); + dp->ssp_link->params.fsync_rate = cfg->rate; - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; } static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_config *cfg, @@ -1813,13 +1917,15 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co { const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob15 = spec_config; const struct dai_intel_ipc4_ssp_configuration_blob *blob = spec_config; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); int err; /* set config only once for playback or capture */ - if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || - ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) + if (ssp_link->is_initialized) { + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; return 0; + } if (blob15->version == SSP_BLOB_VER_1_5) { err = dai_ssp_parse_aux_data(dp, spec_config); @@ -1836,11 +1942,12 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co return err; } - ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_MCLK_ES_REQ; /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); - ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_link->is_initialized = true; return 0; } @@ -1852,14 +1959,14 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co */ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); int ret = 0; /* * We will test if mclk/bclk is configured in * ssp_mclk/bclk_prepare_enable/disable functions */ - if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ES_REQ)) { /* MCLK config */ ret = dai_ssp_mclk_prepare_enable(dp); if (ret < 0) { @@ -1867,7 +1974,7 @@ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) } } - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)) { ret = dai_ssp_bclk_prepare_enable(dp); } @@ -1881,17 +1988,17 @@ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) */ static void dai_ssp_post_stop(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); /* release clocks if SSP is inactive */ - if (ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING && - ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) { - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { - LOG_INF("releasing BCLK clocks for SSP%d...", dp->index); + if (dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING && + dp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)) { + LOG_INF("releasing BCLK clocks for SSP%d...", ssp_link->link_index); dai_ssp_bclk_disable_unprepare(dp); } - if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) { - LOG_INF("releasing MCLK clocks for SSP%d...", dp->index); + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ES_REQ)) { + LOG_INF("releasing MCLK clocks for SSP%d...", ssp_link->link_index); dai_ssp_mclk_disable_unprepare(dp); } } @@ -1899,25 +2006,25 @@ static void dai_ssp_post_stop(struct dai_intel_ssp *dp) static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); k_spinlock_key_t key; key = k_spin_lock(&dp->lock); /* RX fifo must be cleared before start */ if (direction == DAI_DIR_CAPTURE) { - LOG_INF("SSP%d RX", dp->index); + LOG_INF("SSP%d RX", dp->dai_index); ssp_empty_rx_fifo_on_start(dp); } else { - LOG_INF("SSP%d TX", dp->index); + LOG_INF("SSP%d TX", dp->dai_index); } /* request mclk/bclk */ dai_ssp_pre_start(dp); - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)) { /* enable port */ - LOG_INF("SSP%d: set SSE", dp->index); + LOG_INF("SSP%d: set SSE", ssp_link->link_index); dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); } @@ -1935,16 +2042,17 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) { - LOG_INF("SSP%d TX", dp->index); + LOG_INF("SSP%d TX", dp->dai_index); dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, SSCR1_TSRE); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, SSTSA_TXEN); } else { - LOG_INF("SSP%d RX", dp->index); + LOG_INF("SSP%d RX", dp->dai_index); dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, SSCR1_RSRE); dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN); } - ssp->state[direction] = DAI_STATE_RUNNING; + dp->state[direction] = DAI_STATE_RUNNING; + ssp_acquire_link(dp->ssp_link); /* * Wait to get valid fifo status in clock consumer mode. TODO it's @@ -1968,6 +2076,7 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) { struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); k_spinlock_key_t key; key = k_spin_lock(&dp->lock); @@ -1988,64 +2097,68 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) /* stop Rx if neeed */ if (direction == DAI_DIR_CAPTURE && - ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { - LOG_INF("SSP%d RX", dp->index); + dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { + LOG_INF("SSP%d RX", dp->dai_index); dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0); dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, 0); ssp_empty_rx_fifo_on_stop(dp); - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + ssp_release_link(ssp_link); } /* stop Tx if needed */ if (direction == DAI_DIR_PLAYBACK && - ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { - LOG_INF("SSP%d TX", dp->index); + dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + LOG_INF("SSP%d TX", dp->dai_index); dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, 0); dai_ssp_empty_tx_fifo(dp); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, 0); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + ssp_release_link(ssp_link); } /* disable SSP port if no users */ - if (ssp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING && - ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING && + if (dp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING && + dp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING && COND_CODE_1(CONFIG_INTEL_ADSP_CAVS, - (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { - LOG_INF("SSP%d: clear SSE", dp->index); - dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { + + if (!ssp_link_is_acquired(ssp_link)) { + dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + LOG_INF("%s SSE clear SSP%d", __func__, ssp_link->link_index); + } } - dai_ssp_post_stop(dp); + if (!ssp_link_is_acquired(ssp_link)) { + dai_ssp_post_stop(dp); + } k_spin_unlock(&dp->lock, key); } static void dai_ssp_pause(struct dai_intel_ssp *dp, int direction) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - if (direction == DAI_DIR_CAPTURE) { - LOG_INF("SSP%d RX", dp->index); + LOG_INF("SSP%d RX", dp->dai_index); } else { - LOG_INF("SSP%d TX", dp->index); + LOG_INF("SSP%d TX", dp->dai_index); } - ssp->state[direction] = DAI_STATE_PAUSED; + dp->state[direction] = DAI_STATE_PAUSED; } static int dai_ssp_trigger(const struct device *dev, enum dai_dir dir, enum dai_trigger_cmd cmd) { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); int array_index = SSP_ARRAY_INDEX(dir); - LOG_DBG("SSP%d: cmd %d", dp->index, cmd); + LOG_DBG("SSP%d: cmd %d", dp->dai_index, cmd); switch (cmd) { case DAI_TRIGGER_START: - if (ssp->state[array_index] == DAI_STATE_PAUSED || - ssp->state[array_index] == DAI_STATE_PRE_RUNNING) { + if (dp->state[array_index] == DAI_STATE_PAUSED || + dp->state[array_index] == DAI_STATE_PRE_RUNNING) { dai_ssp_start(dp, array_index); } break; @@ -2070,6 +2183,7 @@ static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, struct dai_config *params = (struct dai_config *)dev->config; struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); if (!cfg) { return -EINVAL; @@ -2080,15 +2194,15 @@ static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, return 0; } - params->rate = ssp->params.fsync_rate; + params->rate = ssp_link->params.fsync_rate; if (dir == DAI_DIR_PLAYBACK) { - params->channels = POPCOUNT(ssp->params.tx_slots); + params->channels = POPCOUNT(ssp_link->params.tx_slots); } else { - params->channels = POPCOUNT(ssp->params.rx_slots); + params->channels = POPCOUNT(ssp_link->params.rx_slots); } - params->word_size = ssp->params.sample_valid_bits; + params->word_size = ssp_link->params.sample_valid_bits; *cfg = *params; @@ -2106,7 +2220,7 @@ static int dai_ssp_config_set(const struct device *dev, const struct dai_config } else { ret = dai_ssp_set_config_blob(dp, cfg, bespoke_cfg); } - dai_ssp_program_channel_map(dp, cfg, dp->index); + dai_ssp_program_channel_map(dp, cfg, dp->link_index); return ret; } @@ -2115,19 +2229,20 @@ static const struct dai_properties *dai_ssp_get_properties(const struct device * { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); struct dai_properties *prop = &ssp->props; int array_index = SSP_ARRAY_INDEX(dir); - prop->fifo_address = dp->plat_data.fifo[array_index].offset; - prop->dma_hs_id = dp->plat_data.fifo[array_index].handshake; + prop->fifo_address = ssp_link->ssp_plat_data.fifo[array_index].offset; + prop->dma_hs_id = ssp_link->ssp_plat_data.fifo[array_index].handshake; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE) { prop->reg_init_delay = 0; } else { - prop->reg_init_delay = ssp->params.bclk_delay; + prop->reg_init_delay = ssp_link->params.bclk_delay; } - LOG_INF("SSP%u: fifo %u, handshake %u, init delay %u", dp->index, prop->fifo_address, + LOG_INF("SSP%u: fifo %u, handshake %u, init delay %u", dp->dai_index, prop->fifo_address, prop->dma_hs_id, prop->reg_init_delay); return prop; @@ -2135,6 +2250,7 @@ static const struct dai_properties *dai_ssp_get_properties(const struct device * static int dai_ssp_probe(struct dai_intel_ssp *dp) { + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); struct dai_intel_ssp_pdata *ssp; if (dai_get_drvdata(dp)) { @@ -2144,41 +2260,58 @@ static int dai_ssp_probe(struct dai_intel_ssp *dp) /* allocate private data */ ssp = k_calloc(1, sizeof(*ssp)); if (!ssp) { - LOG_ERR("SSP%d: alloc failed", dp->index); + LOG_ERR("SSP%d: alloc failed", ssp_link->link_index); return -ENOMEM; } dai_set_drvdata(dp, ssp); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY; + + if (ssp_link->is_power_en) { + return 0; + } #if CONFIG_INTEL_MN /* Reset M/N, power-gating functions need it */ - dai_ssp_mn_reset_bclk_divider(dp, dp->index); + dai_ssp_mn_reset_bclk_divider(dp, ssp_link->link_index); #endif /* Enable SSP power */ - dai_ssp_pm_runtime_en_ssp_power(dp, dp->index); + dai_ssp_pm_runtime_en_ssp_power(dp, ssp_link->link_index); /* Disable dynamic clock gating before touching any register */ - dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, dp->index); + dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, ssp_link->link_index); + + ssp_link->is_power_en = true; return 0; } static int dai_ssp_remove(struct dai_intel_ssp *dp) { - dai_ssp_pm_runtime_en_ssp_clk_gating(dp, dp->index); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); + + if (ssp_link_is_acquired(ssp_link)) { + k_free(dai_get_drvdata(dp)); + dai_set_drvdata(dp, NULL); + return 0; + } + + dai_ssp_pm_runtime_en_ssp_clk_gating(dp, ssp_link->link_index); dai_ssp_mclk_disable_unprepare(dp); dai_ssp_bclk_disable_unprepare(dp); /* Disable SSP power */ - dai_ssp_pm_runtime_dis_ssp_power(dp, dp->index); + dai_ssp_pm_runtime_dis_ssp_power(dp, ssp_link->link_index); k_free(dai_get_drvdata(dp)); dai_set_drvdata(dp, NULL); + ssp_link->is_initialized = false; + ssp_link->is_power_en = false; + return 0; } @@ -2203,8 +2336,19 @@ static int ssp_pm_action(const struct device *dev, enum pm_device_action action) return 0; } +static int dai_intel_ssp_init_device(const struct device *dev) +{ + struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; + + dp->ssp_link = ssp_get_link(dp->link_index); + + return 0; +}; + static int ssp_init(const struct device *dev) { + dai_intel_ssp_init_device(dev); + if (pm_device_on_power_domain(dev)) { pm_device_init_off(dev); } else { @@ -2223,66 +2367,27 @@ static struct dai_driver_api dai_intel_ssp_api_funcs = { .get_properties = dai_ssp_get_properties, }; -static struct dai_intel_ssp_freq_table ssp_freq_table[] = { - { DT_PROP(DT_NODELABEL(audioclk), clock_frequency), - DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000}, - { DT_PROP(DT_NODELABEL(sysclk), clock_frequency), - DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000}, - { DT_PROP(DT_NODELABEL(pllclk), clock_frequency), - DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000}, -}; - -static uint32_t ssp_freq_sources[] = { - DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL, - DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR, - DAI_INTEL_SSP_CLOCK_PLL_FIXED, -}; -static struct dai_intel_ssp_mn ssp_mn_divider = { - .base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssp0), 1), -}; +#define DT_DRV_COMPAT intel_ssp_dai -static const char irq_name_level5_z[] = "level5"; #define DAI_INTEL_SSP_DEVICE_INIT(n) \ - static struct dai_config dai_intel_ssp_config_##n = { \ - .type = DAI_INTEL_SSP, \ - .dai_index = n, \ - }; \ - static struct dai_intel_ssp dai_intel_ssp_data_##n = { \ - .index = n, \ - .plat_data = { \ - .base = DT_INST_REG_ADDR_BY_IDX(n, 0), \ - 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(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)), \ - (.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),))\ - IF_ENABLED(DT_INST_PROP_HAS_IDX(n, i2svss, 0), \ - (.i2svss_base = DT_INST_PROP_BY_IDX(n, i2svss, 0),))\ - .irq = n, \ - .irq_name = irq_name_level5_z, \ - .fifo[DAI_DIR_PLAYBACK].offset = \ - DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \ - .fifo[DAI_DIR_PLAYBACK].handshake = \ - DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ - .fifo[DAI_DIR_CAPTURE].offset = \ - DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \ - .fifo[DAI_DIR_CAPTURE].handshake = \ - DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ - .mn_inst = &ssp_mn_divider, \ - .ftable = ssp_freq_table, \ - .fsources = ssp_freq_sources, \ - }, \ - }; \ - \ + static struct dai_config dai_intel_ssp_config_##n = { \ + .type = DAI_INTEL_SSP, \ + .dai_index = DT_INST_REG_ADDR(n), \ + }; \ + static struct dai_intel_ssp dai_intel_ssp_data_##n = { \ + .dai_index = DT_INST_REG_ADDR(n), \ + .link_index = DT_INST_PROP(n, link), \ + }; \ + \ PM_DEVICE_DT_INST_DEFINE(n, ssp_pm_action); \ - \ + \ DEVICE_DT_INST_DEFINE(n, \ - ssp_init, PM_DEVICE_DT_INST_GET(n), \ + ssp_init, PM_DEVICE_DT_INST_GET(n), \ &dai_intel_ssp_data_##n, \ &dai_intel_ssp_config_##n, \ - POST_KERNEL, 42, \ + POST_KERNEL, 42, \ &dai_intel_ssp_api_funcs); DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_SSP_DEVICE_INIT) diff --git a/drivers/dai/intel/ssp/ssp.h b/drivers/dai/intel/ssp/ssp.h index 5a187730dd538b..eb9a817351ea13 100644 --- a/drivers/dai/intel/ssp/ssp.h +++ b/drivers/dai/intel/ssp/ssp.h @@ -330,24 +330,33 @@ struct dai_intel_ssp_plat_data { struct dai_intel_ssp_mn *mn_inst; struct dai_intel_ssp_freq_table *ftable; uint32_t *fsources; + uint32_t clk_active; }; struct dai_intel_ssp_pdata { uint32_t sscr0; uint32_t sscr1; uint32_t psp; - uint32_t state[2]; - uint32_t clk_active; struct dai_config config; struct dai_properties props; +}; + +struct intel_ssp_link { + uint32_t link_index; + int acquire_count; + bool is_initialized; + bool is_power_en; + struct dai_intel_ssp_plat_data ssp_plat_data; struct dai_intel_ipc3_ssp_params params; }; struct dai_intel_ssp { - uint32_t index; /**< index */ + uint32_t dai_index; + uint32_t link_index; + uint32_t state[2]; struct k_spinlock lock; /**< locking mechanism */ int sref; /**< simple ref counter, guarded by lock */ - struct dai_intel_ssp_plat_data plat_data; + struct intel_ssp_link *ssp_link; void *priv_data; }; diff --git a/dts/bindings/i2s/intel,ssp-dai.yaml b/dts/bindings/i2s/intel,ssp-dai.yaml index 59a778baa1f580..262c3e4273e760 100644 --- a/dts/bindings/i2s/intel,ssp-dai.yaml +++ b/dts/bindings/i2s/intel,ssp-dai.yaml @@ -1,8 +1,7 @@ -# Copyright (c) 2022 Intel Corporation -# +# Copyright (c) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -description: Intel SSP DAI controller +description: Intel SSP DAI node compatible: "intel,ssp-dai" @@ -12,17 +11,6 @@ properties: reg: required: true - interrupts: + link: + type: int required: true - - interrupt-parent: - required: true - - dmas: - required: true - - dma-names: - required: true - - i2svss: - type: array diff --git a/dts/bindings/i2s/intel,ssp-link.yaml b/dts/bindings/i2s/intel,ssp-link.yaml new file mode 100644 index 00000000000000..e3786427ea2cb3 --- /dev/null +++ b/dts/bindings/i2s/intel,ssp-link.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Intel SSP DAI controller + +compatible: "intel,ssp-link" + +include: base.yaml + +properties: + reg: + required: true + + link: + type: int + required: true + + interrupts: + required: true + + interrupt-parent: + required: true + + dmas: + required: true + + dma-names: + required: true + + i2svss: + type: array \ No newline at end of file diff --git a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index 9c92387e36a89d..7e6d029b9e6f01 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -242,10 +242,11 @@ status = "okay"; }; - ssp0: ssp@28000 { - compatible = "intel,ssp-dai"; + ssplink0: ssp-link@28000 { #address-cells = <1>; #size-cells = <0>; + compatible = "intel,ssp-link"; + link = <0>; reg = <0x00028000 0x1000 0x00079C00 0x200>; interrupts = <0x00 0 0>; @@ -262,10 +263,11 @@ reg = <0x28800 0x1000>; }; - ssp1: ssp@29000 { - compatible = "intel,ssp-dai"; + ssplink1: ssp-link@29000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <1>; reg = <0x00029000 0x1000 0x00079C00 0x200>; interrupts = <0x01 0 0>; @@ -277,10 +279,11 @@ status = "okay"; }; - ssp2: ssp@2a000 { - compatible = "intel,ssp-dai"; + ssplink2: ssp-link@2a000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <2>; reg = <0x0002a000 0x1000 0x00079C00 0x200>; interrupts = <0x02 0 0>; @@ -292,10 +295,11 @@ status = "okay"; }; - ssp3: ssp@2b000 { - compatible = "intel,ssp-dai"; + ssplink3: ssp-link@2b000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <3>; reg = <0x0002b000 0x1000 0x00079C00 0x200>; interrupts = <0x03 0 0>; @@ -307,10 +311,11 @@ status = "okay"; }; - ssp4: ssp@2c000 { - compatible = "intel,ssp-dai"; + ssplink4: ssp-link@2c000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <4>; reg = <0x0002c000 0x1000 0x00079C00 0x200>; interrupts = <0x04 0 0>; @@ -322,10 +327,11 @@ status = "okay"; }; - ssp5: ssp@2d000 { - compatible = "intel,ssp-dai"; + ssplink5: ssp-link@2d000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <5>; reg = <0x0002d000 0x1000 0x00079C00 0x200>; interrupts = <0x04 0 0>; @@ -689,4 +695,52 @@ reg = <0x12>; }; }; + + ssps { + #address-cells = <1>; + #size-cells = <0>; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + link = <0>; + status = "okay"; + }; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + link = <1>; + status = "okay"; + }; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + link = <2>; + status = "okay"; + }; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + link = <3>; + status = "okay"; + }; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + link = <4>; + status = "okay"; + }; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + link = <5>; + status = "okay"; + }; + + }; }; diff --git a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi index 91535c92dcd95f..12f9eb4b574ef7 100644 --- a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi @@ -176,10 +176,11 @@ status = "okay"; }; - ssp0: ssp@28100 { - compatible = "intel,ssp-dai"; + ssplink0: ssp-link@28100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <0>; reg = <0x00028100 0x1000 0x00079C00 0x200>; i2svss = <0x00028C00 0x1000>; @@ -192,10 +193,11 @@ status = "okay"; }; - ssp1: ssp@29100 { - compatible = "intel,ssp-dai"; + ssplink1: ssp-link@29100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <1>; reg = <0x00029100 0x1000 0x00079C00 0x200>; i2svss = <0x00029C00 0x1000>; @@ -208,10 +210,11 @@ status = "okay"; }; - ssp2: ssp@2a100 { - compatible = "intel,ssp-dai"; + ssplink2: ssp-link@2a100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <2>; reg = <0x0002a100 0x1000 0x00079C00 0x200>; i2svss = <0x0002AC00 0x1000>; @@ -224,10 +227,11 @@ status = "okay"; }; - ssp3: ssp@2b100 { - compatible = "intel,ssp-dai"; + ssplink3: ssp-link@2b100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <3>; reg = <0x0002b100 0x1000 0x00079C00 0x200>; i2svss = <0x0002BC00 0x1000>; @@ -240,10 +244,11 @@ status = "okay"; }; - ssp4: ssp@2c100 { - compatible = "intel,ssp-dai"; + ssplink4: ssp-link@2c100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <4>; reg = <0x0002c100 0x1000 0x00079C00 0x200>; i2svss = <0x0002CC00 0x1000>; @@ -256,10 +261,11 @@ status = "okay"; }; - ssp5: ssp@2d100 { - compatible = "intel,ssp-dai"; + ssplink5: ssp-link@2d100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <5>; reg = <0x0002d100 0x1000 0x00079C00 0x200>; i2svss = <0x0002DC00 0x1000>; @@ -549,4 +555,50 @@ reg = <0x12>; }; }; + + ssps { + #address-cells = <1>; + #size-cells = <0>; + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + link = <0>; + status = "okay"; + }; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + link = <1>; + status = "okay"; + }; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + link = <2>; + status = "okay"; + }; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + link = <3>; + status = "okay"; + }; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + link = <4>; + status = "okay"; + }; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + link = <5>; + status = "okay"; + }; + }; }; diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index 36ad7afa218640..06b7499a49c9c7 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -216,10 +216,11 @@ paddr-size = <11>; }; - ssp0: ssp@77000 { - compatible = "intel,ssp-dai"; + ssplink0: ssp-link@77000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <0>; reg = <0x00077000 0x200 0x00078C00 0x008>; interrupts = <0x01 0 0>; @@ -231,10 +232,11 @@ status = "okay"; }; - ssp1: ssp@77200 { - compatible = "intel,ssp-dai"; + ssplink1: ssp-link@77200 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <1>; reg = <0x00077200 0x200 0x00078C00 0x008>; interrupts = <0x01 0 0>; @@ -246,10 +248,11 @@ status = "okay"; }; - ssp2: ssp@77400 { - compatible = "intel,ssp-dai"; + ssplink2: ssp-link@77400 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <2>; reg = <0x00077400 0x200 0x00078C00 0x008>; interrupts = <0x02 0 0>; @@ -261,10 +264,11 @@ status = "okay"; }; - ssp3: ssp@77600 { - compatible = "intel,ssp-dai"; + ssplink3: ssp-link@77600 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <3>; reg = <0x00077600 0x200 0x00078C00 0x008>; interrupts = <0x03 0 0>; @@ -276,10 +280,11 @@ status = "okay"; }; - ssp4: ssp@77800 { - compatible = "intel,ssp-dai"; + ssplink4: ssp-link@77800 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <4>; reg = <0x00077800 0x200 0x00078C00 0x008>; interrupts = <0x03 0 0>; @@ -291,10 +296,11 @@ status = "okay"; }; - ssp5: ssp@77a00 { - compatible = "intel,ssp-dai"; + ssplink5: ssp-link@77a00 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <5>; reg = <0x00077A00 0x200 0x00078C00 0x008>; interrupts = <0x03 0 0>; @@ -513,4 +519,51 @@ reg = <0x0f>; }; }; + + ssps { + #address-cells = <1>; + #size-cells = <0>; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + link = <0>; + status = "okay"; + }; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + link = <1>; + status = "okay"; + }; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + link = <2>; + status = "okay"; + }; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + link = <3>; + status = "okay"; + }; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + link = <4>; + status = "okay"; + }; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + link = <5>; + status = "okay"; + }; + }; }; diff --git a/tests/boards/intel_adsp/ssp/src/main.c b/tests/boards/intel_adsp/ssp/src/main.c index 7ba608e4bbb4cf..4b0b8f09bd0fbf 100644 --- a/tests/boards/intel_adsp/ssp/src/main.c +++ b/tests/boards/intel_adsp/ssp/src/main.c @@ -44,7 +44,7 @@ struct sof_dai_ssp_params { } __packed; static const struct device *const dev_dai_ssp = - DEVICE_DT_GET(DT_NODELABEL(ssp0)); + DEVICE_DT_GET(DT_NODELABEL(ssp00)); static const struct device *const dev_dma_dw = DEVICE_DT_GET(DT_NODELABEL(lpgpdma0));