Merge commit 'd5fc25e5c360c02b66fe44a372518e89eb6dd34f'

* commit 'd5fc25e5c360c02b66fe44a372518e89eb6dd34f':
  ASoC: rockchip: asrc: support rockchip asrc
  arm64: configs: rockchip_linux_defconfig: enable CONFIG_SND_SOC_ROCKCHIP_ASRC
  arm64: dts: rockchip: rk3576: add asrc node
  ASoC: rockchip: multicodecs: support DPCM
  arm64: dts: rockchip: add kernel logo for rk3576-rk628 hdmi2gvi
  ASoC: rockchip: i2s-tdm: Check stream is valid
  ASoC: rockchip: sai: Check stream is valid
  ASoC: hdmi-codec: Add support for HDMI-TX DLP
  ASoC: rockchip: Add debug for TRCM
  ASoC: rockchip: i2s-tdm: Optimize WL for TDM mode
  ASoC: rockchip: i2s_tdm: Fix params check for TDM mode

Change-Id: I627e74d9ccda4677646fd57e6587f6139e0c7f8c
This commit is contained in:
Tao Huang
2024-07-10 20:22:27 +08:00
13 changed files with 2039 additions and 42 deletions

View File

@@ -126,11 +126,25 @@
};
};
/*
* uboot does not support 4k resolution
*/
&route_hdmi {
status = "disabled";
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing {
clock-frequency = <594000000>;
hactive = <3840>;
vactive = <2160>;
hback-porch = <296>;
hfront-porch = <176>;
vback-porch = <72>;
vfront-porch = <8>;
hsync-len = <88>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&hdmi_sound {

View File

@@ -4602,6 +4602,78 @@
status = "disabled";
};
asrc0: asrc@2a690000 {
compatible = "rockchip,rk3576-asrc";
reg = <0x0 0x2a690000 0x0 0x1000>;
interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru CLK_ASRC_4CH_0>, <&cru HCLK_ASRC_4CH_0>,
<&cru LCLK_ASRC_SRC_0>, <&cru LCLK_ASRC_SRC_1>;
clock-names = "mclk", "hclk", "cru_src0", "cru_src1";
dmas = <&dmac2 17>, <&dmac2 18>;
dma-names = "rx", "tx";
power-domains = <&power RK3576_PD_AUDIO>;
rockchip,grf = <&sys_grf>;
resets = <&cru SRST_ASRC_4CH_0>, <&cru SRST_H_ASRC_4CH_0>;
reset-names = "m", "h";
#sound-dai-cells = <0>;
sound-name-prefix = "ASRC0";
status = "disabled";
};
asrc1: asrc@2a6a0000 {
compatible = "rockchip,rk3576-asrc";
reg = <0x0 0x2a6a0000 0x0 0x1000>;
interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru CLK_ASRC_4CH_1>, <&cru HCLK_ASRC_4CH_1>,
<&cru LCLK_ASRC_SRC_0>, <&cru LCLK_ASRC_SRC_1>;
clock-names = "mclk", "hclk", "cru_src0", "cru_src1";
dmas = <&dmac2 25>, <&dmac2 26>;
dma-names = "rx", "tx";
power-domains = <&power RK3576_PD_AUDIO>;
rockchip,grf = <&sys_grf>;
resets = <&cru SRST_ASRC_4CH_1>, <&cru SRST_H_ASRC_4CH_1>;
reset-names = "m", "h";
#sound-dai-cells = <0>;
sound-name-prefix = "ASRC1";
status = "disabled";
};
asrc2: asrc@2a6b0000 {
compatible = "rockchip,rk3576-asrc";
reg = <0x0 0x2a6b0000 0x0 0x1000>;
interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru CLK_ASRC_2CH_0>, <&cru HCLK_ASRC_2CH_0>,
<&cru LCLK_ASRC_SRC_0>, <&cru LCLK_ASRC_SRC_1>;
clock-names = "mclk", "hclk", "cru_src0", "cru_src1";
dmas = <&dmac0 27>, <&dmac0 28>;
dma-names = "rx", "tx";
power-domains = <&power RK3576_PD_AUDIO>;
rockchip,grf = <&sys_grf>;
resets = <&cru SRST_ASRC_2CH_0>, <&cru SRST_H_ASRC_2CH_0>;
reset-names = "m", "h";
#sound-dai-cells = <0>;
sound-name-prefix = "ASRC2";
status = "disabled";
};
asrc3: asrc@2a6c0000 {
compatible = "rockchip,rk3576-asrc";
reg = <0x0 0x2a6c0000 0x0 0x1000>;
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru CLK_ASRC_2CH_1>, <&cru HCLK_ASRC_2CH_1>,
<&cru LCLK_ASRC_SRC_0>, <&cru LCLK_ASRC_SRC_1>;
clock-names = "mclk", "hclk", "cru_src0", "cru_src1";
dmas = <&dmac1 27>, <&dmac1 28>;
dma-names = "rx", "tx";
power-domains = <&power RK3576_PD_AUDIO>;
rockchip,grf = <&sys_grf>;
resets = <&cru SRST_ASRC_2CH_1>, <&cru SRST_H_ASRC_2CH_1>;
reset-names = "m", "h";
#sound-dai-cells = <0>;
sound-name-prefix = "ASRC3";
status = "disabled";
};
acdcdig_dsm: acdcdig-dsm@2a6d0000 {
compatible = "rockchip,rk3576-dsm";
reg = <0x0 0x2a6d0000 0x0 0x1000>;

View File

@@ -406,6 +406,7 @@ CONFIG_SND_SEQ_DUMMY=y
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_ROCKCHIP=y
CONFIG_SND_SOC_ROCKCHIP_ASRC=y
CONFIG_SND_SOC_ROCKCHIP_DLP_PCM=y
CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y
CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS=y

View File

@@ -272,6 +272,7 @@ struct hdmi_codec_priv {
struct mutex lock;
bool busy;
bool eld_bypass;
bool tx_dlp;
struct snd_soc_jack *jack;
unsigned int jack_status;
u8 iec_status[AES_IEC958_STATUS_SIZE];
@@ -460,6 +461,9 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
int ret = 0;
if (hcp->tx_dlp && substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return 0;
mutex_lock(&hcp->lock);
if (hcp->busy) {
dev_err(dai->dev, "Only one simultaneous stream supported!\n");
@@ -500,6 +504,9 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
{
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
if (hcp->tx_dlp && substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return;
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
@@ -561,6 +568,9 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
};
int ret;
if (hcp->tx_dlp && substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return 0;
if (!hcp->hcd.ops->hw_params)
return 0;
@@ -602,6 +612,9 @@ static int hdmi_codec_prepare(struct snd_pcm_substream *substream,
struct hdmi_codec_params hp;
int ret;
if (hcp->tx_dlp && substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return 0;
if (!hcp->hcd.ops->prepare)
return 0;
@@ -1083,6 +1096,8 @@ static int hdmi_codec_probe(struct platform_device *pdev)
hcp->hcd = *hcd;
mutex_init(&hcp->lock);
hcp->tx_dlp = device_property_read_bool(dev->parent, "audio,digital-loopback");
ret = snd_pcm_create_iec958_consumer_default(hcp->iec_status,
sizeof(hcp->iec_status));
if (ret < 0)

View File

@@ -7,6 +7,13 @@ config SND_SOC_ROCKCHIP
the Rockchip SoCs' Audio interfaces. You will also need to
select the audio interfaces to support below.
config SND_SOC_ROCKCHIP_ASRC
tristate "Rockchip Asynchronous Sampling Rate Converter Driver"
depends on SND_SOC_ROCKCHIP
help
Say Y or M if you want to add support for ASRC driver for
Rockchip.
config SND_SOC_ROCKCHIP_DLP
tristate

View File

@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# ROCKCHIP Platform Support
snd-soc-rockchip-objs := rockchip_utils.o
snd-soc-rockchip-asrc-objs := rockchip_asrc.o
snd-soc-rockchip-dlp-objs := rockchip_dlp.o
snd-soc-rockchip-dlp-pcm-objs := rockchip_dlp_pcm.o
snd-soc-rockchip-i2s-objs := rockchip_i2s.o
@@ -21,6 +22,7 @@ snd-soc-rockchip-vad-$(CONFIG_ARM) += vad_preprocess_arm.o
endif
obj-$(CONFIG_SND_SOC_ROCKCHIP) += snd-soc-rockchip.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_ASRC) += snd-soc-rockchip-asrc.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_DLP) += snd-soc-rockchip-dlp.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_DLP_PCM) += snd-soc-rockchip-dlp-pcm.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,191 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ALSA SoC Audio Layer - Rockchip ASRC Controller driver
*
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
*/
#ifndef _ROCKCHIP_ASRC_H_
#define _ROCKCHIP_ASRC_H_
#define ASRC_VERSION 0x0000
#define ASRC_CON 0x0004
#define ASRC_CLKDIV_CON 0x0008
#define ASRC_DATA_FMT 0x000c
#define ASRC_LOOP_CON0 0x0010
#define ASRC_LOOP_CON1 0x0014
#define ASRC_LOOP_CON2 0x0018
#define ASRC_MANUAL_RATIO 0x0020
#define ASRC_SAMPLE_RATE 0x0024
#define ASRC_RESAMPLE_RATE 0x0028
#define ASRC_TRACK_PERIOD 0x002c
#define ASRC_RATIO_MARGIN 0x0030
#define ASRC_LRCK_MARGIN 0x0034
#define ASRC_FETCH_LEN 0x0040
#define ASRC_DMA_THRESH 0x0050
#define ASRC_INT_CON 0x0060
#define ASRC_INT_ST 0x0064
#define ASRC_ST 0x0070
#define ASRC_RATIO_ST 0x0080
#define ASRC_RESAMPLE_RATE_ST 0x0084
#define ASRC_THETA_CNT_ST 0x0090
#define ASRC_DECI_THETA_ACC_ST 0x0094
#define ASRC_FIFO_IN_WRCNT 0x00a0
#define ASRC_FIFO_IN_RDCNT 0x00a4
#define ASRC_FIFO_OUT_WRCNT 0x00b0
#define ASRC_FIFO_OUT_RDCNT 0x00b4
#define ASRC_RXDR 0x00c0
#define ASRC_TXDR 0x00c4
#define ASRC_FIFO_IN_DATA 0x1000
#define ASRC_FIFO_OUT_DATA 0x5000
/**********************ASRC_CON************************/
#define ASRC_RATIO_FILT_WIN (0x3 << 20)
#define ASRC_RATIO_TRACK_MODE (0x1 << 19)
#define ASRC_RATIO_TRACK_MODE_DIS (0x0 << 19)
#define ASRC_RATIO_EXC_MSK (0x1 << 18)
#define ASRC_RATIO_EXC_EN (0x1 << 18)
#define ASRC_RATIO_EXC_DIS (0x0 << 18)
#define ASRC_RATIO_FILT_MSK (0x1 << 17)
#define ASRC_RATIO_FILT_EN (0x1 << 17)
#define ASRC_RATIO_FILT_DIS (0x0 << 17)
#define ASRC_RATIO_TRACK_MSK (0x1 << 16)
#define ASRC_RATIO_TRACK_EN (0x1 << 16)
#define ASRC_RATIO_TRACK_DIS (0x0 << 16)
#define ASRC_OUT_MSK (0x1 << 9)
#define ASRC_OUT_STOP (0x1 << 9)
#define ASRC_OUT_START (0x0 << 9)
#define ASRC_IN_MSK (0x1 << 8)
#define ASRC_IN_STOP (0x1 << 8)
#define ASRC_IN_START (0x0 << 8)
#define ASRC_CHAN_NUM_MSK (0x3 << 4)
#define ASRC_CHAN_NUM(x) (((x - 2) / 2) << 4)
#define ASRC_REAL_TIME_MODE_MSK (0x3 << 2)
#define ASRC_M2M (0x0 << 2)
#define ASRC_S2M (0x1 << 2)
#define ASRC_M2D (0x2 << 2)
#define ASRC_S2D (0x3 << 2)
#define ASRC_MODE_MSK (0x1 << 1)
#define ASRC_REAL_TIME (0x0 << 1)
#define ASRC_MEMORY_FETCH (0x1 << 1)
#define ASRC_MSK (0x1 << 0)
#define ASRC_EN (0x1 << 0)
#define ASRC_DIS (0x0 << 0)
/**********************ASRC_CLKDIV_CON************************/
#define ASRC_DST_LRCK_DIV_MSK (0x1 << 31)
#define ASRC_DST_LRCK_DIV_EN (0x1 << 31)
#define ASRC_DST_LRCK_DIV_DIS (0x0 << 31)
#define ASRC_DST_LRCK_DIV_CON_MSK (0x7fff << 16)
#define ASRC_DST_LRCK_DIV(x) ((x - 1) << 16)
#define ASRC_SRC_LRCK_DIV_MSK (0x1 << 15)
#define ASRC_SRC_LRCK_DIV_EN (0x1 << 15)
#define ASRC_SRC_LRCK_DIV_DIS (0x0 << 15)
#define ASRC_SRC_LRCK_DIV_CON_MSK (0x7fff << 0)
#define ASRC_SRC_LRCK_DIV(x) ((x - 1) << 0)
/**********************ASRC_DATA_FMT************************/
#define ASRC_OSJM_MSK (0x1f << 24)
#define ASRC_OSJM(x) (x << 24)
#define ASRC_ISJM_MSK (0x1f << 16)
#define ASRC_ISJM(x) (x << 16)
#define ASRC_OFMT_MSK (0x1 << 12)
#define ASRC_OFMT_16 (0x1 << 12)
#define ASRC_OFMT_32 (0x0 << 12)
#define ASRC_IFMT_MSK (0x1 << 8)
#define ASRC_IFMT_16 (0x1 << 8)
#define ASRC_IFMT_32 (0x0 << 8)
#define ASRC_OWL_MSK (0x3 << 4)
#define ASRC_OWL_16BIT (0x2 << 4)
#define ASRC_OWL_20BIT (0x1 << 4)
#define ASRC_OWL_24BIT (0x0 << 4)
#define ASRC_IWL_MSK (0x3 << 0)
#define ASRC_IWL_16BIT (0x2 << 0)
#define ASRC_IWL_20BIT (0x1 << 0)
#define ASRC_IWL_24BIT (0x0 << 0)
/**********************ASRC_TRACK_PERIOD************************/
#define ASRC_RATIO_TRACK_DIV_MSK (0xfff << 16)
#define ASRC_RATIO_TRACK_DIV(x) (x << 16)
#define ASRC_RATIO_TRACK_PERIOD_MSK (0xfff << 0)
#define ASRC_RATIO_TRACK_PERIOD(x) (x << 0)
/**********************ASRC_DMA_THRESH************************/
#define ASRC_POS_THRESH_MSK (0x1f << 26)
#define ASRC_POS_THRESH(x) (x << 26)
#define ASRC_NEG_THRESH_MSK (0x1f << 20)
#define ASRC_NEG_THRESH(x) (x << 20)
#define ASRC_OUT_THRESH_MSK (0xf << 12)
#define ASRC_OUT_THRESH(x) (x << 12)
#define ASRC_IN_THRESH_MSK (0xf << 8)
#define ASRC_IN_THRESH(x) (x << 8)
#define ASRC_DMA_RX_THRESH_MSK (0xf << 4)
#define ASRC_DMA_RX_THRESH(x) (x << 4)
#define ASRC_DMA_TX_THRESH_MSK (0xf << 0)
#define ASRC_DMA_TX_THRESH(x) (x << 0)
/**********************ASRC_INT_CON************************/
#define ASRC_DST_LRCK_UNLOCK_MSK (0x1 << 12)
#define ASRC_DST_LRCK_UNLOCK_EN (0x1 << 12)
#define ASRC_DST_LRCK_UNLOCK_DIS (0x0 << 12)
#define ASRC_SRC_LRCK_UNLOCK_MSK (0x1 << 11)
#define ASRC_SRC_LRCK_UNLOCK_EN (0x1 << 11)
#define ASRC_SRC_LRCK_UNLOCK_DIS (0x0 << 11)
#define ASRC_RATIO_UNLOCK_MSK (0x1 << 10)
#define ASRC_RATIO_UNLOCK_EN (0x1 << 10)
#define ASRC_RATIO_UNLOCK_DIS (0x0 << 10)
#define ASRC_FIFO_OUT_EMPTY_MSK (0x1 << 9)
#define ASRC_FIFO_OUT_EMPTY_EN (0x1 << 9)
#define ASRC_FIFO_OUT_EMPTY_DIS (0x0 << 9)
#define ASRC_FIFO_OUT_FULL_MSK (0x1 << 8)
#define ASRC_FIFO_OUT_FULL_EN (0x1 << 8)
#define ASRC_FIFO_OUT_FULL_DIS (0x0 << 8)
#define ASRC_FIFO_IN_EMPTY_MSK (0x1 << 7)
#define ASRC_FIFO_IN_EMPTY_EN (0x1 << 7)
#define ASRC_FIFO_IN_EMPTY_DIS (0x0 << 7)
#define ASRC_FIFO_IN_FULL_MSK (0x1 << 6)
#define ASRC_FIFO_IN_FULL_EN (0x1 << 6)
#define ASRC_FIFO_IN_FULL_DIS (0x1 << 6)
#define ASRC_RATIO_UPDATE_DONE_MSK (0x1 << 5)
#define ASRC_RATIO_UPDATE_DONE_EN (0x1 << 5)
#define ASRC_RATIO_UPDATE_DONE_DIS (0x0 << 5)
#define ASRC_RATIO_CHANGE_DONE_MSK (0x1 << 4)
#define ASRC_RATIO_CHANGE_DONE_EN (0x1 << 4)
#define ASRC_RATIO_CHANGE_DONE_DIS (0x0 << 4)
#define ASRC_RATIO_INIT_DONE_MSK (0x1 << 3)
#define ASRC_RATIO_INIT_DONE_EN (0x1 << 3)
#define ASRC_RATIO_INIT_DONE_DIS (0x0 << 3)
#define ASRC_CONV_ERROR_MSK (0x1 << 2)
#define ASRC_CONV_ERROR_EN (0x1 << 2)
#define ASRC_CONV_ERROR_DIS (0x0 << 2)
#define ASRC_CONV_DONE_MSK (0x1 << 1)
#define ASRC_CONV_DONE_EN (0x1 << 1)
#define ASRC_CONV_DONE_DIS (0x0 << 0)
#define ASRC_OUT_START_MSK (0x1 << 0)
#define ASRC_OUT_START_EN (0x1 << 0)
#define ASRC_OUT_START_DIS (0x0 << 0)
/**********************ASRC_INT_ST************************/
#define ASRC_DST_LRCK_UNLOCK_ST (0x1 << 12)
#define ASRC_SRC_LRCK_UNLOCK_ST (0x1 << 11)
#define ASRC_RATIO_UNLOCK_ST (0x1 << 10)
#define ASRC_FIFO_OUT_EMPTY_ST (0x1 << 9)
#define ASRC_FIFO_OUT_FULL_ST (0x1 << 8)
#define ASRC_FIFO_IN_EMPTY_ST (0x1 << 7)
#define ASRC_FIFO_IN_FULL_ST (0x1 << 6)
#define ASRC_RATIO_UPDATE_DONE_ST (0x1 << 5)
#define ASRC_RATIO_CHANGE_DONE_ST (0x1 << 4)
#define ASRC_RATIO_INIT_DONE_ST (0x1 << 3)
#define ASRC_CONV_ERROR_ST (0x1 << 2)
#define ASRC_CONV_DONE_ST (0x1 << 1)
#define ASRC_OUT_START_ST (0x1 << 0)
/**********************ASRC_ST************************/
#define ASRC_RATIO_ST_MSK (0x3 << 29)
#define ASRC_RATIO_ST_INIT (0x0 << 29)
#define ASRC_RATIO_ST_TRACK (0x1 << 29)
#define ASRC_RATIO_ST_STOP (0x2 << 29)
#define ASRC_EXCEED_POS (0x1 << 28)
#define ASRC_EXCEED_NEG (0x1 << 27)
#endif

View File

@@ -181,6 +181,25 @@ static struct i2s_of_quirks {
},
};
static bool rockchip_i2s_tdm_stream_valid(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
if (!substream)
return false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
i2s_tdm->has_playback)
return true;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
i2s_tdm->has_capture)
return true;
return false;
}
static int to_ch_num(unsigned int val)
{
switch (val) {
@@ -1024,6 +1043,9 @@ static void rockchip_i2s_tdm_xfer_stop(struct rk_i2s_tdm_dev *i2s_tdm,
udelay(150);
rockchip_i2s_tdm_clear(i2s_tdm, clr);
dev_dbg(i2s_tdm->dev, "%s: stream: %d force: %d\n",
__func__, stream, force);
}
static void rockchip_i2s_tdm_xfer_trcm_start(struct rk_i2s_tdm_dev *i2s_tdm,
@@ -1370,6 +1392,7 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai,
}
val = ret;
ret = 0;
regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, val);
regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, val);
}
@@ -1679,8 +1702,20 @@ static bool is_params_dirty(struct snd_pcm_substream *substream,
if (last_div_bclk != div_bclk)
return true;
regmap_read(i2s_tdm->regmap, I2S_CKR, &val);
last_div_lrck = ((val & I2S_CKR_TSD_MASK) >> I2S_CKR_TSD_SHIFT) + 1;
if (i2s_tdm->tdm_mode) {
regmap_read(i2s_tdm->regmap,
substream->stream ? I2S_TDM_RXCR : I2S_TDM_TXCR, &val);
last_div_lrck = TDM_FRAME_WIDTH_V(val);
regmap_read(i2s_tdm->regmap,
substream->stream ? I2S_RXCR : I2S_TXCR, &val);
val &= I2S_TXCR_TFS_MASK;
if (val == I2S_TXCR_TFS_TDM_I2S && !i2s_tdm->tdm_fsync_half_frame)
last_div_lrck <<= 1;
} else {
regmap_read(i2s_tdm->regmap, I2S_CKR, &val);
last_div_lrck = I2S_CKR_TSD_V(val);
}
if (last_div_lrck != div_lrck)
return true;
@@ -1827,6 +1862,9 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
unsigned int val = 0;
unsigned int mclk_rate, bclk_rate, lrck_rate, div_bclk = 4, div_lrck = 64;
if (!rockchip_i2s_tdm_stream_valid(substream, dai))
return 0;
#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES
if (i2s_tdm->is_tdm_multi_lanes)
rockchip_i2s_tdm_multi_lanes_set_clk(substream, params, dai);
@@ -1892,6 +1930,9 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
static int rockchip_i2s_tdm_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
if (!rockchip_i2s_tdm_stream_valid(substream, dai))
return 0;
rockchip_utils_put_performance(substream, dai);
return 0;
@@ -1902,6 +1943,9 @@ static int rockchip_i2s_tdm_trigger(struct snd_pcm_substream *substream,
{
struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);
if (!rockchip_i2s_tdm_stream_valid(substream, dai))
return 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -2248,6 +2292,24 @@ static int rockchip_dai_tdm_slot(struct snd_soc_dai *dai,
regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, val);
regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, val);
/*
* TDM mode use all FIFOs, the max burst is 16 word of DMAC,
* so we used the max FIFO to cover DDR dmc windows.
*
* 4 FIFOs controller:
*
* TDL:
*
* 16 word: WL = ((32 * 4) - 16) / 4 = 28
*
* RDL:
*
* 16 word: WL = 16 / 4 = 4
*/
regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
I2S_DMACR_TDL(28));
regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
I2S_DMACR_RDL(4));
pm_runtime_put(dai->dev);
@@ -2273,6 +2335,9 @@ static int rockchip_i2s_tdm_startup(struct snd_pcm_substream *substream,
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
if (!rockchip_i2s_tdm_stream_valid(substream, dai))
return 0;
if (i2s_tdm->substreams[stream])
return -EBUSY;
@@ -2289,6 +2354,9 @@ static void rockchip_i2s_tdm_shutdown(struct snd_pcm_substream *substream,
{
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
if (!rockchip_i2s_tdm_stream_valid(substream, dai))
return;
i2s_tdm->substreams[substream->stream] = NULL;
}
@@ -2825,6 +2893,9 @@ static int rockchip_i2s_tdm_keep_clk_always_on(struct rk_i2s_tdm_dev *i2s_tdm)
unsigned int div_bclk;
int ret;
if (mclk_rate < bclk_rate)
mclk_rate = bclk_rate;
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
/* assign generic freq */

View File

@@ -118,6 +118,7 @@
#define I2S_CKR_RSD_MASK (0xff << I2S_CKR_RSD_SHIFT)
#define I2S_CKR_TSD_SHIFT 0
#define I2S_CKR_TSD(x) (((x) - 1) << I2S_CKR_TSD_SHIFT)
#define I2S_CKR_TSD_V(x) ((((x) & I2S_CKR_TSD_MASK) >> I2S_CKR_TSD_SHIFT) + 1)
#define I2S_CKR_TSD_MASK (0xff << I2S_CKR_TSD_SHIFT)
/*
@@ -269,6 +270,7 @@
#define TDM_SLOT_BIT_WIDTH(x) (((x) - 1) << 9)
#define TDM_FRAME_WIDTH_MSK GENMASK(8, 0)
#define TDM_FRAME_WIDTH(x) (((x) - 1) << 0)
#define TDM_FRAME_WIDTH_V(v) ((((v) & TDM_FRAME_WIDTH_MSK) >> 0) + 1)
/*
* CLKDIV

View File

@@ -41,6 +41,7 @@
#define DRV_NAME "rk-multicodecs"
#define WAIT_CARDS (SNDRV_CARDS - 1)
#define DEFAULT_MCLK_FS 256
#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
struct adc_keys_button {
u32 voltage;
@@ -57,7 +58,7 @@ struct input_dev_poller {
struct multicodecs_data {
struct snd_soc_card snd_card;
struct snd_soc_dai_link dai_link;
struct snd_soc_dai_link dai_link[3];
struct snd_soc_jack *jack_headset;
struct gpio_desc *hp_ctl_gpio;
struct gpio_desc *spk_ctl_gpio;
@@ -312,7 +313,6 @@ static int mc_spk_event(struct snd_soc_dapm_widget *w,
break;
default:
return 0;
}
return 0;
@@ -321,6 +321,8 @@ static int mc_spk_event(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget mc_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone", mc_hp_event),
SND_SOC_DAPM_SPK("Speaker", mc_spk_event),
SND_SOC_DAPM_LINE("Line Out Jack", NULL),
SND_SOC_DAPM_LINE("Line In Jack", NULL),
SND_SOC_DAPM_MIC("Main Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -492,7 +494,7 @@ static int rk_multicodecs_parse_daifmt(struct device_node *node,
struct multicodecs_data *mc_data,
const char *prefix)
{
struct snd_soc_dai_link *dai_link = &mc_data->dai_link;
struct snd_soc_dai_link *dai_link = &mc_data->dai_link[0];
struct device_node *bitclkmaster = NULL;
struct device_node *framemaster = NULL;
unsigned int daifmt;
@@ -592,17 +594,56 @@ static struct snd_soc_ops rk_ops = {
.hw_params = rk_multicodecs_hw_params,
};
SND_SOC_DAILINK_DEFS(hifi,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hifi_fe,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hifi_be,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_DUMMY()));
static const struct snd_soc_dai_link rk_multicodecs_card_dai[] = {
/* Default ASoC DAI Link*/
{
.name = "HiFi",
.stream_name = "HiFi",
.ops = &rk_ops,
SND_SOC_DAILINK_REG(hifi),
},
/* DPCM Link between Front-End and Back-End (Optional) */
{
.name = "HiFi-ASRC-FE",
.stream_name = "HiFi-ASRC-FE",
.dpcm_playback = 1,
.dpcm_capture = 1,
.dynamic = 1,
SND_SOC_DAILINK_REG(hifi_fe),
},
{
.name = "HiFi-ASRC-BE",
.stream_name = "HiFi-ASRC-BE",
.ops = &rk_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(hifi_be),
},
};
static int rk_multicodecs_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
struct device_node *np = pdev->dev.of_node;
struct snd_soc_dai_link *link;
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link_component *platforms;
struct device_node *np = pdev->dev.of_node, *node, *asrc_np;
struct snd_soc_dai_link_component *codecs;
struct multicodecs_data *mc_data;
struct of_phandle_args args;
struct device_node *node;
struct input_dev *input;
u32 val;
int count, value, irq;
@@ -619,13 +660,7 @@ static int rk_multicodecs_probe(struct platform_device *pdev)
if (!mc_data)
return -ENOMEM;
cpus = devm_kzalloc(&pdev->dev, sizeof(*cpus), GFP_KERNEL);
if (!cpus)
return -ENOMEM;
platforms = devm_kzalloc(&pdev->dev, sizeof(*platforms), GFP_KERNEL);
if (!platforms)
return -ENOMEM;
memcpy(mc_data->dai_link, rk_multicodecs_card_dai, sizeof(mc_data->dai_link));
card = &mc_data->snd_card;
card->dev = &pdev->dev;
@@ -635,18 +670,15 @@ static int rk_multicodecs_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
link = &mc_data->dai_link;
link->name = "dailink-multicodecs";
link->stream_name = link->name;
link->init = rk_dailink_init;
link->ops = &rk_ops;
link->cpus = cpus;
link->platforms = platforms;
link->num_cpus = 1;
link->num_platforms = 1;
link->ignore_pmdown_time = 1;
mc_data->dai_link[0].name = "dailink-multicodecs";
mc_data->dai_link[0].stream_name = mc_data->dai_link[0].name;
mc_data->dai_link[0].init = rk_dailink_init;
mc_data->dai_link[0].ops = &rk_ops;
mc_data->dai_link[0].num_cpus = 1;
mc_data->dai_link[0].num_platforms = 1;
mc_data->dai_link[0].ignore_pmdown_time = 1;
card->dai_link = link;
card->dai_link = mc_data->dai_link;
card->num_links = 1;
card->dapm_widgets = mc_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(mc_dapm_widgets);
@@ -675,8 +707,8 @@ static int rk_multicodecs_probe(struct platform_device *pdev)
if (!codecs)
return -ENOMEM;
link->codecs = codecs;
link->num_codecs = idx;
mc_data->dai_link[0].codecs = codecs;
mc_data->dai_link[0].num_codecs = idx;
idx = 0;
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "rockchip,codec", i);
@@ -700,11 +732,26 @@ static int rk_multicodecs_probe(struct platform_device *pdev)
/* Only reference the codecs[0].of_node which maybe as master. */
rk_multicodecs_parse_daifmt(np, codecs[0].of_node, mc_data, prefix);
link->cpus->of_node = of_parse_phandle(np, "rockchip,cpu", 0);
if (!link->cpus->of_node)
mc_data->dai_link[0].cpus->of_node = of_parse_phandle(np, "rockchip,cpu", 0);
if (!mc_data->dai_link[0].cpus->of_node)
return -ENODEV;
link->platforms->of_node = link->cpus->of_node;
mc_data->dai_link[0].platforms->of_node = mc_data->dai_link[0].cpus->of_node;
asrc_np = of_parse_phandle(np, "rockchip,asrc", 0);
if (asrc_np) {
mc_data->dai_link[1].cpus->of_node = asrc_np;
mc_data->dai_link[1].platforms->of_node = asrc_np;
mc_data->dai_link[1].num_cpus = 1;
mc_data->dai_link[1].num_platforms = 1;
/* Support multicodec in future */
mc_data->dai_link[2].codecs->dai_name = "dummy_codec";
mc_data->dai_link[2].codecs->of_node = of_parse_phandle(np, "rockchip,codec", 0);
mc_data->dai_link[2].cpus->of_node = mc_data->dai_link[0].cpus->of_node;
card->num_links = 3;
}
mc_data->mclk_fs = DEFAULT_MCLK_FS;
if (!of_property_read_u32(np, "rockchip,mclk-fs", &val))
@@ -814,7 +861,7 @@ static int rk_multicodecs_probe(struct platform_device *pdev)
snd_soc_of_parse_audio_routing(card, "rockchip,audio-routing");
snd_soc_card_set_drvdata(card, mc_data);
platform_set_drvdata(pdev, card);
platform_set_drvdata(pdev, mc_data);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
@@ -832,8 +879,7 @@ static int rk_multicodecs_probe(struct platform_device *pdev)
static int rk_multicodec_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct multicodecs_data *mc_data = snd_soc_card_get_drvdata(card);
struct multicodecs_data *mc_data = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&mc_data->handler);
@@ -842,8 +888,7 @@ static int rk_multicodec_remove(struct platform_device *pdev)
static void rk_multicodec_shutdown(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct multicodecs_data *mc_data = snd_soc_card_get_drvdata(card);
struct multicodecs_data *mc_data = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&mc_data->handler);
}

View File

@@ -87,6 +87,25 @@ static const struct sai_of_quirks {
},
};
static bool rockchip_sai_stream_valid(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
if (!substream)
return false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
sai->has_playback)
return true;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
sai->has_capture)
return true;
return false;
}
static int rockchip_sai_fsync_lost_detect(struct rk_sai_dev *sai, bool en)
{
unsigned int fw, cnt;
@@ -524,6 +543,9 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
unsigned int ch_per_lane, lanes, slot_width;
unsigned int val, fscr, reg, fifo;
if (!rockchip_sai_stream_valid(substream, dai))
return 0;
dma_data = snd_soc_dai_get_dma_data(dai, substream);
dma_data->maxburst = MAXBURST_PER_FIFO * params_channels(params) / 2;
@@ -621,6 +643,9 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
static int rockchip_sai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
if (!rockchip_sai_stream_valid(substream, dai))
return 0;
rockchip_utils_put_performance(substream, dai);
return 0;
@@ -631,6 +656,9 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
if (!rockchip_sai_stream_valid(substream, dai))
return 0;
if (sai->is_master_mode) {
/*
* Should wait for one BCLK ready after DIV and then ungate
@@ -760,6 +788,9 @@ static int rockchip_sai_trigger(struct snd_pcm_substream *substream,
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
int ret = 0;
if (!rockchip_sai_stream_valid(substream, dai))
return 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -934,6 +965,9 @@ static int rockchip_sai_startup(struct snd_pcm_substream *substream,
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
if (!rockchip_sai_stream_valid(substream, dai))
return 0;
if (sai->substreams[stream])
return -EBUSY;
@@ -950,6 +984,9 @@ static void rockchip_sai_shutdown(struct snd_pcm_substream *substream,
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
if (!rockchip_sai_stream_valid(substream, dai))
return;
sai->substreams[substream->stream] = NULL;
}

View File

@@ -303,6 +303,11 @@ static int dmaengine_trcm_trigger(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
#ifdef TRCM_DEBUG
ktime_t start_time, stop_time, diff_time;
start_time = ktime_get();
#endif
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
dmaengine_terminate_async(prtd->dma_chan);
@@ -332,6 +337,13 @@ static int dmaengine_trcm_trigger(struct snd_soc_component *component,
return -EINVAL;
}
#ifdef TRCM_DEBUG
stop_time = ktime_get();
diff_time = ktime_sub(stop_time, start_time);
dev_dbg(component->dev, "cmd: %d time cost %lld\n",
cmd, ktime_to_us(diff_time));
#endif
return 0;
}