-
Notifications
You must be signed in to change notification settings - Fork 349
Start ssp clock earlier and stop later #4219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6f2f3db
7feb456
93379cd
3ffe417
8c269e5
0250a67
6e9ff5a
ae5ee43
ac19390
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -613,35 +613,49 @@ static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config, | |
| return ret; | ||
| } | ||
|
|
||
| /* | ||
| * Portion of the SSP configuration should be applied just before the | ||
| * SSP dai is activated, for either power saving or params runtime | ||
| * configurable flexibility. | ||
| */ | ||
| static int ssp_pre_start(struct dai *dai) | ||
| 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; | ||
| uint32_t sscr0; | ||
| uint32_t mdiv; | ||
| bool need_ecs = false; | ||
|
|
||
| int ret = 0; | ||
|
|
||
| dai_info(dai, "ssp_pre_start()"); | ||
| int ret; | ||
|
|
||
| /* 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) | ||
| 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) { | ||
| if (ret < 0) | ||
| dai_err(dai, "invalid mclk_rate = %d for mclk_id = %d", | ||
| config->ssp.mclk_rate, config->ssp.mclk_id); | ||
| goto out; | ||
| } | ||
| 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); | ||
|
|
||
|
|
@@ -686,6 +700,51 @@ static int ssp_pre_start(struct dai *dai) | |
|
|
||
| dai_info(dai, "ssp_set_config(), 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; | ||
| } | ||
|
|
||
| /* | ||
| * Portion of the SSP configuration should be applied just before the | ||
| * SSP dai is activated, for either power saving or params runtime | ||
| * configurable flexibility. | ||
| */ | ||
| static int ssp_pre_start(struct dai *dai) | ||
| { | ||
| struct ssp_pdata *ssp = dai_get_drvdata(dai); | ||
| int ret = 0; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here the initialisation is indeed redundant |
||
|
|
||
| dai_info(dai, "ssp_pre_start()"); | ||
|
|
||
| /* | ||
| * We will test if mclk/bclk is configured in | ||
| * ssp_mclk/bclk_prepare_enable/disable functions | ||
| */ | ||
| if (!(ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES)) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wrong indentation here and below |
||
| /* MCLK config */ | ||
| ret = ssp_mclk_prepare_enable(dai); | ||
| if (ret < 0) | ||
| return ret; | ||
| } | ||
|
|
||
| if (!(ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES)) | ||
| ret = ssp_bclk_prepare_enable(dai); | ||
|
|
||
| return ret; | ||
| } | ||
|
|
@@ -702,11 +761,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); | ||
| #if CONFIG_INTEL_MN | ||
| mn_release_bclk(dai->index); | ||
| #endif | ||
| mn_release_mclk(ssp->config.ssp.mclk_id); | ||
| if (!(ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES)) { | ||
| dai_info(dai, "ssp_post_stop releasing BCLK clocks for SSP%d...", dai->index); | ||
| ssp_bclk_disable_unprepare(dai); | ||
| } | ||
| if (!(ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES)) { | ||
| dai_info(dai, "ssp_post_stop releasing MCLK clocks for SSP%d...", dai->index); | ||
| ssp_mclk_disable_unprepare(dai); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -742,6 +806,78 @@ static int ssp_get_hw_params(struct dai *dai, | |
| return 0; | ||
| } | ||
|
|
||
| /* | ||
| * enabled clock MCLK/BCLK to support codec that need MCLK/BCLK | ||
| * This is called before trigger(COMP_TRIGGER_START) | ||
| */ | ||
| static int ssp_hw_params(struct dai *dai, | ||
| struct sof_ipc_stream_params *params) | ||
| { | ||
| struct ssp_pdata *ssp = dai_get_drvdata(dai); | ||
|
||
| int ret; | ||
|
|
||
| if (ssp->state[SOF_IPC_STREAM_CAPTURE] < COMP_STATE_PREPARE || | ||
| ssp->state[SOF_IPC_STREAM_PLAYBACK] < COMP_STATE_PREPARE) { | ||
| dai_err(dai, "ssp_hw_params(): Please set config first"); | ||
| return -EINVAL; | ||
bardliao marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
bardliao marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| dai_info(dai, "ssp_hw_params() params.clks_control 0x%x", ssp->params.clks_control); | ||
|
||
|
|
||
| spin_lock(&dai->lock); | ||
|
||
|
|
||
plbossart marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if ((ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES)) { | ||
| ret = ssp_mclk_prepare_enable(dai); | ||
| if (ret < 0) | ||
| goto out; | ||
| } | ||
|
|
||
| if ((ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES)) { | ||
| ret = ssp_bclk_prepare_enable(dai); | ||
| if (ret < 0) | ||
| goto out; | ||
| /* enable port */ | ||
| ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); | ||
| } | ||
| out: | ||
|
|
||
| spin_unlock(&dai->lock); | ||
|
||
| return 0; | ||
| } | ||
|
|
||
| /* | ||
| * disabled clock MCLK/BCLK to support codec that need MCLK/BCLK | ||
| * This is called after trigger(COMP_TRIGGER_STOP) | ||
| */ | ||
| static void ssp_hw_free(struct dai *dai) | ||
| { | ||
| struct ssp_pdata *ssp = dai_get_drvdata(dai); | ||
|
|
||
| dai_info(dai, "ssp_hw_free()"); | ||
|
|
||
| spin_lock(&dai->lock); | ||
|
|
||
| /* release clocks if SSP is inactive */ | ||
| if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE && | ||
| ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) { | ||
| if ((ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES)) { | ||
| dai_info(dai, "ssp_hw_free() releasing BCLK clocks for SSP%d...", dai->index); | ||
| ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); | ||
| ssp_bclk_disable_unprepare(dai); | ||
| } | ||
| if ((ssp->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES)) { | ||
| dai_info(dai, "ssp_hw_free releasing MCLK clocks for SSP%d...", dai->index); | ||
| ssp_mclk_disable_unprepare(dai); | ||
| } | ||
| } | ||
|
|
||
| spin_unlock(&dai->lock); | ||
| } | ||
|
|
||
| /* start the SSP for either playback or capture */ | ||
| static void ssp_start(struct dai *dai, int direction) | ||
| { | ||
|
|
@@ -752,8 +888,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->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES)) { | ||
| /* enable port */ | ||
| ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); | ||
|
||
| } | ||
|
||
| ssp->state[direction] = COMP_STATE_ACTIVE; | ||
|
|
||
| dai_info(dai, "ssp_start()"); | ||
|
|
@@ -814,8 +953,11 @@ 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->params.clks_control & | ||
| SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES)) { | ||
| ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); | ||
| dai_info(dai, "ssp_stop(), SSP port disabled"); | ||
| } | ||
| } | ||
|
|
||
| ssp_post_stop(dai); | ||
|
|
@@ -907,14 +1049,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); | ||
|
|
@@ -949,6 +1087,8 @@ const struct dai_driver ssp_driver = { | |
| .get_hw_params = ssp_get_hw_params, | ||
| .get_handshake = ssp_get_handshake, | ||
| .get_fifo = ssp_get_fifo, | ||
| .hw_params = ssp_hw_params, | ||
| .hw_free = ssp_hw_free, | ||
| .probe = ssp_probe, | ||
| .remove = ssp_remove, | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's incomplete...we need to modify the SSP_CONFIG_DATA macro here
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @plbossart I think the issue is that 636cbef is already on the main branch, but @brentlu was testing with glk-012-stable-branch branch where 636cbef is not there. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to init?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to init because
ret = mn_set_bclk()is only called ifCONFIG_INTEL_MNThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's something weird there: in the
#elsecase below if the condition isn't satisfied we print an error message and jump toout, but we don't setret... Is that correct?