drivers: dai: sai: Add fix for i.MX93 SAI errata 051421

ERRATA 051421 states that if the SAI is FSYNC/BCLK master,
one of the directions is SYNC with the other, and the
ASYNC direction has the BYP bit toggled, the SYNC direction's
BCLK won't be generated properly.

This commit fixes this issue by enabling BCI for the SYNC
direction. What this does is it makes the SYNC direction use
the BCLK from the ASYNC direction's pad, which, if the BYP
bit is toggled, will be the undivided MCLK. Without this fix,
the SYNC direction will use the ASYNC direction's BCLK obtained
by dividing the MCLK via the following formula: MCLK / ((DIV + 1) * 2).
This is wrong because the ASYNC direction will use an undivided
MCLK while the SYNC direction will use a divided MCLK.

Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
This commit is contained in:
Laurentiu Mihalcea 2023-12-21 15:29:56 +02:00 committed by Carles Cufí
commit 265554b873
2 changed files with 84 additions and 0 deletions

View file

@ -27,4 +27,15 @@ config SAI_FIFO_WORD_SIZE
Use this to set the size (in bytes) of a SAI
FIFO word.
config SAI_IMX93_ERRATA_051421
bool "Set if your SAI IP version is affected by i.MX93's ERRATA 051421"
default n
help
Select this if your SAI ip version is affected by
i.MX93's ERRATA 051421. The errata states that if
the SAI is FSYNC/BCLK master, one of the directions
is SYNC with the other, and the ASYNC direction has
the BYP bit toggled, the SYNC direction's BCLK won't
be generated properly.
endif # DAI_NXP_SAI

View file

@ -142,6 +142,73 @@ static const struct dai_properties
CODE_UNREACHABLE;
}
#ifdef CONFIG_SAI_IMX93_ERRATA_051421
/* notes:
* 1) TX and RX operate in the same mode: master/slave. As such,
* there's no need to check the mode for both directions.
*
* 2) Only one of the directions can operate in SYNC mode at a
* time.
*
* 3) What this piece of code does is it makes the SYNC direction
* use the ASYNC direction's BCLK that comes from its input pad.
* Logically speaking, this would look like:
*
* +--------+ +--------+
* | TX | | RX |
* | module | | module |
* +--------+ +--------+
* | ^ |
* | | |
* TX_BCLK | |____________| RX_BCLK
* | |
* V V
* +---------+ +---------+
* | TX BCLK | | RX BCLK |
* | pad | | pad |
* +---------+ +---------+
* | |
* | TX_BCLK | RX_BCLK
* V V
*
* Without BCI enabled, the TX module would use an RX_BCLK
* that's divided instead of the one that's obtained from
* bypassing the MCLK (i.e: TX_BCLK would have the value of
* MCLK / ((RX_DIV + 1) * 2)). If BCI is 1, then TX_BCLK will
* be the same as the RX_BCLK that's obtained from bypassing
* the MCLK on RX's side.
*
* 4) The check for BCLK == MCLK is there to see if the ASYNC
* direction will have the BYP bit toggled.
*
* IMPORTANT1: in the above diagram and information, RX is SYNC
* with TX. The same applies if RX is SYNC with TX. Also, this
* applies to i.MX93. For other SoCs, things may be different
* so use this information with caution.
*
* IMPORTANT2: for this to work, you also need to enable the
* pad's input path. For i.MX93, this can be achieved by setting
* the pad's SION bit.
*/
static void sai_config_set_err_051421(I2S_Type *base,
const struct sai_config *cfg,
const struct sai_bespoke_config *bespoke,
sai_transceiver_t *rx_config,
sai_transceiver_t *tx_config)
{
if (tx_config->masterSlave == kSAI_Master &&
bespoke->mclk_rate == bespoke->bclk_rate) {
if (cfg->tx_sync_mode == kSAI_ModeSync) {
base->TCR2 |= I2S_TCR2_BCI(1);
}
if (cfg->rx_sync_mode == kSAI_ModeSync) {
base->RCR2 |= I2S_RCR2_BCI(1);
}
}
}
#endif /* CONFIG_SAI_IMX93_ERRATA_051421 */
static int sai_config_set(const struct device *dev,
const struct dai_config *cfg,
const void *bespoke_data)
@ -341,6 +408,12 @@ static int sai_config_set(const struct device *dev,
}
#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */
#ifdef CONFIG_SAI_IMX93_ERRATA_051421
sai_config_set_err_051421(UINT_TO_I2S(data->regmap),
sai_cfg, bespoke,
rx_config, tx_config);
#endif /* CONFIG_SAI_IMX93_ERRATA_051421 */
/* this is needed so that rates different from FSYNC_RATE
* will not be allowed.
*