From 3032c56f800823505e0949cbbcc7cc516a45ad9d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 14 Jun 2021 14:13:47 -0500 Subject: [PATCH 01/12] intel: ssp: fix missing return code on bclk configuration issue when the bclk is not based on the default source, we will thrown an error message but return the result of the mclk configuration. Fix by adding an explicit -EINVAL return value. Reported-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart --- src/drivers/intel/ssp/ssp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index 7af11b4274d8..62be3c3ccde4 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -658,6 +658,7 @@ static int ssp_pre_start(struct dai *dai) if (ssp_freq[SSP_DEFAULT_IDX].freq % config->ssp.bclk_rate != 0) { dai_err(dai, "invalid bclk_rate = %d for dai_index = %d", config->ssp.bclk_rate, config->dai_index); + ret = -EINVAL; goto out; } From 07922971d1a3a19c7346d800f0205085364ad432 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 1 Jun 2021 16:35:06 -0500 Subject: [PATCH 02/12] ipc: dai: add flags for DAI_CONFIG IPC The DAI_CONFIG IPC is currently used both for hw_params and hw_free. For some DAIs, there are hacky ways with e.g. invalid DMA channels to indicate a hw_free. Rather than adding a new IPC for hw_params and hw_free, let's add a flag that indicates if the DAI_CONFIG is really applied during a hw_params or hw_free stage. This is tagged as a ABI 3.19 change. Signed-off-by: Pierre-Louis Bossart --- src/include/ipc/dai.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/include/ipc/dai.h b/src/include/ipc/dai.h index 71be41dc2b2c..543b9e386721 100644 --- a/src/include/ipc/dai.h +++ b/src/include/ipc/dai.h @@ -52,6 +52,13 @@ #define SOF_DAI_FMT_INV_MASK 0x0f00 #define SOF_DAI_FMT_CLOCK_PROVIDER_MASK 0xf000 +/* DAI_CONFIG flags */ +#define SOF_DAI_CONFIG_FLAGS_MASK 0x3 +#define SOF_DAI_CONFIG_FLAGS_NONE (0 << 0) /**< DAI_CONFIG sent without stage information */ +#define SOF_DAI_CONFIG_FLAGS_HW_PARAMS (1 << 0) /**< DAI_CONFIG sent during hw_params stage */ +#define SOF_DAI_CONFIG_FLAGS_HW_FREE (2 << 0) /**< DAI_CONFIG sent during hw_free stage */ +#define SOF_DAI_CONFIG_FLAGS_RFU (3 << 0) /**< not used, reserved for future use */ + /** \brief Types of DAI */ enum sof_ipc_dai_type { SOF_DAI_INTEL_NONE = 0, /**< None */ @@ -72,7 +79,7 @@ struct sof_ipc_dai_config { /* physical protocol and clocking */ uint16_t format; /**< SOF_DAI_FMT_ */ uint8_t group_id; /**< group ID, 0 means no group (ABI 3.17) */ - uint8_t reserved8; /**< alignment */ + uint8_t flags; /**< SOF_DAI_CONFIG_FLAGS_ (ABI 3.19) */ /* reserved for future use */ uint32_t reserved[8]; From f46c14461cb73080c0e760774117ca838e6e0f3b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 25 May 2021 10:48:40 +0800 Subject: [PATCH 03/12] ipc: dai-intel: add SOF_DAI_INTEL_SSP_CLKCTRL_MCLK/BCLK_ES bits Add two clks_control bits. MCLK and/or BCLK will start during hw_params and stop during hw_free if the corresponding bit is set. This is tagged as a ABI 3.19 change. Signed-off-by: Bard Liao --- src/include/ipc/dai-intel.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/include/ipc/dai-intel.h b/src/include/ipc/dai-intel.h index 5dd7a00744c3..41e39a47db1f 100644 --- a/src/include/ipc/dai-intel.h +++ b/src/include/ipc/dai-intel.h @@ -56,6 +56,10 @@ #define SOF_DAI_INTEL_SSP_CLKCTRL_FS_KA BIT(4) /* bclk idle */ #define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5) +/* mclk early start */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES BIT(6) +/* bclk early start */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES BIT(7) /* DMIC max. four controllers for eight microphone channels */ #define SOF_DAI_INTEL_DMIC_NUM_CTRL 4 From 2c061639a1cefc77bd8a4fc809bf15f640c2e47c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 15 Jun 2021 08:45:19 -0500 Subject: [PATCH 04/12] ABI: bump level to 3.19 This will help identify support for SSP BCLK/MCLK changes. Signed-off-by: Pierre-Louis Bossart --- src/include/kernel/abi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/kernel/abi.h b/src/include/kernel/abi.h index b5ef6fcf13e8..b9847c7de9f3 100644 --- a/src/include/kernel/abi.h +++ b/src/include/kernel/abi.h @@ -29,8 +29,8 @@ /** \brief SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 18 -#define SOF_ABI_PATCH 1 +#define SOF_ABI_MINOR 19 +#define SOF_ABI_PATCH 0 /** \brief SOF ABI version number. Format within 32bit word is MMmmmppp */ #define SOF_ABI_MAJOR_SHIFT 24 From 2631d0751ad50e178a7e183424d1e4186e31fc7d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 25 May 2021 18:11:38 +0800 Subject: [PATCH 05/12] intel: ssp: introduce ssp_set/release_mclk/bclk helpers to set/release mclk/bclk MCLK and BCLK can be set/release separately. We can set/release mclk/bclk more flexible with these helpers. The helpers are defined after the Linux ones, 'prepare_enable' will first select the relevant resources then enable the clock output. Conversely 'disable_unprepare' will stop the clock output then release the clock resources. Signed-off-by: Bard Liao --- src/drivers/intel/ssp/ssp.c | 192 +++++++++++++++++++++------------- src/include/sof/drivers/ssp.h | 4 + 2 files changed, 123 insertions(+), 73 deletions(-) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index 62be3c3ccde4..1d0c11a85ccf 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -125,6 +125,112 @@ static int ssp_context_restore(struct dai *dai) return 0; } +static int ssp_mclk_prepare_enable(struct dai *dai) +{ + struct ssp_pdata *ssp = dai_get_drvdata(dai); + struct sof_ipc_dai_config *config = &ssp->config; + int ret; + + if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE) + return 0; + + /* MCLK config */ + ret = mn_set_mclk(config->ssp.mclk_id, config->ssp.mclk_rate); + if (ret < 0) + dai_err(dai, "ssp_mclk_prepare_enable(): invalid mclk_rate = %d for mclk_id = %d", + config->ssp.mclk_rate, config->ssp.mclk_id); + else + ssp->clk_active |= SSP_CLK_MCLK_ACTIVE; + + return ret; +} + +static void ssp_mclk_disable_unprepare(struct dai *dai) +{ + struct ssp_pdata *ssp = dai_get_drvdata(dai); + + if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE)) + return; + + mn_release_mclk(ssp->config.ssp.mclk_id); + + ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE; +} + +static int ssp_bclk_prepare_enable(struct dai *dai) +{ + struct ssp_pdata *ssp = dai_get_drvdata(dai); + struct sof_ipc_dai_config *config = &ssp->config; + uint32_t sscr0; + uint32_t mdiv; + bool need_ecs = false; + int ret = 0; + + if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) + return 0; + + sscr0 = ssp_read(dai, SSCR0); + +#if CONFIG_INTEL_MN + /* BCLK config */ + ret = mn_set_bclk(config->dai_index, config->ssp.bclk_rate, + &mdiv, &need_ecs); + if (ret < 0) { + dai_err(dai, "ssp_bclk_prepare_enable(): invalid bclk_rate = %d for dai_index = %d", + config->ssp.bclk_rate, config->dai_index); + goto out; + } +#else + if (ssp_freq[SSP_DEFAULT_IDX].freq % config->ssp.bclk_rate != 0) { + dai_err(dai, "ssp_bclk_prepare_enable(): invalid bclk_rate = %d for dai_index = %d", + config->ssp.bclk_rate, config->dai_index); + ret = -EINVAL; + goto out; + } + + mdiv = ssp_freq[SSP_DEFAULT_IDX].freq / config->ssp.bclk_rate; +#endif + + if (need_ecs) + sscr0 |= SSCR0_ECS; + + /* clock divisor is SCR + 1 */ + mdiv -= 1; + + /* divisor must be within SCR range */ + if (mdiv > (SSCR0_SCR_MASK >> 8)) { + dai_err(dai, "ssp_bclk_prepare_enable(): divisor %d is not within SCR range", + mdiv); + ret = -EINVAL; + goto out; + } + + /* set the SCR divisor */ + sscr0 &= ~SSCR0_SCR_MASK; + sscr0 |= SSCR0_SCR(mdiv); + + ssp_write(dai, SSCR0, sscr0); + + dai_info(dai, "ssp_bclk_prepare_enable(): sscr0 = 0x%08x", sscr0); +out: + if (!ret) + ssp->clk_active |= SSP_CLK_BCLK_ACTIVE; + + return ret; +} + +static void ssp_bclk_disable_unprepare(struct dai *dai) +{ + struct ssp_pdata *ssp = dai_get_drvdata(dai); + + if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) + return; +#if CONFIG_INTEL_MN + mn_release_bclk(dai->index); +#endif + ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE; +} + /* Digital Audio interface formatting */ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, void *spec_config) @@ -620,75 +726,21 @@ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, */ static int ssp_pre_start(struct dai *dai) { - struct ssp_pdata *ssp = dai_get_drvdata(dai); - struct sof_ipc_dai_config *config = &ssp->config; - uint32_t sscr0; - uint32_t mdiv; - bool need_ecs = false; - - int ret = 0; + int ret; dai_info(dai, "ssp_pre_start()"); - /* SSP active means bclk already configured. */ - if (ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_ACTIVE || - ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_ACTIVE) - return 0; + /* + * We will test if mclk/bclk is configured in + * ssp_mclk/bclk_prepare_enable/disable functions + */ /* MCLK config */ - ret = mn_set_mclk(config->ssp.mclk_id, config->ssp.mclk_rate); - if (ret < 0) { - dai_err(dai, "invalid mclk_rate = %d for mclk_id = %d", - config->ssp.mclk_rate, config->ssp.mclk_id); - goto out; - } - - sscr0 = ssp_read(dai, SSCR0); + ret = ssp_mclk_prepare_enable(dai); + if (ret < 0) + return ret; -#if CONFIG_INTEL_MN - /* BCLK config */ - ret = mn_set_bclk(config->dai_index, config->ssp.bclk_rate, - &mdiv, &need_ecs); - if (ret < 0) { - dai_err(dai, "invalid bclk_rate = %d for dai_index = %d", - config->ssp.bclk_rate, config->dai_index); - goto out; - } -#else - if (ssp_freq[SSP_DEFAULT_IDX].freq % config->ssp.bclk_rate != 0) { - dai_err(dai, "invalid bclk_rate = %d for dai_index = %d", - config->ssp.bclk_rate, config->dai_index); - ret = -EINVAL; - goto out; - } - - mdiv = ssp_freq[SSP_DEFAULT_IDX].freq / config->ssp.bclk_rate; -#endif - - if (need_ecs) - sscr0 |= SSCR0_ECS; - - /* clock divisor is SCR + 1 */ - mdiv -= 1; - - /* divisor must be within SCR range */ - if (mdiv > (SSCR0_SCR_MASK >> 8)) { - dai_err(dai, "ssp_pre_start(): divisor %d is not within SCR range", - mdiv); - ret = -EINVAL; - goto out; - } - - /* set the SCR divisor */ - sscr0 &= ~SSCR0_SCR_MASK; - sscr0 |= SSCR0_SCR(mdiv); - - ssp_write(dai, SSCR0, sscr0); - - dai_info(dai, "ssp_set_config(), sscr0 = 0x%08x", sscr0); -out: - - return ret; + return ssp_bclk_prepare_enable(dai); } /* @@ -704,10 +756,8 @@ static void ssp_post_stop(struct dai *dai) if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE && ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) { dai_info(dai, "releasing BCLK/MCLK clocks for SSP%d...", dai->index); -#if CONFIG_INTEL_MN - mn_release_bclk(dai->index); -#endif - mn_release_mclk(ssp->config.ssp.mclk_id); + ssp_bclk_disable_unprepare(dai); + ssp_mclk_disable_unprepare(dai); } } @@ -908,14 +958,10 @@ static int ssp_probe(struct dai *dai) static int ssp_remove(struct dai *dai) { - struct ssp_pdata *ssp = dai_get_drvdata(dai); - pm_runtime_put_sync(SSP_CLK, dai->index); - mn_release_mclk(ssp->config.ssp.mclk_id); -#if CONFIG_INTEL_MN - mn_release_bclk(dai->index); -#endif + ssp_mclk_disable_unprepare(dai); + ssp_bclk_disable_unprepare(dai); /* Disable SSP power */ pm_runtime_put_sync(SSP_POW, dai->index); diff --git a/src/include/sof/drivers/ssp.h b/src/include/sof/drivers/ssp.h index 051d404e28b6..d672159ca691 100644 --- a/src/include/sof/drivers/ssp.h +++ b/src/include/sof/drivers/ssp.h @@ -224,12 +224,16 @@ extern const struct dai_driver ssp_driver; #define ssp_irq(ssp) \ ssp->plat_data.irq +#define SSP_CLK_MCLK_ACTIVE BIT(0) +#define SSP_CLK_BCLK_ACTIVE BIT(1) + /* SSP private data */ struct ssp_pdata { uint32_t sscr0; uint32_t sscr1; uint32_t psp; uint32_t state[2]; /* SSP_STATE_ for each direction */ + uint32_t clk_active; struct sof_ipc_dai_config config; struct sof_ipc_dai_ssp_params params; }; From a0c175818d02a37d35f9ffdd04980b5c671ea3b9 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 20 May 2021 14:44:00 +0800 Subject: [PATCH 06/12] intel: ssp: handle MCLK/BCLK early start Some codecs need the SSP bit clock to start before data is provided, and conversely the bit clock to remain active until the hw_free stage. For backwards-compatibility with older kernels, the SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES and SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES bitfields are used to set an internal state in the ssp->clk_active field. This helps deals with the case where a topology sets these bits but the older kernel does not make use of the modified IPC. While we are at it, add clearer info traces for SSP configurations. Note that the FSYNC only starts when DMA transfers are enabled in the .trigger stage. This is by-design, the FSYNC will only start if the FIFO is not empty. During the prepare stages the DMA transfers are not enabled so the FIFOs are empty. To enable the FSYNC at an earlier stage, we would need a major surgery in the SOF architecture, or we would need to start zero-based DMA transfers. Co-developed-by: Pierre-Louis Bossart Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao --- src/drivers/intel/ssp/ssp.c | 100 +++++++++++++++++++++++++++++----- src/include/sof/drivers/ssp.h | 6 +- 2 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index 1d0c11a85ccf..4104c1457734 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -712,6 +712,63 @@ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE; ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE; + switch (config->flags & SOF_DAI_CONFIG_FLAGS_MASK) { + case SOF_DAI_CONFIG_FLAGS_HW_PARAMS: + if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES) { + ret = ssp_mclk_prepare_enable(dai); + if (ret < 0) + goto out; + + ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; + + dai_info(dai, "ssp_set_config(): hw_params stage: enabled MCLK clocks for SSP%d...", + dai->index); + } + + if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) { + bool enable_sse = false; + + if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) + enable_sse = true; + + ret = ssp_bclk_prepare_enable(dai); + if (ret < 0) + goto out; + + ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + + if (enable_sse) { + /* enable port */ + ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); + + dai_info(dai, "ssp_set_config(): SSE set for SSP%d", dai->index); + } + + dai_info(dai, "ssp_set_config(): hw_params stage: enabled BCLK clocks for SSP%d...", + dai->index); + } + break; + case SOF_DAI_CONFIG_FLAGS_HW_FREE: + if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) { + dai_info(dai, "ssp_set_config(): hw_free stage: releasing BCLK clocks for SSP%d...", + dai->index); + if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); + dai_info(dai, "ssp_set_config(): SSE clear for SSP%d", dai->index); + } + ssp_bclk_disable_unprepare(dai); + ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ; + } + if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES) { + dai_info(dai, "ssp_set_config: hw_free stage: releasing MCLK clocks for SSP%d...", + dai->index); + ssp_mclk_disable_unprepare(dai); + ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ; + } + break; + default: + break; + } out: spin_unlock(&dai->lock); @@ -726,7 +783,8 @@ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, */ static int ssp_pre_start(struct dai *dai) { - int ret; + struct ssp_pdata *ssp = dai_get_drvdata(dai); + int ret = 0; dai_info(dai, "ssp_pre_start()"); @@ -734,13 +792,17 @@ static int ssp_pre_start(struct dai *dai) * 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)) { + /* MCLK config */ + ret = ssp_mclk_prepare_enable(dai); + if (ret < 0) + return ret; + } - /* MCLK config */ - ret = ssp_mclk_prepare_enable(dai); - if (ret < 0) - return ret; + if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) + ret = ssp_bclk_prepare_enable(dai); - return ssp_bclk_prepare_enable(dai); + return ret; } /* @@ -755,9 +817,16 @@ static void ssp_post_stop(struct dai *dai) /* release clocks if SSP is inactive */ if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE && ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) { - dai_info(dai, "releasing BCLK/MCLK clocks for SSP%d...", dai->index); - ssp_bclk_disable_unprepare(dai); - ssp_mclk_disable_unprepare(dai); + if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + dai_info(dai, "ssp_post_stop releasing BCLK clocks for SSP%d...", + dai->index); + ssp_bclk_disable_unprepare(dai); + } + if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) { + dai_info(dai, "ssp_post_stop releasing MCLK clocks for SSP%d...", + dai->index); + ssp_mclk_disable_unprepare(dai); + } } } @@ -803,8 +872,11 @@ static void ssp_start(struct dai *dai, int direction) /* request mclk/bclk */ ssp_pre_start(dai); - /* enable port */ - ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); + if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + /* enable port */ + ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); + dai_info(dai, "ssp_start(): SSE set for SSP%d", dai->index); + } ssp->state[direction] = COMP_STATE_ACTIVE; dai_info(dai, "ssp_start()"); @@ -865,8 +937,10 @@ static void ssp_stop(struct dai *dai, int direction) /* disable SSP port if no users */ if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE && ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) { - ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); - dai_info(dai, "ssp_stop(), SSP port disabled"); + if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); + dai_info(dai, "ssp_stop(): SSE clear SSP%d", dai->index); + } } ssp_post_stop(dai); diff --git a/src/include/sof/drivers/ssp.h b/src/include/sof/drivers/ssp.h index d672159ca691..94787fe25a3f 100644 --- a/src/include/sof/drivers/ssp.h +++ b/src/include/sof/drivers/ssp.h @@ -224,8 +224,10 @@ extern const struct dai_driver ssp_driver; #define ssp_irq(ssp) \ ssp->plat_data.irq -#define SSP_CLK_MCLK_ACTIVE BIT(0) -#define SSP_CLK_BCLK_ACTIVE BIT(1) +#define SSP_CLK_MCLK_ES_REQ BIT(0) +#define SSP_CLK_MCLK_ACTIVE BIT(1) +#define SSP_CLK_BCLK_ES_REQ BIT(2) +#define SSP_CLK_BCLK_ACTIVE BIT(3) /* SSP private data */ struct ssp_pdata { From 99193ab5ae34a76cff7efd86bd75d1d3479d1301 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Jun 2021 15:42:18 -0500 Subject: [PATCH 07/12] intel: ssp: handle TSRE and RSRE along with SSE The current code does not follow recommended programming sequences: TSRE and RSRE should be set before SSE and conversely cleared before SSE. Signed-off-by: Pierre-Louis Bossart --- src/drivers/intel/ssp/ssp.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index 4104c1457734..acb992e8b9d9 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -286,8 +286,8 @@ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, */ sscr0 = SSCR0_PSP | SSCR0_RIM | SSCR0_TIM; - /* sscr1 dynamic settings are SFRMDIR, SCLKDIR, SCFR */ - sscr1 = SSCR1_TTE | SSCR1_TTELP | SSCR1_TRAIL | SSCR1_RSRE | SSCR1_TSRE; + /* sscr1 dynamic settings are SFRMDIR, SCLKDIR, SCFR, RSRE, TSRE */ + sscr1 = SSCR1_TTE | SSCR1_TTELP | SSCR1_TRAIL; /* sscr2 dynamic setting is LJDFD */ sscr2 = SSCR2_SDFD | SSCR2_TURM1; @@ -738,6 +738,12 @@ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; if (enable_sse) { + + /* enable TRSE/RSRE before SSE */ + ssp_update_bits(dai, SSCR1, + SSCR1_TSRE | SSCR1_RSRE, + SSCR1_TSRE | SSCR1_RSRE); + /* enable port */ ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); @@ -753,6 +759,11 @@ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, dai_info(dai, "ssp_set_config(): hw_free stage: releasing BCLK clocks for SSP%d...", dai->index); if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + /* clear TRSE/RSRE before SSE */ + ssp_update_bits(dai, SSCR1, + SSCR1_TSRE | SSCR1_RSRE, + 0); + ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); dai_info(dai, "ssp_set_config(): SSE clear for SSP%d", dai->index); } @@ -873,6 +884,11 @@ static void ssp_start(struct dai *dai, int direction) ssp_pre_start(dai); if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + /* enable TRSE/RSRE before SSE */ + ssp_update_bits(dai, SSCR1, + SSCR1_TSRE | SSCR1_RSRE, + SSCR1_TSRE | SSCR1_RSRE); + /* enable port */ ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); dai_info(dai, "ssp_start(): SSE set for SSP%d", dai->index); @@ -890,13 +906,10 @@ static void ssp_start(struct dai *dai, int direction) } /* enable DMA */ - if (direction == DAI_DIR_PLAYBACK) { - ssp_update_bits(dai, SSCR1, SSCR1_TSRE, SSCR1_TSRE); + if (direction == DAI_DIR_PLAYBACK) ssp_update_bits(dai, SSTSA, SSTSA_TXEN, SSTSA_TXEN); - } else { - ssp_update_bits(dai, SSCR1, SSCR1_RSRE, SSCR1_RSRE); + else ssp_update_bits(dai, SSRSA, SSRSA_RXEN, SSRSA_RXEN); - } /* wait to get valid fifo status */ wait_delay(PLATFORM_SSP_DELAY); @@ -917,7 +930,6 @@ static void ssp_stop(struct dai *dai, int direction) /* stop Rx if neeed */ if (direction == DAI_DIR_CAPTURE && ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_PREPARE) { - ssp_update_bits(dai, SSCR1, SSCR1_RSRE, 0); ssp_update_bits(dai, SSRSA, SSRSA_RXEN, 0); ssp_empty_rx_fifo(dai); ssp->state[SOF_IPC_STREAM_CAPTURE] = COMP_STATE_PREPARE; @@ -928,7 +940,6 @@ static void ssp_stop(struct dai *dai, int direction) if (direction == DAI_DIR_PLAYBACK && ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_PREPARE) { ssp_empty_tx_fifo(dai); - ssp_update_bits(dai, SSCR1, SSCR1_TSRE, 0); ssp_update_bits(dai, SSTSA, SSTSA_TXEN, 0); ssp->state[SOF_IPC_STREAM_PLAYBACK] = COMP_STATE_PREPARE; dai_info(dai, "ssp_stop(), TX stop"); @@ -938,6 +949,11 @@ static void ssp_stop(struct dai *dai, int direction) if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE && ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) { if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + /* clear TRSE/RSRE before SSE */ + ssp_update_bits(dai, SSCR1, + SSCR1_TSRE | SSCR1_RSRE, + 0); + ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); dai_info(dai, "ssp_stop(): SSE clear SSP%d", dai->index); } From 61e4cd7757fe05d0cf3df2f0c1645fcdf87b5903 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Thu, 27 May 2021 11:25:40 +0800 Subject: [PATCH 08/12] topology: ssp: mclk/bclk clock control Define the SSP_CC_MCLK/BCLK_ES bit to be used in SSP_CONFIG_DATA macro to enable mclk/bclk on hw_params and disable malk/bclk on hw_free. Signed-off-by: Brent Lu Signed-off-by: Bard Liao --- tools/topology/platform/common/ssp.m4 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/topology/platform/common/ssp.m4 b/tools/topology/platform/common/ssp.m4 index ce1f2c35b876..39a5ba185b0f 100644 --- a/tools/topology/platform/common/ssp.m4 +++ b/tools/topology/platform/common/ssp.m4 @@ -30,6 +30,11 @@ $6 dnl SSP_QUIRK_LBM 64 = (1 << 6) define(`SSP_QUIRK_LBM', 64) +dnl SSP_CC_MCLK_ES 64 = (1 << 6) +define(`SSP_CC_MCLK_ES', 64) +dnl SSP_CC_BCLK_ES 128 = (1 << 7) +define(`SSP_CC_BCLK_ES', 128) + dnl SSP_CONFIG_DATA(type, idx, valid bits, mclk_id, quirks, bclk_delay, dnl clks_control, pulse_width, padding) dnl mclk_id, quirks, bclk_delay clks_control, pulse_width and padding are optional From 8e1c9906b0e3f9b7566e0d4587c39e768856395e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 27 May 2021 10:02:07 +0800 Subject: [PATCH 09/12] topology: sof-apl-nocodec: enable MCLK/BCLK early start Set clks_control to (SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES | SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) to enable MCLK/BCLK early start feature. Signed-off-by: Bard Liao --- tools/topology/sof-apl-nocodec.m4 | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/topology/sof-apl-nocodec.m4 b/tools/topology/sof-apl-nocodec.m4 index 25210fc4483b..e479752d67ed 100644 --- a/tools/topology/sof-apl-nocodec.m4 +++ b/tools/topology/sof-apl-nocodec.m4 @@ -272,42 +272,48 @@ DAI_CONFIG(SSP, 0, 0, NoCodec-0, SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 16, 3, 3), dnl SSP_CONFIG_DATA(type, dai_index, valid bits, mclk_id, quirks) - SSP_CONFIG_DATA(SSP, 0, 16, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 0, 16, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(SSP, 1, 1, NoCodec-1, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in), SSP_CLOCK(bclk, 1536000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 16, 3, 3), - SSP_CONFIG_DATA(SSP, 1, 16, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 1, 16, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) #DAI_CONFIG(SSP, 2, 2, NoCodec-2, # SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in), # SSP_CLOCK(bclk, 1536000, codec_slave), # SSP_CLOCK(fsync, 48000, codec_slave), # SSP_TDM(2, 16, 3, 3), -# SSP_CONFIG_DATA(SSP, 2, 16, 0, SSP_QUIRK_LBM))) +# SSP_CONFIG_DATA(SSP, 2, 16, 0, SSP_QUIRK_LBM, 0, +# eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(SSP, 3, 3, NoCodec-3, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in), SSP_CLOCK(bclk, 1536000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 16, 3, 3), - SSP_CONFIG_DATA(SSP, 3, 16, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 3, 16, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) #DAI_CONFIG(SSP, 4, 4, NoCodec-4, # SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in), # SSP_CLOCK(bclk, 1536000, codec_slave), # SSP_CLOCK(fsync, 48000, codec_slave), # SSP_TDM(2, 16, 3, 3), -# SSP_CONFIG_DATA(SSP, 4, 16, 0, SSP_QUIRK_LBM))) +# SSP_CONFIG_DATA(SSP, 4, 16, 0, SSP_QUIRK_LBM, 0, +# eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(SSP, 5, 5, NoCodec-5, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in), SSP_CLOCK(bclk, 1536000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 16, 3, 3), - SSP_CONFIG_DATA(SSP, 5, 16, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 5, 16, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(DMIC, 0, 6, NoCodec-6, dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max, From 503dfd357f7fad53bd8d3310551f973d9b4e566b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 25 May 2021 17:54:29 +0800 Subject: [PATCH 10/12] topology: sof-cnl-nocodec: enable MCLK/BCLK early start Set clks_control to (SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES | SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) to enable MCLK/BCLK early start feature. Signed-off-by: Bard Liao --- tools/topology/sof-cnl-nocodec.m4 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/topology/sof-cnl-nocodec.m4 b/tools/topology/sof-cnl-nocodec.m4 index e50c4890f432..8facab900580 100644 --- a/tools/topology/sof-cnl-nocodec.m4 +++ b/tools/topology/sof-cnl-nocodec.m4 @@ -159,21 +159,24 @@ DAI_CONFIG(SSP, 0, 0, NoCodec-0, SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), dnl SSP_CONFIG_DATA(type, dai_index, valid bits, mclk_id, quirks) - SSP_CONFIG_DATA(SSP, 0, 24, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 0, 24, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(SSP, 1, 1, NoCodec-1, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in), SSP_CLOCK(bclk, 4800000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, 1, 24, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 1, 24, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(SSP, 2, 2, NoCodec-2, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in), SSP_CLOCK(bclk, 4800000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, 2, 24, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 2, 24, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(DMIC, 0, 3, NoCodec-3, DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 48000, From a194ef9b22ebc61d5991d7b21b7d96d409a0fc7d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Jun 2021 10:56:01 -0500 Subject: [PATCH 11/12] topology: sof-tgl-nocodec: enable MCLK/BCLK early start set clks_control to (SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES | SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) to enable MCLK/BCLK early start feature. Signed-off-by: Pierre-Louis Bossart --- tools/topology/sof-tgl-nocodec.m4 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/topology/sof-tgl-nocodec.m4 b/tools/topology/sof-tgl-nocodec.m4 index d9922544c742..930efdbdcb00 100644 --- a/tools/topology/sof-tgl-nocodec.m4 +++ b/tools/topology/sof-tgl-nocodec.m4 @@ -158,21 +158,24 @@ DAI_CONFIG(SSP, 0, 0, NoCodec-0, SSP_CLOCK(bclk, 2400000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, 0, 24, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 0, 24, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(SSP, 1, 1, NoCodec-1, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 38400000, codec_mclk_in), SSP_CLOCK(bclk, 2400000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, 1, 24, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 1, 24, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(SSP, 2, 2, NoCodec-2, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 38400000, codec_mclk_in), SSP_CLOCK(bclk, 2400000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, 2, 24, 0, SSP_QUIRK_LBM))) + SSP_CONFIG_DATA(SSP, 2, 24, 0, SSP_QUIRK_LBM, 0, + eval(SSP_CC_MCLK_ES | SSP_CC_BCLK_ES)))) DAI_CONFIG(DMIC, 0, 6, NoCodec-6, dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max, From 7199c686f2bd0f46ed64d5f78df3137afe083875 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Thu, 27 May 2021 10:06:34 +0800 Subject: [PATCH 12/12] topology: sof-glk-da7219/cs42l42: enable bclk control Enable the bclk clock control for SSP2. Note that this impacts existing GLK-based chromebooks as well as newer hardware. Signed-off-by: Brent Lu Signed-off-by: Bard Liao --- tools/topology/sof-glk-da7219.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/topology/sof-glk-da7219.m4 b/tools/topology/sof-glk-da7219.m4 index 0ea80f89dd43..eb4e52b00240 100644 --- a/tools/topology/sof-glk-da7219.m4 +++ b/tools/topology/sof-glk-da7219.m4 @@ -185,7 +185,7 @@ DAI_CONFIG(SSP, 2, 1, SSP2-Codec, SSP_CLOCK(bclk, 2400000, codec_slave), SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, 2, 16, 1, 0, 10))) + SSP_CONFIG_DATA(SSP, 2, 16, 1, 0, 0, SSP_CC_BCLK_ES))) ', ) # dmic01 (id: 2)