diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 0d4ae6d03e16..8b2ff82971de 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1186,10 +1186,12 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1126b-evb1-v11.dtb \ rv1126b-evb1-v11-dual-4k.dtb \ rv1126b-evb2-v10.dtb \ + rv1126b-evb2-v10-dv.dtb \ rv1126b-evb2-v10-mcu-k350c4516t.dtb \ rv1126b-evb2-v10-rgb-Q7050ITH2641AA1T.dtb \ rv1126b-evb2-v10-sii9022-bt1120-to-hdmi.dtb \ - rv1126b-evb2-v10-tb-400w.dtb \ + rv1126b-evb2-v10-tb-400w-emmc.dtb \ + rv1126b-evb2-v10-tb-400w-spi-nor.dtb \ rv1126b-evb3-v10.dtb \ rv1126b-evb4-v10.dtb \ rv1126b-iotest-v10.dtb \ diff --git a/arch/arm/boot/dts/rv1126b-evb2-v10-dv.dts b/arch/arm/boot/dts/rv1126b-evb2-v10-dv.dts new file mode 100644 index 000000000000..7d841c2f5a2c --- /dev/null +++ b/arch/arm/boot/dts/rv1126b-evb2-v10-dv.dts @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +#include "arm64/rockchip/rv1126b-evb2-v10-dv.dts" diff --git a/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w-emmc.dts b/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w-emmc.dts new file mode 100644 index 000000000000..105bdd87ad4b --- /dev/null +++ b/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w-emmc.dts @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "arm64/rockchip/rv1126b.dtsi" +#include "arm64/rockchip/rv1126b-evb.dtsi" +#include "arm64/rockchip/rv1126b-evb2-v10.dtsi" +#include "rv1126b-thunder-boot-cam.dtsi" +#include "rv1126b-thunder-boot-emmc.dtsi" + +/ { + model = "Rockchip RV1126B EVB2 V10 TB 400W eMMC Board"; + compatible = "rockchip,rv1126b-evb2-v10-tb-400w-emmc", "rockchip,rv1126b"; + + chosen { + bootargs = "loglevel=0 initcall_nr_threads=-1 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K"; + }; +}; + +&emmc { + bus-width = <8>; + cap-mmc-highspeed; + non-removable; + mmc-hs200-1_8v; + rockchip,default-sample-phase = <90>; + no-sdio; + no-sd; + status = "okay"; +}; + +&fspi0 { + status = "disabled"; +}; + +&i2c3 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c3m1_pins>; + rockchip,amp-shared; + status = "okay"; + + sc450ai: sc450ai@30 { + compatible = "smartsens,sc450ai"; + reg = <0x30>; + clocks = <&cru CLK_MIPI0_OUT2IO>; + clock-names = "xvclk"; + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk0_pins>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "default"; + rockchip,camera-module-lens-name = "default"; + port { + cam0_out: endpoint { + remote-endpoint = <&csi_dphy_input0>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +&ramdisk_r { + reg = <0x48c40000 (60 * 0x00100000)>; +}; + +&ramdisk_c { + reg = <0x4c840000 (30 * 0x00100000)>; +}; + +&rkisp_thunderboot { + /* reg's offset MUST match with RTOS */ + /* + * vicap, capture raw10, ceil(w*10/8/256)*256*h *4(buf num) + * e.g. 2688x1520: 0x14c8000 + */ + reg = <0x41320000 0x14c8000>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10-tb-400w.dts b/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w-spi-nor.dts similarity index 79% rename from arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10-tb-400w.dts rename to arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w-spi-nor.dts index c1ba05974b77..ad9c331b2226 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10-tb-400w.dts +++ b/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w-spi-nor.dts @@ -4,15 +4,15 @@ */ /dts-v1/; -#include "rv1126b.dtsi" -#include "rv1126b-evb.dtsi" -#include "rv1126b-evb2-v10.dtsi" +#include "arm64/rockchip/rv1126b.dtsi" +#include "arm64/rockchip/rv1126b-evb.dtsi" +#include "arm64/rockchip/rv1126b-evb2-v10.dtsi" #include "rv1126b-thunder-boot-cam.dtsi" #include "rv1126b-thunder-boot-spi-nor.dtsi" / { - model = "Rockchip RV1126B EVB2 V10 ARM64 TB 400W Board"; - compatible = "rockchip,rv1126b-evb2-v10-tb-400w", "rockchip,rv1126b"; + model = "Rockchip RV1126B EVB2 V10 TB 400W SPI NorFlash Board"; + compatible = "rockchip,rv1126b-evb2-v10-tb-400w-spi-nor", "rockchip,rv1126b"; chosen { bootargs = "loglevel=0 initcall_nr_threads=-1 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K"; @@ -28,7 +28,6 @@ sc450ai: sc450ai@30 { compatible = "smartsens,sc450ai"; - status = "okay"; reg = <0x30>; clocks = <&cru CLK_MIPI0_OUT2IO>; clock-names = "xvclk"; @@ -50,11 +49,11 @@ }; &ramdisk_r { - reg = <0x48c40000 (40 * 0x00100000)>; + reg = <0x48c40000 (30 * 0x00100000)>; }; &ramdisk_c { - reg = <0x4b440000 (20 * 0x00100000)>; + reg = <0x4aa40000 (20 * 0x00100000)>; }; &rkisp_thunderboot { diff --git a/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w.dts b/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w.dts deleted file mode 100644 index 5d1bfda82ece..000000000000 --- a/arch/arm/boot/dts/rv1126b-evb2-v10-tb-400w.dts +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Copyright (c) 2025 Rockchip Electronics Co., Ltd. - */ - -#include "arm64/rockchip/rv1126b-evb2-v10-tb-400w.dts" - -/ { - model = "Rockchip RV1126B EVB2 V10 TB 400W Board"; - compatible = "rockchip,rv1126b-evb2-v10-tb-400w", "rockchip,rv1126b"; -}; - -&ramdisk_r { - reg = <0x48c40000 (30 * 0x00100000)>; -}; - -&ramdisk_c { - reg = <0x4aa40000 (20 * 0x00100000)>; -}; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot-cam.dtsi b/arch/arm/boot/dts/rv1126b-thunder-boot-cam.dtsi similarity index 100% rename from arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot-cam.dtsi rename to arch/arm/boot/dts/rv1126b-thunder-boot-cam.dtsi diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot-emmc.dtsi b/arch/arm/boot/dts/rv1126b-thunder-boot-emmc.dtsi similarity index 100% rename from arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot-emmc.dtsi rename to arch/arm/boot/dts/rv1126b-thunder-boot-emmc.dtsi diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot-spi-nor.dtsi b/arch/arm/boot/dts/rv1126b-thunder-boot-spi-nor.dtsi similarity index 100% rename from arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot-spi-nor.dtsi rename to arch/arm/boot/dts/rv1126b-thunder-boot-spi-nor.dtsi diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot.dtsi b/arch/arm/boot/dts/rv1126b-thunder-boot.dtsi similarity index 98% rename from arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot.dtsi rename to arch/arm/boot/dts/rv1126b-thunder-boot.dtsi index 3c7d15df6207..b66d0d5f6d18 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-thunder-boot.dtsi +++ b/arch/arm/boot/dts/rv1126b-thunder-boot.dtsi @@ -116,7 +116,7 @@ }; rtos: rtos@48c00000 { - reg = <0x48c00000 0x0003a000>; + reg = <0x48c00000 0x0003c000>; }; mcu_log: mcu_log@48c3c000 { diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 1bccd6fa1c84..5f5f1fed4985 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -388,10 +388,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb1-v11-dual-4k.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-aov-dual-cam.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-dv.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-mcu-k350c4516t.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-rgb-Q7050ITH2641AA1T.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-sii9022-bt1120-to-hdmi.dtb -dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-tb-400w.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb3-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-iotest-v10.dtb diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10-dv.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10-dv.dts new file mode 100644 index 000000000000..ae0f9e4f4f10 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10-dv.dts @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1126b.dtsi" +#include "rv1126b-evb.dtsi" +#include "rv1126b-evb2-v10.dtsi" +#include "rv1126b-evb-cam-csi0.dtsi" + +/ { + model = "Rockchip RV1126B EVB1 V10 DV Board"; + compatible = "rockchip,rv1126b-evb2-v10-dv", "rockchip,rv1126b"; + chosen { + bootargs = "earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 rw root=PARTUUID=614e0000-0000 rootfstype=ext4 rootwait snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K isolcpus=3 nohz_full=3"; + }; +}; + +&gc8613 { + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; + /delete-property/ pwdn-gpios; +}; + +&gpio5 { + interrupt-affinity = <&cpu0>, <&cpu0>, <&cpu0>, <&cpu3>; + interrupt-pins = <0>, + <0>, + <0>, + ; +}; + +&imx415 { + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; +}; + +&imx586 { + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; +}; + +&pinctrl { + inv { + inv_int1: inv-int1 { + rockchip,pins = + <5 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&rkfec { + status = "okay"; +}; + +&rkfec_mmu { + status = "okay"; +}; + +&rknpu { + status = "disabled"; +}; + +&sc450ai { + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; +}; + +&sc850sl { + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; +}; + +&spi0 { + status = "okay"; + max-freq = <24000000>; + pinctrl-names = "default"; + pinctrl-0 = <&spi0m2_clk_pins &spi0m2_csn0_pins &inv_int1>; + icm42670: icm42670@0 { + compatible = "invensense,icm42670"; + reg = <0x0>; + spi-max-frequency = <24000000>; + spi-cpha; + spi-cpol; + //vdd-supply = <&vcc_3v3_s0>; + int1-gpio = <&gpio5 RK_PB0 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&gpio5>; + interrupts = <8 IRQ_TYPE_EDGE_FALLING>; + status = "okay"; + }; +}; + +&uart2 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index 76a69b31842d..fa046cdc5f6f 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -3377,8 +3377,8 @@ compatible = "rockchip,hw-decompress"; reg = <0x22100000 0x1000>; interrupts = ; - clocks = <&cru ACLK_DECOM>, <&cru DCLK_DECOM>, <&cru PCLK_DECOM>; - clock-names = "aclk", "dclk", "pclk"; + clocks = <&cru ACLK_DECOM>, <&cru DCLK_DECOM>, <&cru PCLK_DECOM>, <&cru ACLK_RKMMU_DECOM>, <&cru HCLK_RKMMU_DECOM>; + clock-names = "aclk", "dclk", "pclk", "aclk_mmu", "hclk_mmu"; resets = <&cru SRST_DRESETN_DECOM>; reset-names = "dresetn"; status = "disabled"; diff --git a/drivers/media/i2c/os12d40.c b/drivers/media/i2c/os12d40.c index 7eb784d0ed80..ce6687855461 100644 --- a/drivers/media/i2c/os12d40.c +++ b/drivers/media/i2c/os12d40.c @@ -181,6 +181,10 @@ struct os12d40 { const char *module_name; const char *len_name; struct rkmodule_awb_cfg awb_cfg; + bool has_init_wbgain; + bool has_init_blc; + struct rkmodule_wb_gain_group init_wbgain; + struct rkmodule_blc_group init_blc; }; #define to_os12d40(sd) container_of(sd, struct os12d40, subdev) @@ -2271,6 +2275,87 @@ static void os12d40_set_awb_cfg(struct os12d40 *os12d40, mutex_unlock(&os12d40->mutex); } +static int os12d40_set_wb_gain(struct os12d40 *os12d40, + struct rkmodule_wb_gain_group *wb_gain_group) +{ + struct rkmodule_wb_gain wb_gain; + u16 reg_bgain = 0, reg_gbgain = 0, reg_grgain = 0, reg_rgain = 0; + int ret = 0; +#ifdef DEBUG + u32 bgain = 0, gbgain = 0, grgain = 0, rgain = 0; +#endif + + if (!os12d40->has_init_wbgain && !os12d40->streaming) { + os12d40->init_wbgain = *wb_gain_group; + os12d40->has_init_wbgain = true; + dev_dbg(&os12d40->client->dev, "os12d40 don't stream, record wbgain!\n"); + return ret; + } + reg_bgain = 0x7000; + reg_gbgain = 0x7002; + reg_grgain = 0x7004; + reg_rgain = 0x7006; + wb_gain = wb_gain_group->wb_gain[0]; + ret = os12d40_write_reg(os12d40->client, reg_bgain, + OS12D40_REG_VALUE_16BIT, wb_gain.b_gain & 0xffff); + ret |= os12d40_write_reg(os12d40->client, reg_grgain, + OS12D40_REG_VALUE_16BIT, wb_gain.gr_gain & 0xffff); + ret |= os12d40_write_reg(os12d40->client, reg_gbgain, + OS12D40_REG_VALUE_16BIT, wb_gain.gb_gain & 0xffff); + ret |= os12d40_write_reg(os12d40->client, reg_rgain, + OS12D40_REG_VALUE_16BIT, wb_gain.r_gain & 0xffff); + dev_info(&os12d40->client->dev, + "write wb gain, type:%d, b:0x%x, gb:0x%x, gr:0x%x, r:0x%x\n", + wb_gain_group->wb_gain_type[0], + wb_gain.b_gain, wb_gain.gb_gain, + wb_gain.gr_gain, wb_gain.r_gain); +#ifdef DEBUG + ret |= os12d40_read_reg(os12d40->client, reg_bgain, + OS12D40_REG_VALUE_16BIT, &bgain); + ret |= os12d40_read_reg(os12d40->client, reg_gbgain, + OS12D40_REG_VALUE_16BIT, &gbgain); + ret |= os12d40_read_reg(os12d40->client, reg_grgain, + OS12D40_REG_VALUE_16BIT, &grgain); + ret |= os12d40_read_reg(os12d40->client, reg_rgain, + OS12D40_REG_VALUE_16BIT, &rgain); + dev_info(&os12d40->client->dev, + "read wb gain, type %d, b:0x%x, gb:0x%x, gr:0x%x, r:0x%x\n", + wb_gain_group->wb_gain_type[0], bgain, gbgain, grgain, rgain); +#endif + return ret; +} + +static int os12d40_set_blc(struct os12d40 *os12d40, + struct rkmodule_blc_group *blc_group) +{ + u32 reg_blc = 0; + u32 blc_val = 0; + int ret = 0; + + if (!os12d40->has_init_blc && !os12d40->streaming) { + os12d40->init_blc = *blc_group; + os12d40->has_init_blc = true; + dev_dbg(&os12d40->client->dev, "os12d40 don't stream, record blc!\n"); + return ret; + } + reg_blc = 0x4019; + blc_val = blc_group->blc[0]; + ret = os12d40_write_reg(os12d40->client, reg_blc, + OS12D40_REG_VALUE_16BIT, blc_val & 0x3ff); + dev_info(&os12d40->client->dev, + "write blc, type:%d, blc_val:0x%x\n", + blc_group->blc_type[0], + blc_val); +#ifdef DEBUG + ret |= os12d40_read_reg(os12d40->client, reg_blc, + OS12D40_REG_VALUE_16BIT, &blc_val); + dev_info(&os12d40->client->dev, + "read blc, type %d, blc_val:0x%x\n", + blc_group->blc_type[0], blc_val); +#endif + return ret; +} + static long os12d40_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct os12d40 *os12d40 = to_os12d40(sd); @@ -2278,6 +2363,10 @@ static long os12d40_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) long ret = 0; u32 stream = 0; u32 *bayer_mode; + struct rkmodule_wb_gain_info *wb_gain_info; + struct rkmodule_blc_info *blc_info; + struct rkmodule_wb_gain_group *wb_gain_group; + struct rkmodule_blc_group *blc_group; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2318,6 +2407,23 @@ static long os12d40_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) *bayer_mode = RKMODULE_NORMAL_BAYER; #endif break; + case RKMODULE_GET_WB_GAIN_INFO: + wb_gain_info = (struct rkmodule_wb_gain_info *)arg; + wb_gain_info->coarse_bit = 5; + wb_gain_info->fine_bit = 10; + break; + case RKMODULE_GET_BLC_INFO: + blc_info = (struct rkmodule_blc_info *)arg; + blc_info->bit_width = 10; + break; + case RKMODULE_SET_WB_GAIN: + wb_gain_group = (struct rkmodule_wb_gain_group *)arg; + ret = os12d40_set_wb_gain(os12d40, wb_gain_group); + break; + case RKMODULE_SET_BLC: + blc_group = (struct rkmodule_blc_group *)arg; + ret = os12d40_set_blc(os12d40, blc_group); + break; default: ret = -ENOIOCTLCMD; break; @@ -2337,6 +2443,10 @@ static long os12d40_compat_ioctl32(struct v4l2_subdev *sd, long ret; u32 stream = 0; u32 bayer_mode = 0; + struct rkmodule_wb_gain_info *wb_gain_info; + struct rkmodule_blc_info *blc_info; + struct rkmodule_wb_gain_group *wb_gain_group; + struct rkmodule_blc_group *blc_group; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2413,6 +2523,68 @@ static long os12d40_compat_ioctl32(struct v4l2_subdev *sd, return -EFAULT; } break; + case RKMODULE_GET_WB_GAIN_INFO: + wb_gain_info = kzalloc(sizeof(*wb_gain_info), GFP_KERNEL); + if (!wb_gain_info) { + ret = -ENOMEM; + return ret; + } + + ret = os12d40_ioctl(sd, cmd, wb_gain_info); + if (!ret) { + if (copy_to_user(up, wb_gain_info, sizeof(*wb_gain_info))) { + kfree(wb_gain_info); + return -EFAULT; + } + } + kfree(wb_gain_info); + break; + case RKMODULE_GET_BLC_INFO: + blc_info = kzalloc(sizeof(*blc_info), GFP_KERNEL); + if (!blc_info) { + ret = -ENOMEM; + return ret; + } + + ret = os12d40_ioctl(sd, cmd, blc_info); + if (!ret) { + if (copy_to_user(up, blc_info, sizeof(*blc_info))) { + kfree(blc_info); + return -EFAULT; + } + } + kfree(blc_info); + break; + case RKMODULE_SET_WB_GAIN: + wb_gain_group = kzalloc(sizeof(*wb_gain_group), GFP_KERNEL); + if (!wb_gain_group) { + ret = -ENOMEM; + return ret; + } + + ret = os12d40_ioctl(sd, cmd, wb_gain_group); + if (!ret) { + ret = copy_to_user(up, wb_gain_group, sizeof(*wb_gain_group)); + if (ret) + return -EFAULT; + } + kfree(wb_gain_group); + break; + case RKMODULE_SET_BLC: + blc_group = kzalloc(sizeof(*blc_group), GFP_KERNEL); + if (!blc_group) { + ret = -ENOMEM; + return ret; + } + + ret = os12d40_ioctl(sd, cmd, blc_group); + if (!ret) { + ret = copy_to_user(up, blc_group, sizeof(*blc_group)); + if (ret) + return -EFAULT; + } + kfree(blc_group); + break; default: ret = -ENOIOCTLCMD; break; @@ -2452,6 +2624,26 @@ static int __os12d40_start_stream(struct os12d40 *os12d40) if (ret) return ret; + if (os12d40->has_init_wbgain) { + ret = os12d40_ioctl(&os12d40->subdev, + RKMODULE_SET_WB_GAIN, + &os12d40->init_wbgain); + if (ret) { + dev_err(&os12d40->client->dev, + "init wbgain fail\n"); + return ret; + } + } + if (os12d40->has_init_blc) { + ret = os12d40_ioctl(&os12d40->subdev, + RKMODULE_SET_BLC, + &os12d40->init_blc); + if (ret) { + dev_err(&os12d40->client->dev, + "init blc fail\n"); + return ret; + } + } ret = os12d40_write_reg(os12d40->client, OS12D40_REG_CTRL_MODE, OS12D40_REG_VALUE_08BIT, OS12D40_MODE_STREAMING); return ret; @@ -2459,6 +2651,8 @@ static int __os12d40_start_stream(struct os12d40 *os12d40) static int __os12d40_stop_stream(struct os12d40 *os12d40) { + os12d40->has_init_wbgain = false; + os12d40->has_init_blc = false; return os12d40_write_reg(os12d40->client, OS12D40_REG_CTRL_MODE, OS12D40_REG_VALUE_08BIT, OS12D40_MODE_SW_STANDBY); } @@ -3001,6 +3195,8 @@ static int os12d40_initialize_controls(struct os12d40 *os12d40) } os12d40->subdev.ctrl_handler = handler; + os12d40->has_init_wbgain = false; + os12d40->has_init_blc = false; return 0; diff --git a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c index 6c92a221257a..637028a2cf59 100644 --- a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c @@ -335,6 +335,8 @@ static void rk628_bt1120_hdmirx_reset(struct v4l2_subdev *sd) bt1120->hdcp.hdcp_start = false; enable_irq(bt1120->plugin_irq); enable_irq(bt1120->hdmirx_irq); + if (bt1120->cec && bt1120->cec->adap) + rk628_hdmirx_cec_state_reconfiguration(bt1120->rk628, bt1120->cec); } static void rk628_hdmirx_plugout(struct v4l2_subdev *sd) @@ -438,8 +440,6 @@ static void rk628_bt1120_delayed_work_enable_hotplug(struct work_struct *work) rk628_hdmirx_controller_setup(bt1120->rk628); rk628_hdmirx_hpd_ctrl(sd, true); rk628_hdmirx_config_all(sd); - if (bt1120->cec && bt1120->cec->adap) - rk628_hdmirx_cec_state_reconfiguration(bt1120->rk628, bt1120->cec); rk628_bt1120_enable_interrupts(sd, true); } else { bt1120->nosignal = true; diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 6d26da0db4ab..f424a3cec945 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -498,6 +498,8 @@ static void rk628_csi_hdmirx_reset(struct v4l2_subdev *sd) csi->hdcp.hdcp_start = false; enable_irq(csi->plugin_irq); enable_irq(csi->hdmirx_irq); + if (csi->cec && csi->cec->adap) + rk628_hdmirx_cec_state_reconfiguration(csi->rk628, csi->cec); } static void rk628_hdmirx_plugout(struct v4l2_subdev *sd) @@ -574,8 +576,6 @@ static void rk628_csi_delayed_work_enable_hotplug(struct work_struct *work) rk628_hdmirx_controller_setup(csi->rk628); rk628_hdmirx_hpd_ctrl(sd, true); rk628_hdmirx_config_all(sd); - if (csi->cec && csi->cec->adap) - rk628_hdmirx_cec_state_reconfiguration(csi->rk628, csi->cec); rk628_csi_enable_interrupts(sd, true); } else { extcon_set_state_sync(csi->extcon, EXTCON_JACK_VIDEO_IN, false); diff --git a/drivers/media/platform/rockchip/aiisp/aiisp.c b/drivers/media/platform/rockchip/aiisp/aiisp.c index 6c37a3069835..85591f813469 100644 --- a/drivers/media/platform/rockchip/aiisp/aiisp.c +++ b/drivers/media/platform/rockchip/aiisp/aiisp.c @@ -174,8 +174,8 @@ static void rkaiisp_dumpreg(struct rkaiisp_device *aidev, u32 start, u32 end) static void rkaiisp_dump_list_reg(struct rkaiisp_device *aidev) { - dev_info(aidev->dev, "frame_id: %d, run_idx: %d\n", - aidev->frame_id, aidev->run_idx); + dev_info(aidev->dev, "frame_id: %d, run_idx: %d, parthdl %d\n", + aidev->frame_id, aidev->run_idx, aidev->parthdl_idx); rkaiisp_dumpreg(aidev, AIISP_CORE_CTRL, AIISP_CORE_NOISE_LMT); rkaiisp_dumpreg(aidev, AIISP_CORE_COMP0, AIISP_CORE_DECOMP16); @@ -350,6 +350,24 @@ static void rkaiisp_free_buffer(struct rkaiisp_device *aidev, } } +static void __maybe_unused rkaiisp_prepare_buffer(struct rkaiisp_device *aidev, + struct rkaiisp_dummy_buffer *buf) +{ + const struct vb2_mem_ops *g_ops = aidev->hw_dev->mem_ops; + + if (buf && buf->mem_priv) + g_ops->prepare(buf->mem_priv); +} + +static void __maybe_unused rkaiisp_finish_buffer(struct rkaiisp_device *aidev, + struct rkaiisp_dummy_buffer *buf) +{ + const struct vb2_mem_ops *g_ops = aidev->hw_dev->mem_ops; + + if (buf && buf->mem_priv) + g_ops->finish(buf->mem_priv); +} + static void rkaiisp_detach_dmabuf(struct rkaiisp_device *aidev, struct rkaiisp_dummy_buffer *buffer) { @@ -651,6 +669,7 @@ static int rkaiisp_init_pool(struct rkaiisp_device *aidev, struct rkaiisp_ispbuf aidev->ispbuf = *ispbuf; aidev->outbuf_idx = 0; + aidev->parthdl_num = 1; aidev->init_buf = true; v4l2_dbg(1, rkaiisp_debug, &aidev->v4l2_dev, "init buf poll\n"); @@ -670,7 +689,6 @@ static int rkaiisp_free_airms_pool(struct rkaiisp_device *aidev) for (i = 0; i < aidev->rmsbuf.outbuf_num; i++) rkaiisp_free_buffer(aidev, &aidev->rms_outbuf[i]); - rkaiisp_free_buffer(aidev, &aidev->sigma_buf); rkaiisp_free_buffer(aidev, &aidev->narmap_buf); aidev->init_buf = false; @@ -682,9 +700,12 @@ static int rkaiisp_free_airms_pool(struct rkaiisp_device *aidev) static int rkaiisp_init_airms_pool(struct rkaiisp_device *aidev, struct rkaiisp_rmsbuf_info *rmsbuf) { int i, ret = 0; + u32 bin_width, bin_height; u32 size; - size = rmsbuf->image_width * rmsbuf->image_height * 2; + bin_width = CEIL_BY(CEIL_DOWN(rmsbuf->image_width, 2), 2); + bin_height = CEIL_BY(CEIL_DOWN(rmsbuf->image_height, 2), 2); + size = rmsbuf->image_width * rmsbuf->image_height * 2 + bin_width * bin_height; rmsbuf->inbuf_num = RKAIISP_MIN(rmsbuf->inbuf_num, RKAIISP_AIRMS_BUF_MAXCNT); for (i = 0; i < rmsbuf->inbuf_num; i++) { aidev->rms_inbuf[i].size = size; @@ -700,6 +721,25 @@ static int rkaiisp_init_airms_pool(struct rkaiisp_device *aidev, struct rkaiisp_ rmsbuf->inbuf_fd[i] = aidev->rms_inbuf[i].dma_fd; } + aidev->rmsbuf = *rmsbuf; + aidev->part_rmsbuf = aidev->rmsbuf; + if (rmsbuf->image_width > RKAIISP_AIRMS_MAX_WIDTH) { + int proc_width; + + aidev->is_parthdl = true; + aidev->parthdl_num = 2; + proc_width = aidev->part_rmsbuf.image_width / 2 + RKAIISP_AIRMS_EXTEND_PIXEL; + aidev->part_rmsbuf.image_width = CEIL_BY(proc_width, 16); + aidev->part_rmsbuf.sigma_width = aidev->part_rmsbuf.image_width / 2; + aidev->part_rmsbuf.narmap_width = (aidev->part_rmsbuf.image_width + 7) / 8 * 2; + aidev->parthdl_image_oft = aidev->rmsbuf.image_width - aidev->part_rmsbuf.image_width; + size = (CEIL_BY(rmsbuf->image_width, 2) + 2 * RKAIISP_AIRMS_EXTEND_PIXEL) * rmsbuf->image_height * 2; + } else { + aidev->is_parthdl = false; + aidev->parthdl_num = 1; + size = rmsbuf->image_width * rmsbuf->image_height * 2; + } + rmsbuf->outbuf_num = RKAIISP_MIN(rmsbuf->outbuf_num, RKAIISP_AIRMS_BUF_MAXCNT); for (i = 0; i < rmsbuf->outbuf_num; i++) { aidev->rms_outbuf[i].size = size; @@ -715,18 +755,12 @@ static int rkaiisp_init_airms_pool(struct rkaiisp_device *aidev, struct rkaiisp_ rmsbuf->outbuf_fd[i] = aidev->rms_outbuf[i].dma_fd; } - aidev->sigma_buf.size = rmsbuf->sigma_width * rmsbuf->sigma_height; - aidev->sigma_buf.is_need_vaddr = false; - aidev->sigma_buf.is_need_dbuf = false; - aidev->sigma_buf.is_need_dmafd = false; - rkaiisp_allow_buffer(aidev, &aidev->sigma_buf); - aidev->narmap_buf.size = rmsbuf->narmap_width * rmsbuf->narmap_height; + aidev->narmap_buf.size = aidev->rmsbuf.narmap_width * aidev->rmsbuf.narmap_height; aidev->narmap_buf.is_need_vaddr = false; aidev->narmap_buf.is_need_dbuf = false; aidev->narmap_buf.is_need_dmafd = false; rkaiisp_allow_buffer(aidev, &aidev->narmap_buf); - aidev->rmsbuf = *rmsbuf; aidev->init_buf = true; v4l2_dbg(1, rkaiisp_debug, &aidev->v4l2_dev, "init buf poll\n"); @@ -880,6 +914,13 @@ static void rkaiisp_gen_slice_param(struct rkaiisp_device *aidev, } } + if (slice_idx > 8) { + aidev->is_state_err = true; + v4l2_err(&aidev->v4l2_dev, + "slice num %d is too big, input width %d\n", slice_idx, width); + return; + } + if (slice_idx >= 1) slice_num = slice_idx - 1; value = slice_mode[0] | @@ -990,6 +1031,9 @@ static int rkaiisp_determine_size(struct rkaiisp_device *aidev, if (n == 3 && model_cfg->sw_mi_chn3_sel == 0) bits = 8; + if (aidev->chn_size[n].stride != 0 && aidev->exealgo == AIRMS) + cols = aidev->chn_size[n].stride; + sw_mi_chn_stride[n] = CEIL_BY(cols * chns * bits, 16 * 8) / 32; } @@ -1130,6 +1174,7 @@ static u32 rkaiisp_config_rdchannel(struct rkaiisp_device *aidev, { struct rkaiisp_ispbuf_info *ispbuf = &aidev->ispbuf; struct rkaiisp_rmsbuf_info *rmsbuf = &aidev->rmsbuf; + struct rkaiisp_rmsbuf_info *part_rmsbuf = &aidev->part_rmsbuf; struct rkaiisp_dummy_buffer *vpsl_buf; dma_addr_t dma_addr; u32 width, height, stride; @@ -1239,20 +1284,29 @@ static u32 rkaiisp_config_rdchannel(struct rkaiisp_device *aidev, dma_addr = aidev->lastout_buf[aidev->outbuf_idx]->dma_addr; break; case VICAP_BAYER_RAW: - width = rmsbuf->image_width; - height = rmsbuf->image_height; - buffer_index = aidev->curr_idxbuf.airms_st.inbuf_idx; - dma_addr = aidev->rms_inbuf[buffer_index].dma_addr; - break; - case ALLZERO_SIGMA: - width = rmsbuf->sigma_width; - height = rmsbuf->sigma_height; - dma_addr = aidev->sigma_buf.dma_addr; - sig_width = width; + if (aidev->is_parthdl) { + width = part_rmsbuf->image_width; + height = part_rmsbuf->image_height; + buffer_index = aidev->curr_idxbuf.airms_st.inbuf_idx; + dma_addr = aidev->rms_inbuf[buffer_index].dma_addr; + if (aidev->parthdl_idx == 1) + dma_addr += aidev->parthdl_image_oft * 2; + stride = rmsbuf->image_width; + } else { + width = rmsbuf->image_width; + height = rmsbuf->image_height; + buffer_index = aidev->curr_idxbuf.airms_st.inbuf_idx; + dma_addr = aidev->rms_inbuf[buffer_index].dma_addr; + } break; case ALLZERO_NARMAP: - width = rmsbuf->narmap_width; - height = rmsbuf->narmap_height; + if (aidev->is_parthdl) { + width = part_rmsbuf->narmap_width; + height = part_rmsbuf->narmap_height; + } else { + width = rmsbuf->narmap_width; + height = rmsbuf->narmap_height; + } dma_addr = aidev->narmap_buf.dma_addr; break; case ISP_FINAL_Y: @@ -1261,6 +1315,28 @@ static u32 rkaiisp_config_rdchannel(struct rkaiisp_device *aidev, buffer_index = aidev->curr_idxbuf.aibnr_st.y_src_index; dma_addr = aidev->ynrinbuf[buffer_index].dma_addr; break; + case VICAP_BAYER_RAW_DOWN: + if (aidev->is_parthdl) { + width = rmsbuf->image_width; + height = rmsbuf->image_height; + buffer_index = aidev->curr_idxbuf.airms_st.inbuf_idx; + dma_addr = aidev->rms_inbuf[buffer_index].dma_addr + width * height * 2; + if (aidev->parthdl_idx == 1) + dma_addr += aidev->parthdl_image_oft / 2; + width = CEIL_BY(CEIL_DOWN(part_rmsbuf->image_width, 2), 2); + height = CEIL_BY(CEIL_DOWN(part_rmsbuf->image_height, 2), 2); + sig_width = width; + stride = CEIL_BY(CEIL_DOWN(rmsbuf->image_width, 2), 2); + } else { + width = rmsbuf->image_width; + height = rmsbuf->image_height; + buffer_index = aidev->curr_idxbuf.airms_st.inbuf_idx; + dma_addr = aidev->rms_inbuf[buffer_index].dma_addr + width * height * 2; + width = CEIL_BY(CEIL_DOWN(rmsbuf->image_width, 2), 2); + height = CEIL_BY(CEIL_DOWN(rmsbuf->image_height, 2), 2); + sig_width = width; + } + break; default: width = 0; height = 0; @@ -1271,7 +1347,7 @@ static u32 rkaiisp_config_rdchannel(struct rkaiisp_device *aidev, if (width > 0) { aidev->chn_size[i].width = width; aidev->chn_size[i].height = height; - aidev->chn_size[i].stride = stride; + aidev->chn_size[i].stride = stride > 0 ? stride : width; rkaiisp_write(aidev, AIISP_MI_RD_CH0_BASE + 0x100 * i, dma_addr, false); rkaiisp_write(aidev, AIISP_MI_RD_CH0_HEIGHT + 0x100 * i, height, false); @@ -1289,6 +1365,7 @@ static u32 rkaiisp_config_rdchannel(struct rkaiisp_device *aidev, static void rkaiisp_run_cfg(struct rkaiisp_device *aidev, u32 run_idx) { struct rkaiisp_ispbuf_info *ispbuf = &aidev->ispbuf; + struct rkaiisp_rmsbuf_info *rmsbuf = &aidev->rmsbuf; struct rkaiisp_params *cur_params; struct rkaiisp_model_cfg *model_cfg; int lastlv, lv_mode, out_chns, i; @@ -1310,6 +1387,7 @@ static void rkaiisp_run_cfg(struct rkaiisp_device *aidev, u32 run_idx) "run frame id: %d, run_idx: %d, model_mode %d\n", sequence, run_idx, aidev->model_mode); + aidev->is_state_err = false; cur_params = (struct rkaiisp_params *)aidev->cur_params->vaddr[0]; model_cfg = &cur_params->model_cfg[run_idx]; @@ -1351,10 +1429,17 @@ static void rkaiisp_run_cfg(struct rkaiisp_device *aidev, u32 run_idx) sig_width = rkaiisp_config_rdchannel(aidev, model_cfg, run_idx); dma_addr = aidev->rms_outbuf[aidev->curr_idxbuf.airms_st.outbuf_idx].dma_addr; + if (aidev->parthdl_idx == 1) + dma_addr += 2 * (CEIL_BY(rmsbuf->image_width, 2) / 2 + RKAIISP_AIRMS_EXTEND_PIXEL); rkaiisp_write(aidev, AIISP_MI_CHN0_WR_BASE, dma_addr, false); rkaiisp_gen_slice_param(aidev, model_cfg, sig_width); rkaiisp_determine_size(aidev, model_cfg); + + iir_stride = CEIL_BY(rmsbuf->image_width, 2); + if (aidev->is_parthdl) + iir_stride += 2 * RKAIISP_AIRMS_EXTEND_PIXEL; + rkaiisp_write(aidev, AIISP_MI_CHN0_WR_STRIDE, iir_stride / 2, false); } else if (aidev->model_mode == SINGLEX2_MODE) { if (run_idx == 0) { sig_width = rkaiisp_config_rdchannel(aidev, model_cfg, run_idx); @@ -1462,7 +1547,8 @@ static void rkaiisp_run_cfg(struct rkaiisp_device *aidev, u32 run_idx) rkaiisp_write(aidev, AIISP_CORE_LEVEL_CTRL0 + i * 4, val, false); } - if ((out_chns == 4 && model_cfg->sw_out_d2s_en == 0)) + if (out_chns == 4 && + model_cfg->sw_out_d2s_en == (model_cfg->sw_out_mode == AIISP_OUT_MODE_BYPASS)) sw_lastlv_bypass = 1; if (model_cfg->sw_aiisp_mode == 0 && model_cfg->sw_out_mode == AIISP_OUT_MODE_DIFF_MERGE) sw_m0_diff_merge = 1; @@ -1509,16 +1595,25 @@ static void rkaiisp_run_start(struct rkaiisp_device *aidev) { struct rkaiisp_hw_dev *hw_dev = aidev->hw_dev; + if (aidev->is_state_err) { + v4l2_err(&aidev->v4l2_dev, + "aiisp status is error!\n"); + rkaiisp_dump_list_reg(aidev); + return; + } + rkaiisp_write(aidev, AIISP_MI_IMSC, AIISP_MI_ISR_ALL, false); rkaiisp_write(aidev, AIISP_MI_WR_INIT, AIISP_MI_CHN0SELF_FORCE_UPD, false); - if ((aidev->run_idx == 0) && (rkaiisp_showreg != 0)) + if ((aidev->run_idx == 0) && (aidev->parthdl_idx == 0) && (rkaiisp_showreg != 0)) aidev->showreg = true; if (aidev->showreg) rkaiisp_dump_list_reg(aidev); - if ((aidev->run_idx == aidev->model_runcnt - 1) && aidev->showreg) { + if ((aidev->run_idx + 1 == aidev->model_runcnt) && + (aidev->parthdl_idx + 1 == aidev->parthdl_num) && + aidev->showreg) { aidev->showreg = false; rkaiisp_showreg = 0; } @@ -1593,6 +1688,7 @@ void rkaiisp_trigger(struct rkaiisp_device *aidev) if (!rkaiisp_update_buf(aidev)) { aidev->run_idx = 0; + aidev->parthdl_idx = 0; aidev->frame_id = sequence; aidev->pre_frm_st = aidev->frm_st; aidev->frm_st = ktime_get_ns(); @@ -1643,8 +1739,9 @@ enum rkaiisp_irqhdl_ret rkaiisp_irq_hdl(struct rkaiisp_device *aidev, u32 mi_mis u64 frm_hdntim = 0; v4l2_dbg(1, rkaiisp_debug, &aidev->v4l2_dev, - "irq val: 0x%x, run_idx %d, model_runcnt %d\n", - mi_mis, aidev->run_idx, aidev->model_runcnt); + "irq val: 0x%x, run_idx %d, model_runcnt %d, parthdl %d, %d\n", + mi_mis, aidev->run_idx, aidev->model_runcnt, + aidev->parthdl_idx, aidev->parthdl_num); if (mi_mis & AIISP_MI_ISR_BUSERR) { v4l2_err(&aidev->v4l2_dev, "buserr 0x%x\n", mi_mis); @@ -1657,11 +1754,17 @@ enum rkaiisp_irqhdl_ret rkaiisp_irq_hdl(struct rkaiisp_device *aidev, u32 mi_mis rkaiisp_write(aidev, AIISP_MI_ICR, AIISP_MI_ISR_WREND, true); aidev->isr_wrend_cnt++; - if (aidev->run_idx < aidev->model_runcnt - 1) { + if (aidev->run_idx + 1 < aidev->model_runcnt) { aidev->run_idx++; rkaiisp_run_cfg(aidev, aidev->run_idx); rkaiisp_run_start(aidev); return CONTINUE_RUN; + } else if (aidev->is_parthdl && (aidev->parthdl_idx + 1 < aidev->parthdl_num)) { + aidev->parthdl_idx++; + aidev->run_idx = 0; + rkaiisp_run_cfg(aidev, aidev->run_idx); + rkaiisp_run_start(aidev); + return CONTINUE_RUN; } aidev->frm_ed = ktime_get_ns(); diff --git a/drivers/media/platform/rockchip/aiisp/aiisp.h b/drivers/media/platform/rockchip/aiisp/aiisp.h index b45ea78bf38f..7ee816c91a6c 100644 --- a/drivers/media/platform/rockchip/aiisp/aiisp.h +++ b/drivers/media/platform/rockchip/aiisp/aiisp.h @@ -37,6 +37,8 @@ #define RKAIISP_SW_REG_SIZE 0x3000 #define RKAIISP_SW_MAX_SIZE (RKAIISP_SW_REG_SIZE * 2) #define RKAIISP_AIRMS_BUF_MAXCNT 8 +#define RKAIISP_AIRMS_MAX_WIDTH 4096 +#define RKAIISP_AIRMS_EXTEND_PIXEL 16 #define RKAIISP_MIN(a, b) ((a) < (b) ? (a) : (b)) enum rkaiisp_irqhdl_ret { @@ -121,10 +123,11 @@ struct rkaiisp_device { struct rkaiisp_dummy_buffer *lastout_buf[RKAIISP_LASTOUT_BUF_CNT]; u32 outbuf_idx; + bool is_parthdl; struct rkaiisp_rmsbuf_info rmsbuf; + struct rkaiisp_rmsbuf_info part_rmsbuf; struct rkaiisp_dummy_buffer rms_inbuf[RKAIISP_AIRMS_BUF_MAXCNT]; struct rkaiisp_dummy_buffer rms_outbuf[RKAIISP_AIRMS_BUF_MAXCNT]; - struct rkaiisp_dummy_buffer sigma_buf; struct rkaiisp_dummy_buffer narmap_buf; struct aiisp_aiynr_ybuf_cfg ynr_ybuf_cfg; @@ -150,6 +153,10 @@ struct rkaiisp_device { u32 run_idx; u32 frame_id; + u32 parthdl_idx; + u32 parthdl_num; + u32 parthdl_image_oft; + u64 pre_frm_st; u64 frm_st; u64 frm_ed; @@ -161,6 +168,7 @@ struct rkaiisp_device { bool streamon; bool showreg; bool init_buf; + bool is_state_err; }; extern int rkaiisp_debug; diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 4da7b20ffd6d..5659bed0cb48 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1968,8 +1968,9 @@ static void rkcif_rdbk_with_tools(struct rkcif_stream *stream, unsigned long flags; spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags); - if (stream->tools_vdev->state == RKCIF_STATE_STREAMING) { - list_add_tail(&active_buf->list, &stream->tools_vdev->buf_done_head); + if (stream->tools_vdev->state == RKCIF_STATE_STREAMING && active_buf) { + list_add_tail(&active_buf->list_tool, &stream->tools_vdev->buf_done_head); + active_buf->use_cnt = 2; if (!work_busy(&stream->tools_vdev->work)) schedule_work(&stream->tools_vdev->work); } @@ -4763,9 +4764,9 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, return 0; } + val = rkcif_read_register(dev, CIF_REG_GLB_CTRL); if (stream->sw_dbg_en) { - rkcif_write_register_and(dev, CIF_REG_GLB_CTRL, - ~(u32)BIT(16)); + val &= ~BIT(16); v4l2_subdev_call(dev->active_sensor->sd, core, ioctl, RKCIF_CMD_SET_PPI_DATA_DEBUG, @@ -4776,18 +4777,23 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, RKCIF_CMD_SET_PPI_DATA_DEBUG, &stream->sw_dbg_en); } - if (dev->chip_id == CHIP_RK3588_CIF || dev->chip_id == CHIP_RV1106_CIF || dev->chip_id == CHIP_RK3562_CIF) { - val = GLB_RESET_IDI_EN_RK3588; + val |= GLB_RESET_IDI_EN_RK3588; } else if (dev->chip_id == CHIP_RK3576_CIF) { - val = GLB_RESET_IDI_EN_RK3576; + val |= GLB_RESET_IDI_EN_RK3576; val |= rkcif_get_split_dphy_mask_rk3576(dev); } else if (dev->chip_id == CHIP_RV1103B_CIF) { - val = rkcif_get_split_dphy_mask_rv1103b(dev); + val |= rkcif_get_split_dphy_mask_rv1103b(dev); } - rkcif_write_register_or(dev, CIF_REG_GLB_CTRL, val); + if (dev->chip_id == CHIP_RV1103B_CIF) { + if (rkcif_frm_toisp_protect) + val &= ~BIT(28); + else + val |= BIT(28); + } + rkcif_write_register(dev, CIF_REG_GLB_CTRL, val); if (dev->terminal_sensor.hdmi_input_en) { if (dev->chip_id == CHIP_RK3562_CIF || @@ -5075,8 +5081,13 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, CSI_DISABLE_CAPTURE); return 0; } - val = rkcif_get_split_mask_rv1126b(dev); - rkcif_write_register_or(dev, CIF_REG_GLB_CTRL, val); + val = rkcif_read_register(dev, CIF_REG_GLB_CTRL); + val |= rkcif_get_split_mask_rv1126b(dev); + if (rkcif_frm_toisp_protect) + val &= ~BIT(28); + else + val |= BIT(28); + rkcif_write_register(dev, CIF_REG_GLB_CTRL, val); rkcif_write_register_and(dev, CIF_REG_MIPI_LVDS_INTSTAT, ~(CSI_START_INTSTAT(channel->id) | CSI_DMA_END_INTSTAT(channel->id) | @@ -6956,6 +6967,7 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, kfifo_free(&stream->dcg_kfifo); } + stream->crop_enable = false; stream->crop_mask = 0; stream->frame_loss = 0; stream->is_fb_first_frame = true; @@ -9778,6 +9790,7 @@ int rkcif_quick_stream_on(struct rkcif_device *dev, bool is_intr) if (dev->sditf[0]->mode.rdbk_mode < RKISP_VICAP_RDBK_AIQ) { for (i = 0; i < stream_num; i++) { stream = &dev->stream[i]; + stream->is_pause_stream = false; if (stream->cifdev->hdr.hdr_mode == NO_HDR || (stream->cifdev->hdr.hdr_mode == HDR_X2 && stream->id == 1) || (stream->cifdev->hdr.hdr_mode == HDR_X3 && stream->id == 2)) { @@ -9807,6 +9820,7 @@ int rkcif_quick_stream_on(struct rkcif_device *dev, bool is_intr) RKISP_VICAP_CMD_MODE, &dev->sditf[0]->mode); } for (i = 0; i < stream_num; i++) { + dev->stream[i].is_pause_stream = false; if (dev->sditf[0]->mode.rdbk_mode != RKISP_VICAP_RDBK_AIQ) dev->stream[i].to_en_dma = RKCIF_DMAEN_BY_ISP; else @@ -11086,7 +11100,8 @@ static bool rkcif_is_csi2_err_trigger_reset(struct rkcif_timer *timer) * or fs and fe had been not paired. */ if (stream->is_fs_fe_not_paired || - stream->fs_cnt_in_single_frame > RKCIF_FS_DETECTED_NUM) { + (stream->fs_cnt_in_single_frame > RKCIF_FS_DETECTED_NUM && + dev->chip_id < CHIP_RK3588_CIF)) { is_triggered = true; v4l2_info(&dev->v4l2_dev, "reset for fs & fe not paired\n"); } @@ -13968,9 +13983,6 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) RKISP_VICAP_CMD_SOF, &sof); } - if (cif_dev->chip_id < CHIP_RK3588_CIF) - detect_stream->fs_cnt_in_single_frame++; - if (cif_dev->sditf[0] && cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ && (!detect_stream->dma_en) && cif_dev->chip_id < CHIP_RK3576_CIF) diff --git a/drivers/media/platform/rockchip/cif/cif-tools.c b/drivers/media/platform/rockchip/cif/cif-tools.c index f46c744489d6..78e92678036d 100644 --- a/drivers/media/platform/rockchip/cif/cif-tools.c +++ b/drivers/media/platform/rockchip/cif/cif-tools.c @@ -474,6 +474,7 @@ static void rkcif_tools_vb2_stop_streaming(struct vb2_queue *vq) struct rkcif_device *dev = tools_vdev->cifdev; struct rkcif_buffer *buf = NULL; struct rkcif_tools_buffer *tools_buf; + struct rkcif_rx_buffer *rx_buf = NULL; int ret = 0; mutex_lock(&dev->tools_lock); @@ -485,6 +486,12 @@ static void rkcif_tools_vb2_stop_streaming(struct vb2_queue *vq) if (!ret) { rkcif_tools_stop(tools_vdev); tools_vdev->stopping = false; + while (!list_empty(&tools_vdev->buf_done_head)) { + rx_buf = list_first_entry(&tools_vdev->buf_done_head, + struct rkcif_rx_buffer, list_tool); + list_del(&rx_buf->list_tool); + v4l2_subdev_call(&dev->sditf[0]->sd, video, s_rx_buffer, &rx_buf->dbufs, NULL); + } } /* release buffers */ if (tools_vdev->curr_buf) @@ -710,9 +717,9 @@ retry_done_rdbk_buf: spin_lock_irqsave(&tools_vdev->vbq_lock, flags); if (!list_empty(&tools_vdev->buf_done_head)) { buf = list_first_entry(&tools_vdev->buf_done_head, - struct rkcif_rx_buffer, list); + struct rkcif_rx_buffer, list_tool); if (buf) - list_del(&buf->list); + list_del(&buf->list_tool); } spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); if (!buf) { @@ -724,12 +731,14 @@ retry_done_rdbk_buf: if (tools_vdev->stopping) { rkcif_tools_stop(tools_vdev); tools_vdev->stopping = false; + if (buf) + v4l2_subdev_call(&dev->sditf[0]->sd, video, s_rx_buffer, &buf->dbufs, NULL); spin_lock_irqsave(&tools_vdev->vbq_lock, flags); while (!list_empty(&tools_vdev->buf_done_head)) { buf = list_first_entry(&tools_vdev->buf_done_head, - struct rkcif_rx_buffer, list); - if (buf) - list_del(&buf->list); + struct rkcif_rx_buffer, list_tool); + list_del(&buf->list_tool); + v4l2_subdev_call(&dev->sditf[0]->sd, video, s_rx_buffer, &buf->dbufs, NULL); } spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); wake_up(&tools_vdev->wq_stopped); @@ -742,9 +751,13 @@ retry_done_rdbk_buf: if (!tools_vdev->curr_buf || tools_vdev->state != RKCIF_STATE_STREAMING) { spin_lock_irqsave(&tools_vdev->vbq_lock, flags); if (!list_empty(&tools_vdev->buf_done_head)) { + if (buf) + v4l2_subdev_call(&dev->sditf[0]->sd, video, s_rx_buffer, &buf->dbufs, NULL); spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); goto retry_done_rdbk_buf; } + if (buf) + v4l2_subdev_call(&dev->sditf[0]->sd, video, s_rx_buffer, &buf->dbufs, NULL); spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); return; } @@ -765,10 +778,14 @@ retry_done_rdbk_buf: payload_size); memcpy(dst, src, payload_size); } + v4l2_subdev_call(&dev->sditf[0]->sd, video, s_rx_buffer, &buf->dbufs, NULL); tools_vdev->curr_buf->vb.sequence = buf->dbufs.sequence; tools_vdev->curr_buf->vb.vb2_buf.timestamp = buf->dbufs.timestamp; vb2_buffer_done(&tools_vdev->curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); tools_vdev->curr_buf = NULL; + } else { + if (buf) + v4l2_subdev_call(&dev->sditf[0]->sd, video, s_rx_buffer, &buf->dbufs, NULL); } spin_lock_irqsave(&tools_vdev->vbq_lock, flags); diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 69c3b214460a..9a127897d9e6 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -36,6 +36,10 @@ int rkcif_debug; module_param_named(debug, rkcif_debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); +bool rkcif_frm_toisp_protect = true; +module_param_named(toisp_protect, rkcif_frm_toisp_protect, bool, 0644); +MODULE_PARM_DESC(toisp_protect, "frame protect of toisp"); + static char rkcif_version[RKCIF_VERNO_LEN]; module_param_string(version, rkcif_version, RKCIF_VERNO_LEN, 0444); MODULE_PARM_DESC(version, "version number"); diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index ad4b059e51dd..ca6e0983b186 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -232,6 +232,7 @@ struct rkcif_tools_buffer { }; extern int rkcif_debug; +extern bool rkcif_frm_toisp_protect; /* * struct rkcif_sensor_info - Sensor infomations @@ -478,12 +479,14 @@ enum rkcif_capture_mode { struct rkcif_rx_buffer { int buf_idx; struct list_head list; + struct list_head list_tool; struct list_head list_free; struct rkisp_rx_buf dbufs; struct rkcif_dummy_buffer dummy; struct rkisp_thunderboot_shmem shmem; u64 fe_timestamp; bool is_init[RKCIF_MAX_DEV]; + int use_cnt; }; enum rkcif_dma_en_mode { diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index bc74726c94c1..8258dfd669a2 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -282,6 +282,8 @@ static int csi2_start(struct csi2_dev *csi2) else host_type = RK_CSI_RXHOST; + csi2->irq1_timestamp = 0; + csi2->irq2_timestamp = 0; for (i = 0; i < csi2->csi_info.csi_num; i++) { csi_idx = csi2->csi_info.csi_idx[i]; ret |= csi2_hw_start(csi2->csi2_hw[csi_idx], host_type); @@ -840,6 +842,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) char cur_str[CSI_ERRSTR_LEN] = {0}; char vc_info[CSI_VCINFO_LEN] = {0}; bool is_add_cnt = false; + u64 cur_timestamp = ktime_get_ns(); if (!csi2_hw) { disable_irq_nosync(irq); @@ -912,7 +915,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) } if (val & CSIHOST_ERR1_ERR_ECC2) { - err_list = &csi2->err_list[RK_CSI2_ERR_CRC]; + err_list = &csi2->err_list[RK_CSI2_ERR_ECC2]; err_list->cnt++; is_add_cnt = true; snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc2) "); @@ -920,12 +923,17 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) } if (val & CSIHOST_ERR1_ERR_CTRL) { + err_list = &csi2->err_list[RK_CSI2_ERR_CTRL]; + err_list->cnt++; csi2_find_err_vc((val >> 16) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(ctrl,vc:%s) ", vc_info); csi2_err_strncat(err_str, cur_str); } - pr_err("(0x%x)MIPI_CSI2 ERR1:0x%x %s\n", (u32)csi2_hw->res->start, val, err_str); + if (csi2->irq1_timestamp == 0 || cur_timestamp - csi2->irq1_timestamp > 1000000000) { + csi2->irq1_timestamp = cur_timestamp; + pr_err("(0x%x)MIPI_CSI2 ERR1:0x%x %s\n", (u32)csi2_hw->res->start, val, err_str); + } if (is_add_cnt) { csi2->err_list[RK_CSI2_ERR_ALL].cnt++; @@ -946,16 +954,24 @@ static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) { struct device *dev = ctx; struct csi2_hw *csi2_hw = dev_get_drvdata(dev); + struct csi2_dev *csi2 = NULL; u32 val; char cur_str[CSI_ERRSTR_LEN] = {0}; char err_str[CSI_ERRSTR_LEN] = {0}; char vc_info[CSI_VCINFO_LEN] = {0}; + u64 cur_timestamp = ktime_get_ns(); if (!csi2_hw) { disable_irq_nosync(irq); return IRQ_HANDLED; } + csi2 = csi2_hw->csi2; + if (!csi2) { + disable_irq_nosync(irq); + return IRQ_HANDLED; + } + val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR2); if (val) { if (val & CSIHOST_ERR2_PHYERR_ESC) { @@ -983,7 +999,10 @@ static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) csi2_err_strncat(err_str, cur_str); } - pr_err("(0x%x)MIPI_CSI2 ERR2:0x%x %s\n", (u32)csi2_hw->res->start, val, err_str); + if (csi2->irq2_timestamp == 0 || cur_timestamp - csi2->irq2_timestamp > 1000000000) { + csi2->irq2_timestamp = cur_timestamp; + pr_err("(0x%x)MIPI_CSI2 ERR2:0x%x %s\n", (u32)csi2_hw->res->start, val, err_str); + } } return IRQ_HANDLED; diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index 026b48ff552f..93c4bc3fbc9b 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -113,6 +113,8 @@ enum csi2_err { RK_CSI2_ERR_FRM_SEQ_ERR, RK_CSI2_ERR_CRC_ONCE, RK_CSI2_ERR_CRC, + RK_CSI2_ERR_ECC2, + RK_CSI2_ERR_CTRL, RK_CSI2_ERR_ALL, RK_CSI2_ERR_MAX }; @@ -176,6 +178,8 @@ struct csi2_dev { struct rkcif_csi_info csi_info; const char *dev_name; int sw_dbg; + u64 irq1_timestamp; + u64 irq2_timestamp; }; struct csi2_hw { diff --git a/drivers/media/platform/rockchip/cif/procfs.c b/drivers/media/platform/rockchip/cif/procfs.c index 1956020b1f75..6122ab4ff2c8 100644 --- a/drivers/media/platform/rockchip/cif/procfs.c +++ b/drivers/media/platform/rockchip/cif/procfs.c @@ -526,6 +526,27 @@ static void rkcif_show_reg_dbg(struct rkcif_device *dev, struct seq_file *f) } } +static void rkcif_show_mipi_csi2_error_info(struct rkcif_device *dev, struct seq_file *f) +{ + struct csi2_dev *csi2 = container_of(dev->active_sensor->sd, struct csi2_dev, sd); + + seq_puts(f, "\nMipi error info:\n"); + seq_printf(f, "\terr sot sync:%u\n", + csi2->err_list[RK_CSI2_ERR_SOTSYN].cnt); + seq_printf(f, "\terr fs/fe not match:%u\n", + csi2->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt); + seq_printf(f, "\terr frm seq:%u\n", + csi2->err_list[RK_CSI2_ERR_FRM_SEQ_ERR].cnt); + seq_printf(f, "\terr crc once:%u\n", + csi2->err_list[RK_CSI2_ERR_CRC_ONCE].cnt); + seq_printf(f, "\terr crc:%u\n", + csi2->err_list[RK_CSI2_ERR_CRC].cnt); + seq_printf(f, "\terr ecc2:%u\n", + csi2->err_list[RK_CSI2_ERR_ECC2].cnt); + seq_printf(f, "\terr ctrl:%u\n", + csi2->err_list[RK_CSI2_ERR_CTRL].cnt); +} + static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) { struct rkcif_stream *stream = &dev->stream[0]; @@ -676,6 +697,9 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) rkcif_show_toisp_info(dev, f); if (dev->reg_dbg) rkcif_show_reg_dbg(dev, f); + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) + rkcif_show_mipi_csi2_error_info(dev, f); } } diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index bdd562341540..73f8b4376bc9 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -1345,6 +1345,26 @@ static int sditf_s_power(struct v4l2_subdev *sd, int on) return ret; } +static int sditf_check_toolbuf_return(struct rkcif_stream *stream, struct rkcif_rx_buffer *rx_buf) +{ + struct rkcif_tools_vdev *tools_vdev = stream->tools_vdev; + unsigned long flags; + + if (tools_vdev) { + spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags); + + if (rx_buf->use_cnt) + rx_buf->use_cnt--; + if (rx_buf->use_cnt) { + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); + return false; + } + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); + } + + return true; +} + static int sditf_s_rx_buffer(struct v4l2_subdev *sd, void *buf, unsigned int *size) { @@ -1422,7 +1442,8 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, is_free = true; } - if (!is_free && (!dbufs->is_switch) && stream->state == RKCIF_STATE_STREAMING) { + if (!is_free && (!dbufs->is_switch) && stream->state == RKCIF_STATE_STREAMING && + sditf_check_toolbuf_return(stream, rx_buf)) { list_add_tail(&rx_buf->list, &buf_stream->rx_buf_head); rkcif_assign_check_buffer_update_toisp(stream); if (cif_dev->resume_mode != RKISP_RTT_MODE_ONE_FRAME && diff --git a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c index c0e48799014a..afff5b3addb3 100644 --- a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c +++ b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c @@ -2485,6 +2485,8 @@ static long hdmirx_ioctl_default(struct file *file, void *fh, { struct hdmirx_stream *stream = video_drvdata(file); struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; + struct v4l2_dv_timings timings = hdmirx_dev->timings; + struct v4l2_bt_timings *bt = &timings.bt; long ret = 0; bool hpd; enum mute_type type; @@ -2497,6 +2499,14 @@ static long hdmirx_ioctl_default(struct file *file, void *fh, case RK_HDMIRX_CMD_GET_FPS: *(int *)arg = hdmirx_dev->get_timing ? hdmirx_dev->fps : 0; break; + case RK_HDMIRX_CMD_GET_SCAN_MODE: + if (!hdmirx_dev->get_timing) + *(int *)arg = HDMIRX_PROGRESSIVE; + else if (bt->interlaced == V4L2_DV_INTERLACED) + *(int *)arg = HDMIRX_INTERLACED; + else + *(int *)arg = HDMIRX_PROGRESSIVE; + break; case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: *(int *)arg = hdmirx_dev->get_timing; break; diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c index 895d0d8fe849..9bbf7f5d1a3b 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c @@ -590,7 +590,7 @@ static int csi2_dphy_enable_clk(struct csi2_dphy *dphy) if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; if (samsung_phy) - clk_prepare_enable(samsung_phy->pclk); + pm_runtime_get_sync(samsung_phy->dev); } else { hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; if (hw) { @@ -615,7 +615,7 @@ static void csi2_dphy_disable_clk(struct csi2_dphy *dphy) if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; if (samsung_phy) - clk_disable_unprepare(samsung_phy->pclk); + pm_runtime_put(samsung_phy->dev); } else { hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; if (hw) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c index cc90acdc0726..ff42a0464342 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c @@ -1781,25 +1781,8 @@ static int samsung_mipi_dcphy_power_on(struct phy *phy) { struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy); enum phy_mode mode = phy_get_mode(phy); - int on = 0; - struct v4l2_subdev *sensor_sd = NULL; pm_runtime_get_sync(samsung->dev); - reset_control_assert(samsung->apb_rst); - udelay(1); - reset_control_deassert(samsung->apb_rst); - if (atomic_read(&samsung->stream_cnt) && samsung->dphy_dev[0]) { - sensor_sd = get_remote_sensor(&samsung->dphy_dev[0]->sd); - samsung->stream_off(samsung->dphy_dev[0], &samsung->dphy_dev[0]->sd); - if (sensor_sd) - v4l2_subdev_call(sensor_sd, core, ioctl, - RKMODULE_SET_QUICK_STREAM, &on); - samsung->stream_on(samsung->dphy_dev[0], &samsung->dphy_dev[0]->sd); - on = 1; - if (sensor_sd) - v4l2_subdev_call(sensor_sd, core, ioctl, - RKMODULE_SET_QUICK_STREAM, &on); - } switch (mode) { case PHY_MODE_MIPI_DPHY: @@ -2492,6 +2475,22 @@ static int samsung_mipi_dcphy_remove(struct platform_device *pdev) return 0; } +static __maybe_unused int samsung_mipi_dcphy_suspend(struct device *dev) +{ + return 0; +} + +static __maybe_unused int samsung_mipi_dcphy_resume(struct device *dev) +{ + struct samsung_mipi_dcphy *samsung = dev_get_drvdata(dev); + + reset_control_assert(samsung->apb_rst); + udelay(1); + reset_control_deassert(samsung->apb_rst); + + return 0; +} + static __maybe_unused int samsung_mipi_dcphy_runtime_suspend(struct device *dev) { struct samsung_mipi_dcphy *samsung = dev_get_drvdata(dev); @@ -2513,6 +2512,8 @@ static __maybe_unused int samsung_mipi_dcphy_runtime_resume(struct device *dev) } static const struct dev_pm_ops samsung_mipi_dcphy_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(samsung_mipi_dcphy_suspend, + samsung_mipi_dcphy_resume) SET_RUNTIME_PM_OPS(samsung_mipi_dcphy_runtime_suspend, samsung_mipi_dcphy_runtime_resume, NULL) }; diff --git a/drivers/power/supply/rockchip_charger_manager.c b/drivers/power/supply/rockchip_charger_manager.c index f7b1a4ef8c6c..5fd2e0f5ffd2 100644 --- a/drivers/power/supply/rockchip_charger_manager.c +++ b/drivers/power/supply/rockchip_charger_manager.c @@ -2409,7 +2409,7 @@ static int cm_normal_adapter_det(struct charger_manager *cm) fc_config = cm->fc_config; fc_config->adaper_power_init_flag = 0; - cm->is_normal_charge = false; + cm->is_normal_charge = true; cm->is_fast_charge = false; cm->is_pps_charge = false; @@ -2561,6 +2561,15 @@ static int charger_extcon_notifier(struct notifier_block *self, return ret; } switch (val.intval) { + case POWER_SUPPLY_USB_TYPE_PD_PPS: + if ((!cm->is_pps_charge) && (desc->psy_charger_pump_stat)) { + ret = cm_pps_adapter_det(cm); + if (ret) + return NOTIFY_BAD; + CM_DBG("USB-TYPE: POWER_SUPPLY_USB_TYPE_PD\n"); + break; + } + fallthrough; case POWER_SUPPLY_USB_TYPE_PD: if (!cm->is_pps_charge && !cm->is_pd_charge) { ret = cm_pd_adapter_det(cm); @@ -2569,14 +2578,6 @@ static int charger_extcon_notifier(struct notifier_block *self, return NOTIFY_BAD; } break; - case POWER_SUPPLY_USB_TYPE_PD_PPS: - if (!cm->is_pps_charge) { - ret = cm_pps_adapter_det(cm); - if (ret) - return NOTIFY_BAD; - CM_DBG("USB-TYPE: POWER_SUPPLY_USB_TYPE_PD\n"); - } - break; default: if (!cm->is_pps_charge && !cm->is_pd_charge && !cm->is_normal_charge) { ret = cm_normal_adapter_det(cm); @@ -2586,7 +2587,8 @@ static int charger_extcon_notifier(struct notifier_block *self, break; } - if (val.intval != POWER_SUPPLY_USB_TYPE_PD_PPS) { + if ((val.intval != POWER_SUPPLY_USB_TYPE_PD_PPS) || + (!desc->psy_charger_pump_stat)) { if (cm->fc_config->jeita_charge_support) { cancel_delayed_work(&cm->cm_jeita_work); queue_delayed_work(cm->cm_wq, &cm->cm_jeita_work, 0); @@ -2631,9 +2633,11 @@ static void cm_pd_work(struct work_struct *work) switch (usb_type) { case POWER_SUPPLY_USB_TYPE_PD_PPS: CM_DBG("POWER_SUPPLY_USB_TYPE_PD_PPS\n"); - if (!cm->is_pps_charge) + if ((!cm->is_pps_charge) && (desc->psy_charger_pump_stat)) { cm_pps_adapter_det(cm); - break; + break; + } + fallthrough; case POWER_SUPPLY_USB_TYPE_PD: CM_DBG("POWER_SUPPLY_USB_TYPE_PD\n"); power_supply_get_property(desc->tcpm_psy, diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 98ecebb135ad..a3ae9a808e8e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -816,6 +816,16 @@ config SPI_ROCKCHIP_SLAVE SPI Slave controller. Rockchip SPI Slave controller support DMA transport and IRQ mode. +config SPI_ROCKCHIP_SLAVE_MISCDEV + bool "Rockchip SPI controller Slave misc devices" + depends on SPI_ROCKCHIP_SLAVE + help + This selects a misc driver for Rockchip SPI Slave controller. + + If you say yes to this option, It will register rkspi-slave-devN misc device + for each spi controller slave and support to get the controller register + resource by calling mmap. + config SPI_RB4XX tristate "Mikrotik RB4XX SPI master" depends on SPI_MASTER && ATH79 diff --git a/drivers/spi/spi-rockchip-slave.c b/drivers/spi/spi-rockchip-slave.c index 4ce660fc734c..cab98219196f 100644 --- a/drivers/spi/spi-rockchip-slave.c +++ b/drivers/spi/spi-rockchip-slave.c @@ -12,11 +12,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -161,16 +163,19 @@ enum rockchip_spi_slave_xfer_mode { }; struct rockchip_spi { + struct spi_controller *ctlr; struct device *dev; struct clk_bulk_data *clks; unsigned int clk_cnt; + struct dma_async_tx_descriptor *rx_cyclic_desc; void __iomem *regs; dma_addr_t dma_addr_rx; dma_addr_t dma_addr_tx; u32 *dma_buf; dma_addr_t dma_phys; + u32 dma_cyclic_period_count; const void *tx; void *rx; @@ -183,6 +188,7 @@ struct rockchip_spi { u32 version; /*depth of the FIFO buffer */ u32 fifo_len; + int transfer_size; int max_transfer_size; u32 fixed_burst_size; u8 tx_idle_type; /* 0-SR_TF_EMPTY 1-SR_SLAVE_TX_BUSY */ @@ -190,6 +196,7 @@ struct rockchip_spi { u8 n_bytes; u32 speed_hz; + u32 mode; bool slave_aborted; bool cs_inactive; /* spi slave tansmition stop when cs inactive */ @@ -198,6 +205,11 @@ struct rockchip_spi { enum rockchip_spi_slave_xfer_mode xfer_mode; bool ext_spi_clk; + /* misc */ + struct miscdevice miscdev; + struct mutex lock; + size_t write_pos; + size_t read_pos; bool verbose; ktime_t dbg_time; }; @@ -329,12 +341,17 @@ static irqreturn_t rockchip_spi_slave_isr(int irq, void *dev_id) } /* When int_cs_inactive comes, spi slave abort */ - if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE) { - - rs->slave_aborted = true; - writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); - writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); - complete(&rs->xfer_done); + if (rs->cs_inactive && + readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE) { + /* Means using dma cyclic now */ + if (rs->rx_cyclic_desc) { + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); + } else { + rs->slave_aborted = true; + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); + complete(&rs->xfer_done); + } } return IRQ_HANDLED; @@ -473,6 +490,46 @@ static int rockchip_spi_slave_prepare_dma(struct rockchip_spi *rs, return 1; } +static int rockchip_spi_slave_prepare_cyclic_dma(struct rockchip_spi *rs, + struct spi_controller *ctlr, + struct spi_transfer *xfer) +{ + struct dma_async_tx_descriptor *rxdesc = NULL; + + atomic_set(&rs->state, 0); + + if (xfer->rx_buf) { + struct dma_slave_config rxconf = { + .direction = DMA_DEV_TO_MEM, + .src_addr = rs->dma_addr_rx, + .src_addr_width = rs->n_bytes, + .src_maxburst = + rockchip_spi_slave_calc_burst_size(rs, xfer->len / rs->n_bytes), + }; + + dmaengine_slave_config(ctlr->dma_rx, &rxconf); + rxdesc = dmaengine_prep_dma_cyclic(ctlr->dma_rx, rs->dma_phys, xfer->len, + xfer->len > rs->dma_cyclic_period_count ? + xfer->len / rs->dma_cyclic_period_count : xfer->len, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + if (!rxdesc) + return -EINVAL; + + rxdesc->callback = NULL; + rxdesc->callback_param = ctlr; + } + + /* rx must be started before tx due to spi instinct */ + if (rxdesc) { + atomic_or(RXDMA, &rs->state); + ctlr->dma_rx->cookie = dmaengine_submit(rxdesc); + dma_async_issue_pending(ctlr->dma_rx); + rs->rx_cyclic_desc = rxdesc; + } + + return 0; +} + static bool rockchip_spi_slave_can_dma(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer) @@ -497,6 +554,7 @@ static int rockchip_spi_slave_config(struct rockchip_spi *rs, u32 cr1; u32 dmacr = 0; u32 val = 0; + u32 mode = 0; rs->slave_aborted = false; if (xfer->speed_hz) @@ -504,8 +562,12 @@ static int rockchip_spi_slave_config(struct rockchip_spi *rs, else rs->speed_hz = 100000; - cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; - if (spi->mode & SPI_LSB_FIRST) + if (spi) + mode = spi->mode; + else + mode = rs->ctlr->mode_bits; + cr0 |= (mode & 0x3U) << CR0_SCPH_OFFSET; + if (mode & SPI_LSB_FIRST) cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; if (xfer->rx_buf && xfer->tx_buf) { @@ -751,11 +813,211 @@ static int rockchip_spi_slave_setup(struct spi_device *spi) cr0 |= ((spi->mode & 0x3) << CR0_SCPH_OFFSET) | CR0_OPM_SLAVE << CR0_OPM_OFFSET; writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); + rs->mode = spi->mode; + pm_runtime_put(rs->dev); return 0; } +static int rockchip_spi_slave_misc_open(struct inode *inode, struct file *file) +{ + struct miscdevice *miscdev = file->private_data; + struct rockchip_spi *rs; + + rs = container_of(miscdev, struct rockchip_spi, miscdev); + file->private_data = rs; + + pm_runtime_get_sync(rs->dev); + + return 0; +} + +static int rockchip_spi_slave_misc_init_cyclic(struct rockchip_spi *rs, int length) +{ + struct spi_transfer *xfer; + int ret = 0; + u32 status; + + if (length > rs->max_transfer_size) { + dev_err(rs->dev, "Transfer is too long (%d)\n", length); + return -EINVAL; + } + + if (rs->cs_inactive) { + ret = readl_poll_timeout(rs->regs + ROCKCHIP_SPI_SR, status, + status & SR_SS_IN_N, 20, + ROCKCHIP_SPI_CLK_TO_CS_DEASSERT_US); + if (ret) { + dev_err(rs->dev, "The cs of spi master is still asserted\n"); + return -EIO; + } + } + + xfer = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL); + if (!xfer) + return -ENOMEM; + + xfer->rx_buf = rs->dma_buf; + xfer->tx_buf = NULL; + xfer->len = length; + xfer->bits_per_word = 8; + xfer->speed_hz = 1000000; + rs->n_bytes = xfer->bits_per_word <= 8 ? 1 : 2; + rs->xfer_mode = ROCKCHIP_SPI_DMA; + + ret = rockchip_spi_slave_config(rs, NULL, xfer); + if (ret) + goto free_spi_transfer; + + rockchip_spi_slave_prepare_cyclic_dma(rs, rs->ctlr, xfer); + + /* Record for check */ + rs->transfer_size = xfer->len; + + if (rs->cs_inactive) + writel_relaxed(INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR); + + spi_enable_chip(rs, true); + + if (rs->ready) { + gpiod_set_value(rs->ready, 0); + gpiod_set_value(rs->ready, 1); + } + +free_spi_transfer: + kfree(xfer); + + return ret; +} + +static int rockchip_spi_slave_misc_deinit_cyclic(struct rockchip_spi *rs) +{ + struct spi_controller *ctlr = rs->ctlr; + + if (rs->rx_cyclic_desc) { + dmaengine_terminate_async(ctlr->dma_rx); + dmaengine_desc_free(rs->rx_cyclic_desc); + rs->rx_cyclic_desc = NULL; + } + + rockchip_spi_slave_stop(ctlr); + + rs->read_pos = 0; + rs->write_pos = 0; + + return 0; +} + +static long rockchip_spi_slave_misc_ioctl(struct file *file, unsigned int cmd, + unsigned long args) +{ + struct rockchip_spi *rs = file->private_data; + int length = (int)args; + int ret = 0; + + mutex_lock(&rs->lock); + + switch (cmd) { + case SPI_SLAVE_INIT_CYCLIC: + ret = rockchip_spi_slave_misc_init_cyclic(rs, length); + if (ret) + dev_err(rs->dev, "DMA cyclic init failed: %d\n", ret); + break; + case SPI_SLAVE_DEINIT_CYCLIC: + ret = rockchip_spi_slave_misc_deinit_cyclic(rs); + if (ret) + dev_err(rs->dev, "DMA cyclic deinit failed: %d\n", ret); + break; + default: + break; + } + + mutex_unlock(&rs->lock); + + return 0; +} + +static ssize_t rockchip_spi_slave_misc_read(struct file *file, char __user *buf, + size_t n, loff_t *offset) +{ + struct rockchip_spi *rs = file->private_data; + struct spi_controller *ctlr = rs->ctlr; + size_t to_copy, copied = 0; + int ret = 0; + size_t period_size = n > rs->dma_cyclic_period_count ? + n / rs->dma_cyclic_period_count : n; + size_t cur_index; + struct dma_tx_state state; + size_t data_available; + + mutex_lock(&rs->lock); + + if (n + (size_t)(*offset) > rs->transfer_size) { + dev_err(rs->dev, "Exceed the expected length: %zu + %lld > %d\n", + n, *offset, rs->transfer_size); + ret = -EINVAL; + goto out; + } + + dmaengine_tx_status(ctlr->dma_rx, ctlr->dma_rx->cookie, &state); + + cur_index = (period_size - state.residue) % period_size; + if (cur_index < rs->read_pos) + data_available = period_size - rs->read_pos + cur_index; + else + data_available = cur_index - rs->read_pos; + + to_copy = min(n, data_available); + + if (rs->read_pos + to_copy > period_size) { + + if (copy_to_user(buf, rs->dma_buf + rs->read_pos, + period_size - rs->read_pos)) { + ret = -EFAULT; + goto out; + } + + if (copy_to_user(buf + period_size - rs->read_pos, rs->dma_buf, + to_copy - period_size + rs->read_pos)) { + ret = -EFAULT; + goto out; + } + } else { + if (copy_to_user(buf, rs->dma_buf + rs->read_pos, to_copy)) { + ret = -EFAULT; + goto out; + } + } + + rs->read_pos = (rs->read_pos + to_copy) % period_size; + copied = to_copy; + +out: + mutex_unlock(&rs->lock); + return copied ? copied : ret; +} + +static int rockchip_spi_slave_misc_release(struct inode *inode, struct file *file) +{ + struct rockchip_spi *rs = file->private_data; + + mutex_lock(&rs->lock); + rockchip_spi_slave_misc_deinit_cyclic(rs); + mutex_unlock(&rs->lock); + + pm_runtime_put(rs->dev); + + return 0; +} + +static const struct file_operations rockchip_spi_slave_misc_fops = { + .open = rockchip_spi_slave_misc_open, + .release = rockchip_spi_slave_misc_release, + .unlocked_ioctl = rockchip_spi_slave_misc_ioctl, + .read = rockchip_spi_slave_misc_read, +}; + static int rockchip_spi_slave_probe(struct platform_device *pdev) { int ret = 0; @@ -774,6 +1036,8 @@ static int rockchip_spi_slave_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctlr); rs = spi_controller_get_devdata(ctlr); + rs->ctlr = ctlr; + mutex_init(&rs->lock); /* Get basic io resource and map it */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -924,6 +1188,12 @@ static int rockchip_spi_slave_probe(struct platform_device *pdev) if (!device_property_read_bool(&pdev->dev, "rockchip,dma-support-req-mix")) rs->dma_timeout = 0; + if (!device_property_read_u32(&pdev->dev, "rockchip,dma-cyclic-period-count", &val)) + /* DMA cyclic period count can't be zero */ + rs->dma_cyclic_period_count = val ? val : 1; + else + rs->dma_cyclic_period_count = 1; + rs->ready = devm_gpiod_get_optional(&pdev->dev, "ready", GPIOD_OUT_HIGH); if (IS_ERR(rs->ready)) { ret = PTR_ERR(rs->ready); @@ -937,6 +1207,22 @@ static int rockchip_spi_slave_probe(struct platform_device *pdev) goto err_free_dma_rx; } + if (IS_ENABLED(CONFIG_SPI_ROCKCHIP_SLAVE_MISCDEV)) { + char misc_name[20]; + + snprintf(misc_name, sizeof(misc_name), "rkspi-slv-dev%d", ctlr->bus_num); + rs->miscdev.minor = MISC_DYNAMIC_MINOR; + rs->miscdev.name = misc_name; + rs->miscdev.fops = &rockchip_spi_slave_misc_fops; + rs->miscdev.parent = &pdev->dev; + + ret = misc_register(&rs->miscdev); + if (ret) + dev_err(&pdev->dev, "failed to register misc device %s\n", misc_name); + else + dev_info(&pdev->dev, "register misc device %s\n", misc_name); + } + dev_info(rs->dev, "slave probed, cs-inactive=%d, ready=%d, ext=%d, dam_buf=%x\n", rs->cs_inactive, rs->ready ? 1 : 0, rs->ext_spi_clk, (u32)rs->dma_phys); @@ -961,6 +1247,9 @@ static int rockchip_spi_slave_remove(struct platform_device *pdev) struct spi_controller *ctlr = spi_controller_get(platform_get_drvdata(pdev)); struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + if (IS_ENABLED(CONFIG_SPI_ROCKCHIP_SLAVE_MISCDEV)) + misc_deregister(&rs->miscdev); + pm_runtime_get_sync(&pdev->dev); clk_bulk_disable_unprepare(rs->clk_cnt, rs->clks); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 4a4c28083ba6..660c91ccb6dc 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1387,6 +1387,11 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0; } +static inline int dwc2_is_force_host_mode(struct dwc2_hsotg *hsotg) +{ + return (dwc2_readl(hsotg, GUSBCFG) & GUSBCFG_FORCEHOSTMODE) != 0; +} + int dwc2_drd_init(struct dwc2_hsotg *hsotg); void dwc2_drd_suspend(struct dwc2_hsotg *hsotg); void dwc2_drd_resume(struct dwc2_hsotg *hsotg); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 598a4e64205d..fdb989e1068e 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -796,7 +796,8 @@ static int __maybe_unused dwc2_resume(struct device *dev) dwc2_drd_resume(dwc2); } - if (dwc2->dr_mode == USB_DR_MODE_HOST && dwc2_is_device_mode(dwc2)) { + if (dwc2->dr_mode == USB_DR_MODE_HOST && (dwc2_is_device_mode(dwc2) || + !dwc2_is_force_host_mode(dwc2))) { /* Reinit for Host mode if lost power */ dwc2_force_mode(dwc2, true); diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index f93e5201c321..2927385d6a6e 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -328,6 +328,9 @@ static int dp_altmode_vdm(struct typec_altmode *alt, break; case CMDT_RSP_NAK: switch (cmd) { + case DP_CMD_STATUS_UPDATE: + dp->state = DP_STATE_EXIT; + break; case DP_CMD_CONFIGURE: dp->data.conf = 0; ret = dp_altmode_configured(dp); diff --git a/include/uapi/linux/rk-aiisp-config.h b/include/uapi/linux/rk-aiisp-config.h index 6453e62dcc3a..ebbbb8f0b09f 100644 --- a/include/uapi/linux/rk-aiisp-config.h +++ b/include/uapi/linux/rk-aiisp-config.h @@ -56,7 +56,8 @@ enum rkaiisp_chn_src { VICAP_BAYER_RAW, ALLZERO_SIGMA, ALLZERO_NARMAP, - ISP_FINAL_Y + ISP_FINAL_Y, + VICAP_BAYER_RAW_DOWN }; enum rkaiisp_exealgo { diff --git a/include/uapi/linux/spi/rk-spi-slave.h b/include/uapi/linux/spi/rk-spi-slave.h new file mode 100644 index 000000000000..9a46703a91cf --- /dev/null +++ b/include/uapi/linux/spi/rk-spi-slave.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef RK_SPI_SLAVE_H +#define RK_SPI_SLAVE_H + +#include + +#define SPI_SLAVE_BASE 's' +#define SPI_SLAVE_INIT_CYCLIC _IOW(SPI_SLAVE_BASE, 0, int) +#define SPI_SLAVE_DEINIT_CYCLIC _IOW(SPI_SLAVE_BASE, 1, int) + +#endif