mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 00:35:42 +01:00
topology: plugins: nhlt: fix ssp dai index
There was a conceptual error in handling the separate ssp dais, so fix it. Fixes: https://github.com/alsa-project/alsa-utils/pull/164 Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
e13a7d3cf6
commit
c57391dd26
4 changed files with 106 additions and 100 deletions
|
@ -168,7 +168,8 @@ int nhlt_ssp_get_ep(struct intel_nhlt_params *nhlt, struct endpoint_descriptor *
|
||||||
/* fill in wave format extensible types */
|
/* fill in wave format extensible types */
|
||||||
f_conf1[i].format.wFormatTag = 0xFFFE;
|
f_conf1[i].format.wFormatTag = 0xFFFE;
|
||||||
|
|
||||||
ret = ssp_get_hw_params(nhlt, i, &sample_rate, &channel_count, &bits_per_sample);
|
ret = ssp_get_hw_params(nhlt, dai_index, i, &sample_rate, &channel_count,
|
||||||
|
&bits_per_sample);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "nhlt_ssp_get_ep: ssp_get_hw_params failed\n");
|
fprintf(stderr, "nhlt_ssp_get_ep: ssp_get_hw_params failed\n");
|
||||||
|
|
|
@ -47,7 +47,7 @@ struct ssp_config_dai {
|
||||||
|
|
||||||
struct intel_ssp_params {
|
struct intel_ssp_params {
|
||||||
/* structs to gather ssp params before calculations */
|
/* structs to gather ssp params before calculations */
|
||||||
struct ssp_config_dai ssp_prm;
|
struct ssp_config_dai ssp_prm[SSP_MAX_DAIS];
|
||||||
uint32_t ssp_dai_index[SSP_MAX_DAIS];
|
uint32_t ssp_dai_index[SSP_MAX_DAIS];
|
||||||
uint32_t ssp_hw_config_count[SSP_MAX_DAIS];
|
uint32_t ssp_hw_config_count[SSP_MAX_DAIS];
|
||||||
int ssp_count;
|
int ssp_count;
|
||||||
|
|
|
@ -69,7 +69,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
ssp->ssp_blob[di][hwi].gateway_attributes = 0;
|
ssp->ssp_blob[di][hwi].gateway_attributes = 0;
|
||||||
|
|
||||||
for (j = 0; j < SSP_TDM_MAX_SLOT_MAP_COUNT; j++) {
|
for (j = 0; j < SSP_TDM_MAX_SLOT_MAP_COUNT; j++) {
|
||||||
for (i = 0; i < ssp->ssp_prm.hw_cfg[hwi].tdm_slots; i++)
|
for (i = 0; i < ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots; i++)
|
||||||
ssp->ssp_blob[di][hwi].ts_group[j] |= (i << (i * 4));
|
ssp->ssp_blob[di][hwi].ts_group[j] |= (i << (i * 4));
|
||||||
for (; i < SSP_TDM_MAX_SLOT_MAP_COUNT; i++)
|
for (; i < SSP_TDM_MAX_SLOT_MAP_COUNT; i++)
|
||||||
ssp->ssp_blob[di][hwi].ts_group[j] |= (0xF << (i * 4));
|
ssp->ssp_blob[di][hwi].ts_group[j] |= (0xF << (i * 4));
|
||||||
|
@ -102,12 +102,12 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
ssp->ssp_blob[di][hwi].sscto = 0x0;
|
ssp->ssp_blob[di][hwi].sscto = 0x0;
|
||||||
|
|
||||||
/* sstsa dynamic setting is TTSA, default 2 slots */
|
/* sstsa dynamic setting is TTSA, default 2 slots */
|
||||||
ssp->ssp_blob[di][hwi].sstsa = SSTSA_SSTSA(ssp->ssp_prm.hw_cfg[hwi].tx_slots);
|
ssp->ssp_blob[di][hwi].sstsa = SSTSA_SSTSA(ssp->ssp_prm[di].hw_cfg[hwi].tx_slots);
|
||||||
|
|
||||||
/* ssrsa dynamic setting is RTSA, default 2 slots */
|
/* ssrsa dynamic setting is RTSA, default 2 slots */
|
||||||
ssp->ssp_blob[di][hwi].ssrsa = SSRSA_SSRSA(ssp->ssp_prm.hw_cfg[hwi].rx_slots);
|
ssp->ssp_blob[di][hwi].ssrsa = SSRSA_SSRSA(ssp->ssp_prm[di].hw_cfg[hwi].rx_slots);
|
||||||
|
|
||||||
switch (ssp->ssp_prm.hw_cfg[hwi].format & SSP_FMT_CLOCK_PROVIDER_MASK) {
|
switch (ssp->ssp_prm[di].hw_cfg[hwi].format & SSP_FMT_CLOCK_PROVIDER_MASK) {
|
||||||
case SSP_FMT_CBP_CFP:
|
case SSP_FMT_CBP_CFP:
|
||||||
ssp->ssp_blob[di][hwi].ssc1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
|
ssp->ssp_blob[di][hwi].ssc1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
|
||||||
break;
|
break;
|
||||||
|
@ -131,7 +131,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clock signal polarity */
|
/* clock signal polarity */
|
||||||
switch (ssp->ssp_prm.hw_cfg[hwi].format & SSP_FMT_INV_MASK) {
|
switch (ssp->ssp_prm[di].hw_cfg[hwi].format & SSP_FMT_INV_MASK) {
|
||||||
case SSP_FMT_NB_NF:
|
case SSP_FMT_NB_NF:
|
||||||
break;
|
break;
|
||||||
case SSP_FMT_NB_IF:
|
case SSP_FMT_NB_IF:
|
||||||
|
@ -150,7 +150,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* supporting bclk idle state */
|
/* supporting bclk idle state */
|
||||||
if (ssp->ssp_prm.clks_control &
|
if (ssp->ssp_prm[di].clks_control &
|
||||||
SSP_INTEL_CLKCTRL_BCLK_IDLE_HIGH) {
|
SSP_INTEL_CLKCTRL_BCLK_IDLE_HIGH) {
|
||||||
/* bclk idle state high */
|
/* bclk idle state high */
|
||||||
ssp->ssp_blob[di][hwi].sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3);
|
ssp->ssp_blob[di][hwi].sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3);
|
||||||
|
@ -164,82 +164,86 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
/* Additional hardware settings */
|
/* Additional hardware settings */
|
||||||
|
|
||||||
/* Receiver Time-out Interrupt Disabled/Enabled */
|
/* Receiver Time-out Interrupt Disabled/Enabled */
|
||||||
ssp->ssp_blob[di][hwi].ssc1 |= (ssp->ssp_prm.quirks & SSP_INTEL_QUIRK_TINTE) ?
|
ssp->ssp_blob[di][hwi].ssc1 |= (ssp->ssp_prm[di].quirks & SSP_INTEL_QUIRK_TINTE) ?
|
||||||
SSCR1_TINTE : 0;
|
SSCR1_TINTE : 0;
|
||||||
|
|
||||||
/* Peripheral Trailing Byte Interrupts Disable/Enable */
|
/* Peripheral Trailing Byte Interrupts Disable/Enable */
|
||||||
ssp->ssp_blob[di][hwi].ssc1 |= (ssp->ssp_prm.quirks & SSP_INTEL_QUIRK_PINTE) ?
|
ssp->ssp_blob[di][hwi].ssc1 |= (ssp->ssp_prm[di].quirks & SSP_INTEL_QUIRK_PINTE) ?
|
||||||
SSCR1_PINTE : 0;
|
SSCR1_PINTE : 0;
|
||||||
|
|
||||||
/* Enable/disable internal loopback. Output of transmit serial
|
/* Enable/disable internal loopback. Output of transmit serial
|
||||||
* shifter connected to input of receive serial shifter, internally.
|
* shifter connected to input of receive serial shifter, internally.
|
||||||
*/
|
*/
|
||||||
ssp->ssp_blob[di][hwi].ssc1 |= (ssp->ssp_prm.quirks & SSP_INTEL_QUIRK_LBM) ?
|
ssp->ssp_blob[di][hwi].ssc1 |= (ssp->ssp_prm[di].quirks & SSP_INTEL_QUIRK_LBM) ?
|
||||||
SSCR1_LBM : 0;
|
SSCR1_LBM : 0;
|
||||||
|
|
||||||
/* Transmit data are driven at the same/opposite clock edge specified
|
/* Transmit data are driven at the same/opposite clock edge specified
|
||||||
* in SSPSP.SCMODE[1:0]
|
* in SSPSP.SCMODE[1:0]
|
||||||
*/
|
*/
|
||||||
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm.quirks & SSP_INTEL_QUIRK_SMTATF) ?
|
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm[di].quirks & SSP_INTEL_QUIRK_SMTATF) ?
|
||||||
SSCR2_SMTATF : 0;
|
SSCR2_SMTATF : 0;
|
||||||
|
|
||||||
/* Receive data are sampled at the same/opposite clock edge specified
|
/* Receive data are sampled at the same/opposite clock edge specified
|
||||||
* in SSPSP.SCMODE[1:0]
|
* in SSPSP.SCMODE[1:0]
|
||||||
*/
|
*/
|
||||||
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm.quirks & SSP_INTEL_QUIRK_MMRATF) ?
|
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm[di].quirks & SSP_INTEL_QUIRK_MMRATF) ?
|
||||||
SSCR2_MMRATF : 0;
|
SSCR2_MMRATF : 0;
|
||||||
|
|
||||||
/* Enable/disable the fix for PSP consumer mode TXD wait for frame
|
/* Enable/disable the fix for PSP consumer mode TXD wait for frame
|
||||||
* de-assertion before starting the second channel
|
* de-assertion before starting the second channel
|
||||||
*/
|
*/
|
||||||
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm.quirks & SSP_INTEL_QUIRK_PSPSTWFDFD) ?
|
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm[di].quirks & SSP_INTEL_QUIRK_PSPSTWFDFD) ?
|
||||||
SSCR2_PSPSTWFDFD : 0;
|
SSCR2_PSPSTWFDFD : 0;
|
||||||
|
|
||||||
/* Enable/disable the fix for PSP provider mode FSRT with dummy stop &
|
/* Enable/disable the fix for PSP provider mode FSRT with dummy stop &
|
||||||
* frame end padding capability
|
* frame end padding capability
|
||||||
*/
|
*/
|
||||||
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm.quirks & SSP_INTEL_QUIRK_PSPSRWFDFD) ?
|
ssp->ssp_blob[di][hwi].ssc2 |= (ssp->ssp_prm[di].quirks & SSP_INTEL_QUIRK_PSPSRWFDFD) ?
|
||||||
SSCR2_PSPSRWFDFD : 0;
|
SSCR2_PSPSRWFDFD : 0;
|
||||||
|
|
||||||
if (!ssp->ssp_prm.hw_cfg[hwi].mclk_rate) {
|
if (!ssp->ssp_prm[di].hw_cfg[hwi].mclk_rate) {
|
||||||
fprintf(stderr, "ssp_calculate(): invalid MCLK = %u \n",
|
fprintf(stderr, "ssp_calculate(): invalid MCLK = %u \n",
|
||||||
ssp->ssp_prm.hw_cfg[hwi].mclk_rate);
|
ssp->ssp_prm[di].hw_cfg[hwi].mclk_rate);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ssp->ssp_prm.hw_cfg[hwi].bclk_rate ||
|
if (!ssp->ssp_prm[di].hw_cfg[hwi].bclk_rate ||
|
||||||
ssp->ssp_prm.hw_cfg[hwi].bclk_rate > ssp->ssp_prm.hw_cfg[hwi].mclk_rate) {
|
ssp->ssp_prm[di].hw_cfg[hwi].bclk_rate > ssp->ssp_prm[di].hw_cfg[hwi].mclk_rate) {
|
||||||
fprintf(stderr, "ssp_calculate(): BCLK %u Hz = 0 or > MCLK %u Hz\n",
|
fprintf(stderr, "ssp_calculate(): BCLK %u Hz = 0 or > MCLK %u Hz\n",
|
||||||
ssp->ssp_prm.hw_cfg[hwi].bclk_rate, ssp->ssp_prm.hw_cfg[hwi].mclk_rate);
|
ssp->ssp_prm[di].hw_cfg[hwi].bclk_rate,
|
||||||
|
ssp->ssp_prm[di].hw_cfg[hwi].mclk_rate);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calc frame width based on BCLK and rate - must be divisible */
|
/* calc frame width based on BCLK and rate - must be divisible */
|
||||||
if (ssp->ssp_prm.hw_cfg[hwi].bclk_rate % ssp->ssp_prm.hw_cfg[hwi].fsync_rate) {
|
if (ssp->ssp_prm[di].hw_cfg[hwi].bclk_rate % ssp->ssp_prm[di].hw_cfg[hwi].fsync_rate) {
|
||||||
fprintf(stderr, "ssp_calculate(): BCLK %u is not divisible by rate %u\n",
|
fprintf(stderr, "ssp_calculate(): BCLK %u is not divisible by rate %u\n",
|
||||||
ssp->ssp_prm.hw_cfg[hwi].bclk_rate, ssp->ssp_prm.hw_cfg[hwi].fsync_rate);
|
ssp->ssp_prm[di].hw_cfg[hwi].bclk_rate,
|
||||||
|
ssp->ssp_prm[di].hw_cfg[hwi].fsync_rate);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must be enough BCLKs for data */
|
/* must be enough BCLKs for data */
|
||||||
bdiv = ssp->ssp_prm.hw_cfg[hwi].bclk_rate / ssp->ssp_prm.hw_cfg[hwi].fsync_rate;
|
bdiv = ssp->ssp_prm[di].hw_cfg[hwi].bclk_rate / ssp->ssp_prm[di].hw_cfg[hwi].fsync_rate;
|
||||||
if (bdiv < ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width * ssp->ssp_prm.hw_cfg[hwi].tdm_slots) {
|
if (bdiv < ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width *
|
||||||
|
ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots) {
|
||||||
fprintf(stderr, "ssp_calculate(): not enough BCLKs need %u\n",
|
fprintf(stderr, "ssp_calculate(): not enough BCLKs need %u\n",
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width *
|
ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width *
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slots);
|
ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tdm_slot_width must be <= 38 for SSP */
|
/* tdm_slot_width must be <= 38 for SSP */
|
||||||
if (ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width > 38) {
|
if (ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width > 38) {
|
||||||
fprintf(stderr, "ssp_calculate(): tdm_slot_width %u > 38\n",
|
fprintf(stderr, "ssp_calculate(): tdm_slot_width %u > 38\n",
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width);
|
ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdiv_min = ssp->ssp_prm.hw_cfg[hwi].tdm_slots *
|
bdiv_min = ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots *
|
||||||
(ssp->ssp_prm.tdm_per_slot_padding_flag ?
|
(ssp->ssp_prm[di].tdm_per_slot_padding_flag ?
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width : ssp->ssp_prm.sample_valid_bits);
|
ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width :
|
||||||
|
ssp->ssp_prm[di].sample_valid_bits);
|
||||||
if (bdiv < bdiv_min) {
|
if (bdiv < bdiv_min) {
|
||||||
fprintf(stderr, "ssp_calculate(): bdiv(%u) < bdiv_min(%u)\n",
|
fprintf(stderr, "ssp_calculate(): bdiv(%u) < bdiv_min(%u)\n",
|
||||||
bdiv, bdiv_min);
|
bdiv, bdiv_min);
|
||||||
|
@ -254,12 +258,12 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* format */
|
/* format */
|
||||||
switch (ssp->ssp_prm.hw_cfg[hwi].format & SSP_FMT_FORMAT_MASK) {
|
switch (ssp->ssp_prm[di].hw_cfg[hwi].format & SSP_FMT_FORMAT_MASK) {
|
||||||
case SSP_FMT_I2S:
|
case SSP_FMT_I2S:
|
||||||
|
|
||||||
start_delay = true;
|
start_delay = true;
|
||||||
|
|
||||||
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_FRDC(ssp->ssp_prm.hw_cfg[hwi].tdm_slots);
|
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_FRDC(ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots);
|
||||||
|
|
||||||
if (bdiv % 2) {
|
if (bdiv % 2) {
|
||||||
fprintf(stderr, "ssp_calculate(): bdiv %u is not divisible by 2\n",
|
fprintf(stderr, "ssp_calculate(): bdiv %u is not divisible by 2\n",
|
||||||
|
@ -307,7 +311,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
|
|
||||||
/* default start_delay value is set to false */
|
/* default start_delay value is set to false */
|
||||||
|
|
||||||
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_FRDC(ssp->ssp_prm.hw_cfg[hwi].tdm_slots);
|
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_FRDC(ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots);
|
||||||
|
|
||||||
/* LJDFD enable */
|
/* LJDFD enable */
|
||||||
ssp->ssp_blob[di][hwi].ssc2 &= ~SSCR2_LJDFD;
|
ssp->ssp_blob[di][hwi].ssc2 &= ~SSCR2_LJDFD;
|
||||||
|
@ -364,19 +368,19 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
/* default start_delay value is set to false */
|
/* default start_delay value is set to false */
|
||||||
|
|
||||||
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_MOD |
|
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_MOD |
|
||||||
SSCR0_FRDC(ssp->ssp_prm.hw_cfg[hwi].tdm_slots);
|
SSCR0_FRDC(ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots);
|
||||||
|
|
||||||
/* set asserted frame length */
|
/* set asserted frame length */
|
||||||
frame_len = 1; /* default */
|
frame_len = 1; /* default */
|
||||||
|
|
||||||
if (cfs && ssp->ssp_prm.frame_pulse_width > 0 &&
|
if (cfs && ssp->ssp_prm[di].frame_pulse_width > 0 &&
|
||||||
ssp->ssp_prm.frame_pulse_width <=
|
ssp->ssp_prm[di].frame_pulse_width <=
|
||||||
SSP_INTEL_FRAME_PULSE_WIDTH_MAX) {
|
SSP_INTEL_FRAME_PULSE_WIDTH_MAX) {
|
||||||
frame_len = ssp->ssp_prm.frame_pulse_width;
|
frame_len = ssp->ssp_prm[di].frame_pulse_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* frame_pulse_width must less or equal 38 */
|
/* frame_pulse_width must less or equal 38 */
|
||||||
if (ssp->ssp_prm.frame_pulse_width >
|
if (ssp->ssp_prm[di].frame_pulse_width >
|
||||||
SSP_INTEL_FRAME_PULSE_WIDTH_MAX) {
|
SSP_INTEL_FRAME_PULSE_WIDTH_MAX) {
|
||||||
fprintf(stderr, "ssp_set_config(): frame_pulse_width > %d\n",
|
fprintf(stderr, "ssp_set_config(): frame_pulse_width > %d\n",
|
||||||
SSP_INTEL_FRAME_PULSE_WIDTH_MAX);
|
SSP_INTEL_FRAME_PULSE_WIDTH_MAX);
|
||||||
|
@ -390,20 +394,20 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
*/
|
*/
|
||||||
ssp->ssp_blob[di][hwi].sspsp |= SSPSP_SFRMP(!inverted_frame ? 1 : 0);
|
ssp->ssp_blob[di][hwi].sspsp |= SSPSP_SFRMP(!inverted_frame ? 1 : 0);
|
||||||
|
|
||||||
active_tx_slots = popcount(ssp->ssp_prm.hw_cfg[hwi].tx_slots);
|
active_tx_slots = popcount(ssp->ssp_prm[di].hw_cfg[hwi].tx_slots);
|
||||||
active_rx_slots = popcount(ssp->ssp_prm.hw_cfg[hwi].rx_slots);
|
active_rx_slots = popcount(ssp->ssp_prm[di].hw_cfg[hwi].rx_slots);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* handle TDM mode, TDM mode has padding at the end of
|
* handle TDM mode, TDM mode has padding at the end of
|
||||||
* each slot. The amount of padding is equal to result of
|
* each slot. The amount of padding is equal to result of
|
||||||
* subtracting slot width and valid bits per slot.
|
* subtracting slot width and valid bits per slot.
|
||||||
*/
|
*/
|
||||||
if (ssp->ssp_prm.tdm_per_slot_padding_flag) {
|
if (ssp->ssp_prm[di].tdm_per_slot_padding_flag) {
|
||||||
frame_end_padding = bdiv - ssp->ssp_prm.hw_cfg[hwi].tdm_slots *
|
frame_end_padding = bdiv - ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots *
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width;
|
ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width;
|
||||||
|
|
||||||
slot_end_padding = ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width -
|
slot_end_padding = ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width -
|
||||||
ssp->ssp_prm.sample_valid_bits;
|
ssp->ssp_prm[di].sample_valid_bits;
|
||||||
|
|
||||||
if (slot_end_padding >
|
if (slot_end_padding >
|
||||||
SSP_INTEL_SLOT_PADDING_MAX) {
|
SSP_INTEL_SLOT_PADDING_MAX) {
|
||||||
|
@ -422,7 +426,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ssp_set_config(): invalid format 0x%04x\n",
|
fprintf(stderr, "ssp_set_config(): invalid format 0x%04x\n",
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format);
|
ssp->ssp_prm[di].hw_cfg[hwi].format);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +435,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
|
|
||||||
ssp->ssp_blob[di][hwi].sspsp |= SSPSP_SFRMWDTH(frame_len);
|
ssp->ssp_blob[di][hwi].sspsp |= SSPSP_SFRMWDTH(frame_len);
|
||||||
|
|
||||||
data_size = ssp->ssp_prm.sample_valid_bits;
|
data_size = ssp->ssp_prm[di].sample_valid_bits;
|
||||||
|
|
||||||
if (data_size > 16)
|
if (data_size > 16)
|
||||||
ssp->ssp_blob[di][hwi].ssc0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16));
|
ssp->ssp_blob[di][hwi].ssc0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16));
|
||||||
|
@ -439,10 +443,10 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_DSIZE(data_size);
|
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_DSIZE(data_size);
|
||||||
|
|
||||||
end_padding = 0;
|
end_padding = 0;
|
||||||
total_sample_size = ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width *
|
total_sample_size = ssp->ssp_prm[di].hw_cfg[hwi].tdm_slot_width *
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slots;
|
ssp->ssp_prm[di].hw_cfg[hwi].tdm_slots;
|
||||||
while (ssp->ssp_prm.io_clk % ((total_sample_size + end_padding) *
|
while (ssp->ssp_prm[di].io_clk % ((total_sample_size + end_padding) *
|
||||||
ssp->ssp_prm.hw_cfg[hwi].fsync_rate)) {
|
ssp->ssp_prm[di].hw_cfg[hwi].fsync_rate)) {
|
||||||
if (++end_padding >= 256)
|
if (++end_padding >= 256)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -451,15 +455,15 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* calc scr divisor */
|
/* calc scr divisor */
|
||||||
clk_div = ssp->ssp_prm.io_clk / ((total_sample_size + end_padding) *
|
clk_div = ssp->ssp_prm[di].io_clk / ((total_sample_size + end_padding) *
|
||||||
ssp->ssp_prm.hw_cfg[hwi].fsync_rate);
|
ssp->ssp_prm[di].hw_cfg[hwi].fsync_rate);
|
||||||
if (clk_div >= 4095)
|
if (clk_div >= 4095)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_SCR(clk_div - 1);
|
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_SCR(clk_div - 1);
|
||||||
|
|
||||||
/* setting TFT and RFT */
|
/* setting TFT and RFT */
|
||||||
switch (ssp->ssp_prm.sample_valid_bits) {
|
switch (ssp->ssp_prm[di].sample_valid_bits) {
|
||||||
case 16:
|
case 16:
|
||||||
/* use 2 bytes for each slot */
|
/* use 2 bytes for each slot */
|
||||||
sample_width = 2;
|
sample_width = 2;
|
||||||
|
@ -471,7 +475,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ssp_set_config(): sample_valid_bits %u\n",
|
fprintf(stderr, "ssp_set_config(): sample_valid_bits %u\n",
|
||||||
ssp->ssp_prm.sample_valid_bits);
|
ssp->ssp_prm[di].sample_valid_bits);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,12 +487,12 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
ssp->ssp_blob[di][hwi].ssc3 |= SSCR3_TX(tft) | SSCR3_RX(rft);
|
ssp->ssp_blob[di][hwi].ssc3 |= SSCR3_TX(tft) | SSCR3_RX(rft);
|
||||||
|
|
||||||
/* calc mn divisor */
|
/* calc mn divisor */
|
||||||
if (ssp->ssp_prm.io_clk % ssp->ssp_prm.hw_cfg[hwi].mclk_rate) {
|
if (ssp->ssp_prm[di].io_clk % ssp->ssp_prm[di].hw_cfg[hwi].mclk_rate) {
|
||||||
fprintf(stderr, "ssp_set_config(): io_clk not divisible with mclk\n");
|
fprintf(stderr, "ssp_set_config(): io_clk not divisible with mclk\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
clk_div = ssp->ssp_prm.io_clk / ssp->ssp_prm.hw_cfg[hwi].mclk_rate;
|
clk_div = ssp->ssp_prm[di].io_clk / ssp->ssp_prm[di].hw_cfg[hwi].mclk_rate;
|
||||||
if (clk_div > 1)
|
if (clk_div > 1)
|
||||||
clk_div -= 2;
|
clk_div -= 2;
|
||||||
else
|
else
|
||||||
|
@ -498,7 +502,7 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
|
||||||
/* clock will always go through the divider */
|
/* clock will always go through the divider */
|
||||||
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_ECS;
|
ssp->ssp_blob[di][hwi].ssc0 |= SSCR0_ECS;
|
||||||
/* enable divider for this clock id */
|
/* enable divider for this clock id */
|
||||||
ssp->ssp_blob[di][hwi].mdivc |= BIT(ssp->ssp_prm.mclk_id);
|
ssp->ssp_blob[di][hwi].mdivc |= BIT(ssp->ssp_prm[di].mclk_id);
|
||||||
/* set mclk source always for audio cardinal clock */
|
/* set mclk source always for audio cardinal clock */
|
||||||
ssp->ssp_blob[di][hwi].mdivc |= MCDSS(SSP_CLOCK_AUDIO_CARDINAL);
|
ssp->ssp_blob[di][hwi].mdivc |= MCDSS(SSP_CLOCK_AUDIO_CARDINAL);
|
||||||
/* set bclk source for audio cardinal clock */
|
/* set bclk source for audio cardinal clock */
|
||||||
|
@ -535,7 +539,7 @@ int ssp_get_dir(struct intel_nhlt_params *nhlt, int dai_index, uint8_t *dir)
|
||||||
if (!ssp)
|
if (!ssp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*dir = ssp->ssp_prm.direction;
|
*dir = ssp->ssp_prm[dai_index].direction;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -554,17 +558,17 @@ int ssp_get_params(struct intel_nhlt_params *nhlt, int dai_index, uint32_t *virt
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssp_get_hw_params(struct intel_nhlt_params *nhlt, int hw_index, uint32_t *sample_rate,
|
int ssp_get_hw_params(struct intel_nhlt_params *nhlt, int dai_index, int hw_index,
|
||||||
uint16_t *channel_count, uint32_t *bits_per_sample)
|
uint32_t *sample_rate, uint16_t *channel_count, uint32_t *bits_per_sample)
|
||||||
{
|
{
|
||||||
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
|
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
|
||||||
|
|
||||||
if (!ssp)
|
if (!ssp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*channel_count = ssp->ssp_prm.hw_cfg[hw_index].tdm_slots;
|
*channel_count = ssp->ssp_prm[dai_index].hw_cfg[hw_index].tdm_slots;
|
||||||
*sample_rate = ssp->ssp_prm.hw_cfg[hw_index].fsync_rate;
|
*sample_rate = ssp->ssp_prm[dai_index].hw_cfg[hw_index].fsync_rate;
|
||||||
*bits_per_sample = ssp->ssp_prm.hw_cfg[hw_index].tdm_slot_width;
|
*bits_per_sample = ssp->ssp_prm[dai_index].hw_cfg[hw_index].tdm_slot_width;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -619,29 +623,30 @@ int ssp_set_params(struct intel_nhlt_params *nhlt, const char *dir, int dai_inde
|
||||||
|
|
||||||
if (dir) {
|
if (dir) {
|
||||||
if (!strcmp(dir, "playback"))
|
if (!strcmp(dir, "playback"))
|
||||||
ssp->ssp_prm.direction = NHLT_ENDPOINT_DIRECTION_RENDER;
|
ssp->ssp_prm[ssp->ssp_count].direction = NHLT_ENDPOINT_DIRECTION_RENDER;
|
||||||
else if (!strcmp(dir, "capture"))
|
else if (!strcmp(dir, "capture"))
|
||||||
ssp->ssp_prm.direction = NHLT_ENDPOINT_DIRECTION_CAPTURE;
|
ssp->ssp_prm[ssp->ssp_count].direction = NHLT_ENDPOINT_DIRECTION_CAPTURE;
|
||||||
else if (!strcmp(dir, "duplex"))
|
else if (!strcmp(dir, "duplex"))
|
||||||
ssp->ssp_prm.direction = NHLT_ENDPOINT_DIRECTION_FEEDBACK_FOR_RENDER + 1;
|
ssp->ssp_prm[ssp->ssp_count].direction =
|
||||||
|
NHLT_ENDPOINT_DIRECTION_FEEDBACK_FOR_RENDER + 1;
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
ssp->ssp_dai_index[ssp->ssp_count] = dai_index;
|
ssp->ssp_dai_index[ssp->ssp_count] = dai_index;
|
||||||
ssp->ssp_prm.io_clk = io_clk;
|
ssp->ssp_prm[ssp->ssp_count].io_clk = io_clk;
|
||||||
ssp->ssp_prm.bclk_delay = bclk_delay;
|
ssp->ssp_prm[ssp->ssp_count].bclk_delay = bclk_delay;
|
||||||
ssp->ssp_prm.sample_valid_bits = sample_bits;
|
ssp->ssp_prm[ssp->ssp_count].sample_valid_bits = sample_bits;
|
||||||
ssp->ssp_prm.mclk_id = mclk_id;
|
ssp->ssp_prm[ssp->ssp_count].mclk_id = mclk_id;
|
||||||
ssp->ssp_prm.clks_control = clks_control;
|
ssp->ssp_prm[ssp->ssp_count].clks_control = clks_control;
|
||||||
ssp->ssp_prm.frame_pulse_width = frame_pulse_width;
|
ssp->ssp_prm[ssp->ssp_count].frame_pulse_width = frame_pulse_width;
|
||||||
if (tdm_padding_per_slot && !strcmp(tdm_padding_per_slot, "true"))
|
if (tdm_padding_per_slot && !strcmp(tdm_padding_per_slot, "true"))
|
||||||
ssp->ssp_prm.tdm_per_slot_padding_flag = 1;
|
ssp->ssp_prm[ssp->ssp_count].tdm_per_slot_padding_flag = 1;
|
||||||
else
|
else
|
||||||
ssp->ssp_prm.tdm_per_slot_padding_flag = 0;
|
ssp->ssp_prm[ssp->ssp_count].tdm_per_slot_padding_flag = 0;
|
||||||
if (quirks && !strcmp(quirks, "lbm_mode"))
|
if (quirks && !strcmp(quirks, "lbm_mode"))
|
||||||
ssp->ssp_prm.quirks = 64; /* 1 << 6 */
|
ssp->ssp_prm[ssp->ssp_count].quirks = 64; /* 1 << 6 */
|
||||||
else
|
else
|
||||||
ssp->ssp_prm.quirks = 0;
|
ssp->ssp_prm[ssp->ssp_count].quirks = 0;
|
||||||
|
|
||||||
/* reset hw config count for this ssp instance */
|
/* reset hw config count for this ssp instance */
|
||||||
ssp->ssp_hw_config_count[ssp->ssp_count] = 0;
|
ssp->ssp_hw_config_count[ssp->ssp_count] = 0;
|
||||||
|
@ -666,15 +671,15 @@ int ssp_hw_set_params(struct intel_nhlt_params *nhlt, const char *format, const
|
||||||
hwi = ssp->ssp_hw_config_count[ssp->ssp_count];
|
hwi = ssp->ssp_hw_config_count[ssp->ssp_count];
|
||||||
|
|
||||||
if (!strcmp(format, "I2S")) {
|
if (!strcmp(format, "I2S")) {
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format = SSP_FMT_I2S;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format = SSP_FMT_I2S;
|
||||||
} else if (!strcmp(format, "RIGHT_J")) {
|
} else if (!strcmp(format, "RIGHT_J")) {
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format = SSP_FMT_RIGHT_J;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format = SSP_FMT_RIGHT_J;
|
||||||
} else if (!strcmp(format, "LEFT_J")) {
|
} else if (!strcmp(format, "LEFT_J")) {
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format = SSP_FMT_LEFT_J;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format = SSP_FMT_LEFT_J;
|
||||||
} else if (!strcmp(format, "DSP_A")) {
|
} else if (!strcmp(format, "DSP_A")) {
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format = SSP_FMT_DSP_A;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format = SSP_FMT_DSP_A;
|
||||||
} else if (!strcmp(format, "DSP_B")) {
|
} else if (!strcmp(format, "DSP_B")) {
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format = SSP_FMT_DSP_B;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format = SSP_FMT_DSP_B;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "no valid format specified for ssp: %s\n", format);
|
fprintf(stderr, "no valid format specified for ssp: %s\n", format);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -684,37 +689,37 @@ int ssp_hw_set_params(struct intel_nhlt_params *nhlt, const char *format, const
|
||||||
if (bclk && !strcmp(bclk, "coded_provider")) {
|
if (bclk && !strcmp(bclk, "coded_provider")) {
|
||||||
/* codec is bclk provider */
|
/* codec is bclk provider */
|
||||||
if (fsync && !strcmp(fsync, "coded_provider"))
|
if (fsync && !strcmp(fsync, "coded_provider"))
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_CBP_CFP;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_CBP_CFP;
|
||||||
else
|
else
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_CBP_CFC;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_CBP_CFC;
|
||||||
} else {
|
} else {
|
||||||
/* codec is bclk consumer */
|
/* codec is bclk consumer */
|
||||||
if (fsync && !strcmp(fsync, "coded_provider"))
|
if (fsync && !strcmp(fsync, "coded_provider"))
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_CBC_CFP;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_CBC_CFP;
|
||||||
else
|
else
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_CBC_CFC;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_CBC_CFC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* inverted clocks ? */
|
/* inverted clocks ? */
|
||||||
if (bclk_invert && !strcmp(bclk_invert, "true")) {
|
if (bclk_invert && !strcmp(bclk_invert, "true")) {
|
||||||
if (fsync_invert && !strcmp(fsync_invert, "true"))
|
if (fsync_invert && !strcmp(fsync_invert, "true"))
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_IB_IF;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_IB_IF;
|
||||||
else
|
else
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_IB_NF;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_IB_NF;
|
||||||
} else {
|
} else {
|
||||||
if (fsync_invert && !strcmp(fsync_invert, "true"))
|
if (fsync_invert && !strcmp(fsync_invert, "true"))
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_NB_IF;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_NB_IF;
|
||||||
else
|
else
|
||||||
ssp->ssp_prm.hw_cfg[hwi].format |= SSP_FMT_NB_NF;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].format |= SSP_FMT_NB_NF;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssp->ssp_prm.hw_cfg[hwi].mclk_rate = mclk_freq;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].mclk_rate = mclk_freq;
|
||||||
ssp->ssp_prm.hw_cfg[hwi].bclk_rate = bclk_freq;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].bclk_rate = bclk_freq;
|
||||||
ssp->ssp_prm.hw_cfg[hwi].fsync_rate = fsync_freq;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].fsync_rate = fsync_freq;
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slots = tdm_slots;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].tdm_slots = tdm_slots;
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tdm_slot_width = tdm_slot_width;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].tdm_slot_width = tdm_slot_width;
|
||||||
ssp->ssp_prm.hw_cfg[hwi].tx_slots = tx_slots;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].tx_slots = tx_slots;
|
||||||
ssp->ssp_prm.hw_cfg[hwi].rx_slots = rx_slots;
|
ssp->ssp_prm[ssp->ssp_count].hw_cfg[hwi].rx_slots = rx_slots;
|
||||||
|
|
||||||
ssp->ssp_hw_config_count[ssp->ssp_count]++;
|
ssp->ssp_hw_config_count[ssp->ssp_count]++;
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ int ssp_calculate(struct intel_nhlt_params *nhlt);
|
||||||
/* get spec parameters when building the nhlt endpoint */
|
/* get spec parameters when building the nhlt endpoint */
|
||||||
int ssp_get_params(struct intel_nhlt_params *nhlt, int dai_index, uint32_t *virtualbus_id,
|
int ssp_get_params(struct intel_nhlt_params *nhlt, int dai_index, uint32_t *virtualbus_id,
|
||||||
uint32_t *formats_count);
|
uint32_t *formats_count);
|
||||||
int ssp_get_hw_params(struct intel_nhlt_params *nhlt, int hw_index, uint32_t *sample_rate,
|
int ssp_get_hw_params(struct intel_nhlt_params *nhlt, int dai_index, int hw_index,
|
||||||
uint16_t *channel_count, uint32_t *bits_per_sample);
|
uint32_t *sample_rate, uint16_t *channel_count, uint32_t *bits_per_sample);
|
||||||
int ssp_get_dir(struct intel_nhlt_params *nhlt, int dai_index, uint8_t *dir);
|
int ssp_get_dir(struct intel_nhlt_params *nhlt, int dai_index, uint8_t *dir);
|
||||||
/* get vendor specific blob when building the nhlt endpoint */
|
/* get vendor specific blob when building the nhlt endpoint */
|
||||||
int ssp_get_vendor_blob_count(struct intel_nhlt_params *nhlt);
|
int ssp_get_vendor_blob_count(struct intel_nhlt_params *nhlt);
|
||||||
|
|
Loading…
Reference in a new issue