diff --git a/Documentation/devicetree/bindings/regulator/fan53555.txt b/Documentation/devicetree/bindings/regulator/fan53555.txt index 3a4a64d606c1..e7fc045281d1 100644 --- a/Documentation/devicetree/bindings/regulator/fan53555.txt +++ b/Documentation/devicetree/bindings/regulator/fan53555.txt @@ -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: diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 68b8029d57a6..463d6172ac85 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -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 \ diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi index 0b1cda728171..f3b2325dfc48 100644 --- a/arch/arm/boot/dts/rk3288-evb.dtsi +++ b/arch/arm/boot/dts/rk3288-evb.dtsi @@ -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 = ; + 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>; }; diff --git a/arch/arm/boot/dts/rv1106-evb-cam.dtsi b/arch/arm/boot/dts/rv1106-evb-cam.dtsi index 2e4967f10a66..9bc4ef9fae27 100644 --- a/arch/arm/boot/dts/rv1106-evb-cam.dtsi +++ b/arch/arm/boot/dts/rv1106-evb-cam.dtsi @@ -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"; diff --git a/arch/arm/boot/dts/rv1106-tb-nofastae-emmc.dtsi b/arch/arm/boot/dts/rv1106-tb-nofastae-emmc.dtsi new file mode 100644 index 000000000000..1095b35564d4 --- /dev/null +++ b/arch/arm/boot/dts/rv1106-tb-nofastae-emmc.dtsi @@ -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>; +}; diff --git a/arch/arm/boot/dts/rv1106-tb-nofastae-spi-nor.dtsi b/arch/arm/boot/dts/rv1106-tb-nofastae-spi-nor.dtsi new file mode 100644 index 000000000000..e0770091de6f --- /dev/null +++ b/arch/arm/boot/dts/rv1106-tb-nofastae-spi-nor.dtsi @@ -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"; +}; diff --git a/arch/arm/boot/dts/rv1106-tb-nofastae.dtsi b/arch/arm/boot/dts/rv1106-tb-nofastae.dtsi new file mode 100644 index 000000000000..de10bc2d951b --- /dev/null +++ b/arch/arm/boot/dts/rv1106-tb-nofastae.dtsi @@ -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>; +}; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v12-nofastae-emmc.dts b/arch/arm/boot/dts/rv1106g-evb2-v12-nofastae-emmc.dts new file mode 100644 index 000000000000..a49f45d5436d --- /dev/null +++ b/arch/arm/boot/dts/rv1106g-evb2-v12-nofastae-emmc.dts @@ -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"; +}; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v12-nofastae-spi-nor.dts b/arch/arm/boot/dts/rv1106g-evb2-v12-nofastae-spi-nor.dts new file mode 100644 index 000000000000..dcc4da3e5aa5 --- /dev/null +++ b/arch/arm/boot/dts/rv1106g-evb2-v12-nofastae-spi-nor.dts @@ -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"; +}; diff --git a/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts b/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts index 258cff792f76..255b4eefe5e4 100644 --- a/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts +++ b/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts @@ -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>; diff --git a/arch/arm/configs/rk3308bs_aarch32_mipi_display.config b/arch/arm/configs/rk3308bs_aarch32_mipi_display.config index 57d69eac4a58..02e4fba5e507 100644 --- a/arch/arm/configs/rk3308bs_aarch32_mipi_display.config +++ b/arch/arm/configs/rk3308bs_aarch32_mipi_display.config @@ -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 diff --git a/arch/arm/configs/rv1106-smart-door.config b/arch/arm/configs/rv1106-smart-door.config index 7bc919762e56..f9938242368c 100644 --- a/arch/arm/configs/rv1106-smart-door.config +++ b/arch/arm/configs/rv1106-smart-door.config @@ -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 diff --git a/arch/arm/configs/rv1106-tb-nofastae.config b/arch/arm/configs/rv1106-tb-nofastae.config new file mode 100644 index 000000000000..c0142d4101f3 --- /dev/null +++ b/arch/arm/configs/rv1106-tb-nofastae.config @@ -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 diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 69211157efb2..1344678c9ee4 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -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 diff --git a/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi index 73089bf04e09..f256ba0a6338 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi @@ -45,147 +45,171 @@ default-brightness-level = <200>; }; - panel: panel { - compatible = "simple-panel"; - bus-format = ; - 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 = ; + 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 - }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi index 095d2e197951..1217f907c646 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi @@ -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 = ; 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 }; diff --git a/arch/arm64/boot/dts/rockchip/rk3528-demo6-ddr3-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3528-demo6-ddr3-v10.dtsi index 228081882c8c..bf9b4ca8d9a5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-demo6-ddr3-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528-demo6-ddr3-v10.dtsi @@ -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>; diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts index a462ed70f3b3..ed4012324e98 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts +++ b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts @@ -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 = ; 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 }; diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts index 57c317a3bf2d..ad75cccc1009 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts +++ b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts @@ -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>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi index 63b8833f93df..a90ff4e4ef86 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi @@ -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 { diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10-linux.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10-linux.dts new file mode 100644 index 000000000000..e3abd49f690f --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10-linux.dts @@ -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 + +&vp0 { + cursor-win-id = ; +}; + +&vp1 { + cursor-win-id = ; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10.dts new file mode 100644 index 000000000000..b382cb433631 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10.dts @@ -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"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10.dtsi new file mode 100644 index 000000000000..f6269ac726be --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb8-lp4-v10.dtsi @@ -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; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index 952602e08593..171fa451d51f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -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 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588.dtsi index 5ce837cd8f73..bcbbc1629c01 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588.dtsi @@ -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 = , , , diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 1ae96bb5c106..8f2c011066b1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -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 = , , , diff --git a/arch/arm64/configs/rockchip_defconfig b/arch/arm64/configs/rockchip_defconfig index ed2421e2ce76..b2912832b178 100644 --- a/arch/arm64/configs/rockchip_defconfig +++ b/arch/arm64/configs/rockchip_defconfig @@ -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 diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index a9639edaca7e..456f6787d3a5 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -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 diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index 8de60c46d542..8ec63aaae4f7 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -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), diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 5c10de93dc53..79365eb18af3 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -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); diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile index 4e788dbdcfbe..757f5526fd64 100644 --- a/drivers/gpu/drm/bridge/synopsys/Makefile +++ b/drivers/gpu/drm/bridge/synopsys/Makefile @@ -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 diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-hdcp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-hdcp.c new file mode 100644 index 000000000000..7f55f7201ff8 --- /dev/null +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-hdcp.c @@ -0,0 +1,650 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) Rockchip Electronics Co.Ltd + * Author: + * Algea Cao + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-hdcp.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-hdcp.h new file mode 100644 index 000000000000..48c3a4843ac0 --- /dev/null +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-hdcp.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) Rockchip Electronics Co.Ltd + * Author: + * Algea Cao + */ +#ifndef DW_HDMI_QP_HDCP_H +#define DW_HDMI_QP_HDCP_H + +#include + +#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 diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index e234228adf88..906f0f628c2a 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -4,6 +4,7 @@ * Author: * Algea Cao */ +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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 @@ -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); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h index 225bfaa69701..e9b5e19a3be5 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h @@ -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__ */ diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 3a36cbecc256..c996343c35ad 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index e7b9e8ed5609..6c051d30f3a0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -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; } diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index ae95fb5b3d3a..f844376b2f28 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -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), diff --git a/drivers/media/i2c/gc2093.c b/drivers/media/i2c/gc2093.c index f0646b4fdd05..aa87a731dfe4 100644 --- a/drivers/media/i2c/gc2093.c +++ b/drivers/media/i2c/gc2093.c @@ -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); diff --git a/drivers/media/i2c/gc8034.c b/drivers/media/i2c/gc8034.c index 2c1dd377595a..caa71e5e119f 100644 --- a/drivers/media/i2c/gc8034.c +++ b/drivers/media/i2c/gc8034.c @@ -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; diff --git a/drivers/media/i2c/imx586.c b/drivers/media/i2c/imx586.c index c0808d0c5962..7948fe0834a5 100644 --- a/drivers/media/i2c/imx586.c +++ b/drivers/media/i2c/imx586.c @@ -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; diff --git a/drivers/media/i2c/lt6911uxe.c b/drivers/media/i2c/lt6911uxe.c index fb15093c13d5..e167aae6d899 100644 --- a/drivers/media/i2c/lt6911uxe.c +++ b/drivers/media/i2c/lt6911uxe.c @@ -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(<6911uxe->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(<6911uxe->i2c_client->dev, "sensor get dphy param\n"); break; diff --git a/drivers/media/i2c/lt7911uxc.c b/drivers/media/i2c/lt7911uxc.c index a39f8f818a22..20c9d2636666 100644 --- a/drivers/media/i2c/lt7911uxc.c +++ b/drivers/media/i2c/lt7911uxc.c @@ -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(<7911uxc->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(<7911uxc->i2c_client->dev, "sensor get dphy param\n"); break; diff --git a/drivers/media/i2c/nvp6158_drv/nvp6158_v4l2.c b/drivers/media/i2c/nvp6158_drv/nvp6158_v4l2.c index 0f163d0af7e0..a89a8369800b 100644 --- a/drivers/media/i2c/nvp6158_drv/nvp6158_v4l2.c +++ b/drivers/media/i2c/nvp6158_drv/nvp6158_v4l2.c @@ -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 = { diff --git a/drivers/media/i2c/otp_eeprom.c b/drivers/media/i2c/otp_eeprom.c index 2fb123ca72ac..315220ec867c 100644 --- a/drivers/media/i2c/otp_eeprom.c +++ b/drivers/media/i2c/otp_eeprom.c @@ -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++) { diff --git a/drivers/media/i2c/otp_eeprom.h b/drivers/media/i2c/otp_eeprom.h index 503d27741936..f284e6d59bb5 100644 --- a/drivers/media/i2c/otp_eeprom.h +++ b/drivers/media/i2c/otp_eeprom.h @@ -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; }; diff --git a/drivers/media/i2c/ov50c40.c b/drivers/media/i2c/ov50c40.c index 55f5b8284836..040dc7ff3fc6 100644 --- a/drivers/media/i2c/ov50c40.c +++ b/drivers/media/i2c/ov50c40.c @@ -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; diff --git a/drivers/media/i2c/s5kjn1.c b/drivers/media/i2c/s5kjn1.c index 29621d3f43ca..c291c1a3f838 100644 --- a/drivers/media/i2c/s5kjn1.c +++ b/drivers/media/i2c/s5kjn1.c @@ -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; diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 98df4f36c627..6f2df9432e16 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -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; diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 9020fff82c63..3df42731f17d 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -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); diff --git a/drivers/media/platform/rockchip/isp/regs_v3x.h b/drivers/media/platform/rockchip/isp/regs_v3x.h index 79c0d35e1717..af325bd17a46 100644 --- a/drivers/media/platform/rockchip/isp/regs_v3x.h +++ b/drivers/media/platform/rockchip/isp/regs_v3x.h @@ -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 */ diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index 1044ff3ef418..fb65cd1b11dd 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -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); diff --git a/drivers/rknpu/include/rknpu_drv.h b/drivers/rknpu/include/rknpu_drv.h index 05180cf5b38d..2f7de548a575 100644 --- a/drivers/rknpu/include/rknpu_drv.h +++ b/drivers/rknpu/include/rknpu_drv.h @@ -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 diff --git a/drivers/rknpu/include/rknpu_job.h b/drivers/rknpu/include/rknpu_job.h index dab2cefce1db..c62b1bf8e0ae 100644 --- a/drivers/rknpu/include/rknpu_job.h +++ b/drivers/rknpu/include/rknpu_job.h @@ -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); diff --git a/drivers/rknpu/rknpu_debugger.c b/drivers/rknpu/rknpu_debugger.c index 8bd7b62cef5b..97c87521575c 100644 --- a/drivers/rknpu/rknpu_debugger.c +++ b/drivers/rknpu/rknpu_debugger.c @@ -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); diff --git a/drivers/rknpu/rknpu_drv.c b/drivers/rknpu/rknpu_drv.c index ad0e22eabaa8..867212ce6059 100644 --- a/drivers/rknpu/rknpu_drv.c +++ b/drivers/rknpu/rknpu_drv.c @@ -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 diff --git a/drivers/rknpu/rknpu_gem.c b/drivers/rknpu/rknpu_gem.c index 6c08734e0fbc..415d3a47a06f 100644 --- a/drivers/rknpu/rknpu_gem.c +++ b/drivers/rknpu/rknpu_gem.c @@ -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; diff --git a/drivers/rknpu/rknpu_job.c b/drivers/rknpu/rknpu_job.c index 71556c8aad31..f0f1dd79c9a6 100644 --- a/drivers/rknpu/rknpu_job.c +++ b/drivers/rknpu/rknpu_job.c @@ -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); } } } diff --git a/drivers/rknpu/rknpu_mem.c b/drivers/rknpu/rknpu_mem.c index ff7e92d0174e..5242f1506280 100644 --- a/drivers/rknpu/rknpu_mem.c +++ b/drivers/rknpu/rknpu_mem.c @@ -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 diff --git a/drivers/soc/rockchip/rockchip_opp_select.c b/drivers/soc/rockchip/rockchip_opp_select.c index 7de80cee6e92..8caae5ccbbf3 100644 --- a/drivers/soc/rockchip/rockchip_opp_select.c +++ b/drivers/soc/rockchip/rockchip_opp_select.c @@ -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); diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c index 1ca0d7c3501d..d261833b3ace 100644 --- a/drivers/video/rockchip/rga3/rga_mm.c +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -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; } diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 84020553cbf8..aca7ae836796 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -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; diff --git a/include/uapi/linux/rk-camera-module.h b/include/uapi/linux/rk-camera-module.h index b1204b09cdca..7a825afaa279 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -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)); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8121978a31a8..cb3b581dbfb5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -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 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20ee39074e71..fd3e6861e75c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -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 diff --git a/sound/soc/codecs/tda7803.c b/sound/soc/codecs/tda7803.c new file mode 100644 index 000000000000..b75459180f0b --- /dev/null +++ b/sound/soc/codecs/tda7803.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("TDA7803 audio processor driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tda7803.h b/sound/soc/codecs/tda7803.h new file mode 100644 index 000000000000..54a7b610722f --- /dev/null +++ b/sound/soc/codecs/tda7803.h @@ -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__ */