Merge tag 'android-12.1-mid-rkr12'

Android 12.1 Mid release rkr12;aosp:refs/tags/android-12.1.0_r11

* tag 'android-12.1-mid-rkr12': (48 commits)
  mmc: sdhci-of-dwcmshc: improve HS400ES compatibility for some eMMC devices
  video: rockchip: mpp: Fix mmu sharing on multi device
  ASoC: codecs: Add driver support for rk730
  soc: rockchip: power-domain: Add new keepon_startup module parameter
  video: rockchip: rga3: remove useless functions in rga_job.c
  PCI: rockchip: dw: Support applications that do not perform phy operations
  dma-buf: heaps: sram_heap: init sram-heap depend on sram driver
  UPSTREAM: drm: log errors in drm_gem_fb_init_with_funcs
  arm64: dts: rockchip: rk3588-nvr: add dp sound support
  media: rockchip: ispp: fec add compat_ioctl32
  media: rockchip: isp: fix stream switch when readback mode
  media: rockchip: isp: frame start to update buf for isp30
  media: rockchip: isp: fix fbc output for isp30 multi sensor
  Revert "drm/bridge: analogix_dp: Fix sync polarity configuration in msa packet"
  ASoC: rockchip: i2s-tdm: Add support for platform shutdown
  ARM: dts: rockchip: add rv1106g-evb-v11-spi-nand-cvr.dts
  media: i2c: update hi556 sensor driver
  ARM: dts: rockchip: add rv1103g-evb-v11.dts
  ARM: dts: rockchip: rv1106-evb: Add adc-key
  ARM: rv1106-evb.config: enable CONFIG_KEYBOARD_ADC
  ...

Change-Id: I081d6b895e0bf7ccce1dec335956f152bbc2bbd9
This commit is contained in:
Tao Huang
2022-11-14 19:46:58 +08:00
70 changed files with 3998 additions and 1118 deletions

View File

@@ -975,6 +975,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rv1103g-battery-ipc-v10.dtb \
rv1103g-battery-ipc-v11.dtb \
rv1103g-evb-v10.dtb \
rv1103g-evb-v11.dtb \
rv1103g-rmsl311-dloc-sl-v10.dtb \
rv1103g-scaner-v10.dtb \
rv1106g-38x38-ipc-v10.dtb \
@@ -983,6 +984,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rv1106g-evb1-rgb-display-v11.dtb \
rv1106g-evb1-v10.dtb \
rv1106g-evb1-v11.dtb \
rv1106g-evb1-v11-cvr.dtb \
rv1106g-evb1-v11-spi-nand-cvr.dtb \
rv1106g-evb1-v11-sii902x-bt11202hdmi.dtb \
rv1106g-evb1-v11-sii902x-rgb2hdmi.dtb \
rv1106g-evb1-v10-dual-cam.dtb \

View File

@@ -670,12 +670,12 @@
compatible = "rockchip,rk3128-mipi-dsi";
reg = <0x10110000 0x4000>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_MIPI>, <&cru HCLK_VIO_H2P>, <&video_phy>;
clock-names = "pclk", "h2p", "hs_clk";
clocks = <&cru PCLK_MIPI>, <&cru HCLK_VIO_H2P>;
clock-names = "pclk", "hclk";
resets = <&cru SRST_VIO_MIPI_DSI>;
reset-names = "apb";
phys = <&video_phy>;
phy-names = "mipi_dphy";
phy-names = "dphy";
power-domains = <&power RK3128_PD_VIO>;
rockchip,grf = <&grf>;
#address-cells = <1>;
@@ -996,14 +996,15 @@
};
video_phy: video-phy@20038000 {
compatible = "rockchip,rk3128-video-phy";
compatible = "rockchip,rk3128-dsi-dphy", "rockchip,rk3128-video-phy";
reg = <0x20038000 0x4000>, <0x10110000 0x4000>;
reg-names = "phy", "host";
clocks = <&cru SCLK_MIPI_24M>, <&cru PCLK_MIPIPHY>,
<&cru PCLK_MIPI>;
clock-names = "ref", "pclk_phy", "pclk_host";
clock-names = "ref", "pclk", "pclk_host";
#clock-cells = <0>;
resets = <&cru SRST_MIPIPHY_P>;
reset-names = "rst";
reset-names = "apb";
power-domains = <&power RK3128_PD_VIO>;
#phy-cells = <0>;
status = "disabled";

View File

@@ -0,0 +1,83 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1103.dtsi"
#include "rv1103-evb-v10.dtsi"
#include "rv1103-evb-cam.dtsi"
/ {
model = "Rockchip RV1103G EVB V11 Board";
compatible = "rockchip,rv1103g-evb-v11", "rockchip,rv1103";
vcc_1v8: vcc-1v8 {
compatible = "regulator-fixed";
regulator-name = "vcc_1v8";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vcc_3v3: vcc-3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc_3v3";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
vcc3v3_sd: vcc3v3-sd {
compatible = "regulator-fixed";
gpio = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>;
regulator-name = "vcc3v3_sd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
enable-active-low;
regulator-always-on;
regulator-boot-on;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_pwren>;
};
vcc3v3_wifi: vcc3v3-wifi {
compatible = "regulator-fixed";
regulator-name = "vcc3v3_wifi";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
enable-active-low;
regulator-always-on;
regulator-boot-on;
gpio = <&gpio1 RK_PC7 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&wifi_pwren>;
};
};
&pinctrl {
sdmmc {
/omit-if-no-ref/
sdmmc_pwren: sdmmc-pwren {
rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
wifi {
wifi_pwren: wifi-pwren {
rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
&saradc {
status = "okay";
vref-supply = <&vcc_1v8>;
};
&usbdrd_dwc3 {
dr_mode = "host";
};

View File

@@ -3,9 +3,28 @@
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
#include "rv1106-amp.dtsi"
#include <dt-bindings/input/input.h>
/ {
adc-keys {
compatible = "adc-keys";
io-channels = <&saradc 0>;
io-channel-names = "buttons";
poll-interval = <100>;
keyup-threshold-microvolt = <1800000>;
key_volumeup-key {
label = "key_volumeup";
linux,code = <KEY_VOLUMEUP>;
press-threshold-microvolt = <0>;
};
key_volumedown-key {
label = "key_volumedown";
linux,code = <KEY_VOLUMEDOWN>;
press-threshold-microvolt = <400781>;
};
};
};
&fiq_debugger {

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106g-evb1-v11.dts"
#include "rv1106-evb-ext-rgb-v10.dtsi"
/ {
model = "Rockchip RV1106G EVB1 V11 Board For CVR";
compatible = "rockchip,rv1106g-evb1-v11-cvr", "rockchip,rv1106";
};
&saradc {
status = "okay";
vref-supply = <&vcc_1v8>;
};

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106g-evb1-v10-spi-nand.dts"
#include "rv1106-evb-ext-rgb-v10.dtsi"
/ {
model = "Rockchip RV1106G EVB1 V11 Board For CVR";
compatible = "rockchip,rv1106g-evb1-v11-spi-nand-cvr", "rockchip,rv1106";
};
&saradc {
status = "okay";
vref-supply = <&vcc_1v8>;
};

View File

@@ -254,8 +254,6 @@ CONFIG_PINCTRL_RK805=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_GENERIC_PLATFORM=y
CONFIG_GPIO_TPS65910=y
CONFIG_POWER_AVS=y
CONFIG_ROCKCHIP_IODOMAIN=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO_RESTART=y
CONFIG_SYSCON_REBOOT_MODE=y
@@ -438,15 +436,22 @@ CONFIG_ROCKCHIP_IOMMU=y
CONFIG_CPU_RK312X=y
CONFIG_CPU_RK3288=y
CONFIG_CPU_RK322X=y
CONFIG_ROCKCHIP_CPUINFO=y
CONFIG_ROCKCHIP_GRF=y
CONFIG_ROCKCHIP_IODOMAIN=y
CONFIG_ROCKCHIP_IPA=y
CONFIG_ROCKCHIP_OPP=y
CONFIG_ROCKCHIP_PM_DOMAINS=y
CONFIG_ROCKCHIP_PVTM=y
CONFIG_ROCKCHIP_SUSPEND_MODE=y
CONFIG_ROCKCHIP_SYSTEM_MONITOR=y
CONFIG_ROCKCHIP_VENDOR_STORAGE_UPDATE_LOADER=y
CONFIG_PM_DEVFREQ=y
CONFIG_DEVFREQ_GOV_PERFORMANCE=y
CONFIG_DEVFREQ_GOV_POWERSAVE=y
CONFIG_DEVFREQ_GOV_USERSPACE=y
CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ=y
CONFIG_EXTCON=y
CONFIG_MEMORY=y
CONFIG_IIO=y
CONFIG_IIO_BUFFER=y
@@ -462,8 +467,7 @@ CONFIG_PWM_ROCKCHIP=y
CONFIG_PHY_ROCKCHIP_DP=y
CONFIG_PHY_ROCKCHIP_INNO_HDMI=y
CONFIG_PHY_ROCKCHIP_INNO_USB2=y
CONFIG_PHY_ROCKCHIP_INNO_VIDEO_COMBO_PHY=y
CONFIG_PHY_ROCKCHIP_INNO_VIDEO_PHY=y
CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=y
CONFIG_PHY_ROCKCHIP_USB=y
CONFIG_ANDROID=y
CONFIG_ROCKCHIP_EFUSE=y

View File

@@ -12,6 +12,7 @@ CONFIG_FB=y
CONFIG_FILE_LOCKING=y
CONFIG_I2C_GPIO=y
CONFIG_I2C_MUX=y
CONFIG_INPUT=y
CONFIG_IPV6=m
CONFIG_JFFS2_FS=y
CONFIG_KCMP=y
@@ -374,6 +375,7 @@ CONFIG_DRM_SII902X=y
# CONFIG_EXT4_FS_SECURITY is not set
CONFIG_EXT4_USE_FOR_EXT2=y
# CONFIG_EXTCON_ADC_JACK is not set
# CONFIG_EXTCON_FSA9480 is not set
# CONFIG_EXTCON_GPIO is not set
# CONFIG_EXTCON_MAX3355 is not set
# CONFIG_EXTCON_PTN5150 is not set
@@ -425,12 +427,15 @@ CONFIG_FS_POSIX_ACL=y
CONFIG_GRACE_PERIOD=y
CONFIG_HDMI=y
# CONFIG_HI8435 is not set
# CONFIG_HID is not set
# CONFIG_HID_PID is not set
# CONFIG_HISI_HIKEY_USB is not set
CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
# CONFIG_I2C_DEMUX_PINCTRL is not set
# CONFIG_I2C_DIOLAN_U2C is not set
# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set
# CONFIG_I2C_HID is not set
# CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_GPMUX is not set
# CONFIG_I2C_MUX_LTC4306 is not set
@@ -446,6 +451,20 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
# CONFIG_INFINEON_DHD is not set
# CONFIG_INPUT_EVBUG is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_JOYSTICK is not set
CONFIG_INPUT_KEYBOARD=y
# CONFIG_INPUT_MATRIXKMAP is not set
# CONFIG_INPUT_MISC is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_POLLDEV is not set
# CONFIG_INPUT_SPARSEKMAP is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INV_ICM42600_SPI is not set
# CONFIG_INV_MPU6050_SPI is not set
# CONFIG_IPV6_MIP6 is not set
@@ -475,6 +494,33 @@ CONFIG_JFFS2_FS_WRITEBUFFER=y
# CONFIG_JFFS2_RUBIN is not set
# CONFIG_JFFS2_SUMMARY is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_KEYBOARD_ADC=y
# CONFIG_KEYBOARD_ADP5588 is not set
# CONFIG_KEYBOARD_ADP5589 is not set
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_KEYBOARD_BCM is not set
# CONFIG_KEYBOARD_CAP11XX is not set
# CONFIG_KEYBOARD_DLINK_DIR685 is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_KEYBOARD_GPIO_POLLED is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_LM8333 is not set
# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_MCS is not set
# CONFIG_KEYBOARD_MPR121 is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_OMAP4 is not set
# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_QT1050 is not set
# CONFIG_KEYBOARD_QT1070 is not set
# CONFIG_KEYBOARD_QT2160 is not set
# CONFIG_KEYBOARD_SAMSUNG is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_TCA6416 is not set
# CONFIG_KEYBOARD_TCA8418 is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYS_REQUEST_CACHE is not set
# CONFIG_KEY_DH_OPERATIONS is not set
# CONFIG_KS7010 is not set
@@ -603,9 +649,11 @@ CONFIG_PKCS7_MESSAGE_PARSER=y
CONFIG_PWRSEQ_SIMPLE=y
# CONFIG_R8188EU is not set
# CONFIG_R8712U is not set
# CONFIG_RC_CORE is not set
CONFIG_REGMAP_SPI=y
# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set
# CONFIG_REGULATOR_TPS6524X is not set
# CONFIG_RMI4_CORE is not set
# CONFIG_ROCKCHIP_ANALOGIX_DP is not set
# CONFIG_ROCKCHIP_CDN_DP is not set
# CONFIG_ROCKCHIP_DRM_CUBIC_LUT is not set
@@ -619,6 +667,7 @@ CONFIG_REGMAP_SPI=y
# CONFIG_ROCKCHIP_LVDS is not set
# CONFIG_ROCKCHIP_MMC_VENDOR_STORAGE is not set
CONFIG_ROCKCHIP_MTD_VENDOR_STORAGE=y
# CONFIG_ROCKCHIP_REMOTECTL is not set
CONFIG_ROCKCHIP_RGA_DEBUGGER=y
# CONFIG_ROCKCHIP_RGA_DEBUG_FS is not set
CONFIG_ROCKCHIP_RGB=y
@@ -651,16 +700,22 @@ CONFIG_ROCKCHIP_VOP=y
# CONFIG_SDIO_UART is not set
# CONFIG_SECONDARY_TRUSTED_KEYRING is not set
# CONFIG_SENSORS_HMC5843_SPI is not set
# CONFIG_SENSORS_LIS3_I2C is not set
# CONFIG_SENSORS_LIS3_SPI is not set
# CONFIG_SENSORS_RM3100_SPI is not set
# CONFIG_SENSOR_DEVICE is not set
# CONFIG_SERIAL_IFX6X60 is not set
# CONFIG_SERIAL_MAX3100 is not set
# CONFIG_SERIAL_MAX310X is not set
CONFIG_SGL_ALLOC=y
# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set
# CONFIG_SND_BCD2000 is not set
CONFIG_SND_JACK_INPUT_DEV=y
# CONFIG_SND_SOC_ADAU1761_SPI is not set
# CONFIG_SND_SOC_AK4104 is not set
# CONFIG_SND_SOC_CS4271_SPI is not set
# CONFIG_SND_SOC_CS42L52 is not set
# CONFIG_SND_SOC_CS42L56 is not set
# CONFIG_SND_SOC_ES8328_SPI is not set
# CONFIG_SND_SOC_PCM179X_SPI is not set
# CONFIG_SND_SOC_PCM186X_SPI is not set
@@ -673,6 +728,7 @@ CONFIG_SGL_ALLOC=y
# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set
# CONFIG_SND_SOC_WM8770 is not set
# CONFIG_SND_SOC_WM8804_SPI is not set
# CONFIG_SND_SOC_WM8962 is not set
# CONFIG_SND_SOC_ZL38060 is not set
# CONFIG_SND_SPI is not set
CONFIG_SND_USB=y
@@ -842,6 +898,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=2
# CONFIG_USB_G_SERIAL is not set
# CONFIG_USB_G_WEBCAM is not set
# CONFIG_USB_HCD_TEST_MODE is not set
# CONFIG_USB_HID is not set
# CONFIG_USB_HSIC_USB3503 is not set
# CONFIG_USB_HSIC_USB4604 is not set
# CONFIG_USB_HUB_USB251XB is not set
@@ -851,6 +908,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=2
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1301 is not set
# CONFIG_USB_ISP1760 is not set
# CONFIG_USB_KBD is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_LEGOTOWER is not set
@@ -863,6 +921,7 @@ CONFIG_USB_LIBCOMPOSITE=y
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_MON is not set
# CONFIG_USB_MOUSE is not set
# CONFIG_USB_MUSB_HDRC is not set
# CONFIG_USB_MV_U3D is not set
# CONFIG_USB_MV_UDC is not set

View File

@@ -181,6 +181,10 @@
status = "okay";
};
&dp1_sound {
status = "okay";
};
&gmac0 {
/* Use rgmii-rxid mode to disable rx delay inside Soc */
phy-mode = "rgmii-rxid";
@@ -678,6 +682,10 @@
status = "okay";
};
&spdif_tx5 {
status = "okay";
};
&pinctrl {
dp {
dp1_hdmi_ctl: dp-hdmi-ctl {

View File

@@ -26,6 +26,10 @@
status = "okay";
};
&dp0_sound {
status = "okay";
};
&dp1 {
pinctrl-0 = <&dp1m2_pins &dp1_hdmi_reset>;
pinctrl-names = "default";
@@ -193,6 +197,10 @@
};
};
&spdif_tx2 {
status = "okay";
};
&pinctrl {
dp {
dp1_hdmi_reset: dp-hdmi-reset {

View File

@@ -28,6 +28,26 @@
};
};
dp0_sound: dp0-sound {
status = "disabled";
compatible = "rockchip,hdmi";
rockchip,card-name= "rockchip,dp0";
rockchip,mclk-fs = <512>;
rockchip,cpu = <&spdif_tx2>;
rockchip,codec = <&dp0 1>;
rockchip,jack-det;
};
dp1_sound: dp1-sound {
status = "disabled";
compatible = "rockchip,hdmi";
rockchip,card-name= "rockchip,dp1";
rockchip,mclk-fs = <512>;
rockchip,cpu = <&spdif_tx5>;
rockchip,codec = <&dp1 1>;
rockchip,jack-det;
};
hdmi0_sound: hdmi0-sound {
status = "disabled";
compatible = "simple-audio-card";

View File

@@ -534,7 +534,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
GATE(PCLK_ACODEC, "pclk_acodec", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
GATE(0, "pclk_ddrupctl", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 7, GFLAGS),
GATE(0, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS),
GATE(0, "pclk_mipiphy", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 0, GFLAGS),
GATE(PCLK_MIPIPHY, "pclk_mipiphy", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 0, GFLAGS),
GATE(0, "pclk_pmu", "pclk_pmu_pre", CLK_IS_CRITICAL, RK2928_CLKGATE_CON(9), 2, GFLAGS),
GATE(0, "pclk_pmu_niu", "pclk_pmu_pre", CLK_IS_CRITICAL, RK2928_CLKGATE_CON(9), 3, GFLAGS),

View File

@@ -958,7 +958,7 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
COMPOSITE_NODIV(HCLK_USB, "hclk_usb", gpll150_gpll100_gpll75_xin24m_p, CLK_IS_CRITICAL,
RK3568_CLKSEL_CON(32), 2, 2, MFLAGS,
RK3568_CLKGATE_CON(16), 1, GFLAGS),
COMPOSITE_NOMUX(PCLK_USB, "pclk_usb", "aclk_usb", 0,
COMPOSITE_NOMUX(PCLK_USB, "pclk_usb", "aclk_usb", CLK_IS_CRITICAL,
RK3568_CLKSEL_CON(32), 4, 4, DFLAGS,
RK3568_CLKGATE_CON(16), 2, GFLAGS),
GATE(HCLK_USB2HOST0, "hclk_usb2host0", "hclk_usb", 0,

View File

@@ -1890,7 +1890,7 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
COMPOSITE(ACLK_VOP_ROOT, "aclk_vop_root", gpll_cpll_dmyaupll_npll_spll_p, 0,
RK3588_CLKSEL_CON(110), 5, 3, MFLAGS, 0, 5, DFLAGS,
RK3588_CLKGATE_CON(52), 0, GFLAGS),
FACTOR(0, "aclk_vop_div2_src", "aclk_vop_root", 0, 1, 2),
FACTOR(ACLK_VOP_DIV2_SRC, "aclk_vop_div2_src", "aclk_vop_root", 0, 1, 2),
COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, 0,
RK3588_CLKSEL_CON(110), 8, 2, MFLAGS,
RK3588_CLKGATE_CON(52), 1, GFLAGS),
@@ -1906,8 +1906,9 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
COMPOSITE_NODIV(HCLK_VO1USB_TOP_ROOT, "hclk_vo1usb_top_root", mux_200m_100m_50m_24m_p, CLK_IS_CRITICAL,
RK3588_CLKSEL_CON(170), 6, 2, MFLAGS,
RK3588_CLKGATE_CON(74), 2, GFLAGS),
MUX(ACLK_VOP_SUB_SRC, "aclk_vop_sub_src", aclk_vop_sub_src_p, 0,
RK3588_CLKSEL_CON(115), 9, 1, MFLAGS),
COMPOSITE_NODIV(ACLK_VOP, "aclk_vop", aclk_vop_sub_src_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(115), 9, 1, MFLAGS,
RK3588_CLKGATE_CON(52), 9, GFLAGS),
GATE(PCLK_EDP0, "pclk_edp0", "pclk_vo1_root", 0,
RK3588_CLKGATE_CON(62), 0, GFLAGS),
GATE(CLK_EDP0_24M, "clk_edp0_24m", "xin24m", 0,
@@ -2064,8 +2065,6 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
RK3588_CLKGATE_CON(72), 4, GFLAGS),
GATE(HCLK_VOP, "hclk_vop", "hclk_vop_root", 0,
RK3588_CLKGATE_CON(52), 8, GFLAGS),
GATE(ACLK_VOP, "aclk_vop", "aclk_vop_sub_src", 0,
RK3588_CLKGATE_CON(52), 9, GFLAGS),
COMPOSITE(DCLK_VOP0_SRC, "dclk_vop0_src", gpll_cpll_v0pll_aupll_p, 0,
RK3588_CLKSEL_CON(111), 7, 2, MFLAGS, 0, 7, DFLAGS,
RK3588_CLKGATE_CON(52), 10, GFLAGS),

View File

@@ -22,3 +22,10 @@ config DMABUF_HEAPS_CMA
Choose this option to enable dma-buf CMA heap. This heap is backed
by the Contiguous Memory Allocator (CMA). If your system has these
regions, you should say Y here.
config DMABUF_HEAPS_SRAM
tristate "Export on-chip SRAM pools using DMA-Heaps"
depends on DMABUF_HEAPS && SRAM
help
This driver allows the export of on-chip SRAM marked as exportable
to userspace using the DMA-Heaps interface.

View File

@@ -3,3 +3,4 @@ obj-$(CONFIG_DMABUF_HEAPS_DEFERRED_FREE) += deferred-free-helper.o
obj-$(CONFIG_DMABUF_HEAPS_PAGE_POOL) += page_pool.o
obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += rk_system_heap.o
obj-$(CONFIG_DMABUF_HEAPS_CMA) += rk_cma_heap.o
obj-$(CONFIG_DMABUF_HEAPS_SRAM) += sram_heap.o

View File

@@ -0,0 +1,437 @@
// SPDX-License-Identifier: GPL-2.0
/*
* SRAM DMA-Heap exporter && support alloc page and dmabuf on kernel
*
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
*
* Author: Andrew F. Davis <afd@ti.com>
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*
* Author: Huang Lee <Putin.li@rock-chips.com>
*/
#define pr_fmt(fmt) "sram_heap: " fmt
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/dma-buf.h>
#include <linux/dma-heap.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/module.h>
#include <linux/sram_heap.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#define RK3588_SRAM_BASE 0xff001000
struct sram_dma_heap {
struct dma_heap *heap;
struct gen_pool *pool;
};
struct sram_dma_heap_buffer {
struct gen_pool *pool;
struct list_head attachments;
struct mutex attachments_lock;
unsigned long len;
void *vaddr;
phys_addr_t paddr;
};
struct dma_heap_attachment {
struct device *dev;
struct sg_table *table;
struct list_head list;
};
static int dma_heap_attach(struct dma_buf *dmabuf,
struct dma_buf_attachment *attachment)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
struct dma_heap_attachment *a;
struct sg_table *table;
a = kzalloc(sizeof(*a), GFP_KERNEL);
if (!a)
return -ENOMEM;
table = kmalloc(sizeof(*table), GFP_KERNEL);
if (!table)
goto table_alloc_failed;
if (sg_alloc_table(table, 1, GFP_KERNEL))
goto sg_alloc_failed;
/*
* The referenced pfn and page are for setting the sram address to the
* sgtable, and cannot be used for other purposes, and cannot be accessed
* directly or indirectly.
*
* And not sure if there is a problem with the 32-bit system.
*
* page cannot support kmap func.
*/
sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(buffer->paddr)), buffer->len, 0);
a->table = table;
a->dev = attachment->dev;
INIT_LIST_HEAD(&a->list);
attachment->priv = a;
mutex_lock(&buffer->attachments_lock);
list_add(&a->list, &buffer->attachments);
mutex_unlock(&buffer->attachments_lock);
return 0;
sg_alloc_failed:
kfree(table);
table_alloc_failed:
kfree(a);
return -ENOMEM;
}
static void dma_heap_detatch(struct dma_buf *dmabuf,
struct dma_buf_attachment *attachment)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
struct dma_heap_attachment *a = attachment->priv;
mutex_lock(&buffer->attachments_lock);
list_del(&a->list);
mutex_unlock(&buffer->attachments_lock);
sg_free_table(a->table);
kfree(a->table);
kfree(a);
}
static struct sg_table *dma_heap_map_dma_buf(struct dma_buf_attachment *attachment,
enum dma_data_direction direction)
{
struct dma_heap_attachment *a = attachment->priv;
struct sg_table *table = a->table;
int ret = 0;
ret = dma_map_sgtable(attachment->dev, table, direction, DMA_ATTR_SKIP_CPU_SYNC);
if (ret)
return ERR_PTR(-ENOMEM);
return table;
}
static void dma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment,
struct sg_table *table,
enum dma_data_direction direction)
{
dma_unmap_sgtable(attachment->dev, table, direction, DMA_ATTR_SKIP_CPU_SYNC);
}
static void dma_heap_dma_buf_release(struct dma_buf *dmabuf)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
gen_pool_free(buffer->pool, (unsigned long)buffer->vaddr, buffer->len);
kfree(buffer);
}
static int dma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
int ret;
/* SRAM mappings are not cached */
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
ret = vm_iomap_memory(vma, buffer->paddr, buffer->len);
if (ret)
pr_err("Could not map buffer to userspace\n");
return ret;
}
static void *dma_heap_vmap(struct dma_buf *dmabuf)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
return buffer->vaddr;
}
static const struct dma_buf_ops sram_dma_heap_buf_ops = {
.attach = dma_heap_attach,
.detach = dma_heap_detatch,
.map_dma_buf = dma_heap_map_dma_buf,
.unmap_dma_buf = dma_heap_unmap_dma_buf,
.release = dma_heap_dma_buf_release,
.mmap = dma_heap_mmap,
.vmap = dma_heap_vmap,
};
static struct dma_buf *sram_dma_heap_allocate(struct dma_heap *heap,
unsigned long len,
unsigned long fd_flags,
unsigned long heap_flags)
{
struct sram_dma_heap *sram_dma_heap = dma_heap_get_drvdata(heap);
struct sram_dma_heap_buffer *buffer;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct dma_buf *dmabuf;
int ret = -ENOMEM;
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
buffer->pool = sram_dma_heap->pool;
INIT_LIST_HEAD(&buffer->attachments);
mutex_init(&buffer->attachments_lock);
buffer->len = len;
buffer->vaddr = (void *)gen_pool_alloc(buffer->pool, buffer->len);
if (!buffer->vaddr) {
ret = -ENOMEM;
goto free_buffer;
}
buffer->paddr = gen_pool_virt_to_phys(buffer->pool, (unsigned long)buffer->vaddr);
if (buffer->paddr == -1) {
ret = -ENOMEM;
goto free_pool;
}
/* create the dmabuf */
exp_info.ops = &sram_dma_heap_buf_ops;
exp_info.size = buffer->len;
exp_info.flags = fd_flags;
exp_info.priv = buffer;
dmabuf = dma_buf_export(&exp_info);
if (IS_ERR(dmabuf)) {
ret = PTR_ERR(dmabuf);
goto free_pool;
}
return dmabuf;
free_pool:
gen_pool_free(buffer->pool, (unsigned long)buffer->vaddr, buffer->len);
free_buffer:
kfree(buffer);
return ERR_PTR(ret);
}
static struct dma_heap_ops sram_dma_heap_ops = {
.allocate = sram_dma_heap_allocate,
};
static struct sram_dma_heap *sram_dma_heap_global;
static int sram_dma_heap_export(const char *name,
struct gen_pool *sram_gp)
{
struct sram_dma_heap *sram_dma_heap;
struct dma_heap_export_info exp_info;
pr_info("Exporting SRAM pool '%s'\n", name);
sram_dma_heap = kzalloc(sizeof(*sram_dma_heap), GFP_KERNEL);
if (!sram_dma_heap)
return -ENOMEM;
sram_dma_heap->pool = sram_gp;
exp_info.name = "sram_dma_heap";
exp_info.ops = &sram_dma_heap_ops;
exp_info.priv = sram_dma_heap;
sram_dma_heap_global = sram_dma_heap;
sram_dma_heap->heap = dma_heap_add(&exp_info);
if (IS_ERR(sram_dma_heap->heap)) {
int ret = PTR_ERR(sram_dma_heap->heap);
kfree(sram_dma_heap);
return ret;
}
return 0;
}
struct dma_buf *sram_heap_alloc_dma_buf(size_t size)
{
struct sram_dma_heap *sram_dma_heap = sram_dma_heap_global;
struct sram_dma_heap_buffer *buffer;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct dma_buf *dmabuf;
int ret = -ENOMEM;
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
buffer->pool = sram_dma_heap->pool;
INIT_LIST_HEAD(&buffer->attachments);
mutex_init(&buffer->attachments_lock);
buffer->len = size;
buffer->vaddr = (void *)gen_pool_alloc(buffer->pool, buffer->len);
if (!buffer->vaddr) {
ret = -ENOMEM;
goto free_buffer;
}
buffer->paddr = gen_pool_virt_to_phys(buffer->pool, (unsigned long)buffer->vaddr);
if (buffer->paddr == -1) {
ret = -ENOMEM;
goto free_pool;
}
/* create the dmabuf */
exp_info.ops = &sram_dma_heap_buf_ops;
exp_info.size = buffer->len;
exp_info.priv = buffer;
dmabuf = dma_buf_export(&exp_info);
if (IS_ERR(dmabuf)) {
ret = PTR_ERR(dmabuf);
goto free_pool;
}
return dmabuf;
free_pool:
gen_pool_free(buffer->pool, (unsigned long)buffer->vaddr, buffer->len);
free_buffer:
kfree(buffer);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(sram_heap_alloc_dma_buf);
struct page *sram_heap_alloc_pages(size_t size)
{
struct sram_dma_heap *sram_dma_heap = sram_dma_heap_global;
void *vaddr;
phys_addr_t paddr;
struct page *p;
int ret = -ENOMEM;
vaddr = (void *)gen_pool_alloc(sram_dma_heap->pool, size);
if (!vaddr) {
ret = -ENOMEM;
pr_err("no memory");
goto failed;
}
paddr = gen_pool_virt_to_phys(sram_dma_heap->pool, (unsigned long)vaddr);
if (paddr == -1) {
ret = -ENOMEM;
pr_err("gen_pool_virt_to_phys failed");
goto free_pool;
}
p = pfn_to_page(PFN_DOWN(paddr));
return p;
free_pool:
gen_pool_free(sram_dma_heap->pool, (unsigned long)vaddr, size);
failed:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(sram_heap_alloc_pages);
static u64 gen_pool_phys_to_virt(struct gen_pool *pool, phys_addr_t paddr)
{
struct gen_pool_chunk *chunk;
u64 vaddr = 0;
rcu_read_lock();
list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
/* TODO: only suit for simple chunk now */
vaddr = chunk->start_addr + (paddr - chunk->phys_addr);
}
rcu_read_unlock();
return vaddr;
}
void sram_heap_free_pages(struct page *p)
{
struct sram_dma_heap *sram_dma_heap = sram_dma_heap_global;
void *vaddr;
vaddr = (void *)gen_pool_phys_to_virt(sram_dma_heap->pool, page_to_phys(p));
gen_pool_free(sram_dma_heap->pool, (unsigned long)vaddr, PAGE_SIZE);
}
EXPORT_SYMBOL_GPL(sram_heap_free_pages);
void sram_heap_free_dma_buf(struct dma_buf *dmabuf)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
gen_pool_free(buffer->pool, (unsigned long)buffer->vaddr, buffer->len);
kfree(buffer);
}
EXPORT_SYMBOL_GPL(sram_heap_free_dma_buf);
void *sram_heap_get_vaddr(struct dma_buf *dmabuf)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
return buffer->vaddr;
}
EXPORT_SYMBOL_GPL(sram_heap_get_vaddr);
phys_addr_t sram_heap_get_paddr(struct dma_buf *dmabuf)
{
struct sram_dma_heap_buffer *buffer = dmabuf->priv;
return buffer->paddr;
}
EXPORT_SYMBOL_GPL(sram_heap_get_paddr);
static int rk_add_default_sram_heap(void)
{
struct device_node *np = NULL;
struct gen_pool *sram_gp = NULL;
int ret = 0;
np = of_find_compatible_node(NULL, NULL, "rockchip,sram-heap");
if (!np) {
pr_info("failed to get device node of sram-heap\n");
return -ENODEV;
}
if (!of_device_is_available(np)) {
of_node_put(np);
return ret;
}
sram_gp = of_gen_pool_get(np, "rockchip,sram", 0);
/* release node */
of_node_put(np);
if (sram_gp == NULL) {
pr_err("sram gen pool is NULL");
return -ENOMEM;
}
ret = sram_dma_heap_export("sram-heap", sram_gp);
return ret;
}
module_init(rk_add_default_sram_heap);
MODULE_DESCRIPTION("Rockchip DMA-BUF SRAM Heap");
MODULE_LICENSE("GPL");

View File

@@ -1785,8 +1785,13 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
/* Input video interlaces & hsync pol & vsync pol */
video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
if (dp->plat_data->dev_type == RK3588_EDP) {
video->v_sync_polarity = true;
video->h_sync_polarity = true;
} else {
video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
}
/* Input video dynamic_range & colorimetry */
vic = drm_match_cea_mode(mode);

View File

@@ -255,6 +255,8 @@ struct dw_hdmi_qp {
bool allm_enable;
bool support_hdmi;
int force_output;
int vp_id;
int old_vp_id;
struct mutex mutex; /* for state below and previous_mode */
struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */
@@ -2262,13 +2264,23 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
struct drm_connector_state *new_state =
drm_atomic_get_new_connector_state(state, connector);
struct drm_crtc *crtc = new_state->crtc;
struct drm_crtc_state *crtc_state;
struct drm_crtc *old_crtc = old_state->crtc;
struct drm_crtc_state *crtc_state, *old_crtc_state;
struct dw_hdmi_qp *hdmi =
container_of(connector, struct dw_hdmi_qp, connector);
struct drm_display_mode *mode = NULL;
void *data = hdmi->plat_data->phy_data;
struct hdmi_vmode_qp *vmode = &hdmi->hdmi_data.video_mode;
if (old_crtc) {
old_crtc_state = drm_atomic_get_crtc_state(state, old_crtc);
if (IS_ERR(old_crtc_state))
return PTR_ERR(old_crtc_state);
if (hdmi->plat_data->get_vp_id)
hdmi->old_vp_id = hdmi->plat_data->get_vp_id(old_crtc_state);
}
if (!crtc)
return 0;
@@ -2276,6 +2288,9 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
if (hdmi->plat_data->get_vp_id)
hdmi->vp_id = hdmi->plat_data->get_vp_id(crtc_state);
mode = &crtc_state->mode;
/*
* If HDMI is enabled in uboot, it's need to record
@@ -2319,7 +2334,7 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
if (hdmi->initialized && !hdmi->dclk_en) {
mutex_lock(&hdmi->audio_mutex);
if (hdmi->plat_data->dclk_set)
hdmi->plat_data->dclk_set(data, true);
hdmi->plat_data->dclk_set(data, true, hdmi->vp_id);
hdmi->dclk_en = true;
mutex_unlock(&hdmi->audio_mutex);
hdmi->curr_conn = connector;
@@ -2500,7 +2515,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
if (hdmi->dclk_en) {
mutex_lock(&hdmi->audio_mutex);
if (hdmi->plat_data->dclk_set)
hdmi->plat_data->dclk_set(data, false);
hdmi->plat_data->dclk_set(data, false, hdmi->old_vp_id);
hdmi->dclk_en = false;
mutex_unlock(&hdmi->audio_mutex);
};
@@ -2542,7 +2557,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
if (!hdmi->dclk_en) {
mutex_lock(&hdmi->audio_mutex);
if (hdmi->plat_data->dclk_set)
hdmi->plat_data->dclk_set(data, true);
hdmi->plat_data->dclk_set(data, true, hdmi->vp_id);
hdmi->dclk_en = true;
mutex_unlock(&hdmi->audio_mutex);
}

View File

@@ -26,6 +26,8 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_print.h>
#define HWVER_131 0x31333100 /* IP version 1.31 */
@@ -239,8 +241,11 @@ struct debugfs_entries {
struct dw_mipi_dsi {
struct drm_bridge bridge;
struct drm_connector connector;
struct drm_encoder *encoder;
struct mipi_dsi_host dsi_host;
struct drm_bridge *panel_bridge;
struct drm_panel *panel;
struct drm_bridge *next_bridge;
struct device *dev;
void __iomem *base;
@@ -250,6 +255,7 @@ struct dw_mipi_dsi {
u32 channel;
u32 lanes;
u32 format;
struct drm_display_mode mode;
unsigned long mode_flags;
#ifdef CONFIG_DEBUG_FS
@@ -299,6 +305,11 @@ static inline struct dw_mipi_dsi *bridge_to_dsi(struct drm_bridge *bridge)
return container_of(bridge, struct dw_mipi_dsi, bridge);
}
static inline struct dw_mipi_dsi *con_to_dsi(struct drm_connector *con)
{
return container_of(con, struct dw_mipi_dsi, connector);
}
static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
{
writel(val, dsi->base + reg);
@@ -314,8 +325,6 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
{
struct dw_mipi_dsi *dsi = host_to_dsi(host);
const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
struct drm_bridge *bridge;
struct drm_panel *panel;
int max_data_lanes = dsi->plat_data->max_data_lanes;
int ret;
@@ -324,20 +333,13 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0,
&panel, &bridge);
if (ret)
ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, -1,
&dsi->panel, &dsi->next_bridge);
if (ret) {
DRM_DEV_ERROR(dsi->dev, "Failed to find panel or bridge: %d\n", ret);
return ret;
if (panel) {
bridge = drm_panel_bridge_add_typed(panel,
DRM_MODE_CONNECTOR_DSI);
if (IS_ERR(bridge))
return PTR_ERR(bridge);
}
dsi->panel_bridge = bridge;
drm_bridge_add(&dsi->bridge);
if (pdata->host_ops && pdata->host_ops->attach) {
@@ -602,6 +604,9 @@ static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_PWR_UP, RESET);
dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ);
pm_runtime_put(dsi->dev);
if (dsi->slave)
dw_mipi_dsi_disable(dsi->slave);
}
static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
@@ -855,31 +860,29 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_INT_MSK1, 0);
}
static void dw_mipi_dsi_post_disable(struct dw_mipi_dsi *dsi)
{
dw_mipi_dsi_set_mode(dsi, 0);
if (dsi->slave)
dw_mipi_dsi_set_mode(dsi->slave, 0);
}
static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
/*
* Switch to command mode before panel-bridge post_disable &
* panel unprepare.
* Note: panel-bridge disable & panel disable has been called
* before by the drm framework.
*/
dw_mipi_dsi_set_mode(dsi, 0);
if (dsi->slave)
dw_mipi_dsi_set_mode(dsi->slave, 0);
if (dsi->panel)
drm_panel_disable(dsi->panel);
/*
* TODO Only way found to call panel-bridge post_disable &
* panel unprepare before the dsi "final" disable...
* This needs to be fixed in the drm_bridge framework and the API
* needs to be updated to manage our own call chains...
*/
if (dsi->panel_bridge->funcs->post_disable)
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
dw_mipi_dsi_post_disable(dsi);
}
if (dsi->slave)
dw_mipi_dsi_disable(dsi->slave);
static void dw_mipi_dsi_bridge_disable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
if (dsi->panel)
drm_panel_unprepare(dsi->panel);
dw_mipi_dsi_disable(dsi);
}
@@ -898,11 +901,23 @@ static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi)
return dsi->lanes;
}
static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
const struct drm_display_mode *adjusted_mode)
static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
drm_mode_copy(&dsi->mode, adjusted_mode);
if (dsi->slave)
drm_mode_copy(&dsi->slave->mode, adjusted_mode);
}
static void dw_mipi_dsi_pre_enable(struct dw_mipi_dsi *dsi)
{
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
void *priv_data = dsi->plat_data->priv_data;
const struct drm_display_mode *adjusted_mode = &dsi->mode;
int ret;
u32 lanes = dw_mipi_dsi_get_lanes(dsi);
@@ -946,27 +961,23 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
/* Switch to cmd mode for panel-bridge pre_enable & panel prepare */
dw_mipi_dsi_set_mode(dsi, 0);
}
static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
dw_mipi_dsi_mode_set(dsi, adjusted_mode);
if (dsi->slave)
dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode);
DRM_DEV_INFO(dsi->dev, "final DSI-Link bandwidth: %u x %d Mbps\n",
dsi->lane_mbps, dsi->slave ? dsi->lanes * 2 : dsi->lanes);
dw_mipi_dsi_pre_enable(dsi->slave);
}
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
static void dw_mipi_dsi_bridge_pre_enable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
/* Switch to video/cmd mode for panel-bridge enable & panel enable */
dw_mipi_dsi_pre_enable(dsi);
if (dsi->panel)
drm_panel_prepare(dsi->panel);
}
static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi)
{
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
if (dsi->slave)
@@ -976,6 +987,22 @@ static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
if (dsi->slave)
dw_mipi_dsi_set_mode(dsi->slave, 0);
}
if (dsi->slave)
dw_mipi_dsi_enable(dsi->slave);
}
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
dw_mipi_dsi_enable(dsi);
if (dsi->panel)
drm_panel_enable(dsi->panel);
DRM_DEV_INFO(dsi->dev, "final DSI-Link bandwidth: %u x %d Mbps\n",
dsi->lane_mbps, dsi->slave ? dsi->lanes * 2 : dsi->lanes);
}
static enum drm_mode_status
@@ -1006,15 +1033,20 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
/* Set the encoder type as caller does not know it */
bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI;
/* Attach the panel-bridge to the dsi bridge */
return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge,
flags);
/* Attach the next-bridge to the dsi bridge */
if (dsi->next_bridge)
return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
bridge, flags);
return 0;
}
static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
.mode_set = dw_mipi_dsi_bridge_mode_set,
.pre_enable = dw_mipi_dsi_bridge_pre_enable,
.enable = dw_mipi_dsi_bridge_enable,
.post_disable = dw_mipi_dsi_bridge_post_disable,
.disable = dw_mipi_dsi_bridge_disable,
.mode_valid = dw_mipi_dsi_bridge_mode_valid,
.attach = dw_mipi_dsi_bridge_attach,
};
@@ -1209,6 +1241,81 @@ void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
}
EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
{
struct dw_mipi_dsi *dsi = con_to_dsi(connector);
if (dsi->next_bridge && (dsi->next_bridge->ops & DRM_BRIDGE_OP_MODES))
return drm_bridge_get_modes(dsi->next_bridge, connector);
if (dsi->panel)
return drm_panel_get_modes(dsi->panel, connector);
return -EINVAL;
}
static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
.get_modes = dw_mipi_dsi_connector_get_modes,
};
static enum drm_connector_status
dw_mipi_dsi_connector_detect(struct drm_connector *connector, bool force)
{
struct dw_mipi_dsi *dsi = con_to_dsi(connector);
if (dsi->next_bridge && (dsi->next_bridge->ops & DRM_BRIDGE_OP_DETECT))
return drm_bridge_detect(dsi->next_bridge);
return connector_status_connected;
}
static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = dw_mipi_dsi_connector_detect,
.destroy = dw_mipi_dsi_drm_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int dw_mipi_dsi_connector_init(struct dw_mipi_dsi *dsi)
{
struct drm_encoder *encoder = dsi->encoder;
struct drm_connector *connector = &dsi->connector;
struct drm_device *drm_dev = dsi->bridge.dev;
struct device *dev = dsi->dev;
int ret;
ret = drm_connector_init(drm_dev, connector,
&dw_mipi_dsi_atomic_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to initialize connector\n");
return ret;
}
drm_connector_helper_add(connector,
&dw_mipi_dsi_connector_helper_funcs);
ret = drm_connector_attach_encoder(connector, encoder);
if (ret < 0) {
DRM_DEV_ERROR(dev, "Failed to attach encoder: %d\n", ret);
goto connector_cleanup;
}
return 0;
connector_cleanup:
connector->funcs->destroy(connector);
return ret;
}
/*
* Bind/unbind API, used from platforms based on the component framework.
*/
@@ -1216,6 +1323,8 @@ int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder)
{
int ret;
dsi->encoder = encoder;
ret = drm_bridge_attach(encoder, &dsi->bridge, NULL, 0);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
@@ -1233,7 +1342,33 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind);
struct drm_connector *dw_mipi_dsi_get_connector(struct dw_mipi_dsi *dsi)
{
return drm_panel_bridge_connector(dsi->panel_bridge);
struct drm_connector *connector = NULL;
enum drm_bridge_attach_flags flags = 0;
int ret;
if (dsi->next_bridge) {
enum drm_bridge_attach_flags flags;
struct list_head *connector_list =
&dsi->next_bridge->dev->mode_config.connector_list;
flags = dsi->next_bridge->ops & DRM_BRIDGE_OP_MODES ?
DRM_BRIDGE_ATTACH_NO_CONNECTOR : 0;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
list_for_each_entry(connector, connector_list, head)
if (drm_connector_has_possible_encoder(connector,
dsi->encoder))
break;
}
if (dsi->panel || (dsi->next_bridge && (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))) {
ret = dw_mipi_dsi_connector_init(dsi);
if (ret)
return ERR_PTR(ret);
connector = &dsi->connector;
}
return connector;
}
EXPORT_SYMBOL_GPL(dw_mipi_dsi_get_connector);

View File

@@ -155,8 +155,10 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
int ret, i;
info = drm_get_format_info(dev, mode_cmd);
if (!info)
if (!info) {
drm_dbg_kms(dev, "Failed to get FB format info\n");
return -EINVAL;
}
for (i = 0; i < info->num_planes; i++) {
unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
@@ -175,6 +177,9 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
+ mode_cmd->offsets[i];
if (objs[i]->size < min_size) {
drm_dbg_kms(dev,
"GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
objs[i]->size, min_size, i);
drm_gem_object_put(objs[i]);
ret = -EINVAL;
goto err_gem_object_put;

View File

@@ -149,6 +149,11 @@
#define PX30_DSI_TURNDISABLE BIT(5)
#define PX30_DSI_LCDC_SEL BIT(0)
#define RK3128_GRF_LVDS_CON0 0x0150
#define RK3128_DSI_FORCETXSTOPMODE (0xf << 10)
#define RK3128_DSI_FORCERXMODE (0x1 << 9)
#define RK3128_DSI_TURNDISABLE (0x1 << 8)
#define RK3288_GRF_SOC_CON6 0x025c
#define RK3288_DSI0_LCDC_SEL BIT(6)
#define RK3288_DSI1_LCDC_SEL BIT(9)
@@ -213,6 +218,7 @@ enum {
enum soc_type {
PX30,
RK3128,
RK3288,
RK3399,
RK3568,
@@ -1283,6 +1289,21 @@ static const struct rockchip_dw_dsi_chip_data px30_chip_data[] = {
{ /* sentinel */ }
};
static const struct rockchip_dw_dsi_chip_data rk3128_chip_data[] = {
{
.reg = 0x10110000,
.lanecfg1_grf_reg = RK3128_GRF_LVDS_CON0,
.lanecfg1 = HIWORD_UPDATE(0, RK3128_DSI_TURNDISABLE |
RK3128_DSI_FORCETXSTOPMODE |
RK3128_DSI_FORCERXMODE),
.flags = DW_MIPI_NEEDS_HCLK,
.max_data_lanes = 4,
.max_bit_rate_per_lane = 1000000000UL,
.soc_type = RK3128,
},
{ /* sentinel */ }
};
static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
{
.reg = 0xff960000,
@@ -1407,6 +1428,9 @@ static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
{
.compatible = "rockchip,px30-mipi-dsi",
.data = &px30_chip_data,
}, {
.compatible = "rockchip,rk3128-mipi-dsi",
.data = &rk3128_chip_data,
}, {
.compatible = "rockchip,rk3288-mipi-dsi",
.data = &rk3288_chip_data,

View File

@@ -184,7 +184,6 @@ struct rockchip_hdmi {
unsigned long enc_out_encoding;
int color_changed;
int hpd_irq;
int vp_id;
struct drm_property *color_depth_property;
struct drm_property *hdmi_output_property;
@@ -2006,7 +2005,6 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
secondary:
drm_mode_copy(&mode, &crtc_state->mode);
hdmi->vp_id = s->vp_id;
if (hdmi->plat_data->split_mode)
drm_mode_convert_to_origin_mode(&mode);
@@ -2216,14 +2214,23 @@ struct dw_hdmi_link_config *dw_hdmi_rockchip_get_link_cfg(void *data)
return &hdmi->link_cfg;
}
static int dw_hdmi_dclk_set(void *data, bool enable)
static int dw_hdmi_rockchip_get_vp_id(struct drm_crtc_state *crtc_state)
{
struct rockchip_crtc_state *s;
s = to_rockchip_crtc_state(crtc_state);
return s->vp_id;
}
static int dw_hdmi_dclk_set(void *data, bool enable, int vp_id)
{
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
char clk_name[16];
struct clk *dclk;
int ret;
snprintf(clk_name, sizeof(clk_name), "dclk_vp%d", hdmi->vp_id);
snprintf(clk_name, sizeof(clk_name), "dclk_vp%d", vp_id);
dclk = devm_clk_get(hdmi->dev, clk_name);
if (IS_ERR(dclk)) {
@@ -2235,7 +2242,7 @@ static int dw_hdmi_dclk_set(void *data, bool enable)
ret = clk_prepare_enable(dclk);
if (ret < 0)
DRM_DEV_ERROR(hdmi->dev, "failed to enable dclk for video port%d - %d\n",
hdmi->vp_id, ret);
vp_id, ret);
} else {
clk_disable_unprepare(dclk);
}
@@ -3147,6 +3154,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
plat_data->convert_to_origin_mode = drm_mode_convert_to_origin_mode;
plat_data->dclk_set = dw_hdmi_dclk_set;
plat_data->link_clk_set = dw_hdmi_link_clk_set;
plat_data->get_vp_id = dw_hdmi_rockchip_get_vp_id;
plat_data->property_ops = &dw_hdmi_rockchip_property_ops;

View File

@@ -836,6 +836,7 @@ static int update_state(struct drm_device *drm_dev,
const struct drm_encoder_helper_funcs *encoder_helper_funcs;
const struct drm_connector_helper_funcs *connector_helper_funcs;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
connector_helper_funcs = connector->helper_private;
if (!connector_helper_funcs)
@@ -860,6 +861,9 @@ static int update_state(struct drm_device *drm_dev,
conn_state);
else if (encoder_helper_funcs->mode_set)
encoder_helper_funcs->mode_set(encoder, mode, mode);
bridge = drm_bridge_chain_get_first_bridge(encoder);
drm_bridge_chain_mode_set(bridge, mode, mode);
}
primary_state = drm_atomic_get_plane_state(state, crtc->primary);

View File

@@ -9,8 +9,6 @@
static int cru_debug;
#define PLL_RATE_MIN 30000000
#define cru_dbg(format, ...) do { \
if (cru_debug) \
pr_info("%s: " format, __func__, ## __VA_ARGS__); \
@@ -157,6 +155,7 @@ static long clk_virtual_round_rate(struct clk_hw *hw, unsigned long rate,
vop2_clk->rate = rate;
cru_dbg("%s rate: %ld\n", clk_hw_get_name(hw), rate);
return rate;
}
@@ -245,10 +244,6 @@ static long vop2_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
if ((*prate % rate))
*prate = rate;
/* SOC PLL can't output a too low pll freq */
if (*prate < PLL_RATE_MIN)
*prate = rate << vop2_clk->div.width;
}
cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, *prate);

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/extcon-provider.h>
#include <linux/fs.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
@@ -195,6 +196,7 @@ struct rk_hdmirx_dev {
struct dentry *debugfs_dir;
struct freq_qos_request min_sta_freq_req;
struct hdmirx_audiostate audio_state;
struct extcon_dev *extcon;
struct hdmirx_cec *cec;
struct mutex stream_lock;
struct mutex work_lock;
@@ -245,6 +247,11 @@ struct rk_hdmirx_dev {
spinlock_t rst_lock;
};
static const unsigned int hdmirx_extcon_cable[] = {
EXTCON_JACK_VIDEO_IN,
EXTCON_NONE,
};
static bool tx_5v_power_present(struct rk_hdmirx_dev *hdmirx_dev);
static void hdmirx_set_fmt(struct hdmirx_stream *stream,
struct v4l2_pix_format_mplane *pixm, bool try);
@@ -2672,12 +2679,14 @@ static void hdmirx_plugin(struct rk_hdmirx_dev *hdmirx_dev)
}
hdmirx_dma_config(hdmirx_dev);
hdmirx_interrupts_setup(hdmirx_dev, true);
extcon_set_state_sync(hdmirx_dev->extcon, EXTCON_JACK_VIDEO_IN, true);
hdmirx_audio_handle_plugged_change(hdmirx_dev, 1);
}
static void hdmirx_plugout(struct rk_hdmirx_dev *hdmirx_dev)
{
hdmirx_audio_handle_plugged_change(hdmirx_dev, 0);
extcon_set_state_sync(hdmirx_dev->extcon, EXTCON_JACK_VIDEO_IN, false);
hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 0);
hdmirx_interrupts_setup(hdmirx_dev, false);
hdmirx_hpd_ctrl(hdmirx_dev, false);
@@ -4102,6 +4111,19 @@ static int hdmirx_probe(struct platform_device *pdev)
if (ret)
goto err_unreg_video_dev;
hdmirx_dev->extcon = devm_extcon_dev_allocate(dev, hdmirx_extcon_cable);
if (IS_ERR(hdmirx_dev->extcon)) {
ret = PTR_ERR(hdmirx_dev->extcon);
dev_err(&pdev->dev, "allocate extcon failed\n");
goto err_unreg_video_dev;
}
ret = devm_extcon_dev_register(dev, hdmirx_dev->extcon);
if (ret) {
dev_err(&pdev->dev, "failed to register extcon: %d\n", ret);
goto err_unreg_video_dev;
}
irq = gpiod_to_irq(hdmirx_dev->hdmirx_det_gpio);
if (irq < 0) {
dev_err(dev, "failed to get hdmirx-det gpio irq\n");

View File

@@ -1552,6 +1552,9 @@ static void rkisp_stream_fast(struct work_struct *work)
if (ispdev->isp_ver != ISP_V32)
return;
rkisp_chk_tb_over(ispdev);
if (ispdev->tb_head.complete != RKISP_TB_OK)
return;
ret = v4l2_pipeline_pm_get(&stream->vnode.vdev.entity);
if (ret < 0) {
dev_err(ispdev->dev, "%s PM get fail:%d\n", __func__, ret);
@@ -1559,11 +1562,8 @@ static void rkisp_stream_fast(struct work_struct *work)
return;
}
rkisp_chk_tb_over(ispdev);
if (ispdev->tb_head.complete != RKISP_TB_OK) {
v4l2_pipeline_pm_put(&stream->vnode.vdev.entity);
return;
}
if (ispdev->hw_dev->dev_num > 1)
ispdev->hw_dev->is_single = false;
ispdev->is_pre_on = true;
ispdev->is_rdbk_auto = true;
ispdev->pipe.open(&ispdev->pipe, &stream->vnode.vdev.entity, true);

View File

@@ -16,6 +16,7 @@
#define CIF_ISP_REQ_BUFS_MIN 0
static int mi_frame_end(struct rkisp_stream *stream);
static int mi_frame_start(struct rkisp_stream *stream, u32 mis);
static const struct capture_fmt mp_fmts[] = {
/* yuv422 */
@@ -856,6 +857,7 @@ static struct streams_ops rkisp_mp_streams_ops = {
.is_stream_stopped = mp_is_stream_stopped,
.update_mi = update_mi,
.frame_end = mi_frame_end,
.frame_start = mi_frame_start,
};
static struct streams_ops rkisp_sp_streams_ops = {
@@ -866,6 +868,7 @@ static struct streams_ops rkisp_sp_streams_ops = {
.is_stream_stopped = sp_is_stream_stopped,
.update_mi = update_mi,
.frame_end = mi_frame_end,
.frame_start = mi_frame_start,
};
static struct streams_ops rkisp_fbc_streams_ops = {
@@ -875,6 +878,7 @@ static struct streams_ops rkisp_fbc_streams_ops = {
.is_stream_stopped = fbc_is_stream_stopped,
.update_mi = update_mi,
.frame_end = mi_frame_end,
.frame_start = mi_frame_start,
};
static struct streams_ops rkisp_bp_streams_ops = {
@@ -884,8 +888,63 @@ static struct streams_ops rkisp_bp_streams_ops = {
.is_stream_stopped = bp_is_stream_stopped,
.update_mi = update_mi,
.frame_end = mi_frame_end,
.frame_start = mi_frame_start,
};
static void stream_self_update(struct rkisp_stream *stream)
{
struct rkisp_device *dev = stream->ispdev;
u32 val, mask = ISP3X_MPSELF_UPD | ISP3X_SPSELF_UPD | ISP3X_BPSELF_UPD;
bool is_unite = dev->hw_dev->is_unite;
if (stream->id == RKISP_STREAM_FBC) {
val = ISP3X_MPFBC_FORCE_UPD;
rkisp_unite_set_bits(dev, ISP3X_MPFBC_CTRL, 0, val, false, is_unite);
return;
}
switch (stream->id) {
case RKISP_STREAM_MP:
val = ISP3X_MPSELF_UPD;
break;
case RKISP_STREAM_SP:
val = ISP3X_SPSELF_UPD;
break;
case RKISP_STREAM_BP:
val = ISP3X_BPSELF_UPD;
break;
default:
return;
}
rkisp_unite_set_bits(dev, ISP3X_MI_WR_XTD_FORMAT_CTRL, mask, val, false, is_unite);
}
static int mi_frame_start(struct rkisp_stream *stream, u32 mis)
{
struct rkisp_device *dev = stream->ispdev;
unsigned long lock_flags = 0;
/* readback start to update stream buf if null */
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (stream->streaming && !mis && !stream->curr_buf) {
if (!stream->next_buf && !list_empty(&stream->buf_queue)) {
stream->next_buf = list_first_entry(&stream->buf_queue,
struct rkisp_buffer, queue);
list_del(&stream->next_buf->queue);
stream->ops->update_mi(stream);
}
if (dev->hw_dev->is_single && stream->next_buf) {
stream->curr_buf = stream->next_buf;
stream->next_buf = NULL;
stream_self_update(stream);
}
}
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
return 0;
}
/*
* This function is called when a frame end come. The next frame
* is processing and we should set up buffer for next-next frame,

View File

@@ -1645,6 +1645,11 @@ rkisp_start_streaming(struct vb2_queue *queue, unsigned int count)
int ret = -EINVAL;
mutex_lock(&dev->hw_dev->dev_lock);
if (dev->is_pre_on &&
!dev->hw_dev->is_single &&
!atomic_read(&dev->hw_dev->refcnt) &&
!atomic_read(&dev->cap_dev.refcnt))
rkisp_hw_enum_isp_size(dev->hw_dev);
v4l2_dbg(1, rkisp_debug, v4l2_dev, "%s %s id:%d\n",
__func__, node->vdev.name, stream->id);

View File

@@ -592,7 +592,7 @@ int rkisp_csi_config_patch(struct rkisp_device *dev)
if (dev->hdr.op_mode == HDR_NORMAL || dev->hdr.op_mode == HDR_COMPR)
dev->hdr.op_mode = HDR_RDBK_FRAME1;
if (dev->isp_inp == INP_CIF && dev->hw_dev->is_single && dev->isp_ver > ISP_V21)
if (dev->isp_inp == INP_CIF && dev->isp_ver > ISP_V21)
mode.rdbk_mode = dev->is_rdbk_auto ? RKISP_VICAP_RDBK_AUTO : RKISP_VICAP_ONLINE;
else
mode.rdbk_mode = RKISP_VICAP_RDBK_AIQ;

View File

@@ -387,9 +387,7 @@ static void update_rawrd(struct rkisp_stream *stream)
rkisp_next_write(dev, stream->config->mi.y_base_ad_init, val, false);
}
stream->frame_end = false;
if (stream->id == RKISP_STREAM_RAWRD2 &&
(stream->out_isp_fmt.fmt_type == FMT_YUV ||
dev->dmarx_dev.trigger == T_AUTO)) {
if (stream->id == RKISP_STREAM_RAWRD2 && stream->out_isp_fmt.fmt_type == FMT_YUV) {
struct vb2_v4l2_buffer *vbuf = &stream->curr_buf->vb;
struct isp2x_csi_trigger trigger = {
.frame_timestamp = vbuf->vb2_buf.timestamp,

View File

@@ -990,28 +990,18 @@ static int __maybe_unused rkisp_runtime_suspend(struct device *dev)
return pinctrl_pm_select_sleep_state(dev);
}
static int __maybe_unused rkisp_runtime_resume(struct device *dev)
void rkisp_hw_enum_isp_size(struct rkisp_hw_dev *hw_dev)
{
struct rkisp_hw_dev *hw_dev = dev_get_drvdata(dev);
void __iomem *base = hw_dev->base_addr;
struct rkisp_device *isp;
int mult = hw_dev->is_unite ? 2 : 1;
int ret, i;
u32 w, h, i;
ret = pinctrl_pm_select_default_state(dev);
if (ret < 0)
return ret;
enable_sys_clk(hw_dev);
memset(hw_dev->isp_size, 0, sizeof(hw_dev->isp_size));
if (!hw_dev->max_in.is_fix) {
hw_dev->max_in.w = 0;
hw_dev->max_in.h = 0;
}
hw_dev->dev_link_num = 0;
for (i = 0; i < hw_dev->dev_num; i++) {
void *buf;
u32 w, h;
isp = hw_dev->isp[i];
if (!isp || (isp && !isp->is_hw_link))
continue;
@@ -1030,6 +1020,33 @@ static int __maybe_unused rkisp_runtime_resume(struct device *dev)
if (hw_dev->max_in.h < h)
hw_dev->max_in.h = h;
}
}
for (i = 0; i < hw_dev->dev_num; i++) {
isp = hw_dev->isp[i];
if (!isp || (isp && !isp->is_hw_link))
continue;
rkisp_params_check_bigmode(&isp->params_vdev);
}
}
static int __maybe_unused rkisp_runtime_resume(struct device *dev)
{
struct rkisp_hw_dev *hw_dev = dev_get_drvdata(dev);
void __iomem *base = hw_dev->base_addr;
struct rkisp_device *isp;
int mult = hw_dev->is_unite ? 2 : 1;
int ret, i;
void *buf;
ret = pinctrl_pm_select_default_state(dev);
if (ret < 0)
return ret;
enable_sys_clk(hw_dev);
for (i = 0; i < hw_dev->dev_num; i++) {
isp = hw_dev->isp[i];
if (!isp)
continue;
buf = isp->sw_base_addr;
memset(buf, 0, RKISP_ISP_SW_MAX_SIZE * mult);
memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE);
@@ -1040,12 +1057,7 @@ static int __maybe_unused rkisp_runtime_resume(struct device *dev)
}
default_sw_reg_flag(hw_dev->isp[i]);
}
for (i = 0; i < hw_dev->dev_num; i++) {
isp = hw_dev->isp[i];
if (!isp || (isp && !isp->is_hw_link))
continue;
rkisp_params_check_bigmode(&isp->params_vdev);
}
rkisp_hw_enum_isp_size(hw_dev);
hw_dev->monitor.is_en = rkisp_monitor;
return 0;
}

View File

@@ -104,4 +104,5 @@ struct rkisp_hw_dev {
int rkisp_register_irq(struct rkisp_hw_dev *dev);
void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure);
void rkisp_hw_enum_isp_size(struct rkisp_hw_dev *hw_dev);
#endif

View File

@@ -3371,6 +3371,31 @@ isp_bay3d_enable(struct rkisp_isp_params_vdev *params_vdev, bool en)
return;
}
value = priv_val->buf_3dnr_iir.size;
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_IIR_WR_SIZE);
value = priv_val->buf_3dnr_iir.dma_addr;
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_IIR_WR_BASE);
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_IIR_RD_BASE);
value = priv_val->buf_3dnr_ds.size;
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_DS_WR_SIZE);
value = priv_val->buf_3dnr_ds.dma_addr;
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_DS_WR_BASE);
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_DS_RD_BASE);
value = priv_val->is_sram ?
ispdev->hw_dev->sram.dma_addr : priv_val->buf_3dnr_cur.dma_addr;
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_CUR_WR_BASE);
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_CUR_RD_BASE);
value = priv_val->bay3d_cur_size;
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_CUR_WR_SIZE);
isp3_param_write(params_vdev, value, ISP32_MI_BAY3D_CUR_RD_SIZE);
value = priv_val->bay3d_cur_wsize;
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_CUR_WR_LENGTH);
isp3_param_write(params_vdev, value, ISP3X_MI_BAY3D_CUR_RD_LENGTH);
value = priv_val->bay3d_cur_wrap_line << 16 | 28;
isp3_param_write(params_vdev, value, ISP3X_BAY3D_MI_ST);
/* mibuf_size for fifo_cur_full, set to max: (3072 - 2) / 2, 2 align */
value = 0x5fe << 16;
isp3_param_set_bits(params_vdev, ISP3X_BAY3D_IN_IRQ_LINECNT, value);
@@ -4085,7 +4110,6 @@ rkisp_alloc_internal_buf(struct rkisp_isp_params_vdev *params_vdev,
u32 w = ALIGN(isp_sdev->in_crop.width, 16);
u32 h = ALIGN(isp_sdev->in_crop.height, 16);
u32 val, wrap_line, wsize, div;
dma_addr_t dma_addr;
bool is_alloc;
priv_val->is_lo8x8 = (!new_params->others.bay3d_cfg.lo4x8_en &&
@@ -4120,10 +4144,6 @@ rkisp_alloc_internal_buf(struct rkisp_isp_params_vdev *params_vdev,
goto err_3dnr;
}
}
isp3_param_write(params_vdev, val, ISP3X_MI_BAY3D_IIR_WR_SIZE);
val = priv_val->buf_3dnr_iir.dma_addr;
isp3_param_write(params_vdev, val, ISP3X_MI_BAY3D_IIR_WR_BASE);
isp3_param_write(params_vdev, val, ISP3X_MI_BAY3D_IIR_RD_BASE);
div = priv_val->is_lo8x8 ? 64 : 16;
val = w * h / div;
@@ -4145,10 +4165,6 @@ rkisp_alloc_internal_buf(struct rkisp_isp_params_vdev *params_vdev,
goto err_3dnr;
}
}
isp3_param_write(params_vdev, val, ISP3X_MI_BAY3D_DS_WR_SIZE);
val = priv_val->buf_3dnr_ds.dma_addr;
isp3_param_write(params_vdev, val, ISP3X_MI_BAY3D_DS_WR_BASE);
isp3_param_write(params_vdev, val, ISP3X_MI_BAY3D_DS_RD_BASE);
wrap_line = priv_val->is_lo8x8 ? 76 : 36;
wsize = is_bwopt_dis ? w : w * 2;
@@ -4177,22 +4193,13 @@ rkisp_alloc_internal_buf(struct rkisp_isp_params_vdev *params_vdev,
dev_err(dev->dev, "alloc bay3d cur buf fail:%d\n", ret);
goto err_3dnr;
}
dma_addr = priv_val->buf_3dnr_cur.dma_addr;
priv_val->is_sram = false;
} else if (val <= dev->hw_dev->sram.size) {
dma_addr = dev->hw_dev->sram.dma_addr;
priv_val->is_sram = true;
} else {
dma_addr = priv_val->buf_3dnr_cur.dma_addr;
}
isp3_param_write(params_vdev, val, ISP3X_MI_BAY3D_CUR_WR_SIZE);
isp3_param_write(params_vdev, val, ISP32_MI_BAY3D_CUR_RD_SIZE);
isp3_param_write(params_vdev, wsize, ISP3X_MI_BAY3D_CUR_WR_LENGTH);
isp3_param_write(params_vdev, wsize, ISP3X_MI_BAY3D_CUR_RD_LENGTH);
isp3_param_write(params_vdev, dma_addr, ISP3X_MI_BAY3D_CUR_WR_BASE);
isp3_param_write(params_vdev, dma_addr, ISP3X_MI_BAY3D_CUR_RD_BASE);
val = wrap_line << 16 | 28;
isp3_param_write(params_vdev, val, ISP3X_BAY3D_MI_ST);
priv_val->bay3d_cur_size = val;
priv_val->bay3d_cur_wsize = wsize;
priv_val->bay3d_cur_wrap_line = wrap_line;
}
return 0;
err_3dnr:
@@ -4421,14 +4428,7 @@ rkisp_params_first_cfg_v32(struct rkisp_isp_params_vdev *params_vdev)
static void rkisp_save_first_param_v32(struct rkisp_isp_params_vdev *params_vdev, void *param)
{
struct rkisp_isp_params_val_v32 *priv_val =
(struct rkisp_isp_params_val_v32 *)params_vdev->priv_val;
memcpy(params_vdev->isp32_params, param, params_vdev->vdev_fmt.fmt.meta.buffersize);
if (!params_vdev->first_params)
return;
tasklet_enable(&priv_val->lsc_tasklet);
rkisp_alloc_internal_buf(params_vdev, params_vdev->isp32_params);
}
@@ -4718,7 +4718,6 @@ rkisp_params_stream_stop_v32(struct rkisp_isp_params_vdev *params_vdev)
int i;
priv_val = (struct rkisp_isp_params_val_v32 *)params_vdev->priv_val;
tasklet_disable(&priv_val->lsc_tasklet);
rkisp_free_buffer(ispdev, &priv_val->buf_3dnr_iir);
rkisp_free_buffer(ispdev, &priv_val->buf_3dnr_cur);
rkisp_free_buffer(ispdev, &priv_val->buf_3dnr_ds);
@@ -4944,7 +4943,6 @@ int rkisp_init_params_vdev_v32(struct rkisp_isp_params_vdev *params_vdev)
tasklet_init(&priv_val->lsc_tasklet,
isp_lsc_cfg_sram_task,
(unsigned long)params_vdev);
tasklet_disable(&priv_val->lsc_tasklet);
priv_val->buf_info_owner = 0;
priv_val->buf_info_cnt = 0;
priv_val->buf_info_idx = -1;

View File

@@ -185,6 +185,9 @@ struct rkisp_isp_params_val_v32 {
u32 buf_info_cnt;
int buf_info_idx;
u32 bay3d_cur_size;
u32 bay3d_cur_wsize;
u32 bay3d_cur_wrap_line;
struct rkisp_dummy_buffer buf_3dnr_iir;
struct rkisp_dummy_buffer buf_3dnr_cur;
struct rkisp_dummy_buffer buf_3dnr_ds;

View File

@@ -614,7 +614,7 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo
rkisp_stream_frame_start(dev, 0);
if (!hw->is_single && !is_try) {
rkisp_update_regs(dev, CTRL_VI_ISP_PATH, SUPER_IMP_COLOR_CR);
rkisp_update_regs(dev, DUAL_CROP_M_H_OFFS, DUAL_CROP_S_V_SIZE);
rkisp_update_regs(dev, DUAL_CROP_M_H_OFFS, ISP3X_DUAL_CROP_FBC_V_SIZE);
rkisp_update_regs(dev, ISP_ACQ_PROP, DUAL_CROP_CTRL);
rkisp_update_regs(dev, SELF_RESIZE_SCALE_HY, MI_WR_CTRL);
rkisp_update_regs(dev, ISP32_BP_RESIZE_SCALE_HY, SELF_RESIZE_CTRL);
@@ -722,6 +722,40 @@ run_next:
rkisp_unite_write(dev, CSI2RX_CTRL0, val, true, hw->is_unite);
}
static void rkisp_fast_switch_rx_buf(struct rkisp_device *dev, bool is_current)
{
struct rkisp_stream *stream;
struct rkisp_buffer *buf;
u32 i, val;
for (i = RKISP_STREAM_RAWRD0; i < RKISP_MAX_DMARX_STREAM; i++) {
stream = &dev->dmarx_dev.stream[i];
if (!stream->ops)
continue;
buf = NULL;
if (is_current)
buf = stream->curr_buf;
else if (!list_empty(&stream->buf_queue))
buf = list_first_entry(&stream->buf_queue,
struct rkisp_buffer, queue);
if (!buf)
continue;
val = buf->buff_addr[RKISP_PLANE_Y];
/* f1 -> f0 -> f1 for normal
* L:f1 L:f1 -> L:f0 S:f0 -> L:f1 S:f1 for hdr2
*/
if (dev->rd_mode == HDR_RDBK_FRAME2 && !is_current &&
rkisp_read_reg_cache(dev, ISP3X_HDRMGE_GAIN0) == 0xfff0040) {
if (i == RKISP_STREAM_RAWRD2)
continue;
else
rkisp_write(dev, ISP3X_MI_RAWS_RD_BASE, val, false);
}
rkisp_write(dev, stream->config->mi.y_base_ad_init, val, false);
}
}
static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
{
struct rkisp_hw_dev *hw = dev->hw_dev;
@@ -766,10 +800,14 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
}
}
/* wait 2 frame to start isp for fast */
if (dev->is_pre_on && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq))
goto end;
if (max) {
v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
"trigger fifo len:%d\n", max);
isp = hw->isp[id];
v4l2_dbg(2, rkisp_debug, &isp->v4l2_dev,
"trigger fifo len:%d\n", max);
rkisp_rdbk_trigger_event(isp, T_CMD_DEQUEUE, &t);
isp->dmarx_dev.pre_frame = isp->dmarx_dev.cur_frame;
if (t.frame_id > isp->dmarx_dev.pre_frame.id &&
@@ -790,9 +828,10 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
isp->sw_rd_cnt = 1;
times = 0;
}
if (dev->is_pre_on && t.frame_id == 0) {
dev->is_first_double = true;
dev->skip_frame = 1;
if (isp->is_pre_on && t.frame_id == 0) {
isp->is_first_double = true;
isp->skip_frame = 1;
rkisp_fast_switch_rx_buf(isp, false);
}
}
end:
@@ -865,10 +904,12 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq)
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
}
if (dev->irq_ends != dev->irq_ends_mask || !IS_HDR_RDBK(dev->rd_mode))
if ((dev->irq_ends & dev->irq_ends_mask) != dev->irq_ends_mask ||
!IS_HDR_RDBK(dev->rd_mode))
return;
if (dev->is_first_double) {
rkisp_fast_switch_rx_buf(dev, true);
dev->skip_frame = 0;
dev->irq_ends = 0;
return;
@@ -2776,9 +2817,16 @@ static void rkisp_rx_qbuf_online(struct rkisp_stream *stream,
static void rkisp_rx_qbuf_rdbk(struct rkisp_stream *stream,
struct rkisp_rx_buf_pool *pool)
{
struct rkisp_device *dev = stream->ispdev;
unsigned long lock_flags = 0;
struct rkisp_buffer *ispbuf = &pool->buf;
struct isp2x_csi_trigger trigger = {
.frame_timestamp = ispbuf->vb.vb2_buf.timestamp,
.sof_timestamp = ispbuf->vb.vb2_buf.timestamp,
.frame_id = ispbuf->vb.sequence,
.mode = 0,
.times = 0,
};
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
if (list_empty(&stream->buf_queue) && !stream->curr_buf) {
stream->curr_buf = ispbuf;
@@ -2787,6 +2835,8 @@ static void rkisp_rx_qbuf_rdbk(struct rkisp_stream *stream,
list_add_tail(&ispbuf->queue, &stream->buf_queue);
}
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
if (stream->id == RKISP_STREAM_RAWRD2)
rkisp_rdbk_trigger_event(dev, T_CMD_QUEUE, &trigger);
}
static int rkisp_rx_qbuf(struct rkisp_device *dev,
@@ -3639,12 +3689,14 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev)
head->enable = 0;
dma_sync_single_for_device(isp_dev->dev, isp_dev->resmem_addr,
sizeof(struct rkisp_thunderboot_resmem_head),
DMA_FROM_DEVICE);
DMA_TO_DEVICE);
}
shm_head_poll_timeout(isp_dev, !!head->complete, 5000, 100 * USEC_PER_MSEC);
shm_head_poll_timeout(isp_dev, !!head->complete, 5000, 200 * USEC_PER_MSEC);
if (head->complete != RKISP_TB_OK) {
v4l2_err(&isp_dev->v4l2_dev, "wait thunderboot over timeout\n");
} else {
struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev;
void *param = NULL;
u32 size = 0;
switch (isp_dev->hw_dev->isp_ver) {
@@ -3657,13 +3709,14 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev)
if (size && size < isp_dev->resmem_size) {
dma_sync_single_for_cpu(isp_dev->dev, isp_dev->resmem_addr,
size, DMA_FROM_DEVICE);
isp_dev->params_vdev.is_first_cfg = true;
params_vdev->is_first_cfg = true;
if (isp_dev->hw_dev->isp_ver == ISP_V32) {
struct rkisp32_thunderboot_resmem_head *tmp = resmem_va;
memcpy(isp_dev->params_vdev.isp32_params, &tmp->cfg,
sizeof(struct isp32_isp_params_cfg));
param = &tmp->cfg;
}
if (param)
params_vdev->ops->save_first_param(params_vdev, param);
} else if (size > isp_dev->resmem_size) {
v4l2_err(&isp_dev->v4l2_dev,
"resmem size:%zu no enough for head:%d\n",

View File

@@ -17,12 +17,14 @@
#include <linux/regmap.h>
#include <linux/dma-buf.h>
#include <linux/highmem.h>
#include <linux/soc/rockchip/rockchip_thunderboot_service.h>
#include "rkisp_tb_helper.h"
static struct platform_device *rkisp_tb_pdev;
static struct clk_bulk_data *rkisp_tb_clk;
static int rkisp_tb_clk_num;
static struct rk_tb_client tb_cl;
struct shm_data {
int npages;
@@ -187,6 +189,11 @@ static int __maybe_unused rkisp_tb_clocks_loader_unprotect(void)
return 0;
}
static void rkisp_tb_cb(void *data)
{
rkisp_tb_clocks_loader_unprotect();
}
static int __maybe_unused rkisp_tb_runtime_suspend(struct device *dev)
{
return 0;
@@ -220,6 +227,12 @@ static int rkisp_tb_plat_probe(struct platform_device *pdev)
rkisp_tb_clk_num = 0;
}
rkisp_tb_clocks_loader_protect();
if (IS_ENABLED(CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE)) {
tb_cl.cb = rkisp_tb_cb;
return rk_tb_client_register_cb(&tb_cl);
}
return 0;
}
@@ -264,6 +277,9 @@ long rkisp_tb_shm_ioctl(struct rkisp_thunderboot_shmem *shmem)
void rkisp_tb_unprotect_clk(void)
{
if (IS_ENABLED(CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE))
return;
rkisp_tb_clocks_loader_unprotect();
}
EXPORT_SYMBOL(rkisp_tb_unprotect_clk);

View File

@@ -281,7 +281,7 @@ static int fec_running(struct rkispp_fec_dev *fec,
v4l2_dbg(3, rkispp_debug, &fec->v4l2_dev,
"0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n"
"0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n"
"0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n",
"0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n",
RKISPP_CTRL_SYS_STATUS, readl(base + RKISPP_CTRL_SYS_STATUS),
RKISPP_FEC_CTRL, readl(base + RKISPP_FEC_CTRL),
RKISPP_FEC_RD_VIR_STRIDE, readl(base + RKISPP_FEC_RD_VIR_STRIDE),
@@ -415,6 +415,9 @@ static const struct v4l2_file_operations fec_fops = {
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = v4l2_m2m_fop_mmap,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = video_ioctl2,
#endif
};
static const struct video_device fec_videodev = {

View File

@@ -1302,7 +1302,7 @@ static int rk808_probe(struct i2c_client *client,
}
ret = regmap_add_irq_chip(rk808->regmap, client->irq,
IRQF_ONESHOT, -1,
IRQF_ONESHOT | IRQF_SHARED, -1,
rk808->regmap_irq_chip, &rk808->irq_data);
if (ret) {
dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);

View File

@@ -45,6 +45,7 @@
#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9)
#define DWCMSHC_EMMC_DLL_START_POINT 16
#define DWCMSHC_EMMC_DLL_INC 8
#define DWCMSHC_EMMC_DLL_BYPASS BIT(24)
#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
#define DLL_TXCLK_TAPNUM_DEFAULT 0x10
@@ -233,8 +234,11 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3);
if (clock <= 52000000) {
/* Disable DLL and reset both of sample and drive clock */
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
/*
* Disable DLL and reset both of sample and drive clock.
* The bypass bit and start bit need to set if DLL is not locked.
*/
sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL);
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK);
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT);
@@ -264,7 +268,8 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
extra |= DLL_RXCLK_NO_INVERTER;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
/* Init DLL settings */
/* Init DLL settings, clean start bit before resetting */
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
0x2 << DWCMSHC_EMMC_DLL_INC |
DWCMSHC_EMMC_DLL_START;

View File

@@ -1279,7 +1279,7 @@ static int rk_pcie_phy_init(struct rk_pcie *rk_pcie)
int ret;
struct device *dev = rk_pcie->pci->dev;
rk_pcie->phy = devm_phy_get(dev, "pcie-phy");
rk_pcie->phy = devm_phy_optional_get(dev, "pcie-phy");
if (IS_ERR(rk_pcie->phy)) {
if (PTR_ERR(rk_pcie->phy) != -EPROBE_DEFER)
dev_info(dev, "missing phy\n");

View File

@@ -104,7 +104,6 @@ obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
obj-$(CONFIG_BATTERY_CW2015) += cw2015_battery.o
obj-$(CONFIG_BATTERY_RK816) += rk816_battery.o
obj-$(CONFIG_BATTERY_RK817) += rk817_battery.o
obj-$(CONFIG_CHARGER_RK817) += rk817_charger.o

View File

@@ -188,19 +188,17 @@ static blk_status_t do_blktrans_all_request(struct nand_blk_dev *dev,
struct request *req)
{
unsigned long block, nsect;
char *buf = NULL;
char *buf = NULL, *page_buf;
struct req_iterator rq_iter;
struct bio_vec bvec;
int ret = BLK_STS_IOERR;
unsigned long totle_nsect;
unsigned long rq_len = 0;
block = blk_rq_pos(req);
nsect = blk_rq_cur_bytes(req) >> 9;
totle_nsect = (req->__data_len) >> 9;
if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
get_capacity(req->rq_disk))
if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > get_capacity(req->rq_disk))
return BLK_STS_IOERR;
switch (req_op(req)) {
@@ -211,20 +209,16 @@ static blk_status_t do_blktrans_all_request(struct nand_blk_dev *dev,
case REQ_OP_READ:
buf = mtd_read_temp_buffer;
req_check_buffer_align(req, &buf);
ret = nand_dev_transfer(dev,
block,
totle_nsect,
buf,
REQ_OP_READ);
ret = nand_dev_transfer(dev, block, totle_nsect, buf, REQ_OP_READ);
if (buf == mtd_read_temp_buffer) {
char *p = buf;
rq_for_each_segment(bvec, req, rq_iter) {
memcpy(page_address(bvec.bv_page) +
bvec.bv_offset,
p,
bvec.bv_len);
page_buf = kmap_atomic(bvec.bv_page);
memcpy(page_buf + bvec.bv_offset, p, bvec.bv_len);
p += bvec.bv_len;
kunmap_atomic(page_buf);
}
}
@@ -233,34 +227,21 @@ static blk_status_t do_blktrans_all_request(struct nand_blk_dev *dev,
else
return BLK_STS_OK;
case REQ_OP_WRITE:
rq_for_each_segment(bvec, req, rq_iter) {
if ((page_address(bvec.bv_page) + bvec.bv_offset) == (buf + rq_len)) {
rq_len += bvec.bv_len;
} else {
if (rq_len) {
ret = nand_dev_transfer(dev,
block,
rq_len >> 9,
buf,
REQ_OP_WRITE);
if (ret)
return BLK_STS_IOERR;
else
return BLK_STS_OK;
}
block += rq_len >> 9;
buf = (page_address(bvec.bv_page) + bvec.bv_offset);
rq_len = bvec.bv_len;
buf = mtd_read_temp_buffer;
req_check_buffer_align(req, &buf);
if (buf == mtd_read_temp_buffer) {
char *p = buf;
rq_for_each_segment(bvec, req, rq_iter) {
page_buf = kmap_atomic(bvec.bv_page);
memcpy(p, page_buf + bvec.bv_offset, bvec.bv_len);
p += bvec.bv_len;
kunmap_atomic(page_buf);
}
}
if (rq_len) {
ret = nand_dev_transfer(dev,
block,
rq_len >> 9,
buf,
REQ_OP_WRITE);
}
ret = nand_dev_transfer(dev, block, totle_nsect, buf, REQ_OP_WRITE);
if (ret)
return BLK_STS_IOERR;

View File

@@ -881,7 +881,9 @@ u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
u32 sec_per_page = p_nand_info->sec_per_page;
u32 data_size = sec_per_page * SFC_NAND_SECTOR_SIZE;
struct nand_mega_area *meta = &p_nand_info->meta;
int retries = 0;
retry:
ret = sfc_nand_read_page_raw(cs, addr, gp_page_buf);
memcpy(p_data, gp_page_buf, data_size);
p_spare[0] = gp_page_buf[(data_size + meta->off0) / 4];
@@ -903,6 +905,10 @@ u32 sfc_nand_read_page(u8 cs, u32 addr, u32 *p_data, u32 *p_spare)
if (p_spare)
rkflash_print_hex("spare:", p_spare, 4, 2);
if (ret == SFC_NAND_ECC_ERROR && retries < 1) {
retries++;
goto retry;
}
}
return ret;

View File

@@ -14,8 +14,10 @@
#include <asm/div64.h>
#ifndef FPGA_PLATFORM
#ifdef CONFIG_PM_DEVFREQ
#include <../drivers/devfreq/governor.h>
#endif
#endif
#include "rknpu_drv.h"
#include "rknpu_mm.h"
@@ -191,6 +193,7 @@ static int rknpu_freq_show(struct seq_file *m, void *data)
return 0;
}
#ifdef CONFIG_PM_DEVFREQ
static ssize_t rknpu_freq_set(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
@@ -233,6 +236,13 @@ static ssize_t rknpu_freq_set(struct file *file, const char __user *ubuf,
return len;
}
#else
static ssize_t rknpu_freq_set(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
return -EFAULT;
}
#endif
static int rknpu_volt_show(struct seq_file *m, void *data)
{

View File

@@ -41,8 +41,10 @@
#include <soc/rockchip/rockchip_opp_select.h>
#include <soc/rockchip/rockchip_system_monitor.h>
#include <soc/rockchip/rockchip_ipa.h>
#ifdef CONFIG_PM_DEVFREQ
#include <../drivers/devfreq/governor.h>
#endif
#endif
#include "rknpu_ioctl.h"
#include "rknpu_reset.h"
@@ -1062,6 +1064,7 @@ static struct devfreq_dev_profile npu_devfreq_profile = {
.get_cur_freq = npu_devfreq_get_cur_freq,
};
#ifdef CONFIG_PM_DEVFREQ
static int devfreq_rknpu_ondemand_func(struct devfreq *df, unsigned long *freq)
{
struct rknpu_device *rknpu_dev = df->data;
@@ -1085,6 +1088,7 @@ static struct devfreq_governor devfreq_rknpu_ondemand = {
.get_target_freq = devfreq_rknpu_ondemand_func,
.event_handler = devfreq_rknpu_ondemand_handler,
};
#endif
static unsigned long npu_get_static_power(struct devfreq *devfreq,
unsigned long voltage)
@@ -1191,11 +1195,13 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
dev_pm_opp_put(opp);
dp->initial_freq = rknpu_dev->current_freq;
#ifdef CONFIG_PM_DEVFREQ
ret = devfreq_add_governor(&devfreq_rknpu_ondemand);
if (ret) {
LOG_DEV_ERROR(dev, "failed to add rknpu_ondemand governor\n");
goto err_remove_table;
}
#endif
rknpu_dev->devfreq = devm_devfreq_add_device(dev, dp, "rknpu_ondemand",
(void *)rknpu_dev);
@@ -1247,7 +1253,9 @@ out:
return 0;
err_remove_governor:
#ifdef CONFIG_PM_DEVFREQ
devfreq_remove_governor(&devfreq_rknpu_ondemand);
#endif
err_remove_table:
dev_pm_opp_of_remove_table(dev);
@@ -1325,11 +1333,13 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
}
dp->initial_freq = rknpu_dev->current_freq;
#ifdef CONFIG_PM_DEVFREQ
ret = devfreq_add_governor(&devfreq_rknpu_ondemand);
if (ret) {
LOG_DEV_ERROR(dev, "failed to add rknpu_ondemand governor\n");
goto err_remove_table;
}
#endif
rknpu_dev->devfreq = devm_devfreq_add_device(dev, dp, "rknpu_ondemand",
(void *)rknpu_dev);
@@ -1380,7 +1390,9 @@ out:
return 0;
err_remove_governor:
#ifdef CONFIG_PM_DEVFREQ
devfreq_remove_governor(&devfreq_rknpu_ondemand);
#endif
err_remove_table:
dev_pm_opp_of_remove_table(dev);
@@ -1396,7 +1408,9 @@ static int rknpu_devfreq_remove(struct rknpu_device *rknpu_dev)
devfreq_unregister_opp_notifier(rknpu_dev->dev,
rknpu_dev->devfreq);
dev_pm_opp_of_remove_table(rknpu_dev->dev);
#ifdef CONFIG_PM_DEVFREQ
devfreq_remove_governor(&devfreq_rknpu_ondemand);
#endif
}
return 0;

View File

@@ -52,6 +52,7 @@ struct rockchip_domain_info {
int mem_status_mask;
int repair_status_mask;
bool keepon_startup;
bool always_on;
u32 pwr_offset;
u32 mem_offset;
u32 req_offset;
@@ -117,6 +118,35 @@ module_param_named(always_on, pm_domain_always_on, bool, 0644);
MODULE_PARM_DESC(always_on,
"Always keep pm domains power on except for system suspend.");
#ifdef MODULE
static bool keepon_startup = true;
static void rockchip_pd_keepon_do_release(void);
static int pd_param_set_keepon_startup(const char *val,
const struct kernel_param *kp)
{
int ret;
ret = param_set_bool(val, kp);
if (ret)
return ret;
if (!keepon_startup)
rockchip_pd_keepon_do_release();
return 0;
}
static const struct kernel_param_ops pd_keepon_startup_ops = {
.set = pd_param_set_keepon_startup,
.get = param_get_bool,
};
module_param_cb(keepon_startup, &pd_keepon_startup_ops, &keepon_startup, 0644);
MODULE_PARM_DESC(keepon_startup,
"Keep pm domains power on during system startup.");
#endif
static void rockchip_pmu_lock(struct rockchip_pm_domain *pd)
{
mutex_lock(&pd->pmu->mutex);
@@ -847,6 +877,26 @@ static void rockchip_pd_qos_init(struct rockchip_pm_domain *pd)
}
}
static int rockchip_pd_add_alwasy_on_flag(struct rockchip_pm_domain *pd)
{
int error;
if (pd->genpd.flags & GENPD_FLAG_ALWAYS_ON)
return 0;
pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
if (!rockchip_pmu_domain_is_on(pd)) {
error = rockchip_pd_power(pd, true);
if (error) {
dev_err(pd->pmu->dev,
"failed to power on domain '%s': %d\n",
pd->genpd.name, error);
return error;
}
}
return 0;
}
static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
struct device_node *node)
{
@@ -1033,20 +1083,11 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
pd->genpd.detach_dev = rockchip_pd_detach_dev;
if (pd_info->active_wakeup)
pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
#ifndef MODULE
if (pd_info->keepon_startup) {
pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
if (!rockchip_pmu_domain_is_on(pd)) {
error = rockchip_pd_power(pd, true);
if (error) {
dev_err(pmu->dev,
"failed to power on domain '%s': %d\n",
node->name, error);
goto err_unprepare_clocks;
}
}
if (pd_info->always_on || pd_info->keepon_startup) {
error = rockchip_pd_add_alwasy_on_flag(pd);
if (error)
goto err_unprepare_clocks;
}
#endif
rockchip_pd_qos_init(pd);
pm_genpd_init(&pd->genpd, NULL, !rockchip_pmu_domain_is_on(pd));
@@ -1181,46 +1222,36 @@ err_out:
return error;
}
#ifndef MODULE
static void rockchip_pd_keepon_do_release(struct generic_pm_domain *genpd,
struct rockchip_pm_domain *pd)
{
struct pm_domain_data *pm_data;
int enable_count;
pd->genpd.flags &= (~GENPD_FLAG_ALWAYS_ON);
list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
if (!atomic_read(&pm_data->dev->power.usage_count)) {
enable_count = 0;
if (!pm_runtime_enabled(pm_data->dev)) {
pm_runtime_enable(pm_data->dev);
enable_count = 1;
}
pm_runtime_get_sync(pm_data->dev);
pm_runtime_put_sync(pm_data->dev);
if (enable_count)
pm_runtime_disable(pm_data->dev);
}
}
}
static int __init rockchip_pd_keepon_release(void)
static void rockchip_pd_keepon_do_release(void)
{
struct generic_pm_domain *genpd;
struct rockchip_pm_domain *pd;
int i;
if (!g_pmu)
return 0;
return;
for (i = 0; i < g_pmu->genpd_data.num_domains; i++) {
genpd = g_pmu->genpd_data.domains[i];
if (genpd) {
pd = to_rockchip_pd(genpd);
if (pd->info->keepon_startup)
rockchip_pd_keepon_do_release(genpd, pd);
if (pd->info->always_on)
continue;
if (!pd->info->keepon_startup)
continue;
if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON))
continue;
genpd->flags &= (~GENPD_FLAG_ALWAYS_ON);
queue_work(pm_wq, &genpd->power_off_work);
}
}
}
#ifndef MODULE
static int __init rockchip_pd_keepon_release(void)
{
rockchip_pd_keepon_do_release();
return 0;
}
late_initcall_sync(rockchip_pd_keepon_release);

View File

@@ -819,6 +819,7 @@ static int mpp_task_run(struct mpp_dev *mpp,
*/
mpp_reset_down_read(mpp->reset_group);
mpp_iommu_dev_activate(mpp->iommu_info, mpp);
if (mpp->dev_ops->run)
mpp->dev_ops->run(mpp, task);
@@ -2032,39 +2033,21 @@ int mpp_task_dump_reg(struct mpp_dev *mpp,
int mpp_task_dump_hw_reg(struct mpp_dev *mpp)
{
if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) {
u32 i;
u32 s = mpp->var->hw_info->reg_start;
u32 e = mpp->var->hw_info->reg_end;
u32 i;
u32 s = mpp->var->hw_info->reg_start;
u32 e = mpp->var->hw_info->reg_end;
mpp_err("--- dump hardware register ---\n");
for (i = s; i <= e; i++) {
u32 reg = i * sizeof(u32);
mpp_err("--- dump hardware register ---\n");
for (i = s; i <= e; i++) {
u32 reg = i * sizeof(u32);
mpp_err("reg[%03d]: %04x: 0x%08x\n",
mpp_err("reg[%03d]: %04x: 0x%08x\n",
i, reg, readl_relaxed(mpp->reg_base + reg));
}
}
return 0;
}
static int mpp_iommu_handle(struct iommu_domain *iommu,
struct device *iommu_dev,
unsigned long iova,
int status, void *arg)
{
struct mpp_dev *mpp = (struct mpp_dev *)arg;
dev_err(mpp->dev, "fault addr 0x%08lx status %x\n", iova, status);
mpp_task_dump_hw_reg(mpp);
if (mpp->iommu_info->hdl)
mpp->iommu_info->hdl(iommu, iommu_dev, iova, status, arg);
return 0;
}
void mpp_reg_show(struct mpp_dev *mpp, u32 offset)
{
if (!mpp)
@@ -2167,10 +2150,6 @@ int mpp_dev_probe(struct mpp_dev *mpp,
if (ret)
goto failed;
}
/* set iommu fault handler */
if (mpp->iommu_info)
iommu_set_fault_handler(mpp->iommu_info->domain,
mpp_iommu_handle, mpp);
/* read hardware id */
if (hw_info->reg_id >= 0) {
@@ -2270,6 +2249,7 @@ irqreturn_t mpp_dev_irq(int irq, void *param)
/* normal condition, set state and wake up isr thread */
set_bit(TASK_STATE_IRQ, &task->state);
}
mpp_iommu_dev_deactivate(mpp->iommu_info, mpp);
} else {
mpp_debug(DEBUG_IRQ_CHECK, "error, task is null\n");
}

View File

@@ -191,6 +191,7 @@ struct mpp_task;
struct mpp_session;
struct mpp_dma_session;
struct mpp_taskqueue;
struct iommu_domain;
/* data common struct for parse out */
struct mpp_request {
@@ -342,6 +343,8 @@ struct mpp_dev {
void __iomem *reg_base;
struct mpp_grf_info *grf_info;
struct mpp_iommu_info *iommu_info;
int (*fault_handler)(struct iommu_domain *iommu, struct device *iommu_dev,
unsigned long iova, int status, void *arg);
atomic_t reset_request;
atomic_t session_index;

View File

@@ -25,6 +25,7 @@
#include "mpp_debug.h"
#include "mpp_iommu.h"
#include "mpp_common.h"
static struct mpp_dma_buffer *
mpp_dma_find_buffer_fd(struct mpp_dma_session *dma, int fd)
@@ -388,6 +389,29 @@ int mpp_iommu_attach(struct mpp_iommu_info *info)
return iommu_attach_group(info->domain, info->group);
}
static int mpp_iommu_handle(struct iommu_domain *iommu,
struct device *iommu_dev,
unsigned long iova,
int status, void *arg)
{
struct mpp_dev *mpp = (struct mpp_dev *)arg;
dev_err(iommu_dev, "fault addr 0x%08lx status %x arg %p\n",
iova, status, arg);
if (!mpp) {
dev_err(iommu_dev, "pagefault without device to handle\n");
return 0;
}
if (mpp->dev_ops && mpp->dev_ops->dump_dev)
mpp->dev_ops->dump_dev(mpp);
else
mpp_task_dump_hw_reg(mpp);
return 0;
}
struct mpp_iommu_info *
mpp_iommu_probe(struct device *dev)
{
@@ -446,10 +470,12 @@ mpp_iommu_probe(struct device *dev)
}
init_rwsem(&info->rw_sem);
spin_lock_init(&info->dev_lock);
info->dev = dev;
info->pdev = pdev;
info->group = group;
info->domain = domain;
info->dev_active = NULL;
info->irq = platform_get_irq(pdev, 0);
info->got_irq = (info->irq < 0) ? false : true;
@@ -507,3 +533,47 @@ int mpp_iommu_flush_tlb(struct mpp_iommu_info *info)
return 0;
}
int mpp_iommu_dev_activate(struct mpp_iommu_info *info, struct mpp_dev *dev)
{
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&info->dev_lock, flags);
if (info->dev_active || !dev) {
dev_err(info->dev, "can not activate %s -> %s\n",
info->dev_active ? dev_name(info->dev_active->dev) : NULL,
dev ? dev_name(dev->dev) : NULL);
ret = -EINVAL;
} else {
info->dev_active = dev;
/* switch domain pagefault handler and arg depending on device */
iommu_set_fault_handler(info->domain, dev->fault_handler ?
dev->fault_handler : mpp_iommu_handle, dev);
dev_dbg(info->dev, "activate -> %p %s\n", dev, dev_name(dev->dev));
}
spin_unlock_irqrestore(&info->dev_lock, flags);
return ret;
}
int mpp_iommu_dev_deactivate(struct mpp_iommu_info *info, struct mpp_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&info->dev_lock, flags);
if (info->dev_active != dev)
dev_err(info->dev, "can not deactivate %s when %s activated\n",
dev_name(dev->dev),
info->dev_active ? dev_name(info->dev_active->dev) : NULL);
dev_dbg(info->dev, "deactivate %p\n", info->dev_active);
info->dev_active = NULL;
spin_unlock_irqrestore(&info->dev_lock, flags);
return 0;
}

View File

@@ -64,6 +64,8 @@ struct mpp_rk_iommu {
u32 is_paged;
};
struct mpp_dev;
struct mpp_iommu_info {
struct rw_semaphore rw_sem;
@@ -73,6 +75,10 @@ struct mpp_iommu_info {
struct iommu_group *group;
struct mpp_rk_iommu *iommu;
iommu_fault_handler_t hdl;
spinlock_t dev_lock;
struct mpp_dev *dev_active;
u32 av1d_iommu;
int irq;
int got_irq;
@@ -110,6 +116,9 @@ int mpp_iommu_flush_tlb(struct mpp_iommu_info *info);
int mpp_av1_iommu_disable(struct device *dev);
int mpp_av1_iommu_enable(struct device *dev);
int mpp_iommu_dev_activate(struct mpp_iommu_info *info, struct mpp_dev *dev);
int mpp_iommu_dev_deactivate(struct mpp_iommu_info *info, struct mpp_dev *dev);
static inline int mpp_iommu_down_read(struct mpp_iommu_info *info)
{
if (info)

View File

@@ -420,8 +420,10 @@ static int rkvdec2_isr(struct mpp_dev *mpp)
RKVDEC_TIMEOUT_STA | RKVDEC_ERROR_STA;
if (err_mask & task->irq_status) {
atomic_inc(&mpp->reset_request);
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status);
mpp_task_dump_hw_reg(mpp);
if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) {
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status);
mpp_task_dump_hw_reg(mpp);
}
}
mpp_task_finish(mpp_task->session, mpp_task);
@@ -1442,7 +1444,7 @@ static int rkvdec2_core_probe(struct platform_device *pdev)
mpp->dev_ops->task_worker = rkvdec2_soft_ccu_worker;
kthread_init_work(&mpp->work, rkvdec2_soft_ccu_worker);
mpp->iommu_info->hdl = rkvdec2_ccu_iommu_fault_handle;
mpp->fault_handler = rkvdec2_ccu_iommu_fault_handle;
/* get irq request */
ret = devm_request_threaded_irq(dev, mpp->irq, rkvdec2_soft_ccu_irq, NULL,
IRQF_SHARED, dev_name(dev), mpp);

View File

@@ -1066,6 +1066,7 @@ static int rkvdec2_link_power_on(struct mpp_dev *mpp)
mpp_clk_set_rate(&dec->cabac_clk_info, CLK_MODE_ADVANCED);
mpp_clk_set_rate(&dec->hevc_cabac_clk_info, CLK_MODE_ADVANCED);
mpp_devfreq_set_core_rate(mpp, CLK_MODE_ADVANCED);
mpp_iommu_dev_activate(mpp->iommu_info, mpp);
}
return 0;
}
@@ -1092,6 +1093,7 @@ static void rkvdec2_link_power_off(struct mpp_dev *mpp)
mpp_clk_set_rate(&dec->cabac_clk_info, CLK_MODE_NORMAL);
mpp_clk_set_rate(&dec->hevc_cabac_clk_info, CLK_MODE_NORMAL);
mpp_devfreq_set_core_rate(mpp, CLK_MODE_NORMAL);
mpp_iommu_dev_deactivate(mpp->iommu_info, mpp);
}
}
@@ -1614,6 +1616,8 @@ static int rkvdec2_ccu_power_on(struct mpp_taskqueue *queue,
pm_stay_awake(mpp->dev);
if (mpp->hw_ops->clk_on)
mpp->hw_ops->clk_on(mpp);
mpp_iommu_dev_activate(mpp->iommu_info, mpp);
}
mpp_debug(DEBUG_CCU, "power on\n");
}
@@ -1642,6 +1646,7 @@ static int rkvdec2_ccu_power_off(struct mpp_taskqueue *queue,
pm_relax(mpp->dev);
pm_runtime_mark_last_busy(mpp->dev);
pm_runtime_put_autosuspend(mpp->dev);
mpp_iommu_dev_deactivate(mpp->iommu_info, mpp);
}
mpp_debug(DEBUG_CCU, "power off\n");
}

View File

@@ -530,9 +530,11 @@ static int rkvenc_isr(struct mpp_dev *mpp)
if (task->irq_status & RKVENC_INT_ERROR_BITS) {
atomic_inc(&mpp->reset_request);
/* dump register */
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status);
mpp_task_dump_hw_reg(mpp);
if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) {
/* dump error register */
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status);
mpp_task_dump_hw_reg(mpp);
}
}
/* unmap reserve buffer */

View File

@@ -1200,9 +1200,10 @@ static int rkvenc_isr(struct mpp_dev *mpp)
if (task->irq_status & enc->hw_info->err_mask) {
atomic_inc(&mpp->reset_request);
/* dump register */
mpp_task_dump_hw_reg(mpp);
/* dump register */
if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG))
mpp_task_dump_hw_reg(mpp);
}
mpp_task_finish(mpp_task->session, mpp_task);

View File

@@ -21,8 +21,6 @@ enum job_flags {
RGA_JOB_UNSUPPORT_RGA_MMU = 1 << 4,
};
struct rga_scheduler_t *rga_job_get_scheduler(struct rga_job *job);
void rga_job_session_destroy(struct rga_session *session);
void rga_job_scheduler_dump_info(struct rga_scheduler_t *scheduler);
@@ -52,10 +50,4 @@ int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job
int rga_request_manager_init(struct rga_pending_request_manager **request_manager_session);
int rga_request_manager_remove(struct rga_pending_request_manager **request_manager_session);
struct rga_job *
rga_scheduler_get_pending_job_list(struct rga_scheduler_t *scheduler);
struct rga_job *
rga_scheduler_get_running_job(struct rga_scheduler_t *scheduler);
#endif /* __LINUX_RKRGA_JOB_H_ */

View File

@@ -270,8 +270,8 @@ int rga_kernel_commit(struct rga_req *cmd)
struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager;
session = rga_session_init();
if (!session)
return -ENOMEM;
if (IS_ERR(session))
return PTR_ERR(session);
request_id = rga_request_alloc(0, session);
if (request_id < 0) {
@@ -561,22 +561,38 @@ static int rga_session_manager_remove(struct rga_session_manager **session_manag
static struct rga_session *rga_session_init(void)
{
int new_id;
struct rga_session_manager *session_manager = NULL;
struct rga_session *session = kzalloc(sizeof(*session), GFP_KERNEL);
struct rga_session *session = NULL;
session_manager = rga_drvdata->session_manager;
if (session_manager == NULL) {
pr_err("rga_session_manager is null!\n");
kfree(session);
return NULL;
return ERR_PTR(-EFAULT);
}
session = kzalloc(sizeof(*session), GFP_KERNEL);
if (!session) {
pr_err("rga_session alloc failed\n");
return ERR_PTR(-ENOMEM);
}
mutex_lock(&session_manager->lock);
idr_preload(GFP_KERNEL);
session->id = idr_alloc(&session_manager->ctx_id_idr, session, 1, 0, GFP_ATOMIC);
session_manager->session_cnt++;
new_id = idr_alloc_cyclic(&session_manager->ctx_id_idr, session, 1, 0, GFP_NOWAIT);
idr_preload_end();
if (new_id < 0) {
mutex_unlock(&session_manager->lock);
pr_err("rga_session alloc id failed!\n");
kfree(session);
return ERR_PTR(new_id);
}
session->id = new_id;
session_manager->session_cnt++;
mutex_unlock(&session_manager->lock);
@@ -1140,8 +1156,8 @@ static int rga_open(struct inode *inode, struct file *file)
struct rga_session *session = NULL;
session = rga_session_init();
if (!session)
return -ENOMEM;
if (IS_ERR(session))
return PTR_ERR(session);
file->private_data = (void *)session;

View File

@@ -14,42 +14,6 @@
#include "rga_iommu.h"
#include "rga_debugger.h"
struct rga_job *
rga_scheduler_get_pending_job_list(struct rga_scheduler_t *scheduler)
{
unsigned long flags;
struct rga_job *job;
spin_lock_irqsave(&scheduler->irq_lock, flags);
job = list_first_entry_or_null(&scheduler->todo_list,
struct rga_job, head);
spin_unlock_irqrestore(&scheduler->irq_lock, flags);
return job;
}
struct rga_job *
rga_scheduler_get_running_job(struct rga_scheduler_t *scheduler)
{
unsigned long flags;
struct rga_job *job;
spin_lock_irqsave(&scheduler->irq_lock, flags);
job = scheduler->running_job;
spin_unlock_irqrestore(&scheduler->irq_lock, flags);
return job;
}
struct rga_scheduler_t *rga_job_get_scheduler(struct rga_job *job)
{
return job->scheduler;
}
static void rga_job_free(struct rga_job *job)
{
free_page((unsigned long)job);
@@ -411,7 +375,7 @@ static struct rga_scheduler_t *rga_job_schedule(struct rga_job *job)
job->scheduler = rga_drvdata->scheduler[0];
}
scheduler = rga_job_get_scheduler(job);
scheduler = job->scheduler;
if (scheduler == NULL) {
pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__);
job->ret = -EFAULT;
@@ -832,8 +796,6 @@ int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job
rga_request_get(request);
mutex_unlock(&request_manager->lock);
rga_job_cleanup(job);
spin_lock_irqsave(&request->lock, flags);
if (job->ret < 0) {
@@ -848,6 +810,8 @@ int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job
spin_unlock_irqrestore(&request->lock, flags);
rga_job_cleanup(job);
if ((failed_count + finished_count) >= request->task_count) {
spin_lock_irqsave(&request->lock, flags);
@@ -1188,6 +1152,7 @@ static int rga_request_free_cb(int id, void *ptr, void *data)
int rga_request_alloc(uint32_t flags, struct rga_session *session)
{
int new_id;
struct rga_pending_request_manager *request_manager;
struct rga_request *request;
@@ -1218,17 +1183,17 @@ int rga_request_alloc(uint32_t flags, struct rga_session *session)
mutex_lock(&request_manager->lock);
idr_preload(GFP_KERNEL);
request->id = idr_alloc(&request_manager->request_idr, request, 1, 0, GFP_KERNEL);
new_id = idr_alloc_cyclic(&request_manager->request_idr, request, 1, 0, GFP_NOWAIT);
idr_preload_end();
if (request->id <= 0) {
pr_err("alloc request_id failed!\n");
if (new_id < 0) {
pr_err("request alloc id failed!\n");
mutex_unlock(&request_manager->lock);
kfree(request);
return -EFAULT;
return new_id;
}
request->id = new_id;
request_manager->request_count++;
mutex_unlock(&request_manager->lock);

View File

@@ -1869,7 +1869,7 @@ void rga_mm_unmap_job_info(struct rga_job *job)
uint32_t rga_mm_import_buffer(struct rga_external_buffer *external_buffer,
struct rga_session *session)
{
int ret = 0;
int ret = 0, new_id;
struct rga_mm *mm;
struct rga_internal_buffer *internal_buffer;
@@ -1911,9 +1911,14 @@ uint32_t rga_mm_import_buffer(struct rga_external_buffer *external_buffer,
* allocation under our spinlock.
*/
idr_preload(GFP_KERNEL);
internal_buffer->handle = idr_alloc(&mm->memory_idr, internal_buffer, 1, 0, GFP_KERNEL);
new_id = idr_alloc_cyclic(&mm->memory_idr, internal_buffer, 1, 0, GFP_NOWAIT);
idr_preload_end();
if (new_id < 0) {
pr_err("internal_buffer alloc id failed!\n");
goto FREE_INTERNAL_BUFFER;
}
internal_buffer->handle = new_id;
mm->buffer_count++;
if (DEBUGGER_EN(MM)) {

View File

@@ -7,6 +7,7 @@
#define __DW_HDMI__
#include <drm/drm_property.h>
#include <drm/drm_crtc.h>
#include <sound/hdmi-codec.h>
#include <media/cec.h>
@@ -248,8 +249,9 @@ struct dw_hdmi_plat_data {
u64 (*get_grf_color_fmt)(void *data);
void (*convert_to_split_mode)(struct drm_display_mode *mode);
void (*convert_to_origin_mode)(struct drm_display_mode *mode);
int (*dclk_set)(void *data, bool enable);
int (*dclk_set)(void *data, bool enable, int vp_id);
int (*link_clk_set)(void *data, bool enable);
int (*get_vp_id)(struct drm_crtc_state *crtc_state);
/* Vendor Property support */
const struct dw_hdmi_property_ops *property_ops;

View File

@@ -116,6 +116,7 @@
#define PCLK_GMAC 367
#define PCLK_PMU_PRE 368
#define PCLK_SIM_CARD 369
#define PCLK_MIPIPHY 370
/* hclk gates */
#define HCLK_SFC 439

View File

@@ -631,7 +631,7 @@
#define CLK_DSIHOST1 635
#define CLK_VOP_PMU 636
#define ACLK_VOP_DOBY 637
#define ACLK_VOP_SUB_SRC 638
#define ACLK_VOP_DIV2_SRC 638
#define CLK_USBDP_PHY0_IMMORTAL 639
#define CLK_USBDP_PHY1_IMMORTAL 640
#define CLK_PMU0 641

49
include/linux/sram_heap.h Normal file
View File

@@ -0,0 +1,49 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* SRAM DMA-Heap exporter && support alloc page and dmabuf on kernel
*
* Copyright (C) Rockchip Electronics Co., Ltd.
*
* Author: Huang Lee <Putin.li@rock-chips.com>
*/
#ifndef _LINUX_SRAM_HEAP_H
#define _LINUX_SRAM_HEAP_H
#include <linux/types.h>
#include <linux/dma-buf.h>
#include <linux/mm.h>
#if IS_REACHABLE(CONFIG_DMABUF_HEAPS_SRAM)
struct dma_buf *sram_heap_alloc_dma_buf(size_t size);
struct page *sram_heap_alloc_pages(size_t size);
void sram_heap_free_pages(struct page *p);
void sram_heap_free_dma_buf(struct dma_buf *dmabuf);
void *sram_heap_get_vaddr(struct dma_buf *dmabuf);
phys_addr_t sram_heap_get_paddr(struct dma_buf *dmabuf);
#else
static inline struct dma_buf *sram_heap_alloc_dma_buf(size_t size)
{
return NULL;
}
static inline struct page *sram_heap_alloc_pages(size_t size)
{
return NULL;
}
static inline void sram_heap_free_pages(struct page *p) {}
static inline void sram_heap_free_dma_buf(struct dma_buf *dmabuf) {}
static inline void *sram_heap_get_vaddr(struct dma_buf *dmabuf)
{
return NULL;
}
static inline phys_addr_t sram_heap_get_paddr(struct dma_buf *dmabuf)
{
return 0;
}
#endif
#endif

View File

@@ -161,6 +161,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RK3228
imply SND_SOC_RK3308
imply SND_SOC_RK3328
imply SND_SOC_RK730
imply SND_SOC_RK817
imply SND_SOC_RT274
imply SND_SOC_RT286
@@ -1096,6 +1097,10 @@ config SND_SOC_RK3328
tristate "Rockchip RK3328 audio CODEC"
select REGMAP_MMIO
config SND_SOC_RK730
tristate "Rockchip RK730 CODEC"
select REGMAP_I2C
config SND_SOC_RK817
tristate "Rockchip RK817 CODEC"
depends on MFD_RK808

View File

@@ -168,6 +168,7 @@ snd-soc-rk312x-objs := rk312x_codec.o
snd-soc-rk3228-objs := rk3228_codec.o
snd-soc-rk3308-objs := rk3308_codec.o
snd-soc-rk3328-objs := rk3328_codec.o
snd-soc-rk730-objs := rk730.o
snd-soc-rk817-objs := rk817_codec.o
snd-soc-rk-codec-digital-objs := rk_codec_digital.o
snd-soc-rl6231-objs := rl6231.o
@@ -492,6 +493,7 @@ obj-$(CONFIG_SND_SOC_RK312X) += snd-soc-rk312x.o
obj-$(CONFIG_SND_SOC_RK3228) += snd-soc-rk3228.o
obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
obj-$(CONFIG_SND_SOC_RK730) += snd-soc-rk730.o
obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o
obj-$(CONFIG_SND_SOC_RK_CODEC_DIGITAL) += snd-soc-rk-codec-digital.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o

971
sound/soc/codecs/rk730.c Normal file
View File

@@ -0,0 +1,971 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* rk730.c -- RK730 ALSA SoC Audio driver
*
* Copyright (C) 2022 Rockchip Electronics Co.,Ltd
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include "rk730.h"
enum rk730_mix_mode {
RK730_MIX_MODE_1_PATH,
RK730_MIX_MODE_2_PATHS,
RK730_MIX_MODE_3_PATHS,
};
enum rk730_chop_freq {
RK730_CHOP_FREQ_NONE,
RK730_CHOP_FREQ_200KHZ,
RK730_CHOP_FREQ_400KHZ,
RK730_CHOP_FREQ_800KHZ,
};
struct rk730_priv {
struct regmap *regmap;
struct clk *mclk;
atomic_t mix_mode;
};
/* ADC Digital Volume */
static const DECLARE_TLV_DB_SCALE(adc_dig_tlv, -95625, 375, 0);
/* DAC Digital Volume */
static const DECLARE_TLV_DB_SCALE(dac_dig_tlv, -95625, 375, 0);
/* D2S Volume */
static const DECLARE_TLV_DB_SCALE(d2s_tlv, -1800, 300, 0);
/* ADC Volume */
static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 300, 0);
/* MUX Volume */
static const DECLARE_TLV_DB_SCALE(mux_tlv, -600, 600, 0);
/* MIX Buf Volume */
static const DECLARE_TLV_DB_SCALE(mix_buf_tlv, -1800, 300, 0);
/* HP Volume */
static const DECLARE_TLV_DB_SCALE(hp_tlv, 0, 300, 0);
/* LINEOUT Volume */
static const DECLARE_TLV_DB_SCALE(lineout_tlv, 0, 300, 0);
/* MIC Boost Volume */
static const DECLARE_TLV_DB_RANGE(micboost_tlv,
0, 2, TLV_DB_SCALE_ITEM(0, 600, 0),
3, 4, TLV_DB_SCALE_ITEM(2400, 1200, 0),
5, 7, TLV_DB_SCALE_ITEM(4200, 600, 0),
8, 8, TLV_DB_SCALE_ITEM(-300, 0, 0),
16, 16, TLV_DB_SCALE_ITEM(-600, 0, 0),
24, 24, TLV_DB_SCALE_ITEM(-900, 0, 0)
);
static const char * const mux_out_l_text[] = { "DIFF", "MIC1N", "MIC2N" };
static const char * const mux_out_r_text[] = { "DIFF", "MIC2P", "MIC1P" };
static const char * const mux_input_l_text[] = { "DIFF", "VINP1", "VINN1" };
static const char * const mux_input_r_text[] = { "DIFF", "VINP2", "VINN2" };
static SOC_ENUM_SINGLE_DECL(mux_out_l_enum, RK730_MUXER_0, 2, mux_out_l_text);
static SOC_ENUM_SINGLE_DECL(mux_out_r_enum, RK730_MUXER_0, 6, mux_out_r_text);
static SOC_ENUM_SINGLE_DECL(mux_input_l_enum, RK730_ADC_PGA_BLOCK_0,
4, mux_input_l_text);
static SOC_ENUM_SINGLE_DECL(mux_input_r_enum, RK730_ADC_PGA_BLOCK_1,
4, mux_input_r_text);
static const struct snd_kcontrol_new mux_out_l =
SOC_DAPM_ENUM("Left Out Mux", mux_out_l_enum);
static const struct snd_kcontrol_new mux_out_r =
SOC_DAPM_ENUM("Right Out Mux", mux_out_r_enum);
static const struct snd_kcontrol_new mux_input_l =
SOC_DAPM_ENUM("Left Input Mux", mux_input_l_enum);
static const struct snd_kcontrol_new mux_input_r =
SOC_DAPM_ENUM("Right Input Mux", mux_input_r_enum);
static const struct snd_kcontrol_new mix_ctls[] = {
SOC_DAPM_SINGLE("Left Out Mux Switch", RK730_MUXER_0, 0, 1, 1),
SOC_DAPM_SINGLE("Right Out Mux Switch", RK730_MUXER_0, 4, 1, 1),
};
static const char * const adc_hpf_cutoff_text[] = {
"3.79Hz", "60Hz", "243Hz", "493Hz",
};
static const char * const dac_hpf_cutoff_text[] = {
"80Hz", "100Hz", "120Hz", "140Hz",
};
static SOC_ENUM_SINGLE_DECL(adc_hpf_cutoff_enum, RK730_DADC_HPF,
4, adc_hpf_cutoff_text);
static SOC_ENUM_SINGLE_DECL(dac_hpf_cutoff_enum, RK730_DDAC_MUTE_MIXCTL,
5, dac_hpf_cutoff_text);
static const char * const chop_freq_text[] = {
"Disabled", "200kHz", "400kHz", "800kHz",
};
static SOC_ENUM_SINGLE_DECL(dac_ref_buf_chop_freq_enum, RK730_HK_TOP_1,
6, chop_freq_text);
static SOC_ENUM_SINGLE_DECL(mic_chop_freq_enum, RK730_MIC_BOOST_3,
6, chop_freq_text);
static SOC_ENUM_SINGLE_DECL(adc_pga_chop_freq_enum, RK730_ADC_PGA_BLOCK_1,
6, chop_freq_text);
static SOC_ENUM_SINGLE_DECL(mux_out_chop_freq_enum, RK730_MUXER_1,
0, chop_freq_text);
static SOC_ENUM_SINGLE_DECL(mix_chop_freq_enum, RK730_MIXER_2,
6, chop_freq_text);
static SOC_ENUM_SINGLE_DECL(hp_lo_chop_freq_enum, RK730_HP_1,
5, chop_freq_text);
static const char * const micbias_volt_text[] = {
"2.0v", "2.2v", "2.5v", "2.8v",
};
static const char * const charge_pump_volt_text[] = {
"2.1v", "2.3v", "2.5v", "2.7v",
};
static SOC_ENUM_SINGLE_DECL(micbias_volt_enum, RK730_MIC_BIAS,
2, micbias_volt_text);
static SOC_ENUM_SINGLE_DECL(charge_pump_volt_enum, RK730_CHARGE_PUMP,
1, charge_pump_volt_text);
static int rk730_adc_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int val = snd_soc_component_read(component, mc->reg);
unsigned int sign = snd_soc_component_read(component, RK730_DADC_SR_ACL);
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int shift = mc->shift;
int mid = mc->max / 2;
int uv;
uv = (val >> shift) & mask;
sign &= RK730_DADC_SR_ACL_VOLL_POL_MASK;
if (sign)
uv = mid + uv;
else
uv = mid - uv;
ucontrol->value.integer.value[0] = uv;
ucontrol->value.integer.value[1] = uv;
return 0;
}
static int rk730_adc_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
unsigned int rreg = mc->rreg;
unsigned int shift = mc->shift;
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int val, val_mask, sign, sign_mask;
int uv = ucontrol->value.integer.value[0];
int min = mc->min;
int mid = mc->max / 2;
sign_mask = RK730_DADC_SR_ACL_VOLL_POL_MASK | RK730_DADC_SR_ACL_VOLR_POL_MASK;
if (uv > mid) {
sign = RK730_DADC_SR_ACL_VOLL_POS | RK730_DADC_SR_ACL_VOLR_POS;
uv = uv - mid;
} else {
sign = RK730_DADC_SR_ACL_VOLL_NEG | RK730_DADC_SR_ACL_VOLR_NEG;
uv = mid - uv;
}
val = ((uv + min) & mask);
val_mask = mask << shift;
val = val << shift;
snd_soc_component_update_bits(component, reg, val_mask, val);
snd_soc_component_update_bits(component, rreg, val_mask, val);
snd_soc_component_update_bits(component, RK730_DADC_SR_ACL, sign_mask, sign);
return 1;
}
static int rk730_dac_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int val = snd_soc_component_read(component, mc->reg);
unsigned int sign = snd_soc_component_read(component, RK730_DDAC_SR_LMT);
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int shift = mc->shift;
int mid = mc->max / 2;
int uv;
uv = (val >> shift) & mask;
sign &= RK730_DDAC_SR_LMT_VOLL_POL_MASK;
if (sign)
uv = mid + uv;
else
uv = mid - uv;
ucontrol->value.integer.value[0] = uv;
ucontrol->value.integer.value[1] = uv;
return 0;
}
static int rk730_dac_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
unsigned int rreg = mc->rreg;
unsigned int shift = mc->shift;
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int val, val_mask, sign, sign_mask;
int uv = ucontrol->value.integer.value[0];
int min = mc->min;
int mid = mc->max / 2;
sign_mask = RK730_DDAC_SR_LMT_VOLL_POL_MASK | RK730_DDAC_SR_LMT_VOLR_POL_MASK;
if (uv > mid) {
sign = RK730_DDAC_SR_LMT_VOLL_POS | RK730_DDAC_SR_LMT_VOLR_POS;
uv = uv - mid;
} else {
sign = RK730_DDAC_SR_LMT_VOLL_NEG | RK730_DDAC_SR_LMT_VOLR_NEG;
uv = mid - uv;
}
val = ((uv + min) & mask);
val_mask = mask << shift;
val = val << shift;
snd_soc_component_update_bits(component, reg, val_mask, val);
snd_soc_component_update_bits(component, rreg, val_mask, val);
snd_soc_component_update_bits(component, RK730_DDAC_SR_LMT, sign_mask, sign);
return 1;
}
static int rk730_cp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
if (SND_SOC_DAPM_EVENT_ON(event))
usleep_range(5000, 5100);
return 0;
}
static int rk730_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
if (SND_SOC_DAPM_EVENT_ON(event))
snd_soc_component_write(component, RK730_SYSPLL_0, 0x00);
else
snd_soc_component_write(component, RK730_SYSPLL_0, 0xff);
return 0;
}
static int rk730_adc_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
if (SND_SOC_DAPM_EVENT_ON(event)) {
snd_soc_component_update_bits(component, RK730_ADC_0,
RK730_ADC_0_DEM_EN_MASK,
RK730_ADC_0_DEM_EN);
snd_soc_component_update_bits(component, RK730_DTOP_DIGEN_CLKE,
RK730_DTOP_DIGEN_CLKE_ADC_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_I2STX_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_ADC_EN_MASK |
RK730_DTOP_DIGEN_CLKE_I2STX_EN_MASK,
RK730_DTOP_DIGEN_CLKE_ADC_CKE_EN |
RK730_DTOP_DIGEN_CLKE_I2STX_CKE_EN |
RK730_DTOP_DIGEN_CLKE_ADC_EN |
RK730_DTOP_DIGEN_CLKE_I2STX_EN);
usleep_range(20000, 21000);
snd_soc_component_update_bits(component, RK730_DI2S_TXCR_3_TXCMD,
RK730_DI2S_TXCR_3_TXCMD_TXS_MASK,
RK730_DI2S_TXCR_3_TXCMD_TXS_EN);
} else {
snd_soc_component_update_bits(component, RK730_DI2S_TXCR_3_TXCMD,
RK730_DI2S_TXCR_3_TXCMD_TXS_MASK,
RK730_DI2S_TXCR_3_TXCMD_TXS_DIS);
snd_soc_component_update_bits(component, RK730_ADC_0,
RK730_ADC_0_DEM_EN_MASK,
RK730_ADC_0_DEM_DIS);
snd_soc_component_update_bits(component, RK730_DTOP_DIGEN_CLKE,
RK730_DTOP_DIGEN_CLKE_ADC_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_I2STX_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_ADC_EN_MASK |
RK730_DTOP_DIGEN_CLKE_I2STX_EN_MASK,
RK730_DTOP_DIGEN_CLKE_ADC_CKE_DIS |
RK730_DTOP_DIGEN_CLKE_I2STX_CKE_DIS |
RK730_DTOP_DIGEN_CLKE_ADC_DIS |
RK730_DTOP_DIGEN_CLKE_I2STX_DIS);
}
return 0;
}
static int rk730_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
if (SND_SOC_DAPM_EVENT_ON(event)) {
snd_soc_component_update_bits(component, RK730_DTOP_DIGEN_CLKE,
RK730_DTOP_DIGEN_CLKE_DAC_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_I2SRX_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_DAC_EN_MASK |
RK730_DTOP_DIGEN_CLKE_I2SRX_EN_MASK,
RK730_DTOP_DIGEN_CLKE_DAC_CKE_EN |
RK730_DTOP_DIGEN_CLKE_I2SRX_CKE_EN |
RK730_DTOP_DIGEN_CLKE_DAC_EN |
RK730_DTOP_DIGEN_CLKE_I2SRX_EN);
snd_soc_component_update_bits(component, RK730_DI2S_RXCMD_TSD,
RK730_DI2S_RXCMD_TSD_RXS_MASK,
RK730_DI2S_RXCMD_TSD_RXS_EN);
} else {
snd_soc_component_update_bits(component, RK730_DI2S_RXCMD_TSD,
RK730_DI2S_RXCMD_TSD_RXS_MASK,
RK730_DI2S_RXCMD_TSD_RXS_DIS);
snd_soc_component_update_bits(component, RK730_DTOP_DIGEN_CLKE,
RK730_DTOP_DIGEN_CLKE_DAC_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_I2SRX_CKE_MASK |
RK730_DTOP_DIGEN_CLKE_DAC_EN_MASK |
RK730_DTOP_DIGEN_CLKE_I2SRX_EN_MASK,
RK730_DTOP_DIGEN_CLKE_DAC_CKE_DIS |
RK730_DTOP_DIGEN_CLKE_I2SRX_CKE_DIS |
RK730_DTOP_DIGEN_CLKE_DAC_DIS |
RK730_DTOP_DIGEN_CLKE_I2SRX_DIS);
}
return 0;
}
static int rk730_mux_out_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct rk730_priv *rk730 = snd_soc_component_get_drvdata(component);
unsigned int val;
if (SND_SOC_DAPM_EVENT_ON(event))
val = atomic_inc_return(&rk730->mix_mode);
else
val = atomic_dec_return(&rk730->mix_mode);
snd_soc_component_update_bits(component, RK730_MIXER_2,
RK730_MIXER_2_MIX_R_MODE_MASK |
RK730_MIXER_2_MIX_L_MODE_MASK,
RK730_MIXER_2_MIX_R_MODE(val) |
RK730_MIXER_2_MIX_L_MODE(val));
return 0;
}
static const struct snd_kcontrol_new rk730_snd_controls[] = {
SOC_DOUBLE_R_TLV("ADC Volume", RK730_ADC_PGA_BLOCK_0, RK730_ADC_PGA_BLOCK_1,
1, 0x7, 1, adc_tlv),
SOC_DOUBLE_R_TLV("D2S Volume", RK730_DAC_1, RK730_DAC_2,
1, 0x6, 1, d2s_tlv),
SOC_DOUBLE_R_TLV("MIC1 Boost Volume", RK730_MIC_BOOST_0, RK730_MIC_BOOST_1,
1, 0x18, 0, micboost_tlv),
SOC_DOUBLE_R_TLV("MIC2 Boost Volume", RK730_MIC_BOOST_2, RK730_MIC_BOOST_3,
1, 0x18, 0, micboost_tlv),
SOC_DOUBLE_TLV("Out Mux Volume", RK730_MUXER_0, 1, 5, 0x1, 0, mux_tlv),
SOC_SINGLE_TLV("Left Out Mux -> Left Out Mixer Volume",
RK730_MIXER_0, 1, 0x6, 1, mix_buf_tlv),
SOC_SINGLE_TLV("Left Out Mux -> Right Out Mixer Volume",
RK730_MIXER_0, 5, 0x6, 1, mix_buf_tlv),
SOC_SINGLE_TLV("Right Out Mux -> Left Out Mixer Volume",
RK730_MIXER_1, 1, 0x6, 1, mix_buf_tlv),
SOC_SINGLE_TLV("Right Out Mux -> Right Out Mixer Volume",
RK730_MIXER_1, 5, 0x6, 1, mix_buf_tlv),
SOC_SINGLE_TLV("HP Volume", RK730_HP_0, 6, 0x3, 0, hp_tlv),
SOC_SINGLE_TLV("Line Out Volume", RK730_LINEOUT_1, 2, 0x3, 0, lineout_tlv),
SOC_DOUBLE_R_EXT_TLV("ADC Digital Volume",
RK730_DADC_VOLL, RK730_DADC_VOLR, 0, 0x1fe, 0,
rk730_adc_vol_get,
rk730_adc_vol_put,
adc_dig_tlv),
SOC_DOUBLE_R_EXT_TLV("DAC Digital Volume",
RK730_DDAC_VOLL, RK730_DDAC_VOLR, 0, 0x1fe, 0,
rk730_dac_vol_get,
rk730_dac_vol_put,
dac_dig_tlv),
SOC_ENUM("ADC HPF Cutoff", adc_hpf_cutoff_enum),
SOC_ENUM("DAC HPF Cutoff", dac_hpf_cutoff_enum),
SOC_ENUM("DAC Ref Buf Chop Freq", dac_ref_buf_chop_freq_enum),
SOC_ENUM("MIC Chop Freq", mic_chop_freq_enum),
SOC_ENUM("ADC PGA Chop Freq", adc_pga_chop_freq_enum),
SOC_ENUM("Out Mux Chop Freq", mux_out_chop_freq_enum),
SOC_ENUM("Mixer Chop Freq", mix_chop_freq_enum),
SOC_ENUM("HP / Lineout Chop Freq", hp_lo_chop_freq_enum),
SOC_ENUM("Mic Bias Volt", micbias_volt_enum),
SOC_ENUM("Charge Pump Volt", charge_pump_volt_enum),
SOC_SINGLE("ADCL HPF Switch", RK730_DADC_HPF, 7, 1, 0),
SOC_SINGLE("ADCR HPF Switch", RK730_DADC_HPF, 6, 1, 0),
SOC_SINGLE("DAC HPF Switch", RK730_DDAC_MUTE_MIXCTL, 7, 1, 0),
SOC_SINGLE("ADC Volume Bypass Switch", RK730_DTOP_VUCTL, 7, 1, 0),
SOC_SINGLE("DAC Volume Bypass Switch", RK730_DTOP_VUCTL, 6, 1, 0),
SOC_SINGLE("ADC Fade Switch", RK730_DTOP_VUCTL, 5, 1, 0),
SOC_SINGLE("DAC Fade Switch", RK730_DTOP_VUCTL, 4, 1, 0),
SOC_SINGLE("ADC Zero Crossing Switch", RK730_DTOP_VUCTL, 1, 1, 0),
SOC_SINGLE("DAC Zero Crossing Switch", RK730_DTOP_VUCTL, 0, 1, 0),
SOC_SINGLE("MIC1N / MIC2P Exchanged Switch", RK730_MIC_BOOST_2, 7, 1, 0),
};
static const struct snd_soc_dapm_widget rk730_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY_S("ANA LDO", 0, RK730_LDO, 7, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("OSC CLK", 1, RK730_HK_TOP_2, 4, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("VAG BUF", 1, RK730_HK_TOP_2, 2, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC BUF", 1, RK730_HK_TOP_2, 1, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DAC BUF", 1, RK730_HK_TOP_2, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("MICBIAS", 1, RK730_MIC_BIAS, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RK730_CHARGE_PUMP, 0, 0,
rk730_cp_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY_S("PLL", 2, SND_SOC_NOPM, 0, 0, rk730_pll_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S("DAC Bias", 2, RK730_DAC_0, 2, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("HP Bias", 2, RK730_HP_0, 5, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("Line Out Bias", 2, RK730_LINEOUT_1, 7, 1, NULL, 0),
SND_SOC_DAPM_ADC_E("ADCL", "HiFi Capture", RK730_ADC_0, 0, 1,
rk730_adc_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADCR", "HiFi Capture", RK730_ADC_0, 1, 1,
rk730_adc_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_DAC_E("DACL", "HiFi Playback", RK730_DAC_0, 0, 1,
rk730_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_DAC_E("DACR", "HiFi Playback", RK730_DAC_0, 1, 1,
rk730_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA("ADCL PGA", RK730_ADC_PGA_BLOCK_0, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("ADCR PGA", RK730_ADC_PGA_BLOCK_1, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("D2SL", RK730_DAC_1, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("D2SR", RK730_DAC_2, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("MIC1P", RK730_MIC_BOOST_0, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("MIC1N", RK730_MIC_BOOST_1, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("MIC2P", RK730_MIC_BOOST_2, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("MIC2N", RK730_MIC_BOOST_3, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("DIFFL", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("DIFFR", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("HP Out", RK730_HP_0, 2, 1, NULL, 0),
SND_SOC_DAPM_PGA("HP Out Stage", RK730_HP_0, 3, 1, NULL, 0),
SND_SOC_DAPM_PGA("Line Out", RK730_LINEOUT_0, 2, 1, NULL, 0),
SND_SOC_DAPM_PGA("Line Out Stage", RK730_LINEOUT_0, 3, 1, NULL, 0),
SND_SOC_DAPM_MUX_E("Left Out Mux", SND_SOC_NOPM, 0, 0, &mux_out_l,
rk730_mux_out_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("Right Out Mux", SND_SOC_NOPM, 0, 0, &mux_out_r,
rk730_mux_out_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &mux_input_l),
SND_SOC_DAPM_MUX("Right Input Mux", SND_SOC_NOPM, 0, 0, &mux_input_r),
SND_SOC_DAPM_MIXER("Left Out Mixer", RK730_MIXER_2, 0, 1,
mix_ctls, ARRAY_SIZE(mix_ctls)),
SND_SOC_DAPM_MIXER("Right Out Mixer", RK730_MIXER_2, 3, 1,
mix_ctls, ARRAY_SIZE(mix_ctls)),
SND_SOC_DAPM_OUTPUT("HPL"),
SND_SOC_DAPM_OUTPUT("HPR"),
SND_SOC_DAPM_OUTPUT("LINEOUTL"),
SND_SOC_DAPM_OUTPUT("LINEOUTR"),
SND_SOC_DAPM_INPUT("MIC1"),
SND_SOC_DAPM_INPUT("MIC2"),
};
static const struct snd_soc_dapm_route rk730_dapm_routes[] = {
{ "DACL", NULL, "ANA LDO" },
{ "DACR", NULL, "ANA LDO" },
{ "DACL", NULL, "OSC CLK" },
{ "DACR", NULL, "OSC CLK" },
{ "DACL", NULL, "VAG BUF" },
{ "DACR", NULL, "VAG BUF" },
{ "DACL", NULL, "DAC BUF" },
{ "DACR", NULL, "DAC BUF" },
{ "DACL", NULL, "PLL" },
{ "DACR", NULL, "PLL" },
{ "DACL", NULL, "DAC Bias" },
{ "DACR", NULL, "DAC Bias" },
{ "D2SL", NULL, "DACL" },
{ "D2SR", NULL, "DACR" },
{ "Left Out Mixer", NULL, "D2SL" },
{ "Left Out Mixer", "Left Out Mux Switch", "Left Out Mux" },
{ "Left Out Mixer", "Right Out Mux Switch", "Right Out Mux" },
{ "Right Out Mixer", NULL, "D2SR" },
{ "Right Out Mixer", "Left Out Mux Switch", "Left Out Mux" },
{ "Right Out Mixer", "Right Out Mux Switch", "Right Out Mux" },
{ "Left Out Mux", "DIFF", "DIFFL" },
{ "Left Out Mux", "MIC1N", "MIC1N" },
{ "Left Out Mux", "MIC2N", "MIC2N" },
{ "Right Out Mux", "DIFF", "DIFFR" },
{ "Right Out Mux", "MIC1P", "MIC1P" },
{ "Right Out Mux", "MIC2P", "MIC2P" },
{ "HP Out", NULL, "HP Bias" },
{ "HP Out", NULL, "HP Bias" },
{ "Line Out", NULL, "Line Out Bias" },
{ "HP Out", NULL, "Left Out Mixer" },
{ "HP Out", NULL, "Right Out Mixer" },
{ "Line Out", NULL, "Left Out Mixer" },
{ "Line Out", NULL, "Right Out Mixer" },
{ "HP Out Stage", NULL, "HP Out" },
{ "Line Out Stage", NULL, "Line Out" },
{ "HPL", NULL, "HP Out Stage" },
{ "HPR", NULL, "HP Out Stage" },
{ "HPL", NULL, "Charge Pump" },
{ "HPR", NULL, "Charge Pump" },
{ "LINEOUTL", NULL, "Line Out Stage" },
{ "LINEOUTR", NULL, "Line Out Stage" },
{ "LINEOUTL", NULL, "Charge Pump" },
{ "LINEOUTR", NULL, "Charge Pump" },
{ "ADCL", NULL, "ANA LDO" },
{ "ADCR", NULL, "ANA LDO" },
{ "ADCL", NULL, "OSC CLK" },
{ "ADCR", NULL, "OSC CLK" },
{ "ADCL", NULL, "ADC BUF" },
{ "ADCR", NULL, "ADC BUF" },
{ "ADCL", NULL, "VAG BUF" },
{ "ADCR", NULL, "VAG BUF" },
{ "ADCL", NULL, "PLL" },
{ "ADCR", NULL, "PLL" },
{ "ADCL", NULL, "ADCL PGA" },
{ "ADCR", NULL, "ADCR PGA" },
{ "ADCL PGA", NULL, "Left Input Mux" },
{ "ADCR PGA", NULL, "Right Input Mux" },
{ "Left Input Mux", "DIFF", "DIFFL" },
{ "Left Input Mux", "VINP1", "MIC1P" },
{ "Left Input Mux", "VINN1", "MIC1N" },
{ "Right Input Mux", "DIFF", "DIFFR" },
{ "Right Input Mux", "VINP2", "MIC2P" },
{ "Right Input Mux", "VINN2", "MIC2N" },
{ "DIFFL", NULL, "MIC1P" },
{ "DIFFL", NULL, "MIC1N" },
{ "DIFFR", NULL, "MIC2P" },
{ "DIFFR", NULL, "MIC2N" },
{ "MIC1P", NULL, "MIC1" },
{ "MIC1N", NULL, "MIC1" },
{ "MIC2P", NULL, "MIC2" },
{ "MIC2N", NULL, "MIC2" },
{ "MIC1", NULL, "MICBIAS" },
{ "MIC2", NULL, "MICBIAS" },
};
static unsigned int samplerate_to_bit(unsigned int samplerate)
{
switch (samplerate) {
case 8000:
case 11025:
case 12000:
return 0;
case 16000:
case 22050:
case 24000:
return 1;
case 32000:
case 44100:
case 48000:
return 2;
case 64000:
case 88200:
case 96000:
return 3;
case 128000:
case 176400:
case 192000:
return 4;
default:
return 2;
}
}
static int rk730_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
unsigned int width, rate;
width = min(params_width(params), 24);
rate = samplerate_to_bit(params_rate(params));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
snd_soc_component_update_bits(component, RK730_DI2S_RXCR_2,
RK730_DI2S_XCR2_VDW_MASK,
RK730_DI2S_XCR2_VDW(width));
snd_soc_component_update_bits(component, RK730_DDAC_SR_LMT,
RK730_DDAC_SR_LMT_SRT_MASK,
RK730_DDAC_SR_LMT_SRT(rate));
} else {
snd_soc_component_update_bits(component, RK730_DI2S_TXCR_2,
RK730_DI2S_XCR2_VDW_MASK,
RK730_DI2S_XCR2_VDW(width));
snd_soc_component_update_bits(component, RK730_DADC_SR_ACL,
RK730_DADC_SR_ACL_SRT_MASK,
RK730_DADC_SR_ACL_SRT(rate));
}
return 0;
}
static int rk730_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_component *component = codec_dai->component;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
snd_soc_component_update_bits(component, RK730_DI2S_CKM,
RK730_DI2S_CKM_MST_MASK,
RK730_DI2S_CKM_MST_SLAVE);
break;
case SND_SOC_DAIFMT_CBM_CFM:
snd_soc_component_update_bits(component, RK730_DI2S_CKM,
RK730_DI2S_CKM_MST_MASK,
RK730_DI2S_CKM_MST_MASTER);
break;
default:
return -EINVAL;
}
return 0;
}
static int rk730_dai_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
{
struct snd_soc_component *component = codec_dai->component;
if (mute)
snd_soc_component_update_bits(component, RK730_DDAC_MUTE_MIXCTL,
RK730_DDAC_MUTE_MIXCTL_MUTE_MASK,
RK730_DDAC_MUTE_MIXCTL_MUTE);
else
snd_soc_component_update_bits(component, RK730_DDAC_MUTE_MIXCTL,
RK730_DDAC_MUTE_MIXCTL_MUTE_MASK,
RK730_DDAC_MUTE_MIXCTL_UNMUTE);
return 0;
}
static int rk730_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rk730_priv *rk730 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
/*
* SND_SOC_BIAS_PREPARE is called while preparing for a
* transition to ON or away from ON. If current bias_level
* is SND_SOC_BIAS_ON, then it is preparing for a transition
* away from ON. Disable the clock in that case, otherwise
* enable it.
*/
if (!IS_ERR(rk730->mclk)) {
if (snd_soc_component_get_bias_level(component) ==
SND_SOC_BIAS_ON)
clk_disable_unprepare(rk730->mclk);
else
clk_prepare_enable(rk730->mclk);
}
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
regcache_sync(rk730->regmap);
break;
case SND_SOC_BIAS_OFF:
regcache_mark_dirty(rk730->regmap);
break;
}
return 0;
}
#define RK730_RATES SNDRV_PCM_RATE_8000_192000
#define RK730_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops rk730_dai_ops = {
.set_fmt = rk730_dai_set_fmt,
.hw_params = rk730_dai_hw_params,
.mute_stream = rk730_dai_mute,
.no_capture_mute = 1,
};
static struct snd_soc_dai_driver rk730_dai = {
.name = "HiFi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
.channels_max = 2,
.rates = RK730_RATES,
.formats = RK730_FORMATS,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 1,
.channels_max = 2,
.rates = RK730_RATES,
.formats = RK730_FORMATS,
},
.ops = &rk730_dai_ops,
};
static int rk730_reset(struct snd_soc_component *component)
{
struct rk730_priv *rk730 = snd_soc_component_get_drvdata(component);
clk_prepare_enable(rk730->mclk);
snd_soc_component_write(component, RK730_DTOP_LPT_SRST, 0x40);
udelay(10);
/* WA: Initial micbias default, ADC stopped with micbias(>2.5v) */
snd_soc_component_update_bits(component, RK730_MIC_BIAS,
RK730_MIC_BIAS_VOLT_MASK,
RK730_MIC_BIAS_VOLT_2_2V);
/* PF: Use the maximum bias current for better performance */
snd_soc_component_update_bits(component, RK730_HK_TOP_1,
RK730_HK_TOP_1_IBIAS_STD_SEL_MASK |
RK730_HK_TOP_1_IBIAS_GAIN_SEL_MASK,
RK730_HK_TOP_1_IBIAS_STD_SEL_27_5UA |
RK730_HK_TOP_1_IBIAS_GAIN_SEL_200);
/* PF: Use the chop 400kHz for better ADC noise performance */
snd_soc_component_update_bits(component, RK730_MIC_BOOST_3,
RK730_MIC_BOOST_3_MIC_CHOP_MASK,
RK730_MIC_BOOST_3_MIC_CHOP(RK730_CHOP_FREQ_400KHZ));
snd_soc_component_update_bits(component, RK730_ADC_PGA_BLOCK_1,
RK730_ADC_PGA_BLOCK_1_PGA_CHOP_MASK,
RK730_ADC_PGA_BLOCK_1_PGA_CHOP(RK730_CHOP_FREQ_400KHZ));
clk_disable_unprepare(rk730->mclk);
return 0;
}
static int rk730_probe(struct snd_soc_component *component)
{
struct rk730_priv *rk730 = snd_soc_component_get_drvdata(component);
int ret = 0;
regcache_mark_dirty(rk730->regmap);
/* initialize private data */
atomic_set(&rk730->mix_mode, RK730_MIX_MODE_1_PATH);
ret = snd_soc_component_read(component, RK730_HK_TOP_0);
if (ret < 0) {
dev_err(component->dev, "Failed to read register: %d\n", ret);
return ret;
}
rk730_reset(component);
return ret;
}
static const struct snd_soc_component_driver rk730_component_driver = {
.probe = rk730_probe,
.set_bias_level = rk730_set_bias_level,
.controls = rk730_snd_controls,
.num_controls = ARRAY_SIZE(rk730_snd_controls),
.dapm_widgets = rk730_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk730_dapm_widgets),
.dapm_routes = rk730_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(rk730_dapm_routes),
.suspend_bias_off = 1,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static const struct reg_default rk730_reg_defaults[] = {
{ 0x00, 0x40 },
{ 0x02, 0x17 },
{ 0x05, 0x03 },
{ 0x06, 0x22 },
{ 0x07, 0x02 },
{ 0x08, 0x07 },
{ 0x09, 0x01 },
{ 0x0a, 0x01 },
{ 0x0b, 0x01 },
{ 0x0c, 0x01 },
{ 0x0d, 0x01 },
{ 0x0e, 0x01 },
{ 0x0f, 0x07 },
{ 0x10, 0x07 },
{ 0x11, 0xff },
{ 0x12, 0x07 },
{ 0x13, 0x54 },
{ 0x14, 0x04 },
{ 0x15, 0x23 },
{ 0x16, 0x35 },
{ 0x17, 0x67 },
{ 0x18, 0x1e },
{ 0x19, 0xc0 },
{ 0x1a, 0x13 },
{ 0x1b, 0x04 },
{ 0x1c, 0x20 },
{ 0x1f, 0x90 },
{ 0x20, 0x11 },
{ 0x21, 0x09 },
{ 0x22, 0x33 },
{ 0x24, 0x11 },
{ 0x25, 0x11 },
{ 0x26, 0x09 },
{ 0x27, 0x02 },
{ 0x28, 0x2c },
{ 0x2a, 0x0c },
{ 0x2b, 0x80 },
{ 0x40, 0x03 },
{ 0x42, 0x20 },
{ 0x47, 0xe6 },
{ 0x48, 0xd0 },
{ 0x49, 0x17 },
{ 0x4a, 0x26 },
{ 0x4b, 0x01 },
{ 0x4c, 0x05 },
{ 0x4d, 0x0e },
{ 0x4e, 0x09 },
{ 0x4f, 0x02 },
{ 0x5b, 0xe6 },
{ 0x5c, 0xd0 },
{ 0x5d, 0x17 },
{ 0x5e, 0x26 },
{ 0x5f, 0x01 },
{ 0x60, 0x05 },
{ 0x61, 0x0e },
{ 0x62, 0x09 },
{ 0x63, 0x20 },
{ 0x66, 0x01 },
{ 0x69, 0x17 },
{ 0x6c, 0x17 },
};
static bool rk730_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case RK730_DTOP_LPT_SRST:
return true;
default:
return false;
}
}
static const struct regmap_config rk730_regmap = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = rk730_volatile_register,
.max_register = RK730_DAC_ATTN,
.reg_defaults = rk730_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rk730_reg_defaults),
.cache_type = REGCACHE_RBTREE,
};
static int rk730_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct rk730_priv *rk730;
int ret;
rk730 = devm_kzalloc(&i2c->dev, sizeof(struct rk730_priv), GFP_KERNEL);
if (!rk730)
return -ENOMEM;
rk730->regmap = devm_regmap_init_i2c(i2c, &rk730_regmap);
if (IS_ERR(rk730->regmap))
return PTR_ERR(rk730->regmap);
rk730->mclk = devm_clk_get(&i2c->dev, "mclk");
if (IS_ERR(rk730->mclk))
return PTR_ERR(rk730->mclk);
i2c_set_clientdata(i2c, rk730);
ret = devm_snd_soc_register_component(&i2c->dev,
&rk730_component_driver, &rk730_dai, 1);
return ret;
}
static const struct i2c_device_id rk730_i2c_id[] = {
{ "rk730", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rk730_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id rk730_of_match[] = {
{ .compatible = "rockchip,rk730" },
{ }
};
MODULE_DEVICE_TABLE(of, rk730_of_match);
#endif
static struct i2c_driver rk730_i2c_driver = {
.driver = {
.name = "rk730",
.of_match_table = of_match_ptr(rk730_of_match),
},
.probe = rk730_i2c_probe,
.id_table = rk730_i2c_id,
};
module_i2c_driver(rk730_i2c_driver);
MODULE_DESCRIPTION("ASoC RK730 driver");
MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
MODULE_LICENSE("GPL");

239
sound/soc/codecs/rk730.h Normal file
View File

@@ -0,0 +1,239 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* rk730.h -- RK730 ALSA SoC Audio driver
*
* Copyright (C) 2022 Rockchip Electronics Co.,Ltd
*/
#ifndef _RK730_H
#define _RK730_H
/* RK730 Analog Registers Definition */
#define RK730_HK_TOP_0 0x00
#define RK730_HK_TOP_1 0x01
#define RK730_HK_TOP_2 0x02
#define RK730_HK_TRIM_0 0x03
#define RK730_HK_TRIM_1 0x04
#define RK730_ADC_0 0x05
#define RK730_ADC_1 0x06
#define RK730_ADC_2 0x07
#define RK730_DAC_0 0x08
#define RK730_DAC_1 0x09
#define RK730_DAC_2 0x0a
#define RK730_MIC_BOOST_0 0x0b
#define RK730_MIC_BOOST_1 0x0c
#define RK730_MIC_BOOST_2 0x0d
#define RK730_MIC_BOOST_3 0x0e
#define RK730_ADC_PGA_BLOCK_0 0x0f
#define RK730_ADC_PGA_BLOCK_1 0x10
#define RK730_SYSPLL_0 0x11
#define RK730_SYSPLL_1 0x12
#define RK730_SYSPLL_2 0x13
#define RK730_SYSPLL_3 0x14
#define RK730_SYSPLL_LOOP_0 0x15
#define RK730_SYSPLL_LOOP_1 0x16
#define RK730_SYSPLL_LOOP_2 0x17
#define RK730_SYSPLL_LOOP_3 0x18
#define RK730_SYSPLL_RVCO_0 0x19
#define RK730_SYSPLL_RVCO_1 0x1a
#define RK730_SYSPLL_RVCO_2 0x1b
#define RK730_SYSPLL_RVCO_3 0x1c
#define RK730_SYSPLL_FRACT_0 0x1d
#define RK730_SYSPLL_FRACT_1 0x1e
#define RK730_SYSPLL_FRACT_2 0x1f
#define RK730_LDO 0x20
#define RK730_MIC_BIAS 0x21
#define RK730_MUXER_0 0x22
#define RK730_MUXER_1 0x23
#define RK730_MIXER_0 0x24
#define RK730_MIXER_1 0x25
#define RK730_MIXER_2 0x26
#define RK730_CHARGE_PUMP 0x27
#define RK730_HP_0 0x28
#define RK730_HP_1 0x29
#define RK730_LINEOUT_0 0x2a
#define RK730_LINEOUT_1 0x2b
/* RK730 Digital Registers Definition */
#define RK730_DTOP_VUCTL 0x40
#define RK730_DTOP_VUCTIME 0x41
#define RK730_DTOP_LPT_SRST 0x42
#define RK730_DTOP_DIGEN_CLKE 0x43
#define RK730_DADC_VOLL 0x44
#define RK730_DADC_VOLR 0x45
#define RK730_DADC_SR_ACL 0x46
#define RK730_DADC_PR_0 0x47
#define RK730_DADC_PR_1 0x48
#define RK730_DADC_PR_2 0x49
#define RK730_DADC_PR_3 0x4a
#define RK730_DADC_NG_0 0x4b
#define RK730_DADC_NG_1 0x4c
#define RK730_DADC_NG_2 0x4d
#define RK730_DADC_NG_3 0x4e
#define RK730_DADC_CICCOMP 0x4f
#define RK730_DADC_HPF 0x50
#define RK730_DADC_RVOLL 0x51
#define RK730_DADC_RVOLR 0x52
#define RK730_DMIC_LMT_1 0x53
#define RK730_DMIC_LMT_2 0x54
#define RK730_DMIC_NG_1 0x55
#define RK730_DMIC_NG_2 0x56
#define RK730_DDAC_POPD_DACST 0x57
#define RK730_DDAC_VOLL 0x58
#define RK730_DDAC_VOLR 0x59
#define RK730_DDAC_SR_LMT 0x5a
#define RK730_DDAC_PR_0 0x5b
#define RK730_DDAC_PR_1 0x5c
#define RK730_DDAC_PR_2 0x5d
#define RK730_DDAC_PR_3 0x5e
#define RK730_DDAC_NG_0 0x5f
#define RK730_DDAC_NG_1 0x60
#define RK730_DDAC_NG_2 0x61
#define RK730_DDAC_NG_3 0x62
#define RK730_DDAC_MUTE_MIXCTL 0x63
#define RK730_DDAC_RVOLL 0x64
#define RK730_DDAC_RVOLR 0x65
#define RK730_DI2S_CKM 0x66
#define RK730_DI2S_RSD 0x67
#define RK730_DI2S_RXCR_1 0x68
#define RK730_DI2S_RXCR_2 0x69
#define RK730_DI2S_RXCMD_TSD 0x6a
#define RK730_DI2S_TXCR_1 0x6b
#define RK730_DI2S_TXCR_2 0x6c
#define RK730_DI2S_TXCR_3_TXCMD 0x6d
#define RK730_DAC_ATTN 0x6e
/* RK730_HK_TOP_1 */
#define RK730_HK_TOP_1_DAC_REF_BUF_CHOP_MASK GENMASK(7, 6)
#define RK730_HK_TOP_1_DAC_REF_BUF_CHOP(x) ((x) << 6)
#define RK730_HK_TOP_1_IBIAS_STD_SEL_MASK GENMASK(5, 4)
#define RK730_HK_TOP_1_IBIAS_STD_SEL_27_5UA (3 << 4)
#define RK730_HK_TOP_1_IBIAS_STD_SEL_23_5UA (2 << 4)
#define RK730_HK_TOP_1_IBIAS_STD_SEL_20UA (1 << 4)
#define RK730_HK_TOP_1_IBIAS_STD_SEL_16_5UA (0 << 4)
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_MASK GENMASK(3, 0)
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_200 8
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_143 9
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_120 10
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_100 0
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_71_5 1
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_62_5 2
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_50 3
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_38_2 6
#define RK730_HK_TOP_1_IBIAS_GAIN_SEL_32 7
/* RK730_ADC_0 */
#define RK730_ADC_0_DEM_EN_MASK BIT(3)
#define RK730_ADC_0_DEM_EN BIT(3)
#define RK730_ADC_0_DEM_DIS 0
/* RK730_MIC_BOOST_3 */
#define RK730_MIC_BOOST_3_MIC_CHOP_MASK GENMASK(7, 6)
#define RK730_MIC_BOOST_3_MIC_CHOP(x) ((x) << 6)
/* RK730_ADC_PGA_BLOCK_1 */
#define RK730_ADC_PGA_BLOCK_1_PGA_CHOP_MASK GENMASK(7, 6)
#define RK730_ADC_PGA_BLOCK_1_PGA_CHOP(x) ((x) << 6)
/* RK730_MIC_BIAS */
#define RK730_MIC_BIAS_VOLT_MASK GENMASK(3, 2)
#define RK730_MIC_BIAS_VOLT_2_8V (3 << 2)
#define RK730_MIC_BIAS_VOLT_2_5V (2 << 2)
#define RK730_MIC_BIAS_VOLT_2_2V (1 << 2)
#define RK730_MIC_BIAS_VOLT_2_0V (0 << 2)
/* RK730_MUXER_1 */
#define RK730_MUXER_1_MUX_OUT_CHOP_MASK GENMASK(1, 0)
#define RK730_MUXER_1_MUX_OUT_CHOP(x) ((x) << 0)
/* RK730_MIXER_2 */
#define RK730_MIXER_2_MIX_CHOP_MASK GENMASK(7, 6)
#define RK730_MIXER_2_MIX_CHOP(x) ((x) << 6)
#define RK730_MIXER_2_MIX_R_MODE_MASK GENMASK(5, 4)
#define RK730_MIXER_2_MIX_R_MODE(x) ((x) << 4)
#define RK730_MIXER_2_MIX_L_MODE_MASK GENMASK(2, 1)
#define RK730_MIXER_2_MIX_L_MODE(x) ((x) << 1)
/* RK730_HP_1 */
#define RK730_HP_1_HP_LO_CHOP_MASK GENMASK(6, 5)
#define RK730_HP_1_HP_LO_CHOP(x) ((x) << 5)
/* RK730_DTOP_DIGEN_CLKE */
#define RK730_DTOP_DIGEN_CLKE_ADC_CKE_MASK BIT(7)
#define RK730_DTOP_DIGEN_CLKE_ADC_CKE_EN BIT(7)
#define RK730_DTOP_DIGEN_CLKE_ADC_CKE_DIS 0
#define RK730_DTOP_DIGEN_CLKE_I2STX_CKE_MASK BIT(6)
#define RK730_DTOP_DIGEN_CLKE_I2STX_CKE_EN BIT(6)
#define RK730_DTOP_DIGEN_CLKE_I2STX_CKE_DIS 0
#define RK730_DTOP_DIGEN_CLKE_ADC_EN_MASK BIT(5)
#define RK730_DTOP_DIGEN_CLKE_ADC_EN BIT(5)
#define RK730_DTOP_DIGEN_CLKE_ADC_DIS 0
#define RK730_DTOP_DIGEN_CLKE_I2STX_EN_MASK BIT(4)
#define RK730_DTOP_DIGEN_CLKE_I2STX_EN BIT(4)
#define RK730_DTOP_DIGEN_CLKE_I2STX_DIS 0
#define RK730_DTOP_DIGEN_CLKE_DAC_CKE_MASK BIT(3)
#define RK730_DTOP_DIGEN_CLKE_DAC_CKE_EN BIT(3)
#define RK730_DTOP_DIGEN_CLKE_DAC_CKE_DIS 0
#define RK730_DTOP_DIGEN_CLKE_I2SRX_CKE_MASK BIT(2)
#define RK730_DTOP_DIGEN_CLKE_I2SRX_CKE_EN BIT(2)
#define RK730_DTOP_DIGEN_CLKE_I2SRX_CKE_DIS 0
#define RK730_DTOP_DIGEN_CLKE_DAC_EN_MASK BIT(1)
#define RK730_DTOP_DIGEN_CLKE_DAC_EN BIT(1)
#define RK730_DTOP_DIGEN_CLKE_DAC_DIS 0
#define RK730_DTOP_DIGEN_CLKE_I2SRX_EN_MASK BIT(0)
#define RK730_DTOP_DIGEN_CLKE_I2SRX_EN BIT(0)
#define RK730_DTOP_DIGEN_CLKE_I2SRX_DIS 0
/* RK730_DADC_SR_ACL */
#define RK730_DADC_SR_ACL_VOLL_POL_MASK BIT(5)
#define RK730_DADC_SR_ACL_VOLL_POS BIT(5)
#define RK730_DADC_SR_ACL_VOLL_NEG 0
#define RK730_DADC_SR_ACL_VOLR_POL_MASK BIT(4)
#define RK730_DADC_SR_ACL_VOLR_POS BIT(4)
#define RK730_DADC_SR_ACL_VOLR_NEG 0
#define RK730_DADC_SR_ACL_SRT_MASK GENMASK(2, 0)
#define RK730_DADC_SR_ACL_SRT(x) (x)
/* RK730_DDAC_SR_LMT */
#define RK730_DDAC_SR_LMT_VOLL_POL_MASK BIT(5)
#define RK730_DDAC_SR_LMT_VOLL_POS BIT(5)
#define RK730_DDAC_SR_LMT_VOLL_NEG 0
#define RK730_DDAC_SR_LMT_VOLR_POL_MASK BIT(4)
#define RK730_DDAC_SR_LMT_VOLR_POS BIT(4)
#define RK730_DDAC_SR_LMT_VOLR_NEG 0
#define RK730_DDAC_SR_LMT_SRT_MASK GENMASK(2, 0)
#define RK730_DDAC_SR_LMT_SRT(x) (x)
/* RK730_DDAC_MUTE_MIXCTL */
#define RK730_DDAC_MUTE_MIXCTL_MUTE_MASK BIT(0)
#define RK730_DDAC_MUTE_MIXCTL_MUTE BIT(0)
#define RK730_DDAC_MUTE_MIXCTL_UNMUTE 0
/* RK730_DI2S_CKM */
#define RK730_DI2S_CKM_SCLK_DIV_MASK GENMASK(7, 4)
#define RK730_DI2S_CKM_SCLK_DIV(x) ((x - 1) << 4)
#define RK730_DI2S_CKM_SCLK_EN_MASK BIT(2)
#define RK730_DI2S_CKM_SCLK_EN BIT(2)
#define RK730_DI2S_CKM_SCLK_DIS 0
#define RK730_DI2S_CKM_SCLK_POL_MASK BIT(1)
#define RK730_DI2S_CKM_SCLK_INVERTED BIT(1)
#define RK730_DI2S_CKM_SCLK_NORMAL 0
#define RK730_DI2S_CKM_MST_MASK BIT(0)
#define RK730_DI2S_CKM_MST_MASTER BIT(0)
#define RK730_DI2S_CKM_MST_SLAVE 0
/* RK730_DI2S_XCR2 */
#define RK730_DI2S_XCR2_VDW_MASK GENMASK(4, 0)
#define RK730_DI2S_XCR2_VDW(x) (x - 1)
/* RK730_DI2S_RXCMD_TSD */
#define RK730_DI2S_RXCMD_TSD_RXS_MASK BIT(5)
#define RK730_DI2S_RXCMD_TSD_RXS_EN BIT(5)
#define RK730_DI2S_RXCMD_TSD_RXS_DIS 0
/* RK730_DI2S_TXCR_3_TXCMD */
#define RK730_DI2S_TXCR_3_TXCMD_TXS_MASK BIT(7)
#define RK730_DI2S_TXCR_3_TXCMD_TXS_EN BIT(7)
#define RK730_DI2S_TXCR_3_TXCMD_TXS_DIS 0
#endif

View File

@@ -2282,6 +2282,16 @@ static int rockchip_i2s_tdm_remove(struct platform_device *pdev)
return 0;
}
static void rockchip_i2s_tdm_platform_shutdown(struct platform_device *pdev)
{
struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(&pdev->dev);
pm_runtime_get_sync(i2s_tdm->dev);
rockchip_i2s_tdm_stop(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK);
rockchip_i2s_tdm_stop(i2s_tdm, SNDRV_PCM_STREAM_CAPTURE);
pm_runtime_put(i2s_tdm->dev);
}
#ifdef CONFIG_PM_SLEEP
static int rockchip_i2s_tdm_suspend(struct device *dev)
{
@@ -2317,6 +2327,7 @@ static const struct dev_pm_ops rockchip_i2s_tdm_pm_ops = {
static struct platform_driver rockchip_i2s_tdm_driver = {
.probe = rockchip_i2s_tdm_probe,
.remove = rockchip_i2s_tdm_remove,
.shutdown = rockchip_i2s_tdm_platform_shutdown,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(rockchip_i2s_tdm_match),

View File

@@ -28,6 +28,7 @@
#define PDM_START_DELAY_MS_MAX (1000)
#define PDM_FILTER_DELAY_MS_MIN (20)
#define PDM_FILTER_DELAY_MS_MAX (1000)
#define PDM_CLK_SHIFT_PPM_MAX (1000000) /* 1 ppm */
enum rk_pdm_version {
RK_PDM_RK3229,
@@ -89,7 +90,7 @@ 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)
{
unsigned int i, count, clk, div, rate;
unsigned int i, count, clk, div, rate, delta;
clk = 0;
if (!sr)
@@ -103,7 +104,9 @@ static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr,
if ((div & (div - 1)) == 0) {
*clk_out = clkref[i].clk_out;
rate = clk_round_rate(pdm->clk, clkref[i].clk);
if (rate != clkref[i].clk)
delta = clkref[i].clk / PDM_CLK_SHIFT_PPM_MAX;
if (rate < clkref[i].clk - delta ||
rate > clkref[i].clk + delta)
continue;
clk = clkref[i].clk;
*clk_src = clkref[i].clk;
@@ -610,6 +613,7 @@ static int rockchip_pdm_runtime_resume(struct device *dev)
return ret;
}
rockchip_pdm_rxctrl(pdm, 0);
regcache_cache_only(pdm->regmap, false);
regcache_mark_dirty(pdm->regmap);
ret = regcache_sync(pdm->regmap);