Skip to content

Commit 8233990

Browse files
bardliaomwasko
authored andcommitted
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 <pierre-louis.bossart@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Brent Lu <brent.lu@intel.com>
1 parent e819f50 commit 8233990

2 files changed

Lines changed: 91 additions & 15 deletions

File tree

src/drivers/intel/ssp/ssp.c

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,63 @@ static int ssp_set_config(struct dai *dai,
711711
ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE;
712712
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
713713

714+
switch (config->flags & SOF_DAI_CONFIG_FLAGS_MASK) {
715+
case SOF_DAI_CONFIG_FLAGS_HW_PARAMS:
716+
if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES) {
717+
ret = ssp_mclk_prepare_enable(dai);
718+
if (ret < 0)
719+
goto out;
720+
721+
ssp->clk_active |= SSP_CLK_MCLK_ES_REQ;
722+
723+
dai_info(dai, "ssp_set_config(): hw_params stage: enabled MCLK clocks for SSP%d...",
724+
dai->index);
725+
}
726+
727+
if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) {
728+
bool enable_sse = false;
729+
730+
if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE))
731+
enable_sse = true;
732+
733+
ret = ssp_bclk_prepare_enable(dai);
734+
if (ret < 0)
735+
goto out;
736+
737+
ssp->clk_active |= SSP_CLK_BCLK_ES_REQ;
738+
739+
if (enable_sse) {
740+
/* enable port */
741+
ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
742+
743+
dai_info(dai, "ssp_set_config(): SSE set for SSP%d", dai->index);
744+
}
745+
746+
dai_info(dai, "ssp_set_config(): hw_params stage: enabled BCLK clocks for SSP%d...",
747+
dai->index);
748+
}
749+
break;
750+
case SOF_DAI_CONFIG_FLAGS_HW_FREE:
751+
if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) {
752+
dai_info(dai, "ssp_set_config(): hw_free stage: releasing BCLK clocks for SSP%d...",
753+
dai->index);
754+
if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
755+
ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
756+
dai_info(dai, "ssp_set_config(): SSE clear for SSP%d", dai->index);
757+
}
758+
ssp_bclk_disable_unprepare(dai);
759+
ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ;
760+
}
761+
if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES) {
762+
dai_info(dai, "ssp_set_config: hw_free stage: releasing MCLK clocks for SSP%d...",
763+
dai->index);
764+
ssp_mclk_disable_unprepare(dai);
765+
ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ;
766+
}
767+
break;
768+
default:
769+
break;
770+
}
714771
out:
715772

716773
spin_unlock(&dai->lock);
@@ -725,21 +782,26 @@ static int ssp_set_config(struct dai *dai,
725782
*/
726783
static int ssp_pre_start(struct dai *dai)
727784
{
728-
int ret;
785+
struct ssp_pdata *ssp = dai_get_drvdata(dai);
786+
int ret = 0;
729787

730788
dai_info(dai, "ssp_pre_start()");
731789

732790
/*
733791
* We will test if mclk/bclk is configured in
734792
* ssp_mclk/bclk_prepare_enable/disable functions
735793
*/
794+
if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
795+
/* MCLK config */
796+
ret = ssp_mclk_prepare_enable(dai);
797+
if (ret < 0)
798+
return ret;
799+
}
736800

737-
/* MCLK config */
738-
ret = ssp_mclk_prepare_enable(dai);
739-
if (ret < 0)
740-
return ret;
801+
if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ))
802+
ret = ssp_bclk_prepare_enable(dai);
741803

742-
return ssp_bclk_prepare_enable(dai);
804+
return ret;
743805
}
744806

745807
/*
@@ -754,9 +816,16 @@ static void ssp_post_stop(struct dai *dai)
754816
/* release clocks if SSP is inactive */
755817
if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE &&
756818
ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) {
757-
dai_info(dai, "releasing BCLK/MCLK clocks for SSP%d...", dai->index);
758-
ssp_bclk_disable_unprepare(dai);
759-
ssp_mclk_disable_unprepare(dai);
819+
if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
820+
dai_info(dai, "ssp_post_stop releasing BCLK clocks for SSP%d...",
821+
dai->index);
822+
ssp_bclk_disable_unprepare(dai);
823+
}
824+
if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
825+
dai_info(dai, "ssp_post_stop releasing MCLK clocks for SSP%d...",
826+
dai->index);
827+
ssp_mclk_disable_unprepare(dai);
828+
}
760829
}
761830
}
762831

@@ -802,8 +871,11 @@ static void ssp_start(struct dai *dai, int direction)
802871
/* request mclk/bclk */
803872
ssp_pre_start(dai);
804873

805-
/* enable port */
806-
ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
874+
if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
875+
/* enable port */
876+
ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
877+
dai_info(dai, "ssp_start(): SSE set for SSP%d", dai->index);
878+
}
807879
ssp->state[direction] = COMP_STATE_ACTIVE;
808880

809881
dai_info(dai, "ssp_start()");
@@ -864,8 +936,10 @@ static void ssp_stop(struct dai *dai, int direction)
864936
/* disable SSP port if no users */
865937
if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE &&
866938
ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) {
867-
ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
868-
dai_info(dai, "ssp_stop(), SSP port disabled");
939+
if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
940+
ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
941+
dai_info(dai, "ssp_stop(): SSE clear SSP%d", dai->index);
942+
}
869943
}
870944

871945
ssp_post_stop(dai);

src/include/sof/drivers/ssp.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,10 @@ extern const struct dai_driver ssp_driver;
224224
#define ssp_irq(ssp) \
225225
ssp->plat_data.irq
226226

227-
#define SSP_CLK_MCLK_ACTIVE BIT(0)
228-
#define SSP_CLK_BCLK_ACTIVE BIT(1)
227+
#define SSP_CLK_MCLK_ES_REQ BIT(0)
228+
#define SSP_CLK_MCLK_ACTIVE BIT(1)
229+
#define SSP_CLK_BCLK_ES_REQ BIT(2)
230+
#define SSP_CLK_BCLK_ACTIVE BIT(3)
229231

230232
/* SSP private data */
231233
struct ssp_pdata {

0 commit comments

Comments
 (0)