From ff344f679a25998bb1fff6ca3a524dba8615906e 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 management This commit refactors the Intel SSP DAI driver to support dynamic management of SSP IP. This change additionally separates the management of the DAI part from the management part of the SSP IP. Key changes: - Add new static functions to manage SSP IP power. - Update the DAI SSP configuration functions to use the new management approach. - Update device tree bindings and instances to reflect the new SSP IP management mechanism. Signed-off-by: Damian Nikodem --- drivers/dai/intel/ssp/ssp.c | 662 +++++++++++--------- drivers/dai/intel/ssp/ssp.h | 15 +- dts/bindings/i2s/intel,ssp-dai.yaml | 20 +- dts/bindings/i2s/intel,ssp.yaml | 32 + dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi | 62 +- dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi | 54 +- dts/xtensa/intel/intel_adsp_cavs25.dtsi | 60 +- tests/boards/intel_adsp/ssp/src/main.c | 2 +- 8 files changed, 574 insertions(+), 333 deletions(-) create mode 100644 dts/bindings/i2s/intel,ssp.yaml diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index f630a656967a330..628be375ba1fafa 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_plat_data(dai) dai->ssp_plat_data +#define dai_get_mn(dai) dai->ssp_plat_data->mn_inst +#define dai_get_ftable(dai) dai->ssp_plat_data->ftable +#define dai_get_fsources(dai) dai->ssp_plat_data->fsources +#define dai_mn_base(dai) dai->ssp_plat_data->mn_inst->base +#define dai_base(dai) dai->ssp_plat_data->base +#define dai_ip_base(dai) dai->ssp_plat_data->ip_base +#define dai_shim_base(dai) dai->ssp_plat_data->shim_base +#define dai_hdamlssp_base(dai) dai->ssp_plat_data->hdamlssp_base +#define dai_i2svss_base(dai) dai->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(ssp0), 1), +}; + + +#define INTEL_SSP_INST_DEFINE(node_id) { \ + .is_initialized = false, \ + .is_power_en = false, \ + .acquire_count = 0, \ + .ssp_index = DT_PROP(node_id, ssp_index), \ + .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 dai_intel_ssp_plat_data ssp_plat_data_table[] = { + DT_FOREACH_STATUS_OKAY(intel_ssp, INTEL_SSP_INST_DEFINE) +}; + + +static uint32_t ssp_get_instance_count(void) +{ + return ARRAY_SIZE(ssp_plat_data_table); +} + + +static struct dai_intel_ssp_plat_data *ssp_get_device_instance(uint32_t ssp_index) +{ + uint32_t ssp_instance = ssp_get_instance_count(); + uint32_t i; + + for (i = 0; i < ssp_instance; i++) { + if (ssp_plat_data_table[i].ssp_index == ssp_index) { + return &ssp_plat_data_table[i]; + } + } + + return NULL; +} + +static void ssp_acquire_port(struct dai_intel_ssp_plat_data *ssp) +{ + ssp->acquire_count++; +} + +static void ssp_release_port(struct dai_intel_ssp_plat_data *ssp) +{ + if (ssp->acquire_count == 0) { + return; + } + + --ssp->acquire_count; +} + +static bool ssp_is_acquired(struct dai_intel_ssp_plat_data *ssp) +{ + return (ssp->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 ssp_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[ssp_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 ssp_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(ssp_index)); + sys_write32(1, dai_mn_base(dp) + MN_MDIV_N_VAL(ssp_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 ssp_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 - + (ssp_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? + SHIM_CLKCTL_I2SFDCGB(ssp_index) : + SHIM_CLKCTL_I2SEFDCGB(ssp_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("ssp_index %d CLKCTL %08x", ssp_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 ssp_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 - + ~(ssp_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? + SHIM_CLKCTL_I2SFDCGB(ssp_index) : + SHIM_CLKCTL_I2SEFDCGB(ssp_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("ssp_index %d CLKCTL %08x", ssp_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 ssp_index) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP%d", ssp_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(ssp_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(ssp_index), I2SLCTL_CPA(ssp_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(ssp_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(ssp_index), I2SLCTL_CPA(ssp_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%d: timeout", ssp_index); } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(ssp_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 ssp_index) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP%d", ssp_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(ssp_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(ssp_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(ssp_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(ssp_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%d: timeout", ssp_index); } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(ssp_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 ssp_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 | (ssp->params.tdm_slots - 1) << 4; + /* Set upper slot number from configuration */ + pcmsycm = pcmsycm | (dp->ssp_plat_data->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 * ssp_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 * ssp_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(ssp_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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); + uint64_t sample_ticks = ssp_plat_data->params.fsync_rate ? + 1000000 / ssp_plat_data->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,21 @@ 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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); int ret; - if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE) { + if (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_plat_data->params.mclk_id, + ssp_plat_data->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_plat_data->params.mclk_rate, + ssp_plat_data->params.mclk_id); } else { - ssp->clk_active |= SSP_CLK_MCLK_ACTIVE; + ssp_plat_data->clk_active |= SSP_CLK_MCLK_ACTIVE; } return ret; @@ -921,15 +1018,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); - if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE)) { + if (!(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_plat_data->params.mclk_id); - ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE; + ssp_plat_data->clk_active &= ~SSP_CLK_MCLK_ACTIVE; } static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) @@ -937,14 +1034,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); uint32_t sscr0; uint32_t mdiv; bool need_ecs = false; int ret = 0; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE) { return 0; } @@ -952,22 +1048,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->dai_index, ssp_plat_data->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 ssp_index = %d", + ssp_plat_data->params.bclk_rate, dp->dai_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_plat_data->params.bclk_rate != 0) { + LOG_ERR("invalid bclk_rate = %d for ssp_index = %d", + ssp_plat_data->params.bclk_rate, dp->dai_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_plat_data->params.bclk_rate; #endif if (need_ecs) { @@ -993,7 +1089,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_plat_data->clk_active |= SSP_CLK_BCLK_ACTIVE; } return ret; @@ -1001,29 +1097,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(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_plat_data->ssp_index); #endif - ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE; + 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_plat_data->base); + LOG_INF("plat_data irq: %u", dp->ssp_plat_data->irq); + LOG_INF("plat_data fifo playback offset: %u", + dp->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_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_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_plat_data->fifo[DAI_DIR_CAPTURE].handshake); } /* Digital Audio interface formatting */ @@ -1031,6 +1128,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp); uint32_t sscr0; uint32_t sscr1; @@ -1066,14 +1164,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_plat_data->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_plat_data->clk_active & + (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) { LOG_WRN("SSP active, cannot change config"); goto clk; } @@ -1081,7 +1181,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 +1204,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_plat_data->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params)); /* sspsp2 no dynamic setting */ sspsp2 = 0x0; @@ -1116,10 +1216,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_plat_data->params.tx_slots); /* ssrsa dynamic setting is RTSA, default 2 slots */ - ssrsa = SSRSA_SSRSA(ssp->params.rx_slots); + ssrsa = SSRSA_SSRSA(ssp_plat_data->params.rx_slots); switch (config->format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) { case DAI_INTEL_IPC3_SSP_FMT_CBP_CFP: @@ -1166,7 +1266,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_plat_data->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 +1279,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_plat_data->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_plat_data->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_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ? SSCR1_LBM : 0; - if (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { + if (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { LOG_INF("going for loopback!"); } else { LOG_INF("no loopback!"); @@ -1201,69 +1301,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_plat_data->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_plat_data->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_plat_data->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_plat_data->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_plat_data->params.mclk_rate || + ssp_plat_data->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) { + LOG_ERR("invalid MCLK = %d Hz (valid < %d)", ssp_plat_data->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_plat_data->params.bclk_rate || + ssp_plat_data->params.bclk_rate > ssp_plat_data->params.mclk_rate) { + LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", ssp_plat_data->params.bclk_rate, + ssp_plat_data->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_plat_data->params.bclk_rate % ssp_plat_data->params.fsync_rate) { + LOG_ERR("BCLK %d is not divisible by rate %d", ssp_plat_data->params.bclk_rate, + ssp_plat_data->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_plat_data->params.bclk_rate / ssp_plat_data->params.fsync_rate; + if (bdiv < ssp_plat_data->params.tdm_slot_width * ssp_plat_data->params.tdm_slots) { LOG_ERR("not enough BCLKs need %d", - ssp->params.tdm_slot_width * ssp->params.tdm_slots); + ssp_plat_data->params.tdm_slot_width * ssp_plat_data->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_plat_data->params.tdm_slot_width > 38) { + LOG_ERR("tdm_slot_width %d > 38", ssp_plat_data->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_plat_data->params.tdm_slots * + (ssp_plat_data->params.tdm_per_slot_padding_flag ? + ssp_plat_data->params.tdm_slot_width : ssp_plat_data->params.sample_valid_bits); if (bdiv < bdiv_min) { LOG_ERR("bdiv(%d) < bdiv_min(%d)", bdiv, bdiv_min); ret = -EINVAL; @@ -1283,7 +1384,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_plat_data->params.tdm_slots); if (bdiv % 2) { LOG_ERR("bdiv %d is not divisible by 2", bdiv); @@ -1331,7 +1432,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_plat_data->params.tdm_slots); /* LJDFD enable */ sscr2 &= ~SSCR2_LJDFD; @@ -1387,19 +1488,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_plat_data->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_plat_data->params.frame_pulse_width > 0 && + ssp_plat_data->params.frame_pulse_width <= DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) { - frame_len = ssp->params.frame_pulse_width; + frame_len = ssp_plat_data->params.frame_pulse_width; } /* frame_pulse_width must less or equal 38 */ - if (ssp->params.frame_pulse_width > + if (ssp_plat_data->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 +1514,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_plat_data->params.tx_slots); + active_rx_slots = POPCOUNT(ssp_plat_data->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_plat_data->params.tdm_per_slot_padding_flag) { + frame_end_padding = bdiv - ssp_plat_data->params.tdm_slots * + ssp_plat_data->params.tdm_slot_width; - slot_end_padding = ssp->params.tdm_slot_width - - ssp->params.sample_valid_bits; + slot_end_padding = ssp_plat_data->params.tdm_slot_width - + ssp_plat_data->params.sample_valid_bits; if (slot_end_padding > DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) { @@ -1456,7 +1557,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_plat_data->params.sample_valid_bits; if (data_size > 16) { sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16)); @@ -1465,7 +1566,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_plat_data->params.sample_valid_bits) { case 16: /* use 2 bytes for each slot */ sample_width = 2; @@ -1476,7 +1577,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_plat_data->params.sample_valid_bits); ret = -EINVAL; goto out; } @@ -1506,27 +1607,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_plat_data->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_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%d...", + dp->dai_index); } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { bool enable_sse = false; - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE)) { enable_sse = true; } @@ -1535,39 +1637,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_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_plat_data->ssp_index); } - LOG_INF("hw_params stage: enabled BCLK clocks for SSP%d...", dp->index); + LOG_INF("hw_params stage: enabled BCLK clocks for SSP%d...", + ssp_plat_data->ssp_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 SSP%d still in use", + dp->dai_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_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + LOG_INF("hw_free stage: releasing BCLK clocks for SSP%d...", + dp->dai_index); + if (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 SSP%d", dp->dai_index); } dai_ssp_bclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ; + 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_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { + LOG_INF("hw_free stage: releasing MCLK clocks for SSP%d...", + dp->dai_index); dai_ssp_mclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ; + ssp_plat_data->clk_active &= ~SSP_CLK_MCLK_ES_REQ; } break; default: @@ -1756,7 +1862,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 +1869,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_INF("SSP%d configuration:", dp->index); + LOG_INF("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 +1899,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_plat_data->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0); if (ssc0 & SSCR0_EDSS) { - ssp->params.sample_valid_bits += 16; + dp->ssp_plat_data->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_plat_data->params.tdm_slots = SSCR0_FRDC_GET(ssc0); + dp->ssp_plat_data->params.tx_slots = SSTSA_GET(sstsa); + dp->ssp_plat_data->params.rx_slots = SSRSA_GET(ssrsa); + dp->ssp_plat_data->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 +1918,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(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_plat_data->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 +1943,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_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_plat_data->clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_plat_data->is_initialized = true; return 0; } @@ -1852,14 +1960,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(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_plat_data->clk_active & SSP_CLK_MCLK_ES_REQ)) { /* MCLK config */ ret = dai_ssp_mclk_prepare_enable(dp); if (ret < 0) { @@ -1867,7 +1975,7 @@ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) } } - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) { ret = dai_ssp_bclk_prepare_enable(dp); } @@ -1881,17 +1989,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(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_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) { + LOG_INF("releasing BCLK clocks for SSP%d...", dp->dai_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_plat_data->clk_active & SSP_CLK_MCLK_ES_REQ)) { + LOG_INF("releasing MCLK clocks for SSP%d...", dp->dai_index); dai_ssp_mclk_disable_unprepare(dp); } } @@ -1899,25 +2007,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(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_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", dp->dai_index); dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); } @@ -1935,16 +2043,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_port(dp->ssp_plat_data); /* * Wait to get valid fifo status in clock consumer mode. TODO it's @@ -1968,6 +2077,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); k_spinlock_key_t key; key = k_spin_lock(&dp->lock); @@ -1988,64 +2098,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_port(ssp_plat_data); } /* 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_port(ssp_plat_data); } /* 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_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { + + if (!ssp_is_acquired(ssp_plat_data)) { + dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + LOG_INF("%s SSE clear SSP%d", __func__, ssp_plat_data->ssp_index); + } } - dai_ssp_post_stop(dp); + if (!ssp_is_acquired(ssp_plat_data)) { + 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 +2184,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); if (!cfg) { return -EINVAL; @@ -2080,15 +2195,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_plat_data->params.fsync_rate; if (dir == DAI_DIR_PLAYBACK) { - params->channels = POPCOUNT(ssp->params.tx_slots); + params->channels = POPCOUNT(ssp_plat_data->params.tx_slots); } else { - params->channels = POPCOUNT(ssp->params.rx_slots); + params->channels = POPCOUNT(ssp_plat_data->params.rx_slots); } - params->word_size = ssp->params.sample_valid_bits; + params->word_size = ssp_plat_data->params.sample_valid_bits; *cfg = *params; @@ -2106,7 +2221,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->ssp_index); return ret; } @@ -2115,19 +2230,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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(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_plat_data->fifo[array_index].offset; + prop->dma_hs_id = ssp_plat_data->fifo[array_index].handshake; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (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_plat_data->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 +2251,7 @@ static const struct dai_properties *dai_ssp_get_properties(const struct device * static int dai_ssp_probe(struct dai_intel_ssp *dp) { + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); struct dai_intel_ssp_pdata *ssp; if (dai_get_drvdata(dp)) { @@ -2144,47 +2261,59 @@ 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_plat_data->ssp_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_plat_data->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_plat_data->ssp_index); #endif /* Enable SSP power */ - dai_ssp_pm_runtime_en_ssp_power(dp, dp->index); + dai_ssp_pm_runtime_en_ssp_power(dp, ssp_plat_data->ssp_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_plat_data->ssp_index); + + ssp_plat_data->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 dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); + + dai_ssp_pm_runtime_en_ssp_clk_gating(dp, ssp_plat_data->ssp_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_plat_data->ssp_index); k_free(dai_get_drvdata(dp)); dai_set_drvdata(dp, NULL); + ssp_plat_data->is_initialized = false; + ssp_plat_data->is_power_en = false; + return 0; } static int ssp_pm_action(const struct device *dev, enum pm_device_action action) { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; + switch (action) { case PM_DEVICE_ACTION_SUSPEND: dai_ssp_remove(dp); @@ -2203,8 +2332,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_plat_data = ssp_get_device_instance(dp->ssp_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 +2363,26 @@ 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), -}; -static const char irq_name_level5_z[] = "level5"; +#define DT_DRV_COMPAT intel_ssp_dai #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), \ + .ssp_index = DT_PROP(DT_INST_PARENT(n), ssp_index), \ + }; \ + \ 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 5a187730dd538ba..f35b398b6b78b93 100644 --- a/drivers/dai/intel/ssp/ssp.h +++ b/drivers/dai/intel/ssp/ssp.h @@ -316,6 +316,10 @@ struct dai_intel_ssp_plat_fifo_data { }; struct dai_intel_ssp_plat_data { + uint32_t ssp_index; + int acquire_count; + bool is_initialized; + bool is_power_en; uint32_t base; uint32_t ip_base; uint32_t shim_base; @@ -330,24 +334,25 @@ 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_ipc3_ssp_params params; }; 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 dai_intel_ipc3_ssp_params params; }; struct dai_intel_ssp { - uint32_t index; /**< index */ + uint32_t dai_index; + uint32_t ssp_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 dai_intel_ssp_plat_data *ssp_plat_data; void *priv_data; }; diff --git a/dts/bindings/i2s/intel,ssp-dai.yaml b/dts/bindings/i2s/intel,ssp-dai.yaml index 59a778baa1f580c..8fc6f1a2e907bd4 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" @@ -11,18 +10,3 @@ include: base.yaml properties: reg: required: true - - interrupts: - required: true - - interrupt-parent: - required: true - - dmas: - required: true - - dma-names: - required: true - - i2svss: - type: array diff --git a/dts/bindings/i2s/intel,ssp.yaml b/dts/bindings/i2s/intel,ssp.yaml new file mode 100644 index 000000000000000..76b59e7c2bcf331 --- /dev/null +++ b/dts/bindings/i2s/intel,ssp.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Intel SSP DAI controller + +compatible: "intel,ssp" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + interrupt-parent: + required: true + + dmas: + required: true + + dma-names: + required: true + + i2svss: + type: array + + ssp-index: + type: int + required: true diff --git a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index 352e119b3aa5ac0..d0b9780844e9401 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -243,10 +243,15 @@ status = "okay"; }; + sspbase: ssp_base@28800 { + compatible = "intel,ssp-sspbase"; + reg = <0x28800 0x1000>; + }; + ssp0: ssp@28000 { - compatible = "intel,ssp-dai"; #address-cells = <1>; #size-cells = <0>; + compatible = "intel,ssp"; reg = <0x00028000 0x1000 0x00079C00 0x200>; interrupts = <0x00 0 0>; @@ -255,16 +260,18 @@ &lpgpdma0 3>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <0>; status = "okay"; - }; - sspbase: ssp_base@28800 { - compatible = "intel,ssp-sspbase"; - reg = <0x28800 0x1000>; + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x0>; + }; }; ssp1: ssp@29000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00029000 0x1000 @@ -275,11 +282,18 @@ &lpgpdma0 5>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <1>; status = "okay"; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x10>; + }; }; ssp2: ssp@2a000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002a000 0x1000 @@ -290,11 +304,18 @@ &lpgpdma0 7>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <2>; status = "okay"; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x20>; + }; }; ssp3: ssp@2b000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002b000 0x1000 @@ -305,11 +326,18 @@ &lpgpdma0 9>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <3>; status = "okay"; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x30>; + }; }; ssp4: ssp@2c000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002c000 0x1000 @@ -320,11 +348,18 @@ &lpgpdma0 11>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <4>; status = "okay"; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x40>; + }; }; ssp5: ssp@2d000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002d000 0x1000 @@ -335,7 +370,14 @@ &lpgpdma0 13>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <5>; status = "okay"; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x50>; + }; }; mem_window0: mem_window@70200 { diff --git a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi index d89dcb9c7f6fa4a..67aebc399d647fd 100644 --- a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi @@ -178,7 +178,7 @@ }; ssp0: ssp@28100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00028100 0x1000 @@ -190,11 +190,18 @@ &hda_link_in 1>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <0>; status = "okay"; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x0>; + }; }; ssp1: ssp@29100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00029100 0x1000 @@ -206,11 +213,18 @@ &hda_link_in 2>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <1>; status = "okay"; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x10>; + }; }; ssp2: ssp@2a100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002a100 0x1000 @@ -222,11 +236,18 @@ &hda_link_in 3>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <2>; status = "okay"; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x20>; + }; }; ssp3: ssp@2b100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002b100 0x1000 @@ -238,11 +259,18 @@ &hda_link_in 4>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <3>; status = "okay"; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x30>; + }; }; ssp4: ssp@2c100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002c100 0x1000 @@ -254,11 +282,18 @@ &hda_link_in 5>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <4>; status = "okay"; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x40>; + }; }; ssp5: ssp@2d100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002d100 0x1000 @@ -270,7 +305,14 @@ &hda_link_in 6>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <5>; status = "okay"; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x50>; + }; }; mem_window0: mem_window@70200 { diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index 36ad7afa2186406..03faf222748f5a6 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -217,7 +217,7 @@ }; ssp0: ssp@77000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077000 0x200 @@ -227,12 +227,18 @@ dmas = <&lpgpdma0 2 &lpgpdma0 3>; dma-names = "tx", "rx"; - + ssp-index = <0>; status = "okay"; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + status = "okay"; + }; }; ssp1: ssp@77200 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077200 0x200 @@ -242,12 +248,18 @@ dmas = <&lpgpdma0 4 &lpgpdma0 5>; dma-names = "tx", "rx"; - + ssp-index = <1>; status = "okay"; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + status = "okay"; + }; }; ssp2: ssp@77400 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077400 0x200 @@ -257,12 +269,18 @@ dmas = <&lpgpdma0 6 &lpgpdma0 7>; dma-names = "tx", "rx"; - + ssp-index = <2>; status = "okay"; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + status = "okay"; + }; }; ssp3: ssp@77600 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077600 0x200 @@ -272,12 +290,18 @@ dmas = <&lpgpdma0 8 &lpgpdma0 9>; dma-names = "tx", "rx"; - + ssp-index = <3>; status = "okay"; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + status = "okay"; + }; }; ssp4: ssp@77800 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077800 0x200 @@ -287,12 +311,18 @@ dmas = <&lpgpdma0 10 &lpgpdma0 11>; dma-names = "tx", "rx"; - + ssp-index = <4>; status = "okay"; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + status = "okay"; + }; }; ssp5: ssp@77a00 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077A00 0x200 @@ -302,8 +332,14 @@ dmas = <&lpgpdma0 12 &lpgpdma0 13>; dma-names = "tx", "rx"; - + ssp-index = <5>; status = "okay"; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + status = "okay"; + }; }; /* diff --git a/tests/boards/intel_adsp/ssp/src/main.c b/tests/boards/intel_adsp/ssp/src/main.c index 7ba608e4bbb4cf5..4b0b8f09bd0fbfa 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));