Merge commit '270c1dfde4111ba347868d1092ebd60aaf658951'

* commit '270c1dfde4111ba347868d1092ebd60aaf658951': (35 commits)
  ARM: dts: rockchip: add rv1106g-evb2-v12-nofastae-spi-nor
  ARM: dts: rockchip: add rv1106g-evb2-v12-nofastae-emmc
  ARM: dts: rockchip: Add rv1106 nofastae dtsi
  ARM: configs: rockchip: Add rv1106-tb-nofastae.config
  ASoC: codecs: Add tda7803 amplifier driver support
  clk: rockchip: rk3568: Add protect clocks
  drm/bridge: dw-hdmi-qp: Don't read edid again if edid is exist
  drm/bridge: dw-hdmi-qp: Add hdcp driver
  arm64: dts: rockchip: rk3588: Add hdmitx hdcp14 ext memory
  arm64: configs: rockchip_linux_defconfig: enable CONFIG_DTC_SYMBOLS
  arm64: dts: rockchip: rk3568: add rk3568-evb8-lp4-v10 support
  ARM: dts: rockchip: rv1106-evb-cam: add sc3338
  ARM: configs: rv1106-smart-door: enable SC230AI and SC301IOT
  arm64: dts: rockchip: fix timing configs of panel k350c4516t for rk3308/rk3562 evb
  media: rockchip: vicap fixes error of buffer state while start stream failed
  media: i2c: nvp6158: add g_frame_interval ops
  clk: rockchip: rk3328: set ddr clk with sip call
  Revert "dt-bindings: regulator: Document Rockchip RK860X regulators"
  arm64: dts: rockchip: rk3568-evb: assign DCLK_VOP2 to PLL_GPLL
  ARM: dts: rockchip: update rk5640 and hdmi sound for rk3288 evb boards
  ...

Change-Id: I0429c2d6884649bdc3a4cb4938d8923ba790dde6
This commit is contained in:
Tao Huang
2023-09-07 14:10:21 +08:00
67 changed files with 3023 additions and 481 deletions

View File

@@ -2,7 +2,7 @@ Binding for Fairchild FAN53555 regulators
Required properties:
- compatible: one of "fcs,fan53555", "fcs,fan53526", "silergy,syr827" or
"silergy,syr828", "rockchip,rk8603", "rockchip,rk8604"
"silergy,syr828"
- reg: I2C address
Optional properties:

View File

@@ -1002,6 +1002,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rv1106g-evb2-v10.dtb \
rv1106g-evb2-v10-dual-camera.dtb \
rv1106g-evb2-v11-emmc.dtb \
rv1106g-evb2-v12-nofastae-emmc.dtb \
rv1106g-evb2-v12-nofastae-spi-nor.dtb \
rv1106g-evb2-v12-wakeup.dtb \
rv1106g-smart-door-lock-rmsl-v10.dtb \
rv1106g-smart-door-lock-rmsl-v12.dtb \

View File

@@ -47,43 +47,49 @@
};
};
sound: sound {
compatible = "simple-audio-card";
simple-audio-card,format = "i2s";
simple-audio-card,name = "rockchip,rt5640-codec";
simple-audio-card,mclk-fs = <512>;
rt5640_sound: rt5640-sound {
status = "okay";
simple-audio-card,dai-link@0 {
format = "i2s";
cpu {
sound-dai = <&i2s>;
};
codec {
sound-dai = <&rt5640>;
};
};
simple-audio-card,dai-link@1 {
format = "i2s";
cpu {
sound-dai = <&i2s>;
};
codec {
sound-dai = <&hdmi>;
};
compatible = "rockchip,multicodecs-card";
rockchip,card-name = "rockchip-rt5640";
hp-det-gpio = <&gpio7 RK_PA7 GPIO_ACTIVE_HIGH>;
io-channels = <&saradc 2>;
io-channel-names = "adc-detect";
keyup-threshold-microvolt = <1800000>;
poll-interval = <100>;
rockchip,format = "i2s";
rockchip,mclk-fs = <512>;
rockchip,cpu = <&i2s>;
rockchip,codec = <&rt5640>;
rockchip,audio-routing =
"Headphone", "HPOL",
"Headphone", "HPOR",
"Speaker", "SPOLP",
"Speaker", "SPOLN",
"Speaker", "SPORP",
"Speaker", "SPORN",
"Headphone", "Headphone Power",
"Headphone", "Headphone Power",
"Speaker", "Speaker Power",
"Speaker", "Speaker Power",
"DMIC L1", "Main Mic",
"DMIC R1", "Main Mic",
"IN3P", "Headset Mic",
"Headset Mic", "MICBIAS1";
play-pause-key {
label = "playpause";
linux,code = <KEY_PLAYPAUSE>;
press-threshold-microvolt = <2000>;
};
};
hdmi_analog_sound: hdmi-analog-sound {
compatible = "rockchip,rk3288-hdmi-analog",
"rockchip,rk3368-hdmi-analog";
rockchip,model = "rockchip,rt5640-codec";
rockchip,cpu = <&i2s>;
rockchip,codec = <&rt5640>, <&hdmi>;
hdmi_sound: hdmi-sound {
status = "disabled";
compatible = "rockchip,hdmi";
rockchip,mclk-fs = <256>;
rockchip,card-name = "rockchip-hdmi0";
rockchip,cpu = <&i2s>;
rockchip,codec = <&hdmi>;
rockchip,jack-det;
};
backlight: backlight {
@@ -368,8 +374,6 @@
reg = <0x1c>;
clocks = <&cru SCLK_I2S0_OUT>;
clock-names = "mclk";
interrupt-parent = <&gpio7>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
pinctrl-names = "default";
pinctrl-0 = <&i2s0_mclk>;
};

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
@@ -45,6 +45,11 @@
remote-endpoint = <&jx_k17_out>;
data-lanes = <1 2>;
};
csi_dphy_input5: endpoint@5 {
reg = <5>;
remote-endpoint = <&sc3338_out>;
data-lanes = <1 2>;
};
};
port@1 {
@@ -110,6 +115,28 @@
};
};
sc3338: sc3338@30 {
compatible = "smartsens,sc3338";
status = "okay";
reg = <0x30>;
clocks = <&cru MCLK_REF_MIPI0>;
clock-names = "xvclk";
reset-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
pwdn-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&mipi_refclk_out0>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "FKO1";
rockchip,camera-module-lens-name = "30IRC-F16";
port {
sc3338_out: endpoint {
remote-endpoint = <&csi_dphy_input5>;
data-lanes = <1 2>;
};
};
};
sc4336: sc4336@30 {
compatible = "smartsens,sc4336";
status = "okay";

View File

@@ -0,0 +1,31 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
#include "rv1106-tb-nofastae.dtsi"
/ {
reserved-memory {
mmc_ecsd: mmc@3f000 {
reg = <0x3f000 0x00001000>;
};
mmc_idmac: mmc@100000 {
reg = <0x00100000 0x00100000>;
};
};
thunder_boot_mmc: thunder-boot-mmc {
compatible = "rockchip,thunder-boot-mmc";
reg = <0xffa90000 0x4000>;
memory-region-src = <&ramdisk_c>;
memory-region-dst = <&ramdisk_r>;
memory-region-idmac = <&mmc_idmac>;
};
};
&emmc {
memory-region-ecsd = <&mmc_ecsd>;
post-power-on-delay-ms = <0>;
};

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
#include "rv1106-tb-nofastae.dtsi"
/ {
thunder_boot_spi_nor: thunder-boot-spi-nor {
compatible = "rockchip,thunder-boot-sfc";
reg = <0xffac0000 0x4000>;
memory-region-src = <&ramdisk_c>;
memory-region-dst = <&ramdisk_r>;
};
};
&emmc {
status = "disabled";
};

View File

@@ -0,0 +1,35 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/ {
memory: memory {
device_type = "memory";
reg = <0x00000000 0x08000000>;
};
ramdisk: ramdisk {
compatible = "rockchip,ramdisk";
memory-region = <&ramdisk_r>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
ramdisk_r: ramdisk_r {
reg = <0x800000 (10 * 0x00100000)>;
};
ramdisk_c: ramdisk_c {
reg = <0x1200000 (5 * 0x00100000)>;
};
};
};
&hw_decompress {
status = "okay";
memory-region = <&ramdisk_c>;
};

View File

@@ -0,0 +1,134 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106.dtsi"
#include "rv1106-evb-v10.dtsi"
#include "rv1106-evb-cam.dtsi"
#include "rv1106-tb-nofastae-emmc.dtsi"
/ {
model = "Rockchip RV1106G EVB2 V12 Board";
compatible = "rockchip,rv1106g-evb2-v12", "rockchip,rv1106";
chosen {
bootargs = "loglevel=0 rootfstype=erofs rootflags=dax console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip";
};
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 = <&gpio2 RK_PA7 GPIO_ACTIVE_LOW>;
regulator-name = "vcc3v3_sd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_pwren>;
};
wireless_wlan: wireless-wlan {
compatible = "wlan-platdata";
WIFI,host_wake_irq = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
&fiq_debugger {
rockchip,baudrate = <1500000>;
pinctrl-names = "default";
pinctrl-0 = <&uart2m1_xfer>;
};
&pinctrl {
sdmmc {
/omit-if-no-ref/
sdmmc_pwren: sdmmc-pwren {
rockchip,pins = <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
&pwm10 {
status = "okay";
};
&pwm11 {
status = "okay";
};
&ramdisk_r {
reg = <0x800000 (20 * 0x00100000)>;
};
&ramdisk_c {
reg = <0x1C00000 (10 * 0x00100000)>;
};
&sdio {
max-frequency = <50000000>;
bus-width = <1>;
cap-sd-highspeed;
cap-sdio-irq;
keep-power-in-suspend;
non-removable;
rockchip,default-sample-phase = <90>;
no-sd;
no-mmc;
supports-sdio;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc1m0_cmd &sdmmc1m0_clk &sdmmc1m0_bus4>;
status = "okay";
};
&sdmmc {
max-frequency = <200000000>;
no-sdio;
no-mmc;
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
disable-wp;
pinctrl-names = "normal", "idle";
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
vmmc-supply = <&vcc3v3_sd>;
status = "okay";
};
&sfc {
assigned-clocks = <&cru SCLK_SFC>;
assigned-clock-rates = <125000000>;
status = "disabled";
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <125000000>;
spi-rx-bus-width = <4>;
spi-tx-bus-width = <1>;
};
};
&usbdrd_dwc3 {
dr_mode = "peripheral";
};

View File

@@ -0,0 +1,134 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106.dtsi"
#include "rv1106-evb-v10.dtsi"
#include "rv1106-evb-cam.dtsi"
#include "rv1106-tb-nofastae-spi-nor.dtsi"
/ {
model = "Rockchip RV1106G EVB2 V12 Board";
compatible = "rockchip,rv1106g-evb2-v12", "rockchip,rv1106";
chosen {
bootargs = "loglevel=0 rootfstype=erofs rootflags=dax console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip";
};
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 = <&gpio2 RK_PA7 GPIO_ACTIVE_LOW>;
regulator-name = "vcc3v3_sd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_pwren>;
};
wireless_wlan: wireless-wlan {
compatible = "wlan-platdata";
WIFI,host_wake_irq = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
&fiq_debugger {
rockchip,baudrate = <1500000>;
pinctrl-names = "default";
pinctrl-0 = <&uart2m1_xfer>;
};
&pinctrl {
sdmmc {
/omit-if-no-ref/
sdmmc_pwren: sdmmc-pwren {
rockchip,pins = <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
&pwm10 {
status = "okay";
};
&pwm11 {
status = "okay";
};
&ramdisk_r {
reg = <0x800000 (10 * 0x00100000)>;
};
&ramdisk_c {
reg = <0x1200000 (5 * 0x00100000)>;
};
&sdio {
max-frequency = <50000000>;
bus-width = <1>;
cap-sd-highspeed;
cap-sdio-irq;
keep-power-in-suspend;
non-removable;
rockchip,default-sample-phase = <90>;
no-sd;
no-mmc;
supports-sdio;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc1m0_cmd &sdmmc1m0_clk &sdmmc1m0_bus4>;
status = "okay";
};
&sdmmc {
max-frequency = <200000000>;
no-sdio;
no-mmc;
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
disable-wp;
pinctrl-names = "normal", "idle";
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
vmmc-supply = <&vcc3v3_sd>;
status = "okay";
};
&sfc {
assigned-clocks = <&cru SCLK_SFC>;
assigned-clock-rates = <125000000>;
status = "okay";
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <125000000>;
spi-rx-bus-width = <4>;
spi-tx-bus-width = <1>;
};
};
&usbdrd_dwc3 {
dr_mode = "peripheral";
};

View File

@@ -117,6 +117,14 @@
status = "okay";
};
&ramdisk_r {
reg = <0x12ec000 (15 * 0x00100000)>;
};
&ramdisk_c {
reg = <0x21ec000 (7 * 0x00100000)>;
};
&sdmmc {
max-frequency = <50000000>;
bus-width = <1>;

View File

@@ -69,7 +69,7 @@ CONFIG_DRM_GEM_CMA_HELPER=y
# CONFIG_DRM_I2C_NXP_TDA9950 is not set
# CONFIG_DRM_I2C_NXP_TDA998X is not set
# CONFIG_DRM_I2C_SIL164 is not set
# CONFIG_DRM_IGNORE_IOTCL_PERMIT is not set
CONFIG_DRM_IGNORE_IOTCL_PERMIT=y
# CONFIG_DRM_ITE_IT6161 is not set
CONFIG_DRM_KMS_FB_HELPER=y
CONFIG_DRM_KMS_HELPER=y

View File

@@ -29,6 +29,8 @@ CONFIG_SPI=y
CONFIG_USB_SUPPORT=y
CONFIG_VIDEO_GC2093=y
CONFIG_VIDEO_SC035GS=y
CONFIG_VIDEO_SC230AI=y
CONFIG_VIDEO_SC301IOT=y
CONFIG_VIDEO_SC3338=y
CONFIG_WIRELESS=y
CONFIG_WLAN=y
@@ -233,6 +235,7 @@ CONFIG_MPILIB=y
# CONFIG_MTD_MCHP23K256 is not set
# CONFIG_MTD_SPI_NAND is not set
CONFIG_MTD_SPI_NOR=m
# CONFIG_MTD_SPI_NOR_MISC is not set
# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
# CONFIG_MTD_SST25L is not set
# CONFIG_NL80211_TESTMODE is not set
@@ -257,8 +260,10 @@ CONFIG_RFKILL_RK=y
CONFIG_ROCKCHIP_MBOX=y
# CONFIG_ROCKCHIP_MMC_VENDOR_STORAGE is not set
CONFIG_ROCKCHIP_MTD_VENDOR_STORAGE=m
# CONFIG_ROCKCHIP_RAM_VENDOR_STORAGE is not set
CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE=y
# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
# CONFIG_RPMSG_ROCKCHIP is not set
# CONFIG_RTC_DRV_DS1302 is not set
# CONFIG_RTC_DRV_DS1305 is not set
# CONFIG_RTC_DRV_DS1343 is not set

View File

@@ -0,0 +1,3 @@
# CONFIG_ROCKCHIP_MBOX is not set
# CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE is not set
# CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP is not set

View File

@@ -144,6 +144,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb6-ddr3-v10-rk628-rgb2hdmi.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb6-ddr3-v10-rk628-rgb2lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb6-ddr3-v10-rk630-bt656-to-cvbs.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb7-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb8-lp4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb8-lp4-v10-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-iotest-ddr3-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-iotest-ddr3-v10-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-nvr-demo-v10.dtb

View File

@@ -45,147 +45,171 @@
default-brightness-level = <200>;
};
panel: panel {
compatible = "simple-panel";
bus-format = <MEDIA_BUS_FMT_RGB666_1X18>;
backlight = <&backlight>;
enable-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
enable-delay-ms = <20>;
reset-gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_LOW>;
reset-delay-ms = <10>;
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
/* spi-sdo-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; */
spi-sdi-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>;
spi-scl-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>;
spi-cs-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>;
width-mm = <217>;
height-mm = <136>;
status = "okay";
spi_gpio: spi-gpio {
compatible = "spi-gpio";
#address-cells = <0x1>;
#size-cells = <0x0>;
pinctrl-names = "default";
pinctrl-0 = <&spi_init_cmd>;
rockchip,cmd-type = "spi";
pinctrl-0 = <&spi_pins>;
spi-delay-us = <10>;
status = "okay";
/* type:0 is cmd, 1 is data */
panel-init-sequence = [
/* type delay num val1 val2 val3 */
00 00 01 e0
01 00 01 00
01 00 01 07
01 00 01 0f
01 00 01 0d
01 00 01 1b
01 00 01 0a
01 00 01 3c
01 00 01 78
01 00 01 4a
01 00 01 07
01 00 01 0e
01 00 01 09
01 00 01 1b
01 00 01 1e
01 00 01 0f
00 00 01 e1
01 00 01 00
01 00 01 22
01 00 01 24
01 00 01 06
01 00 01 12
01 00 01 07
01 00 01 36
01 00 01 47
01 00 01 47
01 00 01 06
01 00 01 0a
01 00 01 07
01 00 01 30
01 00 01 37
01 00 01 0f
sck-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>;
miso-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>;
mosi-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>;
cs-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>;
num-chipselects = <1>;
00 00 01 c0
01 00 01 10
01 00 01 10
/*
* 320x480 RGB/MCU screen K350C4516T
*/
panel: panel {
compatible = "simple-panel-spi";
reg = <0>;
bus-format = <MEDIA_BUS_FMT_RGB666_1X18>;
backlight = <&backlight>;
enable-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
enable-delay-ms = <20>;
reset-gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_LOW>;
reset-delay-ms = <10>;
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
init-delay-ms = <10>;
width-mm = <217>;
height-mm = <136>;
rockchip,cmd-type = "spi";
status = "okay";
00 00 01 c1
01 00 01 41
// type:0 is cmd, 1 is data
panel-init-sequence = [
/* type delay num val1 val2 val3 */
00 00 01 e0
01 00 01 00
01 00 01 07
01 00 01 0f
01 00 01 0d
01 00 01 1b
01 00 01 0a
01 00 01 3c
01 00 01 78
01 00 01 4a
01 00 01 07
01 00 01 0e
01 00 01 09
01 00 01 1b
01 00 01 1e
01 00 01 0f
00 00 01 e1
01 00 01 00
01 00 01 22
01 00 01 24
01 00 01 06
01 00 01 12
01 00 01 07
01 00 01 36
01 00 01 47
01 00 01 47
01 00 01 06
01 00 01 0a
01 00 01 07
01 00 01 30
01 00 01 37
01 00 01 0f
00 00 01 c5
01 00 01 00
01 00 01 22
01 00 01 80
00 00 01 c0
01 00 01 10
01 00 01 10
00 00 01 36
01 00 01 48
00 00 01 c1
01 00 01 41
00 00 01 3a //interface pixel format
01 00 01 66 // bpp cfg
// 3 11
// 16 55
// 18 66
// 24 77
00 00 01 c5
01 00 01 00
01 00 01 22
01 00 01 80
00 00 01 b0 /* interface mode control */
01 00 01 00
00 00 01 36
01 00 01 48
00 00 01 b1 /* frame rate 60hz */
01 00 01 a0
01 00 01 11
00 00 01 b4
01 00 01 02
00 00 01 B6
01 00 01 32
01 00 01 02
00 00 01 3a
01 00 01 66 /*
* interface pixel format:
* 66 for RGB666(18bit)
*/
00 00 01 b7
01 00 01 c6
00 00 01 b0
01 00 01 00
00 00 01 be
01 00 01 00
01 00 01 04
00 00 01 b1
01 00 01 a0 /*
* frame rate control:
* a0 (60hz) for RGB666(18bit)
*/
01 00 01 11
00 00 01 b4
01 00 01 02
00 00 01 B6
01 00 01 32 /*
* display function control:
* 32 for RGB
* 02 for MCU
*/
01 00 01 02
00 00 01 e9
01 00 01 00
00 00 01 b7
01 00 01 c6
00 00 01 f7
01 00 01 a9
01 00 01 51
01 00 01 2c
01 00 01 82
00 00 01 be
01 00 01 00
01 00 01 04
00 78 01 11
00 00 01 29
];
00 00 01 e9
01 00 01 00
panel-exit-sequence = [
/* type delay num val1 val2 val3 */
00 0a 01 28
00 78 01 10
];
00 00 01 f7
01 00 01 a9
01 00 01 51
01 00 01 2c
01 00 01 82
display-timings {
native-mode = <&kd050fwfba002_timing>;
00 78 01 11
00 00 01 29
];
kd050fwfba002_timing: timing0 {
clock-frequency = <94081500>;
hactive = <320>;
vactive = <480>;
hback-porch = <10>;
hfront-porch = <5>;
vback-porch = <10>;
vfront-porch = <5>;
hsync-len = <10>;
vsync-len = <10>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
panel-exit-sequence = [
//type delay num val1 val2 val3
00 0a 01 28
00 78 01 10
];
display-timings {
native-mode = <&kd050fwfba002_timing>;
kd050fwfba002_timing: timing0 {
/*
* 10453500 for RGB666(18bit)
*/
clock-frequency = <10453500>;
hactive = <320>;
vactive = <480>;
hback-porch = <10>;
hfront-porch = <5>;
vback-porch = <10>;
vfront-porch = <5>;
hsync-len = <10>;
vsync-len = <10>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <1>;
};
};
};
port {
panel_in_rgb: endpoint {
remote-endpoint = <&rgb_out_panel>;
port {
panel_in_rgb: endpoint {
remote-endpoint = <&rgb_out_panel>;
};
};
};
};
@@ -196,9 +220,11 @@
};
&pinctrl {
spi_panel {
spi_init_cmd: spi-init-cmd {
soft_spi {
spi_pins: spi-pins {
rockchip,pins =
/* spi sdo */
<3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>,
/* spi sdi */
<1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>,
/* spi scl */
@@ -236,14 +262,4 @@
&vop {
status = "okay";
mcu-timing {
mcu-pix-total = <9>;
mcu-cs-pst = <1>;
mcu-cs-pend = <8>;
mcu-rw-pst = <2>;
mcu-rw-pend = <5>;
mcu-hold-mode = <0>; // default set to 0
};
};

View File

@@ -45,8 +45,40 @@
default-brightness-level = <200>;
};
panel: panel {
compatible = "simple-panel";
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
cma {
compatible = "shared-dma-pool";
reusable;
size = <0x0 0x800000>;
linux,cma-default;
};
};
};
&display_subsystem {
status = "okay";
};
&pwm1 {
status = "okay";
};
&rgb {
status = "okay";
rockchip,data-sync-bypass;
/*
* 320x480 RGB/MCU screen K350C4516T
*/
mcu_panel: mcu-panel {
/*
* MEDIA_BUS_FMT_RGB888_3X8 for RGB3x8(8bit)
* MEDIA_BUS_FMT_RGB565_1X16 for RGB565(16bit)
*/
bus-format = <MEDIA_BUS_FMT_RGB565_1X16>;
backlight = <&backlight>;
enable-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
@@ -59,8 +91,6 @@
disable-delay-ms = <20>;
width-mm = <217>;
height-mm = <136>;
status = "okay";
rockchip,cmd-type = "mcu";
// type:0 is cmd, 1 is data
panel-init-sequence = [
@@ -113,23 +143,31 @@
00 00 01 36
01 00 01 48
00 00 01 3a //interface pixel format
01 00 01 55 // bpp cfg
// 3 11
// 16 55
// 18 66
// 24 77
00 00 01 3a
01 00 01 55 /*
* interface pixel format:
* 66 for RGB3x8(8bit)
* 55 for RGB565(16bit)
*/
00 00 01 b0 //interface mode control
00 00 01 b0
01 00 01 00
00 00 01 b1 //frame rate 60hz
01 00 01 a0
00 00 01 b1
01 00 01 a0 /*
* frame rate control:
* 70 (45hz) for RGB3x8(8bit)
* a0 (60hz) for RGB565(16bit)
*/
01 00 01 11
00 00 01 b4
01 00 01 02
00 00 01 B6
01 00 01 02
01 00 01 02 /*
* display function control:
* 32 for RGB
* 02 for MCU
*/
01 00 01 02
00 00 01 b7
@@ -163,7 +201,11 @@
native-mode = <&kd050fwfba002_timing>;
kd050fwfba002_timing: timing0 {
clock-frequency = <94081500>;
/*
* 7840125 for frame rate 45Hz
* 10453500 for frame rate 60Hz
*/
clock-frequency = <10453500>;
hactive = <320>;
vactive = <480>;
hback-porch = <10>;
@@ -186,35 +228,6 @@
};
};
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
cma {
compatible = "shared-dma-pool";
reusable;
size = <0x0 0x800000>;
linux,cma-default;
};
};
};
&display_subsystem {
status = "okay";
};
&route_rgb {
status = "okay";
};
&pwm1 {
status = "okay";
};
&rgb {
status = "okay";
ports {
rgb_out: port@1 {
reg = <1>;
@@ -229,15 +242,32 @@
};
};
&route_rgb {
status = "okay";
};
&vop {
status = "okay";
/*
* Default config is as follows:
*
* mcu-pix-total = <9>;
* mcu-cs-pst = <1>;
* mcu-cs-pend = <8>;
* mcu-rw-pst = <2>;
* mcu-rw-pend = <5>;
* mcu-hold-mode = <0>; // default set to 0
*
* To increase the frame rate, reduce all parameters because
* the max dclk rate of mcu is 150M in rk3308.
*/
mcu-timing {
mcu-pix-total = <9>;
mcu-pix-total = <5>;
mcu-cs-pst = <1>;
mcu-cs-pend = <8>;
mcu-cs-pend = <4>;
mcu-rw-pst = <2>;
mcu-rw-pend = <5>;
mcu-rw-pend = <3>;
mcu-hold-mode = <0>; // default set to 0
};

View File

@@ -120,7 +120,7 @@
#gpio-cells = <2>;
#clock-cells = <1>;
clock-output-names = "rk805-clkout1", "rk805-clkout2";
rk805,system-power-controoler;
rockchip,system-power-controller;
vcc1-supply = <&vcc5v0_sys>;
vcc2-supply = <&vcc5v0_sys>;

View File

@@ -47,8 +47,8 @@
rockchip,data-sync-bypass;
pinctrl-names = "default";
/*
* rgb3x8_pins_m0/rgb3x8_pins_m1 for serial mcu
* rgb565_pins for parallel mcu
* rgb3x8_pins_m0/rgb3x8_pins_m1 for RGB3x8(8bit)
* rgb565_pins for RGB565(16bit)
*/
pinctrl-0 = <&rgb565_pins>;
@@ -57,19 +57,19 @@
*/
mcu_panel: mcu-panel {
/*
* MEDIA_BUS_FMT_RGB888_3X8 for serial mcu
* MEDIA_BUS_FMT_RGB565_1X16 for parallel mcu
* MEDIA_BUS_FMT_RGB888_3X8 for RGB3x8(8bit)
* MEDIA_BUS_FMT_RGB565_1X16 for RGB565(16bit)
*/
bus-format = <MEDIA_BUS_FMT_RGB565_1X16>;
backlight = <&backlight>;
enable-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>;
enable-delay-ms = <20>;
reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
reset-value = <0>;
reset-delay-ms = <10>;
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
init-delay-ms = <10>;
width-mm = <217>;
height-mm = <136>;
@@ -124,23 +124,31 @@
00 00 01 36
01 00 01 48
00 00 01 3a //interface pixel format
01 00 01 55 // bpp cfg
// 3 11
// 16 55
// 18 66
// 24 77
00 00 01 3a
01 00 01 55 /*
* interface pixel format:
* 66 for RGB3x8(8bit)
* 55 for RGB565(16bit)
*/
00 00 01 b0 //interface mode control
00 00 01 b0
01 00 01 00
00 00 01 b1 //frame rate 60hz
01 00 01 a0
00 00 01 b1
01 00 01 a0 /*
* frame rate control:
* 70 (45hz) for RGB3x8(8bit)
* a0 (60hz) for RGB565(16bit)
*/
01 00 01 11
00 00 01 b4
01 00 01 02
00 00 01 B6
01 00 01 02
01 00 01 02 /*
* display function control:
* 32 for RGB
* 02 for MCU
*/
01 00 01 02
00 00 01 b7
@@ -174,7 +182,11 @@
native-mode = <&kd050fwfba002_timing>;
kd050fwfba002_timing: timing0 {
clock-frequency = <94081500>;
/*
* 7840125 for frame rate 45Hz
* 10453500 for frame rate 60Hz
*/
clock-frequency = <10453500>;
hactive = <320>;
vactive = <480>;
hback-porch = <10>;
@@ -240,12 +252,27 @@
};
&vp0 {
status = "okay";
/*
* Default config is as follows:
*
* mcu-pix-total = <9>;
* mcu-cs-pst = <1>;
* mcu-cs-pend = <8>;
* mcu-rw-pst = <2>;
* mcu-rw-pend = <5>;
* mcu-hold-mode = <0>; // default set to 0
*
* To increase the frame rate, reduce all parameters because
* the max dclk rate of mcu is 150M in rk3562.
*/
mcu-timing {
mcu-pix-total = <9>;
mcu-pix-total = <5>;
mcu-cs-pst = <1>;
mcu-cs-pend = <8>;
mcu-cs-pend = <4>;
mcu-rw-pst = <2>;
mcu-rw-pend = <5>;
mcu-rw-pend = <3>;
mcu-hold-mode = <0>; // default set to 0
};

View File

@@ -43,6 +43,7 @@
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
init-delay-ms = <10>;
width-mm = <217>;
height-mm = <136>;
rockchip,cmd-type = "spi";
@@ -99,23 +100,29 @@
00 00 01 36
01 00 01 48
00 00 01 3a //interface pixel format
01 00 01 66 // bpp cfg
// 3 11
// 16 55
// 18 66
// 24 77
00 00 01 3a
01 00 01 66 /*
* interface pixel format:
* 66 for RGB666(18bit)
*/
00 00 01 b0 /* interface mode control */
00 00 01 b0
01 00 01 00
00 00 01 b1 /* frame rate 60hz */
01 00 01 a0
00 00 01 b1
01 00 01 a0 /*
* frame rate control:
* a0 (60hz) for RGB666(18bit)
*/
01 00 01 11
00 00 01 b4
01 00 01 02
00 00 01 B6
01 00 01 32
01 00 01 32 /*
* display function control:
* 32 for RGB
* 02 for MCU
*/
01 00 01 02
00 00 01 b7
@@ -148,6 +155,9 @@
native-mode = <&kd050fwfba002_timing>;
kd050fwfba002_timing: timing0 {
/*
* 10453500 for RGB666(18bit)
*/
clock-frequency = <10453500>;
hactive = <320>;
vactive = <480>;

View File

@@ -1857,8 +1857,8 @@
&vop {
status = "okay";
assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>, <&cru DCLK_VOP2>;
assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>, <&cru PLL_GPLL>;
};
&vop_mmu {

View File

@@ -0,0 +1,17 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb8-lp4-v10.dtsi"
#include "rk3568-linux.dtsi"
#include <dt-bindings/display/rockchip_vop.h>
&vp0 {
cursor-win-id = <ROCKCHIP_VOP2_CLUSTER0>;
};
&vp1 {
cursor-win-id = <ROCKCHIP_VOP2_CLUSTER1>;
};

View File

@@ -0,0 +1,20 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb8-lp4-v10.dtsi"
#include "rk3568-android.dtsi"
&bt_sco {
status = "okay";
};
&bt_sound {
status = "okay";
};
&i2s3_2ch {
status = "okay";
};

View File

@@ -0,0 +1,37 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
/dts-v1/;
#include "rk3568-evb1-ddr4-v10.dtsi"
/ {
model = "Rockchip RK3568 EVB8 LP4 V10 Board";
compatible = "rockchip,rk3568-evb8-lp4-v10", "rockchip,rk3568";
};
&i2c0 {
status = "okay";
/delete-node/ tcs4525@1c;
vdd_cpu: rk8600@40 {
compatible = "rockchip,rk8600";
reg = <0x40>;
vin-supply = <&vcc5v0_sys>;
regulator-compatible = "rk860x-reg";
regulator-name = "vdd_cpu";
regulator-min-microvolt = <712500>;
regulator-max-microvolt = <1390000>;
regulator-init-microvolt = <900000>;
regulator-ramp-delay = <2300>;
rockchip,suspend-voltage-selector = <1>;
regulator-boot-on;
regulator-always-on;
regulator-state-mem {
regulator-off-in-suspend;
};
};
};

View File

@@ -126,9 +126,9 @@
mbist-vmin = <825000 900000 950000>;
nvmem-cells = <&cpu_leakage>, <&core_pvtm>, <&mbist_vmin>, <&cpu_opp_info>,
<&specification_serial_number>;
<&specification_serial_number>, <&remark_spec_serial_number>;
nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info",
"specification_serial_number";
"specification_serial_number", "remark_spec_serial_number";
rockchip,supported-hw;
rockchip,max-volt = <1150000>;
rockchip,pvtm-voltage-sel = <
@@ -1149,9 +1149,9 @@
mbist-vmin = <825000 900000 950000>;
nvmem-cells = <&npu_leakage>, <&core_pvtm>, <&mbist_vmin>, <&npu_opp_info>,
<&specification_serial_number>;
<&specification_serial_number>, <&remark_spec_serial_number>;
nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info",
"specification_serial_number";
"specification_serial_number", "remark_spec_serial_number";
rockchip,supported-hw;
rockchip,max-volt = <1000000>;
rockchip,temp-hysteresis = <5000>;
@@ -1331,9 +1331,9 @@
mbist-vmin = <825000 900000 950000>;
nvmem-cells = <&gpu_leakage>, <&core_pvtm>, <&mbist_vmin>, <&gpu_opp_info>,
<&specification_serial_number>;
<&specification_serial_number>, <&remark_spec_serial_number>;
nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info",
"specification_serial_number";
"specification_serial_number", "remark_spec_serial_number";
rockchip,supported-hw;
rockchip,max-volt = <1000000>;
rockchip,temp-hysteresis = <5000>;
@@ -2420,9 +2420,9 @@
mbist-vmin = <825000 900000 950000>;
nvmem-cells = <&log_leakage>, <&core_pvtm>, <&mbist_vmin>, <&dmc_opp_info>,
<&specification_serial_number>;
<&specification_serial_number>, <&remark_spec_serial_number>;
nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info",
"specification_serial_number";
"specification_serial_number", "remark_spec_serial_number";
rockchip,supported-hw;
rockchip,max-volt = <1000000>;
rockchip,temp-hysteresis = <5000>;
@@ -2850,6 +2850,10 @@
dmc_opp_info: dmc-opp-info@48 {
reg = <0x48 0x6>;
};
remark_spec_serial_number: remark-spec-serial-number@56 {
reg = <0x56 0x1>;
bits = <0 5>;
};
};
i2s0_8ch: i2s@fe400000 {

View File

@@ -362,7 +362,7 @@
hdmi1: hdmi@fdea0000 {
compatible = "rockchip,rk3588-dw-hdmi";
reg = <0x0 0xfdea0000 0x0 0x20000>;
reg = <0x0 0xfdea0000 0x0 0x10000>, <0x0 0xfdeb0000 0x0 0x10000>;
interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>,

View File

@@ -4984,7 +4984,7 @@
hdmi0: hdmi@fde80000 {
compatible = "rockchip,rk3588-dw-hdmi";
reg = <0x0 0xfde80000 0x0 0x20000>;
reg = <0x0 0xfde80000 0x0 0x10000>, <0x0 0xfde90000 0x0 0x10000>;
interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>,

View File

@@ -951,7 +951,6 @@ CONFIG_ROCKCHIP_EFUSE=y
CONFIG_ROCKCHIP_OTP=y
CONFIG_TEE=y
CONFIG_OPTEE=y
CONFIG_RK_NAND=y
CONFIG_RK_HEADSET=y
CONFIG_ROCKCHIP_RKNPU=y
CONFIG_EXT4_FS=y

View File

@@ -144,6 +144,7 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_SPI_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
CONFIG_DTC_SYMBOLS=y
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y

View File

@@ -317,14 +317,15 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
RK3328_CLKGATE_CON(14), 1, GFLAGS),
/* PD_DDR */
COMPOSITE(0, "clk_ddr", mux_ddrphy_p, CLK_IS_CRITICAL,
RK3328_CLKSEL_CON(3), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
RK3328_CLKGATE_CON(0), 4, GFLAGS),
GATE(0, "clk_ddrmsch", "clk_ddr", CLK_IS_CRITICAL,
COMPOSITE_DDRCLK(SCLK_DDRCLK, "sclk_ddrc", mux_ddrphy_p, 0,
RK3328_CLKSEL_CON(3), 8, 2, 0, 3,
ROCKCHIP_DDRCLK_SIP_V2),
GATE(0, "clk_ddrmsch", "sclk_ddrc", CLK_IGNORE_UNUSED,
RK3328_CLKGATE_CON(18), 6, GFLAGS),
GATE(0, "clk_ddrupctl", "clk_ddr", CLK_IS_CRITICAL,
GATE(0, "clk_ddrupctl", "sclk_ddrc", CLK_IGNORE_UNUSED,
RK3328_CLKGATE_CON(18), 5, GFLAGS),
GATE(0, "aclk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
GATE(0, "aclk_ddrupctl", "sclk_ddrc", CLK_IGNORE_UNUSED,
RK3328_CLKGATE_CON(18), 4, GFLAGS),
GATE(0, "clk_ddrmon", "xin24m", CLK_IGNORE_UNUSED,
RK3328_CLKGATE_CON(0), 6, GFLAGS),

View File

@@ -1618,6 +1618,16 @@ static void rk3568_dump_cru(void)
}
}
static int protect_clocks[] = {
ACLK_VO,
HCLK_VO,
ACLK_VOP,
HCLK_VOP,
DCLK_VOP0,
DCLK_VOP1,
DCLK_VOP2,
};
static void __init rk3568_pmu_clk_init(struct device_node *np)
{
struct rockchip_clk_provider *ctx;
@@ -1695,6 +1705,8 @@ static void __init rk3568_clk_init(struct device_node *np)
if (!rk_dump_cru)
rk_dump_cru = rk3568_dump_cru;
rockchip_clk_protect(ctx, protect_clocks, ARRAY_SIZE(protect_clocks));
}
CLK_OF_DECLARE(rk3568_cru, "rockchip,rk3568-cru", rk3568_clk_init);

View File

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o dw-hdmi-hdcp.o \
dw-hdmi-qp.o
dw-hdmi-qp.o dw-hdmi-qp-hdcp.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o dw-hdmi-qp-i2s-audio.o
obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o dw-hdmi-qp-cec.o

View File

@@ -0,0 +1,650 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) Rockchip Electronics Co.Ltd
* Author:
* Algea Cao <algea.cao@rock-chips.com>
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/hdmi.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/soc/rockchip/rk_vendor_storage.h>
#include <crypto/sha.h>
#include <drm/bridge/dw_hdmi.h>
#include "dw-hdmi-qp.h"
#include "dw-hdmi-qp-hdcp.h"
#define HDCP_KEY_SIZE 308
#define HDCP_KEY_SEED_SIZE 2
#define KSV_LEN 5
#define HEADER 10
#define SHAMAX 20
#define MAX_DOWNSTREAM_DEVICE_NUM 5
#define DPK_WR_OK_TIMEOUT_US 30000
#define HDMI_HDCP1X_ID 5
/* HDCP Registers */
#define HDMI_HDCPREG_RMCTL 0x780e
#define HDMI_HDCPREG_RMSTS 0x780f
#define HDMI_HDCPREG_SEED0 0x7810
#define HDMI_HDCPREG_SEED1 0x7811
#define HDMI_HDCPREG_DPK0 0x7812
#define HDMI_HDCPREG_DPK1 0x7813
#define HDMI_HDCPREG_DPK2 0x7814
#define HDMI_HDCPREG_DPK3 0x7815
#define HDMI_HDCPREG_DPK4 0x7816
#define HDMI_HDCPREG_DPK5 0x7817
#define HDMI_HDCPREG_DPK6 0x7818
#define HDMI_HDCP2REG_CTRL 0x7904
#define HDMI_HDCP2REG_MASK 0x790c
#define HDMI_HDCP2REG_MUTE 0x790e
enum dw_hdmi_hdcp_state {
DW_HDCP_DISABLED,
DW_HDCP_AUTH_START,
DW_HDCP_AUTH_SUCCESS,
DW_HDCP_AUTH_FAIL,
};
enum {
DW_HDMI_HDCP_KSV_LEN = 8,
DW_HDMI_HDCP_SHA_LEN = 20,
DW_HDMI_HDCP_DPK_LEN = 280,
DW_HDMI_HDCP_KEY_LEN = 308,
DW_HDMI_HDCP_SEED_LEN = 2,
};
enum {
HDCP14_R0_TIMER_OVR_EN_MASK = 0x01,
HDCP14_R0_TIMER_OVR_EN = 0x01,
HDCP14_R0_TIMER_OVR_DISABLE = 0x00,
HDCP14_RI_TIMER_OVR_EN_MASK = 0x80,
HDCP14_RI_TIMER_OVR_EN = 0x80,
HDCP14_RI_TIMER_OVR_DISABLE = 0x00,
HDCP14_R0_TIMER_OVR_VALUE_MASK = 0x1e,
HDCP14_RI_TIMER_OVR_VALUE_MASK = 0xff00,
HDCP14_KEY_WR_OK = 0x100,
HDCP14_HPD_MASK = 0x01,
HDCP14_HPD_EN = 0x01,
HDCP14_HPD_DISABLE = 0x00,
HDCP14_ENCRYPTION_ENABLE_MASK = 0x04,
HDCP14_ENCRYPTION_ENABLE = 0x04,
HDCP14_ENCRYPTION_DISABLE = 0x04,
HDCP14_KEY_DECRYPT_EN_MASK = 0x400,
HDCP14_KEY_DECRYPT_EN = 0x400,
HDCP14_KEY_DECRYPT_DISABLE = 0x00,
HDMI_A_SRMCTRL_SHA1_FAIL_MASK = 0X08,
HDMI_A_SRMCTRL_SHA1_FAIL_DISABLE = 0X00,
HDMI_A_SRMCTRL_SHA1_FAIL_ENABLE = 0X08,
HDMI_A_SRMCTRL_KSV_UPDATE_MASK = 0X04,
HDMI_A_SRMCTRL_KSV_UPDATE_DISABLE = 0X00,
HDMI_A_SRMCTRL_KSV_UPDATE_ENABLE = 0X04,
HDMI_A_SRMCTRL_KSV_MEM_REQ_MASK = 0X01,
HDMI_A_SRMCTRL_KSV_MEM_REQ_DISABLE = 0X00,
HDMI_A_SRMCTRL_KSV_MEM_REQ_ENABLE = 0X01,
HDMI_A_SRMCTRL_KSV_MEM_ACCESS_MASK = 0X02,
HDMI_A_SRMCTRL_KSV_MEM_ACCESS_DISABLE = 0X00,
HDMI_A_SRMCTRL_KSV_MEM_ACCESS_ENABLE = 0X02,
HDMI_A_SRM_BASE_MAX_DEVS_EXCEEDED = 0x80,
HDMI_A_SRM_BASE_DEVICE_COUNT = 0x7f,
HDMI_A_SRM_BASE_MAX_CASCADE_EXCEEDED = 0x08,
HDMI_A_APIINTSTAT_KSVSHA1_CALC_INT = 0x02,
/* HDCPREG_RMSTS field values */
DPK_WR_OK_STS = 0x40,
HDMI_A_HDCP22_MASK = 0x40,
HDMI_HDCP2_OVR_EN_MASK = 0x02,
HDMI_HDCP2_OVR_ENABLE = 0x02,
HDMI_HDCP2_OVR_DISABLE = 0x00,
HDMI_HDCP2_FORCE_MASK = 0x04,
HDMI_HDCP2_FORCE_ENABLE = 0x04,
HDMI_HDCP2_FORCE_DISABLE = 0x00,
};
struct sha_t {
u8 mlength[8];
u8 mblock[64];
int mindex;
int mcomputed;
int mcorrupted;
unsigned int mdigest[5];
};
static inline unsigned int shacircularshift(unsigned int bits,
unsigned int word)
{
return (((word << bits) & 0xFFFFFFFF) | (word >> (32 - bits)));
}
static void hdcp_modb(struct dw_qp_hdcp *hdcp, u32 data, u32 mask, u32 reg)
{
struct dw_hdmi_qp *hdmi = hdcp->hdmi;
u32 val = hdcp->read(hdmi, reg) & ~mask;
val |= data & mask;
hdcp->write(hdmi, val, reg);
}
static int hdcp_load_keys_cb(struct dw_qp_hdcp *hdcp)
{
u32 size;
u8 hdcp_vendor_data[320];
hdcp->keys = kmalloc(HDCP_KEY_SIZE, GFP_KERNEL);
if (!hdcp->keys)
return -ENOMEM;
hdcp->seeds = kmalloc(HDCP_KEY_SEED_SIZE, GFP_KERNEL);
if (!hdcp->seeds) {
kfree(hdcp->keys);
return -ENOMEM;
}
size = rk_vendor_read(HDMI_HDCP1X_ID, hdcp_vendor_data, 314);
if (size < (HDCP_KEY_SIZE + HDCP_KEY_SEED_SIZE)) {
dev_err(hdcp->dev, "HDCP: read size %d\n", size);
memset(hdcp->keys, 0, HDCP_KEY_SIZE);
memset(hdcp->seeds, 0, HDCP_KEY_SEED_SIZE);
} else {
memcpy(hdcp->keys, hdcp_vendor_data, HDCP_KEY_SIZE);
memcpy(hdcp->seeds, hdcp_vendor_data + HDCP_KEY_SIZE,
HDCP_KEY_SEED_SIZE);
}
return 0;
}
static int dw_hdcp_qp_hdcp_load_key(struct dw_qp_hdcp *hdcp)
{
int i, j;
int ret, val;
void __iomem *reg_rmsts_addr;
struct dw_hdmi_qp_hdcp_keys *hdcp_keys;
struct dw_hdmi_qp *hdmi = hdcp->hdmi;
u32 ksv, dkl, dkh;
if (!hdcp->keys) {
ret = hdcp_load_keys_cb(hdcp);
if (ret)
return ret;
}
hdcp_keys = hdcp->keys;
reg_rmsts_addr = hdcp->regs + HDCP14_KEY_STATUS;
/* hdcp key has been written */
if (hdcp->read(hdmi, HDCP14_KEY_STATUS) & 0x3f) {
dev_info(hdcp->dev, "hdcp key has been written\n");
return 0;
}
ksv = hdcp_keys->KSV[0] | hdcp_keys->KSV[1] << 8 |
hdcp_keys->KSV[2] << 16 | hdcp_keys->KSV[3] << 24;
hdcp->write(hdmi, ksv, HDCP14_AKSV_L);
ksv = hdcp_keys->KSV[4];
hdcp->write(hdmi, ksv, HDCP14_AKSV_H);
if (hdcp->seeds) {
hdcp_modb(hdcp, HDCP14_KEY_DECRYPT_EN,
HDCP14_KEY_DECRYPT_EN_MASK,
HDCP14_CONFIG0);
hdcp->write(hdmi, (hdcp->seeds[0] << 8) | hdcp->seeds[1],
HDCP14_KEY_SEED);
} else {
hdcp_modb(hdcp, HDCP14_KEY_DECRYPT_DISABLE,
HDCP14_KEY_DECRYPT_EN_MASK,
HDCP14_CONFIG0);
}
for (i = 0; i < DW_HDMI_HDCP_DPK_LEN - 6; i += 7) {
dkl = 0;
dkh = 0;
for (j = 0; j < 4; j++)
dkl |= hdcp_keys->devicekey[i + j] << (j * 8);
for (j = 4; j < 7; j++)
dkh |= hdcp_keys->devicekey[i + j] << ((j - 4) * 8);
hdcp->write(hdmi, dkh, HDCP14_KEY_H);
hdcp->write(hdmi, dkl, HDCP14_KEY_L);
ret = readx_poll_timeout(readl, reg_rmsts_addr, val,
val & HDCP14_KEY_WR_OK, 1000,
DPK_WR_OK_TIMEOUT_US);
if (ret) {
dev_err(hdcp->dev, "hdcp key write err\n");
return ret;
}
}
return 0;
}
static void dw_hdcp_qp_hdcp_restart(struct dw_qp_hdcp *hdcp)
{
mutex_lock(&hdcp->mutex);
if (!hdcp->remaining_times) {
mutex_unlock(&hdcp->mutex);
return;
}
hdcp_modb(hdcp, 0, HDCP14_ENCRYPTION_ENABLE_MASK | HDCP14_HPD_MASK,
HDCP14_CONFIG0);
hdcp->write(hdcp->hdmi, 1, HDCP14_CONFIG1);
mdelay(50);
hdcp->write(hdcp->hdmi, HDCP14_AUTH_CHG_MASK_N | HDCP14_KSV_LIST_DONE_MASK_N,
AVP_1_INT_CLEAR);
hdcp_modb(hdcp, HDCP14_AUTH_CHG_MASK_N | HDCP14_KSV_LIST_DONE_MASK_N,
HDCP14_AUTH_CHG_MASK_N | HDCP14_KSV_LIST_DONE_MASK_N, AVP_1_INT_MASK_N);
hdcp_modb(hdcp, HDCP14_ENCRYPTION_ENABLE_MASK | HDCP14_HPD_MASK,
HDCP14_ENCRYPTION_ENABLE_MASK | HDCP14_HPD_MASK,
HDCP14_CONFIG0);
hdcp->remaining_times--;
mutex_unlock(&hdcp->mutex);
}
static int dw_hdcp_qp_hdcp_start(struct dw_qp_hdcp *hdcp)
{
struct dw_hdmi_qp *hdmi = hdcp->hdmi;
dw_hdcp_qp_hdcp_load_key(hdcp);
mutex_lock(&hdcp->mutex);
hdcp->remaining_times = hdcp->retry_times;
hdcp->write(hdmi, HDCP14_AUTH_CHG_MASK_N | HDCP14_KSV_LIST_DONE_MASK_N, AVP_1_INT_CLEAR);
hdcp_modb(hdcp, HDCP14_AUTH_CHG_MASK_N | HDCP14_KSV_LIST_DONE_MASK_N,
HDCP14_AUTH_CHG_MASK_N | HDCP14_KSV_LIST_DONE_MASK_N, AVP_1_INT_MASK_N);
mdelay(50);
hdcp_modb(hdcp, HDCP14_ENCRYPTION_ENABLE | HDCP14_HPD_EN,
HDCP14_ENCRYPTION_ENABLE_MASK | HDCP14_HPD_MASK,
HDCP14_CONFIG0);
hdcp->status = DW_HDCP_AUTH_START;
dev_info(hdcp->dev, "start hdcp\n");
mutex_unlock(&hdcp->mutex);
queue_work(hdcp->workqueue, &hdcp->work);
return 0;
}
static int dw_hdcp_qp_hdcp_stop(struct dw_qp_hdcp *hdcp)
{
mutex_lock(&hdcp->mutex);
hdcp_modb(hdcp, 0, HDCP14_ENCRYPTION_ENABLE_MASK | HDCP14_HPD_MASK,
HDCP14_CONFIG0);
hdcp_modb(hdcp, 0, HDCP14_AUTH_CHG_MASK_N | HDCP14_KSV_LIST_DONE_MASK_N, AVP_1_INT_MASK_N);
hdcp->write(hdcp->hdmi, 0, HDCP14_CONFIG1);
hdcp->status = DW_HDCP_DISABLED;
mutex_unlock(&hdcp->mutex);
return 0;
}
static void sha_reset(struct sha_t *sha)
{
u32 i = 0;
sha->mindex = 0;
sha->mcomputed = false;
sha->mcorrupted = false;
for (i = 0; i < sizeof(sha->mlength); i++)
sha->mlength[i] = 0;
sha1_init(sha->mdigest);
}
static void sha_processblock(struct sha_t *sha)
{
u32 array[SHA1_WORKSPACE_WORDS];
sha1_transform(sha->mdigest, sha->mblock, array);
sha->mindex = 0;
}
static void sha_padmessage(struct sha_t *sha)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (sha->mindex > 55) {
sha->mblock[sha->mindex++] = 0x80;
while (sha->mindex < 64)
sha->mblock[sha->mindex++] = 0;
sha_processblock(sha);
while (sha->mindex < 56)
sha->mblock[sha->mindex++] = 0;
} else {
sha->mblock[sha->mindex++] = 0x80;
while (sha->mindex < 56)
sha->mblock[sha->mindex++] = 0;
}
/* Store the message length as the last 8 octets */
sha->mblock[56] = sha->mlength[7];
sha->mblock[57] = sha->mlength[6];
sha->mblock[58] = sha->mlength[5];
sha->mblock[59] = sha->mlength[4];
sha->mblock[60] = sha->mlength[3];
sha->mblock[61] = sha->mlength[2];
sha->mblock[62] = sha->mlength[1];
sha->mblock[63] = sha->mlength[0];
sha_processblock(sha);
}
static int sha_result(struct sha_t *sha)
{
if (sha->mcorrupted)
return false;
if (sha->mcomputed == 0) {
sha_padmessage(sha);
sha->mcomputed = true;
}
return true;
}
static void sha_input(struct sha_t *sha, const u8 *data, u32 size)
{
int i = 0;
unsigned int j = 0;
int rc = true;
if (data == 0 || size == 0)
return;
if (sha->mcomputed || sha->mcorrupted) {
sha->mcorrupted = true;
return;
}
while (size-- && !sha->mcorrupted) {
sha->mblock[sha->mindex++] = *data;
for (i = 0; i < 8; i++) {
rc = true;
for (j = 0; j < sizeof(sha->mlength); j++) {
sha->mlength[j]++;
if (sha->mlength[j] != 0) {
rc = false;
break;
}
}
sha->mcorrupted = (sha->mcorrupted ||
rc) ? true : false;
}
/* if corrupted then message is too long */
if (sha->mindex == 64)
sha_processblock(sha);
data++;
}
}
static int hdcp_verify_ksv(const u8 *data, u32 size)
{
u32 i = 0;
struct sha_t sha;
if ((!data) || (size < (HEADER + SHAMAX)))
return false;
sha_reset(&sha);
sha_input(&sha, data, size - SHAMAX);
if (sha_result(&sha) == false)
return false;
for (i = 0; i < SHAMAX; i++) {
if (data[size - SHAMAX + i] != (u8)(sha.mdigest[i / 4] >> ((i % 4) * 8)))
return false;
}
return true;
}
static void dw_hdcp_qp_hdcp_2nd_auth(struct dw_qp_hdcp *hdcp)
{
u8 *data;
u32 len;
len = (hdcp->read(hdcp->hdmi, HDCP14_STATUS0) & HDCP14_RPT_DEVICE_COUNT) >> 9;
len = len * KSV_LEN + BSTATUS_LEN + M0_LEN + SHAMAX;
data = kmalloc(len, GFP_KERNEL);
if (!data)
return;
hdcp->get_mem(hdcp->hdmi, data, len);
if (hdcp_verify_ksv(data, len))
hdcp->write(hdcp->hdmi, HDCP14_SHA1_MSG_CORRECT_P, HDCP14_CONFIG1);
else
dw_hdcp_qp_hdcp_restart(hdcp);
}
static void dw_hdcp_qp_hdcp_auth(struct dw_qp_hdcp *hdcp, u32 hdcp_status)
{
if (!(hdcp_status & BIT(2))) {
mutex_lock(&hdcp->mutex);
if (hdcp->status == DW_HDCP_DISABLED) {
mutex_unlock(&hdcp->mutex);
return;
}
dev_err(hdcp->dev, "hdcp auth failed\n");
hdcp_modb(hdcp, 0, HDCP14_ENCRYPTION_ENABLE_MASK | HDCP14_HPD_MASK,
HDCP14_CONFIG0);
hdcp->status = DW_HDCP_AUTH_FAIL;
mutex_unlock(&hdcp->mutex);
dw_hdcp_qp_hdcp_restart(hdcp);
} else {
mutex_lock(&hdcp->mutex);
dev_info(hdcp->dev, "hdcp auth success\n");
hdcp->status = DW_HDCP_AUTH_SUCCESS;
mutex_unlock(&hdcp->mutex);
}
}
static void dw_hdcp_qp_hdcp_isr(struct dw_qp_hdcp *hdcp, u32 avp_int, u32 hdcp_status)
{
if (hdcp->status == DW_HDCP_DISABLED)
return;
dev_info(hdcp->dev, "hdcp_int is 0x%02x\n", hdcp_status);
if (avp_int & HDCP14_KSV_LIST_DONE_MASK_N)
dw_hdcp_qp_hdcp_2nd_auth(hdcp);
if (avp_int & HDCP14_AUTH_CHG_MASK_N)
dw_hdcp_qp_hdcp_auth(hdcp, hdcp_status);
}
static ssize_t trytimes_show(struct device *device,
struct device_attribute *attr, char *buf)
{
int trytimes = 0;
struct dw_qp_hdcp *hdcp = dev_get_drvdata(device);
if (hdcp)
trytimes = hdcp->retry_times;
return snprintf(buf, PAGE_SIZE, "%d\n", trytimes);
}
static ssize_t trytimes_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
int trytimes;
struct dw_qp_hdcp *hdcp = dev_get_drvdata(device);
if (!hdcp)
return -EINVAL;
if (kstrtoint(buf, 0, &trytimes))
return -EINVAL;
if (hdcp->retry_times != trytimes) {
hdcp->retry_times = trytimes;
hdcp->remaining_times = hdcp->retry_times;
}
return count;
}
static DEVICE_ATTR_RW(trytimes);
static ssize_t status_show(struct device *device,
struct device_attribute *attr, char *buf)
{
int status = DW_HDCP_DISABLED;
struct dw_qp_hdcp *hdcp = dev_get_drvdata(device);
if (hdcp)
status = hdcp->status;
if (status == DW_HDCP_DISABLED)
return snprintf(buf, PAGE_SIZE, "hdcp disable\n");
else if (status == DW_HDCP_AUTH_START)
return snprintf(buf, PAGE_SIZE, "hdcp_auth_start\n");
else if (status == DW_HDCP_AUTH_SUCCESS)
return snprintf(buf, PAGE_SIZE, "hdcp_auth_success\n");
else if (status == DW_HDCP_AUTH_FAIL)
return snprintf(buf, PAGE_SIZE, "hdcp_auth_fail\n");
else
return snprintf(buf, PAGE_SIZE, "unknown status\n");
}
static DEVICE_ATTR_RO(status);
static struct attribute *dw_hdmi_qp_hdcp_attrs[] = {
&dev_attr_trytimes.attr,
&dev_attr_status.attr,
NULL
};
ATTRIBUTE_GROUPS(dw_hdmi_qp_hdcp);
/* If sink is a repeater, we need to wait ksv list ready */
static void dw_hdmi_qp_hdcp(struct work_struct *p_work)
{
struct dw_qp_hdcp *hdcp = container_of(p_work, struct dw_qp_hdcp, work);
u32 val;
int i = 500;
while (i--) {
usleep_range(7000, 8000);
mutex_lock(&hdcp->mutex);
if (hdcp->status == DW_HDCP_DISABLED) {
dev_dbg(hdcp->dev, "hdcp is disabled, don't wait repeater ready\n");
mutex_unlock(&hdcp->mutex);
return;
}
val = hdcp->read(hdcp->hdmi, HDCP14_STATUS1);
/* sink isn't repeater or ksv fifo ready, stop waiting */
if (!(val & HDCP14_RCV_REPEATER) || (val & HDCP14_RCV_KSV_FIFO_READY)) {
dev_dbg(hdcp->dev, "wait ksv fifo finished\n");
mutex_unlock(&hdcp->mutex);
return;
}
mutex_unlock(&hdcp->mutex);
}
if (i < 0) {
dev_err(hdcp->dev, "wait repeater ready time out\n");
dw_hdcp_qp_hdcp_restart(hdcp);
}
}
static int dw_hdcp_qp_hdcp_probe(struct platform_device *pdev)
{
int ret = 0;
struct dw_qp_hdcp *hdcp = pdev->dev.platform_data;
/* retry time if hdcp auth fail. unlimited time if set 0 */
hdcp->dev = &pdev->dev;
hdcp->hdcp_start = dw_hdcp_qp_hdcp_start;
hdcp->hdcp_stop = dw_hdcp_qp_hdcp_stop;
hdcp->hdcp_isr = dw_hdcp_qp_hdcp_isr;
ret = device_add_groups(hdcp->dev, dw_hdmi_qp_hdcp_groups);
if (ret) {
dev_err(hdcp->dev, "Failed to add sysfs files group\n");
return ret;
}
platform_set_drvdata(pdev, hdcp);
hdcp->workqueue = create_workqueue("hdcp_queue");
INIT_WORK(&hdcp->work, dw_hdmi_qp_hdcp);
hdcp->retry_times = 3;
mutex_init(&hdcp->mutex);
dev_info(hdcp->dev, "%s success\n", __func__);
return 0;
}
static int dw_hdcp_qp_hdcp_remove(struct platform_device *pdev)
{
struct dw_qp_hdcp *hdcp = pdev->dev.platform_data;
cancel_work_sync(&hdcp->work);
flush_workqueue(hdcp->workqueue);
destroy_workqueue(hdcp->workqueue);
device_remove_groups(hdcp->dev, dw_hdmi_qp_hdcp_groups);
kfree(hdcp->keys);
kfree(hdcp->seeds);
return 0;
}
static struct platform_driver dw_hdcp_qp_hdcp_driver = {
.probe = dw_hdcp_qp_hdcp_probe,
.remove = dw_hdcp_qp_hdcp_remove,
.driver = {
.name = DW_HDCP_QP_DRIVER_NAME,
},
};
module_platform_driver(dw_hdcp_qp_hdcp_driver);
MODULE_DESCRIPTION("DW HDMI QP transmitter HDCP driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) Rockchip Electronics Co.Ltd
* Author:
* Algea Cao <algea.cao@rock-chips.com>
*/
#ifndef DW_HDMI_QP_HDCP_H
#define DW_HDMI_QP_HDCP_H
#include <linux/miscdevice.h>
#define DW_HDCP_QP_DRIVER_NAME "dw-hdmi-qp-hdcp"
#define PRIVATE_KEY_SIZE 280
#define KEY_SHA_SIZE 20
#define KSV_LEN 5
#define BSTATUS_LEN 2
#define M0_LEN 8
#define SHAMAX 20
struct dw_hdmi_qp_hdcp_keys {
u8 KSV[8];
u8 devicekey[PRIVATE_KEY_SIZE];
u8 sha1[KEY_SHA_SIZE];
};
struct dw_qp_hdcp {
int retry_times;
int remaining_times;
char *seeds;
int invalidkey;
char *invalidkeys;
int hdcp2_enable;
int status;
u32 reg_io_width;
struct dw_hdmi_qp_hdcp_keys *keys;
struct device *dev;
struct dw_hdmi_qp *hdmi;
void __iomem *regs;
struct mutex mutex;
struct work_struct work;
struct workqueue_struct *workqueue;
void (*write)(struct dw_hdmi_qp *hdmi, u32 val, int offset);
u32 (*read)(struct dw_hdmi_qp *hdmi, int offset);
void (*get_mem)(struct dw_hdmi_qp *hdmi, u8 *data, u32 len);
int (*hdcp_start)(struct dw_qp_hdcp *hdcp);
int (*hdcp_stop)(struct dw_qp_hdcp *hdcp);
void (*hdcp_isr)(struct dw_qp_hdcp *hdcp, u32 avp_int, u32 hdcp_status);
};
#endif

View File

@@ -4,6 +4,7 @@
* Author:
* Algea Cao <algea.cao@rock-chips.com>
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -25,6 +26,7 @@
#include <drm/drm_dsc.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
#include <drm/drm_hdcp.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
@@ -38,6 +40,7 @@
#include "dw-hdmi-qp-audio.h"
#include "dw-hdmi-qp.h"
#include "dw-hdmi-qp-cec.h"
#include "dw-hdmi-qp-hdcp.h"
#include <media/cec-notifier.h>
@@ -52,6 +55,19 @@
#define HDMI14_MAX_TMDSCLK 340000000
#define HDMI20_MAX_TMDSCLK_KHZ 600000
#define HDMI_VH0 0x20
#define HDMI_HDCP_ADDR 0x3a
#define HDMI_BCAPS 0x40
#define HDMI_HDCP14_SUPPORT BIT(7)
#define HDMI_HDCP2_VERSION 0x50
#define HDMI_HDCP2_SUPPORT BIT(2)
#define SINK_CAP_HDCP14 BIT(0)
#define SINK_CAP_HDCP2 BIT(1)
#define HDMI_HDCP2_AUTH BIT(1)
#define HDMI_HDCP14_AUTH BIT(0)
static const unsigned int dw_hdmi_cable[] = {
EXTCON_DISP_HDMI,
EXTCON_NONE,
@@ -231,7 +247,7 @@ struct dw_hdmi_qp {
struct hdmi_qp_data_info hdmi_data;
const struct dw_hdmi_plat_data *plat_data;
struct dw_qp_hdcp *hdcp;
int vic;
int main_irq;
int avp_irq;
@@ -250,6 +266,7 @@ struct dw_hdmi_qp {
struct i2c_adapter *ddc;
void __iomem *regs;
void __iomem *hdcp14_mem;
bool sink_is_hdmi;
bool sink_has_audio;
bool dclk_en;
@@ -270,6 +287,8 @@ struct dw_hdmi_qp {
bool rxsense; /* rxsense state */
u8 phy_mask; /* desired phy int mask settings */
u8 mc_clkdis; /* clock disable register */
u8 hdcp_caps;
u8 hdcp_status;
bool update;
bool hdr2sdr;
@@ -947,8 +966,6 @@ static void dw_hdmi_i2c_init(struct dw_hdmi_qp *hdmi)
/* Software reset */
hdmi_writel(hdmi, 0x01, I2CM_CONTROL0);
hdmi_writel(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0);
hdmi_modb(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0);
/* Clear DONE and ERROR interrupts */
@@ -1879,6 +1896,58 @@ hdmi_get_tmdsclock(struct dw_hdmi_qp *hdmi, unsigned long mpixelclock)
return tmdsclock;
}
static void dw_hdmi_qp_hdcp_enable(struct dw_hdmi_qp *hdmi,
struct drm_connector *connector)
{
int ret, val;
const struct drm_connector_state *conn_state = connector->state;
void *data = hdmi->plat_data->phy_data;
if (conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_DESIRED)
return;
/* sink support hdcp2.x */
if (hdmi->hdcp_caps & SINK_CAP_HDCP2) {
hdmi_writel(hdmi, HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ, AVP_3_INT_CLEAR);
hdmi_modb(hdmi, HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ,
HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ, AVP_3_INT_MASK_N);
hdmi_writel(hdmi, 0x35, HDCP2LOGIC_ESM_GPIO_IN);
hdmi_modb(hdmi, 0, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
if (hdmi->plat_data->set_hdcp2_enable)
hdmi->plat_data->set_hdcp2_enable(data, true);
/* wait hdcp2.X auth success */
ret = regmap_read_poll_timeout(hdmi->regm, HDCP2LOGIC_ESM_GPIO_OUT, val,
FIELD_GET(HDCP2_AUTHENTICATION_SUCCESS, val),
10000, 2000000);
if (ret) {
hdmi->hdcp_status &= ~HDMI_HDCP2_AUTH;
dev_info(hdmi->dev, "hdcp2 auth failed,start hdcp1.4\n");
hdmi_writel(hdmi, 0, HDCP2LOGIC_ESM_GPIO_IN);
hdmi_modb(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
if (hdmi->plat_data->set_hdcp2_enable)
hdmi->plat_data->set_hdcp2_enable(data, false);
if (hdmi->hdcp && hdmi->hdcp->hdcp_start)
hdmi->hdcp->hdcp_start(hdmi->hdcp);
goto exit;
}
hdmi->hdcp_status |= HDMI_HDCP2_AUTH;
drm_hdcp_update_content_protection(connector, DRM_MODE_CONTENT_PROTECTION_ENABLED);
dev_info(hdmi->dev, "HDCP2 authentication succeed\n");
} else {
if (hdmi->hdcp && hdmi->hdcp->hdcp_start)
hdmi->hdcp->hdcp_start(hdmi->hdcp);
}
exit:
if (hdmi->plat_data->set_hdcp_status)
hdmi->plat_data->set_hdcp_status(data, hdmi->hdcp_status);
}
static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi,
const struct drm_connector *connector,
struct drm_display_mode *mode)
@@ -2040,6 +2109,7 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi,
dev_info(hdmi->dev, "%s DVI mode\n", __func__);
}
dw_hdmi_qp_hdcp_enable(hdmi, hdmi->curr_conn);
hdmi->frl_switch = false;
return 0;
}
@@ -2129,6 +2199,58 @@ static bool dw_hdmi_qp_check_output_type_changed(struct dw_hdmi_qp *hdmi)
return false;
}
static ssize_t hdcp_ddc_read(struct i2c_adapter *adapter, u8 address,
u8 offset, void *buffer)
{
int ret;
struct i2c_msg msgs[2] = {
{
.addr = address,
.flags = 0,
.len = 1,
.buf = &offset,
}, {
.addr = address,
.flags = I2C_M_RD,
.len = 1,
.buf = buffer,
}
};
ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
return ret;
if (ret != ARRAY_SIZE(msgs))
return -EPROTO;
return 0;
}
static u8 dw_hdmi_qp_hdcp_capable(struct dw_hdmi_qp *hdmi)
{
u8 version = 0;
u8 bcaps;
int ret;
ret = hdcp_ddc_read(hdmi->ddc, HDMI_HDCP_ADDR, HDMI_BCAPS, &bcaps);
if (ret < 0) {
dev_err(hdmi->dev, "get hdcp1.4 capable failed:%d\n", ret);
return 0;
}
if (bcaps & HDMI_HDCP14_SUPPORT)
version |= SINK_CAP_HDCP14;
ret = hdcp_ddc_read(hdmi->ddc, HDMI_HDCP_ADDR, HDMI_HDCP2_VERSION, &bcaps);
if (ret < 0) {
dev_err(hdmi->dev, "get hdcp2.x capable failed:%d\n", ret);
return 0;
}
if (bcaps & HDMI_HDCP2_SUPPORT)
version |= SINK_CAP_HDCP2;
return version;
}
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
struct dw_hdmi_qp *hdmi =
@@ -2139,6 +2261,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
struct drm_display_mode *mode;
struct drm_display_info *info = &connector->display_info;
void *data = hdmi->plat_data->phy_data;
struct drm_property_blob *edid_blob_ptr = connector->edid_blob_ptr;
int i, ret = 0;
if (hdmi->plat_data->right && hdmi->plat_data->right->next_bridge) {
@@ -2160,7 +2283,17 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
memset(metedata, 0, sizeof(*metedata));
edid = drm_get_edid(connector, hdmi->ddc);
if (edid_blob_ptr && edid_blob_ptr->length) {
edid = kmalloc(edid_blob_ptr->length, GFP_KERNEL);
if (!edid)
return -ENOMEM;
memcpy(edid, edid_blob_ptr->data, edid_blob_ptr->length);
} else {
edid = drm_get_edid(connector, hdmi->ddc);
hdmi->hdcp_caps = dw_hdmi_qp_hdcp_capable(hdmi);
}
if (edid) {
dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
edid->width_cm, edid->height_cm);
@@ -2178,6 +2311,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
if (hdmi->plat_data->get_yuv422_format)
hdmi->plat_data->get_yuv422_format(connector, edid);
dw_hdmi_update_hdr_property(connector);
hdmi->hdcp_caps = dw_hdmi_qp_hdcp_capable(hdmi);
if (ret > 0 && hdmi->plat_data->split_mode) {
struct dw_hdmi_qp *secondary = NULL;
void *secondary_data;
@@ -2187,8 +2321,10 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
else if (hdmi->plat_data->right)
secondary = hdmi->plat_data->right;
if (!secondary)
if (!secondary) {
kfree(edid);
return -ENOMEM;
}
secondary_data = secondary->plat_data->phy_data;
list_for_each_entry(mode, &connector->probed_modes, head)
@@ -2460,6 +2596,37 @@ static bool check_hdr_color_change(struct drm_connector_state *old_state,
return false;
}
static bool check_dw_hdcp_state_changed(struct drm_connector *conn,
struct drm_atomic_state *state)
{
struct drm_connector_state *old_state, *new_state;
u64 old_cp, new_cp;
old_state = drm_atomic_get_old_connector_state(state, conn);
new_state = drm_atomic_get_new_connector_state(state, conn);
old_cp = old_state->content_protection;
new_cp = new_state->content_protection;
if (old_state->hdcp_content_type != new_state->hdcp_content_type &&
new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
return true;
}
if (!new_state->crtc) {
if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
return false;
}
if (old_cp == new_cp ||
(old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED))
return false;
return true;
}
static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
struct drm_atomic_state *state)
{
@@ -2605,6 +2772,9 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
}
}
if (check_dw_hdcp_state_changed(connector, state))
crtc_state->mode_changed = true;
return 0;
}
@@ -2791,6 +2961,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
void *data = hdmi->plat_data->phy_data;
const struct drm_connector_state *conn_state = hdmi->curr_conn->state;
if (hdmi->panel)
drm_panel_disable(hdmi->panel);
@@ -2799,6 +2970,19 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
hdmi_writel(hdmi, 1, PKTSCHED_PKT_CONTROL0);
mdelay(50);
hdmi_modb(hdmi, 0, HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ,
AVP_3_INT_MASK_N);
if (hdmi->hdcp && hdmi->hdcp->hdcp_stop)
hdmi->hdcp->hdcp_stop(hdmi->hdcp);
hdmi_writel(hdmi, 0, HDCP2LOGIC_ESM_GPIO_IN);
if (conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
drm_hdcp_update_content_protection(hdmi->curr_conn,
DRM_MODE_CONTENT_PROTECTION_DESIRED);
if (hdmi->plat_data->set_hdcp_status)
hdmi->plat_data->set_hdcp_status(data, hdmi->hdcp_status);
extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, false);
handle_plugged_change(hdmi, false);
mutex_lock(&hdmi->mutex);
@@ -2815,7 +2999,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
hdmi_writel(hdmi, 0, FLT_CONFIG0);
hdmi_writel(hdmi, 0, SCRAMB_CONFIG0);
/* set sink frl mode disable */
if (hdmi->curr_conn && dw_hdmi_support_scdc(hdmi, &hdmi->curr_conn->display_info))
if (dw_hdmi_support_scdc(hdmi, &hdmi->curr_conn->display_info))
drm_scdc_writeb(hdmi->ddc, 0x31, 0);
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
@@ -2947,17 +3131,77 @@ static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_avp_hardirq(int irq, void *dev_id)
{
struct dw_hdmi_qp *hdmi = dev_id;
u32 stat;
u32 stat1, stat3;
stat = hdmi_readl(hdmi, AVP_1_INT_STATUS);
if (stat) {
dev_dbg(hdmi->dev, "HDCP irq %#x\n", stat);
stat &= ~stat;
hdmi_writel(hdmi, stat, AVP_1_INT_MASK_N);
return IRQ_WAKE_THREAD;
stat1 = hdmi_readl(hdmi, AVP_1_INT_STATUS);
stat3 = hdmi_readl(hdmi, AVP_3_INT_STATUS);
if (!stat1 && !stat3)
return IRQ_NONE;
return IRQ_WAKE_THREAD;
}
static irqreturn_t dw_hdmi_qp_avp_irq(int irq, void *dev_id)
{
struct dw_hdmi_qp *hdmi = dev_id;
struct drm_connector_state *conn_state;
void *data = hdmi->plat_data->phy_data;
u32 stat1, stat3, val;
stat1 = hdmi_readl(hdmi, AVP_1_INT_STATUS);
stat3 = hdmi_readl(hdmi, AVP_3_INT_STATUS);
hdmi_writel(hdmi, stat1, AVP_1_INT_CLEAR);
hdmi_writel(hdmi, stat3, AVP_3_INT_CLEAR);
if (!hdmi->curr_conn || !hdmi->curr_conn->state)
return IRQ_HANDLED;
conn_state = hdmi->curr_conn->state;
val = conn_state->content_protection;
if (hdmi->hdcp && hdmi->hdcp->hdcp_isr) {
u32 hdcp_status = hdmi_readl(hdmi, HDCP14_STATUS0);
if (stat1 & HDCP14_AUTH_CHG_MASK_N) {
/* hdcp14 auth success */
if (hdcp_status & BIT(2)) {
hdmi->hdcp_status |= HDMI_HDCP14_AUTH;
if (conn_state->content_protection !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
val = DRM_MODE_CONTENT_PROTECTION_ENABLED;
} else if (!(hdcp_status & BIT(2))) {
hdmi->hdcp_status &= ~HDMI_HDCP14_AUTH;
if (conn_state->content_protection !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
val = DRM_MODE_CONTENT_PROTECTION_DESIRED;
}
conn_state->content_protection = val;
}
hdmi->hdcp->hdcp_isr(hdmi->hdcp, stat1, hdcp_status);
}
return IRQ_NONE;
if (stat3 & HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ) {
stat3 = hdmi_readl(hdmi, HDCP2LOGIC_ESM_GPIO_OUT);
if (stat3 & HDCP2_AUTHENTICATION_SUCCESS) {
hdmi->hdcp_status |= HDMI_HDCP2_AUTH;
if (conn_state->content_protection !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
val = DRM_MODE_CONTENT_PROTECTION_ENABLED;
} else if (!(stat3 & HDCP2_AUTHENTICATION_SUCCESS)) {
hdmi->hdcp_status &= ~HDMI_HDCP2_AUTH;
if (conn_state->content_protection !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
val = DRM_MODE_CONTENT_PROTECTION_DESIRED;
}
conn_state->content_protection = val;
}
if (hdmi->plat_data->set_hdcp_status)
hdmi->plat_data->set_hdcp_status(data, hdmi->hdcp_status);
return IRQ_HANDLED;
}
static irqreturn_t dw_hdmi_qp_earc_hardirq(int irq, void *dev_id)
@@ -2976,21 +3220,6 @@ static irqreturn_t dw_hdmi_qp_earc_hardirq(int irq, void *dev_id)
return IRQ_NONE;
}
static irqreturn_t dw_hdmi_qp_avp_irq(int irq, void *dev_id)
{
struct dw_hdmi_qp *hdmi = dev_id;
u32 stat;
stat = hdmi_readl(hdmi, AVP_1_INT_STATUS);
if (!stat)
return IRQ_NONE;
hdmi_writel(hdmi, stat, AVP_1_INT_CLEAR);
return IRQ_HANDLED;
}
static irqreturn_t dw_hdmi_qp_earc_irq(int irq, void *dev_id)
{
struct dw_hdmi_qp *hdmi = dev_id;
@@ -3383,6 +3612,70 @@ static void dw_hdmi_register_debugfs(struct device *dev, struct dw_hdmi_qp *hdmi
hdmi, &dw_hdmi_ctrl_fops);
}
static void dw_hdmi_qp_hdcp14_get_mem(struct dw_hdmi_qp *hdmi, u8 *data, u32 len)
{
u32 ksv_len, i, val;
void *hdmi_data = hdmi->plat_data->phy_data;
if (hdmi->plat_data->set_hdcp14_mem)
hdmi->plat_data->set_hdcp14_mem(hdmi_data, true);
ksv_len = len - BSTATUS_LEN - M0_LEN - SHAMAX;
for (i = 0; i < len; i++) {
/* read ksv list */
if (i < ksv_len)
val = readl(hdmi->hdcp14_mem + HDMI_HDCP14_MEM_KSV0 + i * 4);
/* read bstatus */
else if (i < len - SHAMAX - M0_LEN)
val = readl(hdmi->hdcp14_mem + HDMI_HDCP14_MEM_BSTATUS0 +
(i - ksv_len) * 4);
/* read M0 */
else if (i < len - SHAMAX)
val = readl(hdmi->hdcp14_mem + HDMI_HDCP14_MEM_M0_1 +
(i - ksv_len - BSTATUS_LEN) * 4);
else
/* VH0 save in external memory is error, we need to read VH0 via ddc */
hdcp_ddc_read(hdmi->ddc, HDMI_HDCP_ADDR, HDMI_VH0 + i - (len - SHAMAX),
&val);
data[i] = val;
}
if (hdmi->plat_data->set_hdcp14_mem)
hdmi->plat_data->set_hdcp14_mem(hdmi_data, false);
}
static int dw_hdmi_qp_register_hdcp(struct device *dev,
struct dw_hdmi_qp *hdmi)
{
struct dw_qp_hdcp hdmi_hdcp = {
.hdmi = hdmi,
.write = hdmi_writel,
.read = hdmi_readl,
.regs = hdmi->regs,
.get_mem = dw_hdmi_qp_hdcp14_get_mem,
};
struct platform_device_info hdcp_device_info = {
.parent = dev,
.id = PLATFORM_DEVID_AUTO,
.res = NULL,
.num_res = 0,
.name = DW_HDCP_QP_DRIVER_NAME,
.data = &hdmi_hdcp,
.size_data = sizeof(hdmi_hdcp),
.dma_mask = DMA_BIT_MASK(32),
};
hdmi->hdcp_dev = platform_device_register_full(&hdcp_device_info);
if (IS_ERR(hdmi->hdcp_dev)) {
dev_err(dev, "failed to register hdcp!\n");
return -ENOMEM;
}
hdmi->hdcp = hdmi->hdcp_dev->dev.platform_data;
return 0;
}
static struct dw_hdmi_qp *
__dw_hdmi_probe(struct platform_device *pdev,
const struct dw_hdmi_plat_data *plat_data)
@@ -3558,7 +3851,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
hdmi->avp_irq = irq;
ret = devm_request_threaded_irq(dev, hdmi->avp_irq,
dw_hdmi_qp_avp_hardirq,
dw_hdmi_qp_avp_irq, IRQF_SHARED,
dw_hdmi_qp_avp_irq, IRQF_ONESHOT,
dev_name(dev), hdmi);
if (ret)
goto err_aud;
@@ -3611,6 +3904,20 @@ __dw_hdmi_probe(struct platform_device *pdev,
dw_hdmi_register_debugfs(dev, hdmi);
if (hdmi_readl(hdmi, CONFIG_REG) & CONFIG_HDCP14) {
iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
hdmi->hdcp14_mem = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->hdcp14_mem)) {
ret = PTR_ERR(hdmi->hdcp14_mem);
goto err_cec;
}
ret = dw_hdmi_qp_register_hdcp(dev, hdmi);
if (ret)
goto err_cec;
}
return hdmi;
err_cec:
@@ -3663,6 +3970,8 @@ static void __dw_hdmi_remove(struct dw_hdmi_qp *hdmi)
hdmi->bridge.encoder->funcs->destroy(hdmi->bridge.encoder);
if (!IS_ERR(hdmi->cec))
platform_device_unregister(hdmi->cec);
if (!IS_ERR(hdmi->hdcp_dev))
platform_device_unregister(hdmi->hdcp_dev);
if (hdmi->i2c)
i2c_del_adapter(&hdmi->i2c->adap);
else
@@ -3753,6 +4062,7 @@ void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
disable_irq(hdmi->earc_irq);
pinctrl_pm_select_sleep_state(dev);
drm_connector_update_edid_property(&hdmi->connector, NULL);
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend);

View File

@@ -13,6 +13,7 @@
#define CONFIG_REG 0xc
#define CONFIG_CEC BIT(28)
#define CONFIG_AUD_UD BIT(23)
#define CONFIG_HDCP14 BIT(8)
#define CORE_TIMESTAMP_HHMM 0x14
#define CORE_TIMESTAMP_MMDD 0x18
#define CORE_TIMESTAMP_YYYY 0x1c
@@ -139,7 +140,7 @@
#define FRAME_COMPOSER_CONFIG8 0x860
#define FRAME_COMPOSER_CONFIG9 0x864
#define KEEPOUT_REKEY_CFG GENMASK(9, 8)
#define KEEPOUT_REKEY_ALWAYS 0x2
#define KEEPOUT_REKEY_ALWAYS (0x2 << 8)
#define FRAME_COMPOSER_CONTROL0 0x86c
/* Video Monitor Registers */
#define VIDEO_MONITOR_CONFIG0 0x880
@@ -155,9 +156,13 @@
#define HDCP2_BYPASS BIT(0)
#define HDCP2LOGIC_ESM_GPIO_IN 0x8e4
#define HDCP2LOGIC_ESM_GPIO_OUT 0x8e8
#define HDCP2_AUTHENTICATION_SUCCESS BIT(6)
/* HDCP14 Registers */
#define HDCP14_CONFIG0 0x900
#define HDCP14_OESS_ESSS_OVR_VALUE BIT(14)
#define HDCP14_OESS_ESSS_OVR_EN BIT(13)
#define HDCP14_CONFIG1 0x904
#define HDCP14_SHA1_MSG_CORRECT_P BIT(3)
#define HDCP14_CONFIG2 0x908
#define HDCP14_CONFIG3 0x90c
#define HDCP14_KEY_SEED 0x914
@@ -169,7 +174,10 @@
#define HDCP14_AN_H 0x92c
#define HDCP14_AN_L 0x930
#define HDCP14_STATUS0 0x934
#define HDCP14_RPT_DEVICE_COUNT 0xFE00
#define HDCP14_STATUS1 0x938
#define HDCP14_RCV_REPEATER BIT(6)
#define HDCP14_RCV_KSV_FIFO_READY BIT(5)
/* Scrambler Registers */
#define SCRAMB_CONFIG0 0x960
/* Video Configuration Registers */
@@ -792,6 +800,7 @@
#define AVP_1_INT_STATUS 0x3820
#define AVP_1_INT_MASK_N 0x3824
#define HDCP14_AUTH_CHG_MASK_N BIT(6)
#define HDCP14_KSV_LIST_DONE_MASK_N BIT(1)
#define AVP_1_INT_CLEAR 0x3828
#define AVP_1_INT_FORCE 0x382c
#define AVP_2_INT_STATUS 0x3830
@@ -802,6 +811,7 @@
#define AVP_3_INT_MASK_N 0x3844
#define AVP_3_INT_CLEAR 0x3848
#define AVP_3_INT_FORCE 0x384c
#define HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ BIT(17)
#define AVP_4_INT_STATUS 0x3850
#define AVP_4_INT_MASK_N 0x3854
#define AVP_4_INT_CLEAR 0x3858
@@ -832,4 +842,9 @@
#define EARCRX_1_INT_CLEAR 0x4828
#define EARCRX_1_INT_FORCE 0x482c
#define HDMI_HDCP14_MEM_KSV0 0x4f08
#define HDMI_HDCP14_MEM_BSTATUS0 0x5958
#define HDMI_HDCP14_MEM_M0_1 0x5960
#define HDMI_HDCP14_MEM_M0_7 0x597c
#endif /* __DW_HDMI_QP_H__ */

View File

@@ -17,6 +17,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dsc.h>
#include <drm/drm_edid.h>
#include <drm/drm_hdcp.h>
#include <drm/bridge/dw_hdmi.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
@@ -105,6 +106,8 @@
#define RK3588_HDMI1_LEVEL_INT BIT(24)
#define RK3588_HDMI1_INTR_CHANGE_CNT (0x7 << 21)
#define RK3588_GRF_VO1_CON1 0x0004
#define HDCP1_P1_GPIO_IN BIT(9)
#define RK3588_GRF_VO1_CON3 0x000c
#define RK3588_COLOR_FORMAT_MASK 0xf
#define RK3588_RGB 0
@@ -129,6 +132,8 @@
#define RK3588_HDMI0_GRANT_SW BIT(11)
#define RK3588_HDMI1_GRANT_SEL BIT(12)
#define RK3588_HDMI1_GRANT_SW BIT(13)
#define RK3588_GRF_VO1_CON4 0x0010
#define RK3588_HDMI_HDCP14_MEM_EN BIT(15)
#define RK3588_GRF_VO1_CON6 0x0018
#define RK3588_GRF_VO1_CON7 0x001c
@@ -216,6 +221,7 @@ struct rockchip_hdmi {
struct drm_property *output_type_capacity;
struct drm_property *allm_capacity;
struct drm_property *allm_enable;
struct drm_property *hdcp_state_property;
struct drm_property_blob *hdr_panel_blob_ptr;
struct drm_property_blob *next_hdr_data_ptr;
@@ -232,6 +238,7 @@ struct rockchip_hdmi {
u8 max_lanes;
u8 add_func;
u8 edid_colorimetry;
u8 hdcp_status;
struct rockchip_drm_dsc_cap dsc_cap;
struct next_hdr_sink_data next_hdr_data;
struct dw_hdmi_link_config link_cfg;
@@ -1889,6 +1896,26 @@ static void rk3588_set_color_format(struct rockchip_hdmi *hdmi, u64 bus_format,
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
}
static void rk3588_set_hdcp_status(void *data, u8 status)
{
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
hdmi->hdcp_status = status;
}
static void rk3588_set_hdcp2_enable(void *data, bool enable)
{
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
u32 val;
if (enable)
val = HIWORD_UPDATE(HDCP1_P1_GPIO_IN, HDCP1_P1_GPIO_IN);
else
val = HIWORD_UPDATE(0, HDCP1_P1_GPIO_IN);
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON1, val);
}
static void rk3588_set_grf_cfg(void *data)
{
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
@@ -2562,6 +2589,18 @@ static void dw_hdmi_rockchip_set_ddc_io(void *data, bool enable)
}
}
static void dw_hdmi_rockchip_set_hdcp14_mem(void *data, bool enable)
{
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
u32 val;
val = HIWORD_UPDATE(enable << 15, RK3588_HDMI_HDCP14_MEM_EN);
if (!hdmi->id)
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON4, val);
else
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON7, val);
}
static const struct drm_prop_enum_list color_depth_enum_list[] = {
{ 0, "Automatic" }, /* Prefer highest color depth */
{ 8, "24bit" },
@@ -2608,6 +2647,7 @@ dw_hdmi_rockchip_attach_properties(struct drm_connector *connector,
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
struct drm_property *prop;
struct rockchip_drm_private *private = connector->dev->dev_private;
int ret;
switch (color) {
case MEDIA_BUS_FMT_RGB101010_1X30:
@@ -2776,6 +2816,21 @@ dw_hdmi_rockchip_attach_properties(struct drm_connector *connector,
drm_object_attach_property(&connector->base,
connector->colorspace_property, 0);
drm_object_attach_property(&connector->base, private->connector_id_prop, hdmi->id);
ret = drm_connector_attach_content_protection_property(connector, true);
if (ret) {
dev_err(hdmi->dev, "failed to attach content protection: %d\n", ret);
return;
}
prop = drm_property_create_range(connector->dev, 0, RK_IF_PROP_ENCRYPTED,
RK_IF_HDCP_ENCRYPTED_NONE, RK_IF_HDCP_ENCRYPTED_LEVEL2);
if (!prop) {
dev_err(hdmi->dev, "create hdcp encrypted prop for hdmi%d failed\n", hdmi->id);
return;
}
hdmi->hdcp_state_property = prop;
drm_object_attach_property(&connector->base, prop, RK_IF_HDCP_ENCRYPTED_NONE);
}
static void
@@ -2909,6 +2964,7 @@ dw_hdmi_rockchip_set_property(struct drm_connector *connector,
hdmi->enable_allm = val;
if (allm_enable != hdmi->enable_allm)
dw_hdmi_qp_set_allm_enable(hdmi->hdmi_qp, hdmi->enable_allm);
} else if (property == hdmi->hdcp_state_property) {
return 0;
}
@@ -2985,6 +3041,14 @@ dw_hdmi_rockchip_get_property(struct drm_connector *connector,
} else if (property == hdmi->allm_enable) {
*val = hdmi->enable_allm;
return 0;
} else if (property == hdmi->hdcp_state_property) {
if (hdmi->hdcp_status & BIT(1))
*val = RK_IF_HDCP_ENCRYPTED_LEVEL2;
else if (hdmi->hdcp_status & BIT(0))
*val = RK_IF_HDCP_ENCRYPTED_LEVEL1;
else
*val = RK_IF_HDCP_ENCRYPTED_NONE;
return 0;
}
DRM_ERROR("Unknown property [PROP:%d:%s]\n",
@@ -3458,6 +3522,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
plat_data->get_colorimetry =
dw_hdmi_rockchip_get_colorimetry;
plat_data->get_link_cfg = dw_hdmi_rockchip_get_link_cfg;
plat_data->set_hdcp2_enable = rk3588_set_hdcp2_enable;
plat_data->set_hdcp_status = rk3588_set_hdcp_status;
plat_data->set_grf_cfg = rk3588_set_grf_cfg;
plat_data->get_grf_color_fmt = rk3588_get_grf_color_fmt;
plat_data->convert_to_split_mode = drm_mode_convert_to_split_mode;
@@ -3473,6 +3539,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
dw_hdmi_rockchip_set_prev_bus_format;
plat_data->set_ddc_io =
dw_hdmi_rockchip_set_ddc_io;
plat_data->set_hdcp14_mem =
dw_hdmi_rockchip_set_hdcp14_mem;
plat_data->property_ops = &dw_hdmi_rockchip_property_ops;
secondary = rockchip_hdmi_find_by_id(dev->driver, !hdmi->id);

View File

@@ -2327,7 +2327,7 @@ static void vop_atomic_plane_reset(struct drm_plane *plane)
return;
__drm_atomic_helper_plane_reset(plane, &vop_plane_state->base);
win->state.zpos = win->zpos;
vop_plane_state->base.zpos = win->zpos;
vop_plane_state->global_alpha = 0xff;
}

View File

@@ -1883,6 +1883,7 @@ static const struct vop2_cluster_regs rk3568_vop_cluster0 = {
.afbc_enable = VOP_REG(RK3568_CLUSTER0_CTRL, 0x1, 1),
.enable = VOP_REG(RK3568_CLUSTER0_CTRL, 1, 0),
.lb_mode = VOP_REG(RK3568_CLUSTER0_CTRL, 0xf, 4),
.frm_reset_en = VOP_REG(RK3568_CLUSTER0_CTRL, 1, 31),
.src_color_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL, 0xffffffff, 0),
.dst_color_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_DST_COLOR_CTRL, 0xffffffff, 0),
.src_alpha_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0),
@@ -1893,6 +1894,7 @@ static const struct vop2_cluster_regs rk3568_vop_cluster1 = {
.afbc_enable = VOP_REG(RK3568_CLUSTER1_CTRL, 0x1, 1),
.enable = VOP_REG(RK3568_CLUSTER1_CTRL, 1, 0),
.lb_mode = VOP_REG(RK3568_CLUSTER1_CTRL, 0xf, 4),
.frm_reset_en = VOP_REG(RK3568_CLUSTER1_CTRL, 1, 31),
.src_color_ctrl = VOP_REG(RK3568_CLUSTER1_MIX_SRC_COLOR_CTRL, 0xffffffff, 0),
.dst_color_ctrl = VOP_REG(RK3568_CLUSTER1_MIX_DST_COLOR_CTRL, 0xffffffff, 0),
.src_alpha_ctrl = VOP_REG(RK3568_CLUSTER1_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0),
@@ -1903,6 +1905,7 @@ static const struct vop2_cluster_regs rk3588_vop_cluster2 = {
.afbc_enable = VOP_REG(RK3588_CLUSTER2_CTRL, 0x1, 1),
.enable = VOP_REG(RK3588_CLUSTER2_CTRL, 1, 0),
.lb_mode = VOP_REG(RK3588_CLUSTER2_CTRL, 0xf, 4),
.frm_reset_en = VOP_REG(RK3588_CLUSTER2_CTRL, 1, 31),
.src_color_ctrl = VOP_REG(RK3588_CLUSTER2_MIX_SRC_COLOR_CTRL, 0xffffffff, 0),
.dst_color_ctrl = VOP_REG(RK3588_CLUSTER2_MIX_DST_COLOR_CTRL, 0xffffffff, 0),
.src_alpha_ctrl = VOP_REG(RK3588_CLUSTER2_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0),
@@ -1913,6 +1916,7 @@ static const struct vop2_cluster_regs rk3588_vop_cluster3 = {
.afbc_enable = VOP_REG(RK3588_CLUSTER3_CTRL, 0x1, 1),
.enable = VOP_REG(RK3588_CLUSTER3_CTRL, 1, 0),
.lb_mode = VOP_REG(RK3588_CLUSTER3_CTRL, 0xf, 4),
.frm_reset_en = VOP_REG(RK3588_CLUSTER3_CTRL, 1, 31),
.src_color_ctrl = VOP_REG(RK3588_CLUSTER3_MIX_SRC_COLOR_CTRL, 0xffffffff, 0),
.dst_color_ctrl = VOP_REG(RK3588_CLUSTER3_MIX_DST_COLOR_CTRL, 0xffffffff, 0),
.src_alpha_ctrl = VOP_REG(RK3588_CLUSTER3_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0),

View File

@@ -82,6 +82,8 @@
#define GC2093_LANES 2
#define OF_CAMERA_HDR_MODE "rockchip,camera-hdr-mode"
static const char * const gc2093_supply_names[] = {
"dovdd", /* Digital I/O power */
"avdd", /* Analog power */
@@ -142,7 +144,6 @@ struct gc2093 {
struct mutex lock;
bool streaming;
bool power_on;
unsigned int cfg_num;
const struct gc2093_mode *cur_mode;
u32 module_index;
@@ -421,6 +422,138 @@ static const struct reg_sequence gc2093_1080p_hdr_settings[] = {
{0x024d, 0x01},
};
/*
* window size=1920*1080 mipi@2lane
* mclk=27M mipi_clk=792Mbps
* pixel_line_total=2640 line_frame_total=1500
* row_time=20us frame_rate=50fps
*/
static const struct reg_sequence gc2093_1080p_25fps_hdr_settings[] = {
/* System */
{0x03fe, 0x80},
{0x03fe, 0x80},
{0x03fe, 0x80},
{0x03fe, 0x00},
{0x03f2, 0x00},
{0x03f3, 0x00},
{0x03f4, 0x36},
{0x03f5, 0xc0},
{0x03f6, 0x0B},
{0x03f7, 0x01},
{0x03f8, 0x58},
{0x03f9, 0x40},
{0x03fc, 0x8e},
/* Cisctl & Analog */
{0x0087, 0x18},
{0x00ee, 0x30},
{0x00d0, 0xbf},
{0x01a0, 0x00},
{0x01a4, 0x40},
{0x01a5, 0x40},
{0x01a6, 0x40},
{0x01af, 0x09},
{0x0001, 0x00},
{0x0002, 0x02},
{0x0003, 0x04},
{0x0004, 0x02},
{0x0005, 0x02},
{0x0006, 0x94},
{0x0007, 0x00},
{0x0008, 0x11},
{0x0009, 0x00},
{0x000a, 0x02},
{0x000b, 0x00},
{0x000c, 0x04},
{0x000d, 0x04},
{0x000e, 0x40},
{0x000f, 0x07},
{0x0010, 0x8c},
{0x0013, 0x15},
{0x0019, 0x0c},
{0x0041, 0x05},
{0x0042, 0xdc},
{0x0053, 0x60},
{0x008d, 0x92},
{0x0090, 0x00},
{0x00c7, 0xe1},
{0x001b, 0x73},
{0x0028, 0x0d},
{0x0029, 0x24},
{0x002b, 0x04},
{0x002e, 0x23},
{0x0037, 0x03},
{0x0043, 0x04},
{0x0044, 0x20},
{0x004a, 0x01},
{0x004b, 0x20},
{0x0055, 0x30},
{0x006b, 0x44},
{0x0077, 0x00},
{0x0078, 0x20},
{0x007c, 0xa1},
{0x00d3, 0xd4},
{0x00e6, 0x50},
/* Gain */
{0x00b6, 0xc0},
{0x00b0, 0x60},
/* Isp */
{0x0102, 0x89},
{0x0104, 0x01},
{0x010e, 0x01},
{0x0158, 0x00},
{0x0183, 0x01},
{0x0187, 0x50},
/* Dark sun*/
{0x0123, 0x08},
{0x0123, 0x00},
{0x0120, 0x01},
{0x0121, 0x00},
{0x0122, 0x10},
{0x0124, 0x03},
{0x0125, 0xff},
{0x0126, 0x3c},
{0x001a, 0x8c},
{0x00c6, 0xe0},
/* Blk */
{0x0026, 0x30},
{0x0142, 0x00},
{0x0149, 0x1e},
{0x014a, 0x0f},
{0x014b, 0x00},
{0x0155, 0x00},
{0x0414, 0x78},
{0x0415, 0x78},
{0x0416, 0x78},
{0x0417, 0x78},
{0x0454, 0x78},
{0x0455, 0x78},
{0x0456, 0x78},
{0x0457, 0x78},
{0x04e0, 0x18},
/* Window */
{0x0192, 0x02},
{0x0194, 0x03},
{0x0195, 0x04},
{0x0196, 0x38},
{0x0197, 0x07},
{0x0198, 0x80},
/* MIPI */
{0x019a, 0x06},
{0x007b, 0x2a},
{0x0023, 0x2d},
{0x0201, 0x27},
{0x0202, 0x56},
{0x0203, 0xb6},
{0x0212, 0x80},
{0x0213, 0x07},
{0x0215, 0x12},
{0x003e, 0x91},
/* HDR En */
{0x0027, 0x71},
{0x0215, 0x92},
{0x024d, 0x01},
};
static const struct gc2093_mode supported_modes[] = {
{
.width = 1920,
@@ -457,6 +590,25 @@ static const struct gc2093_mode supported_modes[] = {
.vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1,
.vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2
},
{
.width = 1920,
.height = 1080,
.max_fps = {
.numerator = 10000,
.denominator = 250000,
},
.exp_def = 0x460,
.hts_def = 0xa50,
.vts_def = 0x5dc,
.link_freq_index = LINK_FREQ_396M_INDEX,
.reg_list = gc2093_1080p_25fps_hdr_settings,
.reg_num = ARRAY_SIZE(gc2093_1080p_25fps_hdr_settings),
.hdr_mode = HDR_X2,
.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_1,
.vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0
.vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1,
.vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2
},
};
/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
@@ -585,6 +737,7 @@ static int gc2093_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
dev_dbg(gc2093->dev, "set exposure value 0x%x\n", ctrl->val);
if (gc2093->cur_mode->hdr_mode != NO_HDR)
goto ctrl_end;
dev_dbg(gc2093->dev, "set exposure value 0x%x\n", ctrl->val);
@@ -594,28 +747,36 @@ static int gc2093_set_ctrl(struct v4l2_ctrl *ctrl)
ctrl->val & 0xff);
break;
case V4L2_CID_ANALOGUE_GAIN:
dev_dbg(gc2093->dev, "set gain value 0x%x, mode: %d\n",
ctrl->val, gc2093->cur_mode->hdr_mode);
if (gc2093->cur_mode->hdr_mode != NO_HDR)
goto ctrl_end;
dev_dbg(gc2093->dev, "set gain value 0x%x\n", ctrl->val);
gc2093_set_gain(gc2093, ctrl->val);
break;
case V4L2_CID_VBLANK:
dev_dbg(gc2093->dev, "set blank value 0x%x\n", ctrl->val);
vts = gc2093->cur_mode->height + ctrl->val;
gc2093->cur_vts = vts;
ret = gc2093_write_reg(gc2093, GC2093_REG_VTS_H,
(vts >> 8) & 0x3f);
ret |= gc2093_write_reg(gc2093, GC2093_REG_VTS_L,
vts & 0xff);
gc2093_modify_fps_info(gc2093);
if (!ret)
gc2093->cur_vts = ctrl->val + gc2093->cur_mode->height;
if (gc2093->cur_vts != gc2093->cur_mode->vts_def)
gc2093_modify_fps_info(gc2093);
dev_dbg(gc2093->dev, " set blank value 0x%x\n", ctrl->val);
break;
case V4L2_CID_HFLIP:
regmap_update_bits(gc2093->regmap, GC2093_MIRROR_FLIP_REG,
MIRROR_MASK, ctrl->val ? MIRROR_MASK : 0);
dev_dbg(gc2093->dev, "set hflip 0x%x\n", ctrl->val);
regmap_update_bits(gc2093->regmap, GC2093_MIRROR_FLIP_REG,
MIRROR_MASK, ctrl->val ? MIRROR_MASK : 0);
break;
case V4L2_CID_VFLIP:
regmap_update_bits(gc2093->regmap, GC2093_MIRROR_FLIP_REG,
FLIP_MASK, ctrl->val ? FLIP_MASK : 0);
dev_dbg(gc2093->dev, "set vflip 0x%x\n", ctrl->val);
regmap_update_bits(gc2093->regmap, GC2093_MIRROR_FLIP_REG,
FLIP_MASK, ctrl->val ? FLIP_MASK : 0);
break;
default:
dev_warn(gc2093->dev, "%s Unhandled id:0x%x, val:0x%x\n",
@@ -672,7 +833,7 @@ static int gc2093_initialize_controls(struct gc2093 *gc2093)
h_blank, h_blank, 1, h_blank);
if (gc2093->hblank)
gc2093->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
gc2093->cur_fps = mode->max_fps;
vblank_def = mode->vts_def - mode->height;
gc2093->cur_vts = mode->vts_def;
gc2093->vblank = v4l2_ctrl_new_std(handler, &gc2093_ctrl_ops,
@@ -819,11 +980,24 @@ static void gc2093_get_module_inf(struct gc2093 *gc2093,
strlcpy(inf->base.module, gc2093->module_name, sizeof(inf->base.module));
}
static int gc2093_get_channel_info(struct gc2093 *gc2093,
struct rkmodule_channel_info *ch_info)
{
if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX)
return -EINVAL;
ch_info->vc = gc2093->cur_mode->vc[ch_info->index];
ch_info->width = gc2093->cur_mode->width;
ch_info->height = gc2093->cur_mode->height;
ch_info->bus_fmt = GC2093_MEDIA_BUS_FMT;
return 0;
}
static long gc2093_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct gc2093 *gc2093 = to_gc2093(sd);
struct preisp_hdrae_exp_s *hdrae_exp = arg;
struct rkmodule_hdr_cfg *hdr_cfg;
struct rkmodule_channel_info *ch_info;
long ret = 0;
u32 i, h, w;
u32 stream = 0;
@@ -913,15 +1087,18 @@ static long gc2093_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
hdr_cfg = (struct rkmodule_hdr_cfg *)arg;
w = gc2093->cur_mode->width;
h = gc2093->cur_mode->height;
for (i = 0; i < gc2093->cfg_num; i++) {
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
if (w == supported_modes[i].width &&
h == supported_modes[i].height &&
supported_modes[i].hdr_mode == hdr_cfg->hdr_mode) {
gc2093->cur_mode = &supported_modes[i];
break;
}
dev_err(gc2093->dev, "i:%d,w:%d, h:%d, hdr:%d\n",
i, supported_modes[i].width, supported_modes[i].height,
supported_modes[i].hdr_mode);
}
if (i == gc2093->cfg_num) {
if (i == ARRAY_SIZE(supported_modes)) {
dev_err(gc2093->dev, "not find hdr mode:%d %dx%d config\n",
hdr_cfg->hdr_mode, w, h);
ret = -EINVAL;
@@ -957,6 +1134,10 @@ static long gc2093_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
usleep_range(delay_us, delay_us + 2000);
}
break;
case RKMODULE_GET_CHANNEL_INFO:
ch_info = (struct rkmodule_channel_info *)arg;
ret = gc2093_get_channel_info(gc2093, ch_info);
break;
default:
ret = -ENOIOCTLCMD;
break;
@@ -989,8 +1170,16 @@ static int __gc2093_start_stream(struct gc2093 *gc2093)
}
}
}
dev_info(gc2093->dev,
"%dx%d@%d, mode %d, vts 0x%x\n",
gc2093->cur_mode->width,
gc2093->cur_mode->height,
gc2093->cur_fps.denominator / gc2093->cur_fps.numerator,
gc2093->cur_mode->hdr_mode,
gc2093->cur_vts);
dev_info(gc2093->dev, "is_tb:%d\n", gc2093->is_thunderboot);
return gc2093_write_reg(gc2093, GC2093_REG_CTRL_MODE,
GC2093_MODE_STREAMING);
GC2093_MODE_STREAMING);
}
static int __gc2093_stop_stream(struct gc2093 *gc2093)
@@ -1012,6 +1201,7 @@ static long gc2093_compat_ioctl32(struct v4l2_subdev *sd,
struct rkmodule_inf *inf;
struct rkmodule_hdr_cfg *hdr;
struct preisp_hdrae_exp_s *hdrae;
struct rkmodule_channel_info *ch_info;
long ret = 0;
u32 stream = 0;
@@ -1081,6 +1271,21 @@ static long gc2093_compat_ioctl32(struct v4l2_subdev *sd,
else
ret = -EFAULT;
break;
case RKMODULE_GET_CHANNEL_INFO:
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
if (!ch_info) {
ret = -ENOMEM;
return ret;
}
ret = gc2093_ioctl(sd, cmd, ch_info);
if (!ret) {
ret = copy_to_user(up, ch_info, sizeof(*ch_info));
if (ret)
ret = -EFAULT;
}
kfree(ch_info);
break;
default:
ret = -ENOIOCTLCMD;
break;
@@ -1099,11 +1304,17 @@ static int gc2093_s_stream(struct v4l2_subdev *sd, int on)
fps = DIV_ROUND_CLOSEST(gc2093->cur_mode->max_fps.denominator,
gc2093->cur_mode->max_fps.numerator);
dev_info(gc2093->dev, "%s: on: %d, %dx%d@%d\n", __func__, on,
gc2093->cur_mode->width,
gc2093->cur_mode->height,
fps);
dev_info(gc2093->dev,
"%dx%d@%d, mode %d, vts 0x%x\n",
gc2093->cur_mode->width,
gc2093->cur_mode->height,
gc2093->cur_fps.denominator / gc2093->cur_fps.numerator,
gc2093->cur_mode->hdr_mode,
gc2093->cur_vts);
dev_info(gc2093->dev,
"stream:%d\n, on:%d",
gc2093->streaming, on);
mutex_lock(&gc2093->lock);
on = !!on;
if (on == gc2093->streaming)
@@ -1150,7 +1361,10 @@ static int gc2093_g_frame_interval(struct v4l2_subdev *sd,
struct gc2093 *gc2093 = to_gc2093(sd);
const struct gc2093_mode *mode = gc2093->cur_mode;
fi->interval = mode->max_fps;
if (gc2093->streaming)
fi->interval = gc2093->cur_fps;
else
fi->interval = mode->max_fps;
return 0;
}
@@ -1183,9 +1397,7 @@ static int gc2093_enum_frame_sizes(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
struct gc2093 *gc2093 = to_gc2093(sd);
if (fse->index >= gc2093->cfg_num)
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
if (fse->code != GC2093_MEDIA_BUS_FMT)
@@ -1202,9 +1414,7 @@ static int gc2093_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct gc2093 *gc2093 = to_gc2093(sd);
if (fie->index >= gc2093->cfg_num)
if (fie->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
fie->code = GC2093_MEDIA_BUS_FMT;
@@ -1400,6 +1610,136 @@ static const struct dev_pm_ops gc2093_pm_ops = {
gc2093_runtime_resume, NULL)
};
#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP
static u32 rk_cam_hdr;
static u32 rk_cam_w;
static u32 rk_cam_h;
static u32 rk_cam_fps;
static int __init __maybe_unused rk_cam_hdr_setup(char *str)
{
int ret = 0;
unsigned long val = 0;
ret = kstrtoul(str, 0, &val);
if (!ret)
rk_cam_hdr = (u32)val;
else
pr_err("get rk_cam_hdr fail\n");
return 1;
}
static int __init __maybe_unused rk_cam_w_setup(char *str)
{
int ret = 0;
unsigned long val = 0;
ret = kstrtoul(str, 0, &val);
if (!ret)
rk_cam_w = (u32)val;
else
pr_err("get rk_cam_w fail\n");
return 1;
}
static int __init __maybe_unused rk_cam_h_setup(char *str)
{
int ret = 0;
unsigned long val = 0;
ret = kstrtoul(str, 0, &val);
if (!ret)
rk_cam_h = (u32)val;
else
pr_err("get rk_cam_h fail\n");
return 1;
}
static int __init __maybe_unused rk_cam_fps_setup(char *str)
{
int ret = 0;
unsigned long val = 0;
ret = kstrtoul(str, 0, &val);
if (!ret)
rk_cam_fps = (u32)val;
else
pr_err("get rk_cam_fps fail\n");
return 1;
}
__setup("rk_cam_hdr=", rk_cam_hdr_setup);
__setup("rk_cam_w=", rk_cam_w_setup);
__setup("rk_cam_h=", rk_cam_h_setup);
__setup("rk_cam_fps=", rk_cam_fps_setup);
static void find_terminal_resolution(struct gc2093 *gc2093)
{
int i = 0;
const struct gc2093_mode *mode = NULL;
const struct gc2093_mode *fit_mode = NULL;
u32 cur_fps = 0;
u32 dst_fps = 0;
u32 tmp_fps = 0;
if (rk_cam_w == 0 || rk_cam_h == 0 ||
rk_cam_fps == 0)
goto err_find_res;
dev_info(gc2093->dev, "find resolution width: %d, height: %d, hdr: %d, fps: %d\n",
rk_cam_w, rk_cam_h, rk_cam_hdr, rk_cam_fps);
dst_fps = rk_cam_fps;
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
mode = &supported_modes[i];
cur_fps = mode->max_fps.denominator / mode->max_fps.numerator;
if (mode->width == rk_cam_w && mode->height == rk_cam_h &&
mode->hdr_mode == rk_cam_hdr) {
if (cur_fps == dst_fps) {
gc2093->cur_mode = mode;
return;
}
if (cur_fps >= dst_fps) {
if (fit_mode) {
tmp_fps = fit_mode->max_fps.denominator /
fit_mode->max_fps.numerator;
if (tmp_fps - dst_fps > cur_fps - dst_fps)
fit_mode = mode;
} else {
fit_mode = mode;
}
}
}
}
if (fit_mode) {
gc2093->cur_mode = fit_mode;
return;
}
err_find_res:
dev_err(gc2093->dev, "not match %dx%d@%dfps mode %d\n!",
rk_cam_w, rk_cam_h, dst_fps, rk_cam_hdr);
gc2093->cur_mode = &supported_modes[0];
}
#else
static void find_terminal_resolution(struct gc2093 *gc2093)
{
u32 hdr_mode = 0;
struct device_node *node = gc2093->dev->of_node;
int i = 0;
of_property_read_u32(node, OF_CAMERA_HDR_MODE, &hdr_mode);
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
if (hdr_mode == supported_modes[i].hdr_mode) {
gc2093->cur_mode = &supported_modes[i];
break;
}
}
if (i == ARRAY_SIZE(supported_modes))
gc2093->cur_mode = &supported_modes[0];
}
#endif
static int gc2093_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1447,6 +1787,8 @@ static int gc2093_probe(struct i2c_client *client,
return -EINVAL;
}
find_terminal_resolution(gc2093);
gc2093->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
if (IS_ERR(gc2093->reset_gpio))
dev_warn(dev, "Failed to get reset-gpios\n");
@@ -1463,11 +1805,6 @@ static int gc2093_probe(struct i2c_client *client,
mutex_init(&gc2093->lock);
/* set default mode */
gc2093->cur_mode = &supported_modes[0];
gc2093->cfg_num = ARRAY_SIZE(supported_modes);
gc2093->cur_vts = gc2093->cur_mode->vts_def;
sd = &gc2093->subdev;
v4l2_i2c_subdev_init(sd, client, &gc2093_subdev_ops);
ret = gc2093_initialize_controls(gc2093);

View File

@@ -1468,6 +1468,7 @@ static void gc8034_get_otp(struct otp_info *otp,
inf->pdaf.flag = 1;
inf->pdaf.gainmap_width = otp->pdaf_data.gainmap_width;
inf->pdaf.gainmap_height = otp->pdaf_data.gainmap_height;
inf->pdaf.pd_offset = otp->pdaf_data.pd_offset;
inf->pdaf.dcc_mode = otp->pdaf_data.dcc_mode;
inf->pdaf.dcc_dir = otp->pdaf_data.dcc_dir;
inf->pdaf.dccmap_width = otp->pdaf_data.dccmap_width;

View File

@@ -1206,6 +1206,7 @@ static void imx586_get_otp(struct otp_info *otp,
inf->pdaf.flag = 1;
inf->pdaf.gainmap_width = otp->pdaf_data.gainmap_width;
inf->pdaf.gainmap_height = otp->pdaf_data.gainmap_height;
inf->pdaf.pd_offset = otp->pdaf_data.pd_offset;
inf->pdaf.dcc_mode = otp->pdaf_data.dcc_mode;
inf->pdaf.dcc_dir = otp->pdaf_data.dcc_dir;
inf->pdaf.dccmap_width = otp->pdaf_data.dccmap_width;

View File

@@ -1395,15 +1395,14 @@ static long lt6911uxe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
break;
case RKMODULE_SET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
if (dphy_param->vendor == PHY_VENDOR_SAMSUNG)
rk3588_dcphy_param = *dphy_param;
dev_dbg(&lt6911uxe->i2c_client->dev,
"sensor set dphy param\n");
break;
case RKMODULE_GET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
*dphy_param = rk3588_dcphy_param;
*dphy_param = rk3588_dcphy_param;
dev_dbg(&lt6911uxe->i2c_client->dev,
"sensor get dphy param\n");
break;

View File

@@ -1178,15 +1178,14 @@ static long lt7911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
break;
case RKMODULE_SET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
if (dphy_param->vendor == PHY_VENDOR_SAMSUNG)
rk3588_dcphy_param = *dphy_param;
dev_dbg(&lt7911uxc->i2c_client->dev,
"sensor set dphy param\n");
break;
case RKMODULE_GET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
*dphy_param = rk3588_dcphy_param;
*dphy_param = rk3588_dcphy_param;
dev_dbg(&lt7911uxc->i2c_client->dev,
"sensor get dphy param\n");
break;

View File

@@ -924,6 +924,17 @@ static int nvp6158_set_fmt(struct v4l2_subdev *sd,
return ret;
}
static int nvp6158_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *fi)
{
struct nvp6158 *nvp6158 = to_nvp6158(sd);
const struct nvp6158_framesize *size = nvp6158->frame_size;
fi->interval = size->max_fps;
return 0;
}
static void nvp6158_get_module_inf(struct nvp6158 *nvp6158,
struct rkmodule_inf *inf)
{
@@ -1174,6 +1185,7 @@ static const struct dev_pm_ops nvp6158_pm_ops = {
static const struct v4l2_subdev_video_ops nvp6158_video_ops = {
.s_stream = nvp6158_stream,
.querystd = nvp6158_querystd,
.g_frame_interval = nvp6158_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops nvp6158_subdev_pad_ops = {

View File

@@ -649,6 +649,11 @@ static void rkotp_read_pdaf(struct eeprom_device *eeprom_dev,
checksum += otp_ptr->pdaf_data.dccmap_checksum;
base_addr += 1;
ret |= read_reg_otp(client, base_addr,
2, &otp_ptr->pdaf_data.pd_offset);
checksum += otp_ptr->pdaf_data.pd_offset;
base_addr += 2;
memset(pdaf_buf, 0, RK_PDAF_RESERVED_SIZE);
ret |= read_reg_otp_buf(client, base_addr,
RK_PDAF_RESERVED_SIZE, pdaf_buf);
@@ -931,7 +936,7 @@ static int otp_eeprom_show(struct seq_file *p, void *v)
seq_printf(p, "flag=%d;\n", dev->otp->pdaf_data.flag);
seq_printf(p, "gainmap_width=%d;\n", gainmap_w);
seq_printf(p, "gainmap_height=%d;\n", gainmap_h);
seq_printf(p, "pd_offset=%d\n", dev->otp->pdaf_data.pd_offset);
seq_printf(p, "gainmap_table=\n");
for (i = 0; i < gainmap_h; i++) {
for (j = 0; j < gainmap_w; j++) {

View File

@@ -56,7 +56,7 @@
#define RK_LSC_RESERVED_SIZE 0x0020
#define RK_GAINMAP_SIZE 0x0800
#define RK_DCCMAP_SIZE 0x0200
#define RK_PDAF_RESERVED_SIZE 0x0020
#define RK_PDAF_RESERVED_SIZE 0x001e
#define RK_AF_RESERVED_SIZE 0x0014
#define RKOTP_MAX_MODULE 0x0008
@@ -151,6 +151,7 @@ struct pdaf_otp_info {
u32 dccmap_height;
u32 dccmap[RK_DCCMAP_SIZE];
u32 dccmap_checksum;
u32 pd_offset;
u32 checksum;
u32 size;
};

View File

@@ -6203,6 +6203,7 @@ static void ov50c40_get_otp(struct otp_info *otp,
inf->pdaf.flag = 1;
inf->pdaf.gainmap_width = otp->pdaf_data.gainmap_width;
inf->pdaf.gainmap_height = otp->pdaf_data.gainmap_height;
inf->pdaf.pd_offset = otp->pdaf_data.pd_offset;
inf->pdaf.dcc_mode = otp->pdaf_data.dcc_mode;
inf->pdaf.dcc_dir = otp->pdaf_data.dcc_dir;
inf->pdaf.dccmap_width = otp->pdaf_data.dccmap_width;

View File

@@ -1265,6 +1265,7 @@ static void s5kjn1_get_otp(struct otp_info *otp,
inf->pdaf.flag = 1;
inf->pdaf.gainmap_width = otp->pdaf_data.gainmap_width;
inf->pdaf.gainmap_height = otp->pdaf_data.gainmap_height;
inf->pdaf.pd_offset = otp->pdaf_data.pd_offset;
inf->pdaf.dcc_mode = otp->pdaf_data.dcc_mode;
inf->pdaf.dcc_dir = otp->pdaf_data.dcc_dir;
inf->pdaf.dccmap_width = otp->pdaf_data.dccmap_width;

View File

@@ -5079,10 +5079,12 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream,
dev->wait_line = 0;
stream->is_line_wake_up = false;
}
tasklet_disable(&stream->vb_done_tasklet);
if (can_reset && hw_dev->dummy_buf.vaddr)
rkcif_destroy_dummy_buf(stream);
}
if (can_reset && hw_dev->dummy_buf.vaddr)
rkcif_destroy_dummy_buf(stream);
if (mode == RKCIF_STREAM_MODE_CAPTURE)
tasklet_disable(&stream->vb_done_tasklet);
stream->cur_stream_mode &= ~mode;
INIT_LIST_HEAD(&stream->vb_done_list);
v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished, dma_en 0x%x\n", stream->id, stream->dma_en);
@@ -6213,8 +6215,10 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode)
}
mutex_unlock(&hw_dev->dev_lock);
if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) {
if (mode == RKCIF_STREAM_MODE_CAPTURE)
tasklet_enable(&stream->vb_done_tasklet);
if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) {
ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true);
if (ret < 0) {
v4l2_err(v4l2_dev, "open cif pipeline failed %d\n",
@@ -6232,7 +6236,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode)
rkmodule_stream_seq == RKMODULE_START_STREAM_FRONT) {
ret = dev->pipe.set_stream(&dev->pipe, true);
if (ret < 0)
goto runtime_put;
goto destroy_buf;
}
}
if (dev->chip_id >= CHIP_RK1808_CIF) {
@@ -6248,7 +6252,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode)
}
if (ret < 0)
goto runtime_put;
goto destroy_buf;
if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) {
ret = media_pipeline_start(&node->vdev.entity, &dev->pipe.pipe);
@@ -6294,15 +6298,19 @@ stop_stream:
rkcif_stream_stop(stream);
pipe_stream_off:
dev->pipe.set_stream(&dev->pipe, false);
runtime_put:
pm_runtime_put_sync(dev->dev);
destroy_buf:
if (stream->next_buf)
vb2_buffer_done(&stream->next_buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
if (mode == RKCIF_STREAM_MODE_CAPTURE)
tasklet_disable(&stream->vb_done_tasklet);
if (stream->curr_buf)
vb2_buffer_done(&stream->curr_buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
list_add_tail(&stream->curr_buf->queue, &stream->buf_head);
if (stream->next_buf &&
stream->next_buf != stream->curr_buf)
list_add_tail(&stream->next_buf->queue, &stream->buf_head);
stream->curr_buf = NULL;
stream->next_buf = NULL;
atomic_set(&stream->buf_cnt, 0);
while (!list_empty(&stream->buf_head)) {
struct rkcif_buffer *buf;

View File

@@ -627,36 +627,39 @@ static int sditf_start_stream(struct sditf_priv *priv)
struct rkcif_device *cif_dev = priv->cif_dev;
struct v4l2_subdev_format fmt;
unsigned int mode = RKCIF_STREAM_MODE_TOISP;
int ret = 0;
sditf_check_capture_mode(cif_dev);
sditf_get_set_fmt(&priv->sd, NULL, &fmt);
if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) {
if (priv->toisp_inf.link_mode == TOISP0) {
sditf_channel_enable(priv, 0);
ret = sditf_channel_enable(priv, 0);
} else if (priv->toisp_inf.link_mode == TOISP1) {
sditf_channel_enable(priv, 1);
ret = sditf_channel_enable(priv, 1);
} else if (priv->toisp_inf.link_mode == TOISP_UNITE) {
sditf_channel_enable(priv, 0);
sditf_channel_enable(priv, 1);
ret = sditf_channel_enable(priv, 0);
ret |= sditf_channel_enable(priv, 1);
}
mode = RKCIF_STREAM_MODE_TOISP;
} else if (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) {
mode = RKCIF_STREAM_MODE_TOISP_RDBK;
}
if (ret)
return ret;
if (priv->hdr_cfg.hdr_mode == NO_HDR ||
priv->hdr_cfg.hdr_mode == HDR_COMPR) {
rkcif_do_start_stream(&cif_dev->stream[0], mode);
ret = rkcif_do_start_stream(&cif_dev->stream[0], mode);
} else if (priv->hdr_cfg.hdr_mode == HDR_X2) {
rkcif_do_start_stream(&cif_dev->stream[0], mode);
rkcif_do_start_stream(&cif_dev->stream[1], mode);
ret = rkcif_do_start_stream(&cif_dev->stream[0], mode);
ret |= rkcif_do_start_stream(&cif_dev->stream[1], mode);
} else if (priv->hdr_cfg.hdr_mode == HDR_X3) {
rkcif_do_start_stream(&cif_dev->stream[0], mode);
rkcif_do_start_stream(&cif_dev->stream[1], mode);
rkcif_do_start_stream(&cif_dev->stream[2], mode);
ret = rkcif_do_start_stream(&cif_dev->stream[0], mode);
ret |= rkcif_do_start_stream(&cif_dev->stream[1], mode);
ret |= rkcif_do_start_stream(&cif_dev->stream[2], mode);
}
INIT_LIST_HEAD(&priv->buf_free_list);
return 0;
return ret;
}
static int sditf_stop_stream(struct sditf_priv *priv)
@@ -718,6 +721,8 @@ static int sditf_s_stream(struct v4l2_subdev *sd, int on)
}
}
if (on && ret)
atomic_dec(&priv->stream_cnt);
return ret;
}
@@ -745,6 +750,7 @@ static int sditf_s_power(struct v4l2_subdev *sd, int on)
} else {
v4l2_pipeline_pm_put(&node->vdev.entity);
pm_runtime_put_sync(cif_dev->dev);
priv->mode.rdbk_mode = RKISP_VICAP_RDBK_AIQ;
}
v4l2_info(&node->vdev, "s_power %d, entity use_count %d\n",
on, node->vdev.entity.use_count);

View File

@@ -2169,9 +2169,12 @@
#define ISP3X_CAC_LUT_MODE(x) (((x) & 0x3) << 24)
/* CNR */
#define ISP3X_CNR_THUMB_MIX_CUR_EN BIT(4)
#define ISP3X_CNR_GLOBAL_GAIN_ALPHA_MAX GENMASK(15, 12)
/* YNR */
#define ISP3X_YNR_THUMB_MIX_CUR_EN BIT(24)
#define ISP3X_YNR_EN_SHD BIT(31)
/* BLS */
@@ -2201,6 +2204,9 @@
/* HDRTMO */
/* HDRDRC */
#define ISP3X_DRC_WEIPRE_FRAME_MASK GENMASK(23, 16)
#define ISP3X_DRC_IIR_WEIGHT_MASK GENMASK(22, 16)
/* HDRMGE */

View File

@@ -518,7 +518,9 @@ static void rkisp_dvfs(struct rkisp_device *dev)
do_div(data_rate, 1000 * 1000);
/* increase margin: 25% * num */
data_rate += (data_rate >> 2) * num;
/* one frame two-run, data double */
if (hw->is_multi_overflow && num > 1)
data_rate *= 2;
/* compare with isp clock adjustment table */
for (i = 0; i < hw->num_clk_rate_tbl; i++)
if (data_rate <= hw->clk_rate_tbl[i].clk_rate)
@@ -541,45 +543,36 @@ static void rkisp_multi_overflow_hdl(struct rkisp_device *dev, bool on)
struct rkisp_hw_dev *hw = dev->hw_dev;
if (on) {
/* enable bay3d and mi */
/* enable mi */
rkisp_update_regs(dev, ISP3X_MI_WR_CTRL, ISP3X_MI_WR_CTRL);
rkisp_update_regs(dev, ISP3X_ISP_CTRL1, ISP3X_ISP_CTRL1);
if (dev->isp_ver == ISP_V21) {
rkisp_update_regs(dev, ISP21_BAY3D_CTRL, ISP21_BAY3D_CTRL);
} else if (dev->isp_ver == ISP_V30) {
if (dev->isp_ver == ISP_V30) {
rkisp_update_regs(dev, ISP3X_MPFBC_CTRL, ISP3X_MPFBC_CTRL);
rkisp_update_regs(dev, ISP3X_MI_BP_WR_CTRL, ISP3X_MI_BP_WR_CTRL);
rkisp_update_regs(dev, ISP3X_BAY3D_CTRL, ISP3X_BAY3D_CTRL);
rkisp_update_regs(dev, ISP3X_SWS_CFG, ISP3X_SWS_CFG);
} else if (dev->isp_ver == ISP_V32) {
rkisp_update_regs(dev, ISP3X_MI_BP_WR_CTRL, ISP3X_MI_BP_WR_CTRL);
rkisp_update_regs(dev, ISP32_MI_BPDS_WR_CTRL, ISP32_MI_BPDS_WR_CTRL);
rkisp_update_regs(dev, ISP32_MI_MPDS_WR_CTRL, ISP32_MI_MPDS_WR_CTRL);
rkisp_update_regs(dev, ISP3X_BAY3D_CTRL, ISP3X_BAY3D_CTRL);
}
} else {
/* disabled bay3d and mi. rv1106 sdmmc workaround, 3a_wr no close */
/* disabled mi. rv1106 sdmmc workaround, 3a_wr no close */
writel(CIF_MI_CTRL_INIT_OFFSET_EN | CIF_MI_CTRL_INIT_BASE_EN,
hw->base_addr + ISP3X_MI_WR_CTRL);
if (dev->isp_ver == ISP_V21) {
writel(0, hw->base_addr + ISP21_BAY3D_CTRL);
} else if (dev->isp_ver == ISP_V30) {
if (dev->isp_ver == ISP_V30) {
writel(0, hw->base_addr + ISP3X_MPFBC_CTRL);
writel(0, hw->base_addr + ISP3X_MI_BP_WR_CTRL);
writel(0, hw->base_addr + ISP3X_BAY3D_CTRL);
writel(0xc, hw->base_addr + ISP3X_SWS_CFG);
if (hw->is_unite) {
writel(0, hw->base_next_addr + ISP3X_MI_WR_CTRL);
writel(0, hw->base_next_addr + ISP3X_MPFBC_CTRL);
writel(0, hw->base_next_addr + ISP3X_MI_BP_WR_CTRL);
writel(0, hw->base_next_addr + ISP3X_BAY3D_CTRL);
writel(0xc, hw->base_next_addr + ISP3X_SWS_CFG);
}
} else if (dev->isp_ver == ISP_V32) {
writel(0, hw->base_addr + ISP3X_MI_BP_WR_CTRL);
writel(0, hw->base_addr + ISP32_MI_BPDS_WR_CTRL);
writel(0, hw->base_addr + ISP32_MI_MPDS_WR_CTRL);
writel(0, hw->base_addr + ISP3X_BAY3D_CTRL);
}
}
rkisp_unite_write(dev, ISP3X_MI_WR_INIT, CIF_MI_INIT_SOFT_UPD, true, hw->is_unite);
@@ -741,19 +734,54 @@ run_next:
if (dev->sw_rd_cnt) {
/* the frame first running to off mi to save bandwidth */
rkisp_multi_overflow_hdl(dev, false);
/* FST_FRAME for YNR/CNR/SHP/ADRC/DHAZ no to refer to sram info */
val = ISP3X_YNR_FST_FRAME | ISP3X_CNR_FST_FRAME | ISP32_SHP_FST_FRAME |
ISP3X_ADRC_FST_FRAME | ISP3X_DHAZ_FST_FRAME;
/* FST_FRAME no to read sram thumb */
val = ISP3X_YNR_FST_FRAME | ISP3X_DHAZ_FST_FRAME;
if (dev->isp_ver == ISP_V32)
val |= ISP32_SHP_FST_FRAME;
else
val |= ISP3X_CNR_FST_FRAME;
rkisp_unite_set_bits(dev, ISP3X_ISP_CTRL1, 0, val, false, hw->is_unite);
/* ADRC low iir thumb weight for first sensor switch */
val = rkisp_read_reg_cache(dev, ISP3X_DRC_IIRWG_GAIN);
val &= ~ISP3X_DRC_IIR_WEIGHT_MASK;
writel(val, hw->base_addr + ISP3X_DRC_IIRWG_GAIN);
/* ADRC iir5x5 and cur3x3 weight */
val = rkisp_read_reg_cache(dev, ISP3X_DRC_EXPLRATIO);
val &= ~ISP3X_DRC_WEIPRE_FRAME_MASK;
writel(val, hw->base_addr + ISP3X_DRC_EXPLRATIO);
/* YNR_THUMB_MIX_CUR_EN for thumb read addr to 0 */
val = rkisp_read_reg_cache(dev, ISP3X_YNR_GLOBAL_CTRL);
val |= ISP3X_YNR_THUMB_MIX_CUR_EN;
writel(val, hw->base_addr + ISP3X_YNR_GLOBAL_CTRL);
if (dev->isp_ver == ISP_V21 || dev->isp_ver == ISP_V30) {
/* CNR_THUMB_MIX_CUR_EN for thumb read addr to 0 */
val = rkisp_read_reg_cache(dev, ISP3X_CNR_CTRL);
val |= ISP3X_CNR_THUMB_MIX_CUR_EN;
writel(val, hw->base_addr + ISP3X_CNR_CTRL);
if (hw->is_unite)
writel(val, hw->base_next_addr + ISP3X_CNR_CTRL);
}
params_vdev->rdbk_times += dev->sw_rd_cnt;
stats_vdev->rdbk_drop = true;
is_upd = true;
} else if (is_try) {
/* the frame second running to on mi */
rkisp_multi_overflow_hdl(dev, true);
rkisp_update_regs(dev, ISP_LDCH_BASE, ISP_LDCH_BASE);
val = ISP3X_YNR_FST_FRAME | ISP3X_CNR_FST_FRAME | ISP32_SHP_FST_FRAME |
ISP3X_ADRC_FST_FRAME | ISP3X_DHAZ_FST_FRAME;
val = ISP3X_YNR_FST_FRAME | ISP3X_DHAZ_FST_FRAME | ISP3X_CNR_FST_FRAME;
if (dev->isp_ver == ISP_V32)
val |= ISP32_SHP_FST_FRAME;
else
val |= ISP3X_CNR_FST_FRAME;
rkisp_unite_clear_bits(dev, ISP3X_ISP_CTRL1, val, false, hw->is_unite);
val = rkisp_read_reg_cache(dev, ISP3X_DRC_IIRWG_GAIN);
writel(val, hw->base_addr + ISP3X_DRC_IIRWG_GAIN);
val = rkisp_read_reg_cache(dev, ISP3X_DRC_EXPLRATIO);
writel(val, hw->base_addr + ISP3X_DRC_EXPLRATIO);
is_upd = true;
}
}
@@ -818,6 +846,8 @@ run_next:
val &= ~SW_IBUF_OP_MODE(0xf);
tmp = SW_IBUF_OP_MODE(dev->rd_mode);
val |= tmp | SW_CSI2RX_EN | SW_DMA_2FRM_MODE(dma2frm);
if (dev->isp_ver > ISP_V20)
dma2frm = dev->sw_rd_cnt;
v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
"readback frame:%d time:%d 0x%x\n",
cur_frame_id, dma2frm + 1, val);

View File

@@ -30,10 +30,10 @@
#define DRIVER_NAME "rknpu"
#define DRIVER_DESC "RKNPU driver"
#define DRIVER_DATE "20230721"
#define DRIVER_DATE "20230825"
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 9
#define DRIVER_PATCHLEVEL 1
#define DRIVER_PATCHLEVEL 2
#define LOG_TAG "RKNPU"
@@ -75,6 +75,7 @@ struct rknpu_config {
int num_resets;
__u64 nbuf_phyaddr;
__u64 nbuf_size;
__u64 max_submit_number;
};
struct rknpu_timer {
@@ -101,6 +102,7 @@ struct rknpu_device {
void __iomem *base[RKNPU_MAX_CORES];
struct device *dev;
#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM
struct device *fake_dev;
struct drm_device *drm_dev;
#endif
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP

View File

@@ -46,6 +46,7 @@ struct rknpu_job {
atomic_t interrupt_count;
ktime_t hw_recoder_time;
ktime_t commit_pc_time;
atomic_t submit_count[RKNPU_MAX_CORES];
};
irqreturn_t rknpu_core0_irq_handler(int irq, void *data);

View File

@@ -63,7 +63,7 @@ static int rknpu_load_show(struct seq_file *m, void *data)
div_value = (RKNPU_LOAD_INTERVAL / 100000);
do_div(busy_time_total, div_value);
load = busy_time_total;
load = busy_time_total > 100 ? 100 : busy_time_total;
if (rknpu_dev->config->num_irqs > 1)
seq_printf(m, "%2.d%%,", load);

View File

@@ -117,7 +117,8 @@ static const struct rknpu_config rk356x_rknpu_config = {
.num_irqs = ARRAY_SIZE(rknpu_irqs),
.num_resets = ARRAY_SIZE(rknpu_resets),
.nbuf_phyaddr = 0,
.nbuf_size = 0
.nbuf_size = 0,
.max_submit_number = (1 << 12) - 1
};
static const struct rknpu_config rk3588_rknpu_config = {
@@ -135,7 +136,8 @@ static const struct rknpu_config rk3588_rknpu_config = {
.num_irqs = ARRAY_SIZE(rk3588_npu_irqs),
.num_resets = ARRAY_SIZE(rk3588_npu_resets),
.nbuf_phyaddr = 0,
.nbuf_size = 0
.nbuf_size = 0,
.max_submit_number = (1 << 12) - 1
};
static const struct rknpu_config rv1106_rknpu_config = {
@@ -153,7 +155,8 @@ static const struct rknpu_config rv1106_rknpu_config = {
.num_irqs = ARRAY_SIZE(rknpu_irqs),
.num_resets = ARRAY_SIZE(rknpu_resets),
.nbuf_phyaddr = 0,
.nbuf_size = 0
.nbuf_size = 0,
.max_submit_number = (1 << 16) - 1
};
static const struct rknpu_config rk3562_rknpu_config = {
@@ -171,7 +174,8 @@ static const struct rknpu_config rk3562_rknpu_config = {
.num_irqs = ARRAY_SIZE(rknpu_irqs),
.num_resets = ARRAY_SIZE(rknpu_resets),
.nbuf_phyaddr = 0xfe400000,
.nbuf_size = 256 * 1024
.nbuf_size = 256 * 1024,
.max_submit_number = (1 << 16) - 1
};
/* driver probe and init */
@@ -539,6 +543,9 @@ static const struct drm_ioctl_desc rknpu_ioctls[] = {
DRM_RENDER_ALLOW),
};
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
DEFINE_DRM_GEM_FOPS(rknpu_drm_driver_fops);
#else
static const struct file_operations rknpu_drm_driver_fops = {
.owner = THIS_MODULE,
.open = drm_open,
@@ -552,6 +559,7 @@ static const struct file_operations rknpu_drm_driver_fops = {
.release = drm_release,
.llseek = noop_llseek,
};
#endif
static struct drm_driver rknpu_drm_driver = {
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
@@ -582,7 +590,11 @@ static struct drm_driver rknpu_drm_driver = {
.gem_prime_import = drm_gem_prime_import,
#endif
.gem_prime_import_sg_table = rknpu_gem_prime_import_sg_table,
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
.gem_prime_mmap = drm_gem_prime_mmap,
#else
.gem_prime_mmap = rknpu_gem_prime_mmap,
#endif
.ioctls = rknpu_ioctls,
.num_ioctls = ARRAY_SIZE(rknpu_ioctls),
.fops = &rknpu_drm_driver_fops,
@@ -602,7 +614,7 @@ static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer)
container_of(timer, struct rknpu_device, timer);
struct rknpu_subcore_data *subcore_data = NULL;
struct rknpu_job *job = NULL;
ktime_t now = ktime_get();
ktime_t now;
unsigned long flags;
int i;
@@ -613,9 +625,10 @@ static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer)
job = subcore_data->job;
if (job) {
now = ktime_get();
subcore_data->timer.busy_time +=
ktime_us_delta(now, job->hw_recoder_time);
job->hw_recoder_time = ktime_get();
job->hw_recoder_time = now;
}
subcore_data->timer.busy_time_record =
@@ -667,6 +680,42 @@ static bool rknpu_is_iommu_enable(struct device *dev)
}
#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM
static int drm_fake_dev_register(struct rknpu_device *rknpu_dev)
{
const struct platform_device_info rknpu_dev_info = {
.name = "rknpu_dev",
.id = PLATFORM_DEVID_AUTO,
.dma_mask = rknpu_dev->config->dma_mask,
};
struct platform_device *pdev = NULL;
int ret = -EINVAL;
pdev = platform_device_register_full(&rknpu_dev_info);
if (pdev) {
ret = of_dma_configure(&pdev->dev, NULL, true);
if (ret) {
platform_device_unregister(pdev);
pdev = NULL;
}
}
rknpu_dev->fake_dev = pdev ? &pdev->dev : NULL;
return ret;
}
static void drm_fake_dev_unregister(struct rknpu_device *rknpu_dev)
{
struct platform_device *pdev = NULL;
if (!rknpu_dev->fake_dev)
return;
pdev = to_platform_device(rknpu_dev->fake_dev);
platform_device_unregister(pdev);
}
static int rknpu_drm_probe(struct rknpu_device *rknpu_dev)
{
struct device *dev = rknpu_dev->dev;
@@ -685,6 +734,8 @@ static int rknpu_drm_probe(struct rknpu_device *rknpu_dev)
drm_dev->dev_private = rknpu_dev;
rknpu_dev->drm_dev = drm_dev;
drm_fake_dev_register(rknpu_dev);
return 0;
err_free_drm:
@@ -701,6 +752,8 @@ static void rknpu_drm_remove(struct rknpu_device *rknpu_dev)
{
struct drm_device *drm_dev = rknpu_dev->drm_dev;
drm_fake_dev_unregister(rknpu_dev);
drm_dev_unregister(drm_dev);
#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE
@@ -2123,6 +2176,6 @@ MODULE_ALIAS("rockchip-rknpu");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(RKNPU_GET_DRV_VERSION_STRING(DRIVER_MAJOR, DRIVER_MINOR,
DRIVER_PATCHLEVEL));
#if defined(CONFIG_ROCKCHIP_RKNPU_DMA_HEAP) && KERNEL_VERSION(5, 16, 0) < LINUX_VERSION_CODE
#if KERNEL_VERSION(5, 16, 0) < LINUX_VERSION_CODE
MODULE_IMPORT_NS(DMA_BUF);
#endif

View File

@@ -985,6 +985,7 @@ static int rknpu_gem_mmap_buffer(struct rknpu_gem_object *rknpu_obj,
* vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
* the whole buffer.
*/
vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_pgoff = 0;
@@ -1329,19 +1330,29 @@ void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
int rknpu_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
{
struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj);
void *vaddr = NULL;
if (!rknpu_obj->pages)
return -EINVAL;
map->vaddr = vmap(rknpu_obj->pages, rknpu_obj->num_pages, VM_MAP,
vaddr = vmap(rknpu_obj->pages, rknpu_obj->num_pages, VM_MAP,
PAGE_KERNEL);
if (!vaddr)
return -ENOMEM;
iosys_map_set_vaddr(map, vaddr);
return 0;
}
void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
{
vunmap(map->vaddr);
struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj);
if (rknpu_obj->pages) {
vunmap(map->vaddr);
map->vaddr = NULL;
}
}
#endif
@@ -1412,10 +1423,12 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct rknpu_gem_object *rknpu_obj = NULL;
struct rknpu_device *rknpu_dev = dev->dev_private;
struct rknpu_mem_sync *args = data;
struct scatterlist *sg;
dma_addr_t sg_phys_addr;
unsigned long length, offset = 0;
unsigned long sg_left, size = 0;
unsigned long sg_offset, sg_left, size = 0;
unsigned long len = 0;
int i;
@@ -1439,6 +1452,8 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
DMA_FROM_DEVICE);
}
} else {
WARN_ON(!rknpu_dev->fake_dev);
length = args->size;
offset = args->offset;
@@ -1462,17 +1477,23 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
if (len <= offset)
continue;
sg_phys_addr = sg_phys(sg);
sg_left = len - offset;
sg_offset = sg->length - sg_left;
size = (length < sg_left) ? length : sg_left;
if (args->flags & RKNPU_MEM_SYNC_TO_DEVICE) {
dma_sync_sg_for_device(dev->dev, sg, 1,
DMA_TO_DEVICE);
dma_sync_single_range_for_device(
rknpu_dev->fake_dev, sg_phys_addr,
sg_offset, size, DMA_TO_DEVICE);
}
if (args->flags & RKNPU_MEM_SYNC_FROM_DEVICE) {
dma_sync_sg_for_cpu(dev->dev, sg, 1,
DMA_FROM_DEVICE);
dma_sync_single_range_for_cpu(
rknpu_dev->fake_dev, sg_phys_addr,
sg_offset, size, DMA_FROM_DEVICE);
}
offset += size;

View File

@@ -23,16 +23,25 @@
#define REG_READ(offset) _REG_READ(rknpu_core_base, offset)
#define REG_WRITE(value, offset) _REG_WRITE(rknpu_core_base, value, offset)
static int rknpu_core_index(int core_mask)
static int rknpu_wait_core_index(int core_mask)
{
int index = 0;
if (core_mask & RKNPU_CORE0_MASK)
switch (core_mask & ((1 << RKNPU_MAX_CORES) - 1)) {
case RKNPU_CORE0_MASK:
case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK:
case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK | RKNPU_CORE2_MASK:
index = 0;
else if (core_mask & RKNPU_CORE1_MASK)
break;
case RKNPU_CORE1_MASK:
index = 1;
else if (core_mask & RKNPU_CORE2_MASK)
break;
case RKNPU_CORE2_MASK:
index = 2;
break;
default:
break;
}
return index;
}
@@ -58,14 +67,24 @@ static int rknpu_core_mask(int core_index)
return core_mask;
}
static int rknn_get_task_number(struct rknpu_job *job, int core_index)
static int rknpu_get_task_number(struct rknpu_job *job, int core_index)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
int task_num = job->args->task_number;
if (job->use_core_num == 2)
task_num = job->args->subcore_task[core_index].task_number;
else if (job->use_core_num == 3)
task_num = job->args->subcore_task[core_index + 2].task_number;
if (core_index >= RKNPU_MAX_CORES || core_index < 0) {
LOG_ERROR("core_index: %d set error!", core_index);
return 0;
}
if (rknpu_dev->config->num_irqs > 1) {
if (job->use_core_num == 1 || job->use_core_num == 2)
task_num =
job->args->subcore_task[core_index].task_number;
else if (job->use_core_num == 3)
task_num = job->args->subcore_task[core_index + 2]
.task_number;
}
return task_num;
}
@@ -159,7 +178,7 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
struct rknpu_subcore_data *subcore_data = NULL;
struct rknpu_job *entry, *q;
void __iomem *rknpu_core_base = NULL;
int core_index = rknpu_core_index(job->args->core_mask);
int core_index = rknpu_wait_core_index(job->args->core_mask);
unsigned long flags;
int wait_count = 0;
bool continue_wait = false;
@@ -179,7 +198,6 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
if (ret == 0) {
int64_t commit_time = 0;
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
commit_time = ktime_us_delta(ktime_get(),
job->commit_pc_time);
@@ -245,7 +263,8 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
return 0;
}
static inline int rknpu_job_commit_pc(struct rknpu_job *job, int core_index)
static inline int rknpu_job_subcore_commit_pc(struct rknpu_job *job,
int core_index)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_submit *args = job->args;
@@ -262,12 +281,14 @@ static inline int rknpu_job_commit_pc(struct rknpu_job *job, int core_index)
struct rknpu_task *last_task = NULL;
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
int task_start = args->task_start;
int task_end = args->task_start + args->task_number - 1;
int task_end;
int task_number = args->task_number;
int task_pp_en = args->flags & RKNPU_JOB_PINGPONG ? 1 : 0;
int pc_data_amount_scale = rknpu_dev->config->pc_data_amount_scale;
int pc_task_number_bits = rknpu_dev->config->pc_task_number_bits;
int i = 0;
int submit_index = atomic_read(&job->submit_count[core_index]);
int max_submit_number = rknpu_dev->config->max_submit_number;
if (!task_obj) {
job->ret = -EINVAL;
@@ -282,38 +303,40 @@ static inline int rknpu_job_commit_pc(struct rknpu_job *job, int core_index)
}
}
if (job->use_core_num == 1) {
switch (job->use_core_num) {
case 1:
case 2:
task_start = args->subcore_task[core_index].task_start;
task_end = args->subcore_task[core_index].task_start +
args->subcore_task[core_index].task_number -
1;
task_number =
args->subcore_task[core_index].task_number;
} else if (job->use_core_num == 2) {
task_start = args->subcore_task[core_index].task_start;
task_end = args->subcore_task[core_index].task_start +
args->subcore_task[core_index].task_number -
1;
task_number =
args->subcore_task[core_index].task_number;
} else if (job->use_core_num == 3) {
break;
case 3:
task_start =
args->subcore_task[core_index + 2].task_start;
task_end =
args->subcore_task[core_index + 2].task_start +
args->subcore_task[core_index + 2].task_number -
1;
task_number =
args->subcore_task[core_index + 2].task_number;
break;
default:
LOG_ERROR("Unknown use core num %d\n",
job->use_core_num);
break;
}
}
task_start = task_start + submit_index * max_submit_number;
task_number = task_number - submit_index * max_submit_number;
task_number = task_number > max_submit_number ? max_submit_number :
task_number;
task_end = task_start + task_number - 1;
task_base = task_obj->kv_addr;
first_task = &task_base[task_start];
last_task = &task_base[task_end];
spin_lock(&rknpu_dev->lock);
REG_WRITE(first_task->regcmd_addr, RKNPU_OFFSET_PC_DATA_ADDR);
spin_unlock(&rknpu_dev->lock);
REG_WRITE((first_task->regcfg_amount + RKNPU_PC_DATA_EXTRA_AMOUNT +
pc_data_amount_scale - 1) /
@@ -340,21 +363,50 @@ static inline int rknpu_job_commit_pc(struct rknpu_job *job, int core_index)
return 0;
}
static int rknpu_job_commit(struct rknpu_job *job, int core_index)
static inline int rknpu_job_subcore_commit(struct rknpu_job *job, int core_index)
{
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_submit *args = job->args;
void __iomem *rknpu_core_base = rknpu_dev->base[core_index];
// switch to slave mode
spin_lock(&rknpu_dev->lock);
REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR);
spin_unlock(&rknpu_dev->lock);
if (!(args->flags & RKNPU_JOB_PC)) {
job->ret = -EINVAL;
return job->ret;
}
return rknpu_job_commit_pc(job, core_index);
return rknpu_job_subcore_commit_pc(job, core_index);
}
static void rknpu_job_commit(struct rknpu_job *job)
{
switch (job->args->core_mask & ((1 << RKNPU_MAX_CORES) - 1)) {
case RKNPU_CORE0_MASK:
rknpu_job_subcore_commit(job, 0);
break;
case RKNPU_CORE1_MASK:
rknpu_job_subcore_commit(job, 1);
break;
case RKNPU_CORE2_MASK:
rknpu_job_subcore_commit(job, 2);
break;
case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK:
rknpu_job_subcore_commit(job, 0);
rknpu_job_subcore_commit(job, 1);
break;
case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK | RKNPU_CORE2_MASK:
rknpu_job_subcore_commit(job, 0);
rknpu_job_subcore_commit(job, 1);
rknpu_job_subcore_commit(job, 2);
break;
default:
LOG_ERROR("Unknown core mask: %d\n", job->args->core_mask);
break;
}
}
static void rknpu_job_next(struct rknpu_device *rknpu_dev, int core_index)
@@ -385,30 +437,7 @@ static void rknpu_job_next(struct rknpu_device *rknpu_dev, int core_index)
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
if (atomic_dec_and_test(&job->run_count)) {
switch (job->args->core_mask & ((1 << RKNPU_MAX_CORES) - 1)) {
case RKNPU_CORE0_MASK:
rknpu_job_commit(job, 0);
break;
case RKNPU_CORE1_MASK:
rknpu_job_commit(job, 1);
break;
case RKNPU_CORE2_MASK:
rknpu_job_commit(job, 2);
break;
case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK:
rknpu_job_commit(job, 0);
rknpu_job_commit(job, 1);
break;
case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK | RKNPU_CORE2_MASK:
rknpu_job_commit(job, 0);
rknpu_job_commit(job, 1);
rknpu_job_commit(job, 2);
break;
default:
LOG_ERROR("Unknown core mask: %#x\n",
job->args->core_mask);
break;
}
rknpu_job_commit(job);
}
}
@@ -417,15 +446,22 @@ static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index)
struct rknpu_device *rknpu_dev = job->rknpu_dev;
struct rknpu_subcore_data *subcore_data = NULL;
unsigned long flags;
ktime_t now = ktime_get();
int max_submit_number = rknpu_dev->config->max_submit_number;
if (atomic_inc_return(&job->submit_count[core_index]) <
(rknpu_get_task_number(job, core_index) + max_submit_number - 1) /
max_submit_number) {
rknpu_job_commit(job);
return;
}
subcore_data = &rknpu_dev->subcore_datas[core_index];
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
subcore_data->job = NULL;
subcore_data->task_num -= rknn_get_task_number(job, core_index);
subcore_data->task_num -= rknpu_get_task_number(job, core_index);
subcore_data->timer.busy_time +=
ktime_us_delta(now, job->hw_recoder_time);
ktime_us_delta(ktime_get(), job->hw_recoder_time);
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
if (atomic_dec_and_test(&job->interrupt_count)) {
@@ -498,7 +534,7 @@ static void rknpu_job_schedule(struct rknpu_job *job)
if (job->args->core_mask & rknpu_core_mask(i)) {
subcore_data = &rknpu_dev->subcore_datas[i];
list_add_tail(&job->head[i], &subcore_data->todo_list);
subcore_data->task_num += rknn_get_task_number(job, i);
subcore_data->task_num += rknpu_get_task_number(job, i);
}
}
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
@@ -525,7 +561,7 @@ static void rknpu_job_abort(struct rknpu_job *job)
if (job == subcore_data->job && !job->irq_entry[i]) {
subcore_data->job = NULL;
subcore_data->task_num -=
rknn_get_task_number(job, i);
rknpu_get_task_number(job, i);
}
}
}

View File

@@ -15,6 +15,8 @@
#include "rknpu_ioctl.h"
#include "rknpu_mem.h"
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data,
struct file *file)
{
@@ -108,7 +110,7 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data,
}
page_count = length >> PAGE_SHIFT;
pages = kmalloc_array(page_count, sizeof(struct page), GFP_KERNEL);
pages = vmalloc(page_count * sizeof(struct page));
if (!pages) {
LOG_ERROR("alloc pages failed\n");
ret = -ENOMEM;
@@ -146,7 +148,8 @@ int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data,
goto err_unmap_kv_addr;
}
kfree(pages);
vfree(pages);
pages = NULL;
dma_buf_unmap_attachment(attachment, table, DMA_BIDIRECTIONAL);
dma_buf_detach(dmabuf, attachment);
@@ -169,7 +172,8 @@ err_unmap_kv_addr:
rknpu_obj->kv_addr = NULL;
err_free_pages:
kfree(pages);
vfree(pages);
pages = NULL;
err_detach_dma_buf:
dma_buf_unmap_attachment(attachment, table, DMA_BIDIRECTIONAL);
@@ -292,7 +296,9 @@ int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data)
{
struct rknpu_mem_object *rknpu_obj = NULL;
struct rknpu_mem_sync args;
#ifdef CONFIG_DMABUF_PARTIAL
struct dma_buf *dmabuf;
#endif
int ret = -EFAULT;
if (unlikely(copy_from_user(&args, (struct rknpu_mem_sync *)data,
@@ -310,7 +316,6 @@ int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data)
}
rknpu_obj = (struct rknpu_mem_object *)(uintptr_t)args.obj_addr;
dmabuf = rknpu_obj->dmabuf;
#ifndef CONFIG_DMABUF_PARTIAL
if (args.flags & RKNPU_MEM_SYNC_TO_DEVICE) {
@@ -322,6 +327,7 @@ int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data)
DMA_FROM_DEVICE, true);
}
#else
dmabuf = rknpu_obj->dmabuf;
if (args.flags & RKNPU_MEM_SYNC_TO_DEVICE) {
dmabuf->ops->end_cpu_access_partial(dmabuf, DMA_TO_DEVICE,
args.offset, args.size);
@@ -334,3 +340,5 @@ int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data)
return 0;
}
#endif

View File

@@ -1312,7 +1312,11 @@ int rockchip_get_soc_info(struct device *dev, struct device_node *np, int *bin,
return 0;
if (of_property_match_string(np, "nvmem-cell-names",
"specification_serial_number") >= 0) {
"remark_spec_serial_number") >= 0)
rockchip_nvmem_cell_read_u8(np, "remark_spec_serial_number", &value);
if (!value && of_property_match_string(np, "nvmem-cell-names",
"specification_serial_number") >= 0) {
ret = rockchip_nvmem_cell_read_u8(np,
"specification_serial_number",
&value);
@@ -1321,14 +1325,15 @@ int rockchip_get_soc_info(struct device *dev, struct device_node *np, int *bin,
"Failed to get specification_serial_number\n");
return ret;
}
/* M */
if (value == 0xd)
*bin = 1;
/* J */
else if (value == 0xa)
*bin = 2;
}
/* M */
if (value == 0xd)
*bin = 1;
/* J */
else if (value == 0xa)
*bin = 2;
if (*bin < 0)
*bin = 0;
dev_info(dev, "bin=%d\n", *bin);

View File

@@ -1302,13 +1302,6 @@ static int rga_mm_sync_dma_sg_for_device(struct rga_internal_buffer *buffer,
struct sg_table *sgt;
struct rga_scheduler_t *scheduler;
sgt = rga_mm_lookup_sgt(buffer);
if (sgt == NULL) {
pr_err("%s(%d), failed to get sgt, core = 0x%x\n",
__func__, __LINE__, job->core);
return -EINVAL;
}
scheduler = buffer->dma_buffer->scheduler;
if (scheduler == NULL) {
pr_err("%s(%d), failed to get scheduler, core = 0x%x\n",
@@ -1316,7 +1309,18 @@ static int rga_mm_sync_dma_sg_for_device(struct rga_internal_buffer *buffer,
return -EFAULT;
}
dma_sync_sg_for_device(scheduler->dev, sgt->sgl, sgt->orig_nents, dir);
if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) {
dma_sync_single_for_device(scheduler->dev, buffer->phys_addr, buffer->size, dir);
} else {
sgt = rga_mm_lookup_sgt(buffer);
if (sgt == NULL) {
pr_err("%s(%d), failed to get sgt, core = 0x%x\n",
__func__, __LINE__, job->core);
return -EINVAL;
}
dma_sync_sg_for_device(scheduler->dev, sgt->sgl, sgt->orig_nents, dir);
}
return 0;
}
@@ -1328,13 +1332,6 @@ static int rga_mm_sync_dma_sg_for_cpu(struct rga_internal_buffer *buffer,
struct sg_table *sgt;
struct rga_scheduler_t *scheduler;
sgt = rga_mm_lookup_sgt(buffer);
if (sgt == NULL) {
pr_err("%s(%d), failed to get sgt, core = 0x%x\n",
__func__, __LINE__, job->core);
return -EINVAL;
}
scheduler = buffer->dma_buffer->scheduler;
if (scheduler == NULL) {
pr_err("%s(%d), failed to get scheduler, core = 0x%x\n",
@@ -1342,7 +1339,18 @@ static int rga_mm_sync_dma_sg_for_cpu(struct rga_internal_buffer *buffer,
return -EFAULT;
}
dma_sync_sg_for_cpu(scheduler->dev, sgt->sgl, sgt->orig_nents, dir);
if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) {
dma_sync_single_for_cpu(scheduler->dev, buffer->phys_addr, buffer->size, dir);
} else {
sgt = rga_mm_lookup_sgt(buffer);
if (sgt == NULL) {
pr_err("%s(%d), failed to get sgt, core = 0x%x\n",
__func__, __LINE__, job->core);
return -EINVAL;
}
dma_sync_sg_for_cpu(scheduler->dev, sgt->sgl, sgt->orig_nents, dir);
}
return 0;
}

View File

@@ -244,6 +244,8 @@ struct dw_hdmi_plat_data {
int (*get_next_hdr_data)(void *data, struct edid *edid,
struct drm_connector *connector);
struct dw_hdmi_link_config *(*get_link_cfg)(void *data);
void (*set_hdcp_status)(void *data, u8 status);
void (*set_hdcp2_enable)(void *data, bool enable);
void (*set_grf_cfg)(void *data);
u64 (*get_grf_color_fmt)(void *data);
void (*convert_to_split_mode)(struct drm_display_mode *mode);
@@ -256,6 +258,7 @@ struct dw_hdmi_plat_data {
void (*set_prev_bus_format)(void *data, unsigned long bus_format);
int (*get_colorimetry)(void *data, struct edid *edid);
void (*set_ddc_io)(void *data, bool enable);
void (*set_hdcp14_mem)(void *data, bool enable);
/* Vendor Property support */
const struct dw_hdmi_property_ops *property_ops;

View File

@@ -326,6 +326,7 @@ struct rkmodule_pdaf_inf {
__u32 dccmap_height;
__u32 dcc_mode;
__u32 dcc_dir;
__u32 pd_offset;
__u16 gainmap[RKMODULE_PADF_GAINMAP_LEN];
__u16 dccmap[RKMODULE_PDAF_DCCMAP_LEN];
} __attribute__ ((packed));

View File

@@ -216,6 +216,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TAS5720
imply SND_SOC_TAS6424
imply SND_SOC_TDA7419
imply SND_SOC_TDA7803
imply SND_SOC_TFA9879
imply SND_SOC_TLV320ADCX140
imply SND_SOC_TLV320AIC23_I2C
@@ -1442,6 +1443,11 @@ config SND_SOC_TDA7419
depends on I2C
select REGMAP_I2C
config SND_SOC_TDA7803
tristate "ST TDA7803 audio processor"
depends on I2C
select REGMAP_I2C
config SND_SOC_TFA9879
tristate "NXP Semiconductors TFA9879 amplifier"
depends on I2C

View File

@@ -232,6 +232,7 @@ snd-soc-tas571x-objs := tas571x.o
snd-soc-tas5720-objs := tas5720.o
snd-soc-tas6424-objs := tas6424.o
snd-soc-tda7419-objs := tda7419.o
snd-soc-tda7803-objs := tda7803.o
snd-soc-tas2770-objs := tas2770.o
snd-soc-tfa9879-objs := tfa9879.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
@@ -560,6 +561,7 @@ obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o
obj-$(CONFIG_SND_SOC_TDA7803) += snd-soc-tda7803.o
obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o

171
sound/soc/codecs/tda7803.c Normal file
View File

@@ -0,0 +1,171 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/soc.h>
#include "tda7803.h"
#define TDA7803_SAMPLE_RATE \
(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
struct tda7803_priv {
struct regmap *regmap;
u32 input_format;
};
static int tda7803_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct tda7803_priv *tda7803 = snd_soc_component_get_drvdata(component);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int val = 0;
snd_soc_component_write(component, TDA7803_REG2, DIGITAL_MUTE_OFF |
CH2_4_UMUTE | CH1_3_UMUTE |
MUTE_TIME_SETTING_1_45MS);
snd_soc_component_write(component, TDA7803_REG7, AMPLIEFIR_SWITCH_ON);
switch (tda7803->input_format) {
case 0:
val = INPUT_FORMAT_TDM_8CH_MODEL1;
break;
case 1:
val = INPUT_FORMAT_TDM_8CH_MODEL2;
break;
default:
return -EINVAL;
}
snd_soc_dai_set_fmt(codec_dai, val);
return 0;
}
static int tda7803_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;
int val = 0;
switch (params_rate(params)) {
case 44100:
val = SAMPLE_FREQUENCY_RANGE_44100HZ;
break;
case 48000:
val = SAMPLE_FREQUENCY_RANGE_48000HZ;
break;
case 96000:
val = SAMPLE_FREQUENCY_RANGE_96000HZ;
break;
case 192000:
val = SAMPLE_FREQUENCY_RANGE_192000HZ;
break;
default:
return -EINVAL;
}
snd_soc_component_write(component, TDA7803_REG3, val);
return 0;
}
static int tda7803_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
snd_soc_component_write(component, TDA7803_REG3, fmt);
return 0;
}
static const struct snd_soc_dai_ops tda7803_ops = {
.startup = tda7803_startup,
.hw_params = tda7803_hw_params,
.set_fmt = tda7803_set_fmt,
};
static struct snd_soc_dai_driver tda7803_dai = {
.name = "tda7803-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 8,
.rates = TDA7803_SAMPLE_RATE,
.formats = SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &tda7803_ops,
};
static const struct snd_soc_component_driver soc_codec_dev_tda7803 = {
.name = "tda7803",
};
static const struct regmap_config tda7803_i2c_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TDA7803_REGMAX,
.cache_type = REGCACHE_RBTREE,
};
static int tda7803_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tda7803_priv *tda7803;
int val;
tda7803 = devm_kzalloc(&i2c->dev, sizeof(*tda7803), GFP_KERNEL);
if (!tda7803)
return -ENOMEM;
i2c_set_clientdata(i2c, tda7803);
tda7803->regmap = devm_regmap_init_i2c(i2c, &tda7803_i2c_regmap);
if (IS_ERR(tda7803->regmap))
return PTR_ERR(tda7803->regmap);
if (!device_property_read_u32(&i2c->dev, "st,tda7803-format", &val))
tda7803->input_format = val;
return devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_tda7803,
&tda7803_dai, 1);
}
static const struct i2c_device_id tda7803_i2c_id[] = {
{ "tda7803", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tda7803_i2c_id);
static const struct of_device_id tda7803_of_match[] = {
{ .compatible = "st,tda7803" },
{ },
};
static struct i2c_driver tda7803_i2c_driver = {
.driver = {
.name = "tda7803",
.of_match_table = of_match_ptr(tda7803_of_match),
},
.probe = tda7803_i2c_probe,
.id_table = tda7803_i2c_id,
};
module_i2c_driver(tda7803_i2c_driver);
MODULE_AUTHOR("Jun Zeng <jun.zeng@rock-chips.com>");
MODULE_DESCRIPTION("TDA7803 audio processor driver");
MODULE_LICENSE("GPL");

138
sound/soc/codecs/tda7803.h Normal file
View File

@@ -0,0 +1,138 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#ifndef __TDA7803_H__
#define __TDA7803_H__
/* tda7803 registers space*/
#define TDA7803_REG0 (0x00)
#define CH1_AMP_SBI_MODE (0x00 << 0)
#define CH1_AMP_ABI_MODE (0x01 << 0)
#define CH2_AMP_SBI_MODE (0x00 << 1)
#define CH2_AMP_ABI_MODE (0x01 << 1)
#define CH3_AMP_SBI_MODE (0x00 << 2)
#define CH3_AMP_ABI_MODE (0x01 << 2)
#define CH4_AMP_SBI_MODE (0x00 << 3)
#define CH4_AMP_ABI_MODE (0x01 << 3)
#define CH1_TRI_MODE_OFF (0x00 << 4)
#define CH1_TRI_MODE_ON (0x01 << 4)
#define CH2_TRI_MODE_OFF (0x00 << 5)
#define CH2_TRI_MODE_ON (0x01 << 5)
#define CH3_TRI_MODE_OFF (0x00 << 6)
#define CH3_TRI_MODE_ON (0x01 << 6)
#define CH4_TRI_MODE_OFF (0x00 << 7)
#define CH4_TRI_MODE_ON (0x01 << 7)
#define TDA7803_REG1 (0x01)
#define CH2_4_GAIN_GV1 (0x00 << 0)
#define CH2_4_GAIN_GV2 (0x01 << 0)
#define CH2_4_GAIN_GV3 (0x02 << 0)
#define CH2_4_GAIN_GV4 (0x03 << 0)
#define CH1_3_GAIN_GV1 (0x00 << 2)
#define CH1_3_GAIN_GV2 (0x01 << 2)
#define CH1_3_GAIN_GV3 (0x02 << 2)
#define CH1_3_GAIN_GV4 (0x03 << 2)
#define GAIN_SELECT_NO (0x00 << 4)
#define GAIN_SELECT_6DB (0x01 << 4)
#define GAIN_SELECT_12DB (0x02 << 4)
#define GAIN_SELECT_NOT_USED (0x03 << 4)
#define IMPEDANCE_OPTIMIZER_REAR_2OHM (0x00 << 6)
#define IMPEDANCE_OPTIMIZER_REAR_4OHM (0x01 << 6)
#define IMPEDANCE_OPTIMIZER_FRONT_2OHM (0x00 << 7)
#define IMPEDANCE_OPTIMIZER_FRONT_4OHM (0x01 << 7)
#define TDA7803_REG2 (0x02)
#define LOW_BATTERY_MUTE_THRESHOLD_1 (0x00 << 0)
#define LOW_BATTERY_MUTE_THRESHOLD_2 (0x01 << 0)
#define DIGITAL_MUTE_ON (0x00 << 2)
#define DIGITAL_MUTE_OFF (0x01 << 2)
#define CH2_4_MUTE (0x00 << 3)
#define CH2_4_UMUTE (0x01 << 3)
#define CH1_3_MUTE (0x00 << 4)
#define CH1_3_UMUTE (0x01 << 4)
#define MUTE_TIME_SETTING_1_45MS (0x00 << 5)
#define MUTE_TIME_SETTING_5_8MS (0x01 << 5)
#define MUTE_TIME_SETTING_11_6MS (0x02 << 5)
#define MUTE_TIME_SETTING_23_2MS (0x03 << 5)
#define MUTE_TIME_SETTING_46_4MS (0x04 << 5)
#define MUTE_TIME_SETTING_92_8MS (0x05 << 5)
#define MUTE_TIME_SETTING_185_5MS (0x06 << 5)
#define MUTE_TIME_SETTING_371_1MS (0x07 << 5)
#define TDA7803_REG3 (0x03)
#define HIGH_PASS_FILTER_DISABLE (0x00 << 0)
#define HIGH_PASS_FILTER_ENABLE (0x01 << 0)
#define INPUT_OFFSET_DETECTION_DIS (0x00 << 1)
#define INPUT_OFFSET_DETECTION_EN (0x01 << 1)
#define NOISE_GATING_FUNCTION_EN (0x00 << 2)
#define NOISE_GATING_FUNCTION_DIS (0x01 << 2)
#define INPUT_FORMAT_I2S_STD (0x00 << 3)
#define INPUT_FORMAT_TDM_4CH (0x01 << 3)
#define INPUT_FORMAT_TDM_8CH_MODEL1 (0x02 << 3)
#define INPUT_FORMAT_TDM_8CH_MODEL2 (0x03 << 3)
#define INPUT_FORMAT_TDM_16CH_MODEL1 (0x04 << 3)
#define INPUT_FORMAT_TDM_16CH_MODEL2 (0x05 << 3)
#define INPUT_FORMAT_TDM_16CH_MODEL3 (0x06 << 3)
#define INPUT_FORMAT_TDM_16CH_MODEL4 (0x07 << 3)
#define SAMPLE_FREQUENCY_RANGE_44100HZ (0x00 << 6)
#define SAMPLE_FREQUENCY_RANGE_48000HZ (0x01 << 6)
#define SAMPLE_FREQUENCY_RANGE_96000HZ (0x02 << 6)
#define SAMPLE_FREQUENCY_RANGE_192000HZ (0x03 << 6)
#define TDA7803_REG4 (0x04)
#define DIAGNOSTIC_MODE_DISABLE (0x00 << 0)
#define DIAGNOSTIC_MODE_ENABLE (0x01 << 0)
#define CH2_4_SPEAKER_MODE (0x00 << 1)
#define CH2_4_LINE_DRIVER_MODE (0x01 << 1)
#define CH1_3_SPEAKER_MODE (0x00 << 2)
#define CH1_3_LINE_DRIVER_MODE (0x01 << 2)
#define DIAGNOSTIC_DISABLE (0X00 << 3)
#define DIAGNOSTIC_ENABLE (0X01 << 3)
#define DIAGNOSTIC_CURRENT_THRESHOLD_HIGH (0X00 << 4)
#define DIAGNOSTIC_CURRENT_THRESHOLD_LOW (0X01 << 4)
#define OFFSET_INFORMATION_YES (0X00 << 5)
#define OFFSET_INFORMATION_NO (0X01 << 5)
#define SHORT_FAULT_INFORMATION_YES (0X00 << 6)
#define SHORT_FAULT_INFORMATION_NO (0X01 << 6)
#define TDA7803_REG5 (0x05)
#define CAPABILITY_ENHANCER_DISABLE (0x00 << 1)
#define CAPABILITY_ENHANCER_ENABLE (0x0F << 1)
#define THERMAL_THRESHOLD_DEFAULT (0x00 << 6)
#define THERMAL_THRESHOLD_TW_NEGATIVE_10 (0x01 << 6)
#define THERMAL_THRESHOLD_TW_NEGATIVE_20 (0x02 << 6)
#define TDA7803_REG6 (0x06)
#define PARALLEL_MODE_CONFIG_MODE_1 (0x00 << 2)
#define PARALLEL_MODE_CONFIG_MODE_2 (0x01 << 2)
#define PARALLEL_MODE_CONFIG_MODE_3 (0x02 << 2)
#define PARALLEL_MODE_CONFIG_MODE_4 (0x03 << 2)
#define DIAGNOSITC_PULSE_STRETCH_MODE_1 (0x00 << 5)
#define DIAGNOSITC_PULSE_STRETCH_MODE_2 (0x01 << 5)
#define DIAGNOSITC_PULSE_STRETCH_MODE_3 (0x02 << 5)
#define DIAGNOSITC_PULSE_STRETCH_MODE_4 (0x03 << 5)
#define DIAGNOSITC_PULSE_STRETCH_MODE_5 (0x04 << 5)
#define DIAGNOSITC_PULSE_STRETCH_DEFAULT (0x05 << 5)
#define TDA7803_REG7 (0x07)
#define AMPLIEFIR_SWITCH_OFF (0x00 << 0)
#define AMPLIEFIR_SWITCH_ON (0x01 << 0)
#define CLIPP_LEVEL_1_REAR_CHANNELS2_4 (0x00 << 1)
#define CLIPP_LEVEL_2_REAR_CHANNELS2_4 (0x01 << 1)
#define CLIPP_LEVEL_3_REAR_CHANNELS2_4 (0x02 << 1)
#define NOT_CLIPP_FOR_REAR_CHANNELS2_4 (0x03 << 1)
#define CLIPP_LEVEL_1_REAR_CHANNELS1_3 (0x00 << 3)
#define CLIPP_LEVEL_2_REAR_CHANNELS1_3 (0x01 << 3)
#define CLIPP_LEVEL_3_REAR_CHANNELS1_3 (0x02 << 3)
#define NOT_CLIPP_FOR_REAR_CHANNELS1_3 (0x03 << 3)
#define TEMPERATURE_WARNING_TW1 (0x00 << 5)
#define TEMPERATURE_WARNING_TW2 (0x01 << 5)
#define TEMPERATURE_WARNING_TW3 (0x02 << 5)
#define TEMPERATURE_WARNING_TW4 (0x03 << 5)
#define NOT_TEMPERATURE_WARNING (0x04 << 5)
#define TDA7803_REGMAX (0x08)
#endif /* __TDA7803_H__ */