diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index ddf8d644d719..67569ffc8dfa 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1134,6 +1134,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1106g-evb1-rgb-display-v11.dtb \ rv1106g-evb1-v10.dtb \ rv1106g-evb1-v11.dtb \ + rv1106g-evb1-v11-4k.dtb \ rv1106g-evb1-v11-cvr.dtb \ rv1106g-evb1-v11-cvr-dual-cam.dtb \ rv1106g-evb1-v11-spi-nand-cvr.dtb \ diff --git a/arch/arm/boot/dts/rv1106-evb-cam.dtsi b/arch/arm/boot/dts/rv1106-evb-cam.dtsi index 30e25864a401..d13073bb0507 100644 --- a/arch/arm/boot/dts/rv1106-evb-cam.dtsi +++ b/arch/arm/boot/dts/rv1106-evb-cam.dtsi @@ -53,7 +53,7 @@ csi_dphy_input6: endpoint@6 { reg = <6>; remote-endpoint = <&imx415_out>; - data-lanes = <1 2 3 4>; + data-lanes = <1 2>; }; }; @@ -225,7 +225,7 @@ port { imx415_out: endpoint { remote-endpoint = <&csi_dphy_input6>; - data-lanes = <1 2 3 4>; + data-lanes = <1 2>; }; }; }; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts b/arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts new file mode 100644 index 000000000000..2116496639f8 --- /dev/null +++ b/arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; + +#include "rv1106g-evb1-v11.dts" + +/ { + model = "Rockchip RV1106G EVB1 V11 Board For RV1106G3 4K Unite"; + compatible = "rockchip,rv1106g-evb1-v11-4k", "rockchip,rv1106"; +}; + +&rkisp { + rockchip,unite-en; +}; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts b/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts index 0ed1b84f05d1..4ab4b1131232 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts @@ -223,7 +223,8 @@ &rkcif_mipi_lvds { status = "okay"; - //memory-region-thunderboot = <&rkisp_thunderboot>; + memory-region-thunderboot = <&rkisp_thunderboot>; + rtt-suspend; pinctrl-names = "default"; pinctrl-0 = <&mipi_pins>; @@ -253,6 +254,9 @@ &rkisp_vir0 { status = "okay"; + memory-region-thunderboot = <&rkisp_thunderboot>; + rtt-suspend; + port@0 { isp_in: endpoint { remote-endpoint = <&mipi_lvds_sditf>; diff --git a/arch/arm/configs/rv1106-evb.config b/arch/arm/configs/rv1106-evb.config index e32ffeb8990f..7e71c6bab354 100644 --- a/arch/arm/configs/rv1106-evb.config +++ b/arch/arm/configs/rv1106-evb.config @@ -37,6 +37,7 @@ CONFIG_SPI=y CONFIG_USB_SUPPORT=y CONFIG_VFAT_FS=y CONFIG_VIDEO_GC2053=m +CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_OS04A10=m CONFIG_VIDEO_SC3336=m CONFIG_VIDEO_SC4336=m diff --git a/arch/arm/mach-rockchip/rv1106_pm.c b/arch/arm/mach-rockchip/rv1106_pm.c index 5b04bfda7983..1f4656f34893 100644 --- a/arch/arm/mach-rockchip/rv1106_pm.c +++ b/arch/arm/mach-rockchip/rv1106_pm.c @@ -59,6 +59,7 @@ static struct rv1106_sleep_ddr_data ddr_data; static void __iomem *pmucru_base; static void __iomem *cru_base; +static void __iomem *pvtpllcru_base; static void __iomem *pericru_base; static void __iomem *vicru_base; static void __iomem *npucru_base; @@ -105,6 +106,10 @@ static struct reg_region vd_core_reg_rgns[] = { { REG_REGION(0x300, 0x310, 4, &corecru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x804, 4, &corecru_base, WMSK_VAL)}, + /* pvtpll_cru */ + { REG_REGION(0x00, 0x24, 4, &pvtpllcru_base, WMSK_VAL)}, + { REG_REGION(0x30, 0x54, 4, &pvtpllcru_base, WMSK_VAL)}, + /* core_sgrf */ { REG_REGION(0x004, 0x014, 4, &coresgrf_base, 0)}, { REG_REGION(0x000, 0x000, 4, &coresgrf_base, 0)}, @@ -1165,6 +1170,7 @@ static int __init rv1106_suspend_init(struct device_node *np) pmucru_base = dev_reg_base + RV1106_PMUCRU_OFFSET; cru_base = dev_reg_base + RV1106_CRU_OFFSET; + pvtpllcru_base = dev_reg_base + RV1106_PVTPLLCRU_OFFSET; pericru_base = dev_reg_base + RV1106_PERICRU_OFFSET; vicru_base = dev_reg_base + RV1106_VICRU_OFFSET; npucru_base = dev_reg_base + RV1106_NPUCRU_OFFSET; diff --git a/arch/arm/mach-rockchip/rv1106_pm.h b/arch/arm/mach-rockchip/rv1106_pm.h index da857a5b6fa2..6e822386ef23 100644 --- a/arch/arm/mach-rockchip/rv1106_pm.h +++ b/arch/arm/mach-rockchip/rv1106_pm.h @@ -35,6 +35,7 @@ #define RV1106_PMUCRU_OFFSET 0x3a0000 #define RV1106_CRU_OFFSET 0x3b0000 +#define RV1106_PVTPLLCRU_OFFSET 0x3b1000 #define RV1106_PERICRU_OFFSET 0x3b2000 #define RV1106_VICRU_OFFSET 0x3b4000 #define RV1106_NPUCRU_OFFSET 0x3b6000 diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 4784bfb0d8ab..3cb8fa0a1ff3 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -155,6 +155,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-dual-lvds.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-camera.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-lvds.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-lvds-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux-amp.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux-spi-nor.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi b/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi index b66f45e15824..492863b00fbe 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi @@ -59,6 +59,7 @@ compatible = "dongwoon,dw9714"; status = "okay"; reg = <0x0c>; + avdd-supply = <&vcc2v8_dvp>; rockchip,vcm-start-current = <10>; rockchip,vcm-rated-current = <85>; rockchip,vcm-step-mode = <5>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds-linux.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds-linux.dts new file mode 100644 index 000000000000..6a15126ee392 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds-linux.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; + +#include +#include "rk3568-evb1-ddr4-v10-dual-lvds.dtsi" +#include "rk3568-linux.dtsi" + +/ { + model = "Rockchip RK3568 EVB1 V10 Board with Dual LVDS"; + compatible = "rockchip,rk3568-evb1-ddr4-v10-dual-lvds", "rockchip,rk3568"; +}; + +&vp0 { + cursor-win-id = ; +}; + +&vp1 { + cursor-win-id = ; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts index d2f0cab9968b..8cff3652b8d1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts @@ -5,165 +5,10 @@ /dts-v1/; -#include -#include -#include - -#include "rk3568-evb1-ddr4-v10.dtsi" +#include "rk3568-evb1-ddr4-v10-dual-lvds.dtsi" #include "rk3568-android.dtsi" / { - panel { - compatible = "simple-panel"; - backlight = <&backlight>; - power-supply = <&vcc3v3_lcd0_n>; - enable-delay-ms = <20>; - prepare-delay-ms = <20>; - unprepare-delay-ms = <20>; - disable-delay-ms = <20>; - bus-format = ; - width-mm = <217>; - height-mm = <136>; - - display-timings { - native-mode = <&timing0>; - - timing0: timing0 { - clock-frequency = <134000000>; - hactive = <1600>; - vactive = <1280>; - hback-porch = <60>; - hfront-porch = <60>; - vback-porch = <4>; - vfront-porch = <2>; - hsync-len = <8>; - vsync-len = <2>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <0>; - pixelclk-active = <0>; - }; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - /** - * Panel <----> LVDS0 - * Panel <----> LVDS1 - */ - port@0 { - reg = <0>; - dual-lvds-left-pixels; - panel_in_lvds0: endpoint { - remote-endpoint = <&lvds0_out_panel>; - }; - }; - port@1 { - reg = <1>; - dual-lvds-right-pixels; - panel_in_lvds1: endpoint { - remote-endpoint = <&lvds1_out_panel>; - }; - }; - }; - }; -}; - -&backlight1 { - status = "okay"; -}; - -&backlight { - status = "okay"; -}; - -&lvds { - status = "okay"; - dual-channel; - - ports { - port@1 { - reg = <1>; - lvds0_out_panel: endpoint { - remote-endpoint = <&panel_in_lvds0>; - }; - }; - }; -}; - -&lvds1 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - lvds1_out_panel: endpoint { - remote-endpoint = <&panel_in_lvds1>; - }; - }; - }; -}; - -&lvds_in_vp1 { - status = "okay"; -}; - -&lvds1_in_vp1 { - status = "disabled"; -}; - -&lvds1_in_vp2 { - status = "okay"; -}; - -/* enable hdmi */ -&hdmi_in_vp1 { - status = "okay"; -}; - -/* enable video phy */ -&video_phy0 { - status = "okay"; -}; - -&video_phy1 { - status = "okay"; -}; - -/* disable other encoder output */ -&dsi0 { - status = "disabled"; -}; - -&dsi0_in_vp0 { - status = "disabled"; -}; - -&dsi0_in_vp1 { - status = "disabled"; -}; - -&dsi1_in_vp1 { - status = "disabled"; -}; - -&edp_in_vp1 { - status = "disabled"; -}; - -&rgb_in_vp2 { - status = "disabled"; -}; - - -&vcc3v3_lcd0_n { - gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; - enable-active-high; -}; - -&vcc3v3_lcd1_n { - gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; - enable-active-high; + model = "Rockchip RK3568 EVB1 V10 Board with Dual LVDS"; + compatible = "rockchip,rk3568-evb1-ddr4-v10-dual-lvds", "rockchip,rk3568"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi new file mode 100644 index 000000000000..d38f2c2ca3ae --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include "rk3568-evb1-ddr4-v10.dtsi" + +/ { + panel { + compatible = "simple-panel"; + backlight = <&backlight>; + power-supply = <&vcc3v3_lcd0_n>; + enable-delay-ms = <20>; + prepare-delay-ms = <20>; + unprepare-delay-ms = <20>; + disable-delay-ms = <20>; + bus-format = ; + width-mm = <217>; + height-mm = <136>; + + display-timings { + native-mode = <&timing0>; + + timing0: timing0 { + clock-frequency = <134000000>; + hactive = <1600>; + vactive = <1280>; + hback-porch = <60>; + hfront-porch = <60>; + vback-porch = <4>; + vfront-porch = <2>; + hsync-len = <8>; + vsync-len = <2>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /** + * Panel <----> LVDS0 + * Panel <----> LVDS1 + */ + port@0 { + reg = <0>; + dual-lvds-left-pixels; + panel_in_lvds0: endpoint { + remote-endpoint = <&lvds0_out_panel>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-right-pixels; + panel_in_lvds1: endpoint { + remote-endpoint = <&lvds1_out_panel>; + }; + }; + }; + }; +}; + +&backlight1 { + status = "okay"; +}; + +&backlight { + status = "okay"; +}; + +&dsi0 { + status = "disabled"; +}; + +&dsi0_in_vp0 { + status = "disabled"; +}; + +&dsi0_in_vp1 { + status = "disabled"; +}; + +&dsi1_in_vp1 { + status = "disabled"; +}; + +&edp_in_vp1 { + status = "disabled"; +}; + +&hdmi_in_vp1 { + status = "okay"; +}; + +&lvds { + status = "okay"; + dual-channel; + + ports { + port@1 { + reg = <1>; + lvds0_out_panel: endpoint { + remote-endpoint = <&panel_in_lvds0>; + }; + }; + }; +}; + +&lvds1 { + status = "okay"; + + ports { + port@1 { + reg = <1>; + lvds1_out_panel: endpoint { + remote-endpoint = <&panel_in_lvds1>; + }; + }; + }; +}; + +&lvds_in_vp1 { + status = "okay"; +}; + +&lvds1_in_vp1 { + status = "disabled"; +}; + +&lvds1_in_vp2 { + status = "okay"; +}; + +&rgb_in_vp2 { + status = "disabled"; +}; + +&video_phy0 { + status = "okay"; +}; + +&video_phy1 { + status = "okay"; +}; + +&vcc3v3_lcd0_n { + gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; + enable-active-high; +}; + +&vcc3v3_lcd1_n { + gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + enable-active-high; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi index 8901a033e9de..174001fd8e7c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi @@ -6,7 +6,7 @@ / { chosen: chosen { - bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0"; + bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 rcupdate.rcu_expedited=1 rcu_nocbs=all"; }; cspmu: cspmu@fd10c000 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi index 12b815850b57..d3f937b38228 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi @@ -12,7 +12,7 @@ }; chosen: chosen { - bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTUUID=614e0000-0000 rw rootwait"; + bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTUUID=614e0000-0000 rw rootwait rcupdate.rcu_expedited=1 rcu_nocbs=all"; }; cspmu: cspmu@fd10c000 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts index 2fe348b486b8..c51f55339127 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts @@ -149,11 +149,10 @@ }; }; - camera1_vcc12v_buck: camera1_vcc12v-buck { + dcphy0_vcc12v_buck: dcphy0_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera1_vcc12v_buck"; + regulator-name = "dcphy0_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -167,11 +166,10 @@ }; }; - camera2_vcc12v_buck: camera2_vcc12v-buck { + dcphy1_vcc12v_buck: dcphy1_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera2_vcc12v_buck"; + regulator-name = "dcphy1_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -185,11 +183,10 @@ }; }; - camera3_vcc12v_buck: camera3_vcc12v-buck { + dphy0_vcc12v_buck: dphy0_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera3_vcc12v_buck"; + regulator-name = "dphy0_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -203,11 +200,10 @@ }; }; - camera4_vcc12v_buck: camera4_vcc12v-buck { + dphy3_vcc12v_buck: dphy3_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera4_vcc12v_buck"; + regulator-name = "dphy3_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -348,7 +344,7 @@ }; &max96712_dphy3_poc { - vin-supply = <&camera1_vcc12v_buck>; + vin-supply = <&dphy3_vcc12v_buck>; }; &avdd1v8_ddr_pll_s0 { @@ -373,12 +369,12 @@ }; &i2c2_bu18tl82 { - //route-enable; - use-delay-work; + route-enable; + //use-delay-work; }; &i2c2_bu18rl82 { - use-delay-work; + //use-delay-work; vpower-supply = <&lcd1_vcc12v_buck>; }; @@ -389,11 +385,11 @@ }; &i2c4_bu18tl82 { - use-delay-work; + //use-delay-work; }; &i2c4_bu18rl82 { - use-delay-work; + //use-delay-work; vpower-supply = <&lcd5_vcc12v_buck>; }; @@ -435,11 +431,11 @@ }; &i2c5_bu18tl82 { - use-delay-work; + //use-delay-work; }; &i2c5_bu18rl82 { - use-delay-work; + //use-delay-work; vpower-supply = <&lcd3_vcc12v_buck>; }; @@ -450,8 +446,8 @@ }; &i2c6_bu18tl82 { - //route-enable; - use-delay-work; + route-enable; + //use-delay-work; }; &i2c6_bu18rl82 { @@ -565,11 +561,11 @@ }; &route_dsi0 { - status = "disabled"; + status = "okay"; }; &route_dsi1 { - status = "disabled"; + status = "okay"; }; &u2phy1_otg { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 0f63e9857aef..6f7616c99ecc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -2651,7 +2651,7 @@ }; usb_host0_ohci: usb@fc840000 { - compatible = "generic-ohci"; + compatible = "rockchip,rk3588-ohci", "generic-ohci"; reg = <0x0 0xfc840000 0x0 0x40000>; interrupts = ; clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST_ARB0>, <&u2phy2>, <&aclk_usb>; @@ -2676,7 +2676,7 @@ }; usb_host1_ohci: usb@fc8c0000 { - compatible = "generic-ohci"; + compatible = "rockchip,rk3588-ohci", "generic-ohci"; reg = <0x0 0xfc8c0000 0x0 0x40000>; interrupts = ; clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST_ARB1>, <&u2phy3>, <&aclk_usb>; @@ -2760,6 +2760,8 @@ mode-panic = ; mode-watchdog = ; mode-quiescent = ; + /* add a mode to capture the ramdump through usb */ + mode-winusb = ; }; }; diff --git a/arch/arm64/configs/rockchip_defconfig b/arch/arm64/configs/rockchip_defconfig index a4d35fd25eb9..f9ee6529c01a 100644 --- a/arch/arm64/configs/rockchip_defconfig +++ b/arch/arm64/configs/rockchip_defconfig @@ -9,6 +9,10 @@ CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_IKHEADERS=m diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index 38804161a4b5..f6d640becad8 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -4,6 +4,9 @@ CONFIG_SYSVIPC=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=18 diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c index 2b4d4a437213..da8dde239972 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c @@ -1604,6 +1604,10 @@ static int kbasep_kcpu_fence_signal_init(struct kbase_kcpu_command_queue *kcpu_q if (!kcpu_fence) return -ENOMEM; + /* Set reference to KCPU metadata and increment refcount */ + kcpu_fence->metadata = kcpu_queue->metadata; + WARN_ON(!kbase_refcount_inc_not_zero(&kcpu_fence->metadata->refcount)); + #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) fence_out = (struct fence *)kcpu_fence; #else @@ -1625,10 +1629,6 @@ static int kbasep_kcpu_fence_signal_init(struct kbase_kcpu_command_queue *kcpu_q dma_fence_get(fence_out); #endif - /* Set reference to KCPU metadata and increment refcount */ - kcpu_fence->metadata = kcpu_queue->metadata; - WARN_ON(!kbase_refcount_inc_not_zero(&kcpu_fence->metadata->refcount)); - /* create a sync_file fd representing the fence */ *sync_file = sync_file_create(fence_out); if (!(*sync_file)) { diff --git a/drivers/media/i2c/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim4c/maxim4c_drv.c index 16d11afb4828..9d9df08b4dbd 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim4c/maxim4c_drv.c @@ -29,10 +29,12 @@ * V2.03.00 * 1. remote device add the maxim4c prefix to driver name. * - * V2.04.02 + * V2.04.03 * 1. Add regulator supplier dependencies. * 2. Add config ssc-ratio property * 3. Add debugfs entry to change MIPI timing + * 4. Use PM runtime autosuspend feature + * 5. Fix unbalanced disabling for PoC regulator * */ #include @@ -63,7 +65,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x02) +#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x03) #define MAXIM4C_XVCLK_FREQ 25000000 @@ -681,6 +683,14 @@ static int maxim4c_probe(struct i2c_client *client, if (ret) goto err_destroy_mutex; + ret = maxim4c_remote_device_power_on(maxim4c); + if (ret) + dev_warn(dev, "Power on PoC regulator failed\n"); + + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + ret = maxim4c_check_local_chipid(maxim4c); if (ret) goto err_power_off; @@ -704,9 +714,10 @@ static int maxim4c_probe(struct i2c_client *client, goto err_power_off; #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; #endif /* MAXIM4C_TEST_PATTERN */ @@ -731,9 +742,10 @@ static int maxim4c_probe(struct i2c_client *client, maxim4c_lock_irq_init(maxim4c); maxim4c_lock_state_work_init(maxim4c); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; @@ -742,6 +754,9 @@ err_dbgfs_deinit: err_subdev_deinit: maxim4c_v4l2_subdev_deinit(maxim4c); err_power_off: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + maxim4c_remote_device_power_off(maxim4c); maxim4c_local_device_power_off(maxim4c); err_destroy_mutex: mutex_destroy(&maxim4c->mutex); diff --git a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c index 37df9a622f59..b40fdf2b3632 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c +++ b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c @@ -589,21 +589,20 @@ static int maxim4c_s_stream(struct v4l2_subdev *sd, int on) goto unlock_and_return; if (on) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) goto unlock_and_return; - } ret = __maxim4c_start_stream(maxim4c); if (ret) { v4l2_err(sd, "start stream failed while write regs\n"); - pm_runtime_put(&client->dev); + pm_runtime_put_sync(&client->dev); goto unlock_and_return; } } else { __maxim4c_stop_stream(maxim4c); - pm_runtime_put(&client->dev); + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); } maxim4c->streaming = on; diff --git a/drivers/media/i2c/sc200ai.c b/drivers/media/i2c/sc200ai.c index 8452f27def63..424112f51f3a 100644 --- a/drivers/media/i2c/sc200ai.c +++ b/drivers/media/i2c/sc200ai.c @@ -2046,11 +2046,11 @@ static int sc200ai_probe(struct i2c_client *client, return -EINVAL; } - sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); + sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); if (IS_ERR(sc200ai->reset_gpio)) dev_warn(dev, "Failed to get reset-gpios\n"); - sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); + sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); if (IS_ERR(sc200ai->pwdn_gpio)) dev_warn(dev, "Failed to get pwdn-gpios\n"); diff --git a/drivers/media/i2c/sc2336.c b/drivers/media/i2c/sc2336.c index a677b073817a..d2a7ca50a3b2 100644 --- a/drivers/media/i2c/sc2336.c +++ b/drivers/media/i2c/sc2336.c @@ -7,7 +7,7 @@ * V0.0X01.0X01 first version */ -//#define DEBUG +// #define DEBUG #include #include #include @@ -192,10 +192,10 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x3301, 0x09}, {0x3302, 0xff}, {0x3303, 0x10}, - {0x3306, 0x60}, + {0x3306, 0x68}, {0x3307, 0x02}, {0x330a, 0x01}, - {0x330b, 0x10}, + {0x330b, 0x18}, {0x330c, 0x16}, {0x330d, 0xff}, {0x3318, 0x02}, @@ -219,8 +219,8 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x33b1, 0x80}, {0x33b2, 0x68}, {0x33b3, 0x42}, - {0x33f9, 0x70}, - {0x33fb, 0xd0}, + {0x33f9, 0x78}, + {0x33fb, 0xe0}, {0x33fc, 0x0f}, {0x33fd, 0x1f}, {0x349f, 0x03}, @@ -229,9 +229,9 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x34a8, 0x42}, {0x34a9, 0x06}, {0x34aa, 0x01}, - {0x34ab, 0x23}, + {0x34ab, 0x28}, {0x34ac, 0x01}, - {0x34ad, 0x84}, + {0x34ad, 0x90}, {0x3630, 0xf4}, {0x3633, 0x22}, {0x3639, 0xf4}, @@ -242,9 +242,9 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x3676, 0xed}, {0x367c, 0x09}, {0x367d, 0x0f}, - {0x3690, 0x33}, - {0x3691, 0x33}, - {0x3692, 0x43}, + {0x3690, 0x22}, + {0x3691, 0x22}, + {0x3692, 0x22}, {0x3698, 0x89}, {0x3699, 0x96}, {0x369a, 0xd0}, @@ -452,15 +452,15 @@ static int sc2336_set_gain_reg(struct sc2336 *sc2336, u32 gain) coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000; } else if (gain_factor < 1000 * 4) { /*2x ~ 4x gain*/ - coarse_again = 0x01; + coarse_again = 0x08; coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000 / 2; } else if (gain_factor < 1000 * 8) { /*4x ~ 8x gain*/ - coarse_again = 0x03; + coarse_again = 0x09; coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000 / 4; } else if (gain_factor < 1000 * 16) { /*8x ~ 16x gain*/ - coarse_again = 0x07; + coarse_again = 0x0b; coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000 / 8; } else if (gain_factor < 1000 * 32) { /*16x ~ 32x gain*/ @@ -481,6 +481,7 @@ static int sc2336_set_gain_reg(struct sc2336 *sc2336, u32 gain) coarse_dgain = 0x03; fine_dgain = 0x80; } + fine_dgain = fine_dgain / 4 * 4; dev_dbg(&sc2336->client->dev, "total_gain: 0x%x, d_gain: 0x%x, d_fine_gain: 0x%x, c_gain: 0x%x\n", gain, coarse_dgain, fine_dgain, coarse_again); @@ -1148,7 +1149,7 @@ static int sc2336_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = sc2336->cur_mode->height + ctrl->val - 8; + max = sc2336->cur_mode->height + ctrl->val - 6; __v4l2_ctrl_modify_range(sc2336->exposure, sc2336->exposure->minimum, max, sc2336->exposure->step, @@ -1271,7 +1272,7 @@ static int sc2336_initialize_controls(struct sc2336 *sc2336) V4L2_CID_VBLANK, vblank_def, SC2336_VTS_MAX - mode->height, 1, vblank_def); - exposure_max = mode->vts_def - 8; + exposure_max = mode->vts_def - 6; sc2336->exposure = v4l2_ctrl_new_std(handler, &sc2336_ctrl_ops, V4L2_CID_EXPOSURE, SC2336_EXPOSURE_MIN, exposure_max, SC2336_EXPOSURE_STEP, diff --git a/drivers/media/platform/rockchip/isp/capture_v21.c b/drivers/media/platform/rockchip/isp/capture_v21.c index 37ba5f66110c..9bbade405d26 100644 --- a/drivers/media/platform/rockchip/isp/capture_v21.c +++ b/drivers/media/platform/rockchip/isp/capture_v21.c @@ -1225,6 +1225,15 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state) struct vb2_buffer *vb2_buf = &stream->curr_buf->vb.vb2_buf; u64 ns = 0; + if (stream->skip_frame) { + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + list_add_tail(&stream->curr_buf->queue, &stream->buf_queue); + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + if (stream->skip_frame) + stream->skip_frame--; + goto end; + } + /* Dequeue a filled buffer */ for (i = 0; i < isp_fmt->mplanes; i++) { u32 payload_size = @@ -1287,6 +1296,7 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state) stream->curr_buf = NULL; } +end: if (!interlaced || (stream->curr_buf == stream->next_buf && stream->u.sp.field == RKISP_FIELD_ODD)) { @@ -1505,7 +1515,7 @@ static int rkisp_start(struct rkisp_stream *stream) if (stream->id == RKISP_STREAM_MP || stream->id == RKISP_STREAM_SP) hdr_config_dmatx(dev); stream->streaming = true; - + stream->skip_frame = 0; return 0; } diff --git a/drivers/media/platform/rockchip/isp/capture_v30.c b/drivers/media/platform/rockchip/isp/capture_v30.c index ef046fddf481..ec1d658505b7 100644 --- a/drivers/media/platform/rockchip/isp/capture_v30.c +++ b/drivers/media/platform/rockchip/isp/capture_v30.c @@ -977,6 +977,15 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state) struct vb2_buffer *vb2_buf = &buf->vb.vb2_buf; u64 ns = 0; + if (stream->skip_frame) { + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + list_add_tail(&buf->queue, &stream->buf_queue); + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + if (stream->skip_frame) + stream->skip_frame--; + goto end; + } + /* Dequeue a filled buffer */ for (i = 0; i < isp_fmt->mplanes; i++) { u32 payload_size = stream->out_fmt.plane_fmt[i].sizeimage; @@ -1097,7 +1106,7 @@ static int rkisp_start(struct rkisp_stream *stream) stream->ops->enable_mi(stream); stream->streaming = true; - + stream->skip_frame = 0; return 0; } diff --git a/drivers/media/platform/rockchip/isp/csi.c b/drivers/media/platform/rockchip/isp/csi.c index f0f1f32ed709..ff9b815f9ffc 100644 --- a/drivers/media/platform/rockchip/isp/csi.c +++ b/drivers/media/platform/rockchip/isp/csi.c @@ -15,7 +15,7 @@ #include "isp_external.h" #include "regs.h" -static void get_remote_mipi_sensor(struct rkisp_device *dev, +void rkisp_get_remote_mipi_sensor(struct rkisp_device *dev, struct v4l2_subdev **sensor_sd, u32 function) { struct media_graph graph; @@ -191,7 +191,7 @@ static int csi_config(struct rkisp_csi_device *csi) emd_vc = 0xFF; emd_dt = 0; dev->hdr.sensor = NULL; - get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); + rkisp_get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); if (mipi_sensor) { ctrl = v4l2_ctrl_find(mipi_sensor->ctrl_handler, CIFISP_CID_EMB_VC); @@ -527,7 +527,7 @@ int rkisp_csi_get_hdr_cfg(struct rkisp_device *dev, void *arg) } return 0; } - get_remote_mipi_sensor(dev, &sd, type); + rkisp_get_remote_mipi_sensor(dev, &sd, type); if (!sd) { v4l2_err(&dev->v4l2_dev, "%s don't find subdev\n", __func__); return -EINVAL; @@ -558,7 +558,7 @@ int rkisp_csi_config_patch(struct rkisp_device *dev) memset(&mode, 0, sizeof(mode)); mode.name = dev->name; - get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_PROC_VIDEO_COMPOSER); + rkisp_get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_PROC_VIDEO_COMPOSER); if (!mipi_sensor) return -EINVAL; dev->hdr.op_mode = HDR_NORMAL; diff --git a/drivers/media/platform/rockchip/isp/csi.h b/drivers/media/platform/rockchip/isp/csi.h index 98bf2511088c..9fbdc35b4405 100644 --- a/drivers/media/platform/rockchip/isp/csi.h +++ b/drivers/media/platform/rockchip/isp/csi.h @@ -80,4 +80,6 @@ void rkisp_unregister_csi_subdev(struct rkisp_device *dev); int rkisp_csi_get_hdr_cfg(struct rkisp_device *dev, void *arg); int rkisp_csi_config_patch(struct rkisp_device *dev); void rkisp_csi_sof(struct rkisp_device *dev, u8 id); +void rkisp_get_remote_mipi_sensor(struct rkisp_device *dev, + struct v4l2_subdev **sensor_sd, u32 function); #endif diff --git a/drivers/media/platform/rockchip/isp/dev.c b/drivers/media/platform/rockchip/isp/dev.c index f06f8ffc4962..a42eeb23d92e 100644 --- a/drivers/media/platform/rockchip/isp/dev.c +++ b/drivers/media/platform/rockchip/isp/dev.c @@ -52,6 +52,7 @@ #include "regs.h" #include "rkisp.h" #include "version.h" +#include "csi.h" #define RKISP_VERNO_LEN 10 @@ -813,6 +814,15 @@ static int rkisp_get_reserved_mem(struct rkisp_device *isp_dev) DMA_BIDIRECTIONAL); ret = dma_mapping_error(dev, isp_dev->resmem_addr); isp_dev->is_thunderboot = true; + isp_dev->is_rtt_suspend = false; + isp_dev->is_rtt_first = true; + if (device_property_read_bool(dev, "rtt-suspend")) { + isp_dev->is_rtt_suspend = true; + if (!isp_dev->hw_dev->is_thunderboot) { + isp_dev->is_thunderboot = false; + isp_dev->is_rtt_first = false; + } + } dev_info(dev, "Allocated reserved memory, paddr: 0x%x\n", (u32)isp_dev->resmem_pa); return ret; } @@ -1004,9 +1014,159 @@ static int __init rkisp_clr_unready_dev(void) late_initcall_sync(rkisp_clr_unready_dev); #endif +static int rkisp_pm_prepare(struct device *dev) +{ + struct rkisp_device *isp_dev = dev_get_drvdata(dev); + struct rkisp_hw_dev *hw = isp_dev->hw_dev; + struct rkisp_pipeline *p = &isp_dev->pipe; + unsigned long lock_flags = 0; + int i, on = 0, time = 100; + + if (isp_dev->isp_state & ISP_STOP) { + if (pm_runtime_active(dev) && + rkisp_link_sensor(isp_dev->isp_inp)) { + struct v4l2_subdev *mipi_sensor = NULL; + + rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); + if (mipi_sensor) + v4l2_subdev_call(mipi_sensor, core, s_power, 0); + } + return 0; + } + + isp_dev->suspend_sync = false; + isp_dev->is_suspend = true; + if (rkisp_link_sensor(isp_dev->isp_inp)) { + for (i = p->num_subdevs - 1; i >= 0; i--) + v4l2_subdev_call(p->subdevs[i], video, s_stream, on); + } else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) { + v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on); + } + if (IS_HDR_RDBK(isp_dev->rd_mode)) { + spin_lock_irqsave(&hw->rdbk_lock, lock_flags); + if (!hw->is_idle && hw->cur_dev_id == isp_dev->dev_id) + isp_dev->suspend_sync = true; + spin_unlock_irqrestore(&hw->rdbk_lock, lock_flags); + } else { + /* wait one frame for online */ + isp_dev->suspend_sync = true; + if (hw->isp_size[isp_dev->dev_id].fps) + time = 1000 / hw->isp_size[isp_dev->dev_id].fps; + } + + if (isp_dev->suspend_sync) { + wait_for_completion_timeout(&isp_dev->pm_cmpl, msecs_to_jiffies(time)); + isp_dev->suspend_sync = false; + } + + if (rkisp_link_sensor(isp_dev->isp_inp)) { + for (i = p->num_subdevs - 1; i >= 0; i--) + v4l2_subdev_call(p->subdevs[i], core, s_power, 0); + } + return 0; +} + +static void rkisp_pm_complete(struct device *dev) +{ + struct rkisp_device *isp_dev = dev_get_drvdata(dev); + struct rkisp_hw_dev *hw = isp_dev->hw_dev; + struct rkisp_pipeline *p = &isp_dev->pipe; + struct rkisp_stream *stream; + int i, on = 1, rd_mode = isp_dev->rd_mode; + + if (isp_dev->isp_state & ISP_STOP) { + if (pm_runtime_active(dev) && + rkisp_link_sensor(isp_dev->isp_inp)) { + struct v4l2_subdev *mipi_sensor = NULL; + + rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); + if (mipi_sensor) + v4l2_subdev_call(mipi_sensor, core, s_power, 1); + } + return; + } + + if (isp_dev->is_rtt_suspend) { + rkisp_save_tb_info(isp_dev); + v4l2_info(&isp_dev->v4l2_dev, + "tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d mode:%d\n", + isp_dev->tb_head.enable, isp_dev->tb_head.complete, + isp_dev->tb_head.frm_total, isp_dev->tb_head.width, + isp_dev->tb_head.height, isp_dev->tb_head.camera_num, + isp_dev->tb_head.camera_index, isp_dev->tb_head.rtt_mode); + isp_dev->is_first_double = false; + switch (isp_dev->tb_head.rtt_mode) { + case RKISP_RTT_MODE_ONE_FRAME: + isp_dev->is_first_double = true; + /* switch to readback mode */ + switch (rd_mode) { + case HDR_LINEX3_DDR: + isp_dev->rd_mode = HDR_RDBK_FRAME3; + break; + case HDR_LINEX2_DDR: + isp_dev->rd_mode = HDR_RDBK_FRAME2; + break; + default: + isp_dev->rd_mode = HDR_RDBK_FRAME1; + } + break; + case RKISP_RTT_MODE_MULTI_FRAME: + default: + if (isp_dev->tb_head.rtt_mode != RKISP_RTT_MODE_MULTI_FRAME) + v4l2_warn(&isp_dev->v4l2_dev, + "invalid rtt mode:%d, change to mode:%d\n", + isp_dev->tb_head.rtt_mode, RKISP_RTT_MODE_MULTI_FRAME); + if (!hw->is_single) + break; + /* switch to online mode for single sensor */ + switch (rd_mode) { + case HDR_RDBK_FRAME3: + isp_dev->rd_mode = HDR_LINEX3_DDR; + break; + case HDR_RDBK_FRAME2: + isp_dev->rd_mode = HDR_LINEX2_DDR; + break; + default: + isp_dev->rd_mode = HDR_NORMAL; + } + } + isp_dev->hdr.op_mode = isp_dev->rd_mode; + if (rd_mode != isp_dev->rd_mode && hw->cur_dev_id == isp_dev->dev_id) { + rkisp_unite_write(isp_dev, CSI2RX_CTRL0, + SW_IBUF_OP_MODE(isp_dev->rd_mode), true); + if (IS_HDR_RDBK(isp_dev->rd_mode)) + rkisp_unite_set_bits(isp_dev, CTRL_SWS_CFG, 0, + SW_MPIP_DROP_FRM_DIS, true); + else + rkisp_unite_clear_bits(isp_dev, CTRL_SWS_CFG, + SW_MPIP_DROP_FRM_DIS, true); + } + } + + isp_dev->is_suspend = false; + isp_dev->isp_state = ISP_START | ISP_FRAME_END; + for (i = 0; i < RKISP_MAX_STREAM; i++) { + stream = &isp_dev->cap_dev.stream[i]; + if (i == RKISP_STREAM_VIR || !stream->streaming) + continue; + stream->skip_frame = 1; + } + if (hw->cur_dev_id == isp_dev->dev_id) + rkisp_rdbk_trigger_event(isp_dev, T_CMD_QUEUE, NULL); + + if (rkisp_link_sensor(isp_dev->isp_inp)) { + for (i = 0; i < p->num_subdevs; i++) + v4l2_subdev_call(p->subdevs[i], core, s_power, 1); + for (i = 0; i < p->num_subdevs; i++) + v4l2_subdev_call(p->subdevs[i], video, s_stream, on); + } else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) { + v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on); + } +} + static const struct dev_pm_ops rkisp_plat_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + .prepare = rkisp_pm_prepare, + .complete = rkisp_pm_complete, SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, rkisp_runtime_resume, NULL) }; diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index afdf7f1c8ecc..c45f31f02555 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -235,6 +235,10 @@ struct rkisp_device { size_t resmem_size; struct rkisp_thunderboot_resmem_head tb_head; bool is_thunderboot; + /* first frame for rtt */ + bool is_rtt_first; + /* suspend/resume with rtt */ + bool is_rtt_suspend; struct rkisp_tb_stream_info tb_stream_info; unsigned int tb_addr_idx; @@ -246,6 +250,8 @@ struct rkisp_device { struct rkisp_ispp_buf *cur_fbcgain; struct rkisp_buffer *cur_spbuf; + struct completion pm_cmpl; + struct work_struct rdbk_work; struct kfifo rdbk_kfifo; spinlock_t rdbk_lock; @@ -269,6 +275,8 @@ struct rkisp_device { bool is_first_double; bool is_probe_end; bool is_frame_double; + bool is_suspend; + bool suspend_sync; struct rkisp_vicap_input vicap_in; @@ -304,4 +312,8 @@ rkisp_unite_clear_bits(struct rkisp_device *dev, u32 reg, u32 mask, rkisp_next_clear_bits(dev, reg, mask, is_direct); } +static inline bool rkisp_link_sensor(u32 isp_inp) +{ + return isp_inp & (INP_CSI | INP_DVP | INP_LVDS); +} #endif diff --git a/drivers/media/platform/rockchip/isp/hw.c b/drivers/media/platform/rockchip/isp/hw.c index cfc486d73725..e66816d70310 100644 --- a/drivers/media/platform/rockchip/isp/hw.c +++ b/drivers/media/platform/rockchip/isp/hw.c @@ -35,6 +35,12 @@ * rkisp_hw */ +struct backup_reg { + const u32 base; + const u32 shd; + u32 val; +}; + struct isp_irqs_data { const char *name; irqreturn_t (*irq_hdl)(int irq, void *ctx); @@ -302,6 +308,192 @@ int rkisp_register_irq(struct rkisp_hw_dev *hw_dev) return 0; } +void rkisp_hw_reg_save(struct rkisp_hw_dev *dev) +{ + void *buf = dev->sw_reg; + + memcpy_fromio(buf, dev->base_addr, RKISP_ISP_SW_REG_SIZE); + if (dev->unite == ISP_UNITE_TWO) { + buf += RKISP_ISP_SW_REG_SIZE; + memcpy_fromio(buf, dev->base_next_addr, RKISP_ISP_SW_REG_SIZE); + } +} + +void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) +{ + struct rkisp_device *isp = dev->isp[dev->cur_dev_id]; + void __iomem *base = dev->base_addr; + void *reg_buf = dev->sw_reg; + u32 val, *reg, *reg1, i, j; + u32 self_upd_reg[] = { + ISP21_BAY3D_BASE, ISP21_DRC_BASE, ISP3X_BAY3D_CTRL, + ISP_DHAZ_CTRL, ISP3X_3DLUT_BASE, ISP_RAWAE_LITE_BASE, + RAWAE_BIG1_BASE, RAWAE_BIG2_BASE, RAWAE_BIG3_BASE, + ISP_RAWHIST_LITE_BASE, ISP_RAWHIST_BIG1_BASE, + ISP_RAWHIST_BIG2_BASE, ISP_RAWHIST_BIG3_BASE, + ISP_RAWAF_BASE, ISP_RAWAWB_BASE, ISP_LDCH_BASE, + ISP3X_CAC_BASE, + }; + struct backup_reg backup[] = { + { + .base = MI_MP_WR_Y_BASE, + .shd = MI_MP_WR_Y_BASE_SHD, + }, { + .base = MI_MP_WR_CB_BASE, + .shd = MI_MP_WR_CB_BASE_SHD, + }, { + .base = MI_MP_WR_CR_BASE, + .shd = MI_MP_WR_CR_BASE_SHD, + }, { + .base = MI_SP_WR_Y_BASE, + .shd = MI_SP_WR_Y_BASE_SHD, + }, { + .base = MI_SP_WR_CB_BASE, + .shd = MI_SP_WR_CB_BASE_AD_SHD, + }, { + .base = MI_SP_WR_CR_BASE, + .shd = MI_SP_WR_CR_BASE_AD_SHD, + }, { + .base = ISP3X_MI_BP_WR_Y_BASE, + .shd = ISP3X_MI_BP_WR_Y_BASE_SHD, + }, { + .base = ISP3X_MI_BP_WR_CB_BASE, + .shd = ISP3X_MI_BP_WR_CB_BASE_SHD, + }, { + .base = ISP32_MI_MPDS_WR_Y_BASE, + .shd = ISP32_MI_MPDS_WR_Y_BASE_SHD, + }, { + .base = ISP32_MI_MPDS_WR_CB_BASE, + .shd = ISP32_MI_MPDS_WR_CB_BASE_SHD, + }, { + .base = ISP32_MI_BPDS_WR_Y_BASE, + .shd = ISP32_MI_BPDS_WR_Y_BASE_SHD, + }, { + .base = ISP32_MI_BPDS_WR_CB_BASE, + .shd = ISP32_MI_BPDS_WR_CB_BASE_SHD, + }, { + .base = MI_RAW0_WR_BASE, + .shd = MI_RAW0_WR_BASE_SHD, + }, { + .base = MI_RAW1_WR_BASE, + .shd = MI_RAW1_WR_BASE_SHD, + }, { + .base = MI_RAW2_WR_BASE, + .shd = MI_RAW2_WR_BASE_SHD, + }, { + .base = MI_RAW3_WR_BASE, + .shd = MI_RAW3_WR_BASE_SHD, + }, { + .base = MI_RAW0_RD_BASE, + .shd = MI_RAW0_RD_BASE_SHD, + }, { + .base = MI_RAW1_RD_BASE, + .shd = MI_RAW1_RD_BASE_SHD, + }, { + .base = MI_RAW2_RD_BASE, + .shd = MI_RAW2_RD_BASE_SHD, + }, { + .base = MI_GAIN_WR_BASE, + .shd = MI_GAIN_WR_BASE_SHD, + } + }; + + for (i = 0; i <= !!dev->unite; i++) { + if (dev->unite != ISP_UNITE_TWO && i) + break; + + if (i) { + reg_buf += RKISP_ISP_SW_REG_SIZE; + base = dev->base_next_addr; + } + + /* process special reg */ + for (j = 0; j < ARRAY_SIZE(self_upd_reg); j++) { + reg = reg_buf + self_upd_reg[j]; + *reg &= ~ISP21_SELF_FORCE_UPD; + if (self_upd_reg[j] == ISP3X_3DLUT_BASE && *reg & ISP_3DLUT_EN) { + reg = reg_buf + ISP3X_3DLUT_UPDATE; + *reg = 1; + } + } + reg = reg_buf + ISP_CTRL; + *reg &= ~(CIF_ISP_CTRL_ISP_ENABLE | + CIF_ISP_CTRL_ISP_INFORM_ENABLE | + CIF_ISP_CTRL_ISP_CFG_UPD); + reg = reg_buf + MI_WR_INIT; + *reg = 0; + reg = reg_buf + CSI2RX_CTRL0; + *reg &= ~SW_CSI2RX_EN; + for (j = 0; j < RKISP_ISP_SW_REG_SIZE; j += 4) { + /* skip table RAM */ + if ((j > ISP3X_LSC_CTRL && j < ISP3X_LSC_XGRAD_01) || + (j > ISP32_CAC_OFFSET && j < ISP3X_CAC_RO_CNT) || + (j > ISP3X_3DLUT_UPDATE && j < ISP3X_GAIN_BASE) || + (j == 0x4840 || j == 0x4a80 || j == 0x4b40 || j == 0x5660)) + continue; + /* skip mmu range */ + if (dev->isp_ver < ISP_V30 && + j > ISP21_MI_BAY3D_RD_BASE_SHD && j < CSI2RX_CTRL0) + continue; + /* reg value of read diff to write */ + if (j == ISP_MPFBC_CTRL || + j == ISP32_ISP_AWB1_GAIN_G || j == ISP32_ISP_AWB1_GAIN_RB) + reg = isp->sw_base_addr + j; + else + reg = reg_buf + j; + writel(*reg, base + j); + } + + /* config shd_reg to base_reg */ + for (j = 0; j < ARRAY_SIZE(backup); j++) { + reg = reg_buf + backup[j].base; + reg1 = reg_buf + backup[j].shd; + backup[j].val = *reg; + writel(*reg1, base + backup[j].base); + } + + /* update module */ + reg = reg_buf + DUAL_CROP_CTRL; + if (*reg & 0xf) + writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL); + reg = reg_buf + SELF_RESIZE_CTRL; + if (*reg & 0xf) { + if (dev->isp_ver == ISP_V32_L) + writel(*reg | ISP32_SCALE_FORCE_UPD, base + ISP32_SELF_SCALE_UPDATE); + else + writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL); + } + reg = reg_buf + MAIN_RESIZE_CTRL; + if (*reg & 0xf) + writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL); + reg = reg_buf + ISP32_BP_RESIZE_CTRL; + if (*reg & 0xf) + writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + ISP32_BP_RESIZE_CTRL); + + /* update mi and isp, base_reg will update to shd_reg */ + writel(CIF_MI_INIT_SOFT_UPD, base + MI_WR_INIT); + + /* config base_reg */ + for (j = 0; j < ARRAY_SIZE(backup); j++) + writel(backup[j].val, base + backup[j].base); + /* base_reg = shd_reg, write is base but read is shd */ + val = rkisp_read_reg_cache(isp, ISP_MPFBC_HEAD_PTR); + writel(val, base + ISP_MPFBC_HEAD_PTR); + val = rkisp_read_reg_cache(isp, MI_SWS_3A_WR_BASE); + writel(val, base + MI_SWS_3A_WR_BASE); + } + + rkisp_params_cfgsram(&isp->params_vdev, false); + + reg = reg_buf + ISP_CTRL; + *reg |= CIF_ISP_CTRL_ISP_ENABLE | + CIF_ISP_CTRL_ISP_CFG_UPD | + CIF_ISP_CTRL_ISP_INFORM_ENABLE; + writel(*reg, dev->base_addr + ISP_CTRL); + if (dev->unite == ISP_UNITE_TWO) + writel(*reg, dev->base_next_addr + ISP_CTRL); +} + static const char * const rk3562_isp_clks[] = { "clk_isp_core", "aclk_isp", @@ -733,7 +925,6 @@ static void disable_sys_clk(struct rkisp_hw_dev *dev) static int enable_sys_clk(struct rkisp_hw_dev *dev) { int i, ret = -EINVAL; - unsigned long rate; for (i = 0; i < dev->num_clks; i++) { if (!IS_ERR(dev->clks[i])) { @@ -743,12 +934,6 @@ static int enable_sys_clk(struct rkisp_hw_dev *dev) } } - if (!dev->is_assigned_clk) { - rate = dev->clk_rate_tbl[0].clk_rate * 1000000UL; - rkisp_set_clk_rate(dev->clks[0], rate); - if (dev->unite == ISP_UNITE_TWO) - rkisp_set_clk_rate(dev->clks[5], rate); - } rkisp_soft_reset(dev, false); isp_config_clk(dev, true); return 0; @@ -805,19 +990,24 @@ static int rkisp_hw_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct rkisp_hw_dev *hw_dev; struct resource *res; - int i, ret; + int i, ret, mult = 1; bool is_mem_reserved = true; u32 clk_rate = 0; match = of_match_node(rkisp_hw_of_match, node); if (IS_ERR(match)) return PTR_ERR(match); + match_data = match->data; hw_dev = devm_kzalloc(dev, sizeof(*hw_dev), GFP_KERNEL); if (!hw_dev) return -ENOMEM; - match_data = match->data; + if (match_data->unite) + mult = 2; + hw_dev->sw_reg = devm_kzalloc(dev, RKISP_ISP_SW_REG_SIZE * mult, GFP_KERNEL); + if (!hw_dev->sw_reg) + return -ENOMEM; dev_set_drvdata(dev, hw_dev); hw_dev->dev = dev; hw_dev->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); @@ -995,11 +1185,23 @@ static void rkisp_hw_shutdown(struct platform_device *pdev) static int __maybe_unused rkisp_runtime_suspend(struct device *dev) { struct rkisp_hw_dev *hw_dev = dev_get_drvdata(dev); + int i; - hw_dev->dev_link_num = 0; - hw_dev->is_single = true; - hw_dev->is_multi_overflow = false; - hw_dev->is_frm_buf = false; + hw_dev->is_idle = true; + if (dev->power.runtime_status) { + hw_dev->dev_link_num = 0; + hw_dev->is_single = true; + hw_dev->is_multi_overflow = false; + hw_dev->is_frm_buf = false; + } else { + /* system suspend */ + for (i = 0; i < hw_dev->dev_num; i++) { + if (hw_dev->isp_size[i].is_on) { + rkisp_hw_reg_save(hw_dev); + break; + } + } + } disable_sys_clk(hw_dev); return pinctrl_pm_select_sleep_state(dev); } @@ -1062,28 +1264,45 @@ static int __maybe_unused rkisp_runtime_resume(struct device *dev) return ret; enable_sys_clk(hw_dev); - for (i = 0; i < hw_dev->dev_num; i++) { - isp = hw_dev->isp[i]; - if (!isp || !isp->sw_base_addr) - continue; - buf = isp->sw_base_addr; - memset(buf, 0, RKISP_ISP_SW_MAX_SIZE * mult); - memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); - if (hw_dev->unite) { - buf += RKISP_ISP_SW_MAX_SIZE; - base = hw_dev->base_next_addr; - memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); + if (dev->power.runtime_status) { + if (!hw_dev->is_assigned_clk) { + unsigned long rate = hw_dev->clk_rate_tbl[0].clk_rate * 1000000UL; + + rkisp_set_clk_rate(hw_dev->clks[0], rate); + if (hw_dev->unite == ISP_UNITE_TWO) + rkisp_set_clk_rate(hw_dev->clks[5], rate); + } + for (i = 0; i < hw_dev->dev_num; i++) { + isp = hw_dev->isp[i]; + if (!isp || !isp->sw_base_addr) + continue; + buf = isp->sw_base_addr; + memset(buf, 0, RKISP_ISP_SW_MAX_SIZE * mult); + memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); + if (hw_dev->unite) { + buf += RKISP_ISP_SW_MAX_SIZE; + base = hw_dev->base_next_addr; + memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); + } + default_sw_reg_flag(hw_dev->isp[i]); + } + rkisp_hw_enum_isp_size(hw_dev); + hw_dev->monitor.is_en = rkisp_monitor; + } else { + /* system resume */ + for (i = 0; i < hw_dev->dev_num; i++) { + if (hw_dev->isp_size[i].is_on) { + rkisp_hw_reg_restore(hw_dev); + break; + } } - default_sw_reg_flag(hw_dev->isp[i]); } - rkisp_hw_enum_isp_size(hw_dev); - hw_dev->monitor.is_en = rkisp_monitor; return 0; } static const struct dev_pm_ops rkisp_hw_pm_ops = { - SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, - rkisp_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, rkisp_runtime_resume, NULL) }; static struct platform_driver rkisp_hw_drv = { diff --git a/drivers/media/platform/rockchip/isp/hw.h b/drivers/media/platform/rockchip/isp/hw.h index 5c7129463101..657c77c0f937 100644 --- a/drivers/media/platform/rockchip/isp/hw.h +++ b/drivers/media/platform/rockchip/isp/hw.h @@ -29,7 +29,6 @@ struct rkisp_monitor { struct rkisp_hw_dev *dev; struct work_struct work; struct completion cmpl; - int (*reset_handle)(struct rkisp_device *dev); u32 state; u8 retry; bool is_en; @@ -53,6 +52,7 @@ struct rkisp_hw_dev { struct platform_device *pdev; struct device *dev; struct regmap *grf; + void *sw_reg; void __iomem *base_addr; void __iomem *base_next_addr; struct clk *clks[RKISP_MAX_BUS_CLK]; @@ -110,4 +110,6 @@ struct rkisp_hw_dev { int rkisp_register_irq(struct rkisp_hw_dev *dev); void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure); void rkisp_hw_enum_isp_size(struct rkisp_hw_dev *hw_dev); +void rkisp_hw_reg_save(struct rkisp_hw_dev *dev); +void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev); #endif diff --git a/drivers/media/platform/rockchip/isp/isp_external.h b/drivers/media/platform/rockchip/isp/isp_external.h index 6e117d40cd4b..3fc155fd03c4 100644 --- a/drivers/media/platform/rockchip/isp/isp_external.h +++ b/drivers/media/platform/rockchip/isp/isp_external.h @@ -13,6 +13,9 @@ #define RKISP_VICAP_CMD_RX_BUFFER_FREE \ _IOW('V', BASE_VIDIOC_PRIVATE + 2, struct rkisp_rx_buf) +#define RKISP_VICAP_CMD_QUICK_STREAM \ + _IOW('V', BASE_VIDIOC_PRIVATE + 3, int) + #define RKISP_VICAP_BUF_CNT 3 #define RKISP_VICAP_BUF_CNT_MAX 8 #define RKISP_RX_BUF_POOL_MAX (RKISP_VICAP_BUF_CNT_MAX * 3) diff --git a/drivers/media/platform/rockchip/isp/isp_params.c b/drivers/media/platform/rockchip/isp/isp_params.c index 3db85a23c220..cbfcf581424d 100644 --- a/drivers/media/platform/rockchip/isp/isp_params.c +++ b/drivers/media/platform/rockchip/isp/isp_params.c @@ -185,6 +185,28 @@ static void rkisp_params_vb2_buf_queue(struct vb2_buffer *vb) spin_lock_irqsave(¶ms_vdev->config_lock, flags); list_add_tail(¶ms_buf->queue, ¶ms_vdev->params); spin_unlock_irqrestore(¶ms_vdev->config_lock, flags); + + if (params_vdev->dev->is_first_double) { + struct isp32_isp_params_cfg *params = params_buf->vaddr[0]; + struct rkisp_buffer *buf; + + if (!(params->module_cfg_update & ISP32_MODULE_RTT_FST)) + return; + spin_lock_irqsave(¶ms_vdev->config_lock, flags); + while (!list_empty(¶ms_vdev->params)) { + buf = list_first_entry(¶ms_vdev->params, + struct rkisp_buffer, queue); + if (buf == params_buf) + break; + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } + spin_unlock_irqrestore(¶ms_vdev->config_lock, flags); + dev_info(params_vdev->dev->dev, + "first params:%d for rtt resume\n", params->frame_id); + params_vdev->dev->is_first_double = false; + rkisp_trigger_read_back(params_vdev->dev, false, false, false); + } } static void rkisp_params_vb2_stop_streaming(struct vb2_queue *vq) @@ -368,15 +390,16 @@ void rkisp_params_cfg(struct rkisp_isp_params_vdev *params_vdev, u32 frame_id) params_vdev->ops->param_cfg(params_vdev, frame_id, RKISP_PARAMS_IMD); } -void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev) +void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev, bool is_check) { - if (params_vdev->dev->procfs.mode & RKISP_PROCFS_FIL_SW) - return; - - /* multi device to switch sram config */ - if (params_vdev->dev->hw_dev->is_single) - return; + if (is_check) { + if (params_vdev->dev->procfs.mode & RKISP_PROCFS_FIL_SW) + return; + /* multi device to switch sram config */ + if (params_vdev->dev->hw_dev->is_single) + return; + } if (params_vdev->ops->param_cfgsram) params_vdev->ops->param_cfgsram(params_vdev); } diff --git a/drivers/media/platform/rockchip/isp/isp_params.h b/drivers/media/platform/rockchip/isp/isp_params.h index d38c0dffb6bf..2d58aba98d16 100644 --- a/drivers/media/platform/rockchip/isp/isp_params.h +++ b/drivers/media/platform/rockchip/isp/isp_params.h @@ -140,7 +140,7 @@ void rkisp_params_isr(struct rkisp_isp_params_vdev *params_vdev, u32 isp_mis); void rkisp_params_cfg(struct rkisp_isp_params_vdev *params_vdev, u32 frame_id); -void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev); +void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev, bool is_check); void rkisp_params_get_meshbuf_inf(struct rkisp_isp_params_vdev *params_vdev, void *meshbuf); int rkisp_params_set_meshbuf_size(struct rkisp_isp_params_vdev *params_vdev, void *meshsize); void rkisp_params_meshbuf_free(struct rkisp_isp_params_vdev *params_vdev, u64 id); diff --git a/drivers/media/platform/rockchip/isp/isp_params_v21.c b/drivers/media/platform/rockchip/isp/isp_params_v21.c index 19f2a6228499..509554d63532 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v21.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v21.c @@ -460,10 +460,9 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, { int i, j; unsigned int sram_addr; - unsigned int data; + unsigned int data = rkisp_ioread32(params_vdev, ISP_LSC_CTRL); - if (is_check && - !(rkisp_ioread32(params_vdev, ISP_LSC_CTRL) & ISP_LSC_EN)) + if (is_check && (data & ISP_LSC_LUT_EN || !(data & ISP_LSC_EN))) return; /* CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ @@ -603,12 +602,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev, * readback mode lsc lut AHB config to sram, once for single device, * need record to switch for multi-device. */ - if (!IS_HDR_RDBK(dev->rd_mode)) + if (!IS_HDR_RDBK(dev->rd_mode)) { isp_lsc_matrix_cfg_ddr(params_vdev, arg); - else if (dev->hw_dev->is_single) - isp_lsc_matrix_cfg_sram(params_vdev, arg, false); - else + } else { + if (dev->hw_dev->is_single) + isp_lsc_matrix_cfg_sram(params_vdev, arg, false); params_rec->others.lsc_cfg = *arg; + } for (i = 0; i < 4; i++) { /* program x size tables */ @@ -1327,8 +1327,8 @@ isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, (arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | (arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | (arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24, - rkisp_iowrite32(params_vdev, val, ISP21_RAWAWB_WRAM_DATA_BASE); + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24; + rkisp_write(params_vdev->dev, ISP21_RAWAWB_WRAM_DATA_BASE, val, true); } } @@ -2143,10 +2143,9 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev, if (params_vdev->dev->hw_dev->is_single) isp_rawawb_cfg_sram(params_vdev, arg, false); - else - memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, - arg->sw_rawawb_wp_blk_wei_w, - ISP21_RAWAWB_WEIGHT_NUM); + memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, + arg->sw_rawawb_wp_blk_wei_w, + ISP21_RAWAWB_WEIGHT_NUM); /* avoid to override the old enable value */ value = rkisp_ioread32(params_vdev, ISP21_RAWAWB_CTRL); @@ -2370,8 +2369,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/isp_params_v2x.c b/drivers/media/platform/rockchip/isp/isp_params_v2x.c index b4525b378a6a..2877ab1d2fd8 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v2x.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v2x.c @@ -536,10 +536,9 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, { int i, j; unsigned int sram_addr; - unsigned int data; + unsigned int data = rkisp_ioread32(params_vdev, ISP_LSC_CTRL); - if (is_check && - !(rkisp_ioread32(params_vdev, ISP_LSC_CTRL) & ISP_LSC_EN)) + if (is_check && (data & ISP_LSC_LUT_EN || !(data & ISP_LSC_EN))) return; /* CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ @@ -679,12 +678,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev, * readback mode lsc lut AHB config to sram, once for single device, * need record to switch for multi-device. */ - if (!IS_HDR_RDBK(dev->rd_mode)) + if (!IS_HDR_RDBK(dev->rd_mode)) { isp_lsc_matrix_cfg_ddr(params_vdev, arg); - else if (dev->hw_dev->is_single) - isp_lsc_matrix_cfg_sram(params_vdev, arg, false); - else + } else { params_rec->others.lsc_cfg = *arg; + if (dev->hw_dev->is_single) + isp_lsc_matrix_cfg_sram(params_vdev, arg, false); + } for (i = 0; i < 4; i++) { /* program x size tables */ @@ -2910,8 +2910,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/isp_params_v32.c b/drivers/media/platform/rockchip/isp/isp_params_v32.c index 4343412c111c..255451cf7fee 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v32.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v32.c @@ -555,11 +555,11 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, bool is_check, u32 id) { struct rkisp_device *dev = params_vdev->dev; - u32 sram_addr, data, table; + u32 data = isp3_param_read(params_vdev, ISP3X_LSC_CTRL, id); + u32 sram_addr, table; int i, j; - if (is_check && - !(isp3_param_read(params_vdev, ISP3X_LSC_CTRL, id) & ISP_LSC_EN)) + if (is_check && (data & ISP3X_LSC_LUT_EN || !(data & ISP_LSC_EN))) return; table = isp3_param_read_direct(params_vdev, ISP3X_LSC_STATUS); @@ -643,12 +643,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev, * readback mode lsc lut AHB config to sram, once for single device, * need record to switch for multi-device. */ - if (!IS_HDR_RDBK(dev->rd_mode)) + if (!IS_HDR_RDBK(dev->rd_mode)) { isp_lsc_matrix_cfg_ddr(params_vdev, arg); - else if (dev->hw_dev->is_single) - isp_lsc_matrix_cfg_sram(params_vdev, arg, false, id); - else + } else { + if (dev->hw_dev->is_single) + isp_lsc_matrix_cfg_sram(params_vdev, arg, false, id); params_rec->others.lsc_cfg = *arg; + } } else { /* two lsc sram table */ params_rec->others.lsc_cfg = *arg; @@ -1576,20 +1577,19 @@ static void isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, const struct isp32_rawawb_meas_cfg *arg, bool is_check, u32 id) { - u32 i, val = ISP32_MODULE_EN; + u32 i, val = isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id); - if (params_vdev->dev->isp_ver == ISP_V32 && is_check && - !(isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id) & val)) + if (params_vdev->dev->isp_ver != ISP_V32 || + (is_check && !(val & ISP32_MODULE_EN))) return; for (i = 0; i < ISP32_RAWAWB_WEIGHT_NUM / 5; i++) { - isp3_param_write_direct(params_vdev, - (arg->wp_blk_wei_w[5 * i] & 0x3f) | - (arg->wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | - (arg->wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | - (arg->wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | - (arg->wp_blk_wei_w[5 * i + 4] & 0x3f) << 24, - ISP3X_RAWAWB_WRAM_DATA_BASE); + val = (arg->wp_blk_wei_w[5 * i] & 0x3f) | + (arg->wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | + (arg->wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | + (arg->wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | + (arg->wp_blk_wei_w[5 * i + 4] & 0x3f) << 24; + isp3_param_write_direct(params_vdev, val, ISP3X_RAWAWB_WRAM_DATA_BASE); } } @@ -2255,9 +2255,7 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev, if (params_vdev->dev->isp_ver == ISP_V32) { if (params_vdev->dev->hw_dev->is_single) isp_rawawb_cfg_sram(params_vdev, arg, false, id); - else - memcpy(arg_rec->wp_blk_wei_w, arg->wp_blk_wei_w, - ISP32_RAWAWB_WEIGHT_NUM); + memcpy(arg_rec->wp_blk_wei_w, arg->wp_blk_wei_w, ISP32_RAWAWB_WEIGHT_NUM); } else { for (i = 0; i < ISP32L_RAWAWB_WEIGHT_NUM; i++) isp3_param_write(params_vdev, arg->win_weight[i], @@ -2503,8 +2501,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false, id); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/isp_params_v3x.c b/drivers/media/platform/rockchip/isp/isp_params_v3x.c index bd1e557eb5e8..2478c09d7062 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v3x.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v3x.c @@ -1430,13 +1430,12 @@ isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, return; for (i = 0; i < ISP3X_RAWAWB_WEIGHT_NUM / 5; i++) { - isp3_param_write(params_vdev, - (arg->sw_rawawb_wp_blk_wei_w[5 * i] & 0x3f) << 0 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24, - ISP3X_RAWAWB_WRAM_DATA_BASE, id); + val = (arg->sw_rawawb_wp_blk_wei_w[5 * i] & 0x3f) << 0 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24; + isp3_param_write_direct(params_vdev, val, ISP3X_RAWAWB_WRAM_DATA_BASE, id); } } @@ -2288,10 +2287,9 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev, if (params_vdev->dev->hw_dev->is_single) isp_rawawb_cfg_sram(params_vdev, arg, false, id); - else - memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, - arg->sw_rawawb_wp_blk_wei_w, - ISP3X_RAWAWB_WEIGHT_NUM); + memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, + arg->sw_rawawb_wp_blk_wei_w, + ISP3X_RAWAWB_WEIGHT_NUM); /* avoid to override the old enable value */ value = isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id); @@ -2502,8 +2500,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false, id); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/isp_rockit.c b/drivers/media/platform/rockchip/isp/isp_rockit.c index 44a5acd30ff4..8a40d09e506d 100644 --- a/drivers/media/platform/rockchip/isp/isp_rockit.c +++ b/drivers/media/platform/rockchip/isp/isp_rockit.c @@ -229,6 +229,11 @@ int rkisp_rockit_buf_done(struct rkisp_stream *stream, int cmd) rockit_cfg->frame.u64PTS = stream->curr_buf->vb.vb2_buf.timestamp; rockit_cfg->frame.u32TimeRef = stream->curr_buf->vb.sequence; + v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev, + "%s stream:%d seq:%d buf:0x%x done\n", + __func__, stream->id, + stream->curr_buf->vb.sequence, + stream->curr_buf->buff_addr[0]); } else { if (stream->ispdev->cap_dev.wrap_line && stream->id == RKISP_STREAM_MP) { diff --git a/drivers/media/platform/rockchip/isp/isp_stats_v32.c b/drivers/media/platform/rockchip/isp/isp_stats_v32.c index cd0a4907846d..79317e618620 100644 --- a/drivers/media/platform/rockchip/isp/isp_stats_v32.c +++ b/drivers/media/platform/rockchip/isp/isp_stats_v32.c @@ -628,6 +628,9 @@ rkisp_stats_send_meas(struct rkisp_isp_stats_vdev *stats_vdev, ops->get_vsm_stats(stats_vdev, cur_stat_buf); } + if (cur_stat_buf && stats_vdev->dev->is_first_double) + cur_stat_buf->meas_type |= ISP32_STAT_RTT_FST; + if (is_dummy) { spin_lock_irqsave(&stats_vdev->rd_lock, flags); if (!list_empty(&stats_vdev->stat)) { diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index e08f7b685552..fde2617f5049 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -87,12 +87,6 @@ static void rkisp_config_cmsk(struct rkisp_device *dev); -struct backup_reg { - const u32 base; - const u32 shd; - u32 val; -}; - static inline struct rkisp_device *sd_to_isp_dev(struct v4l2_subdev *sd) { return container_of(sd->v4l2_dev, struct rkisp_device, v4l2_dev); @@ -717,7 +711,7 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo params_vdev->rdbk_times = dma2frm + 1; run_next: - rkisp_params_cfgsram(params_vdev); + rkisp_params_cfgsram(params_vdev, true); stats_vdev->rdbk_drop = false; if (dev->is_frame_double) { is_upd = true; @@ -866,6 +860,9 @@ static void rkisp_fast_switch_rx_buf(struct rkisp_device *dev, bool is_current) struct rkisp_buffer *buf; u32 i, val; + if (!dev->is_rtt_first) + return; + for (i = RKISP_STREAM_RAWRD0; i < RKISP_MAX_DMARX_STREAM; i++) { stream = &dev->dmarx_dev.stream[i]; if (!stream->ops) @@ -930,11 +927,16 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) goto end; if (!IS_HDR_RDBK(dev->rd_mode)) goto end; + if (dev->is_suspend) { + if (dev->suspend_sync) + complete(&dev->pm_cmpl); + goto end; + } for (i = 0; i < hw->dev_num; i++) { isp = hw->isp[i]; if (!isp || - (isp && !(isp->isp_state & ISP_START))) + (isp && (!(isp->isp_state & ISP_START) || isp->is_suspend))) continue; rkisp_rdbk_trigger_event(isp, T_CMD_LEN, &len[i]); if (max < len[i]) { @@ -944,7 +946,7 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) } /* wait 2 frame to start isp for fast */ - if (dev->is_pre_on && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq)) + if (dev->is_rtt_first && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq)) goto end; if (max) { @@ -990,7 +992,7 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) /* first frame handle twice for thunderboot * first output stats to AIQ and wait new params to run second */ - if (isp->is_pre_on && t.frame_id == 0) { + if (isp->is_rtt_first && t.frame_id == 0) { isp->is_first_double = true; isp->skip_frame = 1; if (hw->unite != ISP_UNITE_ONE) { @@ -998,6 +1000,8 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) isp->is_frame_double = false; } rkisp_fast_switch_rx_buf(isp, false); + } else { + isp->is_rtt_first = false; } isp->params_vdev.rdbk_times = isp->sw_rd_cnt + 1; } @@ -1076,6 +1080,7 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq) if (dev->is_first_double) { rkisp_fast_switch_rx_buf(dev, true); + dev->is_rtt_first = false; dev->skip_frame = 0; dev->irq_ends = 0; return; @@ -1167,86 +1172,19 @@ static void rkisp_config_ism(struct rkisp_device *dev) rkisp_write(dev, CIF_ISP_IS_CTRL, 1, false); } -static int rkisp_reset_handle_v2x(struct rkisp_device *dev) +static int rkisp_reset_handle(struct rkisp_device *dev) { - void __iomem *base = dev->base_addr; - void *reg_buf = NULL; - u32 *reg, *reg1, i; - struct backup_reg backup[] = { - { - .base = MI_MP_WR_Y_BASE, - .shd = MI_MP_WR_Y_BASE_SHD, - }, { - .base = MI_MP_WR_CB_BASE, - .shd = MI_MP_WR_CB_BASE_SHD, - }, { - .base = MI_MP_WR_CR_BASE, - .shd = MI_MP_WR_CR_BASE_SHD, - }, { - .base = MI_SP_WR_Y_BASE, - .shd = MI_SP_WR_Y_BASE_SHD, - }, { - .base = MI_SP_WR_CB_BASE, - .shd = MI_SP_WR_CB_BASE_AD_SHD, - }, { - .base = MI_SP_WR_CR_BASE, - .shd = MI_SP_WR_CR_BASE_AD_SHD, - }, { - .base = MI_RAW0_WR_BASE, - .shd = MI_RAW0_WR_BASE_SHD, - }, { - .base = MI_RAW1_WR_BASE, - .shd = MI_RAW1_WR_BASE_SHD, - }, { - .base = MI_RAW2_WR_BASE, - .shd = MI_RAW2_WR_BASE_SHD, - }, { - .base = MI_RAW3_WR_BASE, - .shd = MI_RAW3_WR_BASE_SHD, - }, { - .base = MI_RAW0_RD_BASE, - .shd = MI_RAW0_RD_BASE_SHD, - }, { - .base = MI_RAW1_RD_BASE, - .shd = MI_RAW1_RD_BASE_SHD, - }, { - .base = MI_RAW2_RD_BASE, - .shd = MI_RAW2_RD_BASE_SHD, - }, { - .base = MI_GAIN_WR_BASE, - .shd = MI_GAIN_WR_BASE_SHD, - } - }; - - reg_buf = kzalloc(RKISP_ISP_SW_REG_SIZE, GFP_KERNEL); - if (!reg_buf) - return -ENOMEM; + u32 val; dev_info(dev->dev, "%s enter\n", __func__); + rkisp_hw_reg_save(dev->hw_dev); - memcpy_fromio(reg_buf, base, RKISP_ISP_SW_REG_SIZE); rkisp_soft_reset(dev->hw_dev, true); - /* process special reg */ - reg = reg_buf + ISP_CTRL; - *reg &= ~(CIF_ISP_CTRL_ISP_ENABLE | - CIF_ISP_CTRL_ISP_INFORM_ENABLE | - CIF_ISP_CTRL_ISP_CFG_UPD); - reg = reg_buf + MI_WR_INIT; - *reg = 0; - reg = reg_buf + CSI2RX_CTRL0; - *reg &= ~SW_CSI2RX_EN; - /* skip mmu range */ - memcpy_toio(base, reg_buf, ISP21_MI_BAY3D_RD_BASE_SHD); - memcpy_toio(base + CSI2RX_CTRL0, reg_buf + CSI2RX_CTRL0, - RKISP_ISP_SW_REG_SIZE - CSI2RX_CTRL0); - /* config shd_reg to base_reg */ - for (i = 0; i < ARRAY_SIZE(backup); i++) { - reg = reg_buf + backup[i].base; - reg1 = reg_buf + backup[i].shd; - backup[i].val = *reg; - writel(*reg1, base + backup[i].base); - } + rkisp_hw_reg_restore(dev->hw_dev); + + val = CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR; + rkisp_unite_set_bits(dev, CIF_ISP_IMSC, 0, val, true); /* clear state */ dev->isp_err_cnt = 0; @@ -1254,40 +1192,12 @@ static int rkisp_reset_handle_v2x(struct rkisp_device *dev) rkisp_set_state(&dev->isp_state, ISP_FRAME_END); dev->hw_dev->monitor.state = ISP_FRAME_END; - /* update module */ - reg = reg_buf + DUAL_CROP_CTRL; - if (*reg & 0xf) - writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL); - reg = reg_buf + SELF_RESIZE_CTRL; - if (*reg & 0xf) - writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL); - reg = reg_buf + MAIN_RESIZE_CTRL; - if (*reg & 0xf) - writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL); - - /* update mi and isp, base_reg will update to shd_reg */ - force_cfg_update(dev); - reg = reg_buf + ISP_CTRL; - *reg |= CIF_ISP_CTRL_ISP_ENABLE | - CIF_ISP_CTRL_ISP_INFORM_ENABLE | - CIF_ISP_CTRL_ISP_CFG_UPD; - writel(*reg, base + ISP_CTRL); - udelay(50); - /* config base_reg */ - for (i = 0; i < ARRAY_SIZE(backup); i++) - writel(backup[i].val, base + backup[i].base); - /* mpfbc base_reg = shd_reg, write is base but read is shd */ - if (dev->isp_ver == ISP_V20) - writel(rkisp_read_reg_cache(dev, ISP_MPFBC_HEAD_PTR), - base + ISP_MPFBC_HEAD_PTR); - rkisp_set_bits(dev, CIF_ISP_IMSC, 0, CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR, true); if (IS_HDR_RDBK(dev->hdr.op_mode)) { if (!dev->hw_dev->is_idle) rkisp_trigger_read_back(dev, 1, 0, true); else rkisp_rdbk_trigger_event(dev, T_CMD_QUEUE, NULL); } - kfree(reg_buf); dev_info(dev->dev, "%s exit\n", __func__); return 0; } @@ -1301,11 +1211,6 @@ static void rkisp_restart_monitor(struct work_struct *work) struct rkisp_pipeline *p; int ret, i, j, timeout = 5, mipi_irq_cnt = 0; - if (!monitor->reset_handle) { - monitor->is_en = false; - return; - } - dev_info(hw->dev, "%s enter\n", __func__); while (!(monitor->state & ISP_STOP) && monitor->is_en) { ret = wait_for_completion_timeout(&monitor->cmpl, @@ -1363,7 +1268,7 @@ static void rkisp_restart_monitor(struct work_struct *work) /* restart isp */ isp = hw->isp[hw->cur_dev_id]; - ret = monitor->reset_handle(isp); + ret = rkisp_reset_handle(isp); if (ret) { monitor->is_en = false; break; @@ -1400,9 +1305,6 @@ static void rkisp_monitor_init(struct rkisp_device *dev) struct rkisp_monitor *monitor = &dev->hw_dev->monitor; monitor->dev = dev->hw_dev; - monitor->reset_handle = NULL; - if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) - monitor->reset_handle = rkisp_reset_handle_v2x; init_completion(&monitor->cmpl); INIT_WORK(&monitor->work, rkisp_restart_monitor); @@ -3105,7 +3007,8 @@ static int rkisp_rx_buf_pool_init(struct rkisp_device *dev, pool->dbufs = dbufs; v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, - "%s type:0x%x dbufs[%d]:%p", __func__, dbufs->type, i, dbufs); + "%s type:0x%x first:%d dbufs[%d]:%p", __func__, + dbufs->type, dbufs->is_first, i, dbufs); if (dbufs->is_resmem) { dma = dbufs->dma; @@ -3491,7 +3394,7 @@ static long rkisp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) rkisp_get_info(isp_dev, arg); break; case RKISP_CMD_GET_TB_HEAD_V32: - if (isp_dev->tb_head.complete != RKISP_TB_OK || !isp_dev->is_pre_on) { + if (isp_dev->tb_head.complete != RKISP_TB_OK) { ret = -EINVAL; break; } @@ -3811,6 +3714,7 @@ int rkisp_register_isp_subdev(struct rkisp_device *isp_dev, atomic_set(&isp_sdev->frm_sync_seq, 0); rkisp_monitor_init(isp_dev); INIT_WORK(&isp_dev->rdbk_work, rkisp_rdbk_work); + init_completion(&isp_dev->pm_cmpl); return 0; err_cleanup_media_entity: media_entity_cleanup(&sd->entity); @@ -3850,8 +3754,7 @@ void rkisp_unregister_isp_subdev(struct rkisp_device *isp_dev) (cond) ? 0 : -ETIMEDOUT; \ }) -#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP -static void rkisp_save_tb_info(struct rkisp_device *isp_dev) +void rkisp_save_tb_info(struct rkisp_device *isp_dev) { struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev; void *resmem_va = phys_to_virt(isp_dev->resmem_pa); @@ -3871,7 +3774,8 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev) if (size && size < isp_dev->resmem_size) { dma_sync_single_for_cpu(isp_dev->dev, isp_dev->resmem_addr + offset, size, DMA_FROM_DEVICE); - params_vdev->is_first_cfg = true; + if (isp_dev->is_rtt_first) + params_vdev->is_first_cfg = true; if (isp_dev->isp_ver == ISP_V32) { struct rkisp32_thunderboot_resmem_head *tmp = resmem_va + offset; @@ -3883,7 +3787,7 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev) tmp->cfg.module_ens, tmp->cfg.module_cfg_update); } - if (param) + if (param && (isp_dev->isp_state & ISP_STOP)) params_vdev->ops->save_first_param(params_vdev, param); } else if (size > isp_dev->resmem_size) { v4l2_err(&isp_dev->v4l2_dev, @@ -3894,6 +3798,7 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev) memcpy(&isp_dev->tb_head, head, sizeof(*head)); } +#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP void rkisp_chk_tb_over(struct rkisp_device *isp_dev) { struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev; @@ -3941,11 +3846,10 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev) end: head = &isp_dev->tb_head; v4l2_info(&isp_dev->v4l2_dev, - "thunderboot info: %d, %d, %d, %d, %d, %d | %d %d\n", + "tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d\n", head->enable, head->complete, head->frm_total, - head->hdr_mode, head->width, head->height, head->camera_num, diff --git a/drivers/media/platform/rockchip/isp/rkisp.h b/drivers/media/platform/rockchip/isp/rkisp.h index 54f32b9685c3..76f8ce05e424 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.h +++ b/drivers/media/platform/rockchip/isp/rkisp.h @@ -153,6 +153,8 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev); static inline void rkisp_chk_tb_over(struct rkisp_device *isp_dev) {} #endif +void rkisp_save_tb_info(struct rkisp_device *isp_dev); + void rkisp_mipi_isr(unsigned int mipi_mis, struct rkisp_device *dev); void rkisp_mipi_v13_isr(unsigned int err1, unsigned int err2, diff --git a/drivers/mfd/display-serdes/core.h b/drivers/mfd/display-serdes/core.h index 28f994588964..e05ff39236c3 100644 --- a/drivers/mfd/display-serdes/core.h +++ b/drivers/mfd/display-serdes/core.h @@ -334,7 +334,8 @@ int serdes_set_pinctrl_default(struct serdes *serdes); int serdes_set_pinctrl_sleep(struct serdes *serdes); int serdes_device_suspend(struct serdes *serdes); int serdes_device_resume(struct serdes *serdes); -void serdes_device_shutdown(struct serdes *serdes); +void serdes_device_poweroff(struct serdes *serdes); +int serdes_device_shutdown(struct serdes *serdes); int serdes_irq_init(struct serdes *serdes); void serdes_irq_exit(struct serdes *serdes); void serdes_auxadc_init(struct serdes *serdes); diff --git a/drivers/mfd/display-serdes/serdes-core.c b/drivers/mfd/display-serdes/serdes-core.c index 5ef62f8e4d75..08805244f928 100644 --- a/drivers/mfd/display-serdes/serdes-core.c +++ b/drivers/mfd/display-serdes/serdes-core.c @@ -376,7 +376,7 @@ int serdes_device_resume(struct serdes *serdes) } EXPORT_SYMBOL_GPL(serdes_device_resume); -void serdes_device_shutdown(struct serdes *serdes) +void serdes_device_poweroff(struct serdes *serdes) { int ret = 0; @@ -385,6 +385,29 @@ void serdes_device_shutdown(struct serdes *serdes) if (ret) dev_err(serdes->dev, "could not set sleep pins\n"); } + + if (!IS_ERR(serdes->vpower)) { + ret = regulator_disable(serdes->vpower); + if (ret) + dev_err(serdes->dev, "fail to disable vpower regulator\n"); + } + +} +EXPORT_SYMBOL_GPL(serdes_device_poweroff); + +int serdes_device_shutdown(struct serdes *serdes) +{ + int ret = 0; + + if (!IS_ERR(serdes->vpower)) { + ret = regulator_disable(serdes->vpower); + if (ret) { + dev_err(serdes->dev, "fail to disable vpower regulator\n"); + return ret; + } + } + + return ret; } EXPORT_SYMBOL_GPL(serdes_device_shutdown); diff --git a/drivers/mfd/display-serdes/serdes-i2c.c b/drivers/mfd/display-serdes/serdes-i2c.c index 237b1e61ded4..c95469bc07bb 100644 --- a/drivers/mfd/display-serdes/serdes-i2c.c +++ b/drivers/mfd/display-serdes/serdes-i2c.c @@ -223,6 +223,14 @@ static int serdes_i2c_probe(struct i2c_client *client, return 0; } +static void serdes_i2c_shutdown(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct serdes *serdes = dev_get_drvdata(dev); + + serdes_device_shutdown(serdes); +} + static int serdes_i2c_prepare(struct device *dev) { return 0; @@ -264,7 +272,7 @@ static int serdes_i2c_poweroff(struct device *dev) { struct serdes *serdes = dev_get_drvdata(dev); - serdes_device_shutdown(serdes); + serdes_device_poweroff(serdes); return 0; } @@ -315,6 +323,7 @@ static struct i2c_driver serdes_i2c_driver = { .of_match_table = of_match_ptr(serdes_of_match), }, .probe = serdes_i2c_probe, + .shutdown = serdes_i2c_shutdown, }; static int __init serdes_i2c_init(void) diff --git a/drivers/mtd/nand/bbt_store.c b/drivers/mtd/nand/bbt_store.c index 37b4708749d8..8687861bf3b4 100644 --- a/drivers/mtd/nand/bbt_store.c +++ b/drivers/mtd/nand/bbt_store.c @@ -8,18 +8,78 @@ #include #ifdef BBT_DEBUG -#define BBT_DBG pr_err +#define bbt_dbg pr_err #else -#define BBT_DBG(args...) +#define bbt_dbg(args...) #endif +#define BBT_VERSION_INVALID (0xFFFFFFFFU) +#define BBT_VERSION_BLOCK_ABNORMAL (BBT_VERSION_INVALID - 1) +#define BBT_VERSION_MAX (BBT_VERSION_INVALID - 8) + struct nanddev_bbt_info { u8 pattern[4]; unsigned int version; + u32 hash; }; static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) +static void bbt_dbg_hex(char *s, void *buf, u32 len) +{ + print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, 4, 4, buf, len, 0); +} +#endif + +static u32 js_hash(u8 *buf, u32 len) +{ + u32 hash = 0x47C6A7E6; + u32 i; + + for (i = 0; i < len; i++) + hash ^= ((hash << 5) + buf[i] + (hash >> 2)); + + return hash; +} + +static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp) +{ + u32 hash; + + /* compatible with no-hash version */ + if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF) + return 1; + + hash = js_hash(buf, len); + if (hash != hash_cmp) + return 0; + + return 1; +} + +static u32 bbt_nand_isbad_bypass(struct nand_device *nand, u32 block) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + struct nand_pos pos; + + nanddev_bbt_set_block_status(nand, block, NAND_BBT_BLOCK_STATUS_UNKNOWN); + nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos); + + return nanddev_isbad(nand, &pos); +} + +/** + * nanddev_read_bbt() - Read the BBT (Bad Block Table) + * @nand: NAND device + * @block: bbt block address + * @update: true - get version and overwrite bbt.cache with new version; + * false - get bbt version only; + * + * Initialize the in-memory BBT. + * + * Return: 0 in case of success, a negative error code otherwise. + */ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) { unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); @@ -30,7 +90,7 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; - int bbt_page_num; + u32 bbt_page_num; int ret = 0; unsigned int version = 0; @@ -40,7 +100,7 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) if (block >= nblocks) return -EINVAL; - /* Aligned to page size, and even pages is better */ + /* aligned to page size, and even pages is better */ bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes + mtd->writesize - 1) >> (ffs(mtd->writesize) - 1); bbt_page_num = (bbt_page_num + 1) / 2 * 2; @@ -64,29 +124,72 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) ops.ooblen = bbt_page_num * mtd->oobsize; ops.ooboffs = 0; + /* store one entry for each block */ ret = mtd_read_oob(mtd, block * mtd->erasesize, &ops); if (ret && ret != -EUCLEAN) { - pr_err("%s fail %d\n", __func__, ret); - ret = -EIO; + pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; goto out; } else { ret = 0; } - if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4)) - version = bbt_info->version; + /* bad block or good block without bbt */ + if (memcmp(bbt_pattern, bbt_info->pattern, 4)) { + ret = 0; + goto out; + } - BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version); + /* good block with abnornal bbt */ + if (oob_buf[0] == 0xff || + !bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) { + pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; + goto out; + } + + /* good block with good bbt */ + version = bbt_info->version; + bbt_dbg("read_bbt from blk=%d ver=%d update=%d\n", block, version, update); if (update && version > nand->bbt.version) { memcpy(nand->bbt.cache, data_buf, nbytes); nand->bbt.version = version; } -out: - kfree(oob_buf); - kfree(data_buf); +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) + bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info)); + if (version) { + u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL); + bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED; - return ret < 0 ? -EIO : version; + if (!temp_buf) + goto out; + + memcpy(temp_buf, nand->bbt.cache, nbytes); + memcpy(nand->bbt.cache, data_buf, nbytes); + + if (!in_scan) + nand->bbt.option |= NANDDEV_BBT_SCANNED; + for (block = 0; block < nblocks; block++) { + ret = nanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + bbt_dbg("bad block[0x%x], ret=%d\n", block, ret); + } + if (!in_scan) + nand->bbt.option &= ~NANDDEV_BBT_SCANNED; + memcpy(nand->bbt.cache, temp_buf, nbytes); + kfree(temp_buf); + ret = 0; + } +#endif + +out: + kfree(data_buf); + kfree(oob_buf); + + return ret < 0 ? -EIO : (int)version; } static int nanddev_write_bbt(struct nand_device *nand, u32 block) @@ -99,18 +202,18 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block) u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; - int bbt_page_num; - int ret = 0; + u32 bbt_page_num; + int ret = 0, version; struct nand_pos pos; - BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version); + bbt_dbg("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version); if (!nand->bbt.cache) return -ENOMEM; if (block >= nblocks) return -EINVAL; - /* Aligned to page size, and even pages is better */ + /* aligned to page size, and even pages is better */ bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes + mtd->writesize - 1) >> (ffs(mtd->writesize) - 1); bbt_page_num = (bbt_page_num + 1) / 2 * 2; @@ -130,7 +233,9 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block) memcpy(data_buf, nand->bbt.cache, nbytes); memcpy(bbt_info, bbt_pattern, 4); bbt_info->version = nand->bbt.version; + bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4); + /* store one entry for each block */ nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos); ret = nand->ops->erase(nand, &pos); if (ret) @@ -144,10 +249,23 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block) ops.ooblen = bbt_page_num * mtd->oobsize; ops.ooboffs = 0; ret = mtd_write_oob(mtd, block * mtd->erasesize, &ops); + if (ret) { + nand->ops->erase(nand, &pos); + goto out; + } + version = nanddev_read_bbt(nand, block, false); + if (version != bbt_info->version) { + pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n", + block, version, bbt_info->version); + nand->ops->erase(nand, &pos); + ret = -EIO; + } else { + ret = 0; + } out: - kfree(oob_buf); kfree(data_buf); + kfree(oob_buf); return ret; } @@ -158,14 +276,30 @@ static int nanddev_bbt_format(struct nand_device *nand) struct mtd_info *mtd = nanddev_to_mtd(nand); struct nand_pos pos; u32 start_block, block; + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block, + BITS_PER_LONG); start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < nblocks; block++) { nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos); - if (nanddev_isbad(nand, &pos)) + if (nanddev_isbad(nand, &pos)) { + if (bbt_nand_isbad_bypass(nand, 0)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test good block %d fail\n", 0); + return -EIO; + } + + if (!bbt_nand_isbad_bypass(nand, block)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test bad block %d fail\n", block); + return -EIO; + } + nanddev_bbt_set_block_status(nand, block, NAND_BBT_BLOCK_FACTORY_BAD); + } } for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { @@ -197,16 +331,34 @@ int nanddev_scan_bbt_in_flash(struct nand_device *nand) for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) nanddev_read_bbt(nand, start_block + block, true); + nand->bbt.option |= NANDDEV_BBT_SCANNED; if (nand->bbt.version == 0) { - nanddev_bbt_format(nand); + ret = nanddev_bbt_format(nand); + if (ret) { + nand->bbt.option = 0; + pr_err("%s format fail\n", __func__); + + return ret; + } ret = nanddev_bbt_in_flash_update(nand); if (ret) { nand->bbt.option = 0; - pr_err("%s fail\n", __func__); + pr_err("%s update fail\n", __func__); + + return ret; } } - nand->bbt.option |= NANDDEV_BBT_SCANNED; +#if defined(BBT_DEBUG) + pr_err("scan_bbt success\n"); + if (nand->bbt.version) { + for (block = 0; block < nblocks; block++) { + ret = nanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + bbt_dbg("bad block[0x%x], ret=%d\n", block, ret); + } + } +#endif return ret; } @@ -222,31 +374,31 @@ EXPORT_SYMBOL_GPL(nanddev_scan_bbt_in_flash); */ int nanddev_bbt_in_flash_update(struct nand_device *nand) { + struct nand_pos pos; + struct mtd_info *mtd = nanddev_to_mtd(nand); + if (nand->bbt.option & NANDDEV_BBT_SCANNED) { unsigned int nblocks = nanddev_neraseblocks(nand); u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS]; int start_block, block; u32 min_version, block_des; - int ret, count = 0; + int ret, count = 0, status; start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { - ret = nanddev_bbt_get_block_status(nand, start_block + block); - if (ret == NAND_BBT_BLOCK_FACTORY_BAD) { - bbt_version[block] = 0xFFFFFFFF; - continue; - } - ret = nanddev_read_bbt(nand, start_block + block, - false); - if (ret < 0) - bbt_version[block] = 0xFFFFFFFF; - else if (ret == 0) - bbt_version[block] = 0; + status = nanddev_bbt_get_block_status(nand, start_block + block); + ret = nanddev_read_bbt(nand, start_block + block, false); + if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == -EIO) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == BBT_VERSION_BLOCK_ABNORMAL) + bbt_version[block] = ret; else bbt_version[block] = ret; } get_min_ver: - min_version = 0xFFFFFFFF; + min_version = BBT_VERSION_MAX; block_des = 0; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { if (bbt_version[block] < min_version) { @@ -255,25 +407,38 @@ get_min_ver: } } + /* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */ + if (nand->bbt.version < min_version) + nand->bbt.version = min_version + 4; + if (block_des > 0) { nand->bbt.version++; ret = nanddev_write_bbt(nand, block_des); - bbt_version[block_des - start_block] = 0xFFFFFFFF; if (ret) { - pr_err("%s blk= %d ret= %d\n", __func__, - block_des, ret); - goto get_min_ver; - } else { - count++; - if (count < 2) - goto get_min_ver; - BBT_DBG("%s success\n", __func__); - } - } else { - pr_err("%s failed\n", __func__); + pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret); - return -EINVAL; + return -1; + } + + bbt_version[block_des - start_block] = BBT_VERSION_INVALID; + count++; + if (count < 2) + goto get_min_ver; + bbt_dbg("bbt_update success\n"); + } else { + pr_err("bbt_update failed\n"); + ret = -1; } + + for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { + if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) { + block_des = start_block + block; + nanddev_offs_to_pos(nand, block_des * mtd->erasesize, &pos); + nand->ops->erase(nand, &pos); + } + } + + return ret; } return 0; diff --git a/drivers/rkflash/sfc_nand_mtd_bbt.c b/drivers/rkflash/sfc_nand_mtd_bbt.c index eb641f89306c..0fce0b994654 100644 --- a/drivers/rkflash/sfc_nand_mtd_bbt.c +++ b/drivers/rkflash/sfc_nand_mtd_bbt.c @@ -21,13 +21,119 @@ #define BBT_DBG(args...) #endif +#define BBT_VERSION_INVALID (0xFFFFFFFFU) +#define BBT_VERSION_BLOCK_ABNORMAL (BBT_VERSION_INVALID - 1) +#define BBT_VERSION_MAX (BBT_VERSION_INVALID - 8) struct nanddev_bbt_info { u8 pattern[4]; unsigned int version; + u32 hash; }; static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) +static void bbt_dbg_hex(char *s, void *buf, u32 len) +{ + print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, 4, 4, buf, len, 0); +} +#endif + +static u32 js_hash(u8 *buf, u32 len) +{ + u32 hash = 0x47C6A7E6; + u32 i; + + for (i = 0; i < len; i++) + hash ^= ((hash << 5) + buf[i] + (hash >> 2)); + + return hash; +} + +static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp) +{ + u32 hash; + + /* compatible with no-hash version */ + if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF) + return 1; + + hash = js_hash(buf, len); + if (hash != hash_cmp) + return 0; + + return 1; +} + +static u32 bbt_nand_isbad_bypass(struct snand_mtd_dev *nand, u32 block) +{ + struct mtd_info *mtd = snanddev_to_mtd(nand); + + return sfc_nand_isbad_mtd(mtd, block * mtd->erasesize); +} + +static int bbt_mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ + int i, ret = 0, bbt_page_num, page_addr, block; + u8 *temp_buf; + + bbt_page_num = ops->len >> mtd->writesize_shift; + block = from >> mtd->erasesize_shift; + + temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + + page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); + for (i = 0; i < bbt_page_num; i++) { + ret = sfc_nand_read_page_raw(0, page_addr + i, (u32 *)temp_buf); + if (ret < 0) { + pr_err("%s fail %d\n", __func__, ret); + ret = -EIO; + goto out; + } + + memcpy(ops->datbuf + i * mtd->writesize, temp_buf, mtd->writesize); + memcpy(ops->oobbuf + i * mtd->oobsize, temp_buf + mtd->writesize, mtd->oobsize); + } + +out: + kfree(temp_buf); + + return ret; +} + +static int bbt_mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) +{ + int i, ret = 0, bbt_page_num, page_addr, block; + u8 *temp_buf; + + bbt_page_num = ops->len >> mtd->writesize_shift; + block = to >> mtd->erasesize_shift; + + temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + + page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); + for (i = 0; i < bbt_page_num; i++) { + memcpy(temp_buf, ops->datbuf + i * mtd->writesize, mtd->writesize); + memcpy(temp_buf + mtd->writesize, ops->oobbuf + i * mtd->oobsize, mtd->oobsize); + + ret = sfc_nand_prog_page_raw(0, page_addr + i, (u32 *)temp_buf); + if (ret < 0) { + pr_err("%s fail %d\n", __func__, ret); + ret = -EIO; + goto out; + } + } + +out: + kfree(temp_buf); + + return ret; +} + /** * nanddev_read_bbt() - Read the BBT (Bad Block Table) * @nand: NAND device @@ -37,7 +143,7 @@ static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; * * Initialize the in-memory BBT. * - * Return: 0 in case of success, a negative error code otherwise. + * Return: positive value means success, 0 means abnornal data, a negative error code otherwise. */ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update) { @@ -46,13 +152,12 @@ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update) unsigned int nbytes = DIV_ROUND_UP(nblocks * bits_per_block, BITS_PER_LONG) * sizeof(*nand->bbt.cache); struct mtd_info *mtd = snanddev_to_mtd(nand); - u8 *data_buf, *oob_buf, *temp_buf; + u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; u32 bbt_page_num; int ret = 0; unsigned int version = 0; - u32 page_addr, i; if (!nand->bbt.cache) return -ENOMEM; @@ -85,37 +190,65 @@ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update) ops.ooboffs = 0; /* Store one entry for each block */ - temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); - if (!temp_buf) { - kfree(data_buf); - kfree(oob_buf); - - return -ENOMEM; + ret = bbt_mtd_read_oob(mtd, block * mtd->erasesize, &ops); + if (ret && ret != -EUCLEAN) { + pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; + goto out; + } else { + ret = 0; } - page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); - for (i = 0; i < bbt_page_num; i++) { - ret = sfc_nand_read_page_raw(0, page_addr + i, (u32 *)temp_buf); - if (ret < 0) { - pr_err("%s fail %d\n", __func__, ret); - ret = -EIO; - kfree(temp_buf); - goto out; - } - - memcpy(ops.datbuf + i * mtd->writesize, temp_buf, mtd->writesize); - memcpy(ops.oobbuf + i * mtd->oobsize, temp_buf + mtd->writesize, mtd->oobsize); + /* bad block or good block without bbt */ + if (memcmp(bbt_pattern, bbt_info->pattern, 4)) { + ret = 0; + goto out; } - kfree(temp_buf); - if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4)) - version = bbt_info->version; + /* good block with abnornal bbt */ + if (oob_buf[0] == 0xff || + !bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) { + pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; + goto out; + } - BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version); + /* good block with good bbt */ + version = bbt_info->version; + BBT_DBG("read_bbt from blk=%d ver=%d update=%d\n", block, version, update); if (update && version > nand->bbt.version) { memcpy(nand->bbt.cache, data_buf, nbytes); nand->bbt.version = version; } +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) + bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info)); + if (version) { + u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL); + bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED; + + if (!temp_buf) + goto out; + + memcpy(temp_buf, nand->bbt.cache, nbytes); + memcpy(nand->bbt.cache, data_buf, nbytes); + + if (!in_scan) + nand->bbt.option |= NANDDEV_BBT_SCANNED; + for (block = 0; block < nblocks; block++) { + ret = snanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + BBT_DBG("bad block[0x%x], ret=%d\n", block, ret); + } + if (!in_scan) + nand->bbt.option &= ~NANDDEV_BBT_SCANNED; + memcpy(nand->bbt.cache, temp_buf, nbytes); + kfree(temp_buf); + ret = 0; + } +#endif + out: kfree(data_buf); kfree(oob_buf); @@ -130,12 +263,11 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block) unsigned int nbytes = DIV_ROUND_UP(nblocks * bits_per_block, BITS_PER_LONG) * sizeof(*nand->bbt.cache); struct mtd_info *mtd = snanddev_to_mtd(nand); - u8 *data_buf, *oob_buf, *temp_buf; + u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; u32 bbt_page_num; - int ret = 0; - u32 page_addr, i; + int ret = 0, version; BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version); if (!nand->bbt.cache) @@ -164,6 +296,7 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block) memcpy(data_buf, nand->bbt.cache, nbytes); memcpy(bbt_info, bbt_pattern, 4); bbt_info->version = nand->bbt.version; + bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4); /* Store one entry for each block */ ret = sfc_nand_erase_mtd(mtd, block * mtd->erasesize); @@ -171,34 +304,27 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block) goto out; memset(&ops, 0, sizeof(struct mtd_oob_ops)); + ops.mode = MTD_OPS_PLACE_OOB; ops.datbuf = data_buf; ops.len = bbt_page_num * mtd->writesize; ops.oobbuf = oob_buf; ops.ooblen = bbt_page_num * mtd->oobsize; ops.ooboffs = 0; - - temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); - if (!temp_buf) { - kfree(data_buf); - kfree(oob_buf); - - return -ENOMEM; + ret = bbt_mtd_write_oob(mtd, block * mtd->erasesize, &ops); + if (ret) { + sfc_nand_erase_mtd(mtd, block * mtd->erasesize); + goto out; } - page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); - for (i = 0; i < bbt_page_num; i++) { - memcpy(temp_buf, ops.datbuf + i * mtd->writesize, mtd->writesize); - memcpy(temp_buf + mtd->writesize, ops.oobbuf + i * mtd->oobsize, mtd->oobsize); - ret = sfc_nand_prog_page_raw(0, page_addr + i, (u32 *)temp_buf); - if (ret < 0) { - pr_err("%s fail %d\n", __func__, ret); - ret = -EIO; - kfree(temp_buf); - goto out; - } + version = nanddev_read_bbt(nand, block, false); + if (version != bbt_info->version) { + pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n", + block, version, bbt_info->version); + sfc_nand_erase_mtd(mtd, block * mtd->erasesize); + ret = -EIO; + } else { + ret = 0; } - kfree(temp_buf); - out: kfree(data_buf); kfree(oob_buf); @@ -211,13 +337,29 @@ static int nanddev_bbt_format(struct snand_mtd_dev *nand) unsigned int nblocks = snanddev_neraseblocks(nand); struct mtd_info *mtd = snanddev_to_mtd(nand); u32 start_block, block; + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block, + BITS_PER_LONG); start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < nblocks; block++) { - if (sfc_nand_isbad_mtd(mtd, block * mtd->erasesize)) + if (sfc_nand_isbad_mtd(mtd, block * mtd->erasesize)) { + if (bbt_nand_isbad_bypass(nand, 0)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test good block %d fail\n", 0); + return -EIO; + } + + if (!bbt_nand_isbad_bypass(nand, block)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test bad block %d fail\n", block); + return -EIO; + } + snanddev_bbt_set_block_status(nand, block, - NAND_BBT_BLOCK_FACTORY_BAD); + NAND_BBT_BLOCK_FACTORY_BAD); + } } for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { @@ -243,14 +385,34 @@ static int nanddev_scan_bbt(struct snand_mtd_dev *nand) nand->bbt.option |= NANDDEV_BBT_SCANNED; if (nand->bbt.version == 0) { - nanddev_bbt_format(nand); + ret = nanddev_bbt_format(nand); + if (ret) { + nand->bbt.option = 0; + pr_err("%s format fail\n", __func__); + + return ret; + } + ret = snanddev_bbt_update(nand); if (ret) { nand->bbt.option = 0; - pr_err("%s fail\n", __func__); + pr_err("%s update fail\n", __func__); + + return ret; } } +#if defined(BBT_DEBUG) + pr_err("scan_bbt success\n"); + if (nand->bbt.version) { + for (block = 0; block < nblocks; block++) { + ret = snanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + BBT_DBG("bad block[0x%x], ret=%d\n", block, ret); + } + } +#endif + return ret; } @@ -304,32 +466,32 @@ EXPORT_SYMBOL_GPL(snanddev_bbt_cleanup); int snanddev_bbt_update(struct snand_mtd_dev *nand) { #ifdef CONFIG_MTD_NAND_BBT_USING_FLASH + struct mtd_info *mtd = snanddev_to_mtd(nand); + if (nand->bbt.cache && nand->bbt.option & NANDDEV_BBT_USE_FLASH) { unsigned int nblocks = snanddev_neraseblocks(nand); u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS]; int start_block, block; u32 min_version, block_des; - int ret, count = 0; + int ret, count = 0, status; start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { - ret = snanddev_bbt_get_block_status(nand, start_block + block); - if (ret == NAND_BBT_BLOCK_FACTORY_BAD) { - bbt_version[block] = 0xFFFFFFFF; - continue; - } - ret = nanddev_read_bbt(nand, start_block + block, - false); - if (ret < 0) - bbt_version[block] = 0xFFFFFFFF; - else if (ret == 0) - bbt_version[block] = 0; + status = snanddev_bbt_get_block_status(nand, start_block + block); + ret = nanddev_read_bbt(nand, start_block + block, false); + + if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == -EIO) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == BBT_VERSION_BLOCK_ABNORMAL) + bbt_version[block] = ret; else bbt_version[block] = ret; } get_min_ver: - min_version = 0xFFFFFFFF; + min_version = BBT_VERSION_MAX; block_des = 0; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { if (bbt_version[block] < min_version) { @@ -338,25 +500,37 @@ get_min_ver: } } + /* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */ + if (nand->bbt.version < min_version) + nand->bbt.version = min_version + 4; + if (block_des > 0) { nand->bbt.version++; ret = nanddev_write_bbt(nand, block_des); - bbt_version[block_des - start_block] = 0xFFFFFFFF; if (ret) { - pr_err("%s blk= %d ret= %d\n", __func__, - block_des, ret); - goto get_min_ver; - } else { - count++; - if (count < 2) - goto get_min_ver; - BBT_DBG("%s success\n", __func__); - } - } else { - pr_err("%s failed\n", __func__); + pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret); - return -1; + return -1; + } + + bbt_version[block_des - start_block] = BBT_VERSION_INVALID; + count++; + if (count < 2) + goto get_min_ver; + BBT_DBG("bbt_update success\n"); + } else { + pr_err("bbt_update failed\n"); + ret = -1; } + + for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { + if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) { + block_des = start_block + block; + sfc_nand_erase_mtd(mtd, block_des * mtd->erasesize); + } + } + + return ret; } #endif return 0; diff --git a/drivers/soc/rockchip/minidump/rk_minidump.c b/drivers/soc/rockchip/minidump/rk_minidump.c index 7fa439746364..0f90fce431e2 100644 --- a/drivers/soc/rockchip/minidump/rk_minidump.c +++ b/drivers/soc/rockchip/minidump/rk_minidump.c @@ -168,6 +168,8 @@ static void md_update_ss_toc(const struct md_region *entry) shdr->sh_flags = SHF_WRITE; shdr->sh_offset = minidump_elfheader.elf_offset; shdr->sh_entsize = 0; + shdr->sh_addralign = shdr->sh_addr; /* backup */ + shdr->sh_entsize = entry->phys_addr; /* backup */ if (strstr((const char *)mdr->name, "note")) phdr->p_type = PT_NOTE; @@ -178,6 +180,7 @@ static void md_update_ss_toc(const struct md_region *entry) phdr->p_paddr = entry->phys_addr; phdr->p_filesz = phdr->p_memsz = mdr->region_size; phdr->p_flags = PF_R | PF_W; + phdr->p_align = phdr->p_paddr; /* backup */ minidump_elfheader.elf_offset += shdr->sh_size; mdr->md_valid = MD_REGION_VALID; minidump_table.md_ss_toc->ss_region_count++; @@ -274,8 +277,11 @@ int rk_minidump_update_region(int regno, const struct md_region *entry) phdr = elf_program(hdr, regno + 1); shdr->sh_addr = (elf_addr_t)entry->virt_addr; + shdr->sh_addralign = shdr->sh_addr; /* backup */ + shdr->sh_entsize = entry->phys_addr; /* backup */ phdr->p_vaddr = entry->virt_addr; phdr->p_paddr = entry->phys_addr; + phdr->p_align = phdr->p_paddr; /* backup */ err_unlock: read_unlock_irqrestore(&mdt_remove_lock, flags); @@ -675,6 +681,8 @@ static int rk_minidump_driver_probe(struct platform_device *pdev) phdr = (Elf64_Phdr *)(md_elf_mem + (ulong)ehdr->e_phoff); phdr += ehdr->e_phnum - 1; md_elf_size = phdr->p_memsz + phdr->p_offset; + if (md_elf_size > r_size) + md_elf_size = r_size; pr_info("Create /proc/rk_md/minidump, size:0x%llx...\n", md_elf_size); proc_rk_minidump = proc_create("minidump", 0400, base_dir, &rk_minidump_proc_ops); } else { diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 5b988961d603..e0b2cd002e3e 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -217,6 +217,10 @@ static int ohci_platform_probe(struct platform_device *dev) device_wakeup_enable(hcd->self.controller); + if (of_device_is_compatible(dev->dev.of_node, + "rockchip,rk3588-ohci")) + device_enable_async_suspend(hcd->self.controller); + platform_set_drvdata(dev, hcd); return err; diff --git a/include/dt-bindings/soc/rockchip,boot-mode.h b/include/dt-bindings/soc/rockchip,boot-mode.h index ec4e5dd83cc1..a0f63a040613 100644 --- a/include/dt-bindings/soc/rockchip,boot-mode.h +++ b/include/dt-bindings/soc/rockchip,boot-mode.h @@ -22,5 +22,7 @@ #define BOOT_UMS (REBOOT_FLAG + 12) /* reboot system quiescent */ #define BOOT_QUIESCENT (REBOOT_FLAG + 14) +/* reboot by panic and capture ramdump in uboot through usb */ +#define BOOT_WINUSB (REBOOT_FLAG + 15) #endif diff --git a/include/uapi/linux/rk-isp2-config.h b/include/uapi/linux/rk-isp2-config.h index 9de8ac7d6e20..fb8254771d92 100644 --- a/include/uapi/linux/rk-isp2-config.h +++ b/include/uapi/linux/rk-isp2-config.h @@ -1968,6 +1968,12 @@ struct rkisp_isp2x_luma_buffer { struct rkisp_mipi_luma luma[ISP2X_MIPI_RAW_MAX]; } __attribute__ ((packed)); +enum { + RKISP_RTT_MODE_NORMAL = 0, + RKISP_RTT_MODE_MULTI_FRAME, + RKISP_RTT_MODE_ONE_FRAME, +}; + /** * struct rkisp_thunderboot_resmem_head */ @@ -1976,10 +1982,12 @@ struct rkisp_thunderboot_resmem_head { __u16 complete; __u16 frm_total; __u16 hdr_mode; + __u16 rtt_mode; __u16 width; __u16 height; __u16 camera_num; __u16 camera_index; + __u16 md_flag; __u32 exp_time[3]; __u32 exp_gain[3]; diff --git a/include/uapi/linux/rk-isp32-config.h b/include/uapi/linux/rk-isp32-config.h index cabd8c191c2d..ecd4eaef2cd3 100644 --- a/include/uapi/linux/rk-isp32-config.h +++ b/include/uapi/linux/rk-isp32-config.h @@ -52,7 +52,7 @@ #define ISP32_MODULE_CSM ISP3X_MODULE_CSM #define ISP32_MODULE_CGC ISP3X_MODULE_CGC #define ISP32_MODULE_VSM BIT_ULL(45) - +#define ISP32_MODULE_RTT_FST BIT_ULL(62) #define ISP32_MODULE_FORCE ISP3X_MODULE_FORCE /* Measurement types */ @@ -70,6 +70,7 @@ #define ISP32_STAT_DHAZ ISP3X_STAT_DHAZ #define ISP32_STAT_VSM BIT(18) #define ISP32_STAT_INFO2DDR BIT(19) +#define ISP32_STAT_RTT_FST BIT(31) #define ISP32_MESH_BUF_NUM ISP3X_MESH_BUF_NUM