ASoC: rockchip: sai: Add support for RV1126B

* Enhance Frame Integrity Robustness
* Support FIFO Interleaved Cfg
* Support Data Debug

Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Change-Id: I1cff642007e3421b49e602ea900832a0d94c58d1
This commit is contained in:
Sugar Zhang
2024-09-21 11:04:08 +08:00
committed by Tao Huang
parent f5ab8f61cc
commit 80e7b5d620
2 changed files with 158 additions and 3 deletions

View File

@@ -31,6 +31,7 @@
#define FW_RATIO_MAX 8
#define FW_RATIO_MIN 1
#define MAXBURST_PER_FIFO 8
#define FIFO_PER_LANE 32
#define DEFAULT_FS 48000
#define TIMEOUT_US 1000
@@ -75,6 +76,7 @@ struct rk_sai_dev {
bool is_clk_auto;
bool is_mclk_calibrate;
bool is_tx_auto_gate; /* auto gate clk when TX FIFO empty */
bool is_lane_interleaved;
bool no_set_mclk;
};
@@ -281,6 +283,33 @@ err_hclk:
return ret;
}
static void rockchip_sai_fifo_level_wdt(struct rk_sai_dev *sai,
int stream, bool en)
{
if (sai->version < SAI_VER_2411)
return;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_TXFLC, SAI_INTCR_TXFLC);
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_TXFLE_MASK,
SAI_INTCR_TXFLE(en));
regmap_update_bits(sai->regmap, SAI_TXCR,
SAI_XCR_FLE_MASK,
SAI_XCR_FLE(en));
} else {
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_RXFLC, SAI_INTCR_RXFLC);
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_RXFLE_MASK,
SAI_INTCR_RXFLE(en));
regmap_update_bits(sai->regmap, SAI_RXCR,
SAI_XCR_FLE_MASK,
SAI_XCR_FLE(en));
}
}
static void rockchip_sai_fifo_xrun_detect(struct rk_sai_dev *sai,
int stream, bool en)
{
@@ -408,12 +437,14 @@ static void rockchip_sai_xfer_stop(struct rk_sai_dev *sai, int stream)
static void rockchip_sai_start(struct rk_sai_dev *sai, int stream)
{
rockchip_sai_fifo_level_wdt(sai, stream, 1);
rockchip_sai_dma_ctrl(sai, stream, 1);
rockchip_sai_xfer_start(sai, stream);
}
static void rockchip_sai_stop(struct rk_sai_dev *sai, int stream)
{
rockchip_sai_fifo_level_wdt(sai, stream, 0);
rockchip_sai_dma_ctrl(sai, stream, 0);
rockchip_sai_xfer_stop(sai, stream);
}
@@ -546,6 +577,21 @@ static unsigned int rockchip_sai_lanes_auto(struct snd_pcm_hw_params *params,
return lanes;
}
static int rockchip_fifo_cfg(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
if (sai->version < SAI_VER_2411)
return 0;
if (!sai->is_lane_interleaved)
regmap_update_bits(sai->regmap, SAI_FIFO_CFG,
SAI_FIFO_CHG_MASK, SAI_FIFO_CHG_EN);
return 0;
}
static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -606,6 +652,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
slot_width = SAI_XCR_SBW_V(val);
ch_per_lane = params_channels(params) / lanes;
rockchip_fifo_cfg(substream, dai);
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
SAI_XCR_SNB(ch_per_lane));
@@ -1072,6 +1120,7 @@ static bool rockchip_sai_wr_reg(struct device *dev, unsigned int reg)
case SAI_DMACR:
case SAI_INTCR:
case SAI_TXDR:
case SAI_TXDR2:
case SAI_PATH_SEL:
case SAI_TX_SLOT_MASK0:
case SAI_TX_SLOT_MASK1:
@@ -1086,6 +1135,10 @@ static bool rockchip_sai_wr_reg(struct device *dev, unsigned int reg)
case SAI_FSXN:
case SAI_FS_TIMEOUT:
case SAI_LOOPBACK_LR:
case SAI_FIFO_CFG:
case SAI_TXFL_TIMEOUT:
case SAI_RXFL_TIMEOUT:
case SAI_DEBUG:
return true;
default:
return false;
@@ -1109,6 +1162,8 @@ static bool rockchip_sai_rd_reg(struct device *dev, unsigned int reg)
case SAI_INTSR:
case SAI_TXDR:
case SAI_RXDR:
case SAI_TXDR2:
case SAI_RXDR2:
case SAI_PATH_SEL:
case SAI_TX_SLOT_MASK0:
case SAI_TX_SLOT_MASK1:
@@ -1127,6 +1182,11 @@ static bool rockchip_sai_rd_reg(struct device *dev, unsigned int reg)
case SAI_FSXN:
case SAI_FS_TIMEOUT:
case SAI_LOOPBACK_LR:
case SAI_FIFO_CFG:
case SAI_TXFL_TIMEOUT:
case SAI_RXFL_TIMEOUT:
case SAI_DEBUG:
case SAI_TXDATA0 ... SAI_RXDATA3:
return true;
default:
return false;
@@ -1144,10 +1204,13 @@ static bool rockchip_sai_volatile_reg(struct device *dev, unsigned int reg)
case SAI_RXFIFOLR:
case SAI_TXDR:
case SAI_RXDR:
case SAI_TXDR2:
case SAI_RXDR2:
case SAI_TX_DATA_CNT:
case SAI_RX_DATA_CNT:
case SAI_STATUS:
case SAI_VERSION:
case SAI_TXDATA0 ... SAI_RXDATA3:
return true;
default:
return false;
@@ -1158,6 +1221,7 @@ static bool rockchip_sai_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case SAI_RXDR:
case SAI_RXDR2:
return true;
default:
return false;
@@ -1175,7 +1239,7 @@ static const struct regmap_config rockchip_sai_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = SAI_LOOPBACK_LR,
.max_register = SAI_RXDR2,
.reg_defaults = rockchip_sai_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rockchip_sai_reg_defaults),
.writeable_reg = rockchip_sai_wr_reg,
@@ -1236,7 +1300,11 @@ static int rockchip_sai_init_dai(struct rk_sai_dev *sai, struct resource *res,
SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
sai->playback_dma_data.addr = res->start + SAI_TXDR;
if (sai->version >= SAI_VER_2411)
sai->playback_dma_data.addr = res->start + SAI_TXDR2;
else
sai->playback_dma_data.addr = res->start + SAI_TXDR;
sai->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
sai->playback_dma_data.maxburst = MAXBURST_PER_FIFO;
}
@@ -1252,11 +1320,27 @@ static int rockchip_sai_init_dai(struct rk_sai_dev *sai, struct resource *res,
SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
sai->capture_dma_data.addr = res->start + SAI_RXDR;
if (sai->version >= SAI_VER_2411)
sai->capture_dma_data.addr = res->start + SAI_RXDR2;
else
sai->capture_dma_data.addr = res->start + SAI_RXDR;
sai->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
sai->capture_dma_data.maxburst = MAXBURST_PER_FIFO;
}
if (sai->version >= SAI_VER_2411) {
regmap_update_bits(sai->regmap, SAI_TXCR,
SAI_XCR_FPC_MASK | SAI_XCR_SFC_MASK,
SAI_XCR_FPC_EN | SAI_XCR_SFC_ONE);
regmap_update_bits(sai->regmap, SAI_RXCR,
SAI_XCR_FPC_MASK | SAI_XCR_SFC_MASK,
SAI_XCR_FPC_EN | SAI_XCR_SFC_ONE);
/* The counter is driven by HCLK */
regmap_write(sai->regmap, SAI_TXFL_TIMEOUT, 0x1000000);
regmap_write(sai->regmap, SAI_RXFL_TIMEOUT, 0x1000000);
}
regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_TDL_MASK,
SAI_DMACR_TDL(16));
regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_RDL_MASK,
@@ -1290,6 +1374,7 @@ static const char * const sbw_text[] = {
"25", "26", "27", "28", "29", "30", "31", "32", };
static const char * const mono_text[] = { "Disable", "Enable" };
static const char * const dbg_text[] = { "Disable", "Enable" };
static DECLARE_TLV_DB_SCALE(rmss_tlv, 0, 128, 0);
@@ -1380,6 +1465,9 @@ static SOC_ENUM_SINGLE_DECL(lp2lr_switch, SAI_LOOPBACK_LR, 2, lplr_text);
static SOC_ENUM_SINGLE_DECL(lp1lr_switch, SAI_LOOPBACK_LR, 1, lplr_text);
static SOC_ENUM_SINGLE_DECL(lp0lr_switch, SAI_LOOPBACK_LR, 0, lplr_text);
/* DEBUG */
static SOC_ENUM_SINGLE_DECL(__maybe_unused dbg_switch, SAI_DEBUG, 0, dbg_text);
static int __maybe_unused rockchip_sai_fpw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1702,6 +1790,8 @@ static const struct snd_kcontrol_new rockchip_sai_controls[] = {
0, 8192, 0, fs_shift_right_tlv),
SOC_SINGLE_TLV("Receive Frame Shift Right Select", SAI_RX_SHIFT,
0, 8192, 0, fs_shift_right_tlv),
SOC_ENUM("Data Debug Switch", dbg_switch),
#endif
SOC_ENUM("Transmit Start Mode Sel", tsl_enum),
SOC_ENUM("Receive Start Mode Sel", rsl_enum),
@@ -1811,6 +1901,25 @@ static irqreturn_t rockchip_sai_isr(int irq, void *devid)
SAI_INTCR_FSLOST(0));
}
if (val & SAI_INTSR_TXFLI_ACT) {
dev_warn_ratelimited(sai->dev, "TX FIFO Level Err\n");
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_TXFLC, SAI_INTCR_TXFLC);
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_TXFLE_MASK,
SAI_INTCR_TXFLE(0));
}
if (val & SAI_INTSR_RXFLI_ACT) {
dev_warn_ratelimited(sai->dev, "RX FIFO Level Err\n");
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_RXFLC, SAI_INTCR_RXFLC);
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_RXFLE_MASK,
SAI_INTCR_RXFLE(0));
}
return IRQ_HANDLED;
}
@@ -1962,6 +2071,9 @@ static int rockchip_sai_probe(struct platform_device *pdev)
}
}
sai->is_lane_interleaved =
device_property_read_bool(&pdev->dev, "rockchip,lane-interleaved");
sai->is_mclk_calibrate =
device_property_read_bool(&pdev->dev, "rockchip,mclk-calibrate");
if (sai->is_mclk_calibrate) {

View File

@@ -9,6 +9,14 @@
#define _ROCKCHIP_SAI_H
/* XCR Transmit / Receive Control Register */
#define SAI_XCR_FLE_MASK BIT(26)
#define SAI_XCR_FLE(x) ((x) << 26)
#define SAI_XCR_FPC_MASK BIT(25)
#define SAI_XCR_FPC_EN BIT(25)
#define SAI_XCR_FPC_DIS 0
#define SAI_XCR_SFC_MASK BIT(24)
#define SAI_XCR_SFC_ONE BIT(24)
#define SAI_XCR_SFC_ALL 0
#define SAI_XCR_START_SEL_MASK BIT(23)
#define SAI_XCR_START_SEL_CHAINED BIT(23)
#define SAI_XCR_START_SEL_STANDALONE 0
@@ -128,11 +136,21 @@
#define SAI_INTCR_RXOIC BIT(18)
#define SAI_INTCR_RXOIE_MASK BIT(17)
#define SAI_INTCR_RXOIE(x) ((x) << 17)
#define SAI_INTCR_RXFLC BIT(12)
#define SAI_INTCR_RXFLE_MASK BIT(11)
#define SAI_INTCR_RXFLE(x) ((x) << 11)
#define SAI_INTCR_TXFLC BIT(10)
#define SAI_INTCR_TXFLE_MASK BIT(9)
#define SAI_INTCR_TXFLE(x) ((x) << 9)
#define SAI_INTCR_TXUIC BIT(2)
#define SAI_INTCR_TXUIE_MASK BIT(1)
#define SAI_INTCR_TXUIE(x) ((x) << 1)
/* INTSR Interrupt Status Register */
#define SAI_INTSR_RXFLI_INA 0
#define SAI_INTSR_RXFLI_ACT BIT(21)
#define SAI_INTSR_TXFLI_INA 0
#define SAI_INTSR_TXFLI_ACT BIT(20)
#define SAI_INTSR_FSLOSTI_INA 0
#define SAI_INTSR_FSLOSTI_ACT BIT(19)
#define SAI_INTSR_FSERRI_INA 0
@@ -203,11 +221,17 @@
*
* Support Loopback LR Select (e.g. L:MIC R:LP)
*
* VERSION >= SAI_VER_2411
*
* Enhance Frame Integrity Robustness
* Support FIFO Interleaved Cfg
* Support Data Debug
*/
#define SAI_VER_2307 0x23073576
#define SAI_VER_2311 0x23112118
#define SAI_VER_2401 0x24013506
#define SAI_VER_2403 0x24031103
#define SAI_VER_2411 0x24111126
/* FS_TIMEOUT: Frame Sync Timeout Register */
#define SAI_FS_TIMEOUT_VAL_MASK GENMASK(31, 1)
@@ -215,6 +239,11 @@
#define SAI_FS_TIMEOUT_EN_MASK BIT(0)
#define SAI_FS_TIMEOUT_EN(x) ((x) << 0)
/* FIFO_CFG: FIFO Config Register */
#define SAI_FIFO_CHG_MASK BIT(0)
#define SAI_FIFO_CHG_EN BIT(0)
#define SAI_FIFO_CHG_DIS 0
/* SAI Registers */
#define SAI_TXCR (0x0000)
#define SAI_FSCR (0x0004)
@@ -248,5 +277,19 @@
#define SAI_FSXN (0x0074)
#define SAI_FS_TIMEOUT (0x0078)
#define SAI_LOOPBACK_LR (0x007c)
#define SAI_FIFO_CFG (0x0080)
#define SAI_TXFL_TIMEOUT (0x0084)
#define SAI_RXFL_TIMEOUT (0x0088)
#define SAI_DEBUG (0x008c)
#define SAI_TXDATA0 (0x0090)
#define SAI_TXDATA1 (0x0094)
#define SAI_TXDATA2 (0x0098)
#define SAI_TXDATA3 (0x009c)
#define SAI_RXDATA0 (0x00a0)
#define SAI_RXDATA1 (0x00a4)
#define SAI_RXDATA2 (0x00a8)
#define SAI_RXDATA3 (0x00ac)
#define SAI_TXDR2 (0x0100)
#define SAI_RXDR2 (0x0104)
#endif /* _ROCKCHIP_SAI_H */