Skip to content
4 changes: 2 additions & 2 deletions src/audio/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 1 addition & 2 deletions src/drivers/intel/baytrail/ssp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 1 addition & 2 deletions src/drivers/intel/haswell/ssp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
85 changes: 70 additions & 15 deletions src/drivers/intel/ssp/ssp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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()");
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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");
Expand All @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/include/ipc/dai-intel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion src/include/ipc/dai.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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];
Expand Down
2 changes: 1 addition & 1 deletion src/include/kernel/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
6 changes: 6 additions & 0 deletions src/include/sof/drivers/ssp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
7 changes: 4 additions & 3 deletions tools/topology/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
21 changes: 16 additions & 5 deletions tools/topology/platform/common/ssp.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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" {'
Expand Down
17 changes: 15 additions & 2 deletions tools/topology/sof-jsl-rt5682.m4
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -176,13 +179,23 @@ 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),
SSP_CLOCK(bclk, 2400000, codec_slave),
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,
Expand Down