diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy0.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy0.dtsi index 85007840d55a..1f9af40db207 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy0.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy0.dtsi @@ -127,7 +127,7 @@ max-fps-numerator = <10000>; max-fps-denominator = <300000>; bpp = <16>; - link-freq-idx = <12>; + link-freq-idx = <24>; vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7 }; /* support mode config end */ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy1.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy1.dtsi index 9c7b3c7a4677..d7a0a2f46011 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy1.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712-dcphy1.dtsi @@ -127,7 +127,7 @@ max-fps-numerator = <10000>; max-fps-denominator = <300000>; bpp = <16>; - link-freq-idx = <20>; + link-freq-idx = <24>; vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7 }; /* support mode config end */ diff --git a/arch/arm64/configs/rockchip_defconfig b/arch/arm64/configs/rockchip_defconfig index f9ee6529c01a..5529fc2f87ce 100644 --- a/arch/arm64/configs/rockchip_defconfig +++ b/arch/arm64/configs/rockchip_defconfig @@ -697,6 +697,7 @@ CONFIG_SND_VERBOSE_PRINTK=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_SND_SOC_ROCKCHIP=y +CONFIG_SND_SOC_ROCKCHIP_DLP_PCM=y CONFIG_SND_SOC_ROCKCHIP_I2S=y CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES=y diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index f6d640becad8..700d94938042 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -392,6 +392,7 @@ CONFIG_SND_SEQ_DUMMY=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_SND_SOC_ROCKCHIP=y +CONFIG_SND_SOC_ROCKCHIP_DLP_PCM=y CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS=y CONFIG_SND_SOC_ROCKCHIP_PDM=y diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index e386c39537ae..55612fe0e285 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -245,6 +245,7 @@ struct dw_mipi_dsi2 { struct phy *dcphy; union phy_configure_opts phy_opts; + bool disable_hold_mode; bool c_option; bool scrambling_en; unsigned int slice_width; @@ -953,7 +954,7 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder, if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)) { s->output_flags |= ROCKCHIP_OUTPUT_MIPI_DS_MODE; s->soft_te = dsi2->te_gpio ? true : false; - s->hold_mode = true; + s->hold_mode = dsi2->disable_hold_mode ? false : true; } if (dsi2->slave) { @@ -1638,6 +1639,9 @@ static int dw_mipi_dsi2_probe(struct platform_device *pdev) dsi2->pdata = of_device_get_match_data(dev); platform_set_drvdata(pdev, dsi2); + if (device_property_read_bool(dev, "disable-hold-mode")) + dsi2->disable_hold_mode = true; + if (device_property_read_bool(dev, "dual-connector-split")) { dsi2->dual_connector_split = true; diff --git a/drivers/media/i2c/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim4c/maxim4c_drv.c index 9d9df08b4dbd..65650eeb5387 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim4c/maxim4c_drv.c @@ -29,12 +29,13 @@ * V2.03.00 * 1. remote device add the maxim4c prefix to driver name. * - * V2.04.03 + * V2.04.04 * 1. Add regulator supplier dependencies. * 2. Add config ssc-ratio property * 3. Add debugfs entry to change MIPI timing * 4. Use PM runtime autosuspend feature * 5. Fix unbalanced disabling for PoC regulator + * 6. MIPI VC count does not affected by data lane count * */ #include @@ -65,7 +66,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x03) +#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x04) #define MAXIM4C_XVCLK_FREQ 25000000 diff --git a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c index b40fdf2b3632..a331023da0d4 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c +++ b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c @@ -786,21 +786,9 @@ static int maxim4c_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, val |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; val |= (1 << (data_lanes - 1)); - switch (data_lanes) { - case 4: - val |= V4L2_MBUS_CSI2_CHANNEL_3; - fallthrough; - case 3: - val |= V4L2_MBUS_CSI2_CHANNEL_2; - fallthrough; - case 2: - val |= V4L2_MBUS_CSI2_CHANNEL_1; - fallthrough; - case 1: - default: - val |= V4L2_MBUS_CSI2_CHANNEL_0; - break; - } + + val |= V4L2_MBUS_CSI2_CHANNEL_3 | V4L2_MBUS_CSI2_CHANNEL_2 | + V4L2_MBUS_CSI2_CHANNEL_1 | V4L2_MBUS_CSI2_CHANNEL_0; config->type = V4L2_MBUS_CSI2_DPHY; config->flags = val; diff --git a/drivers/mfd/rkx110_x120/rkx110_linktx.c b/drivers/mfd/rkx110_x120/rkx110_linktx.c index 007a825ab19e..59135a990deb 100644 --- a/drivers/mfd/rkx110_x120/rkx110_linktx.c +++ b/drivers/mfd/rkx110_x120/rkx110_linktx.c @@ -428,9 +428,11 @@ static int rk_serdes_link_tx_ctrl_enable(struct rk_serdes *serdes, { struct hwclk *hwclk = serdes->chip[remote_id].hwclk; struct i2c_client *client; + struct videomode *vm = &route->vm; u32 ctrl_val, val; u32 rx_src; u32 stream_type; + u32 length; if (route->stream_type == STREAM_DISPLAY) { client = serdes->chip[DEVICE_LOCAL].client; @@ -459,6 +461,18 @@ static int rk_serdes_link_tx_ctrl_enable(struct rk_serdes *serdes, serdes->i2c_read_reg(client, RKLINK_TX_VIDEO_CTRL, &val); rx_src = rk_serdes_get_stream_source(serdes, route->local_port0); val |= rx_src; + if (serdes->version == SERDES_V1) { + /* + * The serdes v1 have a bug when enable video suspend function, which + * is used to enhance the i2c frequency. A workaround ways to do it is + * reducing the video packet length: + * length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16 + */ + length = vm->hactive * 24 / 32 / 16; + length = (length + 15) / 16 * 16; + val &= ~VIDEO_REPKT_LENGTH(0xffff); + val |= VIDEO_REPKT_LENGTH(length); + } serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val); if (route->local_port0 & RK_SERDES_DUAL_LVDS_RX) { diff --git a/drivers/mfd/rkx110_x120/rkx110_x120.h b/drivers/mfd/rkx110_x120/rkx110_x120.h index 67c2d1fe349d..545cb5b6f044 100644 --- a/drivers/mfd/rkx110_x120/rkx110_x120.h +++ b/drivers/mfd/rkx110_x120/rkx110_x120.h @@ -259,6 +259,7 @@ struct rk_serdes_pt { struct rk_serdes { struct device *dev; struct rk_serdes_chip chip[DEVICE_MAX]; + struct regulator *supply; struct gpio_desc *reset; struct gpio_desc *enable; diff --git a/drivers/mfd/rkx110_x120/rkx110_x120_core.c b/drivers/mfd/rkx110_x120/rkx110_x120_core.c index 9a94ee834284..18d0e3e2bc73 100644 --- a/drivers/mfd/rkx110_x120/rkx110_x120_core.c +++ b/drivers/mfd/rkx110_x120/rkx110_x120_core.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "rkx110_x120.h" #include "rkx110_reg.h" @@ -958,6 +959,7 @@ static int rk_serdes_pinctrl_init(struct rk_serdes *serdes) static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct device_node *disp_np; struct rk_serdes *serdes; int ret; @@ -988,6 +990,16 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic serdes->rate = RATE_2GBPS_83M; + serdes->supply = devm_regulator_get_optional(dev, "power"); + if (IS_ERR(serdes->supply)) { + ret = PTR_ERR(serdes->supply); + + if (ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to request regulator\n"); + + serdes->supply = NULL; + } + serdes->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(serdes->enable)) { ret = PTR_ERR(serdes->enable); @@ -1002,15 +1014,10 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic return ret; } - gpiod_set_value(serdes->enable, 1); - - gpiod_set_value(serdes->reset, 1); - usleep_range(10000, 11000); - gpiod_set_value(serdes->reset, 0); - - if (of_get_child_by_name(dev->of_node, "serdes-panel")) { + disp_np = of_get_child_by_name(dev->of_node, "serdes-panel"); + if (disp_np) { serdes->stream_type = STREAM_DISPLAY; - of_node_put(dev->of_node); + of_node_put(disp_np); dev_info(dev, "serdes display stream"); } else { serdes->stream_type = STREAM_CAMERA; @@ -1021,8 +1028,6 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic if (ret) return ret; - msleep(20); - ret = mfd_add_devices(dev, -1, rkx110_x120_devs, ARRAY_SIZE(rkx110_x120_devs), NULL, 0, NULL); if (ret) { @@ -1030,13 +1035,29 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic return ret; } + if (serdes->supply) { + ret = regulator_enable(serdes->supply); + if (ret < 0) { + dev_err(serdes->dev, "failed to enable supply: %d\n", ret); + return ret; + } + } + + gpiod_set_value(serdes->enable, 1); + + gpiod_set_value(serdes->reset, 1); + usleep_range(10000, 11000); + gpiod_set_value(serdes->reset, 0); + + msleep(20); + rk_serdes_wait_link_ready(serdes); rk_serdes_read_chip_id(serdes); ret = rk_serdes_add_hwclk(serdes); if (ret < 0) - return ret; + goto err; rk_serdes_set_rate(serdes, RATE_4GBPS_83M); rk_serdes_pinctrl_init(serdes); @@ -1045,12 +1066,21 @@ out: rk_serdes_debugfs_init(serdes); return 0; + +err: + if (serdes->supply) + ret = regulator_disable(serdes->supply); + + return ret; } static void rk_serdes_i2c_remove(struct i2c_client *client) { struct rk_serdes *rk_serdes = i2c_get_clientdata(client); + if (rk_serdes->supply) + regulator_disable(rk_serdes->supply); + mfd_remove_devices(rk_serdes->dev); } diff --git a/drivers/mfd/rkx110_x120/rkx120_linkrx.c b/drivers/mfd/rkx110_x120/rkx120_linkrx.c index 45d965b077be..bae51fdb0cc6 100644 --- a/drivers/mfd/rkx110_x120/rkx120_linkrx.c +++ b/drivers/mfd/rkx110_x120/rkx120_linkrx.c @@ -104,6 +104,9 @@ #define LANE0_LANE_ID(x) UPDATE(x, 1, 1) #define LNAE0_ID_SEL(x) UPDATE(x, 0, 0) +#define DES_RKLINK_REC01_PKT_LENGTH LINK_REG(0x0028) +#define E1_REPKT_LENGTH(x) UPDATE(x, 29, 16) +#define E0_REPKT_LENGTH(x) UPDATE(x, 13, 0) #define RKLINK_DES_REG01_ENGIN_DEL 0x0030 #define E1_ENGINE_DELAY(x) UPDATE(x, 31, 16) #define E0_ENGINE_DELAY(x) UPDATE(x, 15, 0) @@ -476,12 +479,14 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r { struct hwclk *hwclk = serdes->chip[remote_id].hwclk; struct i2c_client *client; + struct videomode *vm = &route->vm; u32 stream_type; u32 rx_src; u32 ctrl_val, mask, val; u32 lane0_dsource_id, lane1_dsource_id; bool is_rx_dual_lanes; bool is_rx_dual_channels; + u32 length; if (route->stream_type == STREAM_DISPLAY) { client = serdes->chip[remote_id].client; @@ -530,6 +535,19 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_DST, mask, val); + if (serdes->version == SERDES_V1) { + /* + * The serdes v1 have a bug when enable video suspend function, which + * is used to enhance the i2c frequency. A workaround ways to do it is + * reducing the video packet length: + * length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16 + */ + length = vm->hactive * 24 / 32 / 16; + length = (length + 15) / 16 * 16; + serdes->i2c_write_reg(client, DES_RKLINK_REC01_PKT_LENGTH, E0_REPKT_LENGTH(length) | + E1_REPKT_LENGTH(length)); + } + serdes->i2c_read_reg(client, RKLINK_DES_SOURCE_CFG, &val); val &= ~(LANE0_ENGINE_ID(1) | LANE0_LANE_ID(1) | LANE1_ENGINE_ID(1) | diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index 130224509d10..51388b2e6d48 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -415,7 +415,7 @@ static int rk817_codec_power_up(struct snd_soc_component *component, int type) } snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, - ADC_DIG_CLK_MASK, DAC_DIG_CLK_DIS); + ADC_DIG_CLK_MASK, ADC_DIG_CLK_DIS); usleep_range(2000, 2500); snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, ADC_DIG_CLK_MASK, ADC_DIG_CLK_EN); @@ -1027,7 +1027,7 @@ static int rk817_hw_params(struct snd_pcm_substream *substream, return 0; } -static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream) +static int rk817_digital_mute_dac(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); @@ -1049,7 +1049,11 @@ static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream) DAC_DIG_CLK_EN, DAC_DIG_CLK_DIS); snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, DAC_DIG_CLK_EN, DAC_DIG_CLK_EN); + snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, + I2SRX_EN_MASK, I2SRX_DIS); } else { + snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, + I2SRX_EN_MASK, I2SRX_EN); snd_soc_component_update_bits(component, RK817_CODEC_DDAC_MUTE_MIXCTL, DACMT_ENABLE, DACMT_DISABLE); @@ -1099,6 +1103,28 @@ static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static int rk817_digital_mute_adc(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + + if (mute) + snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, + I2STX_EN_MASK, I2STX_DIS); + else + snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, + I2STX_EN_MASK, I2STX_EN); + + return 0; +} + +static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + return rk817_digital_mute_dac(dai, mute, stream); + else + return rk817_digital_mute_adc(dai, mute, stream); +} + #define RK817_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\ SNDRV_PCM_RATE_16000 | \ SNDRV_PCM_RATE_32000 | \ @@ -1143,7 +1169,6 @@ static const struct snd_soc_dai_ops rk817_dai_ops = { .set_sysclk = rk817_set_dai_sysclk, .mute_stream = rk817_digital_mute, .shutdown = rk817_codec_shutdown, - .no_capture_mute = 1, }; static struct snd_soc_dai_driver rk817_dai[] = { diff --git a/sound/soc/codecs/rk817_codec.h b/sound/soc/codecs/rk817_codec.h index ef899e359055..90b2bdb81664 100644 --- a/sound/soc/codecs/rk817_codec.h +++ b/sound/soc/codecs/rk817_codec.h @@ -25,7 +25,7 @@ #define ADC_DIG_CLK_MASK (0xf << 4) #define ADC_DIG_CLK_SFT 4 #define ADC_DIG_CLK_DIS (0x0 << 4) -#define ADC_DIG_CLK_EN (0xf << 4) +#define ADC_DIG_CLK_EN (0xe << 4) #define I2STX_CKE_EN (0x1 << 6) #define I2STX_CKE_DIS (0x0 << 6) @@ -33,7 +33,15 @@ #define DAC_DIG_CLK_MASK (0xf << 0) #define DAC_DIG_CLK_SFT 0 #define DAC_DIG_CLK_DIS (0x0 << 0) -#define DAC_DIG_CLK_EN (0xf << 0) +#define DAC_DIG_CLK_EN (0xe << 0) + +#define I2STX_EN_MASK BIT(4) +#define I2STX_EN BIT(4) +#define I2STX_DIS 0 + +#define I2SRX_EN_MASK BIT(0) +#define I2SRX_EN BIT(0) +#define I2SRX_DIS 0 /* RK817_CODEC_APLL_CFG5 */ #define PLL_PW_DOWN (0x01 << 0) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 2afff701d4cf..aed87483edc4 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -22,6 +22,7 @@ #include #include "rockchip_i2s.h" +#include "rockchip_dlp_pcm.h" #define DRV_NAME "rockchip-i2s" @@ -635,8 +636,8 @@ static int rockchip_i2s_clk_compensation_info(struct snd_kcontrol *kcontrol, static int rockchip_i2s_clk_compensation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); ucontrol->value.integer.value[0] = i2s->clk_ppm; @@ -646,8 +647,8 @@ static int rockchip_i2s_clk_compensation_get(struct snd_kcontrol *kcontrol, static int rockchip_i2s_clk_compensation_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); int ppm = ucontrol->value.integer.value[0]; if ((ucontrol->value.integer.value[0] < CLK_PPM_MIN) || @@ -863,7 +864,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) case I2S_CLR: case I2S_TXDR: case I2S_RXDR: - case I2S_FIFOLR: + case I2S_TXFIFOLR: + case I2S_RXFIFOLR: case I2S_INTSR: return true; default: @@ -876,7 +878,8 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) switch (reg) { case I2S_INTSR: case I2S_CLR: - case I2S_FIFOLR: + case I2S_TXFIFOLR: + case I2S_RXFIFOLR: case I2S_TXDR: case I2S_RXDR: return true; @@ -1081,6 +1084,36 @@ static int rockchip_i2s_keep_clk_always_on(struct rk_i2s_dev *i2s) return 0; } +static int rockchip_i2s_get_fifo_count(struct device *dev, + struct snd_pcm_substream *substream) +{ + struct rk_i2s_dev *i2s = dev_get_drvdata(dev); + unsigned int tx, rx; + int val = 0; + + regmap_read(i2s->regmap, I2S_TXFIFOLR, &tx); + regmap_read(i2s->regmap, I2S_RXFIFOLR, &rx); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val = I2S_FIFOLR_XFL3(tx) + + I2S_FIFOLR_XFL2(tx) + + I2S_FIFOLR_XFL1(tx) + + I2S_FIFOLR_XFL0(tx); + else + /* XFL4 is compatible for old version */ + val = I2S_FIFOLR_XFL4(tx) + + I2S_FIFOLR_XFL3(rx) + + I2S_FIFOLR_XFL2(rx) + + I2S_FIFOLR_XFL1(rx) + + I2S_FIFOLR_XFL0(rx); + + return val; +} + +static const struct snd_dlp_config dconfig = { + .get_fifo_count = rockchip_i2s_get_fifo_count, +}; + static int rockchip_i2s_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -1221,7 +1254,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev) return 0; } - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (device_property_read_bool(&pdev->dev, "rockchip,digital-loopback")) + ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig); + else + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); goto err_suspend; diff --git a/sound/soc/rockchip/rockchip_i2s.h b/sound/soc/rockchip/rockchip_i2s.h index 251851bf4f2c..bf71ea59ab0c 100644 --- a/sound/soc/rockchip/rockchip_i2s.h +++ b/sound/soc/rockchip/rockchip_i2s.h @@ -229,7 +229,7 @@ enum { #define I2S_TXCR (0x0000) #define I2S_RXCR (0x0004) #define I2S_CKR (0x0008) -#define I2S_FIFOLR (0x000c) +#define I2S_TXFIFOLR (0x000c) #define I2S_DMACR (0x0010) #define I2S_INTCR (0x0014) #define I2S_INTSR (0x0018) @@ -237,6 +237,7 @@ enum { #define I2S_CLR (0x0020) #define I2S_TXDR (0x0024) #define I2S_RXDR (0x0028) +#define I2S_RXFIFOLR (0x002c) /* io direction cfg register */ #define I2S_IO_DIRECTION_MASK (7) @@ -245,4 +246,11 @@ enum { #define I2S_IO_4CH_OUT_6CH_IN (6) #define I2S_IO_2CH_OUT_8CH_IN (7) +/* XFL4 is compatible for old version */ +#define I2S_FIFOLR_XFL4(v) (((v) & GENMASK(29, 24)) >> 24) +#define I2S_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18) +#define I2S_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12) +#define I2S_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6) +#define I2S_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0) + #endif /* _ROCKCHIP_IIS_H */ diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 6d236184be3f..333e4f4abfe6 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -1898,8 +1898,8 @@ static int rockchip_i2s_tdm_clk_compensation_info(struct snd_kcontrol *kcontrol, static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = i2s_tdm->clk_ppm; @@ -1909,8 +1909,8 @@ static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol, static int rockchip_i2s_tdm_clk_compensation_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component); int ret = 0, ppm = 0; int changed = 0; unsigned long old_rate; diff --git a/sound/soc/rockchip/rockchip_multi_dais_pcm.c b/sound/soc/rockchip/rockchip_multi_dais_pcm.c index d15875e7bf02..17e12bac7b11 100644 --- a/sound/soc/rockchip/rockchip_multi_dais_pcm.c +++ b/sound/soc/rockchip/rockchip_multi_dais_pcm.c @@ -20,6 +20,8 @@ #define I2S_TXFIFOLR 0xc #define I2S_RXFIFOLR 0x2c +#define SAI_TXFIFOLR 0x1c +#define SAI_RXFIFOLR 0x20 /* XFL4 is compatible for old version */ #define I2S_FIFOLR_XFL4(v) (((v) & GENMASK(29, 24)) >> 24) @@ -28,6 +30,12 @@ #define I2S_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6) #define I2S_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0) +/* XFIFOLR: Transfer / Receive FIFO Level Register */ +#define SAI_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18) +#define SAI_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12) +#define SAI_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6) +#define SAI_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0) + #define MAX_FIFO_SIZE 32 /* max fifo size in frames */ #define SND_DMAENGINE_MPCM_DRV_NAME "snd_dmaengine_mpcm" @@ -862,7 +870,7 @@ static int dmaengine_mpcm_get_fifo_count(struct device *dev, struct rk_mdais_dev *mdais = dev_get_drvdata(dev); struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); struct snd_soc_component *component; - unsigned int tx, rx; + unsigned int tx, rx, reg; int val = 0; if (unlikely(!prtd)) @@ -889,6 +897,13 @@ static int dmaengine_mpcm_get_fifo_count(struct device *dev, I2S_FIFOLR_XFL2(rx) + I2S_FIFOLR_XFL1(rx) + I2S_FIFOLR_XFL0(rx); + } else if (strstr(dev_driver_string(component->dev), "sai")) { + reg = substream->stream ? SAI_RXFIFOLR : SAI_TXFIFOLR; + + val = SAI_FIFOLR_XFL3(reg) + + SAI_FIFOLR_XFL2(reg) + + SAI_FIFOLR_XFL1(reg) + + SAI_FIFOLR_XFL0(reg); } return val; diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index c7833d153bee..ecae4d2ff25e 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -31,8 +31,10 @@ #define PDM_FILTER_DELAY_MS_MIN (20) #define PDM_FILTER_DELAY_MS_MAX (1000) #define PDM_CLK_SHIFT_PPM_MAX (1000000) /* 1 ppm */ -#define CLK_PPM_MIN (-1000) -#define CLK_PPM_MAX (1000) +#define CLK_PPM_MIN (-1000) +#define CLK_PPM_MAX (1000) + +#define QUIRK_ALWAYS_ON BIT(0) enum rk_pdm_version { RK_PDM_RK3229, @@ -56,6 +58,7 @@ struct rk_pdm_dev { enum rk_pdm_version version; unsigned int clk_root_rate; unsigned int clk_root_initial_rate; + unsigned int quirks; int clk_ppm; bool clk_calibrate; }; @@ -97,6 +100,16 @@ static struct rk_pdm_ds_ratio ds_ratio[] = { { 4, 8000 }, }; +static const struct pdm_of_quirks { + char *quirk; + int id; +} of_quirks[] = { + { + .quirk = "rockchip,always-on", + .id = QUIRK_ALWAYS_ON, + }, +}; + static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr, unsigned int *clk_src, unsigned int *clk_out, unsigned int signoff) @@ -508,8 +521,8 @@ static int rockchip_pdm_start_delay_info(struct snd_kcontrol *kcontrol, static int rockchip_pdm_start_delay_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = pdm->start_delay_ms; @@ -519,8 +532,8 @@ static int rockchip_pdm_start_delay_get(struct snd_kcontrol *kcontrol, static int rockchip_pdm_start_delay_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); if ((ucontrol->value.integer.value[0] < PDM_START_DELAY_MS_MIN) || (ucontrol->value.integer.value[0] > PDM_START_DELAY_MS_MAX)) @@ -546,8 +559,8 @@ static int rockchip_pdm_filter_delay_info(struct snd_kcontrol *kcontrol, static int rockchip_pdm_filter_delay_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = pdm->filter_delay_ms; @@ -557,8 +570,8 @@ static int rockchip_pdm_filter_delay_get(struct snd_kcontrol *kcontrol, static int rockchip_pdm_filter_delay_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); if ((ucontrol->value.integer.value[0] < PDM_FILTER_DELAY_MS_MIN) || (ucontrol->value.integer.value[0] > PDM_FILTER_DELAY_MS_MAX)) @@ -577,12 +590,23 @@ static SOC_ENUM_SINGLE_DECL(rpath2_enum, PDM_CLK_CTRL, 12, rpaths_text); static SOC_ENUM_SINGLE_DECL(rpath1_enum, PDM_CLK_CTRL, 10, rpaths_text); static SOC_ENUM_SINGLE_DECL(rpath0_enum, PDM_CLK_CTRL, 8, rpaths_text); +static const char * const hpf_cutoff_text[] = { + "3.79Hz", "60Hz", "243Hz", "493Hz", +}; + +static SOC_ENUM_SINGLE_DECL(hpf_cutoff_enum, PDM_HPF_CTRL, + 0, hpf_cutoff_text); + static const struct snd_kcontrol_new rockchip_pdm_controls[] = { SOC_ENUM("Receive PATH3 Source Select", rpath3_enum), SOC_ENUM("Receive PATH2 Source Select", rpath2_enum), SOC_ENUM("Receive PATH1 Source Select", rpath1_enum), SOC_ENUM("Receive PATH0 Source Select", rpath0_enum), + SOC_ENUM("HPF Cutoff", hpf_cutoff_enum), + SOC_SINGLE("HPFL Switch", PDM_HPF_CTRL, 3, 1, 0), + SOC_SINGLE("HPFR Switch", PDM_HPF_CTRL, 2, 1, 0), + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "PDM Start Delay Ms", @@ -616,8 +640,8 @@ static int rockchip_pdm_clk_compensation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = pdm->clk_ppm; @@ -627,8 +651,8 @@ static int rockchip_pdm_clk_compensation_get(struct snd_kcontrol *kcontrol, static int rockchip_pdm_clk_compensation_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); int ppm = ucontrol->value.integer.value[0]; @@ -947,6 +971,29 @@ static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *n return 0; } +static int rockchip_pdm_keep_clk_always_on(struct rk_pdm_dev *pdm) +{ + pm_runtime_forbid(pdm->dev); + + dev_info(pdm->dev, "CLK-ALWAYS-ON: samplerate: %d\n", PDM_DEFAULT_RATE); + + return 0; +} + +static int rockchip_pdm_parse_quirks(struct rk_pdm_dev *pdm) +{ + int ret = 0, i = 0; + + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) + if (device_property_read_bool(pdm->dev, of_quirks[i].quirk)) + pdm->quirks |= of_quirks[i].id; + + if (pdm->quirks & QUIRK_ALWAYS_ON) + ret = rockchip_pdm_keep_clk_always_on(pdm); + + return ret; +} + static int rockchip_pdm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -1028,6 +1075,10 @@ static int rockchip_pdm_probe(struct platform_device *pdev) if (ret != 0 && ret != -ENOENT) goto err_clk; + ret = rockchip_pdm_parse_quirks(pdm); + if (ret) + goto err_clk; + /* * MUST: after pm_runtime_enable step, any register R/W * should be wrapped with pm_runtime_get_sync/put. diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 0d2136a6a808..8faad87458ce 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -19,10 +19,11 @@ #include #include "rockchip_sai.h" +#include "rockchip_dlp_pcm.h" #define DRV_NAME "rockchip-sai" -#define CLK_SHIFT_RATE_HZ_MAX 1 /* 1 Hz */ +#define CLK_SHIFT_RATE_HZ_MAX 5 #define FW_RATIO_MAX 8 #define FW_RATIO_MIN 1 #define MAXBURST_PER_FIFO 8 @@ -422,7 +423,7 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, { struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai); struct snd_dmaengine_dai_dma_data *dma_data; - unsigned int mclk_rate, bclk_rate, div_bclk; + unsigned int mclk_rate, mclk_req_rate, bclk_rate, div_bclk; unsigned int ch_per_lane, lanes, slot_width; unsigned int val, fscr, reg; @@ -497,15 +498,16 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, if (sai->is_clk_auto) clk_set_rate(sai->mclk, bclk_rate); mclk_rate = clk_get_rate(sai->mclk); - if (mclk_rate < bclk_rate - CLK_SHIFT_RATE_HZ_MAX || - mclk_rate > bclk_rate + CLK_SHIFT_RATE_HZ_MAX) { + div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); + mclk_req_rate = bclk_rate * div_bclk; + + if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX || + mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) { dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n", - mclk_rate, bclk_rate, CLK_SHIFT_RATE_HZ_MAX); + mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX); return -EINVAL; } - div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); - regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK, SAI_CKR_MDIV(div_bclk)); } @@ -1345,6 +1347,29 @@ static int rockchip_sai_parse_quirks(struct rk_sai_dev *sai) return ret; } +static int rockchip_sai_get_fifo_count(struct device *dev, + struct snd_pcm_substream *substream) +{ + struct rk_sai_dev *sai = dev_get_drvdata(dev); + int val = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + regmap_read(sai->regmap, SAI_TXFIFOLR, &val); + else + regmap_read(sai->regmap, SAI_RXFIFOLR, &val); + + val = ((val & SAI_FIFOLR_XFL3_MASK) >> SAI_FIFOLR_XFL3_SHIFT) + + ((val & SAI_FIFOLR_XFL2_MASK) >> SAI_FIFOLR_XFL2_SHIFT) + + ((val & SAI_FIFOLR_XFL1_MASK) >> SAI_FIFOLR_XFL1_SHIFT) + + ((val & SAI_FIFOLR_XFL0_MASK) >> SAI_FIFOLR_XFL0_SHIFT); + + return val; +} + +static const struct snd_dlp_config dconfig = { + .get_fifo_count = rockchip_sai_get_fifo_count, +}; + static int rockchip_sai_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -1439,7 +1464,11 @@ static int rockchip_sai_probe(struct platform_device *pdev) return 0; } - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (device_property_read_bool(&pdev->dev, "rockchip,digital-loopback")) + ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig); + else + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) goto err_runtime_suspend; diff --git a/sound/soc/rockchip/rockchip_sai.h b/sound/soc/rockchip/rockchip_sai.h index c720fc836521..82288185d64f 100644 --- a/sound/soc/rockchip/rockchip_sai.h +++ b/sound/soc/rockchip/rockchip_sai.h @@ -120,6 +120,16 @@ #define SAI_XSHIFT_SEL_MASK GENMASK(23, 0) #define SAI_XSHIFT_SEL(x) (x) +/* XFIFOLR: Transfer / Receive FIFO Level Register */ +#define SAI_FIFOLR_XFL3_SHIFT 18 +#define SAI_FIFOLR_XFL3_MASK GENMASK(23, 18) +#define SAI_FIFOLR_XFL2_SHIFT 12 +#define SAI_FIFOLR_XFL2_MASK GENMASK(17, 12) +#define SAI_FIFOLR_XFL1_SHIFT 6 +#define SAI_FIFOLR_XFL1_MASK GENMASK(11, 6) +#define SAI_FIFOLR_XFL0_SHIFT 0 +#define SAI_FIFOLR_XFL0_MASK GENMASK(5, 0) + /* SAI Registers */ #define SAI_TXCR (0x0000) #define SAI_FSCR (0x0004)