diff --git a/src/audio/dai.c b/src/audio/dai.c index 108b40368844..a4ecf1694148 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -737,8 +737,8 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_err(dev, "dai_config(): Component is in active state."); - return -EINVAL; + comp_info(dev, "dai_config(): Component is in active state. Ignore config"); + return 0; } switch (config->type) { diff --git a/src/drivers/intel/baytrail/ssp.c b/src/drivers/intel/baytrail/ssp.c index b4f3c24d0c28..de740ceff427 100644 --- a/src/drivers/intel/baytrail/ssp.c +++ b/src/drivers/intel/baytrail/ssp.c @@ -100,8 +100,7 @@ static int ssp_set_config(struct dai *dai, /* is playback/capture already running */ if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE || ssp->state[DAI_DIR_CAPTURE] == COMP_STATE_ACTIVE) { - dai_err(dai, "ssp_set_config(): playback/capture already running"); - ret = -EINVAL; + dai_info(dai, "ssp_set_config(): playback/capture active. Ignore config"); goto out; } diff --git a/src/drivers/intel/haswell/ssp.c b/src/drivers/intel/haswell/ssp.c index f11e7bf49372..6e0b5094504c 100644 --- a/src/drivers/intel/haswell/ssp.c +++ b/src/drivers/intel/haswell/ssp.c @@ -76,8 +76,7 @@ static int ssp_set_config(struct dai *dai, /* is playback/capture already running */ if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE || ssp->state[DAI_DIR_CAPTURE] == COMP_STATE_ACTIVE) { - dai_err(dai, "ssp_set_config(): playback/capture already running"); - ret = -EINVAL; + dai_info(dai, "ssp_set_config(): playback/capture active. Ignore config"); goto out; } diff --git a/src/drivers/intel/ssp/ssp.c b/src/drivers/intel/ssp/ssp.c index 9765f737bf18..955069dd6db3 100644 --- a/src/drivers/intel/ssp/ssp.c +++ b/src/drivers/intel/ssp/ssp.c @@ -136,11 +136,55 @@ static int ssp_set_config(struct dai *dai, spin_lock(&dai->lock); + /* unlike the implementation in main branch, here the set config + * command sent from host is just for clock control + */ + 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_BCLK_ES) && + !(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_set_config(), SSP%d port enabled", dai->index); + + ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + } + + goto out; + case SOF_DAI_CONFIG_FLAGS_HW_FREE: + if ((ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) && + (ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + /* disable SSP port if no users */ + if (ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE && + ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE) { + /* clear TRSE/RSRE before SSE */ + ssp_update_bits(dai, SSCR1, + SSCR1_TSRE | SSCR1_RSRE, + 0); + + ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0); + ssp->state[SOF_IPC_STREAM_CAPTURE] = COMP_STATE_PREPARE; + ssp->state[SOF_IPC_STREAM_PLAYBACK] = COMP_STATE_PREPARE; + dai_info(dai, "ssp_set_config(), SSP%d port disabled", dai->index); + + ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ; + } + } + + goto out; + default: + break; + } + /* is playback/capture already running */ if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE || ssp->state[DAI_DIR_CAPTURE] == COMP_STATE_ACTIVE) { - dai_info(dai, "ssp_set_config(): playback/capture already running"); - ret = -EINVAL; + dai_info(dai, "ssp_set_config(): playback/capture active. Ignore config"); goto out; } @@ -155,8 +199,8 @@ static int ssp_set_config(struct dai *dai, */ 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; @@ -672,8 +716,17 @@ static void ssp_start(struct dai *dai, int direction) spin_lock(&dai->lock); - /* enable port */ - ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE); + 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(), SSP%d port enabled", dai->index); + } + ssp->state[direction] = COMP_STATE_ACTIVE; dai_info(dai, "ssp_start()"); @@ -687,13 +740,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); @@ -714,7 +764,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; @@ -725,7 +774,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"); @@ -734,8 +782,15 @@ 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)) { + /* 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(), SSP%d port disabled", dai->index); + } } spin_unlock(&dai->lock); diff --git a/src/include/ipc/dai-intel.h b/src/include/ipc/dai-intel.h index 9e5c395a4928..4d95e7bc2ed0 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 diff --git a/src/include/ipc/dai.h b/src/include/ipc/dai.h index 50f986f54baa..bfeef5e16416 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_MASTER_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 */ @@ -71,7 +78,8 @@ struct sof_ipc_dai_config { /* physical protocol and clocking */ uint16_t format; /**< SOF_DAI_FMT_ */ - uint16_t reserved16; /**< alignment */ + uint8_t reserved8; /**< alignment */ + uint8_t flags; /**< SOF_DAI_CONFIG_FLAGS_ (ABI 3.19) */ /* reserved for future use */ uint32_t reserved[8]; diff --git a/src/include/kernel/abi.h b/src/include/kernel/abi.h index c7f343f355ef..4eb01a563882 100644 --- a/src/include/kernel/abi.h +++ b/src/include/kernel/abi.h @@ -29,7 +29,7 @@ /** \brief SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 17 +#define SOF_ABI_MINOR 18 #define SOF_ABI_PATCH 0 /** \brief SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/src/include/sof/drivers/ssp.h b/src/include/sof/drivers/ssp.h index 43987ee1f08f..a42ee6261e68 100644 --- a/src/include/sof/drivers/ssp.h +++ b/src/include/sof/drivers/ssp.h @@ -220,12 +220,18 @@ extern const struct dai_driver ssp_driver; #define ssp_irq(ssp) \ ssp->plat_data.irq +#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 { 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; }; diff --git a/tools/topology/CMakeLists.txt b/tools/topology/CMakeLists.txt index 151c478d4cb6..50296b660ace 100644 --- a/tools/topology/CMakeLists.txt +++ b/tools/topology/CMakeLists.txt @@ -137,9 +137,10 @@ set(TPLGS "sof-jsl-da7219\;sof-jsl-da7219-mx98360a\;-DPLATFORM=jsl-dedede" "sof-imx8mp-wm8960\;sof-imx8mp-wm8960" "sof-smart-amplifier-nocodec\;sof-smart-amplifier-nocodec" - "sof-jsl-rt5682\;sof-jsl-rt5682-rt1015\;-DPLATFORM=jsl-rt1015" - "sof-jsl-rt5682\;sof-jsl-rt5682-rt1015-xperi\;-DPLATFORM=jsl-rt1015\;-DINCLUDE_IIR_EQ=1" - "sof-jsl-rt5682\;sof-jsl-rt5682-mx98360a\;-DPLATFORM=jsl-dedede" + "sof-jsl-rt5682\;sof-jsl-rt5682-rt1015\;-DHEADPHONE=rt5682\;-DPLATFORM=jsl-rt1015" + "sof-jsl-rt5682\;sof-jsl-rt5682-rt1015-xperi\;-DHEADPHONE=rt5682\;-DPLATFORM=jsl-rt1015\;-DINCLUDE_IIR_EQ=1" + "sof-jsl-rt5682\;sof-jsl-rt5682-mx98360a\;-DHEADPHONE=rt5682\;-DPLATFORM=jsl-dedede" + "sof-jsl-rt5682\;sof-jsl-cs42l42-mx98360a\;-DHEADPHONE=cs42l42\;-DPLATFORM=jsl-dedede" ) add_custom_target(topologies ALL) diff --git a/tools/topology/platform/common/ssp.m4 b/tools/topology/platform/common/ssp.m4 index 22edd8578d72..9236016bc462 100644 --- a/tools/topology/platform/common/ssp.m4 +++ b/tools/topology/platform/common/ssp.m4 @@ -30,18 +30,29 @@ $6 dnl SSP_QUIRK_LBM 64 = (1 << 6) define(`SSP_QUIRK_LBM', 64) -dnl SSP_CONFIG_DATA(type, idx, valid bits, mclk_id, quirks, bclk_delay) -dnl mclk_id, quirks, bclk_delay are optional +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 define(`SSP_CONFIG_DATA', `SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples" {' ` tokens "sof_ssp_tokens"' ` tuples."word" {' ` SOF_TKN_INTEL_SSP_SAMPLE_BITS' STR($3) -` SOF_TKN_INTEL_SSP_QUIRKS' ifelse($5, `', "0", STR($5)) -` SOF_TKN_INTEL_SSP_BCLK_DELAY' ifelse($6, `', "0", STR($6)) +` SOF_TKN_INTEL_SSP_QUIRKS' `ifelse(`$5', `', "0", STR($5))' +` SOF_TKN_INTEL_SSP_BCLK_DELAY' `ifelse(`$6', `', "0", STR($6))' +` SOF_TKN_INTEL_SSP_CLKS_CONTROL' `ifelse(`$7', `', "0", STR($7))' ` }' ` tuples."short" {' -` SOF_TKN_INTEL_SSP_MCLK_ID' ifelse($4, `', "0", STR($4)) +` SOF_TKN_INTEL_SSP_MCLK_ID' `ifelse(`$4', `', "0", STR($4))' +` SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH' `ifelse(`$8', `', "0", STR($8))' +` }' +` tuples."bool" {' +` SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT' `ifelse(`$9', `', "false", STR($9))' ` }' `}' `SectionData."'N_DAI_CONFIG($1$2)`_data" {' diff --git a/tools/topology/sof-jsl-rt5682.m4 b/tools/topology/sof-jsl-rt5682.m4 index dcf6122ccd66..68bcd415f323 100644 --- a/tools/topology/sof-jsl-rt5682.m4 +++ b/tools/topology/sof-jsl-rt5682.m4 @@ -1,5 +1,8 @@ # -# Topology for JasperLake with rt5682 codec + DMIC + 3 HDMI + Speaker amp +# Topology for JasperLake with rt5682 or cs42l42 codec + +# DMIC + +# 3 HDMI + +# speaker amp # # Include topology builder @@ -24,7 +27,7 @@ DEBUG_START # Define the pipelines # # PCM0 ----> volume -----> SSP1 (Speaker - ALC1015) -# PCM1 <---> volume <----> SSP0 (Headset - ALC5682) +`# PCM1 <---> volume <----> SSP0 (Headset - 'HEADPHONE`)' # PCM2 ----> volume -----> iDisp1 # PCM3 ----> volume -----> iDisp2 # PCM4 ----> volume -----> iDisp3 @@ -176,6 +179,7 @@ dnl SSP_CONFIG(format, mclk, bclk, fsync, tdm, ssp_config_data) dnl SSP_CLOCK(clock, freq, codec_master, polarity) dnl SSP_CONFIG_DATA(type, idx, valid bits, mclk_id) +ifelse(HEADPHONE, `rt5682', ` # SSP 0 (ID: 0) ALC5682 DAI_CONFIG(SSP, 0, 0, SSP0-Codec, SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in), @@ -183,6 +187,15 @@ DAI_CONFIG(SSP, 0, 0, SSP0-Codec, SSP_CLOCK(fsync, 48000, codec_slave), SSP_TDM(2, 25, 3, 3), SSP_CONFIG_DATA(SSP, 0, 24))) +', HEADPHONE, `cs42l42', ` +# SSP 0 (ID: 0) CS42L42 +DAI_CONFIG(SSP, 0, 0, SSP0-Codec, + SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, 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, 0, 24, 0, 0, 0, SSP_CC_BCLK_ES))) +', ) # SSP 1 (ID: 6) DAI_CONFIG(SSP, SPK_INDEX, 6, SPK_NAME,