diff --git a/Documentation/ABI/testing/sysfs-device-mali b/Documentation/ABI/testing/sysfs-device-mali index 99f8ae57b7c9..b7be50338f6e 100644 --- a/Documentation/ABI/testing/sysfs-device-mali +++ b/Documentation/ABI/testing/sysfs-device-mali @@ -211,6 +211,31 @@ Description: without forward progress to allow to elapse before terminating a GPU command queue group. +What: /sys/class/misc/mali%u/device/mcu_shader_pwroff_timeout +Description: + This attribute is available only with mali platform + device-driver that supports a CSF GPU. The duration value unit + is in micro-seconds and is used for configuring MCU shader Core power-off + timer. The configured MCU shader Core power-off timer will only have + effect when the host driver has delegated the shader cores + power management to MCU. The supplied value will be + recorded internally without any change. But the actual field + value will be subject to core power-off timer source frequency + scaling and maximum value limiting. The default source will be + SYSTEM_TIMESTAMP counter. But in case the platform is not able + to supply it, the GPU CYCLE_COUNTER source will be used as an + alternative. + + If we set the value to zero then MCU-controlled shader/tiler + power management will be disabled. + + +What: /sys/class/misc/mali%u/device/csg_scheduling_period +Description: + This attribute is available only with mali platform + device-driver that supports a CSF GPU. The duration value unit + is in milliseconds and is used for configuring csf scheduling + tick duration. What: /sys/class/misc/mali%u/device/reset_timeout Description: This attribute is used to set the number of milliseconds to diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt index 41b76762953a..457ce1663d6a 100644 --- a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt @@ -17,6 +17,11 @@ Optional properties: - pulses-per-revolution : define the tachometer pulses per fan revolution as an integer (default is 2 interrupts per revolution). The value must be greater than zero. +- rockchip,temp-trips : The property is an array of 2-tuples items, and + each item consists of temperature in millicelsius and + pwm cooling state. This depends on CONFIG_ROCKCHIP_SYSTEM_MONITOR. + If add the property the fan cooling state will be changed + by system monitor. Otherwise, use the default thermal governor. Example: fan0: pwm-fan { diff --git a/Documentation/devicetree/bindings/net/can/rockchip_canfd.txt b/Documentation/devicetree/bindings/net/can/rockchip_canfd.txt index e73a8a6a0fc9..ad96a1501b5d 100644 --- a/Documentation/devicetree/bindings/net/can/rockchip_canfd.txt +++ b/Documentation/devicetree/bindings/net/can/rockchip_canfd.txt @@ -4,7 +4,8 @@ Rockchip CANFD controller Device Tree Bindings Required properties: - compatible : Should be: - "rockchip,canfd-1.0" for CANFD controllers 1.0 - - "rockchip,can-2.0" for CAN controllers 2.0 + - "rockchip,can-2.0" for RK3588 CAN controllers 2.0 + - "rockchip,rk3568-can-2.0" for RK3568 CAN controllers 2.0 - reg : Physical base address and size of the controller registers map. - interrupts : Property with a value describing the interrupt diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 35473a5f6389..5212e7c0c8b0 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1037,7 +1037,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-vyasa.dtb \ rk3308bs-evb-amic-v11-aarch32.dtb \ rk3308bs-evb-dmic-pdm-v11-aarch32.dtb \ - rk3308bs-evb-mipi-display-v11-aarch32.dtb + rk3308bs-evb-mipi-display-v11-aarch32.dtb \ + rk3308hs-voice-module-board-v10-aarch32.dtb dtb-$(CONFIG_ARCH_S3C24XX) += \ s3c2416-smdk2416.dtb dtb-$(CONFIG_ARCH_S3C64XX) += \ diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 814f4ba3ea02..351e4b1631a7 100644 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -18,6 +18,9 @@ aliases { ethernet0 = &emac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; @@ -701,6 +704,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x2007c000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO0>; gpio-controller; @@ -714,6 +718,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x20080000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO1>; gpio-controller; @@ -727,6 +732,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x20084000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO2>; gpio-controller; diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi index ddcf5e1bfa2f..71e2495d78b2 100644 --- a/arch/arm/boot/dts/rk3066a.dtsi +++ b/arch/arm/boot/dts/rk3066a.dtsi @@ -13,6 +13,15 @@ / { compatible = "rockchip,rk3066a"; + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + gpio6 = &gpio6; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -410,6 +419,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x20034000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO0>; gpio-controller; @@ -423,6 +433,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x2003c000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO1>; gpio-controller; @@ -436,6 +447,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x2003e000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO2>; gpio-controller; @@ -449,6 +461,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x20080000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO3>; gpio-controller; @@ -462,6 +475,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x20084000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO4>; gpio-controller; @@ -475,6 +489,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x2000a000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO6>; gpio-controller; diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index 1eb64aeecbe8..5e3c1038efa8 100644 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -13,6 +13,13 @@ / { compatible = "rockchip,rk3188"; + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -251,6 +258,7 @@ compatible = "rockchip,rk3188-gpio-bank0"; reg = <0x2000a000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO0>; gpio-controller; @@ -264,6 +272,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x2003c000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO1>; gpio-controller; @@ -277,6 +286,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x2003e000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO2>; gpio-controller; @@ -290,6 +300,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x20080000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO3>; gpio-controller; diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi index b29c16d97a8d..1a72629369a7 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi @@ -15,6 +15,10 @@ aliases { ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -833,6 +837,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x11110000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO0>; gpio-controller; @@ -846,6 +851,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x11120000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO1>; gpio-controller; @@ -859,6 +865,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x11130000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO2>; gpio-controller; @@ -872,6 +879,7 @@ compatible = "rockchip,gpio-bank"; reg = <0x11140000 0x100>; interrupts = ; + clock-names = "bus"; clocks = <&cru PCLK_GPIO3>; gpio-controller; diff --git a/arch/arm/boot/dts/rk3288-evb-rk1608.dts b/arch/arm/boot/dts/rk3288-evb-rk1608.dts index ff1f97f08d7c..f65da82f79d5 100644 --- a/arch/arm/boot/dts/rk3288-evb-rk1608.dts +++ b/arch/arm/boot/dts/rk3288-evb-rk1608.dts @@ -423,12 +423,13 @@ &gmac { phy-supply = <&vccio_pmu>; phy-mode = "rgmii"; - clock_in_out = "input"; + clock_in_out = "output"; + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&cru PLL_NPLL>; + assigned-clock-rates = <125000000>; snps,reset-gpio = <&gpio4 7 0>; snps,reset-active-low; snps,reset-delays-us = <0 10000 50000>; - assigned-clocks = <&cru SCLK_MAC>; - assigned-clock-parents = <&ext_gmac>; pinctrl-names = "default"; pinctrl-0 = <&rgmii_pins>; tx_delay = <0x30>; diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi index c4ca73b40d4a..1ca204a8454b 100644 --- a/arch/arm/boot/dts/rk3288-evb.dtsi +++ b/arch/arm/boot/dts/rk3288-evb.dtsi @@ -237,12 +237,13 @@ &gmac { phy-supply = <&vcc_phy>; phy-mode = "rgmii"; - clock_in_out = "input"; + clock_in_out = "output"; + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&cru PLL_NPLL>; + assigned-clock-rates = <125000000>; snps,reset-gpio = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; snps,reset-active-low; snps,reset-delays-us = <0 10000 1000000>; - assigned-clocks = <&cru SCLK_MAC>; - assigned-clock-parents = <&ext_gmac>; pinctrl-names = "default"; pinctrl-0 = <&rgmii_pins>; tx_delay = <0x30>; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index a7952ca9e915..5ca338b4e73e 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -19,6 +19,15 @@ aliases { ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + gpio5 = &gpio5; + gpio6 = &gpio6; + gpio7 = &gpio7; + gpio8 = &gpio8; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm/boot/dts/rk3308hs-voice-module-board-v10-aarch32.dts b/arch/arm/boot/dts/rk3308hs-voice-module-board-v10-aarch32.dts new file mode 100644 index 000000000000..dd94a739ea07 --- /dev/null +++ b/arch/arm/boot/dts/rk3308hs-voice-module-board-v10-aarch32.dts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd + */ + +/dts-v1/; + +#include "rk3308-voice-module-board-v11-aarch32.dts" + +/ { + model = "Rockchip RK3308HS Voice Module Board V10 (AArch32)"; + compatible = "rockchip,rk3308hs-voice-module-board-v10-aarch32", "rockchip,rk3308"; + + /delete-node/ vdd-1v0; + + vdd_0v9: vdd-0v9 { + compatible = "regulator-fixed"; + regulator-name = "vdd_0v9"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + }; +}; + +&vcc_ddr { + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; +}; + +&vdd_log { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; +}; diff --git a/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts b/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts index 9176465f1d43..c96f6f4f43cb 100644 --- a/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts +++ b/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts @@ -44,7 +44,7 @@ }; chosen { - bootargs = "loglevel=0 console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip storagemedia=mtd androidboot.storagemedia=mtd androidboot.mode=normal"; + bootargs = "loglevel=0 rootfstype=erofs rootflags=dax console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip storagemedia=mtd androidboot.storagemedia=mtd androidboot.mode=normal"; }; acodec_sound: acodec-sound { @@ -190,11 +190,6 @@ reg = <0x00000000 0x04000000>; }; -&meta { - /* reserved meta partition 384KB */ - reg = <0x01e00000 (384 * 0x400)>; -}; - &mipi0_csi2 { status = "okay"; @@ -267,11 +262,6 @@ status = "okay"; }; -&rkisp_thunderboot { - /* vicap, capture raw10, ceil(w*10/8/256)*256*h *4(buf num) */ - reg = <0x01e60000 0xa8c000>; -}; - &rkisp_vir0 { status = "okay"; diff --git a/arch/arm/boot/dts/rv1103g-rmsl311-dloc-sl-v10.dts b/arch/arm/boot/dts/rv1103g-rmsl311-dloc-sl-v10.dts index 970f598e0596..1ef3a983b1c3 100644 --- a/arch/arm/boot/dts/rv1103g-rmsl311-dloc-sl-v10.dts +++ b/arch/arm/boot/dts/rv1103g-rmsl311-dloc-sl-v10.dts @@ -13,7 +13,7 @@ compatible = "rockchip,rv1103g-rmsl311-dloc-v10", "rockchip,rv1103"; chosen { - bootargs = "loglevel=0 console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip"; + bootargs = "loglevel=0 rootfstype=erofs rootflags=dax console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip"; }; vcc_1v8: vcc-1v8 { @@ -132,11 +132,6 @@ reg = <0x00000000 0x04000000>; }; -&meta { - /* reserved meta partition 384KB */ - reg = <0x01e00000 (384 * 0x400)>; -}; - &mipi0_csi2 { status = "okay"; diff --git a/arch/arm/boot/dts/rv1106-evb-cam.dtsi b/arch/arm/boot/dts/rv1106-evb-cam.dtsi index dfb5e8d9c708..541c38e43065 100644 --- a/arch/arm/boot/dts/rv1106-evb-cam.dtsi +++ b/arch/arm/boot/dts/rv1106-evb-cam.dtsi @@ -3,16 +3,6 @@ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. * */ -/ { - cam_ircut0: cam_ircut { - status = "okay"; - compatible = "rockchip,ircut"; - ircut-open-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>; - ircut-close-gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; - rockchip,camera-module-index = <0>; - rockchip,camera-module-facing = "back"; - }; -}; &csi2_dphy_hw { status = "okay"; @@ -90,7 +80,6 @@ rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "CMK-OT2115-PC1"; rockchip,camera-module-lens-name = "30IRC-F16"; - lens-focus = <&cam_ircut0>; port { sc530ai_out: endpoint { remote-endpoint = <&csi_dphy_input0>; @@ -113,7 +102,6 @@ rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "CMK-OT2119-PC1"; rockchip,camera-module-lens-name = "30IRC-F16"; - lens-focus = <&cam_ircut0>; port { sc3336_out: endpoint { remote-endpoint = <&csi_dphy_input1>; @@ -136,7 +124,6 @@ rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "OT01"; rockchip,camera-module-lens-name = "40IRC_F16"; - lens-focus = <&cam_ircut0>; port { sc4336_out: endpoint { remote-endpoint = <&csi_dphy_input2>; diff --git a/arch/arm/boot/dts/rv1106-ipc.dtsi b/arch/arm/boot/dts/rv1106-ipc.dtsi index 80ce6af2eda9..d4ac29301f1f 100644 --- a/arch/arm/boot/dts/rv1106-ipc.dtsi +++ b/arch/arm/boot/dts/rv1106-ipc.dtsi @@ -22,15 +22,6 @@ }; }; - cam_ircut0: cam_ircut { - status = "okay"; - compatible = "rockchip,ircut"; - ircut-open-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; - ircut-close-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; - rockchip,camera-module-index = <0>; - rockchip,camera-module-facing = "back"; - }; - vcc_1v8: vcc-1v8 { compatible = "regulator-fixed"; regulator-name = "vcc_1v8"; @@ -156,7 +147,6 @@ pwdn-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&mipi_refclk_out0>; - lens-focus = <&cam_ircut0>; rockchip,camera-module-index = <0>; rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "OT01"; diff --git a/arch/arm/boot/dts/rv1106-smd-cam.dtsi b/arch/arm/boot/dts/rv1106-smd-cam.dtsi index 03bff39c00f4..7238b22f6a05 100644 --- a/arch/arm/boot/dts/rv1106-smd-cam.dtsi +++ b/arch/arm/boot/dts/rv1106-smd-cam.dtsi @@ -132,6 +132,11 @@ }; }; + gt24c512: gt24c512@50 { + compatible = "atmel,24c512"; + reg = <0x50>; + }; + vcsel_rk803: vcsel_rk803@63 { compatible = "rockchip,rk803"; status = "okay"; diff --git a/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi b/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi index dbb61987602c..208cb559d7b5 100644 --- a/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi +++ b/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi @@ -7,8 +7,8 @@ / { reserved-memory { - mmc_ecsd: mmc@3fe00 { - reg = <0x3fe00 0x00000800>; + mmc_ecsd: mmc@3f000 { + reg = <0x3f000 0x00001000>; }; mmc_idmac: mmc@100000 { diff --git a/arch/arm/boot/dts/rv1106-thunder-boot.dtsi b/arch/arm/boot/dts/rv1106-thunder-boot.dtsi index ecc9ac178d1b..f4951af8fa8f 100644 --- a/arch/arm/boot/dts/rv1106-thunder-boot.dtsi +++ b/arch/arm/boot/dts/rv1106-thunder-boot.dtsi @@ -19,25 +19,30 @@ #size-cells = <1>; ranges; - rtos@40000 { + rtos: rtos@40000 { reg = <0x40000 0x40000>; }; - ramdisk_r: ramdisk@a00000 { - reg = <0x00a00000 (10 * 0x00100000)>; + meta: meta@800000 { + /* reg's offset MUST match with RTOS */ + reg = <0x00800000 0x60000>; }; - ramdisk_c: ramdisk@1900000 { - reg = <0x01900000 (5 * 0x00100000)>; + rkisp_thunderboot: rkisp@860000 { + /* reg's offset MUST match with RTOS */ + /* + * vicap, capture raw10, ceil(w*10/8/256)*256*h *4(buf num) + * e.g. 1920x1080: 0xa8c000 + */ + reg = <0x00860000 0xa8c000>; }; - meta: meta@1e00000 { - reg = <0x01e00000 0x0>; + ramdisk_r: ramdisk_r { + reg = <0x12ec000 (10 * 0x00100000)>; }; - rkisp_thunderboot: rkisp@1e60000 { - /* NV12 (w*h*1.5*2) w and h 16 align, eg:1920x1088 */ - reg = <0x1e60000 0x0>; + ramdisk_c: ramdisk_c { + reg = <0x1cec000 (5 * 0x00100000)>; }; }; @@ -73,6 +78,11 @@ compatible = "rockchip,thunder-boot-service"; mbox-names = "amp-rx"; mboxes = <&mailbox 1>; + resets = <&cru SRST_CORE_MCU>, <&cru SRST_CORE_MCU_PWRUP>, + <&cru SRST_CORE_MCU_CPU>, <&cru SRST_T_CORE_MCU_CPU>; + reset-names = "core_mcu", "core_mcu_pwrup", + "core_mcu_cpu", "t_core_mcu_cpu"; + memory-region = <&rtos>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v10.dts b/arch/arm/boot/dts/rv1106g-evb2-v10.dts index deb02ea09767..68aed729ec96 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v10.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v10.dts @@ -14,7 +14,7 @@ compatible = "rockchip,rv1106g-evb2-v10", "rockchip,rv1106"; chosen { - bootargs = "loglevel=0 console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip rk_dma_heap_cma=24M mtdparts=sfc_nor:64K(env),256K@64K(idblock),256K(uboot),64K(vnvm),8M(boot),3M(userdata)"; + bootargs = "loglevel=0 rootfstype=erofs rootflags=dax console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip"; }; vcc_1v8: vcc-1v8 { @@ -54,7 +54,7 @@ csi_dphy_input0: endpoint@0 { reg = <0>; - remote-endpoint = <&sc3336_out>; + remote-endpoint = <&sc3338_out>; data-lanes = <1 2>; }; }; @@ -83,22 +83,23 @@ }; &i2c4 { - sc3336: sc3336@30 { - compatible = "smartsens,sc3336"; + rockchip,amp-shared; + + sc3338: sc3338@30 { + compatible = "smartsens,sc3338"; status = "okay"; reg = <0x30>; clocks = <&cru MCLK_REF_MIPI0>; clock-names = "xvclk"; - reset-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; - pwdn-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; + pwdn-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&mipi_refclk_out0>; rockchip,camera-module-index = <0>; rockchip,camera-module-facing = "back"; - rockchip,camera-module-name = "CMK-OT2119-PC1"; + rockchip,camera-module-name = "FKO1"; rockchip,camera-module-lens-name = "30IRC-F16"; port { - sc3336_out: endpoint { + sc3338_out: endpoint { remote-endpoint = <&csi_dphy_input0>; data-lanes = <1 2>; }; @@ -137,13 +138,8 @@ }; }; -&memory { - reg = <0x00000000 0x08000000>; -}; - -&meta { - /* reserved meta partition 384KB */ - reg = <0x01e00000 (384 * 0x400)>; +&mailbox { + status = "okay"; }; &rkcif { @@ -152,6 +148,7 @@ &rkcif_mipi_lvds { status = "okay"; + memory-region-thunderboot = <&rkisp_thunderboot>; pinctrl-names = "default"; pinctrl-0 = <&mipi_pins>; @@ -188,9 +185,25 @@ }; }; +&thunder_boot_service { + status = "okay"; +}; + &rkisp_thunderboot { - /* 9M for NV12 (w*h*1.5*2) w and h 16 align, 2304/1296 */ - reg = <0x01e60000 (9 * 0x00100000)>; + /* reg's offset MUST match with RTOS */ + /* + * vicap, capture raw10, ceil(w*10/8/256)*256*h *4(buf num) + * e.g. 2304x1296: 0xf30000 + */ + reg = <0x00860000 0xf30000>; +}; + +&ramdisk_r { + reg = <0x1790000 (10 * 0x00100000)>; +}; + +&ramdisk_c { + reg = <0x2190000 (5 * 0x00100000)>; }; &pwm10 { diff --git a/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts b/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts index 081d1603f72a..16b9fb261d17 100644 --- a/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts +++ b/arch/arm/boot/dts/rv1106g-smart-door-lock-rmsl-v10.dts @@ -15,7 +15,7 @@ compatible = "rockchip,rv1106g-smart-door-lock-rmsl-v10", "rockchip,rv1106"; chosen { - bootargs = "loglevel=0 console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip"; + bootargs = "loglevel=0 rootfstype=erofs rootflags=dax console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip"; }; acodec_sound: acodec-sound { @@ -98,11 +98,6 @@ status = "disabled"; }; -&meta { - /* reserved meta partition 384KB */ - reg = <0x01e00000 (384 * 0x400)>; -}; - &pinctrl { mcu { /omit-if-no-ref/ diff --git a/arch/arm/configs/rv1106-battery-ipc.config b/arch/arm/configs/rv1106-battery-ipc.config index 9e8e5eb72bbd..ac191f3ba281 100644 --- a/arch/arm/configs/rv1106-battery-ipc.config +++ b/arch/arm/configs/rv1106-battery-ipc.config @@ -13,7 +13,7 @@ CONFIG_SND_SOC_ROCKCHIP=m CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=m CONFIG_SPI=y CONFIG_VIDEO_SC230AI=y -CONFIG_VIDEO_SC3336=y +CONFIG_VIDEO_SC3338=y # CONFIG_AD2S1200 is not set # CONFIG_AD2S1210 is not set # CONFIG_AD2S90 is not set diff --git a/arch/arm/configs/rv1106-smart-door.config b/arch/arm/configs/rv1106-smart-door.config index 6b367836a6d4..5cdd669122f2 100644 --- a/arch/arm/configs/rv1106-smart-door.config +++ b/arch/arm/configs/rv1106-smart-door.config @@ -1,8 +1,10 @@ CONFIG_CONFIGFS_FS=m CONFIG_CRYPTO=y +CONFIG_EEPROM_AT24=y CONFIG_EXTCON=m CONFIG_JFFS2_FS=y CONFIG_KEYS=y +CONFIG_NVMEM_SYSFS=y CONFIG_RFKILL=y CONFIG_RK803=y CONFIG_ROCKCHIP_HW_DECOMPRESS_USER=y diff --git a/arch/arm/configs/rv1106-tb.config b/arch/arm/configs/rv1106-tb.config index e5d89bd5a24b..3b992dde3d5b 100644 --- a/arch/arm/configs/rv1106-tb.config +++ b/arch/arm/configs/rv1106-tb.config @@ -1,7 +1,11 @@ CONFIG_BLK_DEV_INITRD=y +CONFIG_CRYPTO=y +CONFIG_DAX=y +CONFIG_EROFS_FS=y # CONFIG_ETHERNET is not set CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_XZ is not set +CONFIG_LIBCRC32C=y # CONFIG_MDIO_DEVICE is not set CONFIG_MMC=y CONFIG_MTD_BLOCK=y @@ -14,11 +18,111 @@ CONFIG_ROCKCHIP_MULTI_RGA=y CONFIG_ROCKCHIP_RAMDISK=y CONFIG_ROCKCHIP_RGA_PROC_FS=y CONFIG_ROCKCHIP_THUNDER_BOOT=y -CONFIG_ROMFS_FS=y # CONFIG_SLUB_SYSFS is not set CONFIG_SND_SOC_RV1106=m CONFIG_VIDEO_ROCKCHIP_CIF=y CONFIG_VIDEO_ROCKCHIP_ISP=y +# CONFIG_ARM_CRYPTO is not set +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_BLAKE2B is not set +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CFB is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_ESSIV is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +# CONFIG_CRYPTO_LIB_POLY1305 is not set +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_XXHASH is not set +# CONFIG_CRYPTO_ZSTD is not set +# CONFIG_EROFS_FS_DEBUG is not set +# CONFIG_EROFS_FS_XATTR is not set +# CONFIG_EROFS_FS_ZIP is not set +CONFIG_FS_DAX=y +CONFIG_FS_IOMAP=y # CONFIG_INITCALL_ASYNC is not set # CONFIG_INITRAMFS_FORCE is not set CONFIG_INITRAMFS_SOURCE="" @@ -54,9 +158,5 @@ CONFIG_MTD_BLKDEVS=y CONFIG_ROCKCHIP_RGA_DEBUGGER=y CONFIG_ROCKCHIP_THUNDER_BOOT_MMC=y CONFIG_ROCKCHIP_THUNDER_BOOT_SFC=y -CONFIG_ROMFS_BACKED_BY_BLOCK=y -# CONFIG_ROMFS_BACKED_BY_BOTH is not set -# CONFIG_ROMFS_BACKED_BY_MTD is not set -CONFIG_ROMFS_ON_BLOCK=y # CONFIG_SDIO_UART is not set CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP=y diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index bc9f05fc62da..82683049b811 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -3,8 +3,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr3-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr3-v10-avb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr3-v10-linux.dtb -dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr3-v11.dtb -dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr3-v11-avb.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-mini-evb-ddr3-v11.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-mini-evb-ddr3-v11-avb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr3-v11-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-evb.dtb @@ -20,6 +20,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-evb-lp3-v10-avb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-evb-lp3-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-evb-lp3-v11.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-evb-lp3-v11-avb.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-evb-lp3-v12-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-863-lp3-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-863-lp3-v10-avb.dtb diff --git a/arch/arm64/boot/dts/rockchip/px30-android.dtsi b/arch/arm64/boot/dts/rockchip/px30-android.dtsi index 98a94a448518..3f296c44e5dd 100644 --- a/arch/arm64/boot/dts/rockchip/px30-android.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-android.dtsi @@ -58,7 +58,6 @@ &display_subsystem { status = "disabled"; - ports = <&vopb_out>, <&vopl_out>; logo-memory-region = <&drm_logo>; route { diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-avb.dts b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-avb.dts index e9a56be8c394..7b122c5461f8 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-avb.dts +++ b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-avb.dts @@ -4,33 +4,13 @@ */ /dts-v1/; +#include "px30.dtsi" +#include "px30-android.dtsi" #include "px30-evb-ddr3-v10.dtsi" / { model = "Rockchip PX30 evb ddr3 board"; compatible = "rockchip,px30-evb-ddr3-v10-avb", "rockchip,px30"; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&hp_det>; - io-channels = <&saradc 1>; - }; - - wireless-bluetooth { - compatible = "bluetooth-platdata"; - clocks = <&rk809 1>; - clock-names = "ext_clock"; - uart_rts_gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>; - pinctrl-names = "default","rts_gpio"; - pinctrl-0 = <&uart1_rts>; - pinctrl-1 = <&uart1_rts_gpio>; - BT,reset_gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; - BT,wake_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; - BT,wake_host_irq = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; }; &chosen { @@ -295,24 +275,3 @@ }; }; }; - -&gmac { - phy-supply = <&vcc_phy>; - clock_in_out = "input"; - assigned-clocks = <&cru SCLK_GMAC>; - assigned-clock-parents = <&gmac_clkin>; - pinctrl-names = "default"; - pinctrl-0 = <&rmii_pins &mac_refclk>; - snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>; - snps,reset-active-low; - snps,reset-delays-us = <0 50000 50000>; - status = "okay"; -}; - -&pinctrl { - headphone { - hp_det: hp-det { - rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; -}; diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts index 680e67c42a88..9edb04ae267c 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts +++ b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts @@ -4,197 +4,31 @@ */ /dts-v1/; -#include -#include -#include -#include -#include #include "px30.dtsi" #include "rk3326-linux.dtsi" +#include "px30-evb-ddr3-v10.dtsi" / { model = "Rockchip linux PX30 evb ddr3 board"; compatible = "rockchip,px30-evb-ddr3-v10-linux", "rockchip,px30"; - adc-keys { - compatible = "adc-keys"; - io-channels = <&saradc 2>; - io-channel-names = "buttons"; - poll-interval = <100>; - keyup-threshold-microvolt = <1800000>; - - esc-key { - linux,code = ; - label = "esc"; - press-threshold-microvolt = <1310000>; - }; - - home-key { - linux,code = ; - label = "home"; - press-threshold-microvolt = <624000>; - }; - - menu-key { - linux,code = ; - label = "menu"; - press-threshold-microvolt = <987000>; - }; - - vol-down-key { - linux,code = ; - label = "volume down"; - press-threshold-microvolt = <300000>; - }; - - vol-up-key { - linux,code = ; - label = "volume up"; - press-threshold-microvolt = <17000>; - }; - }; - - backlight: backlight { - compatible = "pwm-backlight"; - pwms = <&pwm1 0 25000 0>; - brightness-levels = < - 0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 - 24 25 26 27 28 29 30 31 - 32 33 34 35 36 37 38 39 - 40 41 42 43 44 45 46 47 - 48 49 50 51 52 53 54 55 - 56 57 58 59 60 61 62 63 - 64 65 66 67 68 69 70 71 - 72 73 74 75 76 77 78 79 - 80 81 82 83 84 85 86 87 - 88 89 90 91 92 93 94 95 - 96 97 98 99 100 101 102 103 - 104 105 106 107 108 109 110 111 - 112 113 114 115 116 117 118 119 - 120 121 122 123 124 125 126 127 - 128 129 130 131 132 133 134 135 - 136 137 138 139 140 141 142 143 - 144 145 146 147 148 149 150 151 - 152 153 154 155 156 157 158 159 - 160 161 162 163 164 165 166 167 - 168 169 170 171 172 173 174 175 - 176 177 178 179 180 181 182 183 - 184 185 186 187 188 189 190 191 - 192 193 194 195 196 197 198 199 - 200 201 202 203 204 205 206 207 - 208 209 210 211 212 213 214 215 - 216 217 218 219 220 221 222 223 - 224 225 226 227 228 229 230 231 - 232 233 234 235 236 237 238 239 - 240 241 242 243 244 245 246 247 - 248 249 250 251 252 253 254 255>; - default-brightness-level = <200>; - }; - - charge-animation { - compatible = "rockchip,uboot-charge"; - rockchip,uboot-charge-on = <0>; - rockchip,android-charge-on = <1>; - rockchip,uboot-low-power-voltage = <3500>; - rockchip,screen-on-voltage = <3600>; - status = "okay"; - }; - - rk809-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk809-codec"; - simple-audio-card,mclk-fs = <256>; - simple-audio-card,cpu { - sound-dai = <&i2s1_2ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk809_codec>; - }; - }; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&hp_det>; - io-channels = <&saradc 1>; - }; - - sdio_pwrseq: sdio-pwrseq { - compatible = "mmc-pwrseq-simple"; - /*clocks = <&rk809 1>;*/ - /*clock-names = "ext_clock";*/ - pinctrl-names = "default"; - pinctrl-0 = <&wifi_enable_h>; - - /* - * On the module itself this is one of these (depending - * on the actual card populated): - * - SDIO_RESET_L_WL_REG_ON - * - PDN (power down when low) - */ - reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO3_A4 */ - }; - - vcc_phy: vcc-phy-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_phy"; - regulator-always-on; - regulator-boot-on; - }; - - vcc5v0_sys: vccsys { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_sys"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - wireless-wlan { - compatible = "wlan-platdata"; - wifi_chip_type = "AP6210"; - WIFI,host_wake_irq = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; - - wireless-bluetooth { - compatible = "bluetooth-platdata"; - clocks = <&rk809 1>; - clock-names = "ext_clock"; - uart_rts_gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>; - pinctrl-names = "default","rts_gpio"; - pinctrl-0 = <&uart1_rts>; - pinctrl-1 = <&uart1_rts_gpio>; - BT,reset_gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; - BT,wake_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; - BT,wake_host_irq = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; -}; - -&display_subsystem { - status = "okay"; + /delete-node/ test-power; }; &dsi { status = "okay"; panel@0 { - compatible = "simple-panel-dsi"; + compatible = "sitronix,st7703", "simple-panel-dsi"; reg = <0>; power-supply = <&vcc3v3_lcd>; backlight = <&backlight>; - prepare-delay-ms = <0>; - reset-delay-ms = <0>; - init-delay-ms = <80>; - enable-delay-ms = <0>; - disable-delay-ms = <10>; - unprepare-delay-ms = <60>; + prepare-delay-ms = <2>; + reset-delay-ms = <1>; + init-delay-ms = <20>; + enable-delay-ms = <120>; + disable-delay-ms = <50>; + unprepare-delay-ms = <20>; width-mm = <68>; height-mm = <121>; @@ -205,212 +39,46 @@ dsi,lanes = <4>; panel-init-sequence = [ - 39 00 04 ff 98 81 03 - 15 00 02 01 00 - 15 00 02 02 00 - 15 00 02 03 53 - 15 00 02 04 53 - 15 00 02 05 13 - 15 00 02 06 04 - 15 00 02 07 02 - 15 00 02 08 02 - 15 00 02 09 00 - 15 00 02 0a 00 - 15 00 02 0b 00 - 15 00 02 0c 00 - 15 00 02 0d 00 - 15 00 02 0e 00 - 15 00 02 0f 00 - - 15 00 02 10 00 - 15 00 02 11 00 - 15 00 02 12 00 - 15 00 02 13 00 - 15 00 02 14 00 - 15 00 02 15 08 - 15 00 02 16 10 - 15 00 02 17 00 - 15 00 02 18 08 - 15 00 02 19 00 - 15 00 02 1a 00 - 15 00 02 1b 00 - 15 00 02 1c 00 - 15 00 02 1d 00 - 15 00 02 1e c0 - 15 00 02 1f 80 - - 15 00 02 20 02 - 15 00 02 21 09 - 15 00 02 22 00 - 15 00 02 23 00 - 15 00 02 24 00 - 15 00 02 25 00 - 15 00 02 26 00 - 15 00 02 27 00 - 15 00 02 28 55 - 15 00 02 29 03 - 15 00 02 2a 00 - 15 00 02 2b 00 - 15 00 02 2c 00 - 15 00 02 2d 00 - 15 00 02 2e 00 - 15 00 02 2f 00 - - 15 00 02 30 00 - 15 00 02 31 00 - 15 00 02 32 00 - 15 00 02 33 00 - 15 00 02 34 04 - 15 00 02 35 05 - 15 00 02 36 05 - 15 00 02 37 00 - 15 00 02 38 3c - 15 00 02 39 35 - 15 00 02 3a 00 - 15 00 02 3b 40 - 15 00 02 3c 00 - 15 00 02 3d 00 - 15 00 02 3e 00 - 15 00 02 3f 00 - - 15 00 02 40 00 - 15 00 02 41 88 - 15 00 02 42 00 - 15 00 02 43 00 - 15 00 02 44 1f - - 15 00 02 50 01 - 15 00 02 51 23 - 15 00 02 52 45 - 15 00 02 53 67 - 15 00 02 54 89 - 15 00 02 55 ab - 15 00 02 56 01 - 15 00 02 57 23 - 15 00 02 58 45 - 15 00 02 59 67 - 15 00 02 5a 89 - 15 00 02 5b ab - 15 00 02 5c cd - 15 00 02 5d ef - 15 00 02 5e 03 - 15 00 02 5f 14 - - 15 00 02 60 15 - 15 00 02 61 0c - 15 00 02 62 0d - 15 00 02 63 0e - 15 00 02 64 0f - 15 00 02 65 10 - 15 00 02 66 11 - 15 00 02 67 08 - 15 00 02 68 02 - 15 00 02 69 0a - 15 00 02 6a 02 - 15 00 02 6b 02 - 15 00 02 6c 02 - 15 00 02 6d 02 - 15 00 02 6e 02 - 15 00 02 6f 02 - - 15 00 02 70 02 - 15 00 02 71 02 - 15 00 02 72 06 - 15 00 02 73 02 - 15 00 02 74 02 - 15 00 02 75 14 - 15 00 02 76 15 - 15 00 02 77 0f - 15 00 02 78 0e - 15 00 02 79 0d - 15 00 02 7a 0c - 15 00 02 7b 11 - 15 00 02 7c 10 - 15 00 02 7d 06 - 15 00 02 7e 02 - 15 00 02 7f 0a - - 15 00 02 80 02 - 15 00 02 81 02 - 15 00 02 82 02 - 15 00 02 83 02 - 15 00 02 84 02 - 15 00 02 85 02 - 15 00 02 86 02 - 15 00 02 87 02 - 15 00 02 88 08 - 15 00 02 89 02 - 15 00 02 8a 02 - - 39 00 04 ff 98 81 04 - 15 00 02 00 80 - 15 00 02 70 00 - 15 00 02 71 00 - 15 00 02 66 fe - 15 00 02 82 15 - 15 00 02 84 15 - 15 00 02 85 15 - 15 00 02 3a 24 - 15 00 02 32 ac - 15 00 02 8c 80 - 15 00 02 3c f5 - 15 00 02 88 33 - - 39 00 04 ff 98 81 01 - 15 00 02 22 0a - 15 00 02 31 00 - 15 00 02 53 78 - 15 00 02 50 5b - 15 00 02 51 5b - 15 00 02 60 20 - 15 00 02 61 00 - 15 00 02 62 0d - 15 00 02 63 00 - - 15 00 02 a0 00 - 15 00 02 a1 10 - 15 00 02 a2 1c - 15 00 02 a3 13 - 15 00 02 a4 15 - 15 00 02 a5 26 - 15 00 02 a6 1a - 15 00 02 a7 1d - 15 00 02 a8 67 - 15 00 02 a9 1c - 15 00 02 aa 29 - 15 00 02 ab 5b - 15 00 02 ac 26 - 15 00 02 ad 28 - 15 00 02 ae 5c - 15 00 02 af 30 - 15 00 02 b0 31 - 15 00 02 b1 2e - 15 00 02 b2 32 - 15 00 02 b3 00 - - 15 00 02 c0 00 - 15 00 02 c1 10 - 15 00 02 c2 1c - 15 00 02 c3 13 - 15 00 02 c4 15 - 15 00 02 c5 26 - 15 00 02 c6 1a - 15 00 02 c7 1d - 15 00 02 c8 67 - 15 00 02 c9 1c - 15 00 02 ca 29 - 15 00 02 cb 5b - 15 00 02 cc 26 - 15 00 02 cd 28 - 15 00 02 ce 5c - 15 00 02 cf 30 - 15 00 02 d0 31 - 15 00 02 d1 2e - 15 00 02 d2 32 - 15 00 02 d3 00 - 39 00 04 ff 98 81 00 - 05 00 01 11 - 05 01 01 29 + 05 fa 01 11 + 39 00 04 b9 f1 12 83 + 39 00 1c ba 33 81 05 f9 0e 0e 00 00 00 + 00 00 00 00 00 44 25 00 91 0a + 00 00 02 4f 01 00 00 37 + 15 00 02 b8 25 + 39 00 04 bf 02 11 00 + 39 00 0b b3 0c 10 0a 50 03 ff 00 00 00 + 00 + 39 00 0a c0 73 73 50 50 00 00 08 70 00 + 15 00 02 bc 46 + 15 00 02 cc 0b + 15 00 02 b4 80 + 39 00 04 b2 c8 12 30 + 39 00 0f e3 07 07 0b 0b 03 0b 00 00 00 + 00 ff 00 c0 10 + 39 00 0d c1 53 00 1e 1e 77 e1 cc dd 67 + 77 33 33 + 39 00 07 c6 00 00 ff ff 01 ff + 39 00 03 b5 09 09 + 39 00 03 b6 87 95 + 39 00 40 e9 c2 10 05 05 10 05 a0 12 31 + 23 3f 81 0a a0 37 18 00 80 01 + 00 00 00 00 80 01 00 00 00 48 + f8 86 42 08 88 88 80 88 88 88 + 58 f8 87 53 18 88 88 81 88 88 + 88 00 00 00 01 00 00 00 00 00 + 00 00 00 00 + 39 00 3e ea 00 1a 00 00 00 00 02 00 00 + 00 00 00 1f 88 81 35 78 88 88 + 85 88 88 88 0f 88 80 24 68 88 + 88 84 88 88 88 23 10 00 00 1c + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 30 05 a0 00 00 + 00 00 + 39 00 23 e0 00 06 08 2a 31 3f 38 36 07 + 0c 0d 11 13 12 13 11 18 00 06 + 08 2a 31 3f 38 36 07 0c 0d 11 + 13 12 13 11 18 + 05 32 01 29 ]; panel-exit-sequence = [ @@ -463,644 +131,3 @@ }; }; }; - -&dsi_in_vopb { - status = "okay"; -}; - -&dsi_in_vopl { - status = "disabled"; -}; - -&route_dsi { - connect = <&vopb_out_dsi>; - status = "okay"; -}; - -&bus_apll { - bus-supply = <&vdd_logic>; - status = "okay"; -}; - -&cpu0 { - cpu-supply = <&vdd_arm>; -}; - -&dfi { - status = "okay"; -}; - -&dmc { - center-supply = <&vdd_logic>; - status = "okay"; -}; - -&emmc { - bus-width = <8>; - cap-mmc-highspeed; - mmc-hs200-1_8v; - no-sdio; - no-sd; - disable-wp; - non-removable; - num-slots = <1>; - status = "okay"; -}; - -&gmac { - phy-supply = <&vcc_phy>; - clock_in_out = "input"; - assigned-clocks = <&cru SCLK_GMAC>; - assigned-clock-parents = <&gmac_clkin>; - pinctrl-names = "default"; - pinctrl-0 = <&rmii_pins &mac_refclk>; - snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>; - snps,reset-active-low; - snps,reset-delays-us = <0 50000 50000>; - status = "okay"; -}; - -&gpu { - mali-supply = <&vdd_logic>; - status = "okay"; -}; - -&i2c0 { - status = "okay"; - - rk809: pmic@20 { - compatible = "rockchip,rk809"; - reg = <0x20>; - interrupt-parent = <&gpio0>; - interrupts = <7 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default", "pmic-sleep", - "pmic-power-off", "pmic-reset"; - pinctrl-0 = <&pmic_int>; - pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>; - pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>; - pinctrl-3 = <&soc_slppin_rst>, <&rk817_slppin_rst>; - rockchip,system-power-controller; - wakeup-source; - #clock-cells = <1>; - clock-output-names = "rk808-clkout1", "rk808-clkout2"; - //fb-inner-reg-idxs = <2>; - /* 1: rst regs (default in codes), 0: rst the pmic */ - pmic-reset-func = <1>; - - vcc1-supply = <&vcc5v0_sys>; - vcc2-supply = <&vcc5v0_sys>; - vcc3-supply = <&vcc5v0_sys>; - vcc4-supply = <&vcc5v0_sys>; - vcc5-supply = <&vcc3v3_sys>; - vcc6-supply = <&vcc3v3_sys>; - vcc7-supply = <&vcc3v3_sys>; - vcc8-supply = <&vcc3v3_sys>; - vcc9-supply = <&vcc5v0_sys>; - - pwrkey { - status = "okay"; - }; - - pinctrl_rk8xx: pinctrl_rk8xx { - gpio-controller; - #gpio-cells = <2>; - - rk817_slppin_null: rk817_slppin_null { - pins = "gpio_slp"; - function = "pin_fun0"; - }; - - rk817_slppin_slp: rk817_slppin_slp { - pins = "gpio_slp"; - function = "pin_fun1"; - }; - - rk817_slppin_pwrdn: rk817_slppin_pwrdn { - pins = "gpio_slp"; - function = "pin_fun2"; - }; - - rk817_slppin_rst: rk817_slppin_rst { - pins = "gpio_slp"; - function = "pin_fun3"; - }; - }; - - regulators { - vdd_logic: DCDC_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1350000>; - regulator-ramp-delay = <6001>; - regulator-initial-mode = <0x2>; - regulator-name = "vdd_logic"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <950000>; - }; - }; - - vdd_arm: DCDC_REG2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1350000>; - regulator-ramp-delay = <6001>; - regulator-initial-mode = <0x2>; - regulator-name = "vdd_arm"; - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <950000>; - }; - }; - - vcc_ddr: DCDC_REG3 { - regulator-always-on; - regulator-boot-on; - regulator-name = "vcc_ddr"; - regulator-initial-mode = <0x2>; - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_3v0: DCDC_REG4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-initial-mode = <0x2>; - regulator-name = "vcc_3v0"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3000000>; - }; - }; - - vcc_1v0: LDO_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-name = "vcc_1v0"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vccio_sdio: vcc1v8_soc: LDO_REG2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-name = "vcc1v8_soc"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd1v0_soc: LDO_REG3 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - - regulator-name = "vcc1v0_soc"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vcc3v0_pmu: LDO_REG4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - - regulator-name = "vcc3v0_pmu"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3000000>; - - }; - }; - - vccio_sd: LDO_REG5 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - - regulator-name = "vccio_sd"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vcc_sd: LDO_REG6 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - - regulator-name = "vcc_sd"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - - }; - }; - - vcc2v8_dvp: LDO_REG7 { - regulator-boot-on; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - - regulator-name = "vcc2v8_dvp"; - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <2800000>; - }; - }; - - vcc1v8_dvp: LDO_REG8 { - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-name = "vcc1v8_dvp"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd1v5_dvp: LDO_REG9 { - regulator-boot-on; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; - - regulator-name = "vdd1v5_dvp"; - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <1500000>; - }; - }; - - vcc3v3_sys: DCDC_REG5 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vcc3v3_sys"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vcc5v0_host: SWITCH_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-name = "vcc5v0_host"; - }; - - vcc3v3_lcd: SWITCH_REG2 { - regulator-boot-on; - regulator-name = "vcc3v3_lcd"; - }; - }; - - rk809_codec: codec { - #sound-dai-cells = <0>; - compatible = "rockchip,rk809-codec", "rockchip,rk817-codec"; - clocks = <&cru SCLK_I2S1_OUT>; - clock-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&i2s1_2ch_mclk>; - hp-volume = <20>; - spk-volume = <3>; - status = "okay"; - }; - }; -}; - -&i2c1 { - status = "okay"; - - sensor@f { - status = "okay"; - compatible = "ak8963"; - reg = <0x0f>; - type = ; - irq_enable = <0>; - poll_delay_ms = <30>; - layout = <1>; - reprobe_en = <1>; - }; - - gt1x: gt1x@14 { - compatible = "goodix,gt1x"; - reg = <0x14>; - power-supply = <&vcc3v3_lcd>; - goodix,rst-gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; - goodix,irq-gpio = <&gpio0 RK_PA5 IRQ_TYPE_LEVEL_LOW>; - }; - - sensor@4c { - status = "okay"; - compatible = "gs_mma7660"; - reg = <0x4c>; - type = ; - irq-gpio = <&gpio0 RK_PB7 IRQ_TYPE_LEVEL_LOW>; - irq_enable = <0>; - poll_delay_ms = <30>; - layout = <2>; - reprobe_en = <1>; - }; -}; - -&i2c2 { - status = "okay"; - - clock-frequency = <100000>; - - /* These are relatively safe rise/fall times; TODO: measure */ - i2c-scl-falling-time-ns = <50>; - i2c-scl-rising-time-ns = <300>; - - ov5695: ov5695@36 { - compatible = "ovti,ov5695"; - reg = <0x36>; - clocks = <&cru SCLK_CIF_OUT>; - clock-names = "xvclk"; - - avdd-supply = <&vcc2v8_dvp>; - dovdd-supply = <&vcc1v8_dvp>; - dvdd-supply = <&vdd1v5_dvp>; - - /*reset-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;*/ - pwdn-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&cif_clkout_m0>; - - rockchip,camera-module-index = <0>; - rockchip,camera-module-facing = "back"; - rockchip,camera-module-name = "TongJu"; - rockchip,camera-module-lens-name = "CHT842-MD"; - port { - ucam_out: endpoint { - remote-endpoint = <&mipi_in_ucam>; - data-lanes = <1 2>; - }; - }; - }; -}; - -&i2s1_2ch { - status = "okay"; - #sound-dai-cells = <0>; -}; - -&io_domains { - status = "okay"; - - vccio1-supply = <&vccio_sdio>; - vccio2-supply = <&vccio_sd>; - vccio3-supply = <&vcc_3v0>; - vccio4-supply = <&vcc3v0_pmu>; - vccio5-supply = <&vcc_3v0>; -}; - -&isp_mmu { - status = "okay"; -}; - -&mipi_dphy_rx0 { - status = "okay"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - #address-cells = <1>; - #size-cells = <0>; - - mipi_in_ucam: endpoint@1 { - reg = <1>; - remote-endpoint = <&ucam_out>; - data-lanes = <1 2>; - }; - }; - - port@1 { - reg = <1>; - #address-cells = <1>; - #size-cells = <0>; - - dphy_rx0_out: endpoint@0 { - reg = <0>; - remote-endpoint = <&isp0_mipi_in>; - }; - }; - }; -}; - -&nandc0 { - status = "okay"; -}; - -&pmu_io_domains { - status = "okay"; - - pmuio1-supply = <&vcc3v0_pmu>; - pmuio2-supply = <&vcc3v0_pmu>; -}; - -&pwm1 { - status = "okay"; -}; - -&rk_rga { - status = "okay"; -}; - -&rkisp1 { - status = "okay"; - - port { - #address-cells = <1>; - #size-cells = <0>; - - isp0_mipi_in: endpoint@0 { - reg = <0>; - remote-endpoint = <&dphy_rx0_out>; - }; - }; -}; - -&rockchip_suspend { - status = "okay"; - rockchip,sleep-debug-en = <1>; -}; - -&saradc { - status = "okay"; - vref-supply = <&vcc1v8_soc>; -}; - -&sdmmc { - bus-width = <4>; - cap-mmc-highspeed; - cap-sd-highspeed; - no-sdio; - no-mmc; - card-detect-delay = <800>; - ignore-pm-notify; - /*cd-gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>; [> CD GPIO <]*/ - sd-uhs-sdr12; - sd-uhs-sdr25; - sd-uhs-sdr50; - sd-uhs-sdr104; - vqmmc-supply = <&vccio_sd>; - vmmc-supply = <&vcc_sd>; - status = "okay"; -}; - -&sdio { - bus-width = <4>; - cap-sd-highspeed; - no-sd; - no-mmc; - ignore-pm-notify; - keep-power-in-suspend; - non-removable; - mmc-pwrseq = <&sdio_pwrseq>; - sd-uhs-sdr104; - status = "okay"; -}; - -&tsadc { - pinctrl-names = "gpio", "otpout"; - pinctrl-0 = <&tsadc_otp_gpio>; - pinctrl-1 = <&tsadc_otp_out>; - status = "okay"; -}; - -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&uart1_xfer &uart1_cts>; - status = "okay"; -}; - -&u2phy { - status = "okay"; - - u2phy_host: host-port { - status = "okay"; - }; - - u2phy_otg: otg-port { - status = "okay"; - }; -}; - -&usb20_otg { - status = "okay"; -}; - -&usb_host0_ehci { - status = "okay"; -}; - -&usb_host0_ohci { - status = "okay"; -}; - -&vopb { - status = "okay"; -}; - -&vopb_mmu { - status = "okay"; -}; - -&vopl { - status = "okay"; -}; - -&vopl_mmu { - status = "okay"; -}; - -&mpp_srv { - status = "okay"; -}; - -&vdpu { - status = "okay"; -}; - -&vepu { - status = "okay"; -}; - -&vpu_mmu { - status = "okay"; -}; - -&hevc { - status = "okay"; -}; - -&hevc_mmu { - status = "okay"; -}; - -&pinctrl { - headphone { - hp_det: hp-det { - rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; - - pmic { - pmic_int: pmic_int { - rockchip,pins = - <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>; - }; - - soc_slppin_gpio: soc_slppin_gpio { - rockchip,pins = - <0 RK_PA4 RK_FUNC_GPIO &pcfg_output_low>; - }; - - soc_slppin_slp: soc_slppin_slp { - rockchip,pins = - <0 RK_PA4 1 &pcfg_pull_none>; - }; - - soc_slppin_rst: soc_slppin_rst { - rockchip,pins = - <0 RK_PA4 2 &pcfg_pull_none>; - }; - }; - - sdio-pwrseq { - wifi_enable_h: wifi-enable-h { - rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; -}; - -/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */ -/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */ -/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */ - diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dts b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dts index 4fe2ab7bf8ca..ac0836b9ac13 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dts +++ b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dts @@ -5,6 +5,8 @@ */ /dts-v1/; +#include "px30.dtsi" +#include "px30-android.dtsi" #include "px30-evb-ddr3-v10.dtsi" / { @@ -125,16 +127,3 @@ }; }; }; - -&gmac { - phy-supply = <&vcc_phy>; - clock_in_out = "input"; - assigned-clocks = <&cru SCLK_GMAC>; - assigned-clock-parents = <&gmac_clkin>; - pinctrl-names = "default"; - pinctrl-0 = <&rmii_pins &mac_refclk>; - snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>; - snps,reset-active-low; - snps,reset-delays-us = <0 50000 50000>; - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi index ee2a47830a35..480e76e8dc6a 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi @@ -3,14 +3,11 @@ * Copyright (c) 2017-2019 Fuzhou Rockchip Electronics Co., Ltd */ -/dts-v1/; #include #include #include #include #include -#include "px30.dtsi" -#include "px30-android.dtsi" / { adc-keys { @@ -99,25 +96,26 @@ status = "okay"; }; - rk809-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk809-codec"; - simple-audio-card,mclk-fs = <256>; - simple-audio-card,cpu { - sound-dai = <&i2s1_2ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk809_codec>; - }; - }; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio3 RK_PA4 GPIO_ACTIVE_LOW>; + rk809_sound: rk809-sound { + status = "okay"; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk809"; + hp-det-gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>; + io-channels = <&saradc 1>; + io-channel-names = "adc-detect"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s1_2ch>; + rockchip,codec = <&rk809_codec>; pinctrl-names = "default"; pinctrl-0 = <&hp_det>; - io-channels = <&saradc 1>; + play-pause-key { + label = "playpause"; + linux,code = ; + press-threshold-microvolt = <2000>; + }; }; sdio_pwrseq: sdio-pwrseq { @@ -163,7 +161,7 @@ status = "okay"; }; - wireless-bluetooth { + wireless_bluetooth: wireless-bluetooth { compatible = "bluetooth-platdata"; clocks = <&rk809 1>; clock-names = "ext_clock"; @@ -171,8 +169,8 @@ pinctrl-names = "default","rts_gpio"; pinctrl-0 = <&uart1_rts>; pinctrl-1 = <&uart1_rts_gpio>; - BT,reset_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; - BT,wake_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_HIGH>; + BT,reset_gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; + BT,wake_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; BT,wake_host_irq = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; status = "okay"; }; @@ -227,7 +225,11 @@ &gmac { phy-supply = <&vcc_phy>; - clock_in_out = "output"; + clock_in_out = "input"; + assigned-clocks = <&cru SCLK_GMAC>; + assigned-clock-parents = <&gmac_clkin>; + pinctrl-names = "default"; + pinctrl-0 = <&rmii_pins &mac_refclk>; snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 50000 50000>; @@ -342,13 +344,13 @@ vcc_3v0: DCDC_REG4 { regulator-always-on; regulator-boot-on; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-initial-mode = <0x2>; regulator-name = "vcc_3v0"; regulator-state-mem { regulator-on-in-suspend; - regulator-suspend-microvolt = <3000000>; + regulator-suspend-microvolt = <3300000>; }; }; @@ -393,13 +395,13 @@ vcc3v0_pmu: LDO_REG4 { regulator-always-on; regulator-boot-on; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-name = "vcc3v0_pmu"; regulator-state-mem { regulator-on-in-suspend; - regulator-suspend-microvolt = <3000000>; + regulator-suspend-microvolt = <3300000>; }; }; @@ -630,7 +632,7 @@ &pinctrl { headphone { hp_det: hp-det { - rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>; + rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr4-v10.dts b/arch/arm64/boot/dts/rockchip/px30-evb-ddr4-v10.dts index ef9f356f9913..24935f2a3c03 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr4-v10.dts +++ b/arch/arm64/boot/dts/rockchip/px30-evb-ddr4-v10.dts @@ -4,34 +4,14 @@ */ /dts-v1/; +#include "px30.dtsi" +#include "px30-android.dtsi" #include "px30-evb-ddr3-v10.dtsi" #include "px30-ddr4p416dd6-timing.dtsi" / { model = "Rockchip PX30 evb ddr4 board"; compatible = "rockchip,px30-evb-ddr4-v10", "rockchip,px30"; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&hp_det>; - io-channels = <&saradc 1>; - }; - - wireless-bluetooth { - compatible = "bluetooth-platdata"; - clocks = <&rk809 1>; - clock-names = "ext_clock"; - uart_rts_gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>; - pinctrl-names = "default","rts_gpio"; - pinctrl-0 = <&uart1_rts>; - pinctrl-1 = <&uart1_rts_gpio>; - BT,reset_gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; - BT,wake_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; - BT,wake_host_irq = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; }; &chosen { @@ -296,24 +276,3 @@ }; }; }; - -&gmac { - phy-supply = <&vcc_phy>; - clock_in_out = "input"; - assigned-clocks = <&cru SCLK_GMAC>; - assigned-clock-parents = <&gmac_clkin>; - pinctrl-names = "default"; - pinctrl-0 = <&rmii_pins &mac_refclk>; - snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>; - snps,reset-active-low; - snps,reset-delays-us = <0 50000 50000>; - status = "okay"; -}; - -&pinctrl { - headphone { - hp_det: hp-det { - rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; -}; diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ext-rk618.dtsi b/arch/arm64/boot/dts/rockchip/px30-evb-ext-rk618.dtsi index 0eac63181407..f076787f5210 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ext-rk618.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-evb-ext-rk618.dtsi @@ -7,6 +7,7 @@ #include #include #include "px30-evb-ddr3-v10.dtsi" +#include "px30-android.dtsi" &dsi { status = "okay"; diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v11-avb.dts b/arch/arm64/boot/dts/rockchip/px30-mini-evb-ddr3-v11-avb.dts similarity index 95% rename from arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v11-avb.dts rename to arch/arm64/boot/dts/rockchip/px30-mini-evb-ddr3-v11-avb.dts index f2659a7f524e..c47101d4e7f9 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v11-avb.dts +++ b/arch/arm64/boot/dts/rockchip/px30-mini-evb-ddr3-v11-avb.dts @@ -4,11 +4,14 @@ */ /dts-v1/; +#include "px30.dtsi" +#include "px30-android.dtsi" #include "px30-evb-ddr3-v10.dtsi" +#include "px30-mini-evb-v11.dtsi" / { - model = "Rockchip PX30 evb ddr3 board"; - compatible = "rockchip,px30-evb-ddr3-v11-avb", "rockchip,px30"; + model = "Rockchip PX30 mini evb ddr3 board"; + compatible = "rockchip,px30-mini-evb-ddr3-v11-avb", "rockchip,px30"; }; &chosen { diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v11.dts b/arch/arm64/boot/dts/rockchip/px30-mini-evb-ddr3-v11.dts similarity index 96% rename from arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v11.dts rename to arch/arm64/boot/dts/rockchip/px30-mini-evb-ddr3-v11.dts index 2e59a09d3c5c..34d3d9cab2e5 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v11.dts +++ b/arch/arm64/boot/dts/rockchip/px30-mini-evb-ddr3-v11.dts @@ -4,11 +4,14 @@ */ /dts-v1/; +#include "px30.dtsi" +#include "px30-android.dtsi" #include "px30-evb-ddr3-v10.dtsi" +#include "px30-mini-evb-v11.dtsi" / { - model = "Rockchip PX30 evb ddr3 board"; - compatible = "rockchip,px30-evb-ddr3-v11", "rockchip,px30"; + model = "Rockchip PX30 mini evb ddr3 board"; + compatible = "rockchip,px30-mini-evb-ddr3-v11", "rockchip,px30"; }; &dsi { diff --git a/arch/arm64/boot/dts/rockchip/px30-mini-evb-v11.dtsi b/arch/arm64/boot/dts/rockchip/px30-mini-evb-v11.dtsi new file mode 100644 index 000000000000..ef6475ce4f73 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/px30-mini-evb-v11.dtsi @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Fuzhou Rockchip Electronics Co., Ltd + */ + +&gmac { + clock_in_out = "output"; + /delete-property/ assigned-clocks; + /delete-property/ assigned-clock-parents; + pinctrl-names = "default"; + pinctrl-0 = <&rmii_pins &mac_refclk_12ma>; +}; + +&rk809_sound { + hp-det-gpio = <&gpio3 RK_PA4 GPIO_ACTIVE_LOW>; +}; + + +&pinctrl { + headphone { + hp_det: hp-det { + rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +}; + +&wireless_bluetooth { + BT,reset_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; + BT,wake_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_HIGH>; +}; + diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi index afaad9a5a8e0..d4914057810a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi @@ -23,6 +23,11 @@ aliases { ethernet0 = &mac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm64/boot/dts/rockchip/rk3308k.dtsi b/arch/arm64/boot/dts/rockchip/rk3308k.dtsi index 6f9114846931..5f02591ad77b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308k.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308k.dtsi @@ -41,10 +41,10 @@ k_i = <0>; trips { - trip-point-0 { + trip-point@0 { temperature = <55000>; }; - trip-point-1 { + trip-point@1 { temperature = <90000>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-863-lp3-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-863-lp3-v10.dtsi index 9e7f1ea419a9..c7b435a3a7c9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-863-lp3-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3326-863-lp3-v10.dtsi @@ -83,29 +83,13 @@ }; rk817-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip-rk817-codec"; - simple-audio-card,mclk-fs = <256>; - simple-audio-card,widgets = - "Microphone", "Mic Jack", - "Headphone", "Headphone Jack"; - simple-audio-card,routing = - "Mic Jack", "MICBIAS1", - "IN1P", "Mic Jack", - "Headphone Jack", "HPOL", - "Headphone Jack", "HPOR"; - simple-audio-card,cpu { - sound-dai = <&i2s1_2ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk817_codec>; - }; - }; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_LOW>; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk817"; + hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_LOW>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s1_2ch>; + rockchip,codec = <&rk817_codec>; pinctrl-names = "default"; pinctrl-0 = <&hp_det>; }; @@ -245,10 +229,6 @@ status = "okay"; }; -&dsi_in_vopl { - status = "disabled"; -}; - &route_dsi { connect = <&vopb_out_dsi>; status = "okay"; @@ -800,14 +780,6 @@ status = "okay"; }; -&vopl { - status = "okay"; -}; - -&vopl_mmu { - status = "okay"; -}; - &mpp_srv { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-avb.dts b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-avb.dts index 4c12a79f814b..274dccd08acc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-avb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-avb.dts @@ -4,7 +4,10 @@ */ /dts-v1/; +#include "rk3326.dtsi" +#include "px30-android.dtsi" #include "rk3326-evb-lp3-v10.dtsi" +#include "rk3326-863-cif-sensor.dtsi" / { model = "Rockchip rk3326 evb board"; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-linux.dts b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-linux.dts index 8a93245b4880..a6dfb18c2cbd 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-linux.dts @@ -4,13 +4,9 @@ */ /dts-v1/; -#include -#include -#include -#include -#include #include "rk3326.dtsi" #include "rk3326-linux.dtsi" +#include "rk3326-evb-lp3-v10.dtsi" / { model = "Rockchip rk3326 evb lpddr3 v10 board for linux"; @@ -20,170 +16,7 @@ bootargs = "earlycon=uart8250,mmio32,0xff160000 console=ttyFIQ0 rw root=PARTUUID=614e0000-0000 rootfstype=ext4 rootwait"; }; - adc-keys { - compatible = "adc-keys"; - io-channels = <&saradc 2>; - io-channel-names = "buttons"; - poll-interval = <100>; - keyup-threshold-microvolt = <1800000>; - - esc-key { - linux,code = ; - label = "esc"; - press-threshold-microvolt = <1310000>; - }; - - home-key { - linux,code = ; - label = "home"; - press-threshold-microvolt = <624000>; - }; - - menu-key { - linux,code = ; - label = "menu"; - press-threshold-microvolt = <987000>; - }; - - vol-down-key { - linux,code = ; - label = "volume down"; - press-threshold-microvolt = <300000>; - }; - - vol-up-key { - linux,code = ; - label = "volume up"; - press-threshold-microvolt = <17000>; - }; - }; - - backlight: backlight { - compatible = "pwm-backlight"; - pwms = <&pwm1 0 25000 0>; - brightness-levels = < - 0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 - 24 25 26 27 28 29 30 31 - 32 33 34 35 36 37 38 39 - 40 41 42 43 44 45 46 47 - 48 49 50 51 52 53 54 55 - 56 57 58 59 60 61 62 63 - 64 65 66 67 68 69 70 71 - 72 73 74 75 76 77 78 79 - 80 81 82 83 84 85 86 87 - 88 89 90 91 92 93 94 95 - 96 97 98 99 100 101 102 103 - 104 105 106 107 108 109 110 111 - 112 113 114 115 116 117 118 119 - 120 121 122 123 124 125 126 127 - 128 129 130 131 132 133 134 135 - 136 137 138 139 140 141 142 143 - 144 145 146 147 148 149 150 151 - 152 153 154 155 156 157 158 159 - 160 161 162 163 164 165 166 167 - 168 169 170 171 172 173 174 175 - 176 177 178 179 180 181 182 183 - 184 185 186 187 188 189 190 191 - 192 193 194 195 196 197 198 199 - 200 201 202 203 204 205 206 207 - 208 209 210 211 212 213 214 215 - 216 217 218 219 220 221 222 223 - 224 225 226 227 228 229 230 231 - 232 233 234 235 236 237 238 239 - 240 241 242 243 244 245 246 247 - 248 249 250 251 252 253 254 255>; - default-brightness-level = <200>; - }; - - rk817-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk817-codec"; - simple-audio-card,mclk-fs = <256>; - simple-audio-card,widgets = - "Microphone", "Mic Jack", - "Headphone", "Headphone Jack"; - simple-audio-card,routing = - "MIC_IN", "Microphone Jack", - "IN1P", "Mic Jack", - "Headphone Jack", "HPOL", - "Headphone Jack", "HPOR"; - simple-audio-card,cpu { - sound-dai = <&i2s1_2ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk817_codec>; - }; - }; - - rk_headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&hp_det>; - io-channels = <&saradc 1>; - }; - - sdio_pwrseq: sdio-pwrseq { - compatible = "mmc-pwrseq-simple"; - /*clocks = <&rk817 1>;*/ - /*clock-names = "ext_clock";*/ - pinctrl-names = "default"; - pinctrl-0 = <&wifi_enable_h>; - - /* - * On the module itself this is one of these (depending - * on the actual card populated): - * - SDIO_RESET_L_WL_REG_ON - * - PDN (power down when low) - */ - reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO3_A4 */ - }; - - vccsys: vccsys { - compatible = "regulator-fixed"; - regulator-name = "vcc3v8_sys"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3800000>; - regulator-max-microvolt = <3800000>; - }; - - wireless-wlan { - compatible = "wlan-platdata"; - wifi_chip_type = "AP6210"; - WIFI,host_wake_irq = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; - - wireless-bluetooth { - compatible = "bluetooth-platdata"; - clocks = <&rk817 1>; - clock-names = "ext_clock"; - uart_rts_gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>; - pinctrl-names = "default","rts_gpio"; - pinctrl-0 = <&uart1_rts>; - pinctrl-1 = <&uart1_rts_gpio>; - BT,reset_gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; - BT,wake_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; - BT,wake_host_irq = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; - - vcc18_lcd_n: vcc18-lcd-n { - compatible = "regulator-fixed"; - regulator-name = "vcc18_lcd_n"; - regulator-boot-on; - gpio = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; -}; - -&bus_apll { - bus-supply = <&vdd_logic>; - status = "okay"; + /delete-node/ test-power; }; &cif_new { @@ -198,685 +31,6 @@ }; }; -&cpu0 { - cpu-supply = <&vdd_arm>; -}; - -&display_subsystem { - status = "okay"; -}; - -&dsi { - status = "okay"; - - panel@0 { - compatible = "sitronix,st7703", "simple-panel-dsi"; - reg = <0>; - backlight = <&backlight>; - power-supply = <&vcc18_lcd_n>; - prepare-delay-ms = <0>; - reset-delay-ms = <0>; - init-delay-ms = <80>; - enable-delay-ms = <0>; - disable-delay-ms = <10>; - unprepare-delay-ms = <60>; - - width-mm = <68>; - height-mm = <121>; - - dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>; - dsi,format = ; - dsi,lanes = <4>; - - panel-init-sequence = [ - 39 00 04 ff 98 81 03 - 15 00 02 01 00 - 15 00 02 02 00 - 15 00 02 03 53 - 15 00 02 04 53 - 15 00 02 05 13 - 15 00 02 06 04 - 15 00 02 07 02 - 15 00 02 08 02 - 15 00 02 09 00 - 15 00 02 0a 00 - 15 00 02 0b 00 - 15 00 02 0c 00 - 15 00 02 0d 00 - 15 00 02 0e 00 - 15 00 02 0f 00 - - 15 00 02 10 00 - 15 00 02 11 00 - 15 00 02 12 00 - 15 00 02 13 00 - 15 00 02 14 00 - 15 00 02 15 08 - 15 00 02 16 10 - 15 00 02 17 00 - 15 00 02 18 08 - 15 00 02 19 00 - 15 00 02 1a 00 - 15 00 02 1b 00 - 15 00 02 1c 00 - 15 00 02 1d 00 - 15 00 02 1e c0 - 15 00 02 1f 80 - - 15 00 02 20 02 - 15 00 02 21 09 - 15 00 02 22 00 - 15 00 02 23 00 - 15 00 02 24 00 - 15 00 02 25 00 - 15 00 02 26 00 - 15 00 02 27 00 - 15 00 02 28 55 - 15 00 02 29 03 - 15 00 02 2a 00 - 15 00 02 2b 00 - 15 00 02 2c 00 - 15 00 02 2d 00 - 15 00 02 2e 00 - 15 00 02 2f 00 - - 15 00 02 30 00 - 15 00 02 31 00 - 15 00 02 32 00 - 15 00 02 33 00 - 15 00 02 34 04 - 15 00 02 35 05 - 15 00 02 36 05 - 15 00 02 37 00 - 15 00 02 38 3c - 15 00 02 39 35 - 15 00 02 3a 00 - 15 00 02 3b 40 - 15 00 02 3c 00 - 15 00 02 3d 00 - 15 00 02 3e 00 - 15 00 02 3f 00 - - 15 00 02 40 00 - 15 00 02 41 88 - 15 00 02 42 00 - 15 00 02 43 00 - 15 00 02 44 1f - - 15 00 02 50 01 - 15 00 02 51 23 - 15 00 02 52 45 - 15 00 02 53 67 - 15 00 02 54 89 - 15 00 02 55 ab - 15 00 02 56 01 - 15 00 02 57 23 - 15 00 02 58 45 - 15 00 02 59 67 - 15 00 02 5a 89 - 15 00 02 5b ab - 15 00 02 5c cd - 15 00 02 5d ef - 15 00 02 5e 03 - 15 00 02 5f 14 - - 15 00 02 60 15 - 15 00 02 61 0c - 15 00 02 62 0d - 15 00 02 63 0e - 15 00 02 64 0f - 15 00 02 65 10 - 15 00 02 66 11 - 15 00 02 67 08 - 15 00 02 68 02 - 15 00 02 69 0a - 15 00 02 6a 02 - 15 00 02 6b 02 - 15 00 02 6c 02 - 15 00 02 6d 02 - 15 00 02 6e 02 - 15 00 02 6f 02 - - 15 00 02 70 02 - 15 00 02 71 02 - 15 00 02 72 06 - 15 00 02 73 02 - 15 00 02 74 02 - 15 00 02 75 14 - 15 00 02 76 15 - 15 00 02 77 0f - 15 00 02 78 0e - 15 00 02 79 0d - 15 00 02 7a 0c - 15 00 02 7b 11 - 15 00 02 7c 10 - 15 00 02 7d 06 - 15 00 02 7e 02 - 15 00 02 7f 0a - - 15 00 02 80 02 - 15 00 02 81 02 - 15 00 02 82 02 - 15 00 02 83 02 - 15 00 02 84 02 - 15 00 02 85 02 - 15 00 02 86 02 - 15 00 02 87 02 - 15 00 02 88 08 - 15 00 02 89 02 - 15 00 02 8a 02 - - 39 00 04 ff 98 81 04 - 15 00 02 00 80 - 15 00 02 70 00 - 15 00 02 71 00 - 15 00 02 66 fe - 15 00 02 82 15 - 15 00 02 84 15 - 15 00 02 85 15 - 15 00 02 3a 24 - 15 00 02 32 ac - 15 00 02 8c 80 - 15 00 02 3c f5 - 15 00 02 88 33 - - 39 00 04 ff 98 81 01 - 15 00 02 22 0a - 15 00 02 31 00 - 15 00 02 53 78 - 15 00 02 50 5b - 15 00 02 51 5b - 15 00 02 60 20 - 15 00 02 61 00 - 15 00 02 62 0d - 15 00 02 63 00 - - 15 00 02 a0 00 - 15 00 02 a1 10 - 15 00 02 a2 1c - 15 00 02 a3 13 - 15 00 02 a4 15 - 15 00 02 a5 26 - 15 00 02 a6 1a - 15 00 02 a7 1d - 15 00 02 a8 67 - 15 00 02 a9 1c - 15 00 02 aa 29 - 15 00 02 ab 5b - 15 00 02 ac 26 - 15 00 02 ad 28 - 15 00 02 ae 5c - 15 00 02 af 30 - 15 00 02 b0 31 - 15 00 02 b1 2e - 15 00 02 b2 32 - 15 00 02 b3 00 - - 15 00 02 c0 00 - 15 00 02 c1 10 - 15 00 02 c2 1c - 15 00 02 c3 13 - 15 00 02 c4 15 - 15 00 02 c5 26 - 15 00 02 c6 1a - 15 00 02 c7 1d - 15 00 02 c8 67 - 15 00 02 c9 1c - 15 00 02 ca 29 - 15 00 02 cb 5b - 15 00 02 cc 26 - 15 00 02 cd 28 - 15 00 02 ce 5c - 15 00 02 cf 30 - 15 00 02 d0 31 - 15 00 02 d1 2e - 15 00 02 d2 32 - 15 00 02 d3 00 - 39 00 04 ff 98 81 00 - 05 00 01 11 - 05 01 01 29 - ]; - - panel-exit-sequence = [ - 05 00 01 28 - 05 00 01 10 - ]; - - display-timings { - native-mode = <&timing0>; - - timing0: timing0 { - clock-frequency = <66000000>; - hactive = <720>; - vactive = <1280>; - hfront-porch = <40>; - hsync-len = <10>; - hback-porch = <40>; - vfront-porch = <22>; - vsync-len = <4>; - vback-porch = <11>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <0>; - pixelclk-active = <0>; - }; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - panel_in_dsi: endpoint { - remote-endpoint = <&dsi_out_panel>; - }; - }; - }; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@1 { - reg = <1>; - dsi_out_panel: endpoint { - remote-endpoint = <&panel_in_dsi>; - }; - }; - }; -}; - -&dsi_in_vopb { - status = "okay"; -}; - -&dsi_in_vopl { - status = "disabled"; -}; - -&route_dsi { - connect = <&vopb_out_dsi>; - status = "okay"; -}; - -&dfi { - status = "okay"; -}; - -&dmc { - center-supply = <&vdd_logic>; - status = "okay"; -}; - -&emmc { - bus-width = <8>; - cap-mmc-highspeed; - mmc-hs200-1_8v; - no-sdio; - no-sd; - disable-wp; - non-removable; - num-slots = <1>; - status = "okay"; -}; - -&gpu { - mali-supply = <&vdd_logic>; - status = "okay"; -}; - -&i2c0 { - status = "okay"; - clock-frequency = <400000>; - i2c-scl-rising-time-ns = <280>; - i2c-scl-falling-time-ns = <16>; - - rk817: pmic@20 { - compatible = "rockchip,rk817"; - reg = <0x20>; - interrupt-parent = <&gpio0>; - interrupts = <7 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default", "pmic-sleep", - "pmic-power-off", "pmic-reset"; - pinctrl-0 = <&pmic_int>; - pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>; - pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>; - pinctrl-3 = <&soc_slppin_rst>, <&rk817_slppin_rst>; - rockchip,system-power-controller; - wakeup-source; - #clock-cells = <1>; - clock-output-names = "rk808-clkout1", "rk808-clkout2"; - //fb-inner-reg-idxs = <2>; - /* 1: rst regs (default in codes), 0: rst the pmic */ - pmic-reset-func = <1>; - - vcc1-supply = <&vccsys>; - vcc2-supply = <&vccsys>; - vcc3-supply = <&vccsys>; - vcc4-supply = <&vccsys>; - vcc5-supply = <&vccsys>; - vcc6-supply = <&vccsys>; - vcc7-supply = <&vcc_3v0>; - vcc8-supply = <&vccsys>; - vcc9-supply = <&dcdc_boost>; - - pwrkey { - status = "okay"; - }; - - pinctrl_rk8xx: pinctrl_rk8xx { - gpio-controller; - #gpio-cells = <2>; - - rk817_ts_gpio1: rk817_ts_gpio1 { - pins = "gpio_ts"; - function = "pin_fun1"; - /* output-low; */ - /* input-enable; */ - }; - - rk817_gt_gpio2: rk817_gt_gpio2 { - pins = "gpio_gt"; - function = "pin_fun1"; - }; - - rk817_pin_ts: rk817_pin_ts { - pins = "gpio_ts"; - function = "pin_fun0"; - }; - - rk817_pin_gt: rk817_pin_gt { - pins = "gpio_gt"; - function = "pin_fun0"; - }; - - rk817_slppin_null: rk817_slppin_null { - pins = "gpio_slp"; - function = "pin_fun0"; - }; - - rk817_slppin_slp: rk817_slppin_slp { - pins = "gpio_slp"; - function = "pin_fun1"; - }; - - rk817_slppin_pwrdn: rk817_slppin_pwrdn { - pins = "gpio_slp"; - function = "pin_fun2"; - }; - - rk817_slppin_rst: rk817_slppin_rst { - pins = "gpio_slp"; - function = "pin_fun3"; - }; - }; - - regulators { - vdd_logic: DCDC_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1350000>; - regulator-ramp-delay = <6001>; - regulator-initial-mode = <0x2>; - regulator-name = "vdd_logic"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <950000>; - }; - }; - - vdd_arm: DCDC_REG2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1350000>; - regulator-ramp-delay = <6001>; - regulator-initial-mode = <0x2>; - regulator-name = "vdd_arm"; - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <950000>; - }; - }; - - vcc_ddr: DCDC_REG3 { - regulator-always-on; - regulator-boot-on; - regulator-initial-mode = <0x2>; - regulator-name = "vcc_ddr"; - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_3v0: DCDC_REG4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-initial-mode = <0x2>; - regulator-name = "vcc_3v0"; - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <3000000>; - }; - }; - - vcc_1v0: LDO_REG1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-name = "vcc_1v0"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vcc1v8_soc: LDO_REG2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-name = "vcc1v8_soc"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd1v0_soc: LDO_REG3 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - - regulator-name = "vcc1v0_soc"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vcc3v0_pmu: LDO_REG4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - - regulator-name = "vcc3v0_pmu"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3000000>; - - }; - }; - - vccio_sd: LDO_REG5 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - - regulator-name = "vccio_sd"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vcc_sd: LDO_REG6 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - - regulator-name = "vcc_sd"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - - }; - }; - - vcc2v8_dvp: LDO_REG7 { - regulator-boot-on; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - - regulator-name = "vcc2v8_dvp"; - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <2800000>; - }; - }; - - vcc1v8_dvp: LDO_REG8 { - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-name = "vcc1v8_dvp"; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd1v5_dvp: LDO_REG9 { - regulator-boot-on; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; - - regulator-name = "vdd1v5_dvp"; - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <1500000>; - }; - }; - - dcdc_boost: BOOST { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <4700000>; - regulator-max-microvolt = <5400000>; - regulator-name = "boost"; - }; - - otg_switch: OTG_SWITCH { - regulator-name = "otg_switch"; - }; - }; - - battery { - compatible = "rk817,battery"; - ocv_table = <3500 3625 3685 3697 3718 3735 3748 - 3760 3774 3788 3802 3816 3834 3853 - 3877 3908 3946 3975 4018 4071 4106>; - design_capacity = <2500>; - design_qmax = <2750>; - bat_res = <100>; - sleep_enter_current = <300>; - sleep_exit_current = <300>; - sleep_filter_current = <100>; - power_off_thresd = <3500>; - zero_algorithm_vol = <3850>; - max_soc_offset = <60>; - monitor_sec = <5>; - sample_res = <10>; - virtual_power = <1>; - }; - - charger { - compatible = "rk817,charger"; - min_input_voltage = <4500>; - max_input_current = <1500>; - max_chrg_current = <2000>; - max_chrg_voltage = <4200>; - chrg_term_mode = <0>; - chrg_finish_cur = <300>; - virtual_power = <0>; - dc_det_adc = <0>; - extcon = <&u2phy>; - }; - - rk817_codec: codec { - #sound-dai-cells = <0>; - compatible = "rockchip,rk817-codec"; - clocks = <&cru SCLK_I2S1_OUT>; - clock-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&i2s1_2ch_mclk>; - hp-volume = <20>; - spk-volume = <3>; - status = "okay"; - }; - }; -}; - -&i2c1 { - status = "okay"; - clock-frequency = <400000>; - i2c-scl-rising-time-ns = <275>; - i2c-scl-falling-time-ns = <16>; - - sensor@f { - status = "okay"; - compatible = "ak8963"; - reg = <0x0f>; - type = ; - irq_enable = <0>; - poll_delay_ms = <30>; - layout = <1>; - reprobe_en = <1>; - }; - - gt1x: gt1x@14 { - compatible = "goodix,gt1x"; - reg = <0x14>; - power-supply = <&vcc18_lcd_n>; - goodix,rst-gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; - goodix,irq-gpio = <&gpio0 RK_PA5 IRQ_TYPE_LEVEL_LOW>; - }; - - sensor@4c { - status = "okay"; - compatible = "gs_mma7660"; - reg = <0x4c>; - type = ; - irq-gpio = <&gpio0 RK_PB5 IRQ_TYPE_LEVEL_LOW>; - irq_enable = <0>; - poll_delay_ms = <30>; - layout = <1>; - reprobe_en = <1>; - }; -}; - &i2c2 { status = "okay"; clock-frequency = <400000>; @@ -939,25 +93,6 @@ }; }; -&i2s1_2ch { - status = "okay"; - #sound-dai-cells = <0>; -}; - -&io_domains { - status = "okay"; - - vccio1-supply = <&vcc1v8_soc>; - vccio2-supply = <&vccio_sd>; - vccio3-supply = <&vcc1v8_dvp>; - vccio4-supply = <&vcc_3v0>; - vccio5-supply = <&vcc_3v0>; -}; - -&isp_mmu { - status = "okay"; -}; - &mipi_dphy_rx0 { status = "okay"; @@ -990,153 +125,6 @@ }; }; -&nandc0 { - status = "okay"; -}; - -&rkisp1 { - status = "okay"; - - port { - #address-cells = <1>; - #size-cells = <0>; - - isp0_mipi_in: endpoint@0 { - reg = <0>; - remote-endpoint = <&dphy_rx0_out>; - }; - }; -}; - -&pmu_io_domains { - status = "okay"; - - pmuio1-supply = <&vcc3v0_pmu>; - pmuio2-supply = <&vcc3v0_pmu>; -}; - -&pwm1 { - status = "okay"; -}; - -&rk_rga { - status = "okay"; -}; - -&rockchip_suspend { - status = "okay"; - rockchip,sleep-debug-en = <1>; -}; - -&saradc { - status = "okay"; - vref-supply = <&vcc1v8_soc>; -}; - -&sdmmc { - bus-width = <4>; - cap-mmc-highspeed; - cap-sd-highspeed; - no-sdio; - no-mmc; - card-detect-delay = <800>; - ignore-pm-notify; - /*cd-gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>; [> CD GPIO <]*/ - sd-uhs-sdr12; - sd-uhs-sdr25; - sd-uhs-sdr50; - sd-uhs-sdr104; - vqmmc-supply = <&vccio_sd>; - vmmc-supply = <&vcc_sd>; - status = "disabled"; -}; - -&sdio { - bus-width = <4>; - cap-sd-highspeed; - no-sd; - no-mmc; - ignore-pm-notify; - keep-power-in-suspend; - non-removable; - mmc-pwrseq = <&sdio_pwrseq>; - sd-uhs-sdr104; - status = "okay"; -}; - -&tsadc { - pinctrl-names = "gpio", "otpout"; - pinctrl-0 = <&tsadc_otp_gpio>; - pinctrl-1 = <&tsadc_otp_out>; - status = "okay"; -}; - -&u2phy { - status = "okay"; - - u2phy_host: host-port { - status = "okay"; - }; - - u2phy_otg: otg-port { - status = "okay"; - }; -}; - -&usb20_otg { - status = "okay"; -}; - -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&uart1_xfer &uart1_cts>; - status = "okay"; -}; - -&vip_mmu { - status = "okay"; -}; - -&vopb { - status = "okay"; -}; - -&vopb_mmu { - status = "okay"; -}; - -&vopl { - status = "okay"; -}; - -&vopl_mmu { - status = "okay"; -}; - -&mpp_srv { - status = "okay"; -}; - -&vdpu { - status = "okay"; -}; - -&vepu { - status = "okay"; -}; - -&vpu_mmu { - status = "okay"; -}; - -&hevc { - status = "okay"; -}; - -&hevc_mmu { - status = "okay"; -}; - &pinctrl { cif-pin-m0 { cif_pin_m0: cif-pin-m0 { @@ -1154,42 +142,22 @@ <2 RK_PB2 1 &pcfg_pull_none>;/* cif_clkin */ }; }; +}; - headphone { - hp_det: hp-det { - rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; +&rkisp1 { + status = "okay"; - pmic { - pmic_int: pmic_int { - rockchip,pins = - <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>; - }; + port { + #address-cells = <1>; + #size-cells = <0>; - soc_slppin_gpio: soc_slppin_gpio { - rockchip,pins = - <0 RK_PA4 RK_FUNC_GPIO &pcfg_output_low>; - }; - - soc_slppin_slp: soc_slppin_slp { - rockchip,pins = - <0 RK_PA4 1 &pcfg_pull_none>; - }; - - soc_slppin_rst: soc_slppin_rst { - rockchip,pins = - <0 RK_PA4 2 &pcfg_pull_none>; - }; - }; - - sdio-pwrseq { - wifi_enable_h: wifi-enable-h { - rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + isp0_mipi_in: endpoint@0 { + reg = <0>; + remote-endpoint = <&dphy_rx0_out>; }; }; }; -/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */ -/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */ -/* DON'T PUT ANYTHING BELOW HERE. PUT IT ABOVE PINCTRL */ +&vip_mmu { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dts b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dts index 58bbfdafb489..cc2057e8f8c5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dts @@ -4,7 +4,10 @@ */ /dts-v1/; +#include "rk3326.dtsi" +#include "px30-android.dtsi" #include "rk3326-evb-lp3-v10.dtsi" +#include "rk3326-863-cif-sensor.dtsi" / { model = "Rockchip rk3326 evb board"; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dtsi index 688b5be11be5..9eace0c152ef 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10.dtsi @@ -3,15 +3,11 @@ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd */ -/dts-v1/; #include #include #include #include #include -#include "rk3326.dtsi" -#include "rk3326-863-cif-sensor.dtsi" -#include "px30-android.dtsi" / { adc-keys { @@ -92,24 +88,24 @@ }; rk817-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk817-codec"; - simple-audio-card,mclk-fs = <256>; - simple-audio-card,cpu { - sound-dai = <&i2s1_2ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk817_codec>; - }; - }; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_LOW>; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk817"; + hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_LOW>; + io-channels = <&saradc 1>; + io-channel-names = "adc-detect"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s1_2ch>; + rockchip,codec = <&rk817_codec>; pinctrl-names = "default"; pinctrl-0 = <&hp_det>; - io-channels = <&saradc 1>; + play-pause-key { + label = "playpause"; + linux,code = ; + press-threshold-microvolt = <2000>; + }; }; sdio_pwrseq: sdio-pwrseq { @@ -308,10 +304,6 @@ status = "okay"; }; -&dsi_in_vopl { - status = "disabled"; -}; - &route_dsi { connect = <&vopb_out_dsi>; status = "okay"; @@ -850,14 +842,6 @@ status = "okay"; }; -&vopl { - status = "okay"; -}; - -&vopl_mmu { - status = "okay"; -}; - &mpp_srv { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11-avb.dts b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11-avb.dts index 2f0c3fc3a38d..0f2a35179f43 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11-avb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11-avb.dts @@ -4,7 +4,10 @@ */ /dts-v1/; +#include "rk3326.dtsi" +#include "px30-android.dtsi" #include "rk3326-evb-lp3-v10.dtsi" +#include "rk3326-863-cif-sensor.dtsi" / { model = "Rockchip rk3326 evb board"; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11.dts b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11.dts index 139efd9d1332..f8a3eef33f4e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v11.dts @@ -4,7 +4,10 @@ */ /dts-v1/; +#include "rk3326.dtsi" +#include "px30-android.dtsi" #include "rk3326-evb-lp3-v10.dtsi" +#include "rk3326-863-cif-sensor.dtsi" / { model = "Rockchip rk3326 evb board"; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v12-linux.dts b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v12-linux.dts new file mode 100644 index 000000000000..ed0781d2f2a8 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v12-linux.dts @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd + * + */ + +/dts-v1/; + +#include "rk3326-evb-lp3-v10-linux.dts" + +/ { + model = "Rockchip rk3326 evb lpddr3 v12 board for linux"; + compatible = "rockchip,rk3326-evb-lp3-v12-linux", "rockchip,rk3326"; +}; + +&dsi { + status = "okay"; + + panel@0 { + compatible = "sitronix,st7703", "simple-panel-dsi"; + reg = <0>; + backlight = <&backlight>; + power-supply = <&vcc18_lcd_n>; + prepare-delay-ms = <0>; + reset-delay-ms = <0>; + init-delay-ms = <80>; + enable-delay-ms = <0>; + disable-delay-ms = <10>; + unprepare-delay-ms = <60>; + + width-mm = <68>; + height-mm = <121>; + + dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>; + dsi,format = ; + dsi,lanes = <4>; + + panel-init-sequence = [ + 39 00 04 ff 98 81 03 + 15 00 02 01 00 + 15 00 02 02 00 + 15 00 02 03 53 + 15 00 02 04 53 + 15 00 02 05 13 + 15 00 02 06 04 + 15 00 02 07 02 + 15 00 02 08 02 + 15 00 02 09 00 + 15 00 02 0a 00 + 15 00 02 0b 00 + 15 00 02 0c 00 + 15 00 02 0d 00 + 15 00 02 0e 00 + 15 00 02 0f 00 + + 15 00 02 10 00 + 15 00 02 11 00 + 15 00 02 12 00 + 15 00 02 13 00 + 15 00 02 14 00 + 15 00 02 15 08 + 15 00 02 16 10 + 15 00 02 17 00 + 15 00 02 18 08 + 15 00 02 19 00 + 15 00 02 1a 00 + 15 00 02 1b 00 + 15 00 02 1c 00 + 15 00 02 1d 00 + 15 00 02 1e c0 + 15 00 02 1f 80 + + 15 00 02 20 02 + 15 00 02 21 09 + 15 00 02 22 00 + 15 00 02 23 00 + 15 00 02 24 00 + 15 00 02 25 00 + 15 00 02 26 00 + 15 00 02 27 00 + 15 00 02 28 55 + 15 00 02 29 03 + 15 00 02 2a 00 + 15 00 02 2b 00 + 15 00 02 2c 00 + 15 00 02 2d 00 + 15 00 02 2e 00 + 15 00 02 2f 00 + + 15 00 02 30 00 + 15 00 02 31 00 + 15 00 02 32 00 + 15 00 02 33 00 + 15 00 02 34 04 + 15 00 02 35 05 + 15 00 02 36 05 + 15 00 02 37 00 + 15 00 02 38 3c + 15 00 02 39 35 + 15 00 02 3a 00 + 15 00 02 3b 40 + 15 00 02 3c 00 + 15 00 02 3d 00 + 15 00 02 3e 00 + 15 00 02 3f 00 + + 15 00 02 40 00 + 15 00 02 41 88 + 15 00 02 42 00 + 15 00 02 43 00 + 15 00 02 44 1f + + 15 00 02 50 01 + 15 00 02 51 23 + 15 00 02 52 45 + 15 00 02 53 67 + 15 00 02 54 89 + 15 00 02 55 ab + 15 00 02 56 01 + 15 00 02 57 23 + 15 00 02 58 45 + 15 00 02 59 67 + 15 00 02 5a 89 + 15 00 02 5b ab + 15 00 02 5c cd + 15 00 02 5d ef + 15 00 02 5e 03 + 15 00 02 5f 14 + + 15 00 02 60 15 + 15 00 02 61 0c + 15 00 02 62 0d + 15 00 02 63 0e + 15 00 02 64 0f + 15 00 02 65 10 + 15 00 02 66 11 + 15 00 02 67 08 + 15 00 02 68 02 + 15 00 02 69 0a + 15 00 02 6a 02 + 15 00 02 6b 02 + 15 00 02 6c 02 + 15 00 02 6d 02 + 15 00 02 6e 02 + 15 00 02 6f 02 + + 15 00 02 70 02 + 15 00 02 71 02 + 15 00 02 72 06 + 15 00 02 73 02 + 15 00 02 74 02 + 15 00 02 75 14 + 15 00 02 76 15 + 15 00 02 77 0f + 15 00 02 78 0e + 15 00 02 79 0d + 15 00 02 7a 0c + 15 00 02 7b 11 + 15 00 02 7c 10 + 15 00 02 7d 06 + 15 00 02 7e 02 + 15 00 02 7f 0a + + 15 00 02 80 02 + 15 00 02 81 02 + 15 00 02 82 02 + 15 00 02 83 02 + 15 00 02 84 02 + 15 00 02 85 02 + 15 00 02 86 02 + 15 00 02 87 02 + 15 00 02 88 08 + 15 00 02 89 02 + 15 00 02 8a 02 + + 39 00 04 ff 98 81 04 + 15 00 02 00 80 + 15 00 02 70 00 + 15 00 02 71 00 + 15 00 02 66 fe + 15 00 02 82 15 + 15 00 02 84 15 + 15 00 02 85 15 + 15 00 02 3a 24 + 15 00 02 32 ac + 15 00 02 8c 80 + 15 00 02 3c f5 + 15 00 02 88 33 + + 39 00 04 ff 98 81 01 + 15 00 02 22 0a + 15 00 02 31 00 + 15 00 02 53 78 + 15 00 02 50 5b + 15 00 02 51 5b + 15 00 02 60 20 + 15 00 02 61 00 + 15 00 02 62 0d + 15 00 02 63 00 + + 15 00 02 a0 00 + 15 00 02 a1 10 + 15 00 02 a2 1c + 15 00 02 a3 13 + 15 00 02 a4 15 + 15 00 02 a5 26 + 15 00 02 a6 1a + 15 00 02 a7 1d + 15 00 02 a8 67 + 15 00 02 a9 1c + 15 00 02 aa 29 + 15 00 02 ab 5b + 15 00 02 ac 26 + 15 00 02 ad 28 + 15 00 02 ae 5c + 15 00 02 af 30 + 15 00 02 b0 31 + 15 00 02 b1 2e + 15 00 02 b2 32 + 15 00 02 b3 00 + + 15 00 02 c0 00 + 15 00 02 c1 10 + 15 00 02 c2 1c + 15 00 02 c3 13 + 15 00 02 c4 15 + 15 00 02 c5 26 + 15 00 02 c6 1a + 15 00 02 c7 1d + 15 00 02 c8 67 + 15 00 02 c9 1c + 15 00 02 ca 29 + 15 00 02 cb 5b + 15 00 02 cc 26 + 15 00 02 cd 28 + 15 00 02 ce 5c + 15 00 02 cf 30 + 15 00 02 d0 31 + 15 00 02 d1 2e + 15 00 02 d2 32 + 15 00 02 d3 00 + 39 00 04 ff 98 81 00 + 05 00 01 11 + 05 01 01 29 + ]; + + panel-exit-sequence = [ + 05 00 01 28 + 05 00 01 10 + ]; + + display-timings { + native-mode = <&timing0>; + + timing0: timing0 { + clock-frequency = <66000000>; + hactive = <720>; + vactive = <1280>; + hfront-porch = <40>; + hsync-len = <10>; + hback-porch = <40>; + vfront-porch = <22>; + vsync-len = <4>; + vback-porch = <11>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi index 623431e2e355..f3ed899ab054 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi @@ -39,6 +39,15 @@ compatible = "rockchip,drm-logo"; reg = <0x0 0x0 0x0 0x0>; }; + + ramoops: ramoops@110000 { + compatible = "ramoops"; + reg = <0x0 0x110000 0x0 0xf0000>; + record-size = <0x20000>; + console-size = <0x80000>; + ftrace-size = <0x00000>; + pmsg-size = <0x50000>; + }; }; }; @@ -48,7 +57,6 @@ &display_subsystem { status = "disabled"; - ports = <&vopb_out>, <&vopl_out>; logo-memory-region = <&drm_logo>; route { diff --git a/arch/arm64/boot/dts/rockchip/rk3326.dtsi b/arch/arm64/boot/dts/rockchip/rk3326.dtsi index fdb000c14038..004bda94a955 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3326.dtsi @@ -10,6 +10,10 @@ assigned-clock-rates = <1040000000>; }; +&display_subsystem { + ports = <&vopb_out>; +}; + &gpu_opp_table { opp-520000000 { opp-hz = /bits/ 64 <520000000>; @@ -76,3 +80,9 @@ }; }; }; + +/delete-node/ &dsi_in_vopl; +/delete-node/ &lvds_vopl_in; +/delete-node/ &rgb_in_vopl; +/delete-node/ &vopl; +/delete-node/ &vopl_mmu; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index ddf1792bfa2f..503dba319e73 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -20,6 +20,10 @@ #size-cells = <2>; aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index e962c7962789..cf6b66e022c0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi @@ -19,6 +19,10 @@ aliases { ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts index 6589bb6853f2..b4b3a003dd33 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts @@ -287,6 +287,11 @@ status = "okay"; }; +&route_hdmi { + status = "okay"; + connect = <&vopb_out_hdmi>; +}; + /* * if enable dp_sound, should disable spdif_sound and spdif_out */ diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index b0188e115097..64b2d7f2fee5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -27,6 +27,11 @@ dsi0 = &dsi; dsi1 = &dsi1; ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-evb1-ddr4-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-evb1-ddr4-v10.dtsi index b41db0eb5510..1ce24932257a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-evb1-ddr4-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-evb1-ddr4-v10.dtsi @@ -25,13 +25,6 @@ vin-supply = <&dc_12v>; }; - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&hp_det>; - }; - vcc3v3_vga: vcc3v3-vga { compatible = "regulator-fixed"; regulator-name = "vcc3v3_vga"; @@ -457,12 +450,6 @@ }; }; - headphone { - hp_det: hp-det { - rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; - lcd0 { lcd0_rst_gpio: lcd0-rst-gpio { rockchip,pins = <4 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-evb2-lp4x-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-evb2-lp4x-v10.dtsi index fbbd5d038d54..7dc4e284891b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-evb2-lp4x-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-evb2-lp4x-v10.dtsi @@ -16,13 +16,6 @@ model = "Rockchip RK3566 EVB2 LP4X V10 Board"; compatible = "rockchip,rk3566-evb2-lp4x-v10", "rockchip,rk3566"; - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&hp_det>; - }; - vcc_camera: vcc-camera-regulator { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; @@ -78,6 +71,18 @@ remote-endpoint = <&gc8034_out>; data-lanes = <1 2 3 4>; }; + + mipi_in_ucam1: endpoint@2 { + reg = <2>; + remote-endpoint = <&ov5695_out>; + data-lanes = <1 2>; + }; + + mipi_in_ucam2: endpoint@3 { + reg = <3>; + remote-endpoint = <&gc5025_out>; + data-lanes = <1 2>; + }; }; port@1 { @@ -112,7 +117,7 @@ dphy1_in: endpoint@1 { reg = <1>; - remote-endpoint = <&ov5695_out>; + //remote-endpoint = <&ov5695_out>; data-lanes = <1 2>; }; }; @@ -149,7 +154,7 @@ dphy2_in: endpoint@1 { reg = <1>; - remote-endpoint = <&gc5025_out>; + //remote-endpoint = <&gc5025_out>; data-lanes = <1 2>; }; }; @@ -263,7 +268,7 @@ rockchip,camera-module-lens-name = "CHT842-MD"; port { ov5695_out: endpoint { - remote-endpoint = <&dphy1_in>; + remote-endpoint = <&mipi_in_ucam1>; data-lanes = <1 2>; }; }; @@ -288,7 +293,7 @@ rockchip,camera-module-lens-name = "CHT842-MD"; port { gc5025_out: endpoint { - remote-endpoint = <&dphy2_in>; + remote-endpoint = <&mipi_in_ucam2>; data-lanes = <1 2>; }; }; @@ -430,12 +435,6 @@ }; }; - headphone { - hp_det: hp-det { - rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; - sdio-pwrseq { wifi_enable_h: wifi-enable-h { rockchip,pins = <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-rk817-eink.dts b/arch/arm64/boot/dts/rockchip/rk3566-rk817-eink.dts index 50412b44bb71..d491ba8ee87d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-rk817-eink.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-rk817-eink.dts @@ -75,17 +75,15 @@ }; rk817-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk817-codec"; - simple-audio-card,mclk-fs = <256>; - - simple-audio-card,cpu { - sound-dai = <&i2s1_8ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk817_codec>; - }; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk817"; + hp-det-gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_LOW>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s1_8ch>; + rockchip,codec = <&rk817_codec>; + pinctrl-names = "default"; + pinctrl-0 = <&hp_det>; }; sdio_pwrseq: sdio-pwrseq { diff --git a/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet-v10.dts b/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet-v10.dts index 1d4a0484473a..4f3c935998a0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet-v10.dts @@ -137,25 +137,24 @@ }; rk817-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk817-codec"; - simple-audio-card,mclk-fs = <256>; - - simple-audio-card,cpu { - sound-dai = <&i2s1_8ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk817_codec>; - }; - }; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_LOW>; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk817"; + hp-det-gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_LOW>; + io-channels = <&saradc 2>; + io-channel-names = "adc-detect"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s1_8ch>; + rockchip,codec = <&rk817_codec>; pinctrl-names = "default"; pinctrl-0 = <&hp_det>; - io-channels = <&saradc 2>; + play-pause-key { + label = "playpause"; + linux,code = ; + press-threshold-microvolt = <2000>; + }; }; sdio_pwrseq: sdio-pwrseq { diff --git a/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts b/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts index 40022eb6c646..9e2f59073671 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts @@ -137,25 +137,24 @@ }; rk817-sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk817-codec"; - simple-audio-card,mclk-fs = <256>; - - simple-audio-card,cpu { - sound-dai = <&i2s1_8ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk817_codec>; - }; - }; - - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_LOW>; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk817"; + hp-det-gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_LOW>; + io-channels = <&saradc 2>; + io-channel-names = "adc-detect"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s1_8ch>; + rockchip,codec = <&rk817_codec>; pinctrl-names = "default"; pinctrl-0 = <&hp_det>; - io-channels = <&saradc 2>; + play-pause-key { + label = "playpause"; + linux,code = ; + press-threshold-microvolt = <2000>; + }; }; sdio_pwrseq: sdio-pwrseq { diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi index c6e3f77abfd9..8a3dfb933b51 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi @@ -193,17 +193,15 @@ rk809_sound: rk809-sound { status = "okay"; - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,name = "rockchip,rk809-codec"; - simple-audio-card,mclk-fs = <256>; - - simple-audio-card,cpu { - sound-dai = <&i2s1_8ch>; - }; - simple-audio-card,codec { - sound-dai = <&rk809_codec 0>; - }; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk809"; + hp-det-gpio = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s1_8ch>; + rockchip,codec = <&rk809_codec>; + pinctrl-names = "default"; + pinctrl-0 = <&hp_det>; }; spdif-sound { @@ -1452,6 +1450,12 @@ &pinctrl { + headphone { + hp_det: hp-det { + rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + mxc6655xa { mxc6655xa_irq_gpio: mxc6655xa_irq_gpio { rockchip,pins = <3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi index 3860aca56a13..7ef900001f51 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi @@ -15,13 +15,6 @@ model = "Rockchip RK3568 EVB1 DDR4 V10 Board"; compatible = "rockchip,rk3568-evb1-ddr4-v10", "rockchip,rk3568"; - rk_headset: rk-headset { - compatible = "rockchip_headset"; - headset_gpio = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&hp_det>; - }; - vcc2v5_sys: vcc2v5-ddr { compatible = "regulator-fixed"; regulator-name = "vcc2v5-sys"; @@ -398,6 +391,10 @@ }; }; +&rk809_sound { + hp-det-gpio = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>; +}; + &rkisp { status = "okay"; }; @@ -425,6 +422,11 @@ connect = <&vp1_out_dsi0>; }; +&route_edp { + status = "okay"; + connect = <&vp0_out_edp>; +}; + &sata2 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index e9790f5cd2fd..c5a7af71d403 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -2892,7 +2892,7 @@ }; can0: can@fe570000 { - compatible = "rockchip,canfd-1.0"; + compatible = "rockchip,rk3568-can-2.0"; reg = <0x0 0xfe570000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru PCLK_CAN0>; @@ -2905,7 +2905,7 @@ }; can1: can@fe580000 { - compatible = "rockchip,canfd-1.0"; + compatible = "rockchip,rk3568-can-2.0"; reg = <0x0 0xfe580000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru PCLK_CAN1>; @@ -2918,7 +2918,7 @@ }; can2: can@fe590000 { - compatible = "rockchip,canfd-1.0"; + compatible = "rockchip,rk3568-can-2.0"; reg = <0x0 0xfe590000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN2>, <&cru PCLK_CAN2>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi index 71ba6f7eb0fe..d4cdfb8b9e9f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi @@ -53,15 +53,6 @@ }; }; - ramoops: ramoops@110000 { - compatible = "ramoops"; - reg = <0x0 0x110000 0x0 0xf0000>; - record-size = <0x20000>; - console-size = <0x80000>; - ftrace-size = <0x00000>; - pmsg-size = <0x50000>; - }; - reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -83,6 +74,18 @@ compatible = "rockchip,drm-cubic-lut"; reg = <0x0 0x0 0x0 0x0>; }; + + ramoops: ramoops@110000 { + compatible = "ramoops"; + /* 0x110000 to 0x1f0000 is for ramoops */ + reg = <0x0 0x110000 0x0 0xe0000>; + boot-log-size = <0x8000>; /* do not change */ + boot-log-count = <0x1>; /* do not change */ + console-size = <0x80000>; + pmsg-size = <0x30000>; + ftrace-size = <0x00000>; + record-size = <0x14000>; + }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10-ipc-6x-linux.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10-ipc-6x-linux.dts index 4ee88903c50f..2dcef191fc6b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10-ipc-6x-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10-ipc-6x-linux.dts @@ -67,18 +67,6 @@ status = "disabled"; }; -&hdmi0 { - status = "disabled"; -}; - -&hdmi0_in_vp0 { - status = "disabled"; -}; - -&hdmi0_sound { - status = "disabled"; -}; - &hdmi1 { status = "disabled"; }; @@ -91,10 +79,6 @@ status = "disabled"; }; -&hdptxphy_hdmi0 { - status = "disabled"; -}; - &hdptxphy_hdmi1 { status = "disabled"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi index f5269776b64e..d7708b7f9005 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi @@ -62,6 +62,20 @@ }; }; + fan: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + pwms = <&pwm9 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; + }; + hdmiin_dc: hdmiin-dc { compatible = "rockchip,dummy-codec"; #sound-dai-cells = <0>; @@ -613,7 +627,7 @@ touch_gpio: touch-gpio { rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>, - <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; }; }; @@ -666,6 +680,11 @@ status = "okay"; }; +&pwm9 { + pinctrl-0 = <&pwm9m1_pins>; + status = "okay"; +}; + &route_dsi0 { status = "okay"; connect = <&vp3_out_dsi0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb2-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb2-lp4.dtsi index 1f2822c781d9..37d7bdfe5706 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb2-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb2-lp4.dtsi @@ -67,6 +67,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm9 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; pcie20_avdd0v85: pcie20-avdd0v85 { @@ -411,7 +419,7 @@ touch_gpio: touch-gpio { rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>, - <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb3-lp5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb3-lp5.dtsi index 90354594a657..3b08bb998fe9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb3-lp5.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb3-lp5.dtsi @@ -68,6 +68,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm6 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; hall_sensor: hall-mh248 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb4-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb4-lp4.dtsi index 4f6e0c422062..ef5dd89975c4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb4-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb4-lp4.dtsi @@ -14,6 +14,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm14 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; pcie30_avdd1v8: pcie30-avdd1v8 { @@ -373,7 +381,7 @@ touch_gpio: touch-gpio { rockchip,pins = <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>, - <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb5-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb5-lp4.dtsi index e05e2948d8ab..8e783a98735c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb5-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb5-lp4.dtsi @@ -28,6 +28,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm9 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; hdmiin_dc: hdmiin-dc { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb6-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb6-lp4.dtsi index 53c30e532694..96b7406c9b3a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb6-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb6-lp4.dtsi @@ -416,7 +416,7 @@ touch_gpio: touch-gpio { rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>, - <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi index 639f23a67369..d08549fa78aa 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi @@ -66,6 +66,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm3 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; hdmiin_dc: hdmiin-dc { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi index ea2303acd475..12b815850b57 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi @@ -60,15 +60,6 @@ }; }; - ramoops: ramoops@110000 { - compatible = "ramoops"; - reg = <0x0 0x110000 0x0 0xf0000>; - record-size = <0x20000>; - console-size = <0x80000>; - ftrace-size = <0x00000>; - pmsg-size = <0x50000>; - }; - reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -90,6 +81,15 @@ compatible = "rockchip,drm-cubic-lut"; reg = <0x0 0x0 0x0 0x0>; }; + + ramoops: ramoops@110000 { + compatible = "ramoops"; + reg = <0x0 0x110000 0x0 0xf0000>; + record-size = <0x20000>; + console-size = <0x80000>; + ftrace-size = <0x00000>; + pmsg-size = <0x50000>; + }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-edp-x0.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-edp-x0.dtsi index 440d5866e4f4..9f8768cec79e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-edp-x0.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-edp-x0.dtsi @@ -647,7 +647,7 @@ touch_gpio: touch-gpio { rockchip,pins = <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>, - <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtsi index b68b407e0147..ea8cab776e77 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtsi @@ -613,7 +613,7 @@ touch_gpio: touch-gpio { rockchip,pins = <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>, - <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi index 9c870a80d8db..7c5bc3ea7e05 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi @@ -51,6 +51,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm3 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x.dtsi index b7839d4960a6..2396a91d06a1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x.dtsi @@ -115,6 +115,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm11 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; hall_sensor: hall-mh248 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb2-lp5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb2-lp5.dtsi index fd97039080b7..263bdfe3bd70 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb2-lp5.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb2-lp5.dtsi @@ -890,7 +890,7 @@ touch_gpio: touch-gpio { rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>, - <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb3-lp4x.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb3-lp4x.dtsi index ea951d375e11..cfdbcae8cbe8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb3-lp4x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb3-lp4x.dtsi @@ -34,6 +34,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm7 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; vcc3v3_lcd_n: vcc3v3-lcd0-n { @@ -243,7 +251,7 @@ touch_gpio: touch-gpio { rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>, - <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi index a79a6220fe87..d61d365c80dc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi @@ -88,6 +88,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm11 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; vbus5v0_typec: vbus5v0-typec { @@ -678,7 +686,7 @@ touch_gpio: touch-gpio { rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>, - <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb8-lp4x.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb8-lp4x.dtsi index c2cd7f4b7c64..a9e68fe49ee8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb8-lp4x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb8-lp4x.dtsi @@ -88,6 +88,14 @@ compatible = "pwm-fan"; #cooling-cells = <2>; pwms = <&pwm11 0 50000 0>; + cooling-levels = <0 50 100 150 200 255>; + rockchip,temp-trips = < + 50000 1 + 55000 2 + 60000 3 + 65000 4 + 70000 5 + >; }; panel-edp { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi index 3673af66be55..0aceee389623 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi @@ -2527,97 +2527,97 @@ spi0m0_pins: spi0m0-pins { rockchip,pins = /* spi0_clk_m0 */ - <0 RK_PC6 8 &pcfg_pull_up_drv_level_1>, + <0 RK_PC6 8 &pcfg_pull_up_drv_level_6>, /* spi0_miso_m0 */ - <0 RK_PC7 8 &pcfg_pull_up_drv_level_1>, + <0 RK_PC7 8 &pcfg_pull_up_drv_level_6>, /* spi0_mosi_m0 */ - <0 RK_PC0 8 &pcfg_pull_up_drv_level_1>; + <0 RK_PC0 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m0_cs0: spi0m0-cs0 { rockchip,pins = /* spi0_cs0_m0 */ - <0 RK_PD1 8 &pcfg_pull_up_drv_level_1>; + <0 RK_PD1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m0_cs1: spi0m0-cs1 { rockchip,pins = /* spi0_cs1_m0 */ - <0 RK_PB7 8 &pcfg_pull_up_drv_level_1>; + <0 RK_PB7 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m1_pins: spi0m1-pins { rockchip,pins = /* spi0_clk_m1 */ - <4 RK_PA2 8 &pcfg_pull_up_drv_level_1>, + <4 RK_PA2 8 &pcfg_pull_up_drv_level_6>, /* spi0_miso_m1 */ - <4 RK_PA0 8 &pcfg_pull_up_drv_level_1>, + <4 RK_PA0 8 &pcfg_pull_up_drv_level_6>, /* spi0_mosi_m1 */ - <4 RK_PA1 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PA1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m1_cs0: spi0m1-cs0 { rockchip,pins = /* spi0_cs0_m1 */ - <4 RK_PB2 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PB2 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m1_cs1: spi0m1-cs1 { rockchip,pins = /* spi0_cs1_m1 */ - <4 RK_PB1 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PB1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m2_pins: spi0m2-pins { rockchip,pins = /* spi0_clk_m2 */ - <1 RK_PB3 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PB3 8 &pcfg_pull_up_drv_level_6>, /* spi0_miso_m2 */ - <1 RK_PB1 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PB1 8 &pcfg_pull_up_drv_level_6>, /* spi0_mosi_m2 */ - <1 RK_PB2 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PB2 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m2_cs0: spi0m2-cs0 { rockchip,pins = /* spi0_cs0_m2 */ - <1 RK_PB4 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PB4 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m2_cs1: spi0m2-cs1 { rockchip,pins = /* spi0_cs1_m2 */ - <1 RK_PB5 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PB5 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m3_pins: spi0m3-pins { rockchip,pins = /* spi0_clk_m3 */ - <3 RK_PD3 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PD3 8 &pcfg_pull_up_drv_level_6>, /* spi0_miso_m3 */ - <3 RK_PD1 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PD1 8 &pcfg_pull_up_drv_level_6>, /* spi0_mosi_m3 */ - <3 RK_PD2 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PD2 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m3_cs0: spi0m3-cs0 { rockchip,pins = /* spi0_cs0_m3 */ - <3 RK_PD4 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PD4 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi0m3_cs1: spi0m3-cs1 { rockchip,pins = /* spi0_cs1_m3 */ - <3 RK_PD5 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PD5 8 &pcfg_pull_up_drv_level_6>; }; }; @@ -2626,50 +2626,50 @@ spi1m1_pins: spi1m1-pins { rockchip,pins = /* spi1_clk_m1 */ - <3 RK_PC1 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PC1 8 &pcfg_pull_up_drv_level_6>, /* spi1_miso_m1 */ - <3 RK_PC0 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PC0 8 &pcfg_pull_up_drv_level_6>, /* spi1_mosi_m1 */ - <3 RK_PB7 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PB7 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi1m1_cs0: spi1m1-cs0 { rockchip,pins = /* spi1_cs0_m1 */ - <3 RK_PC2 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PC2 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi1m1_cs1: spi1m1-cs1 { rockchip,pins = /* spi1_cs1_m1 */ - <3 RK_PC3 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PC3 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi1m2_pins: spi1m2-pins { rockchip,pins = /* spi1_clk_m2 */ - <1 RK_PD2 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PD2 8 &pcfg_pull_up_drv_level_6>, /* spi1_miso_m2 */ - <1 RK_PD0 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PD0 8 &pcfg_pull_up_drv_level_6>, /* spi1_mosi_m2 */ - <1 RK_PD1 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PD1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi1m2_cs0: spi1m2-cs0 { rockchip,pins = /* spi1_cs0_m2 */ - <1 RK_PD3 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PD3 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi1m2_cs1: spi1m2-cs1 { rockchip,pins = /* spi1_cs1_m2 */ - <1 RK_PD5 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PD5 8 &pcfg_pull_up_drv_level_6>; }; }; @@ -2678,50 +2678,50 @@ spi2m0_pins: spi2m0-pins { rockchip,pins = /* spi2_clk_m0 */ - <1 RK_PA6 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PA6 8 &pcfg_pull_up_drv_level_6>, /* spi2_miso_m0 */ - <1 RK_PA4 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PA4 8 &pcfg_pull_up_drv_level_6>, /* spi2_mosi_m0 */ - <1 RK_PA5 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PA5 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi2m0_cs0: spi2m0-cs0 { rockchip,pins = /* spi2_cs0_m0 */ - <1 RK_PA7 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PA7 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi2m0_cs1: spi2m0-cs1 { rockchip,pins = /* spi2_cs1_m0 */ - <1 RK_PB0 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PB0 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi2m1_pins: spi2m1-pins { rockchip,pins = /* spi2_clk_m1 */ - <4 RK_PA6 8 &pcfg_pull_up_drv_level_1>, + <4 RK_PA6 8 &pcfg_pull_up_drv_level_6>, /* spi2_miso_m1 */ - <4 RK_PA4 8 &pcfg_pull_up_drv_level_1>, + <4 RK_PA4 8 &pcfg_pull_up_drv_level_6>, /* spi2_mosi_m1 */ - <4 RK_PA5 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PA5 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi2m1_cs0: spi2m1-cs0 { rockchip,pins = /* spi2_cs0_m1 */ - <4 RK_PA7 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PA7 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi2m1_cs1: spi2m1-cs1 { rockchip,pins = /* spi2_cs1_m1 */ - <4 RK_PB0 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PB0 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ @@ -2755,75 +2755,75 @@ spi3m1_pins: spi3m1-pins { rockchip,pins = /* spi3_clk_m1 */ - <4 RK_PB7 8 &pcfg_pull_up_drv_level_1>, + <4 RK_PB7 8 &pcfg_pull_up_drv_level_6>, /* spi3_miso_m1 */ - <4 RK_PB5 8 &pcfg_pull_up_drv_level_1>, + <4 RK_PB5 8 &pcfg_pull_up_drv_level_6>, /* spi3_mosi_m1 */ - <4 RK_PB6 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PB6 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m1_cs0: spi3m1-cs0 { rockchip,pins = /* spi3_cs0_m1 */ - <4 RK_PC0 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PC0 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m1_cs1: spi3m1-cs1 { rockchip,pins = /* spi3_cs1_m1 */ - <4 RK_PC1 8 &pcfg_pull_up_drv_level_1>; + <4 RK_PC1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m2_pins: spi3m2-pins { rockchip,pins = /* spi3_clk_m2 */ - <0 RK_PD3 8 &pcfg_pull_up_drv_level_1>, + <0 RK_PD3 8 &pcfg_pull_up_drv_level_6>, /* spi3_miso_m2 */ - <0 RK_PD0 8 &pcfg_pull_up_drv_level_1>, + <0 RK_PD0 8 &pcfg_pull_up_drv_level_6>, /* spi3_mosi_m2 */ - <0 RK_PD2 8 &pcfg_pull_up_drv_level_1>; + <0 RK_PD2 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m2_cs0: spi3m2-cs0 { rockchip,pins = /* spi3_cs0_m2 */ - <0 RK_PD4 8 &pcfg_pull_up_drv_level_1>; + <0 RK_PD4 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m2_cs1: spi3m2-cs1 { rockchip,pins = /* spi3_cs1_m2 */ - <0 RK_PD5 8 &pcfg_pull_up_drv_level_1>; + <0 RK_PD5 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m3_pins: spi3m3-pins { rockchip,pins = /* spi3_clk_m3 */ - <3 RK_PD0 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PD0 8 &pcfg_pull_up_drv_level_6>, /* spi3_miso_m3 */ - <3 RK_PC6 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PC6 8 &pcfg_pull_up_drv_level_6>, /* spi3_mosi_m3 */ - <3 RK_PC7 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PC7 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m3_cs0: spi3m3-cs0 { rockchip,pins = /* spi3_cs0_m3 */ - <3 RK_PC4 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PC4 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi3m3_cs1: spi3m3-cs1 { rockchip,pins = /* spi3_cs1_m3 */ - <3 RK_PC5 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PC5 8 &pcfg_pull_up_drv_level_6>; }; }; @@ -2832,68 +2832,68 @@ spi4m0_pins: spi4m0-pins { rockchip,pins = /* spi4_clk_m0 */ - <1 RK_PC2 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PC2 8 &pcfg_pull_up_drv_level_6>, /* spi4_miso_m0 */ - <1 RK_PC0 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PC0 8 &pcfg_pull_up_drv_level_6>, /* spi4_mosi_m0 */ - <1 RK_PC1 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PC1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi4m0_cs0: spi4m0-cs0 { rockchip,pins = /* spi4_cs0_m0 */ - <1 RK_PC3 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PC3 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi4m0_cs1: spi4m0-cs1 { rockchip,pins = /* spi4_cs1_m0 */ - <1 RK_PC4 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PC4 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi4m1_pins: spi4m1-pins { rockchip,pins = /* spi4_clk_m1 */ - <3 RK_PA2 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PA2 8 &pcfg_pull_up_drv_level_6>, /* spi4_miso_m1 */ - <3 RK_PA0 8 &pcfg_pull_up_drv_level_1>, + <3 RK_PA0 8 &pcfg_pull_up_drv_level_6>, /* spi4_mosi_m1 */ - <3 RK_PA1 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PA1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi4m1_cs0: spi4m1-cs0 { rockchip,pins = /* spi4_cs0_m1 */ - <3 RK_PA3 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PA3 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi4m1_cs1: spi4m1-cs1 { rockchip,pins = /* spi4_cs1_m1 */ - <3 RK_PA4 8 &pcfg_pull_up_drv_level_1>; + <3 RK_PA4 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi4m2_pins: spi4m2-pins { rockchip,pins = /* spi4_clk_m2 */ - <1 RK_PA2 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PA2 8 &pcfg_pull_up_drv_level_6>, /* spi4_miso_m2 */ - <1 RK_PA0 8 &pcfg_pull_up_drv_level_1>, + <1 RK_PA0 8 &pcfg_pull_up_drv_level_6>, /* spi4_mosi_m2 */ - <1 RK_PA1 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PA1 8 &pcfg_pull_up_drv_level_6>; }; /omit-if-no-ref/ spi4m2_cs0: spi4m2-cs0 { rockchip,pins = /* spi4_cs0_m2 */ - <1 RK_PA3 8 &pcfg_pull_up_drv_level_1>; + <1 RK_PA3 8 &pcfg_pull_up_drv_level_6>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi index ceae180041eb..4357661eac4c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi @@ -1457,7 +1457,7 @@ touch_gpio: touch-gpio { rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>, - <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi index 59fad2df04b2..21c5e721d4cc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi @@ -920,7 +920,7 @@ touch_gpio: touch-gpio { rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>, - <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index b9853fdf3677..83915e50054c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -1909,11 +1909,12 @@ }; usb_host0_ehci: usb@fc800000 { - compatible = "generic-ehci"; + compatible = "rockchip,rk3588-ehci", "generic-ehci"; reg = <0x0 0xfc800000 0x0 0x40000>; interrupts = ; clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST_ARB0>, <&u2phy2>; clock-names = "usbhost", "arbiter", "utmi"; + companion = <&usb_host0_ohci>; phys = <&u2phy2_host>; phy-names = "usb2-phy"; power-domains = <&power RK3588_PD_USB>; @@ -1933,11 +1934,12 @@ }; usb_host1_ehci: usb@fc880000 { - compatible = "generic-ehci"; + compatible = "rockchip,rk3588-ehci", "generic-ehci"; reg = <0x0 0xfc880000 0x0 0x40000>; interrupts = ; clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST_ARB1>, <&u2phy3>; clock-names = "usbhost", "arbiter", "utmi"; + companion = <&usb_host1_ohci>; phys = <&u2phy3_host>; phy-names = "usb2-phy"; power-domains = <&power RK3588_PD_USB>; diff --git a/arch/arm64/configs/px30_linux_defconfig b/arch/arm64/configs/px30_linux_defconfig index 518854521dc1..ab7b88f44532 100644 --- a/arch/arm64/configs/px30_linux_defconfig +++ b/arch/arm64/configs/px30_linux_defconfig @@ -38,6 +38,7 @@ CONFIG_PREEMPT_VOLUNTARY=y CONFIG_HZ_1000=y # CONFIG_COMPACTION is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y CONFIG_ARMV8_DEPRECATED=y @@ -279,7 +280,6 @@ CONFIG_USB_VIDEO_CLASS=y # CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV is not set # CONFIG_USB_GSPCA is not set CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_VIDEO_ROCKCHIP_CIF=y CONFIG_VIDEO_ROCKCHIP_RKISP1=y CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set @@ -326,6 +326,8 @@ CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_SND_SOC_ROCKCHIP=y +CONFIG_SND_SOC_ROCKCHIP_MULTICODECS=y +CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS=y CONFIG_SND_SOC_ROCKCHIP_I2S=y CONFIG_SND_SOC_RK817=y CONFIG_SND_SIMPLE_CARD=y @@ -456,6 +458,7 @@ CONFIG_NLS_CODEPAGE_936=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y +CONFIG_DMA_CMA=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y diff --git a/arch/arm64/configs/rk3326_linux.config b/arch/arm64/configs/rk3326_linux.config new file mode 100644 index 000000000000..3d913bcc63c7 --- /dev/null +++ b/arch/arm64/configs/rk3326_linux.config @@ -0,0 +1,8 @@ +# CONFIG_ETHERNET is not set +CONFIG_MD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_SND_SOC_ROCKCHIP_PDM=y +CONFIG_VIDEO_ROCKCHIP_CIF=y +CONFIG_VIDEO_GC2155=y diff --git a/arch/arm64/configs/rk3326_linux_defconfig b/arch/arm64/configs/rk3326_linux_defconfig deleted file mode 100644 index 3b5854cc9d15..000000000000 --- a/arch/arm64/configs/rk3326_linux_defconfig +++ /dev/null @@ -1,480 +0,0 @@ -CONFIG_DEFAULT_HOSTNAME="localhost" -CONFIG_SYSVIPC=y -CONFIG_FHANDLE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_CGROUPS=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CGROUP_DEVICE=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_NAMESPACES=y -CONFIG_USER_NS=y -CONFIG_DEFAULT_USE_ENERGY_AWARE=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_EMBEDDED=y -# CONFIG_COMPAT_BRK is not set -CONFIG_PROFILING=y -CONFIG_MODULES=y -CONFIG_MODULE_FORCE_LOAD=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_ARCH_ROCKCHIP=y -CONFIG_PCI=y -CONFIG_PCI_MSI=y -CONFIG_PCIEPORTBUS=y -CONFIG_PCIEASPM_POWERSAVE=y -# CONFIG_ARM64_ERRATUM_826319 is not set -# CONFIG_ARM64_ERRATUM_827319 is not set -# CONFIG_ARM64_ERRATUM_824069 is not set -# CONFIG_ARM64_ERRATUM_819472 is not set -# CONFIG_ARM64_ERRATUM_832075 is not set -# CONFIG_CAVIUM_ERRATUM_22375 is not set -# CONFIG_CAVIUM_ERRATUM_23154 is not set -CONFIG_SCHED_MC=y -CONFIG_NR_CPUS=8 -CONFIG_PREEMPT_VOLUNTARY=y -CONFIG_HZ_1000=y -# CONFIG_COMPACTION is not set -CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 -CONFIG_ZSMALLOC=y -CONFIG_SECCOMP=y -CONFIG_ARMV8_DEPRECATED=y -CONFIG_SWP_EMULATION=y -CONFIG_CP15_BARRIER_EMULATION=y -CONFIG_SETEND_EMULATION=y -# CONFIG_EFI is not set -CONFIG_COMPAT=y -CONFIG_PM_DEBUG=y -CONFIG_PM_ADVANCED_DEBUG=y -CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y -CONFIG_CPU_IDLE=y -CONFIG_ARM_CPUIDLE=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y -CONFIG_CPUFREQ_DT=y -CONFIG_ARM_ROCKCHIP_CPUFREQ=y -CONFIG_ARM_SCMI_PROTOCOL=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_NET_KEY=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MROUTE=y -CONFIG_SYN_COOKIES=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set -# CONFIG_IPV6_SIT is not set -# CONFIG_ANDROID_PARANOID_NETWORK is not set -CONFIG_BT=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_HIDP=y -CONFIG_BT_HCIBTUSB=y -CONFIG_BT_HCIUART=y -CONFIG_BT_HCIUART_ATH3K=y -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIBFUSB=y -CONFIG_BT_HCIVHCI=y -CONFIG_BT_MRVL=y -CONFIG_BT_MRVL_SDIO=y -CONFIG_NL80211_TESTMODE=y -CONFIG_CFG80211_DEBUGFS=y -CONFIG_CFG80211_WEXT=y -CONFIG_MAC80211_LEDS=y -CONFIG_MAC80211_DEBUGFS=y -CONFIG_MAC80211_DEBUG_MENU=y -CONFIG_MAC80211_VERBOSE_DEBUG=y -CONFIG_RFKILL=y -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_DTC_SYMBOLS=y -CONFIG_DEBUG_DEVRES=y -CONFIG_CONNECTOR=y -CONFIG_ZRAM=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=1 -CONFIG_BLK_DEV_NVME=y -CONFIG_ROCKCHIP_SCR=y -CONFIG_SRAM=y -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_BLK_DEV_SR=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_SPI_ATTRS=y -CONFIG_MD=y -CONFIG_NETDEVICES=y -# CONFIG_ETHERNET is not set -CONFIG_ROCKCHIP_PHY=y -CONFIG_USB_RTL8150=y -CONFIG_USB_RTL8152=y -CONFIG_USB_NET_CDC_MBIM=y -# CONFIG_USB_NET_NET1080 is not set -# CONFIG_USB_NET_CDC_SUBSET is not set -# CONFIG_USB_NET_ZAURUS is not set -CONFIG_LIBERTAS_THINFIRM=y -CONFIG_USB_NET_RNDIS_WLAN=y -CONFIG_WL_ROCKCHIP=y -CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP=y -CONFIG_AP6XXX=y -CONFIG_RTL8188EU=y -CONFIG_MWIFIEX=y -CONFIG_MWIFIEX_SDIO=y -CONFIG_INPUT_FF_MEMLESS=y -# CONFIG_INPUT_MOUSEDEV is not set -CONFIG_INPUT_EVDEV=y -CONFIG_KEYBOARD_ADC=y -# CONFIG_KEYBOARD_ATKBD is not set -CONFIG_KEYBOARD_GPIO=y -CONFIG_KEYBOARD_GPIO_POLLED=y -CONFIG_KEYBOARD_ROCKCHIP=y -CONFIG_KEYBOARD_CROS_EC=y -# CONFIG_MOUSE_PS2 is not set -CONFIG_MOUSE_CYAPA=y -CONFIG_MOUSE_ELAN_I2C=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_ATMEL_MXT=y -CONFIG_TOUCHSCREEN_GSLX680_VR=y -CONFIG_TOUCHSCREEN_GSL3673=y -CONFIG_TOUCHSCREEN_GT9XX=y -CONFIG_TOUCHSCREEN_ELAN=y -CONFIG_TOUCHSCREEN_USB_COMPOSITE=y -CONFIG_TOUCHSCREEN_GT1X=y -CONFIG_ROCKCHIP_REMOTECTL=y -CONFIG_ROCKCHIP_REMOTECTL_PWM=y -CONFIG_INPUT_MISC=y -CONFIG_INPUT_RK8XX_PWRKEY=y -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_GPIO=y -# CONFIG_SERIO is not set -CONFIG_DEVPTS_MULTIPLE_INSTANCES=y -# CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVKMEM is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_SERIAL_8250_PCI is not set -CONFIG_SERIAL_8250_NR_UARTS=5 -CONFIG_SERIAL_8250_RUNTIME_UARTS=5 -CONFIG_SERIAL_8250_DW=y -CONFIG_SERIAL_OF_PLATFORM=y -CONFIG_HW_RANDOM=y -CONFIG_TCG_TPM=y -CONFIG_TCG_TIS_I2C_INFINEON=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MUX=y -CONFIG_I2C_RK3X=y -CONFIG_I2C_CROS_EC_TUNNEL=y -CONFIG_SPI=y -CONFIG_SPI_BITBANG=y -CONFIG_SPI_ROCKCHIP=y -CONFIG_SPI_SPIDEV=y -CONFIG_PTP_1588_CLOCK=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_GENERIC_PLATFORM=y -CONFIG_GPIO_RK8XX=y -CONFIG_BATTERY_SBS=y -CONFIG_CHARGER_GPIO=y -CONFIG_CHARGER_BQ24735=y -CONFIG_BATTERY_RK817=y -CONFIG_CHARGER_RK817=y -CONFIG_POWER_RESET_GPIO=y -CONFIG_POWER_RESET_GPIO_RESTART=y -CONFIG_SYSCON_REBOOT_MODE=y -CONFIG_POWER_AVS=y -CONFIG_ROCKCHIP_IODOMAIN=y -CONFIG_THERMAL=y -CONFIG_THERMAL_WRITABLE_TRIPS=y -CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y -CONFIG_THERMAL_GOV_FAIR_SHARE=y -CONFIG_THERMAL_GOV_STEP_WISE=y -CONFIG_CPU_THERMAL=y -CONFIG_DEVFREQ_THERMAL=y -CONFIG_ROCKCHIP_THERMAL=y -CONFIG_WATCHDOG=y -CONFIG_DW_WATCHDOG=y -CONFIG_MFD_CROS_EC=y -CONFIG_MFD_CROS_EC_SPI=y -CONFIG_MFD_RK808=y -CONFIG_MFD_TPS6586X=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_DEBUG=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_ACT8865=y -CONFIG_REGULATOR_FAN53555=y -CONFIG_REGULATOR_GPIO=y -CONFIG_REGULATOR_LP8752=y -CONFIG_REGULATOR_MP8865=y -CONFIG_REGULATOR_PWM=y -CONFIG_REGULATOR_RK808=y -CONFIG_REGULATOR_RK818=y -CONFIG_REGULATOR_TPS6586X=y -CONFIG_REGULATOR_XZ3216=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_RC_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -# CONFIG_IR_RC5_DECODER is not set -# CONFIG_IR_RC6_DECODER is not set -# CONFIG_IR_JVC_DECODER is not set -# CONFIG_IR_SONY_DECODER is not set -# CONFIG_IR_SANYO_DECODER is not set -# CONFIG_IR_SHARP_DECODER is not set -# CONFIG_IR_MCE_KBD_DECODER is not set -# CONFIG_IR_XMP_DECODER is not set -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_USB_VIDEO_CLASS=y -# CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV is not set -# CONFIG_USB_GSPCA is not set -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_SOC_CAMERA=y -CONFIG_VIDEO_ROCKCHIP_CIF=y -CONFIG_VIDEO_ROCKCHIP_ISP1=y -CONFIG_V4L_MEM2MEM_DRIVERS=y -CONFIG_VIDEO_ROCKCHIP_RGA=y -# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -# CONFIG_VIDEO_IR_I2C is not set -CONFIG_VIDEO_OV5695=y -CONFIG_VIDEO_GC2155=y -# CONFIG_DVB_AU8522_V4L is not set -# CONFIG_DVB_TUNER_DIB0070 is not set -# CONFIG_DVB_TUNER_DIB0090 is not set -# CONFIG_VGA_ARB is not set -CONFIG_DRM=y -CONFIG_DRM_LOAD_EDID_FIRMWARE=y -CONFIG_DRM_DMA_SYNC=y -CONFIG_DRM_ROCKCHIP=y -CONFIG_ROCKCHIP_DW_MIPI_DSI=y -CONFIG_ROCKCHIP_ANALOGIX_DP=y -CONFIG_ROCKCHIP_LVDS=y -CONFIG_ROCKCHIP_DRM_TVE=y -CONFIG_DRM_PANEL_SIMPLE=y -CONFIG_MALI_PWRSOFT_765=y -CONFIG_MALI_BIFROST=y -CONFIG_MALI_BIFROST_DEVFREQ=y -CONFIG_MALI_PLATFORM_NAME="rk" -CONFIG_MALI_BIFROST_EXPERT=y -CONFIG_MALI_BIFROST_DEBUG=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -# CONFIG_LCD_CLASS_DEVICE is not set -CONFIG_BACKLIGHT_CLASS_DEVICE=y -CONFIG_BACKLIGHT_PWM=y -CONFIG_RK_VCODEC=y -CONFIG_ROCKCHIP_MPP_SERVICE=y -CONFIG_ROCKCHIP_MPP_DEVICE=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_SEQUENCER=y -CONFIG_SND_SEQ_DUMMY=y -CONFIG_SND_HRTIMER=y -CONFIG_SND_DYNAMIC_MINORS=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_PROC_FS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=y -CONFIG_SND_SOC=y -CONFIG_SND_SOC_ROCKCHIP=y -CONFIG_SND_SOC_ROCKCHIP_SPDIF=y -CONFIG_SND_SOC_ROCKCHIP_MAX98090=y -CONFIG_SND_SOC_ROCKCHIP_RT5645=y -CONFIG_SND_SOC_ES8316=y -CONFIG_SND_SOC_RK817=y -CONFIG_SND_SOC_RT5616=y -CONFIG_SND_SOC_RT5640=y -CONFIG_SND_SOC_RT5651=y -CONFIG_SND_SOC_SPDIF=y -CONFIG_SND_SIMPLE_CARD=y -CONFIG_HID_BATTERY_STRENGTH=y -CONFIG_HIDRAW=y -CONFIG_UHID=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_MULTITOUCH=y -CONFIG_USB_HIDDEV=y -CONFIG_I2C_HID=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -# CONFIG_USB_DEFAULT_PERSIST is not set -CONFIG_USB_OTG=y -CONFIG_USB_MON=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_OHCI_HCD_PCI is not set -CONFIG_USB_OHCI_HCD_PLATFORM=y -CONFIG_USB_ACM=y -CONFIG_USB_STORAGE=y -CONFIG_USB_UAS=y -CONFIG_USB_DWC2=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_CP210X=y -CONFIG_USB_SERIAL_FTDI_SIO=y -CONFIG_USB_SERIAL_KEYSPAN=y -CONFIG_USB_SERIAL_PL2303=y -CONFIG_USB_SERIAL_OTI6858=y -CONFIG_USB_SERIAL_QUALCOMM=y -CONFIG_USB_SERIAL_SIERRAWIRELESS=y -CONFIG_USB_SERIAL_OPTION=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_GADGET_VBUS_DRAW=500 -CONFIG_USB_CONFIGFS=y -CONFIG_USB_CONFIGFS_ACM=y -CONFIG_USB_CONFIGFS_MASS_STORAGE=y -CONFIG_USB_CONFIGFS_F_FS=y -CONFIG_USB_CONFIGFS_UEVENT=y -CONFIG_MMC=y -CONFIG_MMC_BLOCK_MINORS=32 -CONFIG_MMC_TEST=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_OF_ARASAN=y -CONFIG_MMC_DW=y -CONFIG_MMC_DW_ROCKCHIP=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_IS31FL32XX=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_HYM8563=y -CONFIG_RTC_DRV_RK808=y -CONFIG_DMADEVICES=y -CONFIG_PL330_DMA=y -CONFIG_STAGING=y -CONFIG_SENSORS_ISL29018=y -CONFIG_TSL2583=y -# CONFIG_ANDROID_TIMED_OUTPUT is not set -CONFIG_FIQ_DEBUGGER=y -CONFIG_FIQ_DEBUGGER_NO_SLEEP=y -CONFIG_FIQ_DEBUGGER_CONSOLE=y -CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y -CONFIG_COMMON_CLK_RK808=y -CONFIG_COMMON_CLK_SCMI=y -CONFIG_MAILBOX=y -CONFIG_ROCKCHIP_IOMMU=y -CONFIG_CPU_PX30=y -CONFIG_ROCKCHIP_CPUINFO=y -CONFIG_ROCKCHIP_GRF=y -CONFIG_ROCKCHIP_IPA=y -CONFIG_ROCKCHIP_OPP=y -CONFIG_ROCKCHIP_PM_DOMAINS=y -CONFIG_ROCKCHIP_PVTM=y -CONFIG_ROCKCHIP_SUSPEND_MODE=y -CONFIG_ROCKCHIP_SYSTEM_MONITOR=y -CONFIG_PM_DEVFREQ=y -CONFIG_DEVFREQ_GOV_PERFORMANCE=y -CONFIG_DEVFREQ_GOV_POWERSAVE=y -CONFIG_DEVFREQ_GOV_USERSPACE=y -CONFIG_ARM_ROCKCHIP_BUS_DEVFREQ=y -CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ=y -CONFIG_PM_DEVFREQ_EVENT=y -CONFIG_MEMORY=y -CONFIG_IIO=y -CONFIG_IIO_BUFFER=y -CONFIG_IIO_KFIFO_BUF=y -CONFIG_IIO_TRIGGER=y -CONFIG_ROCKCHIP_SARADC=y -CONFIG_SENSORS_TSL2563=y -CONFIG_IIO_SYSFS_TRIGGER=y -CONFIG_PWM=y -CONFIG_PWM_ROCKCHIP=y -CONFIG_PHY_ROCKCHIP_USB=y -CONFIG_PHY_ROCKCHIP_INNO_USB2=y -CONFIG_PHY_ROCKCHIP_EMMC=y -CONFIG_PHY_ROCKCHIP_DP=y -CONFIG_PHY_ROCKCHIP_INNO_VIDEO_COMBO_PHY=y -CONFIG_ANDROID=y -CONFIG_NVMEM=y -CONFIG_ROCKCHIP_OTP=y -CONFIG_ROCKCHIP_SIP=y -# CONFIG_ACPI is not set -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_XFS_FS=y -# CONFIG_DNOTIFY is not set -CONFIG_FUSE_FS=y -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_VFAT_FS=y -CONFIG_FAT_DEFAULT_CODEPAGE=936 -CONFIG_FAT_DEFAULT_IOCHARSET="utf8" -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_SQUASHFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_NFS_SWAP=y -CONFIG_NLS_DEFAULT="utf8" -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_936=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_PRINTK_TIME=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_INFO=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0 -CONFIG_LOCKUP_DETECTOR=y -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y -CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y -CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_CREDENTIALS=y -CONFIG_RCU_CPU_STALL_TIMEOUT=60 -CONFIG_FUNCTION_TRACER=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_LKDTM=y -CONFIG_STRICT_DEVMEM=y -CONFIG_DEBUG_SET_MODULE_RONX=y -# CONFIG_CRYPTO_ECHAINIV is not set -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_TWOFISH=y -CONFIG_CRYPTO_ANSI_CPRNG=y -CONFIG_CRYPTO_USER_API_HASH=y -CONFIG_CRYPTO_USER_API_SKCIPHER=y -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_PKCS7_MESSAGE_PARSER=y -CONFIG_SYSTEM_TRUSTED_KEYRING=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRC_CCITT=y -CONFIG_CRC_T10DIF=y -CONFIG_CRC7=y -# CONFIG_XZ_DEC_X86 is not set -# CONFIG_XZ_DEC_POWERPC is not set -# CONFIG_XZ_DEC_IA64 is not set -# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/arm64/configs/rk3358_linux.config b/arch/arm64/configs/rk3358_linux.config new file mode 100644 index 000000000000..4be7a7cfe0ac --- /dev/null +++ b/arch/arm64/configs/rk3358_linux.config @@ -0,0 +1,2 @@ +CONFIG_LTE=y +CONFIG_LTE_RM310=y diff --git a/arch/arm64/configs/rk3588_edge.config b/arch/arm64/configs/rk3588_edge.config index 1ccc4a1778d9..8b07747a6020 100644 --- a/arch/arm64/configs/rk3588_edge.config +++ b/arch/arm64/configs/rk3588_edge.config @@ -3,6 +3,9 @@ CONFIG_R8169=y CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP=y CONFIG_AP6XXX=y # CONFIG_WIFI_BUILD_MODULE is not set +# CONFIG_BCMDHD_SDIO is not set +CONFIG_BCMDHD_PCIE=y +CONFIG_MALI_CSF_SUPPORT=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_F_UAC1=y diff --git a/arch/arm64/configs/rk3588_linux.config b/arch/arm64/configs/rk3588_linux.config new file mode 100644 index 000000000000..e2d30904b5f6 --- /dev/null +++ b/arch/arm64/configs/rk3588_linux.config @@ -0,0 +1,3 @@ +# CONFIG_BCMDHD_SDIO=y is not set +CONFIG_BCMDHD_PCIE=y +CONFIG_MALI_CSF_SUPPORT=y diff --git a/arch/arm64/configs/rk3588_nvr.config b/arch/arm64/configs/rk3588_nvr.config index 38b868946aee..e8356d628475 100644 --- a/arch/arm64/configs/rk3588_nvr.config +++ b/arch/arm64/configs/rk3588_nvr.config @@ -11,6 +11,7 @@ CONFIG_DRM_ITE_IT6161=y CONFIG_INPUT_MOUSEDEV=y # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_MALI400 is not set +CONFIG_MALI_CSF_SUPPORT=y # CONFIG_MALI_MIDGARD is not set # CONFIG_MEDIA_CEC_SUPPORT is not set # CONFIG_MEDIA_USB_SUPPORT is not set diff --git a/arch/arm64/configs/rockchip_defconfig b/arch/arm64/configs/rockchip_defconfig index 4b27d47ec634..c266bef5c434 100644 --- a/arch/arm64/configs/rockchip_defconfig +++ b/arch/arm64/configs/rockchip_defconfig @@ -960,6 +960,7 @@ CONFIG_PSTORE=y CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_PMSG=y CONFIG_PSTORE_RAM=y +CONFIG_PSTORE_BOOT_LOG=y CONFIG_CIFS=y CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index b8b04e7792d4..3783dc7717b5 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -183,7 +183,6 @@ CONFIG_USB_RTL8152=y CONFIG_WL_ROCKCHIP=y CONFIG_WIFI_BUILD_MODULE=y CONFIG_AP6XXX=m -CONFIG_BCMDHD_PCIE=y CONFIG_INPUT_FF_MEMLESS=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_ADC=y @@ -309,6 +308,7 @@ CONFIG_ROCKCHIP_DW_DP=y CONFIG_ROCKCHIP_INNO_HDMI=y CONFIG_ROCKCHIP_LVDS=y CONFIG_ROCKCHIP_RGB=y +CONFIG_ROCKCHIP_DW_HDCP2=y CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_DISPLAY_CONNECTOR=y CONFIG_DRM_SII902X=y @@ -328,7 +328,6 @@ CONFIG_MALI_DEBUG=y CONFIG_MALI_PWRSOFT_765=y CONFIG_MALI_BIFROST=y CONFIG_MALI_PLATFORM_NAME="rk" -CONFIG_MALI_CSF_SUPPORT=y CONFIG_MALI_BIFROST_EXPERT=y CONFIG_MALI_BIFROST_DEBUG=y CONFIG_BACKLIGHT_CLASS_DEVICE=y diff --git a/drivers/base/arm/dma_buf_lock/src/dma_buf_lock.c b/drivers/base/arm/dma_buf_lock/src/dma_buf_lock.c index 04ec2d296c79..43333ca8e5e2 100644 --- a/drivers/base/arm/dma_buf_lock/src/dma_buf_lock.c +++ b/drivers/base/arm/dma_buf_lock/src/dma_buf_lock.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2012-2014, 2017-2018, 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2012-2014, 2017-2018, 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -99,9 +100,6 @@ static const struct file_operations dma_buf_lock_fops = { #if defined(HAVE_COMPAT_IOCTL) || ((KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE)) .compat_ioctl = dma_buf_lock_ioctl, #endif -#if !defined(HAVE_UNLOCKED_IOCTL) && !defined(HAVE_COMPAT_IOCTL) && ((KERNEL_VERSION(2, 6, 36) > LINUX_VERSION_CODE)) - .ioctl = dma_buf_lock_ioctl, -#endif }; struct dma_buf_lock_resource { @@ -480,15 +478,18 @@ static int dma_buf_lock_handle_release(struct inode *inode, struct file *file) return 0; } -static unsigned int dma_buf_lock_handle_poll( - struct file *file, - struct poll_table_struct *wait) +static __poll_t dma_buf_lock_handle_poll(struct file *file, poll_table *wait) { struct dma_buf_lock_resource *resource; unsigned int ret = 0; - if (!is_dma_buf_lock_file(file)) + if (!is_dma_buf_lock_file(file)) { +#if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE) return POLLERR; +#else + return EPOLLERR; +#endif + } resource = file->private_data; #if DMA_BUF_LOCK_DEBUG @@ -496,9 +497,15 @@ static unsigned int dma_buf_lock_handle_poll( #endif if (atomic_read(&resource->locked) == 1) { /* Resources have been locked */ +#if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE) ret = POLLIN | POLLRDNORM; if (resource->exclusive) - ret |= POLLOUT | POLLWRNORM; + ret |= POLLOUT | POLLWRNORM; +#else + ret = EPOLLIN | EPOLLRDNORM; + if (resource->exclusive) + ret |= EPOLLOUT | EPOLLWRNORM; +#endif } else { if (!poll_does_not_wait(wait)) poll_wait(file, &resource->wait, wait); @@ -533,10 +540,12 @@ static int dma_buf_lock_dolock(struct dma_buf_lock_k_request *request) { struct dma_buf_lock_resource *resource; struct ww_acquire_ctx ww_ctx; + struct file *file; int size; int fd; int i; int ret; + int error; if (request->list_of_dma_buf_fds == NULL) return -EINVAL; @@ -634,15 +643,21 @@ static int dma_buf_lock_dolock(struct dma_buf_lock_k_request *request) kref_get(&resource->refcount); - /* Create file descriptor associated with lock request */ - fd = anon_inode_getfd("dma_buf_lock", &dma_buf_lock_handle_fops, - (void *)resource, 0); - if (fd < 0) { + error = get_unused_fd_flags(0); + if (error < 0) + return error; + + fd = error; + + file = anon_inode_getfile("dma_buf_lock", &dma_buf_lock_handle_fops, (void *)resource, 0); + + if (IS_ERR(file)) { + put_unused_fd(fd); mutex_lock(&dma_buf_lock_mutex); kref_put(&resource->refcount, dma_buf_lock_dounlock); kref_put(&resource->refcount, dma_buf_lock_dounlock); mutex_unlock(&dma_buf_lock_mutex); - return fd; + return PTR_ERR(file); } resource->exclusive = request->exclusive; @@ -711,9 +726,7 @@ static int dma_buf_lock_dolock(struct dma_buf_lock_k_request *request) dma_resv_add_shared_fence(resv, &resource->fence); #endif } else { - ret = dma_buf_lock_add_fence_reservation_callback(resource, - resv, - true); + ret = dma_buf_lock_add_fence_reservation_callback(resource, resv, true); if (ret) { #if DMA_BUF_LOCK_DEBUG pr_debug("%s : Error %d adding reservation to callback.\n", __func__, ret); @@ -758,6 +771,10 @@ static int dma_buf_lock_dolock(struct dma_buf_lock_k_request *request) kref_put(&resource->refcount, dma_buf_lock_dounlock); mutex_unlock(&dma_buf_lock_mutex); + /* Installing the fd is deferred to the very last operation before return + * to avoid allowing userspace to close it during the setup. + */ + fd_install(fd, file); return fd; } diff --git a/drivers/base/arm/dma_buf_test_exporter/dma-buf-test-exporter.c b/drivers/base/arm/dma_buf_test_exporter/dma-buf-test-exporter.c index 22664c5690c0..6b9a4d70483a 100644 --- a/drivers/base/arm/dma_buf_test_exporter/dma-buf-test-exporter.c +++ b/drivers/base/arm/dma_buf_test_exporter/dma-buf-test-exporter.c @@ -30,9 +30,6 @@ #include #include #include -#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE) -#include -#endif #include /* Maximum size allowed in a single DMA_BUF_TE_ALLOC call */ @@ -211,20 +208,11 @@ static void dma_buf_te_release(struct dma_buf *buf) /* no need for locking */ if (alloc->contiguous) { -#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE) dma_free_attrs(te_device.this_device, alloc->nr_pages * PAGE_SIZE, alloc->contig_cpu_addr, alloc->contig_dma_addr, DMA_ATTR_WRITE_COMBINE); -#else - DEFINE_DMA_ATTRS(attrs); - - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - dma_free_attrs(te_device.this_device, - alloc->nr_pages * PAGE_SIZE, - alloc->contig_cpu_addr, alloc->contig_dma_addr, &attrs); -#endif } else { for (i = 0; i < alloc->nr_pages; i++) __free_page(alloc->pages[i]); @@ -269,32 +257,17 @@ static int dma_buf_te_sync(struct dma_buf *dmabuf, return 0; } -#if (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) static int dma_buf_te_begin_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction direction) -#else -static int dma_buf_te_begin_cpu_access(struct dma_buf *dmabuf, size_t start, - size_t len, - enum dma_data_direction direction) -#endif { return dma_buf_te_sync(dmabuf, direction, true); } -#if (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) static int dma_buf_te_end_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction direction) { return dma_buf_te_sync(dmabuf, direction, false); } -#else -static void dma_buf_te_end_cpu_access(struct dma_buf *dmabuf, size_t start, - size_t len, - enum dma_data_direction direction) -{ - dma_buf_te_sync(dmabuf, direction, false); -} -#endif static void dma_buf_te_mmap_open(struct vm_area_struct *vma) { @@ -521,21 +494,11 @@ static int do_dma_buf_te_ioctl_alloc(struct dma_buf_te_ioctl_alloc __user *buf, if (contiguous) { dma_addr_t dma_aux; -#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE) alloc->contig_cpu_addr = dma_alloc_attrs(te_device.this_device, alloc->nr_pages * PAGE_SIZE, &alloc->contig_dma_addr, GFP_KERNEL | __GFP_ZERO, DMA_ATTR_WRITE_COMBINE); -#else - DEFINE_DMA_ATTRS(attrs); - - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - alloc->contig_cpu_addr = dma_alloc_attrs(te_device.this_device, - alloc->nr_pages * PAGE_SIZE, - &alloc->contig_dma_addr, - GFP_KERNEL | __GFP_ZERO, &attrs); -#endif if (!alloc->contig_cpu_addr) { dev_err(te_device.this_device, "%s: couldn't alloc contiguous buffer %zu pages", __func__, alloc->nr_pages); @@ -591,20 +554,11 @@ no_export: /* i still valid */ no_page: if (contiguous) { -#if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE) dma_free_attrs(te_device.this_device, alloc->nr_pages * PAGE_SIZE, alloc->contig_cpu_addr, alloc->contig_dma_addr, DMA_ATTR_WRITE_COMBINE); -#else - DEFINE_DMA_ATTRS(attrs); - - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - dma_free_attrs(te_device.this_device, - alloc->nr_pages * PAGE_SIZE, - alloc->contig_cpu_addr, alloc->contig_dma_addr, &attrs); -#endif } else { while (i-- > 0) __free_page(alloc->pages[i]); @@ -703,7 +657,6 @@ static u32 dma_te_buf_fill(struct dma_buf *dma_buf, unsigned int value) struct sg_table *sgt; struct scatterlist *sg; unsigned int count; - unsigned int offset = 0; int ret = 0; size_t i; @@ -717,11 +670,7 @@ static u32 dma_te_buf_fill(struct dma_buf *dma_buf, unsigned int value) goto no_import; } - ret = dma_buf_begin_cpu_access(dma_buf, -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE - 0, dma_buf->size, -#endif - DMA_BIDIRECTIONAL); + ret = dma_buf_begin_cpu_access(dma_buf, DMA_BIDIRECTIONAL); if (ret) goto no_cpu_access; @@ -744,15 +693,10 @@ static u32 dma_te_buf_fill(struct dma_buf *dma_buf, unsigned int value) dma_buf_kunmap(dma_buf, i >> PAGE_SHIFT, addr); #endif } - offset += sg_dma_len(sg); } no_kmap: - dma_buf_end_cpu_access(dma_buf, -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE - 0, dma_buf->size, -#endif - DMA_BIDIRECTIONAL); + dma_buf_end_cpu_access(dma_buf, DMA_BIDIRECTIONAL); no_cpu_access: dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL); no_import: diff --git a/drivers/base/arm/memory_group_manager/memory_group_manager.c b/drivers/base/arm/memory_group_manager/memory_group_manager.c index b2bdc36f4a2d..7729492e0c80 100644 --- a/drivers/base/arm/memory_group_manager/memory_group_manager.c +++ b/drivers/base/arm/memory_group_manager/memory_group_manager.c @@ -42,18 +42,7 @@ static inline vm_fault_t vmf_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, pgprot_t pgprot) { - int err; - -#if ((KERNEL_VERSION(4, 4, 147) >= LINUX_VERSION_CODE) || \ - ((KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) && \ - (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE))) - if (pgprot_val(pgprot) != pgprot_val(vma->vm_page_prot)) - return VM_FAULT_SIGBUS; - - err = vm_insert_pfn(vma, addr, pfn); -#else - err = vm_insert_pfn_prot(vma, addr, pfn, pgprot); -#endif + int err = vm_insert_pfn_prot(vma, addr, pfn, pgprot); if (unlikely(err == -ENOMEM)) return VM_FAULT_OOM; @@ -64,6 +53,10 @@ static inline vm_fault_t vmf_insert_pfn_prot(struct vm_area_struct *vma, } #endif +#define PTE_PBHA_SHIFT (59) +#define PTE_PBHA_MASK ((uint64_t)0xf << PTE_PBHA_SHIFT) +#define PTE_RES_BIT_MULTI_AS_SHIFT (63) + #define IMPORTED_MEMORY_ID (MEMORY_GROUP_MANAGER_NR_GROUPS - 1) /** @@ -335,8 +328,6 @@ static u64 example_mgm_update_gpu_pte( int const mmu_level, u64 pte) { struct mgm_groups *const data = mgm_dev->data; - const u32 pbha_bit_pos = 59; /* bits 62:59 */ - const u32 pbha_bit_mask = 0xf; /* 4-bit */ dev_dbg(data->dev, "%s(mgm_dev=%p, group_id=%d, mmu_level=%d, pte=0x%llx)\n", @@ -346,13 +337,27 @@ static u64 example_mgm_update_gpu_pte( WARN_ON(group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS)) return pte; - pte |= ((u64)group_id & pbha_bit_mask) << pbha_bit_pos; + pte |= ((u64)group_id << PTE_PBHA_SHIFT) & PTE_PBHA_MASK; + + /* Address could be translated into a different bus address here */ + pte |= ((u64)1 << PTE_RES_BIT_MULTI_AS_SHIFT); data->groups[group_id].update_gpu_pte++; return pte; } +static u64 example_mgm_pte_to_original_pte(struct memory_group_manager_device *const mgm_dev, + int const group_id, int const mmu_level, u64 pte) +{ + /* Undo the group ID modification */ + pte &= ~PTE_PBHA_MASK; + /* Undo the bit set */ + pte &= ~((u64)1 << PTE_RES_BIT_MULTI_AS_SHIFT); + + return pte; +} + static vm_fault_t example_mgm_vmf_insert_pfn_prot( struct memory_group_manager_device *const mgm_dev, int const group_id, struct vm_area_struct *const vma, unsigned long const addr, @@ -428,6 +433,7 @@ static int memory_group_manager_probe(struct platform_device *pdev) example_mgm_get_import_memory_id; mgm_dev->ops.mgm_vmf_insert_pfn_prot = example_mgm_vmf_insert_pfn_prot; mgm_dev->ops.mgm_update_gpu_pte = example_mgm_update_gpu_pte; + mgm_dev->ops.mgm_pte_to_original_pte = example_mgm_pte_to_original_pte; mgm_data = kzalloc(sizeof(*mgm_data), GFP_KERNEL); if (!mgm_data) { diff --git a/drivers/char/hw_random/rockchip-rng.c b/drivers/char/hw_random/rockchip-rng.c index 08ad08148d25..13503c54fe62 100644 --- a/drivers/char/hw_random/rockchip-rng.c +++ b/drivers/char/hw_random/rockchip-rng.c @@ -192,10 +192,12 @@ static int rk_crypto_v1_read(struct hwrng *rng, void *buf, size_t max, bool wait rk_rng_writel(rk_rng, reg_ctrl, CRYPTO_V1_CTRL); - ret = readl_poll_timeout(rk_rng->mem + CRYPTO_V1_CTRL, reg_ctrl, - !(reg_ctrl & CRYPTO_V1_RNG_START), - ROCKCHIP_POLL_PERIOD_US, - ROCKCHIP_POLL_TIMEOUT_US); + ret = read_poll_timeout(rk_rng_readl, reg_ctrl, + !(reg_ctrl & CRYPTO_V1_RNG_START), + ROCKCHIP_POLL_PERIOD_US, + ROCKCHIP_POLL_TIMEOUT_US, false, + rk_rng, CRYPTO_V1_CTRL); + if (ret < 0) goto out; @@ -228,10 +230,11 @@ static int rk_crypto_v2_read(struct hwrng *rng, void *buf, size_t max, bool wait rk_rng_writel(rk_rng, HIWORD_UPDATE(reg_ctrl, 0xffff, 0), CRYPTO_V2_RNG_CTL); - ret = readl_poll_timeout(rk_rng->mem + CRYPTO_V2_RNG_CTL, reg_ctrl, - !(reg_ctrl & CRYPTO_V2_RNG_START), - ROCKCHIP_POLL_PERIOD_US, - ROCKCHIP_POLL_TIMEOUT_US); + ret = read_poll_timeout(rk_rng_readl, reg_ctrl, + !(reg_ctrl & CRYPTO_V2_RNG_START), + ROCKCHIP_POLL_PERIOD_US, + ROCKCHIP_POLL_TIMEOUT_US, false, + rk_rng, CRYPTO_V2_RNG_CTL); if (ret < 0) goto out; @@ -281,10 +284,11 @@ static int rk_trng_v1_init(struct hwrng *rng) udelay(10); /* wait for GENERATING and RESEEDING flag to clear */ - readl_poll_timeout(rk_rng->mem + TRNG_V1_STAT, reg_ctrl, - (reg_ctrl & mask) == TRNG_V1_STAT_SEEDED, - ROCKCHIP_POLL_PERIOD_US, - ROCKCHIP_POLL_TIMEOUT_US); + read_poll_timeout(rk_rng_readl, reg_ctrl, + (reg_ctrl & mask) == TRNG_V1_STAT_SEEDED, + ROCKCHIP_POLL_PERIOD_US, + ROCKCHIP_POLL_TIMEOUT_US, false, + rk_rng, TRNG_V1_STAT); } /* clear ISTAT flag because trng may auto reseeding when power on */ @@ -324,10 +328,11 @@ static int rk_trng_v1_read(struct hwrng *rng, void *buf, size_t max, bool wait) reg_ctrl = rk_rng_readl(rk_rng, TRNG_V1_ISTAT); if (!(reg_ctrl & TRNG_V1_ISTAT_RAND_RDY)) { /* wait RAND_RDY triggered */ - ret = readl_poll_timeout(rk_rng->mem + TRNG_V1_ISTAT, reg_ctrl, - (reg_ctrl & TRNG_V1_ISTAT_RAND_RDY), - ROCKCHIP_POLL_PERIOD_US, - ROCKCHIP_POLL_TIMEOUT_US); + ret = read_poll_timeout(rk_rng_readl, reg_ctrl, + (reg_ctrl & TRNG_V1_ISTAT_RAND_RDY), + ROCKCHIP_POLL_PERIOD_US, + ROCKCHIP_POLL_TIMEOUT_US, false, + rk_rng, TRNG_V1_ISTAT); if (ret < 0) goto out; } diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c index 99bb5111d695..ee2826a70742 100644 --- a/drivers/clk/rockchip/clk-rk3588.c +++ b/drivers/clk/rockchip/clk-rk3588.c @@ -1890,6 +1890,7 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { COMPOSITE(ACLK_VOP_ROOT, "aclk_vop_root", gpll_cpll_dmyaupll_npll_spll_p, 0, RK3588_CLKSEL_CON(110), 5, 3, MFLAGS, 0, 5, DFLAGS, RK3588_CLKGATE_CON(52), 0, GFLAGS), + FACTOR(0, "aclk_vop_div2_src", "aclk_vop_root", 0, 1, 2), COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, 0, RK3588_CLKSEL_CON(110), 8, 2, MFLAGS, RK3588_CLKGATE_CON(52), 1, GFLAGS), @@ -1905,7 +1906,7 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { COMPOSITE_NODIV(HCLK_VO1USB_TOP_ROOT, "hclk_vo1usb_top_root", mux_200m_100m_50m_24m_p, CLK_IS_CRITICAL, RK3588_CLKSEL_CON(170), 6, 2, MFLAGS, RK3588_CLKGATE_CON(74), 2, GFLAGS), - MUX(ACLK_VOP_SUB_SRC, "aclk_vop_sub_src", aclk_vop_sub_src_p, CLK_SET_RATE_PARENT, + MUX(ACLK_VOP_SUB_SRC, "aclk_vop_sub_src", aclk_vop_sub_src_p, 0, RK3588_CLKSEL_CON(115), 9, 1, MFLAGS), GATE(PCLK_EDP0, "pclk_edp0", "pclk_vo1_root", 0, RK3588_CLKGATE_CON(62), 0, GFLAGS), diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c index 0067a0cfd708..699f53e15ece 100644 --- a/drivers/cpufreq/rockchip-cpufreq.c +++ b/drivers/cpufreq/rockchip-cpufreq.c @@ -899,6 +899,22 @@ static struct notifier_block rockchip_cpufreq_transition_notifier_block = { .notifier_call = rockchip_cpufreq_transition_notifier, }; +static int rockchip_cpufreq_panic_notifier(struct notifier_block *nb, + unsigned long v, void *p) +{ + struct cluster_info *ci; + + list_for_each_entry(ci, &cluster_info_list, list_head) { + rockchip_opp_dump_cur_state(ci->opp_info.dev); + } + + return 0; +} + +static struct notifier_block rockchip_cpufreq_panic_notifier_block = { + .notifier_call = rockchip_cpufreq_panic_notifier, +}; + static int __init rockchip_cpufreq_driver_init(void) { struct cluster_info *cluster, *pos; @@ -948,6 +964,11 @@ static int __init rockchip_cpufreq_driver_init(void) #endif } + ret = atomic_notifier_chain_register(&panic_notifier_list, + &rockchip_cpufreq_panic_notifier_block); + if (ret) + pr_err("failed to register cpufreq panic notifier\n"); + return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt", -1, (void *)&pdata, sizeof(struct cpufreq_dt_platform_data))); diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile index 96f800fc4775..53e34aa47bc1 100644 --- a/drivers/crypto/rockchip/Makefile +++ b/drivers/crypto/rockchip/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o rk_crypto-objs := rk_crypto_core.o \ rk_crypto_utils.o \ rk_crypto_ahash_utils.o \ - rk_crypto_skcipher_utils.o + rk_crypto_skcipher_utils.o \ + procfs.o rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V1) += \ rk_crypto_v1.o \ diff --git a/drivers/crypto/rockchip/procfs.c b/drivers/crypto/rockchip/procfs.c new file mode 100644 index 000000000000..e1f08fd5d968 --- /dev/null +++ b/drivers/crypto/rockchip/procfs.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Rockchip Electronics Co., Ltd. */ +#include +#include +#include +#include + +#include "procfs.h" + +#ifdef CONFIG_PROC_FS + +static const char *alg_type2name[ALG_TYPE_MAX] = { + [ALG_TYPE_HASH] = "HASH", + [ALG_TYPE_HMAC] = "HMAC", + [ALG_TYPE_CIPHER] = "CIPHER", + [ALG_TYPE_ASYM] = "ASYM", + [ALG_TYPE_AEAD] = "AEAD", +}; + +static void crypto_show_clock(struct seq_file *p, struct clk_bulk_data *clk_bulks, int clks_num) +{ + int i; + + seq_puts(p, "clock info:\n"); + + for (i = 0; i < clks_num; i++) + seq_printf(p, "\t%-10s %ld\n", clk_bulks[i].id, clk_get_rate(clk_bulks[i].clk)); + + seq_puts(p, "\n"); +} + +static void crypto_show_stat(struct seq_file *p, struct rk_crypto_stat *stat) +{ + /* show statistic info */ + seq_puts(p, "Statistic info:\n"); + seq_printf(p, "\tbusy_cnt : %llu\n", stat->busy_cnt); + seq_printf(p, "\tequeue_cnt : %llu\n", stat->equeue_cnt); + seq_printf(p, "\tdequeue_cnt : %llu\n", stat->dequeue_cnt); + seq_printf(p, "\tdone_cnt : %llu\n", stat->done_cnt); + seq_printf(p, "\tcomplete_cnt : %llu\n", stat->complete_cnt); + seq_printf(p, "\tfake_cnt : %llu\n", stat->fake_cnt); + seq_printf(p, "\tirq_cnt : %llu\n", stat->irq_cnt); + seq_printf(p, "\ttimeout_cnt : %llu\n", stat->timeout_cnt); + seq_printf(p, "\terror_cnt : %llu\n", stat->error_cnt); + seq_printf(p, "\tlast_error : %d\n", stat->last_error); + seq_puts(p, "\n"); +} + +static void crypto_show_queue_info(struct seq_file *p, struct rk_crypto_dev *rk_dev) +{ + bool busy; + unsigned long flags; + u32 qlen, max_qlen; + + spin_lock_irqsave(&rk_dev->lock, flags); + + qlen = rk_dev->queue.qlen; + max_qlen = rk_dev->queue.max_qlen; + busy = rk_dev->busy; + + spin_unlock_irqrestore(&rk_dev->lock, flags); + + seq_printf(p, "Crypto queue usage [%u/%u], ever_max = %llu, status: %s\n", + qlen, max_qlen, rk_dev->stat.ever_queue_max, busy ? "busy" : "idle"); + + seq_puts(p, "\n"); +} + +static void crypto_show_valid_algo_single(struct seq_file *p, enum alg_type type, + struct rk_crypto_algt **algs, u32 algs_num) +{ + u32 i; + struct rk_crypto_algt *tmp_algs; + + seq_printf(p, "\t%s:\n", alg_type2name[type]); + + for (i = 0; i < algs_num; i++, algs++) { + tmp_algs = *algs; + + if (!(tmp_algs->valid_flag) || tmp_algs->type != type) + continue; + + seq_printf(p, "\t\t%s\n", tmp_algs->name); + } + + seq_puts(p, "\n"); +} + +static void crypto_show_valid_algos(struct seq_file *p, struct rk_crypto_soc_data *soc_data) +{ + u32 algs_num = 0; + struct rk_crypto_algt **algs; + + seq_puts(p, "Valid algorithms:\n"); + + algs = soc_data->hw_get_algts(&algs_num); + if (!algs || algs_num == 0) + return; + + crypto_show_valid_algo_single(p, ALG_TYPE_CIPHER, algs, algs_num); + crypto_show_valid_algo_single(p, ALG_TYPE_AEAD, algs, algs_num); + crypto_show_valid_algo_single(p, ALG_TYPE_HASH, algs, algs_num); + crypto_show_valid_algo_single(p, ALG_TYPE_HMAC, algs, algs_num); + crypto_show_valid_algo_single(p, ALG_TYPE_ASYM, algs, algs_num); +} + +static int crypto_show_all(struct seq_file *p, void *v) +{ + struct rk_crypto_dev *rk_dev = p->private; + struct rk_crypto_soc_data *soc_data = rk_dev->soc_data; + struct rk_crypto_stat *stat = &rk_dev->stat; + + seq_printf(p, "Rockchip Crypto Version: %s\n\n", + soc_data->crypto_ver); + + seq_printf(p, "use_soft_aes192 : %s\n\n", soc_data->use_soft_aes192 ? "true" : "false"); + + crypto_show_clock(p, rk_dev->clk_bulks, rk_dev->clks_num); + + crypto_show_valid_algos(p, soc_data); + + crypto_show_stat(p, stat); + + crypto_show_queue_info(p, rk_dev); + + return 0; +} + +static int crypto_open(struct inode *inode, struct file *file) +{ + struct rk_crypto_dev *data = PDE_DATA(inode); + + return single_open(file, crypto_show_all, data); +} + +static const struct proc_ops ops = { + .proc_open = crypto_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +int rkcrypto_proc_init(struct rk_crypto_dev *rk_dev) +{ + rk_dev->procfs = proc_create_data(rk_dev->name, 0, NULL, &ops, rk_dev); + if (!rk_dev->procfs) + return -EINVAL; + + return 0; +} + +void rkcrypto_proc_cleanup(struct rk_crypto_dev *rk_dev) +{ + if (rk_dev->procfs) + remove_proc_entry(rk_dev->name, NULL); + + rk_dev->procfs = NULL; +} + +#endif /* CONFIG_PROC_FS */ diff --git a/drivers/crypto/rockchip/procfs.h b/drivers/crypto/rockchip/procfs.h new file mode 100644 index 000000000000..e491c53b4e04 --- /dev/null +++ b/drivers/crypto/rockchip/procfs.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2022 Rockchip Electronics Co., Ltd. */ + +#ifndef _RKCRYPTO_PROCFS_H +#define _RKCRYPTO_PROCFS_H + +#include "rk_crypto_core.h" + +#ifdef CONFIG_PROC_FS +int rkcrypto_proc_init(struct rk_crypto_dev *dev); +void rkcrypto_proc_cleanup(struct rk_crypto_dev *dev); +#else +static inline int rkcrypto_proc_init(struct rk_crypto_dev *dev) +{ + return 0; +} +static inline void rkcrypto_proc_cleanup(struct rk_crypto_dev *dev) +{ + +} +#endif + +#endif diff --git a/drivers/crypto/rockchip/rk_crypto_core.c b/drivers/crypto/rockchip/rk_crypto_core.c index 4a89ccafa28c..f25d722ea776 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.c +++ b/drivers/crypto/rockchip/rk_crypto_core.c @@ -26,6 +26,9 @@ #include "rk_crypto_v2.h" #include "rk_crypto_v3.h" #include "cryptodev_linux/rk_cryptodev.h" +#include "procfs.h" + +#define CRYPTO_NAME "rkcrypto" static struct rk_alg_ctx *rk_alg_ctx_cast(struct crypto_async_request *async_req) { @@ -271,6 +274,7 @@ static void rk_crypto_irq_timer_handle(struct timer_list *t) struct rk_crypto_dev *rk_dev = from_timer(rk_dev, t, timer); rk_dev->err = -ETIMEDOUT; + rk_dev->stat.timeout_cnt++; tasklet_schedule(&rk_dev->done_task); } @@ -281,6 +285,8 @@ static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) spin_lock(&rk_dev->lock); + rk_dev->stat.irq_cnt++; + if (alg_ctx->ops.irq_handle) alg_ctx->ops.irq_handle(irq, dev_id); @@ -310,6 +316,7 @@ static int rk_start_op(struct rk_crypto_dev *rk_dev) /* fake calculations are used to trigger the Done Task */ if (alg_ctx->total == 0) { CRYPTO_TRACE("fake done_task"); + rk_dev->stat.fake_cnt++; tasklet_schedule(&rk_dev->done_task); } @@ -333,13 +340,20 @@ static void rk_complete_op(struct rk_crypto_dev *rk_dev, int err) disable_irq(rk_dev->irq); del_timer(&rk_dev->timer); + rk_dev->stat.complete_cnt++; + + if (err) { + rk_dev->stat.error_cnt++; + rk_dev->stat.last_error = err; + dev_err(rk_dev->dev, "complete_op err = %d\n", err); + } + if (!alg_ctx || !alg_ctx->ops.complete) return; alg_ctx->ops.complete(rk_dev->async_req, err); - if (err) - dev_err(rk_dev->dev, "complete_op err = %d\n", err); + rk_dev->async_req = NULL; tasklet_schedule(&rk_dev->queue_task); } @@ -352,10 +366,17 @@ static int rk_crypto_enqueue(struct rk_crypto_dev *rk_dev, spin_lock_irqsave(&rk_dev->lock, flags); ret = crypto_enqueue_request(&rk_dev->queue, async_req); + + if (rk_dev->queue.qlen > rk_dev->stat.ever_queue_max) + rk_dev->stat.ever_queue_max = rk_dev->queue.qlen; + if (rk_dev->busy) { + rk_dev->stat.busy_cnt++; spin_unlock_irqrestore(&rk_dev->lock, flags); return ret; } + + rk_dev->stat.equeue_cnt++; rk_dev->busy = true; spin_unlock_irqrestore(&rk_dev->lock, flags); tasklet_schedule(&rk_dev->queue_task); @@ -369,6 +390,11 @@ static void rk_crypto_queue_task_cb(unsigned long data) struct crypto_async_request *async_req, *backlog; unsigned long flags; + if (rk_dev->async_req) { + dev_err(rk_dev->dev, "%s: Unexpected crypto paths.\n", __func__); + return; + } + rk_dev->err = 0; spin_lock_irqsave(&rk_dev->lock, flags); backlog = crypto_get_backlog(&rk_dev->queue); @@ -379,6 +405,7 @@ static void rk_crypto_queue_task_cb(unsigned long data) spin_unlock_irqrestore(&rk_dev->lock, flags); return; } + rk_dev->stat.dequeue_cnt++; spin_unlock_irqrestore(&rk_dev->lock, flags); if (backlog) { @@ -397,6 +424,8 @@ static void rk_crypto_done_task_cb(unsigned long data) struct rk_crypto_dev *rk_dev = (struct rk_crypto_dev *)data; struct rk_alg_ctx *alg_ctx = rk_alg_ctx_cast(rk_dev->async_req); + rk_dev->stat.done_cnt++; + if (rk_dev->err) goto exit; @@ -500,6 +529,8 @@ static int rk_crypto_register(struct rk_crypto_dev *rk_dev) if (err) goto err_cipher_algs; + tmp_algs->valid_flag = true; + CRYPTO_TRACE("%s register OK!!!\n", *algs_name); } @@ -579,7 +610,7 @@ static void rk_crypto_action(void *data) } static char *crypto_no_sm_algs_name[] = { - "ecb(aes)", "cbc(aes)", "cfb(aes)", "ofb(aes)", "ctr(aes)", + "ecb(aes)", "cbc(aes)", "cfb(aes)", "ofb(aes)", "ctr(aes)", "gcm(aes)", "ecb(des)", "cbc(des)", "cfb(des)", "ofb(des)", "ecb(des3_ede)", "cbc(des3_ede)", "cfb(des3_ede)", "ofb(des3_ede)", "sha1", "sha224", "sha256", "sha384", "sha512", "md5", @@ -691,6 +722,8 @@ static int rk_crypto_probe(struct platform_device *pdev) goto err_crypto; } + rk_dev->name = CRYPTO_NAME; + match = of_match_node(crypto_of_id_table, np); soc_data = (struct rk_crypto_soc_data *)match->data; rk_dev->soc_data = soc_data; @@ -818,6 +851,8 @@ static int rk_crypto_probe(struct platform_device *pdev) rk_cryptodev_register_dev(rk_dev->dev, soc_data->crypto_ver); + rkcrypto_proc_init(rk_dev); + dev_info(dev, "%s Accelerator successfully registered\n", soc_data->crypto_ver); return 0; @@ -832,6 +867,8 @@ static int rk_crypto_remove(struct platform_device *pdev) { struct rk_crypto_dev *rk_dev = platform_get_drvdata(pdev); + rkcrypto_proc_cleanup(rk_dev); + rk_cryptodev_unregister_dev(rk_dev->dev); del_timer_sync(&rk_dev->timer); diff --git a/drivers/crypto/rockchip/rk_crypto_core.h b/drivers/crypto/rockchip/rk_crypto_core.h index 3914601caf9b..4efebaa4541a 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.h +++ b/drivers/crypto/rockchip/rk_crypto_core.h @@ -48,6 +48,20 @@ #define RK_FLAG_FINAL BIT(0) #define RK_FLAG_UPDATE BIT(1) +struct rk_crypto_stat { + unsigned long long busy_cnt; + unsigned long long equeue_cnt; + unsigned long long dequeue_cnt; + unsigned long long complete_cnt; + unsigned long long done_cnt; + unsigned long long fake_cnt; + unsigned long long irq_cnt; + unsigned long long timeout_cnt; + unsigned long long error_cnt; + unsigned long long ever_queue_max; + int last_error; +}; + struct rk_crypto_dev { struct device *dev; struct reset_control *rst; @@ -62,6 +76,9 @@ struct rk_crypto_dev { struct rk_crypto_soc_data *soc_data; int clks_num; struct clk_bulk_data *clk_bulks; + const char *name; + struct proc_dir_entry *procfs; + struct rk_crypto_stat stat; /* device lock */ spinlock_t lock; @@ -208,6 +225,7 @@ enum alg_type { ALG_TYPE_CIPHER, ALG_TYPE_ASYM, ALG_TYPE_AEAD, + ALG_TYPE_MAX, }; struct rk_crypto_algt { @@ -223,6 +241,7 @@ struct rk_crypto_algt { u32 mode; char *name; bool use_soft_aes192; + bool valid_flag; }; enum rk_hash_algo { diff --git a/drivers/crypto/rockchip/rk_crypto_v2_ahash.c b/drivers/crypto/rockchip/rk_crypto_v2_ahash.c index 16e7cbdb29db..dd9ea240bac0 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_ahash.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_ahash.c @@ -51,8 +51,8 @@ static void rk_hash_reset(struct rk_crypto_dev *rk_dev) CRYPTO_WRITE(rk_dev, CRYPTO_RST_CTL, tmp | tmp_mask); /* This is usually done in 20 clock cycles */ - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_RST_CTL, - tmp, !tmp, 0, pool_timeout_us); + ret = read_poll_timeout_atomic(CRYPTO_READ, tmp, !tmp, 0, pool_timeout_us, + false, rk_dev, CRYPTO_RST_CTL); if (ret) dev_err(rk_dev->dev, "cipher reset pool timeout %ums.", pool_timeout_us); @@ -285,11 +285,11 @@ static int rk_ahash_get_result(struct rk_crypto_dev *rk_dev, int ret = 0; u32 reg_ctrl = 0; - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_HASH_VALID, - reg_ctrl, - reg_ctrl & CRYPTO_HASH_IS_VALID, - RK_POLL_PERIOD_US, - RK_POLL_TIMEOUT_US); + ret = read_poll_timeout_atomic(CRYPTO_READ, reg_ctrl, + reg_ctrl & CRYPTO_HASH_IS_VALID, + RK_POLL_PERIOD_US, + RK_POLL_TIMEOUT_US, false, + rk_dev, CRYPTO_HASH_VALID); if (ret) goto exit; diff --git a/drivers/crypto/rockchip/rk_crypto_v2_pka.c b/drivers/crypto/rockchip/rk_crypto_v2_pka.c index c2883626be04..d2c0a265b3ad 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_pka.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_pka.c @@ -175,7 +175,7 @@ static int pka_wait_pipe_rdy(void) { u32 reg_val = 0; - return readl_poll_timeout(pka_base + CRYPTO_PKA_PIPE_RDY, reg_val, + return readx_poll_timeout(PKA_READ, CRYPTO_PKA_PIPE_RDY, reg_val, reg_val, PKA_POLL_PERIOD_US, PKA_POLL_TIMEOUT_US); } @@ -183,7 +183,7 @@ static int pka_wait_done(void) { u32 reg_val = 0; - return readl_poll_timeout(pka_base + CRYPTO_PKA_DONE, reg_val, + return readx_poll_timeout(PKA_READ, CRYPTO_PKA_DONE, reg_val, reg_val, PKA_POLL_PERIOD_US, PKA_POLL_TIMEOUT_US); } @@ -191,7 +191,7 @@ static int pka_max_wait_done(void) { u32 reg_val = 0; - return readl_poll_timeout(pka_base + CRYPTO_PKA_DONE, reg_val, + return readx_poll_timeout(PKA_READ, CRYPTO_PKA_DONE, reg_val, reg_val, PKA_MAX_POLL_PERIOD_US, PKA_MAX_POLL_TIMEOUT_US); } diff --git a/drivers/crypto/rockchip/rk_crypto_v2_skcipher.c b/drivers/crypto/rockchip/rk_crypto_v2_skcipher.c index cce8e86228bc..5edef31da8f6 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_skcipher.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_skcipher.c @@ -136,11 +136,13 @@ static int get_tag_reg(struct rk_crypto_dev *rk_dev, u8 *tag, u32 tag_len) if (tag_len > RK_MAX_TAG_SIZE) return -EINVAL; - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_TAG_VALID, + ret = read_poll_timeout_atomic(CRYPTO_READ, reg_ctrl, reg_ctrl & CRYPTO_CH0_TAG_VALID, - RK_POLL_PERIOD_US, - RK_POLL_TIMEOUT_US); + 0, + RK_POLL_TIMEOUT_US, + false, + rk_dev, CRYPTO_TAG_VALID); if (ret) goto exit; @@ -188,8 +190,8 @@ static void rk_cipher_reset(struct rk_crypto_dev *rk_dev) CRYPTO_WRITE(rk_dev, CRYPTO_RST_CTL, tmp | tmp_mask); /* This is usually done in 20 clock cycles */ - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_RST_CTL, - tmp, !tmp, 0, pool_timeout_us); + ret = read_poll_timeout_atomic(CRYPTO_READ, tmp, !tmp, 0, + pool_timeout_us, false, rk_dev, CRYPTO_RST_CTL); if (ret) dev_err(rk_dev->dev, "cipher reset pool timeout %ums.", pool_timeout_us); diff --git a/drivers/crypto/rockchip/rk_crypto_v3_ahash.c b/drivers/crypto/rockchip/rk_crypto_v3_ahash.c index 213aaf1d084d..f39026dbc314 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3_ahash.c +++ b/drivers/crypto/rockchip/rk_crypto_v3_ahash.c @@ -56,8 +56,8 @@ static void rk_hash_reset(struct rk_crypto_dev *rk_dev) CRYPTO_WRITE(rk_dev, CRYPTO_RST_CTL, tmp | tmp_mask); /* This is usually done in 20 clock cycles */ - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_RST_CTL, - tmp, !tmp, 0, pool_timeout_us); + ret = read_poll_timeout_atomic(CRYPTO_READ, tmp, !tmp, 0, pool_timeout_us, + false, rk_dev, CRYPTO_RST_CTL); if (ret) dev_err(rk_dev->dev, "cipher reset pool timeout %ums.", pool_timeout_us); @@ -72,11 +72,13 @@ static int rk_hash_mid_data_store(struct rk_crypto_dev *rk_dev, struct rk_hash_m CRYPTO_TRACE(); - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_MID_VALID, + ret = read_poll_timeout_atomic(CRYPTO_READ, reg_ctrl, reg_ctrl & CRYPTO_HASH_MID_IS_VALID, - RK_POLL_PERIOD_US, - RK_POLL_TIMEOUT_US); + 0, + RK_POLL_TIMEOUT_US, + false, rk_dev, CRYPTO_MID_VALID); + CRYPTO_WRITE(rk_dev, CRYPTO_MID_VALID_SWITCH, CRYPTO_MID_VALID_ENABLE << CRYPTO_WRITE_MASK_SHIFT); if (ret) { @@ -362,11 +364,11 @@ static int rk_ahash_get_result(struct rk_crypto_dev *rk_dev, memset(ctx->priv, 0x00, sizeof(struct rk_hash_mid_data)); - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_HASH_VALID, - reg_ctrl, - reg_ctrl & CRYPTO_HASH_IS_VALID, - RK_POLL_PERIOD_US, - RK_POLL_TIMEOUT_US); + ret = read_poll_timeout_atomic(CRYPTO_READ, reg_ctrl, + reg_ctrl & CRYPTO_HASH_IS_VALID, + RK_POLL_PERIOD_US, + RK_POLL_TIMEOUT_US, false, + rk_dev, CRYPTO_HASH_VALID); if (ret) goto exit; diff --git a/drivers/crypto/rockchip/rk_crypto_v3_skcipher.c b/drivers/crypto/rockchip/rk_crypto_v3_skcipher.c index 06f7f74a8694..9eab01274fc8 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3_skcipher.c +++ b/drivers/crypto/rockchip/rk_crypto_v3_skcipher.c @@ -135,11 +135,13 @@ static int get_tag_reg(struct rk_crypto_dev *rk_dev, u8 *tag, u32 tag_len) if (tag_len > RK_MAX_TAG_SIZE) return -EINVAL; - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_TAG_VALID, + ret = read_poll_timeout_atomic(CRYPTO_READ, reg_ctrl, reg_ctrl & CRYPTO_CH0_TAG_VALID, - RK_POLL_PERIOD_US, - RK_POLL_TIMEOUT_US); + 0, + RK_POLL_TIMEOUT_US, + false, + rk_dev, CRYPTO_TAG_VALID); if (ret) goto exit; @@ -187,8 +189,8 @@ static void rk_cipher_reset(struct rk_crypto_dev *rk_dev) CRYPTO_WRITE(rk_dev, CRYPTO_RST_CTL, tmp | tmp_mask); /* This is usually done in 20 clock cycles */ - ret = readl_poll_timeout_atomic(rk_dev->reg + CRYPTO_RST_CTL, - tmp, !tmp, 0, pool_timeout_us); + ret = read_poll_timeout_atomic(CRYPTO_READ, tmp, !tmp, 0, + pool_timeout_us, false, rk_dev, CRYPTO_RST_CTL); if (ret) dev_err(rk_dev->dev, "cipher reset pool timeout %ums.", pool_timeout_us); diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c index 1cdb66af9084..4348297316e0 100644 --- a/drivers/devfreq/rockchip_dmc.c +++ b/drivers/devfreq/rockchip_dmc.c @@ -118,6 +118,7 @@ struct rockchip_dmcfreq { struct regulator *vdd_center; struct regulator *mem_reg; struct notifier_block status_nb; + struct notifier_block panic_nb; struct list_head video_info_list; struct freq_map_table *cpu_bw_tbl; struct work_struct boost_work; @@ -2576,6 +2577,17 @@ next: return NOTIFY_OK; } +static int rockchip_dmcfreq_panic_notifier(struct notifier_block *nb, + unsigned long v, void *p) +{ + struct rockchip_dmcfreq *dmcfreq = + container_of(nb, struct rockchip_dmcfreq, panic_nb); + + rockchip_opp_dump_cur_state(dmcfreq->dev); + + return 0; +} + static ssize_t rockchip_dmcfreq_status_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -3129,6 +3141,12 @@ static void rockchip_dmcfreq_register_notifier(struct rockchip_dmcfreq *dmcfreq) if (ret) dev_err(dmcfreq->dev, "failed to register system_status nb\n"); + dmcfreq->panic_nb.notifier_call = rockchip_dmcfreq_panic_notifier; + ret = atomic_notifier_chain_register(&panic_notifier_list, + &dmcfreq->panic_nb); + if (ret) + dev_err(dmcfreq->dev, "failed to register panic nb\n"); + dmc_mdevp.data = dmcfreq->info.devfreq; dmcfreq->mdev_info = rockchip_system_monitor_register(dmcfreq->dev, &dmc_mdevp); diff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile index 4d4cd94a3a4a..4e134a221a06 100644 --- a/drivers/dma-buf/heaps/Makefile +++ b/drivers/dma-buf/heaps/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DMABUF_HEAPS_DEFERRED_FREE) += deferred-free-helper.o obj-$(CONFIG_DMABUF_HEAPS_PAGE_POOL) += page_pool.o -obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o -obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o +obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += rk_system_heap.o +obj-$(CONFIG_DMABUF_HEAPS_CMA) += rk_cma_heap.o diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 803f523cd3e5..fd564aa70ee9 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -21,7 +21,6 @@ #include #include #include -#include struct cma_heap { @@ -39,8 +38,6 @@ struct cma_heap_buffer { pgoff_t pagecount; int vmap_cnt; void *vaddr; - - bool uncached; }; struct dma_heap_attachment { @@ -48,8 +45,6 @@ struct dma_heap_attachment { struct sg_table table; struct list_head list; bool mapped; - - bool uncached; }; static int cma_heap_attach(struct dma_buf *dmabuf, @@ -76,7 +71,6 @@ static int cma_heap_attach(struct dma_buf *dmabuf, INIT_LIST_HEAD(&a->list); a->mapped = false; - a->uncached = buffer->uncached; attachment->priv = a; mutex_lock(&buffer->lock); @@ -108,9 +102,6 @@ static struct sg_table *cma_heap_map_dma_buf(struct dma_buf_attachment *attachme int attrs = attachment->dma_map_attrs; int ret; - if (a->uncached) - attrs |= DMA_ATTR_SKIP_CPU_SYNC; - ret = dma_map_sgtable(attachment->dev, table, direction, attrs); if (ret) return ERR_PTR(-ENOMEM); @@ -126,18 +117,11 @@ static void cma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, int attrs = attachment->dma_map_attrs; a->mapped = false; - - if (a->uncached) - attrs |= DMA_ATTR_SKIP_CPU_SYNC; - dma_unmap_sgtable(attachment->dev, table, direction, attrs); } -static int -cma_heap_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, - enum dma_data_direction direction, - unsigned int offset, - unsigned int len) +static int cma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) { struct cma_heap_buffer *buffer = dmabuf->priv; struct dma_heap_attachment *a; @@ -145,33 +129,19 @@ cma_heap_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, if (buffer->vmap_cnt) invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); - if (buffer->uncached) - return 0; - mutex_lock(&buffer->lock); list_for_each_entry(a, &buffer->attachments, list) { if (!a->mapped) continue; dma_sync_sgtable_for_cpu(a->dev, &a->table, direction); } - if (list_empty(&buffer->attachments)) { - phys_addr_t phys = page_to_phys(buffer->cma_pages); - - dma_sync_single_for_cpu(dma_heap_get_dev(buffer->heap->heap), - phys + offset, - len, - direction); - } mutex_unlock(&buffer->lock); return 0; } -static int -cma_heap_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, - enum dma_data_direction direction, - unsigned int offset, - unsigned int len) +static int cma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) { struct cma_heap_buffer *buffer = dmabuf->priv; struct dma_heap_attachment *a; @@ -179,42 +149,17 @@ cma_heap_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, if (buffer->vmap_cnt) flush_kernel_vmap_range(buffer->vaddr, buffer->len); - if (buffer->uncached) - return 0; - mutex_lock(&buffer->lock); list_for_each_entry(a, &buffer->attachments, list) { if (!a->mapped) continue; dma_sync_sgtable_for_device(a->dev, &a->table, direction); } - if (list_empty(&buffer->attachments)) { - phys_addr_t phys = page_to_phys(buffer->cma_pages); - - dma_sync_single_for_device(dma_heap_get_dev(buffer->heap->heap), - phys + offset, - len, - direction); - } mutex_unlock(&buffer->lock); return 0; } -static int cma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, - enum dma_data_direction dir) -{ - return cma_heap_dma_buf_begin_cpu_access_partial(dmabuf, dir, 0, - dmabuf->size); -} - -static int cma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, - enum dma_data_direction dir) -{ - return cma_heap_dma_buf_end_cpu_access_partial(dmabuf, dir, 0, - dmabuf->size); -} - static vm_fault_t cma_heap_vm_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; @@ -240,9 +185,6 @@ static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) return -EINVAL; - if (buffer->uncached) - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - vma->vm_ops = &dma_heap_vm_ops; vma->vm_private_data = buffer; @@ -252,12 +194,8 @@ static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) static void *cma_heap_do_vmap(struct cma_heap_buffer *buffer) { void *vaddr; - pgprot_t pgprot = PAGE_KERNEL; - if (buffer->uncached) - pgprot = pgprot_writecombine(PAGE_KERNEL); - - vaddr = vmap(buffer->pages, buffer->pagecount, VM_MAP, pgprot); + vaddr = vmap(buffer->pages, buffer->pagecount, VM_MAP, PAGE_KERNEL); if (!vaddr) return ERR_PTR(-ENOMEM); @@ -324,18 +262,16 @@ static const struct dma_buf_ops cma_heap_buf_ops = { .unmap_dma_buf = cma_heap_unmap_dma_buf, .begin_cpu_access = cma_heap_dma_buf_begin_cpu_access, .end_cpu_access = cma_heap_dma_buf_end_cpu_access, - .begin_cpu_access_partial = cma_heap_dma_buf_begin_cpu_access_partial, - .end_cpu_access_partial = cma_heap_dma_buf_end_cpu_access_partial, .mmap = cma_heap_mmap, .vmap = cma_heap_vmap, .vunmap = cma_heap_vunmap, .release = cma_heap_dma_buf_release, }; -static struct dma_buf *cma_heap_do_allocate(struct dma_heap *heap, +static struct dma_buf *cma_heap_allocate(struct dma_heap *heap, unsigned long len, unsigned long fd_flags, - unsigned long heap_flags, bool uncached) + unsigned long heap_flags) { struct cma_heap *cma_heap = dma_heap_get_drvdata(heap); struct cma_heap_buffer *buffer; @@ -347,14 +283,11 @@ static struct dma_buf *cma_heap_do_allocate(struct dma_heap *heap, struct dma_buf *dmabuf; int ret = -ENOMEM; pgoff_t pg; - dma_addr_t dma; buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (!buffer) return ERR_PTR(-ENOMEM); - buffer->uncached = uncached; - INIT_LIST_HEAD(&buffer->attachments); mutex_init(&buffer->lock); buffer->len = size; @@ -414,13 +347,6 @@ static struct dma_buf *cma_heap_do_allocate(struct dma_heap *heap, goto free_pages; } - if (buffer->uncached) { - dma = dma_map_page(dma_heap_get_dev(heap), buffer->cma_pages, 0, - buffer->pagecount * PAGE_SIZE, DMA_FROM_DEVICE); - dma_unmap_page(dma_heap_get_dev(heap), dma, - buffer->pagecount * PAGE_SIZE, DMA_FROM_DEVICE); - } - return dmabuf; free_pages: @@ -433,107 +359,14 @@ free_buffer: return ERR_PTR(ret); } -static struct dma_buf *cma_heap_allocate(struct dma_heap *heap, - unsigned long len, - unsigned long fd_flags, - unsigned long heap_flags) -{ - return cma_heap_do_allocate(heap, len, fd_flags, heap_flags, false); -} - -#if IS_ENABLED(CONFIG_NO_GKI) -static int cma_heap_get_phys(struct dma_heap *heap, - struct dma_heap_phys_data *phys) -{ - struct cma_heap *cma_heap = dma_heap_get_drvdata(heap); - struct cma_heap_buffer *buffer; - struct dma_buf *dmabuf; - - phys->paddr = (__u64)-1; - - if (IS_ERR_OR_NULL(phys)) - return -EINVAL; - - dmabuf = dma_buf_get(phys->fd); - if (IS_ERR_OR_NULL(dmabuf)) - return -EBADFD; - - buffer = dmabuf->priv; - if (IS_ERR_OR_NULL(buffer)) - goto err; - - if (buffer->heap != cma_heap) - goto err; - - phys->paddr = page_to_phys(buffer->cma_pages); - -err: - dma_buf_put(dmabuf); - - return (phys->paddr == (__u64)-1) ? -EINVAL : 0; -} -#endif - static const struct dma_heap_ops cma_heap_ops = { .allocate = cma_heap_allocate, -#if IS_ENABLED(CONFIG_NO_GKI) - .get_phys = cma_heap_get_phys, -#endif }; -static struct dma_buf *cma_uncached_heap_allocate(struct dma_heap *heap, - unsigned long len, - unsigned long fd_flags, - unsigned long heap_flags) -{ - return cma_heap_do_allocate(heap, len, fd_flags, heap_flags, true); -} - -static struct dma_buf *cma_uncached_heap_not_initialized(struct dma_heap *heap, - unsigned long len, - unsigned long fd_flags, - unsigned long heap_flags) -{ - pr_info("heap %s not initialized\n", dma_heap_get_name(heap)); - return ERR_PTR(-EBUSY); -} - -static struct dma_heap_ops cma_uncached_heap_ops = { - .allocate = cma_uncached_heap_not_initialized, -}; - -static int set_heap_dev_dma(struct device *heap_dev) -{ - int err = 0; - - if (!heap_dev) - return -EINVAL; - - dma_coerce_mask_and_coherent(heap_dev, DMA_BIT_MASK(64)); - - if (!heap_dev->dma_parms) { - heap_dev->dma_parms = devm_kzalloc(heap_dev, - sizeof(*heap_dev->dma_parms), - GFP_KERNEL); - if (!heap_dev->dma_parms) - return -ENOMEM; - - err = dma_set_max_seg_size(heap_dev, (unsigned int)DMA_BIT_MASK(64)); - if (err) { - devm_kfree(heap_dev, heap_dev->dma_parms); - dev_err(heap_dev, "Failed to set DMA segment size, err:%d\n", err); - return err; - } - } - - return 0; -} - static int __add_cma_heap(struct cma *cma, void *data) { - struct cma_heap *cma_heap, *cma_uncached_heap; + struct cma_heap *cma_heap; struct dma_heap_export_info exp_info; - int ret; cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); if (!cma_heap) @@ -546,47 +379,13 @@ static int __add_cma_heap(struct cma *cma, void *data) cma_heap->heap = dma_heap_add(&exp_info); if (IS_ERR(cma_heap->heap)) { - ret = PTR_ERR(cma_heap->heap); - goto free_cma_heap; + int ret = PTR_ERR(cma_heap->heap); + + kfree(cma_heap); + return ret; } - cma_uncached_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); - if (!cma_uncached_heap) { - ret = -ENOMEM; - goto put_cma_heap; - } - - cma_uncached_heap->cma = cma; - - exp_info.name = "cma-uncached"; - exp_info.ops = &cma_uncached_heap_ops; - exp_info.priv = cma_uncached_heap; - - cma_uncached_heap->heap = dma_heap_add(&exp_info); - if (IS_ERR(cma_uncached_heap->heap)) { - ret = PTR_ERR(cma_uncached_heap->heap); - goto free_uncached_cma_heap; - } - - ret = set_heap_dev_dma(dma_heap_get_dev(cma_uncached_heap->heap)); - if (ret) - goto put_uncached_cma_heap; - - mb(); /* make sure we only set allocate after dma_mask is set */ - cma_uncached_heap_ops.allocate = cma_uncached_heap_allocate; - return 0; - -put_uncached_cma_heap: - dma_heap_put(cma_uncached_heap->heap); -free_uncached_cma_heap: - kfree(cma_uncached_heap); -put_cma_heap: - dma_heap_put(cma_heap->heap); -free_cma_heap: - kfree(cma_heap); - - return ret; } static int add_default_cma_heap(void) diff --git a/drivers/dma-buf/heaps/rk_cma_heap.c b/drivers/dma-buf/heaps/rk_cma_heap.c new file mode 100644 index 000000000000..7631997e8e21 --- /dev/null +++ b/drivers/dma-buf/heaps/rk_cma_heap.c @@ -0,0 +1,614 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMABUF CMA heap exporter + * + * Copyright (C) 2012, 2019, 2020 Linaro Ltd. + * Author: for ST-Ericsson. + * + * Also utilizing parts of Andrew Davis' SRAM heap: + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * Andrew F. Davis + * + * Copyright (C) 2021, 2022 Rockchip Electronics Co. Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct cma_heap { + struct dma_heap *heap; + struct cma *cma; +}; + +struct cma_heap_buffer { + struct cma_heap *heap; + struct list_head attachments; + struct mutex lock; + unsigned long len; + struct page *cma_pages; + struct page **pages; + pgoff_t pagecount; + int vmap_cnt; + void *vaddr; + + bool uncached; +}; + +struct dma_heap_attachment { + struct device *dev; + struct sg_table table; + struct list_head list; + bool mapped; + + bool uncached; +}; + +static int cma_heap_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + int ret; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + ret = sg_alloc_table_from_pages(&a->table, buffer->pages, + buffer->pagecount, 0, + buffer->pagecount << PAGE_SHIFT, + GFP_KERNEL); + if (ret) { + kfree(a); + return ret; + } + + a->dev = attachment->dev; + INIT_LIST_HEAD(&a->list); + a->mapped = false; + + a->uncached = buffer->uncached; + attachment->priv = a; + + mutex_lock(&buffer->lock); + list_add(&a->list, &buffer->attachments); + mutex_unlock(&buffer->lock); + + return 0; +} + +static void cma_heap_detach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a = attachment->priv; + + mutex_lock(&buffer->lock); + list_del(&a->list); + mutex_unlock(&buffer->lock); + + sg_free_table(&a->table); + kfree(a); +} + +static struct sg_table *cma_heap_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct dma_heap_attachment *a = attachment->priv; + struct sg_table *table = &a->table; + int attrs = attachment->dma_map_attrs; + int ret; + + if (a->uncached) + attrs |= DMA_ATTR_SKIP_CPU_SYNC; + + ret = dma_map_sgtable(attachment->dev, table, direction, attrs); + if (ret) + return ERR_PTR(-ENOMEM); + a->mapped = true; + return table; +} + +static void cma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ + struct dma_heap_attachment *a = attachment->priv; + int attrs = attachment->dma_map_attrs; + + a->mapped = false; + + if (a->uncached) + attrs |= DMA_ATTR_SKIP_CPU_SYNC; + + dma_unmap_sgtable(attachment->dev, table, direction, attrs); +} + +static int +cma_heap_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, + enum dma_data_direction direction, + unsigned int offset, + unsigned int len) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + phys_addr_t phys = page_to_phys(buffer->cma_pages); + + if (buffer->vmap_cnt) + invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); + + if (buffer->uncached) + return 0; + + mutex_lock(&buffer->lock); + dma_sync_single_for_cpu(dma_heap_get_dev(buffer->heap->heap), + phys + offset, + len, + direction); + mutex_unlock(&buffer->lock); + + return 0; +} + +static int +cma_heap_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, + enum dma_data_direction direction, + unsigned int offset, + unsigned int len) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + phys_addr_t phys = page_to_phys(buffer->cma_pages); + + if (buffer->vmap_cnt) + flush_kernel_vmap_range(buffer->vaddr, buffer->len); + + if (buffer->uncached) + return 0; + + mutex_lock(&buffer->lock); + dma_sync_single_for_device(dma_heap_get_dev(buffer->heap->heap), + phys + offset, + len, + direction); + mutex_unlock(&buffer->lock); + + return 0; +} + +static int cma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + + if (buffer->vmap_cnt) + invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); + + mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; + dma_sync_sgtable_for_cpu(a->dev, &a->table, direction); + } + mutex_unlock(&buffer->lock); + + return 0; +} + +static int cma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + + if (buffer->vmap_cnt) + flush_kernel_vmap_range(buffer->vaddr, buffer->len); + + mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; + dma_sync_sgtable_for_device(a->dev, &a->table, direction); + } + mutex_unlock(&buffer->lock); + + return 0; +} + +static vm_fault_t cma_heap_vm_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct cma_heap_buffer *buffer = vma->vm_private_data; + + if (vmf->pgoff > buffer->pagecount) + return VM_FAULT_SIGBUS; + + vmf->page = buffer->pages[vmf->pgoff]; + get_page(vmf->page); + + return 0; +} + +static const struct vm_operations_struct dma_heap_vm_ops = { + .fault = cma_heap_vm_fault, +}; + +static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) + return -EINVAL; + + if (buffer->uncached) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + vma->vm_ops = &dma_heap_vm_ops; + vma->vm_private_data = buffer; + + return 0; +} + +static void *cma_heap_do_vmap(struct cma_heap_buffer *buffer) +{ + void *vaddr; + pgprot_t pgprot = PAGE_KERNEL; + + if (buffer->uncached) + pgprot = pgprot_writecombine(PAGE_KERNEL); + + vaddr = vmap(buffer->pages, buffer->pagecount, VM_MAP, pgprot); + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} + +static void *cma_heap_vmap(struct dma_buf *dmabuf) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + void *vaddr; + + mutex_lock(&buffer->lock); + if (buffer->vmap_cnt) { + buffer->vmap_cnt++; + vaddr = buffer->vaddr; + goto out; + } + + vaddr = cma_heap_do_vmap(buffer); + if (IS_ERR(vaddr)) + goto out; + + buffer->vaddr = vaddr; + buffer->vmap_cnt++; +out: + mutex_unlock(&buffer->lock); + + return vaddr; +} + +static void cma_heap_vunmap(struct dma_buf *dmabuf, void *vaddr) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + + mutex_lock(&buffer->lock); + if (!--buffer->vmap_cnt) { + vunmap(buffer->vaddr); + buffer->vaddr = NULL; + } + mutex_unlock(&buffer->lock); +} + +static void cma_heap_dma_buf_release(struct dma_buf *dmabuf) +{ + struct cma_heap_buffer *buffer = dmabuf->priv; + struct cma_heap *cma_heap = buffer->heap; + + if (buffer->vmap_cnt > 0) { + WARN(1, "%s: buffer still mapped in the kernel\n", __func__); + vunmap(buffer->vaddr); + } + + /* free page list */ + kfree(buffer->pages); + /* release memory */ + cma_release(cma_heap->cma, buffer->cma_pages, buffer->pagecount); + kfree(buffer); +} + +static const struct dma_buf_ops cma_heap_buf_ops = { + .attach = cma_heap_attach, + .detach = cma_heap_detach, + .map_dma_buf = cma_heap_map_dma_buf, + .unmap_dma_buf = cma_heap_unmap_dma_buf, + .begin_cpu_access = cma_heap_dma_buf_begin_cpu_access, + .end_cpu_access = cma_heap_dma_buf_end_cpu_access, + .begin_cpu_access_partial = cma_heap_dma_buf_begin_cpu_access_partial, + .end_cpu_access_partial = cma_heap_dma_buf_end_cpu_access_partial, + .mmap = cma_heap_mmap, + .vmap = cma_heap_vmap, + .vunmap = cma_heap_vunmap, + .release = cma_heap_dma_buf_release, +}; + +static struct dma_buf *cma_heap_do_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags, bool uncached) +{ + struct cma_heap *cma_heap = dma_heap_get_drvdata(heap); + struct cma_heap_buffer *buffer; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + size_t size = PAGE_ALIGN(len); + pgoff_t pagecount = size >> PAGE_SHIFT; + unsigned long align = get_order(size); + struct page *cma_pages; + struct dma_buf *dmabuf; + int ret = -ENOMEM; + pgoff_t pg; + dma_addr_t dma; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + + buffer->uncached = uncached; + + INIT_LIST_HEAD(&buffer->attachments); + mutex_init(&buffer->lock); + buffer->len = size; + + if (align > CONFIG_CMA_ALIGNMENT) + align = CONFIG_CMA_ALIGNMENT; + + cma_pages = cma_alloc(cma_heap->cma, pagecount, align, GFP_KERNEL); + if (!cma_pages) + goto free_buffer; + + /* Clear the cma pages */ + if (PageHighMem(cma_pages)) { + unsigned long nr_clear_pages = pagecount; + struct page *page = cma_pages; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(page); + + memset(vaddr, 0, PAGE_SIZE); + kunmap_atomic(vaddr); + /* + * Avoid wasting time zeroing memory if the process + * has been killed by by SIGKILL + */ + if (fatal_signal_pending(current)) + goto free_cma; + page++; + nr_clear_pages--; + } + } else { + memset(page_address(cma_pages), 0, size); + } + + buffer->pages = kmalloc_array(pagecount, sizeof(*buffer->pages), GFP_KERNEL); + if (!buffer->pages) { + ret = -ENOMEM; + goto free_cma; + } + + for (pg = 0; pg < pagecount; pg++) + buffer->pages[pg] = &cma_pages[pg]; + + buffer->cma_pages = cma_pages; + buffer->heap = cma_heap; + buffer->pagecount = pagecount; + + /* create the dmabuf */ + exp_info.exp_name = dma_heap_get_name(heap); + exp_info.ops = &cma_heap_buf_ops; + exp_info.size = buffer->len; + exp_info.flags = fd_flags; + exp_info.priv = buffer; + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto free_pages; + } + + if (buffer->uncached) { + dma = dma_map_page(dma_heap_get_dev(heap), buffer->cma_pages, 0, + buffer->pagecount * PAGE_SIZE, DMA_FROM_DEVICE); + dma_unmap_page(dma_heap_get_dev(heap), dma, + buffer->pagecount * PAGE_SIZE, DMA_FROM_DEVICE); + } + + return dmabuf; + +free_pages: + kfree(buffer->pages); +free_cma: + cma_release(cma_heap->cma, cma_pages, pagecount); +free_buffer: + kfree(buffer); + + return ERR_PTR(ret); +} + +static struct dma_buf *cma_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + return cma_heap_do_allocate(heap, len, fd_flags, heap_flags, false); +} + +#if IS_ENABLED(CONFIG_NO_GKI) +static int cma_heap_get_phys(struct dma_heap *heap, + struct dma_heap_phys_data *phys) +{ + struct cma_heap *cma_heap = dma_heap_get_drvdata(heap); + struct cma_heap_buffer *buffer; + struct dma_buf *dmabuf; + + phys->paddr = (__u64)-1; + + if (IS_ERR_OR_NULL(phys)) + return -EINVAL; + + dmabuf = dma_buf_get(phys->fd); + if (IS_ERR_OR_NULL(dmabuf)) + return -EBADFD; + + buffer = dmabuf->priv; + if (IS_ERR_OR_NULL(buffer)) + goto err; + + if (buffer->heap != cma_heap) + goto err; + + phys->paddr = page_to_phys(buffer->cma_pages); + +err: + dma_buf_put(dmabuf); + + return (phys->paddr == (__u64)-1) ? -EINVAL : 0; +} +#endif + +static const struct dma_heap_ops cma_heap_ops = { + .allocate = cma_heap_allocate, +#if IS_ENABLED(CONFIG_NO_GKI) + .get_phys = cma_heap_get_phys, +#endif +}; + +static struct dma_buf *cma_uncached_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + return cma_heap_do_allocate(heap, len, fd_flags, heap_flags, true); +} + +static struct dma_buf *cma_uncached_heap_not_initialized(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + pr_info("heap %s not initialized\n", dma_heap_get_name(heap)); + return ERR_PTR(-EBUSY); +} + +static struct dma_heap_ops cma_uncached_heap_ops = { + .allocate = cma_uncached_heap_not_initialized, +}; + +static int set_heap_dev_dma(struct device *heap_dev) +{ + int err = 0; + + if (!heap_dev) + return -EINVAL; + + dma_coerce_mask_and_coherent(heap_dev, DMA_BIT_MASK(64)); + + if (!heap_dev->dma_parms) { + heap_dev->dma_parms = devm_kzalloc(heap_dev, + sizeof(*heap_dev->dma_parms), + GFP_KERNEL); + if (!heap_dev->dma_parms) + return -ENOMEM; + + err = dma_set_max_seg_size(heap_dev, (unsigned int)DMA_BIT_MASK(64)); + if (err) { + devm_kfree(heap_dev, heap_dev->dma_parms); + dev_err(heap_dev, "Failed to set DMA segment size, err:%d\n", err); + return err; + } + } + + return 0; +} + +static int __add_cma_heap(struct cma *cma, void *data) +{ + struct cma_heap *cma_heap, *cma_uncached_heap; + struct dma_heap_export_info exp_info; + int ret; + + cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); + if (!cma_heap) + return -ENOMEM; + cma_heap->cma = cma; + + exp_info.name = "cma"; + exp_info.ops = &cma_heap_ops; + exp_info.priv = cma_heap; + + cma_heap->heap = dma_heap_add(&exp_info); + if (IS_ERR(cma_heap->heap)) { + ret = PTR_ERR(cma_heap->heap); + goto free_cma_heap; + } + + cma_uncached_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); + if (!cma_uncached_heap) { + ret = -ENOMEM; + goto put_cma_heap; + } + + cma_uncached_heap->cma = cma; + + exp_info.name = "cma-uncached"; + exp_info.ops = &cma_uncached_heap_ops; + exp_info.priv = cma_uncached_heap; + + cma_uncached_heap->heap = dma_heap_add(&exp_info); + if (IS_ERR(cma_uncached_heap->heap)) { + ret = PTR_ERR(cma_uncached_heap->heap); + goto free_uncached_cma_heap; + } + + ret = set_heap_dev_dma(dma_heap_get_dev(cma_uncached_heap->heap)); + if (ret) + goto put_uncached_cma_heap; + + mb(); /* make sure we only set allocate after dma_mask is set */ + cma_uncached_heap_ops.allocate = cma_uncached_heap_allocate; + + return 0; + +put_uncached_cma_heap: + dma_heap_put(cma_uncached_heap->heap); +free_uncached_cma_heap: + kfree(cma_uncached_heap); +put_cma_heap: + dma_heap_put(cma_heap->heap); +free_cma_heap: + kfree(cma_heap); + + return ret; +} + +static int add_default_cma_heap(void) +{ + struct cma *default_cma = dev_get_cma_area(NULL); + int ret = 0; + + if (default_cma) + ret = __add_cma_heap(default_cma, NULL); + + return ret; +} +module_init(add_default_cma_heap); +MODULE_DESCRIPTION("DMA-BUF CMA Heap"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma-buf/heaps/rk_system_heap.c b/drivers/dma-buf/heaps/rk_system_heap.c new file mode 100644 index 000000000000..2d29eec1a670 --- /dev/null +++ b/drivers/dma-buf/heaps/rk_system_heap.c @@ -0,0 +1,840 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMABUF System heap exporter for Rockchip + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2019, 2020 Linaro Ltd. + * Copyright (c) 2021, 2022 Rockchip Electronics Co. Ltd. + * + * Portions based off of Andrew Davis' SRAM heap: + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * Andrew F. Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "page_pool.h" +#include "deferred-free-helper.h" + +static struct dma_heap *sys_heap; +static struct dma_heap *sys_dma32_heap; +static struct dma_heap *sys_uncached_heap; +static struct dma_heap *sys_uncached_dma32_heap; + +/* Default setting */ +static u32 bank_bit_first = 12; +static u32 bank_bit_mask = 0x7; + +struct system_heap_buffer { + struct dma_heap *heap; + struct list_head attachments; + struct mutex lock; + unsigned long len; + struct sg_table sg_table; + int vmap_cnt; + void *vaddr; + struct deferred_freelist_item deferred_free; + struct dmabuf_page_pool **pools; + bool uncached; +}; + +struct dma_heap_attachment { + struct device *dev; + struct sg_table *table; + struct list_head list; + bool mapped; + + bool uncached; +}; + +#define LOW_ORDER_GFP (GFP_HIGHUSER | __GFP_ZERO | __GFP_COMP) +#define MID_ORDER_GFP (LOW_ORDER_GFP | __GFP_NOWARN) +#define HIGH_ORDER_GFP (((GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN \ + | __GFP_NORETRY) & ~__GFP_RECLAIM) \ + | __GFP_COMP) +static gfp_t order_flags[] = {HIGH_ORDER_GFP, MID_ORDER_GFP, LOW_ORDER_GFP}; +/* + * The selection of the orders used for allocation (1MB, 64K, 4K) is designed + * to match with the sizes often found in IOMMUs. Using order 4 pages instead + * of order 0 pages can significantly improve the performance of many IOMMUs + * by reducing TLB pressure and time spent updating page tables. + */ +static unsigned int orders[] = {8, 4, 0}; +#define NUM_ORDERS ARRAY_SIZE(orders) +struct dmabuf_page_pool *pools[NUM_ORDERS]; +struct dmabuf_page_pool *dma32_pools[NUM_ORDERS]; + +static struct sg_table *dup_sg_table(struct sg_table *table) +{ + struct sg_table *new_table; + int ret, i; + struct scatterlist *sg, *new_sg; + + new_table = kzalloc(sizeof(*new_table), GFP_KERNEL); + if (!new_table) + return ERR_PTR(-ENOMEM); + + ret = sg_alloc_table(new_table, table->orig_nents, GFP_KERNEL); + if (ret) { + kfree(new_table); + return ERR_PTR(-ENOMEM); + } + + new_sg = new_table->sgl; + for_each_sgtable_sg(table, sg, i) { + sg_set_page(new_sg, sg_page(sg), sg->length, sg->offset); + new_sg = sg_next(new_sg); + } + + return new_table; +} + +static int system_heap_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + struct sg_table *table; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + table = dup_sg_table(&buffer->sg_table); + if (IS_ERR(table)) { + kfree(a); + return -ENOMEM; + } + + a->table = table; + a->dev = attachment->dev; + INIT_LIST_HEAD(&a->list); + a->mapped = false; + a->uncached = buffer->uncached; + attachment->priv = a; + + mutex_lock(&buffer->lock); + list_add(&a->list, &buffer->attachments); + mutex_unlock(&buffer->lock); + + return 0; +} + +static void system_heap_detach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a = attachment->priv; + + mutex_lock(&buffer->lock); + list_del(&a->list); + mutex_unlock(&buffer->lock); + + sg_free_table(a->table); + kfree(a->table); + kfree(a); +} + +static struct sg_table *system_heap_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct dma_heap_attachment *a = attachment->priv; + struct sg_table *table = a->table; + int attr = attachment->dma_map_attrs; + int ret; + + if (a->uncached) + attr |= DMA_ATTR_SKIP_CPU_SYNC; + + ret = dma_map_sgtable(attachment->dev, table, direction, attr); + if (ret) + return ERR_PTR(ret); + + a->mapped = true; + return table; +} + +static void system_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ + struct dma_heap_attachment *a = attachment->priv; + int attr = attachment->dma_map_attrs; + + if (a->uncached) + attr |= DMA_ATTR_SKIP_CPU_SYNC; + a->mapped = false; + dma_unmap_sgtable(attachment->dev, table, direction, attr); +} + +static int system_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + + mutex_lock(&buffer->lock); + + if (buffer->vmap_cnt) + invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); + + if (!buffer->uncached) { + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; + dma_sync_sgtable_for_cpu(a->dev, a->table, direction); + } + } + mutex_unlock(&buffer->lock); + + return 0; +} + +static int system_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + + mutex_lock(&buffer->lock); + + if (buffer->vmap_cnt) + flush_kernel_vmap_range(buffer->vaddr, buffer->len); + + if (!buffer->uncached) { + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; + dma_sync_sgtable_for_device(a->dev, a->table, direction); + } + } + mutex_unlock(&buffer->lock); + + return 0; +} + +static int system_heap_sgl_sync_range(struct device *dev, + struct sg_table *sgt, + unsigned int offset, + unsigned int length, + enum dma_data_direction dir, + bool for_cpu) +{ + struct scatterlist *sg; + unsigned int len = 0; + dma_addr_t sg_dma_addr; + int i; + + for_each_sgtable_sg(sgt, sg, i) { + unsigned int sg_offset, sg_left, size = 0; + + sg_dma_addr = sg_phys(sg); + + len += sg->length; + if (len <= offset) + continue; + + sg_left = len - offset; + sg_offset = sg->length - sg_left; + + size = (length < sg_left) ? length : sg_left; + if (for_cpu) + dma_sync_single_range_for_cpu(dev, sg_dma_addr, + sg_offset, size, dir); + else + dma_sync_single_range_for_device(dev, sg_dma_addr, + sg_offset, size, dir); + + offset += size; + length -= size; + + if (length == 0) + break; + } + + return 0; +} + +static int +system_heap_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, + enum dma_data_direction direction, + unsigned int offset, + unsigned int len) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + struct dma_heap *heap = buffer->heap; + struct sg_table *table = &buffer->sg_table; + int ret; + + if (direction == DMA_TO_DEVICE) + return 0; + + mutex_lock(&buffer->lock); + if (buffer->vmap_cnt) + invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); + + if (buffer->uncached) { + mutex_unlock(&buffer->lock); + return 0; + } + + ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap), table, + offset, len, direction, true); + mutex_unlock(&buffer->lock); + + return ret; +} + +static int +system_heap_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, + enum dma_data_direction direction, + unsigned int offset, + unsigned int len) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + struct dma_heap *heap = buffer->heap; + struct sg_table *table = &buffer->sg_table; + int ret; + + mutex_lock(&buffer->lock); + if (buffer->vmap_cnt) + flush_kernel_vmap_range(buffer->vaddr, buffer->len); + + if (buffer->uncached) { + mutex_unlock(&buffer->lock); + return 0; + } + + ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap), table, + offset, len, direction, false); + mutex_unlock(&buffer->lock); + + return ret; +} + +static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + struct sg_table *table = &buffer->sg_table; + unsigned long addr = vma->vm_start; + struct sg_page_iter piter; + int ret; + + if (buffer->uncached) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + for_each_sgtable_page(table, &piter, vma->vm_pgoff) { + struct page *page = sg_page_iter_page(&piter); + + ret = remap_pfn_range(vma, addr, page_to_pfn(page), PAGE_SIZE, + vma->vm_page_prot); + if (ret) + return ret; + addr += PAGE_SIZE; + if (addr >= vma->vm_end) + return 0; + } + return 0; +} + +static void *system_heap_do_vmap(struct system_heap_buffer *buffer) +{ + struct sg_table *table = &buffer->sg_table; + int npages = PAGE_ALIGN(buffer->len) / PAGE_SIZE; + struct page **pages = vmalloc(sizeof(struct page *) * npages); + struct page **tmp = pages; + struct sg_page_iter piter; + pgprot_t pgprot = PAGE_KERNEL; + void *vaddr; + + if (!pages) + return ERR_PTR(-ENOMEM); + + if (buffer->uncached) + pgprot = pgprot_writecombine(PAGE_KERNEL); + + for_each_sgtable_page(table, &piter, 0) { + WARN_ON(tmp - pages >= npages); + *tmp++ = sg_page_iter_page(&piter); + } + + vaddr = vmap(pages, npages, VM_MAP, pgprot); + vfree(pages); + + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} + +static void *system_heap_vmap(struct dma_buf *dmabuf) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + void *vaddr; + + mutex_lock(&buffer->lock); + if (buffer->vmap_cnt) { + buffer->vmap_cnt++; + vaddr = buffer->vaddr; + goto out; + } + + vaddr = system_heap_do_vmap(buffer); + if (IS_ERR(vaddr)) + goto out; + + buffer->vaddr = vaddr; + buffer->vmap_cnt++; +out: + mutex_unlock(&buffer->lock); + + return vaddr; +} + +static void system_heap_vunmap(struct dma_buf *dmabuf, void *vaddr) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + + mutex_lock(&buffer->lock); + if (!--buffer->vmap_cnt) { + vunmap(buffer->vaddr); + buffer->vaddr = NULL; + } + mutex_unlock(&buffer->lock); +} + +static int system_heap_zero_buffer(struct system_heap_buffer *buffer) +{ + struct sg_table *sgt = &buffer->sg_table; + struct sg_page_iter piter; + struct page *p; + void *vaddr; + int ret = 0; + + for_each_sgtable_page(sgt, &piter, 0) { + p = sg_page_iter_page(&piter); + vaddr = kmap_atomic(p); + memset(vaddr, 0, PAGE_SIZE); + kunmap_atomic(vaddr); + } + + return ret; +} + +static void system_heap_buf_free(struct deferred_freelist_item *item, + enum df_reason reason) +{ + struct system_heap_buffer *buffer; + struct sg_table *table; + struct scatterlist *sg; + int i, j; + + buffer = container_of(item, struct system_heap_buffer, deferred_free); + /* Zero the buffer pages before adding back to the pool */ + if (reason == DF_NORMAL) + if (system_heap_zero_buffer(buffer)) + reason = DF_UNDER_PRESSURE; // On failure, just free + + table = &buffer->sg_table; + for_each_sgtable_sg(table, sg, i) { + struct page *page = sg_page(sg); + + if (reason == DF_UNDER_PRESSURE) { + __free_pages(page, compound_order(page)); + } else { + for (j = 0; j < NUM_ORDERS; j++) { + if (compound_order(page) == orders[j]) + break; + } + dmabuf_page_pool_free(buffer->pools[j], page); + } + } + sg_free_table(table); + kfree(buffer); +} + +static void system_heap_dma_buf_release(struct dma_buf *dmabuf) +{ + struct system_heap_buffer *buffer = dmabuf->priv; + int npages = PAGE_ALIGN(buffer->len) / PAGE_SIZE; + + deferred_free(&buffer->deferred_free, system_heap_buf_free, npages); +} + +static const struct dma_buf_ops system_heap_buf_ops = { + .attach = system_heap_attach, + .detach = system_heap_detach, + .map_dma_buf = system_heap_map_dma_buf, + .unmap_dma_buf = system_heap_unmap_dma_buf, + .begin_cpu_access = system_heap_dma_buf_begin_cpu_access, + .end_cpu_access = system_heap_dma_buf_end_cpu_access, + .begin_cpu_access_partial = system_heap_dma_buf_begin_cpu_access_partial, + .end_cpu_access_partial = system_heap_dma_buf_end_cpu_access_partial, + .mmap = system_heap_mmap, + .vmap = system_heap_vmap, + .vunmap = system_heap_vunmap, + .release = system_heap_dma_buf_release, +}; + +static struct page *system_heap_alloc_largest_available(struct dma_heap *heap, + struct dmabuf_page_pool **pool, + unsigned long size, + unsigned int max_order) +{ + struct page *page; + int i; + + for (i = 0; i < NUM_ORDERS; i++) { + if (size < (PAGE_SIZE << orders[i])) + continue; + if (max_order < orders[i]) + continue; + page = dmabuf_page_pool_alloc(pool[i]); + if (!page) + continue; + return page; + } + return NULL; +} + +static struct dma_buf *system_heap_do_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags, + bool uncached) +{ + struct system_heap_buffer *buffer; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + unsigned long size_remaining = len; + unsigned int max_order = orders[0]; + struct dma_buf *dmabuf; + struct sg_table *table; + struct scatterlist *sg; + struct list_head pages; + struct page *page, *tmp_page; + int i, ret = -ENOMEM; + struct list_head lists[8]; + unsigned int block_index[8] = {0}; + unsigned int block_1M = 0; + unsigned int block_64K = 0; + unsigned int maximum; + int j; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&buffer->attachments); + mutex_init(&buffer->lock); + buffer->heap = heap; + buffer->len = len; + buffer->uncached = uncached; + buffer->pools = strstr(dma_heap_get_name(heap), "dma32") ? dma32_pools : pools; + + INIT_LIST_HEAD(&pages); + for (i = 0; i < 8; i++) + INIT_LIST_HEAD(&lists[i]); + i = 0; + while (size_remaining > 0) { + /* + * Avoid trying to allocate memory if the process + * has been killed by SIGKILL + */ + if (fatal_signal_pending(current)) + goto free_buffer; + + page = system_heap_alloc_largest_available(heap, buffer->pools, + size_remaining, + max_order); + if (!page) + goto free_buffer; + + size_remaining -= page_size(page); + max_order = compound_order(page); + if (max_order) { + if (max_order == 8) + block_1M++; + if (max_order == 4) + block_64K++; + list_add_tail(&page->lru, &pages); + } else { + dma_addr_t phys = page_to_phys(page); + unsigned int bit_index = ((phys >> bank_bit_first) & bank_bit_mask) & 0x7; + + list_add_tail(&page->lru, &lists[bit_index]); + block_index[bit_index]++; + } + i++; + } + + table = &buffer->sg_table; + if (sg_alloc_table(table, i, GFP_KERNEL)) + goto free_buffer; + + maximum = block_index[0]; + for (i = 1; i < 8; i++) + maximum = max(maximum, block_index[i]); + sg = table->sgl; + list_for_each_entry_safe(page, tmp_page, &pages, lru) { + sg_set_page(sg, page, page_size(page), 0); + sg = sg_next(sg); + list_del(&page->lru); + } + for (i = 0; i < maximum; i++) { + for (j = 0; j < 8; j++) { + if (!list_empty(&lists[j])) { + page = list_first_entry(&lists[j], struct page, lru); + sg_set_page(sg, page, PAGE_SIZE, 0); + sg = sg_next(sg); + list_del(&page->lru); + } + } + } + + /* create the dmabuf */ + exp_info.exp_name = dma_heap_get_name(heap); + exp_info.ops = &system_heap_buf_ops; + exp_info.size = buffer->len; + exp_info.flags = fd_flags; + exp_info.priv = buffer; + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto free_pages; + } + + /* + * For uncached buffers, we need to initially flush cpu cache, since + * the __GFP_ZERO on the allocation means the zeroing was done by the + * cpu and thus it is likely cached. Map (and implicitly flush) and + * unmap it now so we don't get corruption later on. + */ + if (buffer->uncached) { + dma_map_sgtable(dma_heap_get_dev(heap), table, DMA_BIDIRECTIONAL, 0); + dma_unmap_sgtable(dma_heap_get_dev(heap), table, DMA_BIDIRECTIONAL, 0); + } + + return dmabuf; + +free_pages: + for_each_sgtable_sg(table, sg, i) { + struct page *p = sg_page(sg); + + __free_pages(p, compound_order(p)); + } + sg_free_table(table); +free_buffer: + list_for_each_entry_safe(page, tmp_page, &pages, lru) + __free_pages(page, compound_order(page)); + for (i = 0; i < 8; i++) { + list_for_each_entry_safe(page, tmp_page, &lists[i], lru) + __free_pages(page, compound_order(page)); + } + kfree(buffer); + + return ERR_PTR(ret); +} + +static struct dma_buf *system_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + return system_heap_do_allocate(heap, len, fd_flags, heap_flags, false); +} + +static long system_get_pool_size(struct dma_heap *heap) +{ + int i; + long num_pages = 0; + struct dmabuf_page_pool **pool; + + pool = strstr(dma_heap_get_name(heap), "dma32") ? dma32_pools : pools; + for (i = 0; i < NUM_ORDERS; i++, pool++) { + num_pages += ((*pool)->count[POOL_LOWPAGE] + + (*pool)->count[POOL_HIGHPAGE]) << (*pool)->order; + } + + return num_pages << PAGE_SHIFT; +} + +static const struct dma_heap_ops system_heap_ops = { + .allocate = system_heap_allocate, + .get_pool_size = system_get_pool_size, +}; + +static struct dma_buf *system_uncached_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + return system_heap_do_allocate(heap, len, fd_flags, heap_flags, true); +} + +/* Dummy function to be used until we can call coerce_mask_and_coherent */ +static struct dma_buf *system_uncached_heap_not_initialized(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + return ERR_PTR(-EBUSY); +} + +static struct dma_heap_ops system_uncached_heap_ops = { + /* After system_heap_create is complete, we will swap this */ + .allocate = system_uncached_heap_not_initialized, +}; + +static int set_heap_dev_dma(struct device *heap_dev) +{ + int err = 0; + + if (!heap_dev) + return -EINVAL; + + dma_coerce_mask_and_coherent(heap_dev, DMA_BIT_MASK(64)); + + if (!heap_dev->dma_parms) { + heap_dev->dma_parms = devm_kzalloc(heap_dev, + sizeof(*heap_dev->dma_parms), + GFP_KERNEL); + if (!heap_dev->dma_parms) + return -ENOMEM; + + err = dma_set_max_seg_size(heap_dev, (unsigned int)DMA_BIT_MASK(64)); + if (err) { + devm_kfree(heap_dev, heap_dev->dma_parms); + dev_err(heap_dev, "Failed to set DMA segment size, err:%d\n", err); + return err; + } + } + + return 0; +} + +static int system_heap_create(void) +{ + struct dma_heap_export_info exp_info; + int i, err = 0; + struct dram_addrmap_info *ddr_map_info; + + /* + * Since swiotlb has memory size limitation, this will calculate + * the maximum size locally. + * + * Once swiotlb_max_segment() return not '0', means that the totalram size + * is larger than 4GiB and swiotlb is not force mode, in this case, system + * heap should limit largest allocation. + * + * FIX: fix the orders[] as a workaround. + */ + if (swiotlb_max_segment()) { + unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE; + int max_order = MAX_ORDER; + int i; + + max_size = max_t(unsigned int, max_size, PAGE_SIZE) >> PAGE_SHIFT; + max_order = min(max_order, ilog2(max_size)); + for (i = 0; i < NUM_ORDERS; i++) { + if (max_order < orders[i]) + orders[i] = max_order; + pr_info("system_heap: orders[%d] = %u\n", i, orders[i]); + } + } + + for (i = 0; i < NUM_ORDERS; i++) { + pools[i] = dmabuf_page_pool_create(order_flags[i], orders[i]); + + if (!pools[i]) { + int j; + + pr_err("%s: page pool creation failed!\n", __func__); + for (j = 0; j < i; j++) + dmabuf_page_pool_destroy(pools[j]); + return -ENOMEM; + } + } + + for (i = 0; i < NUM_ORDERS; i++) { + dma32_pools[i] = dmabuf_page_pool_create(order_flags[i] | GFP_DMA32, orders[i]); + + if (!dma32_pools[i]) { + int j; + + pr_err("%s: page dma32 pool creation failed!\n", __func__); + for (j = 0; j < i; j++) + dmabuf_page_pool_destroy(dma32_pools[j]); + goto err_dma32_pool; + } + } + + exp_info.name = "system"; + exp_info.ops = &system_heap_ops; + exp_info.priv = NULL; + + sys_heap = dma_heap_add(&exp_info); + if (IS_ERR(sys_heap)) + return PTR_ERR(sys_heap); + + exp_info.name = "system-dma32"; + exp_info.ops = &system_heap_ops; + exp_info.priv = NULL; + + sys_dma32_heap = dma_heap_add(&exp_info); + if (IS_ERR(sys_dma32_heap)) + return PTR_ERR(sys_dma32_heap); + + exp_info.name = "system-uncached"; + exp_info.ops = &system_uncached_heap_ops; + exp_info.priv = NULL; + + sys_uncached_heap = dma_heap_add(&exp_info); + if (IS_ERR(sys_uncached_heap)) + return PTR_ERR(sys_uncached_heap); + + err = set_heap_dev_dma(dma_heap_get_dev(sys_uncached_heap)); + if (err) + return err; + + exp_info.name = "system-uncached-dma32"; + exp_info.ops = &system_uncached_heap_ops; + exp_info.priv = NULL; + + sys_uncached_dma32_heap = dma_heap_add(&exp_info); + if (IS_ERR(sys_uncached_dma32_heap)) + return PTR_ERR(sys_uncached_dma32_heap); + + err = set_heap_dev_dma(dma_heap_get_dev(sys_uncached_dma32_heap)); + if (err) + return err; + dma_coerce_mask_and_coherent(dma_heap_get_dev(sys_uncached_dma32_heap), DMA_BIT_MASK(32)); + + mb(); /* make sure we only set allocate after dma_mask is set */ + system_uncached_heap_ops.allocate = system_uncached_heap_allocate; + + ddr_map_info = sip_smc_get_dram_map(); + if (ddr_map_info) { + bank_bit_first = ddr_map_info->bank_bit_first; + bank_bit_mask = ddr_map_info->bank_bit_mask; + } + + return 0; +err_dma32_pool: + for (i = 0; i < NUM_ORDERS; i++) + dmabuf_page_pool_destroy(pools[i]); + + return -ENOMEM; +} +module_init(system_heap_create); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index a21fddd4abc6..b46cdaa69702 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -19,21 +19,13 @@ #include #include #include -#include #include -#include #include "page_pool.h" #include "deferred-free-helper.h" static struct dma_heap *sys_heap; -static struct dma_heap *sys_dma32_heap; static struct dma_heap *sys_uncached_heap; -static struct dma_heap *sys_uncached_dma32_heap; - -/* Default setting */ -static u32 bank_bit_first = 12; -static u32 bank_bit_mask = 0x7; struct system_heap_buffer { struct dma_heap *heap; @@ -69,10 +61,9 @@ static gfp_t order_flags[] = {HIGH_ORDER_GFP, MID_ORDER_GFP, LOW_ORDER_GFP}; * of order 0 pages can significantly improve the performance of many IOMMUs * by reducing TLB pressure and time spent updating page tables. */ -static unsigned int orders[] = {8, 4, 0}; +static const unsigned int orders[] = {8, 4, 0}; #define NUM_ORDERS ARRAY_SIZE(orders) struct dmabuf_page_pool *pools[NUM_ORDERS]; -struct dmabuf_page_pool *dma32_pools[NUM_ORDERS]; static struct sg_table *dup_sg_table(struct sg_table *table) { @@ -223,105 +214,6 @@ static int system_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, return 0; } -static int system_heap_sgl_sync_range(struct device *dev, - struct sg_table *sgt, - unsigned int offset, - unsigned int length, - enum dma_data_direction dir, - bool for_cpu) -{ - struct scatterlist *sg; - unsigned int len = 0; - dma_addr_t sg_dma_addr; - int i; - - for_each_sgtable_sg(sgt, sg, i) { - unsigned int sg_offset, sg_left, size = 0; - - sg_dma_addr = sg_phys(sg); - - len += sg->length; - if (len <= offset) - continue; - - sg_left = len - offset; - sg_offset = sg->length - sg_left; - - size = (length < sg_left) ? length : sg_left; - if (for_cpu) - dma_sync_single_range_for_cpu(dev, sg_dma_addr, - sg_offset, size, dir); - else - dma_sync_single_range_for_device(dev, sg_dma_addr, - sg_offset, size, dir); - - offset += size; - length -= size; - - if (length == 0) - break; - } - - return 0; -} - -static int -system_heap_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, - enum dma_data_direction direction, - unsigned int offset, - unsigned int len) -{ - struct system_heap_buffer *buffer = dmabuf->priv; - struct dma_heap *heap = buffer->heap; - struct sg_table *table = &buffer->sg_table; - int ret; - - if (direction == DMA_TO_DEVICE) - return 0; - - mutex_lock(&buffer->lock); - if (buffer->vmap_cnt) - invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); - - if (buffer->uncached) { - mutex_unlock(&buffer->lock); - return 0; - } - - ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap), table, - offset, len, direction, true); - mutex_unlock(&buffer->lock); - - return ret; -} - -static int -system_heap_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, - enum dma_data_direction direction, - unsigned int offset, - unsigned int len) -{ - struct system_heap_buffer *buffer = dmabuf->priv; - struct dma_heap *heap = buffer->heap; - struct sg_table *table = &buffer->sg_table; - int ret; - - mutex_lock(&buffer->lock); - if (buffer->vmap_cnt) - flush_kernel_vmap_range(buffer->vaddr, buffer->len); - - if (buffer->uncached) { - mutex_unlock(&buffer->lock); - return 0; - } - - ret = system_heap_sgl_sync_range(dma_heap_get_dev(heap), table, - offset, len, direction, false); - mutex_unlock(&buffer->lock); - - return ret; -} - static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) { struct system_heap_buffer *buffer = dmabuf->priv; @@ -478,30 +370,24 @@ static const struct dma_buf_ops system_heap_buf_ops = { .unmap_dma_buf = system_heap_unmap_dma_buf, .begin_cpu_access = system_heap_dma_buf_begin_cpu_access, .end_cpu_access = system_heap_dma_buf_end_cpu_access, - .begin_cpu_access_partial = system_heap_dma_buf_begin_cpu_access_partial, - .end_cpu_access_partial = system_heap_dma_buf_end_cpu_access_partial, .mmap = system_heap_mmap, .vmap = system_heap_vmap, .vunmap = system_heap_vunmap, .release = system_heap_dma_buf_release, }; -static struct page *system_heap_alloc_largest_available(struct dma_heap *heap, - unsigned long size, - unsigned int max_order) +static struct page *alloc_largest_available(unsigned long size, + unsigned int max_order) { struct page *page; int i; - const char *name = dma_heap_get_name(heap); - struct dmabuf_page_pool **pool; - pool = strstr(name, "dma32") ? dma32_pools : pools; for (i = 0; i < NUM_ORDERS; i++) { if (size < (PAGE_SIZE << orders[i])) continue; if (max_order < orders[i]) continue; - page = dmabuf_page_pool_alloc(pool[i]); + page = dmabuf_page_pool_alloc(pools[i]); if (!page) continue; return page; @@ -525,12 +411,6 @@ static struct dma_buf *system_heap_do_allocate(struct dma_heap *heap, struct list_head pages; struct page *page, *tmp_page; int i, ret = -ENOMEM; - struct list_head lists[8]; - unsigned int block_index[8] = {0}; - unsigned int block_1M = 0; - unsigned int block_64K = 0; - unsigned int maximum; - int j; buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (!buffer) @@ -543,8 +423,6 @@ static struct dma_buf *system_heap_do_allocate(struct dma_heap *heap, buffer->uncached = uncached; INIT_LIST_HEAD(&pages); - for (i = 0; i < 8; i++) - INIT_LIST_HEAD(&lists[i]); i = 0; while (size_remaining > 0) { /* @@ -554,25 +432,13 @@ static struct dma_buf *system_heap_do_allocate(struct dma_heap *heap, if (fatal_signal_pending(current)) goto free_buffer; - page = system_heap_alloc_largest_available(heap, size_remaining, max_order); + page = alloc_largest_available(size_remaining, max_order); if (!page) goto free_buffer; + list_add_tail(&page->lru, &pages); size_remaining -= page_size(page); max_order = compound_order(page); - if (max_order) { - if (max_order == 8) - block_1M++; - if (max_order == 4) - block_64K++; - list_add_tail(&page->lru, &pages); - } else { - dma_addr_t phys = page_to_phys(page); - unsigned int bit_index = ((phys >> bank_bit_first) & bank_bit_mask) & 0x7; - - list_add_tail(&page->lru, &lists[bit_index]); - block_index[bit_index]++; - } i++; } @@ -580,25 +446,12 @@ static struct dma_buf *system_heap_do_allocate(struct dma_heap *heap, if (sg_alloc_table(table, i, GFP_KERNEL)) goto free_buffer; - maximum = block_index[0]; - for (i = 1; i < 8; i++) - maximum = max(maximum, block_index[i]); sg = table->sgl; list_for_each_entry_safe(page, tmp_page, &pages, lru) { sg_set_page(sg, page, page_size(page), 0); sg = sg_next(sg); list_del(&page->lru); } - for (i = 0; i < maximum; i++) { - for (j = 0; j < 8; j++) { - if (!list_empty(&lists[j])) { - page = list_first_entry(&lists[j], struct page, lru); - sg_set_page(sg, page, PAGE_SIZE, 0); - sg = sg_next(sg); - list_del(&page->lru); - } - } - } /* create the dmabuf */ exp_info.exp_name = dma_heap_get_name(heap); @@ -635,10 +488,6 @@ free_pages: free_buffer: list_for_each_entry_safe(page, tmp_page, &pages, lru) __free_pages(page, compound_order(page)); - for (i = 0; i < 8; i++) { - list_for_each_entry_safe(page, tmp_page, &lists[i], lru) - __free_pages(page, compound_order(page)); - } kfree(buffer); return ERR_PTR(ret); @@ -657,11 +506,8 @@ static long system_get_pool_size(struct dma_heap *heap) int i; long num_pages = 0; struct dmabuf_page_pool **pool; - const char *name = dma_heap_get_name(heap); pool = pools; - if (!strcmp(name, "system-dma32") || !strcmp(name, "system-uncached-dma32")) - pool = dma32_pools; for (i = 0; i < NUM_ORDERS; i++, pool++) { num_pages += ((*pool)->count[POOL_LOWPAGE] + (*pool)->count[POOL_HIGHPAGE]) << (*pool)->order; @@ -728,31 +574,6 @@ static int system_heap_create(void) { struct dma_heap_export_info exp_info; int i, err = 0; - struct dram_addrmap_info *ddr_map_info; - - /* - * Since swiotlb has memory size limitation, this will calculate - * the maximum size locally. - * - * Once swiotlb_max_segment() return not '0', means that the totalram size - * is larger than 4GiB and swiotlb is not force mode, in this case, system - * heap should limit largest allocation. - * - * FIX: fix the orders[] as a workaround. - */ - if (swiotlb_max_segment()) { - unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE; - int max_order = MAX_ORDER; - int i; - - max_size = max_t(unsigned int, max_size, PAGE_SIZE) >> PAGE_SHIFT; - max_order = min(max_order, ilog2(max_size)); - for (i = 0; i < NUM_ORDERS; i++) { - if (max_order < orders[i]) - orders[i] = max_order; - pr_info("system_heap: orders[%d] = %u\n", i, orders[i]); - } - } for (i = 0; i < NUM_ORDERS; i++) { pools[i] = dmabuf_page_pool_create(order_flags[i], orders[i]); @@ -767,19 +588,6 @@ static int system_heap_create(void) } } - for (i = 0; i < NUM_ORDERS; i++) { - dma32_pools[i] = dmabuf_page_pool_create(order_flags[i] | GFP_DMA32, orders[i]); - - if (!dma32_pools[i]) { - int j; - - pr_err("%s: page dma32 pool creation failed!\n", __func__); - for (j = 0; j < i; j++) - dmabuf_page_pool_destroy(dma32_pools[j]); - goto err_dma32_pool; - } - } - exp_info.name = "system"; exp_info.ops = &system_heap_ops; exp_info.priv = NULL; @@ -788,14 +596,6 @@ static int system_heap_create(void) if (IS_ERR(sys_heap)) return PTR_ERR(sys_heap); - exp_info.name = "system-dma32"; - exp_info.ops = &system_heap_ops; - exp_info.priv = NULL; - - sys_dma32_heap = dma_heap_add(&exp_info); - if (IS_ERR(sys_dma32_heap)) - return PTR_ERR(sys_dma32_heap); - exp_info.name = "system-uncached"; exp_info.ops = &system_uncached_heap_ops; exp_info.priv = NULL; @@ -808,34 +608,10 @@ static int system_heap_create(void) if (err) return err; - exp_info.name = "system-uncached-dma32"; - exp_info.ops = &system_uncached_heap_ops; - exp_info.priv = NULL; - - sys_uncached_dma32_heap = dma_heap_add(&exp_info); - if (IS_ERR(sys_uncached_dma32_heap)) - return PTR_ERR(sys_uncached_dma32_heap); - - err = set_heap_dev_dma(dma_heap_get_dev(sys_uncached_dma32_heap)); - if (err) - return err; - dma_coerce_mask_and_coherent(dma_heap_get_dev(sys_uncached_dma32_heap), DMA_BIT_MASK(32)); - mb(); /* make sure we only set allocate after dma_mask is set */ system_uncached_heap_ops.allocate = system_uncached_heap_allocate; - ddr_map_info = sip_smc_get_dram_map(); - if (ddr_map_info) { - bank_bit_first = ddr_map_info->bank_bit_first; - bank_bit_mask = ddr_map_info->bank_bit_mask; - } - return 0; -err_dma32_pool: - for (i = 0; i < NUM_ORDERS; i++) - dmabuf_page_pool_destroy(pools[i]); - - return -ENOMEM; } module_init(system_heap_create); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index 36d81c7efec5..e4e16ba551be 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -777,20 +777,27 @@ static int rockchip_gpio_probe(struct platform_device *pdev) } } - while (!list_empty(&bank->deferred_output)) { - struct rockchip_pin_output_deferred *cfg; + while (!list_empty(&bank->deferred_pins)) { + struct rockchip_pin_deferred *cfg; - cfg = list_first_entry(&bank->deferred_output, - struct rockchip_pin_output_deferred, head); + cfg = list_first_entry(&bank->deferred_pins, + struct rockchip_pin_deferred, head); if (!cfg) break; list_del(&cfg->head); - ret = rockchip_gpio_direction_output(&bank->gpio_chip, cfg->pin, cfg->arg); - if (ret) - dev_warn(dev, "setting output pin %u to %u failed\n", cfg->pin, cfg->arg); - + switch (cfg->param) { + case PIN_CONFIG_OUTPUT: + ret = rockchip_gpio_direction_output(&bank->gpio_chip, cfg->pin, cfg->arg); + if (ret) + dev_warn(dev, "setting output pin %u to %u failed\n", cfg->pin, + cfg->arg); + break; + default: + dev_warn(dev, "unknown deferred config param %d\n", cfg->param); + break; + } kfree(cfg); } diff --git a/drivers/gpu/arm/bifrost/Kbuild b/drivers/gpu/arm/bifrost/Kbuild index 7172468829c9..a7f0ba0da1e8 100644 --- a/drivers/gpu/arm/bifrost/Kbuild +++ b/drivers/gpu/arm/bifrost/Kbuild @@ -71,7 +71,7 @@ endif # # Driver version string which is returned to userspace via an ioctl -MALI_RELEASE_NAME ?= '"g12p0-01eac0"' +MALI_RELEASE_NAME ?= '"g13p0-01eac0"' # Set up defaults if not defined by build system ifeq ($(CONFIG_MALI_BIFROST_DEBUG), y) MALI_UNIT_TEST = 1 diff --git a/drivers/gpu/arm/bifrost/Kconfig b/drivers/gpu/arm/bifrost/Kconfig index 72f4c19fc07a..54f083dbad27 100644 --- a/drivers/gpu/arm/bifrost/Kconfig +++ b/drivers/gpu/arm/bifrost/Kconfig @@ -214,6 +214,20 @@ config MALI_GEM5_BUILD comment "Debug options" depends on MALI_BIFROST && MALI_BIFROST_EXPERT +config MALI_FW_CORE_DUMP + bool "Enable support for FW core dump" + depends on MALI_BIFROST && MALI_BIFROST_EXPERT && MALI_CSF_SUPPORT + default n + help + Adds ability to request firmware core dump + + Example: + * To explicitly request core dump: + echo 1 >/sys/kernel/debug/mali0/fw_core_dump + * To output current core dump (after explicitly requesting a core dump, + or kernel driver reported an internal firmware error): + cat /sys/kernel/debug/mali0/fw_core_dump + config MALI_BIFROST_DEBUG bool "Enable debug build" depends on MALI_BIFROST && MALI_BIFROST_EXPERT diff --git a/drivers/gpu/arm/bifrost/Makefile b/drivers/gpu/arm/bifrost/Makefile index 5233e4c1e26b..623177ed26fb 100644 --- a/drivers/gpu/arm/bifrost/Makefile +++ b/drivers/gpu/arm/bifrost/Makefile @@ -130,16 +130,19 @@ ifeq ($(CONFIG_MALI_BIFROST),m) ifeq ($(CONFIG_MALI_KUTF), y) CONFIG_MALI_KUTF_IRQ_TEST ?= y CONFIG_MALI_KUTF_CLK_RATE_TRACE ?= y + CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST ?= y else # Prevent misuse when CONFIG_MALI_KUTF=n CONFIG_MALI_KUTF_IRQ_TEST = n CONFIG_MALI_KUTF_CLK_RATE_TRACE = n + CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST = n endif else # Prevent misuse when CONFIG_MALI_BIFROST_DEBUG=n CONFIG_MALI_KUTF = n CONFIG_MALI_KUTF_IRQ_TEST = n CONFIG_MALI_KUTF_CLK_RATE_TRACE = n + CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST = n endif else # Prevent misuse when CONFIG_MALI_BIFROST=n @@ -149,6 +152,7 @@ else CONFIG_MALI_KUTF = n CONFIG_MALI_KUTF_IRQ_TEST = n CONFIG_MALI_KUTF_CLK_RATE_TRACE = n + CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST = n endif # All Mali CONFIG should be listed here @@ -189,6 +193,7 @@ CONFIGS := \ CONFIG_MALI_KUTF \ CONFIG_MALI_KUTF_IRQ_TEST \ CONFIG_MALI_KUTF_CLK_RATE_TRACE \ + CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST \ CONFIG_MALI_XEN diff --git a/drivers/gpu/arm/bifrost/Mconfig b/drivers/gpu/arm/bifrost/Mconfig index f43da8ba28f2..fd81ac44af3d 100644 --- a/drivers/gpu/arm/bifrost/Mconfig +++ b/drivers/gpu/arm/bifrost/Mconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2012-2021 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2012-2022 ARM Limited. All rights reserved. # # This program is free software and is provided to you under the terms of the # GNU General Public License version 2 as published by the Free Software @@ -65,8 +65,7 @@ config MALI_CSF_SUPPORT config MALI_BIFROST_DEVFREQ bool "Enable devfreq support for Mali" depends on MALI_BIFROST - default y if PLATFORM_JUNO - default y if PLATFORM_CUSTOM + default y help Support devfreq for Mali. @@ -192,6 +191,20 @@ config MALI_CORESTACK If unsure, say N. +config MALI_FW_CORE_DUMP + bool "Enable support for FW core dump" + depends on MALI_BIFROST && MALI_BIFROST_EXPERT && MALI_CSF_SUPPORT + default n + help + Adds ability to request firmware core dump + + Example: + * To explicitly request core dump: + echo 1 >/sys/kernel/debug/mali0/fw_core_dump + * To output current core dump (after explicitly requesting a core dump, + or kernel driver reported an internal firmware error): + cat /sys/kernel/debug/mali0/fw_core_dump + choice prompt "Error injection level" depends on MALI_BIFROST && MALI_BIFROST_EXPERT diff --git a/drivers/gpu/arm/bifrost/arbiter/mali_kbase_arbiter_pm.c b/drivers/gpu/arm/bifrost/arbiter/mali_kbase_arbiter_pm.c index 6079dd87e067..667552c561fb 100644 --- a/drivers/gpu/arm/bifrost/arbiter/mali_kbase_arbiter_pm.c +++ b/drivers/gpu/arm/bifrost/arbiter/mali_kbase_arbiter_pm.c @@ -955,7 +955,6 @@ static inline bool kbase_arbiter_pm_vm_gpu_assigned_lockheld( int kbase_arbiter_pm_ctx_active_handle_suspend(struct kbase_device *kbdev, enum kbase_pm_suspend_handler suspend_handler) { - struct kbasep_js_device_data *js_devdata = &kbdev->js_data; struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state; int res = 0; @@ -1008,11 +1007,9 @@ int kbase_arbiter_pm_ctx_active_handle_suspend(struct kbase_device *kbdev, /* Need to synchronously wait for GPU assignment */ atomic_inc(&kbdev->pm.gpu_users_waiting); mutex_unlock(&arb_vm_state->vm_state_lock); - mutex_unlock(&kbdev->pm.lock); - mutex_unlock(&js_devdata->runpool_mutex); + kbase_pm_unlock(kbdev); kbase_arbiter_pm_vm_wait_gpu_assignment(kbdev); - mutex_lock(&js_devdata->runpool_mutex); - mutex_lock(&kbdev->pm.lock); + kbase_pm_lock(kbdev); mutex_lock(&arb_vm_state->vm_state_lock); atomic_dec(&kbdev->pm.gpu_users_waiting); } diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c index 0590b13c1b24..9ca764488e9d 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c @@ -824,12 +824,6 @@ int kbase_devfreq_init(struct kbase_device *kbdev) goto ipa_init_failed; } } else { - err = kbase_ipa_init(kbdev); - if (err) { - dev_err(kbdev->dev, "IPA initialization failed\n"); - goto ipa_init_failed; - } - kbdev->devfreq_cooling = of_devfreq_cooling_register_power( kbdev->dev->of_node, kbdev->devfreq, diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_gpuprops_backend.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_gpuprops_backend.c index 0ea14bc89da4..10e92ec94d3a 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_gpuprops_backend.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_gpuprops_backend.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -40,19 +40,7 @@ int kbase_backend_gpuprops_get(struct kbase_device *kbdev, registers.l2_features = kbase_reg_read(kbdev, GPU_CONTROL_REG(L2_FEATURES)); - registers.core_features = 0; -#if !MALI_USE_CSF - /* TGOx */ - registers.core_features = kbase_reg_read(kbdev, - GPU_CONTROL_REG(CORE_FEATURES)); -#else /* !MALI_USE_CSF */ - if (!(((registers.gpu_id & GPU_ID2_PRODUCT_MODEL) == - GPU_ID2_PRODUCT_TDUX) || - ((registers.gpu_id & GPU_ID2_PRODUCT_MODEL) == - GPU_ID2_PRODUCT_TODX))) - registers.core_features = - kbase_reg_read(kbdev, GPU_CONTROL_REG(CORE_FEATURES)); -#endif /* MALI_USE_CSF */ + registers.tiler_features = kbase_reg_read(kbdev, GPU_CONTROL_REG(TILER_FEATURES)); registers.mem_features = kbase_reg_read(kbdev, @@ -170,6 +158,11 @@ int kbase_backend_gpuprops_get_features(struct kbase_device *kbdev, regdump->coherency_features = coherency_features; + if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_CORE_FEATURES)) + regdump->core_features = kbase_reg_read(kbdev, GPU_CONTROL_REG(CORE_FEATURES)); + else + regdump->core_features = 0; + kbase_pm_register_access_disable(kbdev); return error; diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_hw.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_hw.c index 0d2683d73efd..08de02495a4a 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_hw.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_hw.c @@ -191,9 +191,7 @@ static u64 select_job_chain(struct kbase_jd_atom *katom) return jc; } -void kbase_job_hw_submit(struct kbase_device *kbdev, - struct kbase_jd_atom *katom, - int js) +int kbase_job_hw_submit(struct kbase_device *kbdev, struct kbase_jd_atom *katom, int js) { struct kbase_context *kctx; u32 cfg; @@ -202,13 +200,13 @@ void kbase_job_hw_submit(struct kbase_device *kbdev, struct slot_rb *ptr_slot_rb = &kbdev->hwaccess.backend.slot_rb[js]; lockdep_assert_held(&kbdev->hwaccess_lock); - KBASE_DEBUG_ASSERT(kbdev); - KBASE_DEBUG_ASSERT(katom); kctx = katom->kctx; /* Command register must be available */ - KBASE_DEBUG_ASSERT(kbasep_jm_is_js_free(kbdev, js, kctx)); + if (WARN(!kbasep_jm_is_js_free(kbdev, js, kctx), + "Attempting to assign to occupied slot %d in kctx %pK\n", js, (void *)kctx)) + return -EPERM; dev_dbg(kctx->kbdev->dev, "Write JS_HEAD_NEXT 0x%llx for atom %pK\n", jc_head, (void *)katom); @@ -329,6 +327,8 @@ void kbase_job_hw_submit(struct kbase_device *kbdev, kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT), JS_COMMAND_START); + + return 0; } /** @@ -393,8 +393,6 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done) lockdep_assert_held(&kbdev->hwaccess_lock); - KBASE_DEBUG_ASSERT(kbdev); - KBASE_KTRACE_ADD_JM(kbdev, JM_IRQ, NULL, NULL, 0, done); end_timestamp = ktime_get_raw(); @@ -409,7 +407,8 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done) * numbered interrupts before the higher numbered ones. */ i = ffs(finished) - 1; - KBASE_DEBUG_ASSERT(i >= 0); + if (WARN(i < 0, "%s: called without receiving any interrupts\n", __func__)) + break; do { int nr_done; @@ -619,7 +618,7 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev, u64 job_in_head_before; u32 status_reg_after; - KBASE_DEBUG_ASSERT(!(action & (~JS_COMMAND_MASK))); + WARN_ON(action & (~JS_COMMAND_MASK)); /* Check the head pointer */ job_in_head_before = ((u64) kbase_reg_read(kbdev, @@ -697,7 +696,8 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev, KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP_1, head_kctx, head, head->jc, js); break; default: - BUG(); + WARN(1, "Unknown action %d on atom %pK in kctx %pK\n", action, + (void *)target_katom, (void *)target_katom->kctx); break; } } else { @@ -726,7 +726,8 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev, KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP_1, NULL, NULL, 0, js); break; default: - BUG(); + WARN(1, "Unknown action %d on atom %pK in kctx %pK\n", action, + (void *)target_katom, (void *)target_katom->kctx); break; } } @@ -752,9 +753,7 @@ void kbase_job_slot_ctx_priority_check_locked(struct kbase_context *kctx, int i; bool stop_sent = false; - KBASE_DEBUG_ASSERT(kctx != NULL); kbdev = kctx->kbdev; - KBASE_DEBUG_ASSERT(kbdev != NULL); lockdep_assert_held(&kbdev->hwaccess_lock); @@ -934,7 +933,11 @@ void kbase_job_slot_softstop_swflags(struct kbase_device *kbdev, int js, dev_dbg(kbdev->dev, "Soft-stop atom %pK with flags 0x%x (s:%d)\n", target_katom, sw_flags, js); - KBASE_DEBUG_ASSERT(!(sw_flags & JS_COMMAND_MASK)); + if (sw_flags & JS_COMMAND_MASK) { + WARN(true, "Atom %pK in kctx %pK received non-NOP flags %d\n", (void *)target_katom, + target_katom ? (void *)target_katom->kctx : NULL, sw_flags); + sw_flags &= ~((u32)JS_COMMAND_MASK); + } kbase_backend_soft_hard_stop_slot(kbdev, NULL, js, target_katom, JS_COMMAND_SOFT_STOP | sw_flags); } @@ -1059,18 +1062,18 @@ static void kbasep_reset_timeout_worker(struct work_struct *data) bool silent = false; u32 max_loops = KBASE_CLEAN_CACHE_MAX_LOOPS; - KBASE_DEBUG_ASSERT(data); - kbdev = container_of(data, struct kbase_device, hwaccess.backend.reset_work); - KBASE_DEBUG_ASSERT(kbdev); js_devdata = &kbdev->js_data; if (atomic_read(&kbdev->hwaccess.backend.reset_gpu) == KBASE_RESET_GPU_SILENT) silent = true; + if (kbase_is_quick_reset_enabled(kbdev)) + silent = true; + KBASE_KTRACE_ADD_JM(kbdev, JM_BEGIN_RESET_WORKER, NULL, NULL, 0u, 0); /* Disable GPU hardware counters. @@ -1099,7 +1102,7 @@ static void kbasep_reset_timeout_worker(struct work_struct *data) return; } - KBASE_DEBUG_ASSERT(kbdev->irq_reset_flush == false); + WARN(kbdev->irq_reset_flush, "%s: GPU reset already in flight\n", __func__); spin_lock_irqsave(&kbdev->hwaccess_lock, flags); spin_lock(&kbdev->mmu_mask_change); @@ -1140,7 +1143,8 @@ static void kbasep_reset_timeout_worker(struct work_struct *data) mutex_lock(&kbdev->pm.lock); /* We hold the pm lock, so there ought to be a current policy */ - KBASE_DEBUG_ASSERT(kbdev->pm.backend.pm_current_policy); + if (unlikely(!kbdev->pm.backend.pm_current_policy)) + dev_warn(kbdev->dev, "No power policy set!"); /* All slot have been soft-stopped and we've waited * SOFT_STOP_RESET_TIMEOUT for the slots to clear, at this point we @@ -1237,8 +1241,6 @@ static enum hrtimer_restart kbasep_reset_timer_callback(struct hrtimer *timer) struct kbase_device *kbdev = container_of(timer, struct kbase_device, hwaccess.backend.reset_timer); - KBASE_DEBUG_ASSERT(kbdev); - /* Reset still pending? */ if (atomic_cmpxchg(&kbdev->hwaccess.backend.reset_gpu, KBASE_RESET_GPU_COMMITTED, KBASE_RESET_GPU_HAPPENING) == @@ -1259,8 +1261,6 @@ static void kbasep_try_reset_gpu_early_locked(struct kbase_device *kbdev) int i; int pending_jobs = 0; - KBASE_DEBUG_ASSERT(kbdev); - /* Count the number of jobs */ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++) pending_jobs += kbase_backend_nr_atoms_submitted(kbdev, i); @@ -1318,8 +1318,6 @@ bool kbase_prepare_to_reset_gpu_locked(struct kbase_device *kbdev, { int i; - KBASE_DEBUG_ASSERT(kbdev); - #ifdef CONFIG_MALI_ARBITER_SUPPORT if (kbase_pm_is_gpu_lost(kbdev)) { /* GPU access has been removed, reset will be done by @@ -1373,18 +1371,17 @@ KBASE_EXPORT_TEST_API(kbase_prepare_to_reset_gpu); */ void kbase_reset_gpu(struct kbase_device *kbdev) { - KBASE_DEBUG_ASSERT(kbdev); - /* Note this is an assert/atomic_set because it is a software issue for * a race to be occurring here */ - KBASE_DEBUG_ASSERT(atomic_read(&kbdev->hwaccess.backend.reset_gpu) == - KBASE_RESET_GPU_PREPARED); + if (WARN_ON(atomic_read(&kbdev->hwaccess.backend.reset_gpu) != KBASE_RESET_GPU_PREPARED)) + return; atomic_set(&kbdev->hwaccess.backend.reset_gpu, KBASE_RESET_GPU_COMMITTED); - dev_err(kbdev->dev, "Preparing to soft-reset GPU: Waiting (upto %d ms) for all jobs to complete soft-stop\n", - kbdev->reset_timeout_ms); + if (!kbase_is_quick_reset_enabled(kbdev)) + dev_err(kbdev->dev, "Preparing to soft-reset GPU: Waiting (upto %d ms) for all jobs to complete soft-stop\n", + kbdev->reset_timeout_ms); hrtimer_start(&kbdev->hwaccess.backend.reset_timer, HR_TIMER_DELAY_MSEC(kbdev->reset_timeout_ms), @@ -1397,18 +1394,17 @@ KBASE_EXPORT_TEST_API(kbase_reset_gpu); void kbase_reset_gpu_locked(struct kbase_device *kbdev) { - KBASE_DEBUG_ASSERT(kbdev); - /* Note this is an assert/atomic_set because it is a software issue for * a race to be occurring here */ - KBASE_DEBUG_ASSERT(atomic_read(&kbdev->hwaccess.backend.reset_gpu) == - KBASE_RESET_GPU_PREPARED); + if (WARN_ON(atomic_read(&kbdev->hwaccess.backend.reset_gpu) != KBASE_RESET_GPU_PREPARED)) + return; atomic_set(&kbdev->hwaccess.backend.reset_gpu, KBASE_RESET_GPU_COMMITTED); - dev_err(kbdev->dev, "Preparing to soft-reset GPU: Waiting (upto %d ms) for all jobs to complete soft-stop\n", - kbdev->reset_timeout_ms); + if (!kbase_is_quick_reset_enabled(kbdev)) + dev_err(kbdev->dev, "Preparing to soft-reset GPU: Waiting (upto %d ms) for all jobs to complete soft-stop\n", + kbdev->reset_timeout_ms); hrtimer_start(&kbdev->hwaccess.backend.reset_timer, HR_TIMER_DELAY_MSEC(kbdev->reset_timeout_ms), HRTIMER_MODE_REL); diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_internal.h b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_internal.h index 1039e851f959..1ebb8434046c 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_internal.h +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_internal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2011-2016, 2018-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2016, 2018-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -76,7 +76,6 @@ static inline int kbasep_jm_is_js_free(struct kbase_device *kbdev, int js, } #endif - /** * kbase_job_hw_submit() - Submit a job to the GPU * @kbdev: Device pointer @@ -88,10 +87,10 @@ static inline int kbasep_jm_is_js_free(struct kbase_device *kbdev, int js, * * The following locking conditions are made on the caller: * - it must hold the hwaccess_lock + * + * Return: 0 if the job was successfully submitted to hardware, an error otherwise. */ -void kbase_job_hw_submit(struct kbase_device *kbdev, - struct kbase_jd_atom *katom, - int js); +int kbase_job_hw_submit(struct kbase_device *kbdev, struct kbase_jd_atom *katom, int js); #if !MALI_USE_CSF /** diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_rb.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_rb.c index c49c2cb17085..9960beb2e9b4 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_rb.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_jm_rb.c @@ -347,16 +347,35 @@ static void kbase_gpu_release_atom(struct kbase_device *kbdev, katom->protected_state.exit != KBASE_ATOM_EXIT_PROTECTED_CHECK) kbdev->protected_mode_transition = false; + + /* If the atom is at KBASE_ATOM_ENTER_PROTECTED_HWCNT state, it means + * one of two events prevented it from progressing to the next state and + * ultimately reach protected mode: + * - hwcnts were enabled, and the atom had to schedule a worker to + * disable them. + * - the hwcnts were already disabled, but some other error occurred. + * In the first case, if the worker has not yet completed + * (kbdev->protected_mode_hwcnt_disabled == false), we need to re-enable + * them and signal to the worker they have already been enabled + */ + if (kbase_jd_katom_is_protected(katom) && + (katom->protected_state.enter == KBASE_ATOM_ENTER_PROTECTED_HWCNT)) { + kbdev->protected_mode_hwcnt_desired = true; + if (kbdev->protected_mode_hwcnt_disabled) { + kbase_hwcnt_context_enable(kbdev->hwcnt_gpu_ctx); + kbdev->protected_mode_hwcnt_disabled = false; + } + } + /* If the atom has suspended hwcnt but has not yet entered * protected mode, then resume hwcnt now. If the GPU is now in * protected mode then hwcnt will be resumed by GPU reset so * don't resume it here. */ if (kbase_jd_katom_is_protected(katom) && - ((katom->protected_state.enter == - KBASE_ATOM_ENTER_PROTECTED_IDLE_L2) || - (katom->protected_state.enter == - KBASE_ATOM_ENTER_PROTECTED_SET_COHERENCY))) { + ((katom->protected_state.enter == KBASE_ATOM_ENTER_PROTECTED_IDLE_L2) || + (katom->protected_state.enter == KBASE_ATOM_ENTER_PROTECTED_SET_COHERENCY) || + (katom->protected_state.enter == KBASE_ATOM_ENTER_PROTECTED_FINISHED))) { WARN_ON(!kbdev->protected_mode_hwcnt_disabled); kbdev->protected_mode_hwcnt_desired = true; if (kbdev->protected_mode_hwcnt_disabled) { @@ -507,17 +526,14 @@ static int kbase_jm_protected_entry(struct kbase_device *kbdev, KBASE_TLSTREAM_AUX_PROTECTED_ENTER_END(kbdev, kbdev); if (err) { /* - * Failed to switch into protected mode, resume - * GPU hwcnt and fail atom. + * Failed to switch into protected mode. + * + * At this point we expect: + * katom->gpu_rb_state = KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION && + * katom->protected_state.enter = KBASE_ATOM_ENTER_PROTECTED_FINISHED + * ==> + * kbdev->protected_mode_hwcnt_disabled = false */ - WARN_ON(!kbdev->protected_mode_hwcnt_disabled); - kbdev->protected_mode_hwcnt_desired = true; - if (kbdev->protected_mode_hwcnt_disabled) { - kbase_hwcnt_context_enable( - kbdev->hwcnt_gpu_ctx); - kbdev->protected_mode_hwcnt_disabled = false; - } - katom[idx]->event_code = BASE_JD_EVENT_JOB_INVALID; kbase_gpu_mark_atom_for_return(kbdev, katom[idx]); /* @@ -537,12 +553,9 @@ static int kbase_jm_protected_entry(struct kbase_device *kbdev, /* * Protected mode sanity checks. */ - KBASE_DEBUG_ASSERT_MSG( - kbase_jd_katom_is_protected(katom[idx]) == - kbase_gpu_in_protected_mode(kbdev), - "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", - kbase_jd_katom_is_protected(katom[idx]), - kbase_gpu_in_protected_mode(kbdev)); + WARN(kbase_jd_katom_is_protected(katom[idx]) != kbase_gpu_in_protected_mode(kbdev), + "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", + kbase_jd_katom_is_protected(katom[idx]), kbase_gpu_in_protected_mode(kbdev)); katom[idx]->gpu_rb_state = KBASE_ATOM_GPU_RB_READY; @@ -952,18 +965,6 @@ void kbase_backend_slot_update(struct kbase_device *kbdev) cores_ready = kbase_pm_cores_requested(kbdev, true); - if (katom[idx]->event_code == - BASE_JD_EVENT_PM_EVENT) { - KBASE_KTRACE_ADD_JM_SLOT_INFO( - kbdev, JM_MARK_FOR_RETURN_TO_JS, - katom[idx]->kctx, katom[idx], - katom[idx]->jc, js, - katom[idx]->event_code); - katom[idx]->gpu_rb_state = - KBASE_ATOM_GPU_RB_RETURN_TO_JS; - break; - } - if (!cores_ready) break; @@ -1012,9 +1013,10 @@ void kbase_backend_slot_update(struct kbase_device *kbdev) kbase_pm_request_gpu_cycle_counter_l2_is_on( kbdev); - kbase_job_hw_submit(kbdev, katom[idx], js); - katom[idx]->gpu_rb_state = - KBASE_ATOM_GPU_RB_SUBMITTED; + if (!kbase_job_hw_submit(kbdev, katom[idx], js)) + katom[idx]->gpu_rb_state = KBASE_ATOM_GPU_RB_SUBMITTED; + else + break; /* ***TRANSITION TO HIGHER STATE*** */ fallthrough; @@ -1407,14 +1409,14 @@ void kbase_backend_reset(struct kbase_device *kbdev, ktime_t *end_timestamp) if (katom->protected_state.exit == KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT) { /* protected mode sanity checks */ - KBASE_DEBUG_ASSERT_MSG( - kbase_jd_katom_is_protected(katom) == kbase_gpu_in_protected_mode(kbdev), - "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", - kbase_jd_katom_is_protected(katom), kbase_gpu_in_protected_mode(kbdev)); - KBASE_DEBUG_ASSERT_MSG( - (kbase_jd_katom_is_protected(katom) && js == 0) || - !kbase_jd_katom_is_protected(katom), - "Protected atom on JS%d not supported", js); + WARN(kbase_jd_katom_is_protected(katom) != + kbase_gpu_in_protected_mode(kbdev), + "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", + kbase_jd_katom_is_protected(katom), + kbase_gpu_in_protected_mode(kbdev)); + WARN(!(kbase_jd_katom_is_protected(katom) && js == 0) && + kbase_jd_katom_is_protected(katom), + "Protected atom on JS%d not supported", js); } if ((katom->gpu_rb_state < KBASE_ATOM_GPU_RB_SUBMITTED) && !kbase_ctx_flag(katom->kctx, KCTX_DYING)) @@ -1805,11 +1807,9 @@ void kbase_backend_complete_wq_post_sched(struct kbase_device *kbdev, base_jd_core_req core_req) { if (!kbdev->pm.active_count) { - mutex_lock(&kbdev->js_data.runpool_mutex); - mutex_lock(&kbdev->pm.lock); + kbase_pm_lock(kbdev); kbase_pm_update_active(kbdev); - mutex_unlock(&kbdev->pm.lock); - mutex_unlock(&kbdev->js_data.runpool_mutex); + kbase_pm_unlock(kbdev); } } diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_js_backend.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_js_backend.c index ea4c4d0cfe73..a2f824da5e04 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_js_backend.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_js_backend.c @@ -131,10 +131,15 @@ static enum hrtimer_restart timer_callback(struct hrtimer *timer) } else { soft_stop_ticks = js_devdata->soft_stop_ticks; + if (kbase_is_quick_reset_enabled(kbdev)) { + hard_stop_ticks = 2; + gpu_reset_ticks = 3; + } else { hard_stop_ticks = js_devdata->hard_stop_ticks_ss; gpu_reset_ticks = js_devdata->gpu_reset_ticks_ss; + } } /* If timeouts have been changed then ensure @@ -196,9 +201,10 @@ static enum hrtimer_restart timer_callback(struct hrtimer *timer) int ms = js_devdata->scheduling_period_ns / 1000000u; - dev_warn(kbdev->dev, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)", - (unsigned long)ticks, - (unsigned long)ms); + if (!kbase_is_quick_reset_enabled(kbdev)) + dev_warn(kbdev->dev, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)", + (unsigned long)ticks, + (unsigned long)ms); kbase_job_slot_hardstop(atom->kctx, s, atom); #endif @@ -255,7 +261,11 @@ static enum hrtimer_restart timer_callback(struct hrtimer *timer) } } if (reset_needed) { - dev_err(kbdev->dev, "JS: Job has been on the GPU for too long (JS_RESET_TICKS_SS/DUMPING timeout hit). Issuing GPU soft-reset to resolve."); + if (kbase_is_quick_reset_enabled(kbdev)) + dev_err(kbdev->dev, "quick reset"); + else { + dev_err(kbdev->dev, "JS: Job has been on the GPU for too long (JS_RESET_TICKS_SS/DUMPING timeout hit). Issuing GPU soft-reset to resolve."); + } if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_NONE)) kbase_reset_gpu_locked(kbdev); diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.c index 12c6bb791e98..e4f4b2455925 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.c @@ -1066,7 +1066,7 @@ static void midgard_model_get_outputs(void *h) hw_error_status.gpu_error_irq || #if !MALI_USE_CSF dummy->prfcnt_sample_completed || -#endif /* !MALI_USE_CSF */ +#endif (dummy->clean_caches_completed && dummy->clean_caches_completed_irq_enabled)) gpu_device_raise_irq(dummy, GPU_DUMMY_GPU_IRQ); @@ -1247,7 +1247,7 @@ u8 midgard_model_write_reg(void *h, u32 addr, u32 value) if (value & (1 << 17)) dummy->clean_caches_completed = false; -#if !MALI_USE_CSF +#if !MALI_USE_CSF if (value & PRFCNT_SAMPLE_COMPLETED) dummy->prfcnt_sample_completed = 0; #endif /* !MALI_USE_CSF */ @@ -1274,7 +1274,7 @@ u8 midgard_model_write_reg(void *h, u32 addr, u32 value) pr_debug("clean caches requested"); dummy->clean_caches_completed = true; break; -#if !MALI_USE_CSF +#if !MALI_USE_CSF case GPU_COMMAND_PRFCNT_SAMPLE: midgard_model_dump_prfcnt(); dummy->prfcnt_sample_completed = 1; @@ -1545,7 +1545,8 @@ u8 midgard_model_read_reg(void *h, u32 addr, u32 * const value) #endif /* !MALI_USE_CSF */ else if (addr == GPU_CONTROL_REG(GPU_IRQ_MASK)) { *value = (dummy->reset_completed_mask << 8) | - (dummy->power_changed_mask << 9) | (1 << 7) | 1; + ((dummy->clean_caches_completed_irq_enabled ? 1u : 0u) << 17) | + (dummy->power_changed_mask << 9) | (1 << 7) | 1; pr_debug("GPU_IRQ_MASK read %x", *value); } else if (addr == GPU_CONTROL_REG(GPU_IRQ_RAWSTAT)) { *value = (dummy->power_changed << 9) | (dummy->power_changed << 10) | diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_backend.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_backend.c index 90e580b906f3..df735d95de9f 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_backend.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_backend.c @@ -422,8 +422,7 @@ static void kbase_pm_l2_clock_slow(struct kbase_device *kbdev) return; /* Stop the metrics gathering framework */ - if (kbase_pm_metrics_is_active(kbdev)) - kbase_pm_metrics_stop(kbdev); + kbase_pm_metrics_stop(kbdev); /* Keep the current freq to restore it upon resume */ kbdev->previous_frequency = clk_get_rate(clk); diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_defs.h b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_defs.h index faacbb929818..75d99a30efc0 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_defs.h +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_defs.h @@ -144,7 +144,7 @@ struct kbasep_pm_metrics { * @initialized: tracks whether metrics_state has been initialized or not. * @timer: timer to regularly make DVFS decisions based on the power * management metrics. - * @timer_active: boolean indicating @timer is running + * @timer_state: atomic indicating current @timer state, on, off, or stopped. * @dvfs_last: values of the PM metrics from the last DVFS tick * @dvfs_diff: different between the current and previous PM metrics. */ @@ -168,7 +168,7 @@ struct kbasep_pm_metrics_state { #ifdef CONFIG_MALI_BIFROST_DVFS bool initialized; struct hrtimer timer; - bool timer_active; + atomic_t timer_state; struct kbasep_pm_metrics dvfs_last; struct kbasep_pm_metrics dvfs_diff; #endif diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_driver.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_driver.c index 794a6066a6eb..94b87ce7166b 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_driver.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_driver.c @@ -939,7 +939,7 @@ static int kbase_pm_mcu_update_state(struct kbase_device *kbdev) case KBASE_MCU_ON_PEND_HALT: if (kbase_csf_firmware_mcu_halted(kbdev)) { - KBASE_KTRACE_ADD(kbdev, MCU_HALTED, NULL, + KBASE_KTRACE_ADD(kbdev, CSF_FIRMWARE_MCU_HALTED, NULL, kbase_csf_ktrace_gpu_cycle_cnt(kbdev)); if (kbdev->csf.firmware_hctl_core_pwr) backend->mcu_state = @@ -986,7 +986,7 @@ static int kbase_pm_mcu_update_state(struct kbase_device *kbdev) case KBASE_MCU_ON_PEND_SLEEP: if (kbase_csf_firmware_is_mcu_in_sleep(kbdev)) { - KBASE_KTRACE_ADD(kbdev, MCU_IN_SLEEP, NULL, + KBASE_KTRACE_ADD(kbdev, CSF_FIRMWARE_MCU_SLEEP, NULL, kbase_csf_ktrace_gpu_cycle_cnt(kbdev)); backend->mcu_state = KBASE_MCU_IN_SLEEP; kbase_pm_enable_db_mirror_interrupt(kbdev); @@ -1108,13 +1108,24 @@ static bool can_power_down_l2(struct kbase_device *kbdev) #endif } +static bool need_tiler_control(struct kbase_device *kbdev) +{ +#if MALI_USE_CSF + if (kbase_pm_no_mcu_core_pwroff(kbdev)) + return true; + else + return false; +#else + return true; +#endif +} + static int kbase_pm_l2_update_state(struct kbase_device *kbdev) { struct kbase_pm_backend_data *backend = &kbdev->pm.backend; u64 l2_present = kbdev->gpu_props.curr_config.l2_present; -#if !MALI_USE_CSF u64 tiler_present = kbdev->gpu_props.props.raw_props.tiler_present; -#endif + bool l2_power_up_done; enum kbase_l2_core_state prev_state; lockdep_assert_held(&kbdev->hwaccess_lock); @@ -1125,24 +1136,18 @@ static int kbase_pm_l2_update_state(struct kbase_device *kbdev) KBASE_PM_CORE_L2); u64 l2_ready = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_L2); - -#if !MALI_USE_CSF - u64 tiler_trans = kbase_pm_get_trans_cores(kbdev, - KBASE_PM_CORE_TILER); - u64 tiler_ready = kbase_pm_get_ready_cores(kbdev, - KBASE_PM_CORE_TILER); -#endif +#ifdef CONFIG_MALI_ARBITER_SUPPORT + u64 tiler_trans = kbase_pm_get_trans_cores( + kbdev, KBASE_PM_CORE_TILER); + u64 tiler_ready = kbase_pm_get_ready_cores( + kbdev, KBASE_PM_CORE_TILER); /* * kbase_pm_get_ready_cores and kbase_pm_get_trans_cores * are vulnerable to corruption if gpu is lost */ if (kbase_is_gpu_removed(kbdev) -#ifdef CONFIG_MALI_ARBITER_SUPPORT || kbase_pm_is_gpu_lost(kbdev)) { -#else - ) { -#endif backend->shaders_state = KBASE_SHADERS_OFF_CORESTACK_OFF; backend->hwcnt_desired = false; @@ -1165,14 +1170,13 @@ static int kbase_pm_l2_update_state(struct kbase_device *kbdev) } break; } +#endif /* CONFIG_MALI_ARBITER_SUPPORT */ /* mask off ready from trans in case transitions finished * between the register reads */ l2_trans &= ~l2_ready; -#if !MALI_USE_CSF - tiler_trans &= ~tiler_ready; -#endif + prev_state = backend->l2_state; switch (backend->l2_state) { @@ -1184,13 +1188,21 @@ static int kbase_pm_l2_update_state(struct kbase_device *kbdev) */ kbase_pm_l2_config_override(kbdev); kbase_pbha_write_settings(kbdev); -#if !MALI_USE_CSF - /* L2 is required, power on. Powering on the - * tiler will also power the first L2 cache. - */ - kbase_pm_invoke(kbdev, KBASE_PM_CORE_TILER, - tiler_present, ACTION_PWRON); + /* If Host is controlling the power for shader + * cores, then it also needs to control the + * power for Tiler. + * Powering on the tiler will also power the + * L2 cache. + */ + if (need_tiler_control(kbdev)) { + kbase_pm_invoke(kbdev, KBASE_PM_CORE_TILER, tiler_present, + ACTION_PWRON); + } else { + kbase_pm_invoke(kbdev, KBASE_PM_CORE_L2, l2_present, + ACTION_PWRON); + } +#if !MALI_USE_CSF /* If we have more than one L2 cache then we * must power them on explicitly. */ @@ -1200,30 +1212,36 @@ static int kbase_pm_l2_update_state(struct kbase_device *kbdev) ACTION_PWRON); /* Clear backend slot submission kctx */ kbase_pm_l2_clear_backend_slot_submit_kctx(kbdev); -#else - /* With CSF firmware, Host driver doesn't need to - * handle power management with both shader and tiler cores. - * The CSF firmware will power up the cores appropriately. - * So only power the l2 cache explicitly. - */ - kbase_pm_invoke(kbdev, KBASE_PM_CORE_L2, - l2_present, ACTION_PWRON); #endif backend->l2_state = KBASE_L2_PEND_ON; } break; case KBASE_L2_PEND_ON: -#if !MALI_USE_CSF - if (!l2_trans && l2_ready == l2_present && !tiler_trans - && tiler_ready == tiler_present) { - KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER, NULL, - tiler_ready); -#else + l2_power_up_done = false; if (!l2_trans && l2_ready == l2_present) { - KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_L2, NULL, - l2_ready); + if (need_tiler_control(kbdev)) { +#ifndef CONFIG_MALI_ARBITER_SUPPORT + u64 tiler_trans = kbase_pm_get_trans_cores( + kbdev, KBASE_PM_CORE_TILER); + u64 tiler_ready = kbase_pm_get_ready_cores( + kbdev, KBASE_PM_CORE_TILER); #endif + + tiler_trans &= ~tiler_ready; + if (!tiler_trans && tiler_ready == tiler_present) { + KBASE_KTRACE_ADD(kbdev, + PM_CORES_CHANGE_AVAILABLE_TILER, + NULL, tiler_ready); + l2_power_up_done = true; + } + } else { + KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_L2, NULL, + l2_ready); + l2_power_up_done = true; + } + } + if (l2_power_up_done) { /* * Ensure snoops are enabled after L2 is powered * up. Note that kbase keeps track of the snoop @@ -2248,12 +2266,14 @@ int kbase_pm_wait_for_l2_powered(struct kbase_device *kbdev) /* Wait for cores */ #if KERNEL_VERSION(4, 13, 1) <= LINUX_VERSION_CODE - remaining = wait_event_killable_timeout( + remaining = wait_event_killable_timeout(kbdev->pm.backend.gpu_in_desired_state_wait, + kbase_pm_is_in_desired_state_with_l2_powered(kbdev), + timeout); #else remaining = wait_event_timeout( -#endif kbdev->pm.backend.gpu_in_desired_state_wait, kbase_pm_is_in_desired_state_with_l2_powered(kbdev), timeout); +#endif if (!remaining) { kbase_pm_timed_out(kbdev); diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c index 675cfd7d6baf..4cc2d50db586 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c @@ -49,27 +49,51 @@ #define GPU_ACTIVE_SCALING_FACTOR ((u64)1E9) #endif +/* + * Possible state transitions + * ON -> ON | OFF | STOPPED + * STOPPED -> ON | OFF + * OFF -> ON + * + * + * ┌─e─┐┌────────────f─────────────┐ + * │ v│ v + * └───ON ──a──> STOPPED ──b──> OFF + * ^^ │ │ + * │└──────c─────┘ │ + * │ │ + * └─────────────d─────────────┘ + * + * Transition effects: + * a. None + * b. Timer expires without restart + * c. Timer is not stopped, timer period is unaffected + * d. Timer must be restarted + * e. Callback is executed and the timer is restarted + * f. Timer is cancelled, or the callback is waited on if currently executing. This is called during + * tear-down and should not be subject to a race from an OFF->ON transition + */ +enum dvfs_metric_timer_state { TIMER_OFF, TIMER_STOPPED, TIMER_ON }; + #ifdef CONFIG_MALI_BIFROST_DVFS static enum hrtimer_restart dvfs_callback(struct hrtimer *timer) { - unsigned long flags; struct kbasep_pm_metrics_state *metrics; - KBASE_DEBUG_ASSERT(timer != NULL); + if (WARN_ON(!timer)) + return HRTIMER_NORESTART; metrics = container_of(timer, struct kbasep_pm_metrics_state, timer); + + /* Transition (b) to fully off if timer was stopped, don't restart the timer in this case */ + if (atomic_cmpxchg(&metrics->timer_state, TIMER_STOPPED, TIMER_OFF) != TIMER_ON) + return HRTIMER_NORESTART; + kbase_pm_get_dvfs_action(metrics->kbdev); - spin_lock_irqsave(&metrics->lock, flags); - - if (metrics->timer_active) - hrtimer_start(timer, - HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period), - HRTIMER_MODE_REL); - - spin_unlock_irqrestore(&metrics->lock, flags); - - return HRTIMER_NORESTART; + /* Set the new expiration time and restart (transition e) */ + hrtimer_forward_now(timer, HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period)); + return HRTIMER_RESTART; } #endif /* CONFIG_MALI_BIFROST_DVFS */ @@ -135,6 +159,7 @@ int kbasep_pm_metrics_init(struct kbase_device *kbdev) HRTIMER_MODE_REL); kbdev->pm.backend.metrics.timer.function = dvfs_callback; kbdev->pm.backend.metrics.initialized = true; + atomic_set(&kbdev->pm.backend.metrics.timer_state, TIMER_OFF); kbase_pm_metrics_start(kbdev); #endif /* CONFIG_MALI_BIFROST_DVFS */ @@ -153,16 +178,12 @@ KBASE_EXPORT_TEST_API(kbasep_pm_metrics_init); void kbasep_pm_metrics_term(struct kbase_device *kbdev) { #ifdef CONFIG_MALI_BIFROST_DVFS - unsigned long flags; - KBASE_DEBUG_ASSERT(kbdev != NULL); - spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); - kbdev->pm.backend.metrics.timer_active = false; - spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); - - hrtimer_cancel(&kbdev->pm.backend.metrics.timer); + /* Cancel the timer, and block if the callback is currently executing (transition f) */ kbdev->pm.backend.metrics.initialized = false; + atomic_set(&kbdev->pm.backend.metrics.timer_state, TIMER_OFF); + hrtimer_cancel(&kbdev->pm.backend.metrics.timer); #endif /* CONFIG_MALI_BIFROST_DVFS */ #if MALI_USE_CSF @@ -399,57 +420,33 @@ void kbase_pm_get_dvfs_action(struct kbase_device *kbdev) bool kbase_pm_metrics_is_active(struct kbase_device *kbdev) { - bool isactive; - unsigned long flags; - KBASE_DEBUG_ASSERT(kbdev != NULL); - spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); - isactive = kbdev->pm.backend.metrics.timer_active; - spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); - - return isactive; + return atomic_read(&kbdev->pm.backend.metrics.timer_state) == TIMER_ON; } KBASE_EXPORT_TEST_API(kbase_pm_metrics_is_active); void kbase_pm_metrics_start(struct kbase_device *kbdev) { - unsigned long flags; - bool update = true; + struct kbasep_pm_metrics_state *metrics = &kbdev->pm.backend.metrics; - if (unlikely(!kbdev->pm.backend.metrics.initialized)) + if (unlikely(!metrics->initialized)) return; - spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); - if (!kbdev->pm.backend.metrics.timer_active) - kbdev->pm.backend.metrics.timer_active = true; - else - update = false; - spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); - - if (update) - hrtimer_start(&kbdev->pm.backend.metrics.timer, - HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period), - HRTIMER_MODE_REL); + /* Transition to ON, from a stopped state (transition c) */ + if (atomic_xchg(&metrics->timer_state, TIMER_ON) == TIMER_OFF) + /* Start the timer only if it's been fully stopped (transition d)*/ + hrtimer_start(&metrics->timer, HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period), + HRTIMER_MODE_REL); } void kbase_pm_metrics_stop(struct kbase_device *kbdev) { - unsigned long flags; - bool update = true; - if (unlikely(!kbdev->pm.backend.metrics.initialized)) return; - spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); - if (kbdev->pm.backend.metrics.timer_active) - kbdev->pm.backend.metrics.timer_active = false; - else - update = false; - spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); - - if (update) - hrtimer_cancel(&kbdev->pm.backend.metrics.timer); + /* Timer is Stopped if its currently on (transition a) */ + atomic_cmpxchg(&kbdev->pm.backend.metrics.timer_state, TIMER_ON, TIMER_STOPPED); } diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_policy.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_policy.c index 306266cf075b..4788f04132c1 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_policy.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_policy.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -292,6 +292,8 @@ void kbase_pm_set_policy(struct kbase_device *kbdev, unsigned int new_policy_csf_pm_sched_flags; bool sched_suspend; bool reset_gpu = false; + bool reset_op_prevented = true; + struct kbase_csf_scheduler *scheduler = NULL; #endif KBASE_DEBUG_ASSERT(kbdev != NULL); @@ -300,9 +302,23 @@ void kbase_pm_set_policy(struct kbase_device *kbdev, KBASE_KTRACE_ADD(kbdev, PM_SET_POLICY, NULL, new_policy->id); #if MALI_USE_CSF + scheduler = &kbdev->csf.scheduler; + KBASE_DEBUG_ASSERT(scheduler != NULL); + /* Serialize calls on kbase_pm_set_policy() */ mutex_lock(&kbdev->pm.backend.policy_change_lock); + if (kbase_reset_gpu_prevent_and_wait(kbdev)) { + dev_warn(kbdev->dev, "Set PM policy failing to prevent gpu reset"); + reset_op_prevented = false; + } + + /* In case of CSF, the scheduler may be invoked to suspend. In that + * case, there is a risk that the L2 may be turned on by the time we + * check it here. So we hold the scheduler lock to avoid other operations + * interfering with the policy change and vice versa. + */ + mutex_lock(&scheduler->lock); spin_lock_irqsave(&kbdev->hwaccess_lock, flags); /* policy_change_clamp_state_to_off, when needed, is set/cleared in * this function, a very limited temporal scope for covering the @@ -315,24 +331,22 @@ void kbase_pm_set_policy(struct kbase_device *kbdev, * the always_on policy, reflected by the CSF_DYNAMIC_PM_CORE_KEEP_ON * flag bit. */ - sched_suspend = kbdev->csf.firmware_inited && + sched_suspend = reset_op_prevented && (CSF_DYNAMIC_PM_CORE_KEEP_ON & - (new_policy_csf_pm_sched_flags | - kbdev->pm.backend.csf_pm_sched_flags)); + (new_policy_csf_pm_sched_flags | kbdev->pm.backend.csf_pm_sched_flags)); spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); - if (sched_suspend) - kbase_csf_scheduler_pm_suspend(kbdev); + if (sched_suspend) { + /* Update the suspend flag to reflect actually suspend being done ! */ + sched_suspend = !kbase_csf_scheduler_pm_suspend_no_lock(kbdev); + /* Set the reset recovery flag if the required suspend failed */ + reset_gpu = !sched_suspend; + } spin_lock_irqsave(&kbdev->hwaccess_lock, flags); - /* If the current active policy is always_on, one needs to clamp the - * MCU/L2 for reaching off-state - */ - if (sched_suspend) - kbdev->pm.backend.policy_change_clamp_state_to_off = - CSF_DYNAMIC_PM_CORE_KEEP_ON & kbdev->pm.backend.csf_pm_sched_flags; + kbdev->pm.backend.policy_change_clamp_state_to_off = sched_suspend; kbase_pm_update_state(kbdev); spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); @@ -391,13 +405,19 @@ void kbase_pm_set_policy(struct kbase_device *kbdev, #if MALI_USE_CSF /* Reverse the suspension done */ + if (sched_suspend) + kbase_csf_scheduler_pm_resume_no_lock(kbdev); + mutex_unlock(&scheduler->lock); + + if (reset_op_prevented) + kbase_reset_gpu_allow(kbdev); + if (reset_gpu) { dev_warn(kbdev->dev, "Resorting to GPU reset for policy change\n"); if (kbase_prepare_to_reset_gpu(kbdev, RESET_FLAGS_NONE)) kbase_reset_gpu(kbdev); kbase_reset_gpu_wait(kbdev); - } else if (sched_suspend) - kbase_csf_scheduler_pm_resume(kbdev); + } mutex_unlock(&kbdev->pm.backend.policy_change_lock); #endif diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_time.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_time.c index e5f92cb34159..6bee1fff324a 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_time.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_time.c @@ -116,8 +116,6 @@ unsigned int kbase_get_timeout_ms(struct kbase_device *kbdev, */ u64 timeout, nr_cycles = 0; - /* Default value to mean 'no cap' */ - u64 timeout_cap = U64_MAX; u64 freq_khz; /* Only for debug messages, safe default in case it's mis-maintained */ @@ -144,16 +142,15 @@ unsigned int kbase_get_timeout_ms(struct kbase_device *kbdev, fallthrough; case CSF_FIRMWARE_TIMEOUT: selector_str = "CSF_FIRMWARE_TIMEOUT"; - nr_cycles = CSF_FIRMWARE_TIMEOUT_CYCLES; - /* Setup a cap on CSF FW timeout to FIRMWARE_PING_INTERVAL_MS, - * if calculated timeout exceeds it. This should be adapted to - * a direct timeout comparison once the - * FIRMWARE_PING_INTERVAL_MS option is added to this timeout - * function. A compile-time check such as BUILD_BUG_ON can also - * be done once the firmware ping interval in cycles becomes - * available as a macro. + /* Any FW timeout cannot be longer than the FW ping interval, after which + * the firmware_aliveness_monitor will be triggered and may restart + * the GPU if the FW is unresponsive. */ - timeout_cap = FIRMWARE_PING_INTERVAL_MS; + nr_cycles = min(CSF_FIRMWARE_PING_TIMEOUT_CYCLES, CSF_FIRMWARE_TIMEOUT_CYCLES); + + if (nr_cycles == CSF_FIRMWARE_PING_TIMEOUT_CYCLES) + dev_warn(kbdev->dev, "Capping %s to CSF_FIRMWARE_PING_TIMEOUT\n", + selector_str); break; case CSF_PM_TIMEOUT: selector_str = "CSF_PM_TIMEOUT"; @@ -171,6 +168,10 @@ unsigned int kbase_get_timeout_ms(struct kbase_device *kbdev, selector_str = "CSF_FIRMWARE_BOOT_TIMEOUT"; nr_cycles = CSF_FIRMWARE_BOOT_TIMEOUT_CYCLES; break; + case CSF_FIRMWARE_PING_TIMEOUT: + selector_str = "CSF_FIRMWARE_PING_TIMEOUT"; + nr_cycles = CSF_FIRMWARE_PING_TIMEOUT_CYCLES; + break; case CSF_SCHED_PROTM_PROGRESS_TIMEOUT: selector_str = "CSF_SCHED_PROTM_PROGRESS_TIMEOUT"; nr_cycles = kbase_csf_timeout_get(kbdev); @@ -179,11 +180,6 @@ unsigned int kbase_get_timeout_ms(struct kbase_device *kbdev, } timeout = div_u64(nr_cycles, freq_khz); - if (timeout > timeout_cap) { - dev_dbg(kbdev->dev, "Capped %s %llu to %llu", selector_str, - (unsigned long long)timeout, (unsigned long long)timeout_cap); - timeout = timeout_cap; - } if (WARN(timeout > UINT_MAX, "Capping excessive timeout %llums for %s at freq %llukHz to UINT_MAX ms", (unsigned long long)timeout, selector_str, (unsigned long long)freq_khz)) diff --git a/drivers/gpu/arm/bifrost/build.bp b/drivers/gpu/arm/bifrost/build.bp index db02dd2e0052..977d13961786 100644 --- a/drivers/gpu/arm/bifrost/build.bp +++ b/drivers/gpu/arm/bifrost/build.bp @@ -139,6 +139,9 @@ bob_defaults { platform_is_fpga: { kbuild_options: ["CONFIG_MALI_IS_FPGA=y"], }, + mali_fw_core_dump: { + kbuild_options: ["CONFIG_MALI_FW_CORE_DUMP=y"], + }, kbuild_options: [ "CONFIG_MALI_PLATFORM_NAME={{.mali_platform_name}}", "MALI_CUSTOMER_RELEASE={{.release}}", diff --git a/drivers/gpu/arm/bifrost/context/mali_kbase_context.c b/drivers/gpu/arm/bifrost/context/mali_kbase_context.c index f5258bd9d8a0..f84e01edee93 100644 --- a/drivers/gpu/arm/bifrost/context/mali_kbase_context.c +++ b/drivers/gpu/arm/bifrost/context/mali_kbase_context.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -239,7 +239,9 @@ static void kbase_remove_kctx_from_process(struct kbase_context *kctx) /* Add checks, so that the terminating process Should not * hold any gpu_memory. */ + spin_lock(&kctx->kbdev->gpu_mem_usage_lock); WARN_ON(kprcs->total_gpu_pages); + spin_unlock(&kctx->kbdev->gpu_mem_usage_lock); WARN_ON(!RB_EMPTY_ROOT(&kprcs->dma_buf_root)); kfree(kprcs); } diff --git a/drivers/gpu/arm/bifrost/csf/Kbuild b/drivers/gpu/arm/bifrost/csf/Kbuild index 70ea295db617..c5d9154a2e35 100644 --- a/drivers/gpu/arm/bifrost/csf/Kbuild +++ b/drivers/gpu/arm/bifrost/csf/Kbuild @@ -40,6 +40,7 @@ bifrost_kbase-$(CONFIG_MALI_REAL_HW) += csf/mali_kbase_csf_firmware.o bifrost_kbase-$(CONFIG_MALI_BIFROST_NO_MALI) += csf/mali_kbase_csf_firmware_no_mali.o + ifeq ($(KBUILD_EXTMOD),) # in-tree -include $(src)/csf/ipa_control/Kbuild diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c index 497e05c9b691..80e37a36ca76 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2018-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -34,6 +34,7 @@ #include #include #include "mali_kbase_csf_event.h" +#include #define CS_REQ_EXCEPTION_MASK (CS_REQ_FAULT_MASK | CS_REQ_FATAL_MASK) #define CS_ACK_EXCEPTION_MASK (CS_ACK_FAULT_MASK | CS_ACK_FATAL_MASK) @@ -52,6 +53,23 @@ const u8 kbasep_csf_relative_to_queue_group_priority[KBASE_QUEUE_GROUP_PRIORITY_ BASE_QUEUE_GROUP_PRIORITY_LOW }; +/* + * struct irq_idle_and_protm_track - Object that tracks the idle and protected mode + * request information in an interrupt case across + * groups. + * + * @protm_grp: Possibly schedulable group that requested protected mode in the interrupt. + * If NULL, no such case observed in the tracked interrupt case. + * @idle_seq: The highest priority group that notified idle. If no such instance in the + * interrupt case, marked with the largest field value: U32_MAX. + * @idle_slot: The slot number if @p idle_seq is valid in the given tracking case. + */ +struct irq_idle_and_protm_track { + struct kbase_queue_group *protm_grp; + u32 idle_seq; + s8 idle_slot; +}; + static void put_user_pages_mmap_handle(struct kbase_context *kctx, struct kbase_queue *queue) { @@ -112,13 +130,13 @@ static int get_user_pages_mmap_handle(struct kbase_context *kctx, return 0; } -static void gpu_munmap_user_io_pages(struct kbase_context *kctx, - struct kbase_va_region *reg) +static void gpu_munmap_user_io_pages(struct kbase_context *kctx, struct kbase_va_region *reg, + struct tagged_addr *phys) { size_t num_pages = 2; - kbase_mmu_teardown_pages(kctx->kbdev, &kctx->kbdev->csf.mcu_mmu, - reg->start_pfn, num_pages, MCU_AS_NR); + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->kbdev->csf.mcu_mmu, reg->start_pfn, phys, + num_pages, MCU_AS_NR); WARN_ON(reg->flags & KBASE_REG_FREE); @@ -159,12 +177,6 @@ static int gpu_mmap_user_io_pages(struct kbase_device *kbdev, */ const enum kbase_caller_mmu_sync_info mmu_sync_info = CALLER_MMU_ASYNC; -#if ((KERNEL_VERSION(4, 4, 147) >= LINUX_VERSION_CODE) || \ - ((KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) && \ - (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE))) - mem_flags |= - KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_NON_CACHEABLE); -#else if (kbdev->system_coherency == COHERENCY_NONE) { mem_flags |= KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_NON_CACHEABLE); @@ -172,7 +184,6 @@ static int gpu_mmap_user_io_pages(struct kbase_device *kbdev, mem_flags |= KBASE_REG_SHARE_BOTH | KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_SHARED); } -#endif mutex_lock(&kbdev->csf.reg_lock); ret = kbase_add_va_region_rbtree(kbdev, reg, 0, num_pages, 1); @@ -201,8 +212,7 @@ static int gpu_mmap_user_io_pages(struct kbase_device *kbdev, return 0; bad_insert_output_page: - kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, - reg->start_pfn, 1, MCU_AS_NR); + kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, reg->start_pfn, phys, 1, MCU_AS_NR); bad_insert: mutex_lock(&kbdev->csf.reg_lock); kbase_remove_va_region(kbdev, reg); @@ -231,6 +241,8 @@ static int kernel_map_user_io_pages(struct kbase_context *kctx, { struct page *page_list[2]; pgprot_t cpu_map_prot; + unsigned long flags; + char *user_io_addr; int ret = 0; size_t i; @@ -245,25 +257,19 @@ static int kernel_map_user_io_pages(struct kbase_context *kctx, /* The pages are mapped to Userspace also, so use the same mapping * attributes as used inside the CPU page fault handler. */ -#if ((KERNEL_VERSION(4, 4, 147) >= LINUX_VERSION_CODE) || \ - ((KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) && \ - (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE))) - cpu_map_prot = pgprot_device(PAGE_KERNEL); -#else if (kctx->kbdev->system_coherency == COHERENCY_NONE) cpu_map_prot = pgprot_writecombine(PAGE_KERNEL); else cpu_map_prot = PAGE_KERNEL; -#endif for (i = 0; i < ARRAY_SIZE(page_list); i++) page_list[i] = as_page(queue->phys[i]); - queue->user_io_addr = vmap(page_list, ARRAY_SIZE(page_list), VM_MAP, cpu_map_prot); + user_io_addr = vmap(page_list, ARRAY_SIZE(page_list), VM_MAP, cpu_map_prot); - if (!queue->user_io_addr) { + if (!user_io_addr) { dev_err(kctx->kbdev->dev, - "%s(): queue->user_io_addr is NULL, queue: %p", + "%s(): user_io_addr is NULL, queue: %p", __func__, queue); ret = -ENOMEM; @@ -271,6 +277,10 @@ static int kernel_map_user_io_pages(struct kbase_context *kctx, atomic_add(ARRAY_SIZE(page_list), &kctx->permanent_mapped_pages); } + kbase_csf_scheduler_spin_lock(kctx->kbdev, &flags); + queue->user_io_addr = user_io_addr; + kbase_csf_scheduler_spin_unlock(kctx->kbdev, flags); + unlock: kbase_gpu_vm_unlock(kctx); return ret; @@ -307,7 +317,7 @@ static void kbase_csf_free_command_stream_user_pages(struct kbase_context *kctx, { const size_t num_pages = 2; - gpu_munmap_user_io_pages(kctx, queue->reg); + gpu_munmap_user_io_pages(kctx, queue->reg, &queue->phys[0]); kernel_unmap_user_io_pages(kctx, queue); kbase_mem_pool_free_pages( @@ -934,7 +944,7 @@ static void unbind_stopped_queue(struct kbase_context *kctx, kbase_csf_scheduler_spin_lock(kctx->kbdev, &flags); bitmap_clear(queue->group->protm_pending_bitmap, queue->csi_index, 1); - KBASE_KTRACE_ADD_CSF_GRP_Q(kctx->kbdev, PROTM_PENDING_CLEAR, + KBASE_KTRACE_ADD_CSF_GRP_Q(kctx->kbdev, CSI_PROTM_PEND_CLEAR, queue->group, queue, queue->group->protm_pending_bitmap[0]); queue->group->bound_queues[queue->csi_index] = NULL; queue->group = NULL; @@ -982,7 +992,7 @@ static void unbind_queue(struct kbase_context *kctx, struct kbase_queue *queue) } } -void kbase_csf_queue_unbind(struct kbase_queue *queue) +void kbase_csf_queue_unbind(struct kbase_queue *queue, bool process_exit) { struct kbase_context *kctx = queue->kctx; @@ -996,7 +1006,7 @@ void kbase_csf_queue_unbind(struct kbase_queue *queue) * whereas CSG TERM request would result in an immediate abort or * cancellation of the pending work. */ - if (current->flags & PF_EXITING) { + if (process_exit) { struct kbase_queue_group *group = get_bound_queue_group(queue); if (group) @@ -1344,10 +1354,13 @@ static int create_queue_group(struct kbase_context *const kctx, group->tiler_max = create->in.tiler_max; group->fragment_max = create->in.fragment_max; group->compute_max = create->in.compute_max; + group->csi_handlers = create->in.csi_handlers; group->priority = kbase_csf_priority_queue_group_priority_to_relative( kbase_csf_priority_check(kctx->kbdev, create->in.priority)); group->doorbell_nr = KBASEP_USER_DB_NR_INVALID; group->faulted = false; + group->cs_unrecoverable = false; + group->reevaluate_idle_status = false; group->group_uid = generate_group_uid(); @@ -1391,6 +1404,14 @@ int kbase_csf_queue_group_create(struct kbase_context *const kctx, const u32 tiler_count = hweight64(create->in.tiler_mask); const u32 fragment_count = hweight64(create->in.fragment_mask); const u32 compute_count = hweight64(create->in.compute_mask); + size_t i; + + for (i = 0; i < sizeof(create->in.padding); i++) { + if (create->in.padding[i] != 0) { + dev_warn(kctx->kbdev->dev, "Invalid padding not 0 in queue group create\n"); + return -EINVAL; + } + } mutex_lock(&kctx->csf.lock); @@ -1409,6 +1430,10 @@ int kbase_csf_queue_group_create(struct kbase_context *const kctx, "No CSG has at least %d CSs", create->in.cs_min); err = -EINVAL; + } else if (create->in.csi_handlers & ~BASE_CSF_EXCEPTION_HANDLER_FLAGS_MASK) { + dev_warn(kctx->kbdev->dev, "Unknown exception handler flags set: %u", + create->in.csi_handlers & ~BASE_CSF_EXCEPTION_HANDLER_FLAGS_MASK); + err = -EINVAL; } else if (create->in.reserved) { dev_warn(kctx->kbdev->dev, "Reserved field was set to non-0"); err = -EINVAL; @@ -1447,9 +1472,8 @@ static void term_normal_suspend_buffer(struct kbase_context *const kctx, lockdep_assert_held(&kctx->csf.lock); - WARN_ON(kbase_mmu_teardown_pages( - kctx->kbdev, &kctx->kbdev->csf.mcu_mmu, - s_buf->reg->start_pfn, nr_pages, MCU_AS_NR)); + WARN_ON(kbase_mmu_teardown_pages(kctx->kbdev, &kctx->kbdev->csf.mcu_mmu, + s_buf->reg->start_pfn, s_buf->phy, nr_pages, MCU_AS_NR)); WARN_ON(s_buf->reg->flags & KBASE_REG_FREE); @@ -1479,10 +1503,16 @@ static void term_protected_suspend_buffer(struct kbase_device *const kbdev, { const size_t nr_pages = PFN_UP(kbdev->csf.global_iface.groups[0].suspend_size); + struct tagged_addr *phys = kmalloc(sizeof(*phys) * nr_pages, GFP_KERNEL); + size_t i = 0; - WARN_ON(kbase_mmu_teardown_pages( - kbdev, &kbdev->csf.mcu_mmu, - s_buf->reg->start_pfn, nr_pages, MCU_AS_NR)); + for (i = 0; phys && i < nr_pages; i++) + phys[i] = as_tagged(s_buf->pma[i]->pa); + + WARN_ON(kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, s_buf->reg->start_pfn, phys, + nr_pages, MCU_AS_NR)); + + kfree(phys); WARN_ON(s_buf->reg->flags & KBASE_REG_FREE); @@ -1929,7 +1959,7 @@ void kbase_csf_ctx_term(struct kbase_context *kctx) * handle_oom_event - Handle the OoM event generated by the firmware for the * CSI. * - * @kctx: Pointer to the kbase context in which the tiler heap was initialized. + * @group: Pointer to the CSG group the oom-event belongs to. * @stream: Pointer to the structure containing info provided by the firmware * about the CSI. * @@ -1944,9 +1974,10 @@ void kbase_csf_ctx_term(struct kbase_context *kctx) * Return: 0 if successfully handled the request, otherwise a negative error * code on failure. */ -static int handle_oom_event(struct kbase_context *const kctx, - struct kbase_csf_cmd_stream_info const *const stream) +static int handle_oom_event(struct kbase_queue_group *const group, + struct kbase_csf_cmd_stream_info const *const stream) { + struct kbase_context *const kctx = group->kctx; u64 gpu_heap_va = kbase_csf_firmware_cs_output(stream, CS_HEAP_ADDRESS_LO) | ((u64)kbase_csf_firmware_cs_output(stream, CS_HEAP_ADDRESS_HI) << 32); @@ -1960,25 +1991,36 @@ static int handle_oom_event(struct kbase_context *const kctx, u32 pending_frag_count; u64 new_chunk_ptr; int err; + bool frag_end_err = false; if ((frag_end > vt_end) || (vt_end >= vt_start)) { - dev_warn(kctx->kbdev->dev, "Invalid Heap statistics provided by firmware: vt_start %d, vt_end %d, frag_end %d\n", + frag_end_err = true; + dev_dbg(kctx->kbdev->dev, "Invalid Heap statistics provided by firmware: vt_start %d, vt_end %d, frag_end %d\n", vt_start, vt_end, frag_end); - return -EINVAL; } - - renderpasses_in_flight = vt_start - frag_end; - pending_frag_count = vt_end - frag_end; + if (frag_end_err) { + renderpasses_in_flight = 1; + pending_frag_count = 1; + } else { + renderpasses_in_flight = vt_start - frag_end; + pending_frag_count = vt_end - frag_end; + } err = kbase_csf_tiler_heap_alloc_new_chunk(kctx, gpu_heap_va, renderpasses_in_flight, pending_frag_count, &new_chunk_ptr); - /* It is okay to acknowledge with a NULL chunk (firmware will then wait - * for the fragment jobs to complete and release chunks) - */ - if (err == -EBUSY) + if ((group->csi_handlers & BASE_CSF_TILER_OOM_EXCEPTION_FLAG) && + (pending_frag_count == 0) && (err == -ENOMEM || err == -EBUSY)) { + /* The group allows incremental rendering, trigger it */ new_chunk_ptr = 0; - else if (err) + dev_dbg(kctx->kbdev->dev, "Group-%d (slot-%d) enter incremental render\n", + group->handle, group->csg_nr); + } else if (err == -EBUSY) { + /* Acknowledge with a NULL chunk (firmware will then wait for + * the fragment jobs to complete and release chunks) + */ + new_chunk_ptr = 0; + } else if (err) return err; kbase_csf_firmware_cs_input(stream, CS_TILER_HEAP_START_LO, @@ -2085,7 +2127,7 @@ static void kbase_queue_oom_event(struct kbase_queue *const queue) if (cs_oom_ack == cs_oom_req) goto unlock; - err = handle_oom_event(kctx, stream); + err = handle_oom_event(group, stream); kbase_csf_firmware_cs_input_mask(stream, CS_REQ, cs_oom_ack, CS_REQ_TILER_OOM_MASK); @@ -2221,7 +2263,7 @@ static void protm_event_worker(struct work_struct *data) struct kbase_queue_group *const group = container_of(data, struct kbase_queue_group, protm_event_work); - KBASE_KTRACE_ADD_CSF_GRP(group->kctx->kbdev, PROTM_EVENT_WORKER_BEGIN, + KBASE_KTRACE_ADD_CSF_GRP(group->kctx->kbdev, PROTM_EVENT_WORKER_START, group, 0u); kbase_csf_scheduler_group_protm_enter(group); KBASE_KTRACE_ADD_CSF_GRP(group->kctx->kbdev, PROTM_EVENT_WORKER_END, @@ -2388,6 +2430,11 @@ handle_fatal_event(struct kbase_queue *const queue, CS_FATAL_EXCEPTION_TYPE_FIRMWARE_INTERNAL_ERROR) { queue_work(system_wq, &kbdev->csf.fw_error_work); } else { + if (cs_fatal_exception_type == CS_FATAL_EXCEPTION_TYPE_CS_UNRECOVERABLE) { + queue->group->cs_unrecoverable = true; + if (kbase_prepare_to_reset_gpu(queue->kctx->kbdev, RESET_FLAGS_NONE)) + kbase_reset_gpu(queue->kctx->kbdev); + } get_queue(queue); queue->cs_fatal = cs_fatal; queue->cs_fatal_info = cs_fatal_info; @@ -2441,6 +2488,9 @@ static void handle_queue_exception_event(struct kbase_queue *const queue, * @ginfo: The CSG interface provided by the firmware. * @irqreq: CSG's IRQ request bitmask (one bit per CS). * @irqack: CSG's IRQ acknowledge bitmask (one bit per CS). + * @track: Pointer that tracks the highest scanout priority idle CSG + * and any newly potentially viable protected mode requesting + * CSG in current IRQ context. * * If the interrupt request bitmask differs from the acknowledge bitmask * then the firmware is notifying the host of an event concerning those @@ -2449,8 +2499,9 @@ static void handle_queue_exception_event(struct kbase_queue *const queue, * the request and acknowledge registers for the individual CS(s). */ static void process_cs_interrupts(struct kbase_queue_group *const group, - struct kbase_csf_cmd_stream_group_info const *const ginfo, - u32 const irqreq, u32 const irqack) + struct kbase_csf_cmd_stream_group_info const *const ginfo, + u32 const irqreq, u32 const irqack, + struct irq_idle_and_protm_track *track) { struct kbase_device *const kbdev = group->kctx->kbdev; u32 remaining = irqreq ^ irqack; @@ -2482,7 +2533,8 @@ static void process_cs_interrupts(struct kbase_queue_group *const group, if ((cs_req & CS_REQ_EXCEPTION_MASK) ^ (cs_ack & CS_ACK_EXCEPTION_MASK)) { - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_FAULT_INTERRUPT, group, queue, cs_req ^ cs_ack); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_INTERRUPT_FAULT, + group, queue, cs_req ^ cs_ack); handle_queue_exception_event(queue, cs_req, cs_ack); } @@ -2494,16 +2546,18 @@ static void process_cs_interrupts(struct kbase_queue_group *const group, u32 const cs_req_remain = cs_req & ~CS_REQ_EXCEPTION_MASK; u32 const cs_ack_remain = cs_ack & ~CS_ACK_EXCEPTION_MASK; - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_IGNORED_INTERRUPTS_GROUP_SUSPEND, - group, queue, cs_req_remain ^ cs_ack_remain); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, + CSI_INTERRUPT_GROUP_SUSPENDS_IGNORED, + group, queue, + cs_req_remain ^ cs_ack_remain); continue; } if (((cs_req & CS_REQ_TILER_OOM_MASK) ^ (cs_ack & CS_ACK_TILER_OOM_MASK))) { get_queue(queue); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_TILER_OOM_INTERRUPT, group, queue, - cs_req ^ cs_ack); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_INTERRUPT_TILER_OOM, + group, queue, cs_req ^ cs_ack); if (WARN_ON(!queue_work(wq, &queue->oom_event_work))) { /* The work item shall not have been * already queued, there can be only @@ -2516,8 +2570,8 @@ static void process_cs_interrupts(struct kbase_queue_group *const group, if ((cs_req & CS_REQ_PROTM_PEND_MASK) ^ (cs_ack & CS_ACK_PROTM_PEND_MASK)) { - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_PROTM_PEND_INTERRUPT, group, queue, - cs_req ^ cs_ack); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_INTERRUPT_PROTM_PEND, + group, queue, cs_req ^ cs_ack); dev_dbg(kbdev->dev, "Protected mode entry request for queue on csi %d bound to group-%d on slot %d", @@ -2525,7 +2579,7 @@ static void process_cs_interrupts(struct kbase_queue_group *const group, group->csg_nr); bitmap_set(group->protm_pending_bitmap, i, 1); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, PROTM_PENDING_SET, group, queue, + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_PROTM_PEND_SET, group, queue, group->protm_pending_bitmap[0]); protm_pend = true; } @@ -2534,12 +2588,10 @@ static void process_cs_interrupts(struct kbase_queue_group *const group, if (protm_pend) { struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; - u32 current_protm_pending_seq = - scheduler->tick_protm_pending_seq; - if (current_protm_pending_seq > group->scan_seq_num) { + if (scheduler->tick_protm_pending_seq > group->scan_seq_num) { scheduler->tick_protm_pending_seq = group->scan_seq_num; - queue_work(group->kctx->csf.wq, &group->protm_event_work); + track->protm_grp = group; } if (test_bit(group->csg_nr, scheduler->csg_slots_idle_mask)) { @@ -2557,6 +2609,8 @@ static void process_cs_interrupts(struct kbase_queue_group *const group, * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * @csg_nr: CSG number. + * @track: Pointer that tracks the highest idle CSG and the newly possible viable + * protected mode requesting group, in current IRQ context. * * Handles interrupts for a CSG and for CSs within it. * @@ -2567,8 +2621,8 @@ static void process_cs_interrupts(struct kbase_queue_group *const group, * * See process_cs_interrupts() for details of per-stream interrupt handling. */ -static void process_csg_interrupts(struct kbase_device *const kbdev, - int const csg_nr) +static void process_csg_interrupts(struct kbase_device *const kbdev, int const csg_nr, + struct irq_idle_and_protm_track *track) { struct kbase_csf_cmd_stream_group_info *ginfo; struct kbase_queue_group *group = NULL; @@ -2579,7 +2633,7 @@ static void process_csg_interrupts(struct kbase_device *const kbdev, if (WARN_ON(csg_nr >= kbdev->csf.global_iface.group_num)) return; - KBASE_KTRACE_ADD(kbdev, CSG_INTERRUPT_PROCESS, NULL, csg_nr); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_INTERRUPT_PROCESS_START, group, csg_nr); ginfo = &kbdev->csf.global_iface.groups[csg_nr]; req = kbase_csf_firmware_csg_input_read(ginfo, CSG_REQ); @@ -2619,7 +2673,7 @@ static void process_csg_interrupts(struct kbase_device *const kbdev, kbase_csf_firmware_csg_input_mask(ginfo, CSG_REQ, ack, CSG_REQ_SYNC_UPDATE_MASK); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SYNC_UPDATE_INTERRUPT, group, req ^ ack); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_INTERRUPT_SYNC_UPDATE, group, req ^ ack); /* SYNC_UPDATE events shall invalidate GPU idle event */ atomic_set(&kbdev->csf.scheduler.gpu_no_longer_idle, true); @@ -2636,7 +2690,7 @@ static void process_csg_interrupts(struct kbase_device *const kbdev, set_bit(csg_nr, scheduler->csg_slots_idle_mask); KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_IDLE_SET, group, scheduler->csg_slots_idle_mask[0]); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_IDLE_INTERRUPT, group, req ^ ack); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_INTERRUPT_IDLE, group, req ^ ack); dev_dbg(kbdev->dev, "Idle notification received for Group %u on slot %d\n", group->handle, csg_nr); @@ -2645,20 +2699,11 @@ static void process_csg_interrupts(struct kbase_device *const kbdev, * a tock for a replacement. */ mod_delayed_work(scheduler->wq, &scheduler->tock_work, 0); - } else { - u32 current_protm_pending_seq = - scheduler->tick_protm_pending_seq; + } - if ((current_protm_pending_seq != - KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID) && - (group->scan_seq_num < current_protm_pending_seq)) { - /* If the protm enter was prevented due to groups - * priority, then fire a tock for the scheduler - * to re-examine the case. - */ - mod_delayed_work(scheduler->wq, - &scheduler->tock_work, 0); - } + if (group->scan_seq_num < track->idle_seq) { + track->idle_seq = group->scan_seq_num; + track->idle_slot = csg_nr; } } @@ -2666,7 +2711,7 @@ static void process_csg_interrupts(struct kbase_device *const kbdev, kbase_csf_firmware_csg_input_mask(ginfo, CSG_REQ, ack, CSG_REQ_PROGRESS_TIMER_EVENT_MASK); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_PROGRESS_TIMER_INTERRUPT, + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_INTERRUPT_PROGRESS_TIMER_EVENT, group, req ^ ack); dev_info(kbdev->dev, "[%llu] Iterator PROGRESS_TIMER timeout notification received for group %u of ctx %d_%d on slot %d\n", @@ -2676,7 +2721,7 @@ static void process_csg_interrupts(struct kbase_device *const kbdev, handle_progress_timer_event(group); } - process_cs_interrupts(group, ginfo, irqreq, irqack); + process_cs_interrupts(group, ginfo, irqreq, irqack, track); out: /* group may still be NULL here */ @@ -2827,7 +2872,7 @@ static inline void process_protm_exit(struct kbase_device *kbdev, u32 glb_ack) GLB_REQ_PROTM_EXIT_MASK); if (likely(scheduler->active_protm_grp)) { - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_EXIT_PROTM, + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_PROTM_EXIT, scheduler->active_protm_grp, 0u); scheduler->active_protm_grp = NULL; } else { @@ -2841,24 +2886,83 @@ static inline void process_protm_exit(struct kbase_device *kbdev, u32 glb_ack) } } +static inline void process_tracked_info_for_protm(struct kbase_device *kbdev, + struct irq_idle_and_protm_track *track) +{ + struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; + struct kbase_queue_group *group = track->protm_grp; + u32 current_protm_pending_seq = scheduler->tick_protm_pending_seq; + + kbase_csf_scheduler_spin_lock_assert_held(kbdev); + + if (likely(current_protm_pending_seq == KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID)) + return; + + /* Handle protm from the tracked information */ + if (track->idle_seq < current_protm_pending_seq) { + /* If the protm enter was prevented due to groups priority, then fire a tock + * for the scheduler to re-examine the case. + */ + dev_dbg(kbdev->dev, "Attempt pending protm from idle slot %d\n", track->idle_slot); + mod_delayed_work(scheduler->wq, &scheduler->tock_work, 0); + } else if (group) { + u32 i, num_groups = kbdev->csf.global_iface.group_num; + struct kbase_queue_group *grp; + bool tock_triggered = false; + + /* A new protm request, and track->idle_seq is not sufficient, check across + * previously notified idle CSGs in the current tick/tock cycle. + */ + for_each_set_bit(i, scheduler->csg_slots_idle_mask, num_groups) { + if (i == track->idle_slot) + continue; + grp = kbase_csf_scheduler_get_group_on_slot(kbdev, i); + /* If not NULL then the group pointer cannot disappear as the + * scheduler spinlock is held. + */ + if (grp == NULL) + continue; + + if (grp->scan_seq_num < current_protm_pending_seq) { + tock_triggered = true; + dev_dbg(kbdev->dev, + "Attempt new protm from tick/tock idle slot %d\n", i); + mod_delayed_work(scheduler->wq, &scheduler->tock_work, 0); + break; + } + } + + if (!tock_triggered) { + dev_dbg(kbdev->dev, "Group-%d on slot-%d start protm work\n", + group->handle, group->csg_nr); + queue_work(group->kctx->csf.wq, &group->protm_event_work); + } + } +} + void kbase_csf_interrupt(struct kbase_device *kbdev, u32 val) { unsigned long flags; u32 csg_interrupts = val & ~JOB_IRQ_GLOBAL_IF; + struct irq_idle_and_protm_track track = { .protm_grp = NULL, .idle_seq = U32_MAX }; lockdep_assert_held(&kbdev->hwaccess_lock); - KBASE_KTRACE_ADD(kbdev, CSF_INTERRUPT, NULL, val); + KBASE_KTRACE_ADD(kbdev, CSF_INTERRUPT_START, NULL, val); kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), val); if (csg_interrupts != 0) { kbase_csf_scheduler_spin_lock(kbdev, &flags); + /* Looping through and track the highest idle and protm groups */ while (csg_interrupts != 0) { int const csg_nr = ffs(csg_interrupts) - 1; - process_csg_interrupts(kbdev, csg_nr); + process_csg_interrupts(kbdev, csg_nr, &track); csg_interrupts &= ~(1 << csg_nr); } + + /* Handle protm from the tracked information */ + process_tracked_info_for_protm(kbdev, &track); kbase_csf_scheduler_spin_unlock(kbdev, flags); } @@ -2878,7 +2982,7 @@ void kbase_csf_interrupt(struct kbase_device *kbdev, u32 val) global_iface, GLB_REQ); glb_ack = kbase_csf_firmware_global_output( global_iface, GLB_ACK); - KBASE_KTRACE_ADD(kbdev, GLB_REQ_ACQ, NULL, glb_req ^ glb_ack); + KBASE_KTRACE_ADD(kbdev, CSF_INTERRUPT_GLB_REQ_ACK, NULL, glb_req ^ glb_ack); check_protm_enter_req_complete(kbdev, glb_req, glb_ack); diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h index 46a052951e4a..b2677405761f 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2018-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -45,8 +45,6 @@ */ #define KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID (U32_MAX) -#define FIRMWARE_PING_INTERVAL_MS (12000) /* 12 seconds */ - #define FIRMWARE_IDLE_HYSTERESIS_TIME_MS (10) /* Default 10 milliseconds */ /* Idle hysteresis time can be scaled down when GPU sleep feature is used */ @@ -161,8 +159,9 @@ int kbase_csf_queue_bind(struct kbase_context *kctx, * are any. * * @queue: Pointer to queue to be unbound. + * @process_exit: Flag to indicate if process exit is happening. */ -void kbase_csf_queue_unbind(struct kbase_queue *queue); +void kbase_csf_queue_unbind(struct kbase_queue *queue, bool process_exit); /** * kbase_csf_queue_unbind_stopped - Unbind a GPU command queue in the case diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_csg_debugfs.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_csg_debugfs.c index c511e5f3cd2d..92a511d79a05 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_csg_debugfs.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_csg_debugfs.c @@ -500,11 +500,7 @@ static const struct file_operations kbasep_csf_queue_group_debugfs_fops = { void kbase_csf_queue_group_debugfs_init(struct kbase_context *kctx) { struct dentry *file; -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) const mode_t mode = 0444; -#else - const mode_t mode = 0400; -#endif if (WARN_ON(!kctx || IS_ERR_OR_NULL(kctx->kctx_dentry))) return; diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_defs.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_defs.h index 798924fc4b21..27aa53de110d 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_defs.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_defs.h @@ -261,6 +261,8 @@ enum kbase_queue_group_priority { * @CSF_GPU_RESET_TIMEOUT: Waiting timeout for GPU reset to complete. * @CSF_CSG_SUSPEND_TIMEOUT: Timeout given for all active CSGs to be suspended. * @CSF_FIRMWARE_BOOT_TIMEOUT: Maximum time to wait for firmware to boot. + * @CSF_FIRMWARE_PING_TIMEOUT: Maximum time to wait for firmware to respond + * to a ping from KBase. * @CSF_SCHED_PROTM_PROGRESS_TIMEOUT: Timeout used to prevent protected mode execution hang. * @KBASE_TIMEOUT_SELECTOR_COUNT: Number of timeout selectors. Must be last in * the enum. @@ -271,6 +273,7 @@ enum kbase_timeout_selector { CSF_GPU_RESET_TIMEOUT, CSF_CSG_SUSPEND_TIMEOUT, CSF_FIRMWARE_BOOT_TIMEOUT, + CSF_FIRMWARE_PING_TIMEOUT, CSF_SCHED_PROTM_PROGRESS_TIMEOUT, /* Must be the last in the enum */ @@ -452,6 +455,7 @@ struct kbase_protected_suspend_buffer { * allowed to use. * @compute_max: Maximum number of compute endpoints the group is * allowed to use. + * @csi_handlers: Requested CSI exception handler flags for the group. * @tiler_mask: Mask of tiler endpoints the group is allowed to use. * @fragment_mask: Mask of fragment endpoints the group is allowed to use. * @compute_mask: Mask of compute endpoints the group is allowed to use. @@ -473,6 +477,12 @@ struct kbase_protected_suspend_buffer { * @faulted: Indicates that a GPU fault occurred for the queue group. * This flag persists until the fault has been queued to be * reported to userspace. + * @cs_unrecoverable: Flag to unblock the thread waiting for CSG termination in + * case of CS_FATAL_EXCEPTION_TYPE_CS_UNRECOVERABLE + * @reevaluate_idle_status : Flag set when work is submitted for the normal group + * or it becomes unblocked during protected mode. The + * flag helps Scheduler confirm if the group actually + * became non idle or not. * @bound_queues: Array of registered queues bound to this queue group. * @doorbell_nr: Index of the hardware doorbell page assigned to the * group. @@ -500,6 +510,7 @@ struct kbase_queue_group { u8 tiler_max; u8 fragment_max; u8 compute_max; + u8 csi_handlers; u64 tiler_mask; u64 fragment_mask; @@ -513,6 +524,8 @@ struct kbase_queue_group { u32 prepared_seq_num; u32 scan_seq_num; bool faulted; + bool cs_unrecoverable; + bool reevaluate_idle_status; struct kbase_queue *bound_queues[MAX_SUPPORTED_STREAMS_PER_GROUP]; diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_event.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_event.c index 5c86688c3ea6..170b7ec51af7 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_event.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_event.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2021-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -102,7 +102,7 @@ static void sync_update_notify_gpu(struct kbase_context *kctx) if (can_notify_gpu) { kbase_csf_ring_doorbell(kctx->kbdev, CSF_KERNEL_DOORBELL_NR); - KBASE_KTRACE_ADD(kctx->kbdev, SYNC_UPDATE_EVENT_NOTIFY_GPU, kctx, 0u); + KBASE_KTRACE_ADD(kctx->kbdev, CSF_SYNC_UPDATE_NOTIFY_GPU_EVENT, kctx, 0u); } spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, flags); @@ -226,12 +226,15 @@ void kbase_csf_event_add_error(struct kbase_context *const kctx, return; spin_lock_irqsave(&kctx->csf.event.lock, flags); - if (!WARN_ON(!list_empty(&error->link))) { + if (list_empty(&error->link)) { error->data = *data; list_add_tail(&error->link, &kctx->csf.event.error_list); dev_dbg(kctx->kbdev->dev, "Added error %pK of type %d in context %pK\n", (void *)error, data->type, (void *)kctx); + } else { + dev_dbg(kctx->kbdev->dev, "Error %pK of type %d already pending in context %pK", + (void *)error, error->data.type, (void *)kctx); } spin_unlock_irqrestore(&kctx->csf.event.lock, flags); } diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.c index 553ee03dd9e1..0fb56e0094c5 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.c @@ -44,6 +44,7 @@ #include #include #include +#include #if (KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE) #include #endif @@ -94,6 +95,7 @@ MODULE_PARM_DESC(fw_debug, #define CSF_FIRMWARE_ENTRY_TYPE_FUTF_TEST (2) #define CSF_FIRMWARE_ENTRY_TYPE_TRACE_BUFFER (3) #define CSF_FIRMWARE_ENTRY_TYPE_TIMELINE_METADATA (4) +#define CSF_FIRMWARE_ENTRY_TYPE_BUILD_INFO_METADATA (6) #define CSF_FIRMWARE_CACHE_MODE_NONE (0ul << 3) #define CSF_FIRMWARE_CACHE_MODE_CACHED (1ul << 3) @@ -104,12 +106,18 @@ MODULE_PARM_DESC(fw_debug, #define TL_METADATA_ENTRY_NAME_OFFSET (0x8) +#define BUILD_INFO_METADATA_SIZE_OFFSET (0x4) +#define BUILD_INFO_GIT_SHA_LEN (40U) +#define BUILD_INFO_GIT_DIRTY_LEN (1U) +#define BUILD_INFO_GIT_SHA_PATTERN "git_sha: " + #define CSF_MAX_FW_STOP_LOOPS (100000) #define CSF_GLB_REQ_CFG_MASK \ (GLB_REQ_CFG_ALLOC_EN_MASK | GLB_REQ_CFG_PROGRESS_TIMER_MASK | \ GLB_REQ_CFG_PWROFF_TIMER_MASK | GLB_REQ_IDLE_ENABLE_MASK) + static inline u32 input_page_read(const u32 *const input, const u32 offset) { WARN_ON(offset % sizeof(u32)); @@ -589,7 +597,7 @@ static int parse_memory_setup_entry(struct kbase_device *kbdev, protected_mode = true; if (protected_mode && kbdev->csf.pma_dev == NULL) { - dev_err(kbdev->dev, + dev_dbg(kbdev->dev, "Protected memory allocator not found, Firmware protected mode entry will not be supported"); return 0; } @@ -719,8 +727,9 @@ static int parse_memory_setup_entry(struct kbase_device *kbdev, if (!reuse_pages) { ret = kbase_mmu_insert_pages_no_flush(kbdev, &kbdev->csf.mcu_mmu, - virtual_start >> PAGE_SHIFT, phys, num_pages_aligned, mem_flags, - KBASE_MEM_GROUP_CSF_FW); + virtual_start >> PAGE_SHIFT, phys, + num_pages_aligned, mem_flags, + KBASE_MEM_GROUP_CSF_FW, NULL); if (ret != 0) { dev_err(kbdev->dev, "Failed to insert firmware pages\n"); @@ -810,6 +819,57 @@ static int parse_timeline_metadata_entry(struct kbase_device *kbdev, return 0; } +/** + * parse_build_info_metadata_entry() - Process a "build info metadata" section + * @kbdev: Kbase device structure + * @fw: Firmware image containing the section + * @entry: Pointer to the section + * @size: Size (in bytes) of the section + * + * This prints the git SHA of the firmware on frimware load. + * + * Return: 0 if successful, negative error code on failure + */ +static int parse_build_info_metadata_entry(struct kbase_device *kbdev, + const struct kbase_csf_mcu_fw *const fw, + const u32 *entry, unsigned int size) +{ + const u32 meta_start_addr = entry[0]; + char *ptr = NULL; + size_t sha_pattern_len = strlen(BUILD_INFO_GIT_SHA_PATTERN); + + /* Only print git SHA to avoid releasing sensitive information */ + ptr = strstr(fw->data + meta_start_addr, BUILD_INFO_GIT_SHA_PATTERN); + /* Check that we won't overrun the found string */ + if (ptr && + strlen(ptr) >= BUILD_INFO_GIT_SHA_LEN + BUILD_INFO_GIT_DIRTY_LEN + sha_pattern_len) { + char git_sha[BUILD_INFO_GIT_SHA_LEN + BUILD_INFO_GIT_DIRTY_LEN + 1]; + int i = 0; + + /* Move ptr to start of SHA */ + ptr += sha_pattern_len; + for (i = 0; i < BUILD_INFO_GIT_SHA_LEN; i++) { + /* Ensure that the SHA is made up of hex digits */ + if (!isxdigit(ptr[i])) + break; + + git_sha[i] = ptr[i]; + } + + /* Check if the next char indicates git SHA is dirty */ + if (ptr[i] == ' ' || ptr[i] == '+') { + git_sha[i] = ptr[i]; + i++; + } + git_sha[i] = '\0'; + + dev_info(kbdev->dev, "Mali firmware git_sha: %s\n", git_sha); + } else + dev_info(kbdev->dev, "Mali firmware git_sha not found or invalid\n"); + + return 0; +} + /** * load_firmware_entry() - Process an entry from a firmware image * @@ -889,6 +949,13 @@ static int load_firmware_entry(struct kbase_device *kbdev, const struct kbase_cs return -EINVAL; } return parse_timeline_metadata_entry(kbdev, fw, entry, size); + case CSF_FIRMWARE_ENTRY_TYPE_BUILD_INFO_METADATA: + if (size < BUILD_INFO_METADATA_SIZE_OFFSET + sizeof(*entry)) { + dev_err(kbdev->dev, "Build info metadata entry too short (size=%u)\n", + size); + return -EINVAL; + } + return parse_build_info_metadata_entry(kbdev, fw, entry, size); } if (!optional) { @@ -1491,6 +1558,7 @@ static void enable_gpu_idle_timer(struct kbase_device *const kbdev) kbdev->csf.gpu_idle_dur_count); } + static void global_init(struct kbase_device *const kbdev, u64 core_mask) { u32 const ack_irq_mask = @@ -1665,7 +1733,7 @@ void kbase_csf_firmware_reload_completed(struct kbase_device *kbdev) if (version != kbdev->csf.global_iface.version) dev_err(kbdev->dev, "Version check failed in firmware reboot."); - KBASE_KTRACE_ADD(kbdev, FIRMWARE_REBOOT, NULL, 0u); + KBASE_KTRACE_ADD(kbdev, CSF_FIRMWARE_REBOOT, NULL, 0u); /* Tell MCU state machine to transit to next state */ kbdev->csf.firmware_reloaded = true; @@ -2121,7 +2189,7 @@ int kbase_csf_firmware_init(struct kbase_device *kbdev) goto err_out; /* Firmware loaded successfully, ret = 0 */ - KBASE_KTRACE_ADD(kbdev, FIRMWARE_BOOT, NULL, + KBASE_KTRACE_ADD(kbdev, CSF_FIRMWARE_BOOT, NULL, (((u64)version_hash) << 32) | (((u64)version_major) << 8) | version_minor); return 0; @@ -2611,9 +2679,9 @@ int kbase_csf_firmware_mcu_shared_mapping_init( gpu_map_properties &= (KBASE_REG_GPU_RD | KBASE_REG_GPU_WR); gpu_map_properties |= gpu_map_prot; - ret = kbase_mmu_insert_pages_no_flush(kbdev, &kbdev->csf.mcu_mmu, - va_reg->start_pfn, &phys[0], num_pages, - gpu_map_properties, KBASE_MEM_GROUP_CSF_FW); + ret = kbase_mmu_insert_pages_no_flush(kbdev, &kbdev->csf.mcu_mmu, va_reg->start_pfn, + &phys[0], num_pages, gpu_map_properties, + KBASE_MEM_GROUP_CSF_FW, NULL); if (ret) goto mmu_insert_pages_error; @@ -2674,3 +2742,4 @@ void kbase_csf_firmware_mcu_shared_mapping_term( vunmap(csf_mapping->cpu_addr); kfree(csf_mapping->phys); } + diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.h index f688fdcdb4d0..85caaa7b2ab4 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.h @@ -246,6 +246,7 @@ void kbase_csf_firmware_csg_input_mask( u32 kbase_csf_firmware_csg_output( const struct kbase_csf_cmd_stream_group_info *info, u32 offset); + /** * struct kbase_csf_global_iface - Global CSF interface * provided by the firmware. @@ -794,4 +795,6 @@ static inline u32 kbase_csf_interface_version(u32 major, u32 minor, u32 patch) * Return: 0 if success, or negative error code on failure. */ int kbase_csf_trigger_firmware_config_update(struct kbase_device *kbdev); + + #endif diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_cfg.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_cfg.c index 961335c024bd..ad4ae74c7569 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_cfg.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_cfg.c @@ -22,6 +22,7 @@ #include #include "mali_kbase_csf_firmware_cfg.h" #include +#include #if CONFIG_SYSFS #define CSF_FIRMWARE_CFG_SYSFS_DIR_NAME "firmware_config" @@ -209,11 +210,18 @@ static struct attribute *fw_cfg_attrs[] = { &fw_cfg_attr_cur, NULL, }; +#if (KERNEL_VERSION(5, 2, 0) <= LINUX_VERSION_CODE) +ATTRIBUTE_GROUPS(fw_cfg); +#endif static struct kobj_type fw_cfg_kobj_type = { .release = &fw_cfg_kobj_release, .sysfs_ops = &fw_cfg_ops, +#if (KERNEL_VERSION(5, 2, 0) <= LINUX_VERSION_CODE) + .default_groups = fw_cfg_groups, +#else .default_attrs = fw_cfg_attrs, +#endif }; int kbase_csf_firmware_cfg_init(struct kbase_device *kbdev) diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_no_mali.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_no_mali.c index 670e31ec0fce..54f1f6b9c199 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_no_mali.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware_no_mali.c @@ -104,6 +104,7 @@ struct dummy_firmware_interface { (GLB_REQ_CFG_ALLOC_EN_MASK | GLB_REQ_CFG_PROGRESS_TIMER_MASK | \ GLB_REQ_CFG_PWROFF_TIMER_MASK | GLB_REQ_IDLE_ENABLE_MASK) + static inline u32 input_page_read(const u32 *const input, const u32 offset) { WARN_ON(offset % sizeof(u32)); @@ -703,17 +704,16 @@ static void enable_gpu_idle_timer(struct kbase_device *const kbdev) kbdev->csf.gpu_idle_dur_count); } + static void global_init(struct kbase_device *const kbdev, u64 core_mask) { - u32 const ack_irq_mask = GLB_ACK_IRQ_MASK_CFG_ALLOC_EN_MASK | - GLB_ACK_IRQ_MASK_PING_MASK | - GLB_ACK_IRQ_MASK_CFG_PROGRESS_TIMER_MASK | - GLB_ACK_IRQ_MASK_PROTM_ENTER_MASK | - GLB_ACK_IRQ_MASK_FIRMWARE_CONFIG_UPDATE_MASK | - GLB_ACK_IRQ_MASK_PROTM_EXIT_MASK | - GLB_ACK_IRQ_MASK_CFG_PWROFF_TIMER_MASK | - GLB_ACK_IRQ_MASK_IDLE_EVENT_MASK | - GLB_ACK_IRQ_MASK_IDLE_ENABLE_MASK; + u32 const ack_irq_mask = + GLB_ACK_IRQ_MASK_CFG_ALLOC_EN_MASK | GLB_ACK_IRQ_MASK_PING_MASK | + GLB_ACK_IRQ_MASK_CFG_PROGRESS_TIMER_MASK | GLB_ACK_IRQ_MASK_PROTM_ENTER_MASK | + GLB_ACK_IRQ_MASK_PROTM_EXIT_MASK | GLB_ACK_IRQ_MASK_FIRMWARE_CONFIG_UPDATE_MASK | + GLB_ACK_IRQ_MASK_CFG_PWROFF_TIMER_MASK | GLB_ACK_IRQ_MASK_IDLE_EVENT_MASK | + GLB_ACK_IRQ_MASK_IDLE_ENABLE_MASK | + 0; const struct kbase_csf_global_iface *const global_iface = &kbdev->csf.global_iface; @@ -1473,7 +1473,7 @@ int kbase_csf_firmware_mcu_shared_mapping_init( gpu_map_prot = KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_NON_CACHEABLE); cpu_map_prot = pgprot_writecombine(cpu_map_prot); - }; + } phys = kmalloc_array(num_pages, sizeof(*phys), GFP_KERNEL); if (!phys) @@ -1511,9 +1511,9 @@ int kbase_csf_firmware_mcu_shared_mapping_init( gpu_map_properties &= (KBASE_REG_GPU_RD | KBASE_REG_GPU_WR); gpu_map_properties |= gpu_map_prot; - ret = kbase_mmu_insert_pages_no_flush(kbdev, &kbdev->csf.mcu_mmu, - va_reg->start_pfn, &phys[0], num_pages, - gpu_map_properties, KBASE_MEM_GROUP_CSF_FW); + ret = kbase_mmu_insert_pages_no_flush(kbdev, &kbdev->csf.mcu_mmu, va_reg->start_pfn, + &phys[0], num_pages, gpu_map_properties, + KBASE_MEM_GROUP_CSF_FW, NULL); if (ret) goto mmu_insert_pages_error; @@ -1574,3 +1574,4 @@ void kbase_csf_firmware_mcu_shared_mapping_term( vunmap(csf_mapping->cpu_addr); kfree(csf_mapping->phys); } + 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 c72142ca7685..542f04579898 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c @@ -33,6 +33,10 @@ static DEFINE_SPINLOCK(kbase_csf_fence_lock); #endif +#ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG +#define FENCE_WAIT_TIMEOUT_MS 3000 +#endif + static void kcpu_queue_process(struct kbase_kcpu_command_queue *kcpu_queue, bool drain_queue); @@ -748,7 +752,7 @@ static int kbase_kcpu_cqs_wait_process(struct kbase_device *kbdev, KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_START(kbdev, queue); queue->command_started = true; - KBASE_KTRACE_ADD_CSF_KCPU(kbdev, CQS_WAIT_START, + KBASE_KTRACE_ADD_CSF_KCPU(kbdev, KCPU_CQS_WAIT_START, queue, cqs_wait->nr_objs, 0); } @@ -770,7 +774,7 @@ static int kbase_kcpu_cqs_wait_process(struct kbase_device *kbdev, error = true; } - KBASE_KTRACE_ADD_CSF_KCPU(kbdev, CQS_WAIT_END, + KBASE_KTRACE_ADD_CSF_KCPU(kbdev, KCPU_CQS_WAIT_END, queue, cqs_wait->objs[i].addr, error); @@ -877,7 +881,7 @@ static void kbase_kcpu_cqs_set_process(struct kbase_device *kbdev, evt[BASEP_EVENT_VAL_INDEX]++; kbase_phy_alloc_mapping_put(queue->kctx, mapping); - KBASE_KTRACE_ADD_CSF_KCPU(kbdev, CQS_SET, + KBASE_KTRACE_ADD_CSF_KCPU(kbdev, KCPU_CQS_SET, queue, cqs_set->objs[i].addr, evt[BASEP_EVENT_ERR_INDEX]); } @@ -1200,7 +1204,11 @@ static void kbase_csf_fence_wait_callback(struct dma_fence *fence, struct kbase_kcpu_command_queue *kcpu_queue = fence_info->kcpu_queue; struct kbase_context *const kctx = kcpu_queue->kctx; - KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, FENCE_WAIT_END, kcpu_queue, +#ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG + /* Fence gets signaled. Deactivate the timer for fence-wait timeout */ + del_timer(&kcpu_queue->fence_timeout); +#endif + KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, KCPU_FENCE_WAIT_END, kcpu_queue, fence->context, fence->seqno); /* Resume kcpu command queue processing. */ @@ -1222,8 +1230,15 @@ static void kbase_kcpu_fence_wait_cancel( bool removed = dma_fence_remove_callback(fence_info->fence, &fence_info->fence_cb); +#ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG + /* Fence-wait cancelled or fence signaled. In the latter case + * the timer would already have been deactivated inside + * kbase_csf_fence_wait_callback(). + */ + del_timer_sync(&kcpu_queue->fence_timeout); +#endif if (removed) - KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, FENCE_WAIT_END, + KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, KCPU_FENCE_WAIT_END, kcpu_queue, fence_info->fence->context, fence_info->fence->seqno); } @@ -1235,6 +1250,80 @@ static void kbase_kcpu_fence_wait_cancel( fence_info->fence = NULL; } +#ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG +/** + * fence_timeout_callback() - Timeout callback function for fence-wait + * + * @timer: Timer struct + * + * Context and seqno of the timed-out fence will be displayed in dmesg. + * If the fence has been signalled a work will be enqueued to process + * the fence-wait without displaying debugging information. + */ +static void fence_timeout_callback(struct timer_list *timer) +{ + struct kbase_kcpu_command_queue *kcpu_queue = + container_of(timer, struct kbase_kcpu_command_queue, fence_timeout); + struct kbase_context *const kctx = kcpu_queue->kctx; + struct kbase_kcpu_command *cmd = &kcpu_queue->commands[kcpu_queue->start_offset]; + struct kbase_kcpu_command_fence_info *fence_info; +#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) + struct fence *fence; +#else + struct dma_fence *fence; +#endif + struct kbase_sync_fence_info info; + + if (cmd->type != BASE_KCPU_COMMAND_TYPE_FENCE_WAIT) { + dev_err(kctx->kbdev->dev, + "%s: Unexpected command type %d in ctx:%d_%d kcpu queue:%u", __func__, + cmd->type, kctx->tgid, kctx->id, kcpu_queue->id); + return; + } + + fence_info = &cmd->info.fence; + + fence = kbase_fence_get(fence_info); + if (!fence) { + dev_err(kctx->kbdev->dev, "no fence found in ctx:%d_%d kcpu queue:%u", kctx->tgid, + kctx->id, kcpu_queue->id); + return; + } + + kbase_sync_fence_info_get(fence, &info); + + if (info.status == 1) { + queue_work(kctx->csf.kcpu_queues.wq, &kcpu_queue->work); + } else if (info.status == 0) { + dev_warn(kctx->kbdev->dev, "fence has not yet signalled in %ums", + FENCE_WAIT_TIMEOUT_MS); + dev_warn(kctx->kbdev->dev, + "ctx:%d_%d kcpu queue:%u still waiting for fence[%pK] context#seqno:%s", + kctx->tgid, kctx->id, kcpu_queue->id, fence, info.name); + } else { + dev_warn(kctx->kbdev->dev, "fence has got error"); + dev_warn(kctx->kbdev->dev, + "ctx:%d_%d kcpu queue:%u faulty fence[%pK] context#seqno:%s error(%d)", + kctx->tgid, kctx->id, kcpu_queue->id, fence, info.name, info.status); + } + + kbase_fence_put(fence); +} + +/** + * fence_timeout_start() - Start a timer to check fence-wait timeout + * + * @cmd: KCPU command queue + * + * Activate a timer to check whether a fence-wait command in the queue + * gets completed within FENCE_WAIT_TIMEOUT_MS + */ +static void fence_timeout_start(struct kbase_kcpu_command_queue *cmd) +{ + mod_timer(&cmd->fence_timeout, jiffies + msecs_to_jiffies(FENCE_WAIT_TIMEOUT_MS)); +} +#endif + /** * kbase_kcpu_fence_wait_process() - Process the kcpu fence wait command * @@ -1254,8 +1343,9 @@ static int kbase_kcpu_fence_wait_process( #else struct dma_fence *fence; #endif + struct kbase_context *const kctx = kcpu_queue->kctx; - lockdep_assert_held(&kcpu_queue->kctx->csf.kcpu_queues.lock); + lockdep_assert_held(&kctx->csf.kcpu_queues.lock); if (WARN_ON(!fence_info->fence)) return -EINVAL; @@ -1269,14 +1359,26 @@ static int kbase_kcpu_fence_wait_process( &fence_info->fence_cb, kbase_csf_fence_wait_callback); - KBASE_KTRACE_ADD_CSF_KCPU(kcpu_queue->kctx->kbdev, - FENCE_WAIT_START, kcpu_queue, + KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, + KCPU_FENCE_WAIT_START, kcpu_queue, fence->context, fence->seqno); fence_status = cb_err; - if (cb_err == 0) + if (cb_err == 0) { kcpu_queue->fence_wait_processed = true; - else if (cb_err == -ENOENT) +#ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG + fence_timeout_start(kcpu_queue); +#endif + } else if (cb_err == -ENOENT) { fence_status = dma_fence_get_status(fence); + if (!fence_status) { + struct kbase_sync_fence_info info; + + kbase_sync_fence_info_get(fence, &info); + dev_warn(kctx->kbdev->dev, + "Unexpected status for fence %s of ctx:%d_%d kcpu queue:%u", + info.name, kctx->tgid, kctx->id, kcpu_queue->id); + } + } } /* @@ -1321,7 +1423,6 @@ static int kbase_kcpu_fence_wait_prepare( current_command->type = BASE_KCPU_COMMAND_TYPE_FENCE_WAIT; current_command->info.fence.fence = fence_in; current_command->info.fence.kcpu_queue = kcpu_queue; - return 0; } @@ -1343,7 +1444,7 @@ static int kbase_kcpu_fence_signal_process( ret = 0; } - KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, FENCE_SIGNAL, kcpu_queue, + KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, KCPU_FENCE_SIGNAL, kcpu_queue, fence_info->fence->context, fence_info->fence->seqno); @@ -1465,7 +1566,7 @@ static int delete_queue(struct kbase_context *kctx, u32 id) struct kbase_kcpu_command_queue *queue = kctx->csf.kcpu_queues.array[id]; - KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, KCPU_QUEUE_DESTROY, + KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, KCPU_QUEUE_DELETE, queue, queue->num_pending_cmds, queue->cqs_wait_count); /* Drain the remaining work for this queue first and go past @@ -2221,8 +2322,11 @@ int kbase_csf_kcpu_queue_new(struct kbase_context *kctx, KBASE_TLSTREAM_TL_KBASE_NEW_KCPUQUEUE(kctx->kbdev, queue, queue->id, kctx->id, queue->num_pending_cmds); - KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, KCPU_QUEUE_NEW, queue, + KBASE_KTRACE_ADD_CSF_KCPU(kctx->kbdev, KCPU_QUEUE_CREATE, queue, queue->fence_context, 0); +#ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG + kbase_timer_setup(&queue->fence_timeout, fence_timeout_callback); +#endif out: mutex_unlock(&kctx->csf.kcpu_queues.lock); diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.h index ba702d0ae281..a4db86984721 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.h @@ -47,9 +47,9 @@ struct kbase_kcpu_command_import_info { * struct kbase_kcpu_command_fence_info - Structure which holds information * about the fence object enqueued in the kcpu command queue * - * @fence_cb: Fence callback - * @fence: Fence - * @kcpu_queue: kcpu command queue + * @fence_cb: Fence callback + * @fence: Fence + * @kcpu_queue: kcpu command queue */ struct kbase_kcpu_command_fence_info { #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) @@ -271,6 +271,7 @@ struct kbase_kcpu_command { * or without errors since last cleaned. * @jit_blocked: Used to keep track of command queues blocked * by a pending JIT allocation command. + * @fence_timeout: Timer used to detect the fence wait timeout. */ struct kbase_kcpu_command_queue { struct kbase_context *kctx; @@ -287,6 +288,9 @@ struct kbase_kcpu_command_queue { bool command_started; struct list_head jit_blocked; bool has_error; +#ifdef CONFIG_MALI_BIFROST_FENCE_DEBUG + struct timer_list fence_timeout; +#endif /* CONFIG_MALI_BIFROST_FENCE_DEBUG */ }; /** diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu_debugfs.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu_debugfs.c index b195afacb005..fa877778ca79 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu_debugfs.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu_debugfs.c @@ -167,11 +167,7 @@ static const struct file_operations kbasep_csf_kcpu_debugfs_fops = { void kbase_csf_kcpu_debugfs_init(struct kbase_context *kctx) { struct dentry *file; -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) const mode_t mode = 0444; -#else - const mode_t mode = 0400; -#endif if (WARN_ON(!kctx || IS_ERR_OR_NULL(kctx->kctx_dentry))) return; diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_registers.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_registers.h index 8257a3ea84ea..177569bfb427 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_registers.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_registers.h @@ -387,7 +387,7 @@ /* CS_BASE register */ #define CS_BASE_POINTER_SHIFT 0 -#define CS_BASE_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_BASE_POINTER_SHIFT) +#define CS_BASE_POINTER_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_BASE_POINTER_SHIFT) #define CS_BASE_POINTER_GET(reg_val) (((reg_val)&CS_BASE_POINTER_MASK) >> CS_BASE_POINTER_SHIFT) #define CS_BASE_POINTER_SET(reg_val, value) \ (((reg_val) & ~CS_BASE_POINTER_MASK) | (((value) << CS_BASE_POINTER_SHIFT) & CS_BASE_POINTER_MASK)) @@ -401,7 +401,8 @@ /* CS_TILER_HEAP_START register */ #define CS_TILER_HEAP_START_POINTER_SHIFT 0 -#define CS_TILER_HEAP_START_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_TILER_HEAP_START_POINTER_SHIFT) +#define CS_TILER_HEAP_START_POINTER_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_TILER_HEAP_START_POINTER_SHIFT) #define CS_TILER_HEAP_START_POINTER_GET(reg_val) \ (((reg_val)&CS_TILER_HEAP_START_POINTER_MASK) >> CS_TILER_HEAP_START_POINTER_SHIFT) #define CS_TILER_HEAP_START_POINTER_SET(reg_val, value) \ @@ -412,7 +413,8 @@ /* CS_TILER_HEAP_END register */ #define CS_TILER_HEAP_END_POINTER_SHIFT 0 -#define CS_TILER_HEAP_END_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_TILER_HEAP_END_POINTER_SHIFT) +#define CS_TILER_HEAP_END_POINTER_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_TILER_HEAP_END_POINTER_SHIFT) #define CS_TILER_HEAP_END_POINTER_GET(reg_val) \ (((reg_val)&CS_TILER_HEAP_END_POINTER_MASK) >> CS_TILER_HEAP_END_POINTER_SHIFT) #define CS_TILER_HEAP_END_POINTER_SET(reg_val, value) \ @@ -423,7 +425,7 @@ /* CS_USER_INPUT register */ #define CS_USER_INPUT_POINTER_SHIFT 0 -#define CS_USER_INPUT_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_USER_INPUT_POINTER_SHIFT) +#define CS_USER_INPUT_POINTER_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_USER_INPUT_POINTER_SHIFT) #define CS_USER_INPUT_POINTER_GET(reg_val) (((reg_val)&CS_USER_INPUT_POINTER_MASK) >> CS_USER_INPUT_POINTER_SHIFT) #define CS_USER_INPUT_POINTER_SET(reg_val, value) \ (((reg_val) & ~CS_USER_INPUT_POINTER_MASK) | \ @@ -431,7 +433,7 @@ /* CS_USER_OUTPUT register */ #define CS_USER_OUTPUT_POINTER_SHIFT 0 -#define CS_USER_OUTPUT_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_USER_OUTPUT_POINTER_SHIFT) +#define CS_USER_OUTPUT_POINTER_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_USER_OUTPUT_POINTER_SHIFT) #define CS_USER_OUTPUT_POINTER_GET(reg_val) (((reg_val)&CS_USER_OUTPUT_POINTER_MASK) >> CS_USER_OUTPUT_POINTER_SHIFT) #define CS_USER_OUTPUT_POINTER_SET(reg_val, value) \ (((reg_val) & ~CS_USER_OUTPUT_POINTER_MASK) | \ @@ -470,7 +472,8 @@ /* CS_INSTR_BUFFER_BASE register */ #define CS_INSTR_BUFFER_BASE_POINTER_SHIFT (0) -#define CS_INSTR_BUFFER_BASE_POINTER_MASK ((u64)0xFFFFFFFFFFFFFFFF << CS_INSTR_BUFFER_BASE_POINTER_SHIFT) +#define CS_INSTR_BUFFER_BASE_POINTER_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_INSTR_BUFFER_BASE_POINTER_SHIFT) #define CS_INSTR_BUFFER_BASE_POINTER_GET(reg_val) \ (((reg_val)&CS_INSTR_BUFFER_BASE_POINTER_MASK) >> CS_INSTR_BUFFER_BASE_POINTER_SHIFT) #define CS_INSTR_BUFFER_BASE_POINTER_SET(reg_val, value) \ @@ -479,8 +482,8 @@ /* CS_INSTR_BUFFER_OFFSET_POINTER register */ #define CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_SHIFT (0) -#define CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_MASK \ - (((u64)0xFFFFFFFFFFFFFFFF) << CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_SHIFT) +#define CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_MASK \ + ((GPU_ULL(0xFFFFFFFFFFFFFFFF)) << CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_SHIFT) #define CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_GET(reg_val) \ (((reg_val)&CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_MASK) >> CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_SHIFT) #define CS_INSTR_BUFFER_OFFSET_POINTER_POINTER_SET(reg_val, value) \ @@ -529,7 +532,8 @@ /* CS_STATUS_CMD_PTR register */ #define CS_STATUS_CMD_PTR_POINTER_SHIFT 0 -#define CS_STATUS_CMD_PTR_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_STATUS_CMD_PTR_POINTER_SHIFT) +#define CS_STATUS_CMD_PTR_POINTER_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_STATUS_CMD_PTR_POINTER_SHIFT) #define CS_STATUS_CMD_PTR_POINTER_GET(reg_val) \ (((reg_val)&CS_STATUS_CMD_PTR_POINTER_MASK) >> CS_STATUS_CMD_PTR_POINTER_SHIFT) #define CS_STATUS_CMD_PTR_POINTER_SET(reg_val, value) \ @@ -608,7 +612,8 @@ /* CS_STATUS_WAIT_SYNC_POINTER register */ #define CS_STATUS_WAIT_SYNC_POINTER_POINTER_SHIFT 0 -#define CS_STATUS_WAIT_SYNC_POINTER_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_STATUS_WAIT_SYNC_POINTER_POINTER_SHIFT) +#define CS_STATUS_WAIT_SYNC_POINTER_POINTER_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_STATUS_WAIT_SYNC_POINTER_POINTER_SHIFT) #define CS_STATUS_WAIT_SYNC_POINTER_POINTER_GET(reg_val) \ (((reg_val)&CS_STATUS_WAIT_SYNC_POINTER_POINTER_MASK) >> CS_STATUS_WAIT_SYNC_POINTER_POINTER_SHIFT) #define CS_STATUS_WAIT_SYNC_POINTER_POINTER_SET(reg_val, value) \ @@ -694,6 +699,7 @@ (((value) << CS_FATAL_EXCEPTION_TYPE_SHIFT) & CS_FATAL_EXCEPTION_TYPE_MASK)) /* CS_FATAL_EXCEPTION_TYPE values */ #define CS_FATAL_EXCEPTION_TYPE_CS_CONFIG_FAULT 0x40 +#define CS_FATAL_EXCEPTION_TYPE_CS_UNRECOVERABLE 0x41 #define CS_FATAL_EXCEPTION_TYPE_CS_ENDPOINT_FAULT 0x44 #define CS_FATAL_EXCEPTION_TYPE_CS_BUS_FAULT 0x48 #define CS_FATAL_EXCEPTION_TYPE_CS_INVALID_INSTRUCTION 0x49 @@ -709,7 +715,8 @@ /* CS_FAULT_INFO register */ #define CS_FAULT_INFO_EXCEPTION_DATA_SHIFT 0 -#define CS_FAULT_INFO_EXCEPTION_DATA_MASK (0xFFFFFFFFFFFFFFFF << CS_FAULT_INFO_EXCEPTION_DATA_SHIFT) +#define CS_FAULT_INFO_EXCEPTION_DATA_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_FAULT_INFO_EXCEPTION_DATA_SHIFT) #define CS_FAULT_INFO_EXCEPTION_DATA_GET(reg_val) \ (((reg_val)&CS_FAULT_INFO_EXCEPTION_DATA_MASK) >> CS_FAULT_INFO_EXCEPTION_DATA_SHIFT) #define CS_FAULT_INFO_EXCEPTION_DATA_SET(reg_val, value) \ @@ -718,7 +725,8 @@ /* CS_FATAL_INFO register */ #define CS_FATAL_INFO_EXCEPTION_DATA_SHIFT 0 -#define CS_FATAL_INFO_EXCEPTION_DATA_MASK (0xFFFFFFFFFFFFFFFF << CS_FATAL_INFO_EXCEPTION_DATA_SHIFT) +#define CS_FATAL_INFO_EXCEPTION_DATA_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_FATAL_INFO_EXCEPTION_DATA_SHIFT) #define CS_FATAL_INFO_EXCEPTION_DATA_GET(reg_val) \ (((reg_val)&CS_FATAL_INFO_EXCEPTION_DATA_MASK) >> CS_FATAL_INFO_EXCEPTION_DATA_SHIFT) #define CS_FATAL_INFO_EXCEPTION_DATA_SET(reg_val, value) \ @@ -750,7 +758,7 @@ /* CS_HEAP_ADDRESS register */ #define CS_HEAP_ADDRESS_POINTER_SHIFT 0 -#define CS_HEAP_ADDRESS_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CS_HEAP_ADDRESS_POINTER_SHIFT) +#define CS_HEAP_ADDRESS_POINTER_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_HEAP_ADDRESS_POINTER_SHIFT) #define CS_HEAP_ADDRESS_POINTER_GET(reg_val) (((reg_val)&CS_HEAP_ADDRESS_POINTER_MASK) >> CS_HEAP_ADDRESS_POINTER_SHIFT) #define CS_HEAP_ADDRESS_POINTER_SET(reg_val, value) \ (((reg_val) & ~CS_HEAP_ADDRESS_POINTER_MASK) | \ @@ -761,14 +769,14 @@ /* CS_INSERT register */ #define CS_INSERT_VALUE_SHIFT 0 -#define CS_INSERT_VALUE_MASK (0xFFFFFFFFFFFFFFFF << CS_INSERT_VALUE_SHIFT) +#define CS_INSERT_VALUE_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_INSERT_VALUE_SHIFT) #define CS_INSERT_VALUE_GET(reg_val) (((reg_val)&CS_INSERT_VALUE_MASK) >> CS_INSERT_VALUE_SHIFT) #define CS_INSERT_VALUE_SET(reg_val, value) \ (((reg_val) & ~CS_INSERT_VALUE_MASK) | (((value) << CS_INSERT_VALUE_SHIFT) & CS_INSERT_VALUE_MASK)) /* CS_EXTRACT_INIT register */ #define CS_EXTRACT_INIT_VALUE_SHIFT 0 -#define CS_EXTRACT_INIT_VALUE_MASK (0xFFFFFFFFFFFFFFFF << CS_EXTRACT_INIT_VALUE_SHIFT) +#define CS_EXTRACT_INIT_VALUE_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_EXTRACT_INIT_VALUE_SHIFT) #define CS_EXTRACT_INIT_VALUE_GET(reg_val) (((reg_val)&CS_EXTRACT_INIT_VALUE_MASK) >> CS_EXTRACT_INIT_VALUE_SHIFT) #define CS_EXTRACT_INIT_VALUE_SET(reg_val, value) \ (((reg_val) & ~CS_EXTRACT_INIT_VALUE_MASK) | \ @@ -779,7 +787,7 @@ /* CS_EXTRACT register */ #define CS_EXTRACT_VALUE_SHIFT 0 -#define CS_EXTRACT_VALUE_MASK (0xFFFFFFFFFFFFFFFF << CS_EXTRACT_VALUE_SHIFT) +#define CS_EXTRACT_VALUE_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CS_EXTRACT_VALUE_SHIFT) #define CS_EXTRACT_VALUE_GET(reg_val) (((reg_val)&CS_EXTRACT_VALUE_MASK) >> CS_EXTRACT_VALUE_SHIFT) #define CS_EXTRACT_VALUE_SET(reg_val, value) \ (((reg_val) & ~CS_EXTRACT_VALUE_MASK) | (((value) << CS_EXTRACT_VALUE_SHIFT) & CS_EXTRACT_VALUE_MASK)) @@ -932,7 +940,7 @@ /* CSG_SUSPEND_BUF register */ #define CSG_SUSPEND_BUF_POINTER_SHIFT 0 -#define CSG_SUSPEND_BUF_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CSG_SUSPEND_BUF_POINTER_SHIFT) +#define CSG_SUSPEND_BUF_POINTER_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CSG_SUSPEND_BUF_POINTER_SHIFT) #define CSG_SUSPEND_BUF_POINTER_GET(reg_val) (((reg_val)&CSG_SUSPEND_BUF_POINTER_MASK) >> CSG_SUSPEND_BUF_POINTER_SHIFT) #define CSG_SUSPEND_BUF_POINTER_SET(reg_val, value) \ (((reg_val) & ~CSG_SUSPEND_BUF_POINTER_MASK) | \ @@ -940,7 +948,8 @@ /* CSG_PROTM_SUSPEND_BUF register */ #define CSG_PROTM_SUSPEND_BUF_POINTER_SHIFT 0 -#define CSG_PROTM_SUSPEND_BUF_POINTER_MASK (0xFFFFFFFFFFFFFFFF << CSG_PROTM_SUSPEND_BUF_POINTER_SHIFT) +#define CSG_PROTM_SUSPEND_BUF_POINTER_MASK \ + (GPU_ULL(0xFFFFFFFFFFFFFFFF) << CSG_PROTM_SUSPEND_BUF_POINTER_SHIFT) #define CSG_PROTM_SUSPEND_BUF_POINTER_GET(reg_val) \ (((reg_val)&CSG_PROTM_SUSPEND_BUF_POINTER_MASK) >> CSG_PROTM_SUSPEND_BUF_POINTER_SHIFT) #define CSG_PROTM_SUSPEND_BUF_POINTER_SET(reg_val, value) \ @@ -1408,7 +1417,7 @@ /* GLB_ALLOC_EN register */ #define GLB_ALLOC_EN_MASK_SHIFT 0 -#define GLB_ALLOC_EN_MASK_MASK (0xFFFFFFFFFFFFFFFF << GLB_ALLOC_EN_MASK_SHIFT) +#define GLB_ALLOC_EN_MASK_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << GLB_ALLOC_EN_MASK_SHIFT) #define GLB_ALLOC_EN_MASK_GET(reg_val) (((reg_val)&GLB_ALLOC_EN_MASK_MASK) >> GLB_ALLOC_EN_MASK_SHIFT) #define GLB_ALLOC_EN_MASK_SET(reg_val, value) \ (((reg_val) & ~GLB_ALLOC_EN_MASK_MASK) | (((value) << GLB_ALLOC_EN_MASK_SHIFT) & GLB_ALLOC_EN_MASK_MASK)) @@ -1549,5 +1558,16 @@ (((reg_val) & ~GLB_PRFCNT_SIZE_HARDWARE_SIZE_MASK) | \ ((GLB_PRFCNT_SIZE_HARDWARE_SIZE_SET_MOD(value) << GLB_PRFCNT_SIZE_HARDWARE_SIZE_SHIFT) & \ GLB_PRFCNT_SIZE_HARDWARE_SIZE_MASK)) +#define GLB_PRFCNT_SIZE_FIRMWARE_SIZE_SET_MOD(value) ((value) >> 8) +#define GLB_PRFCNT_SIZE_FIRMWARE_SIZE_GET_MOD(value) ((value) << 8) +#define GLB_PRFCNT_SIZE_FIRMWARE_SIZE_SHIFT GPU_U(16) +#define GLB_PRFCNT_SIZE_FIRMWARE_SIZE_MASK (GPU_U(0xFFFF) << GLB_PRFCNT_SIZE_FIRMWARE_SIZE_SHIFT) +#define GLB_PRFCNT_SIZE_FIRMWARE_SIZE_GET(reg_val) \ + (GLB_PRFCNT_SIZE_FIRMWARE_SIZE_GET_MOD(((reg_val)&GLB_PRFCNT_SIZE_FIRMWARE_SIZE_MASK) >> \ + GLB_PRFCNT_SIZE_FIRMWARE_SIZE_SHIFT)) +#define GLB_PRFCNT_SIZE_FIRMWARE_SIZE_SET(reg_val, value) \ + (((reg_val) & ~GLB_PRFCNT_SIZE_FIRMWARE_SIZE_MASK) | \ + ((GLB_PRFCNT_SIZE_FIRMWARE_SIZE_SET_MOD(value) << GLB_PRFCNT_SIZE_FIRMWARE_SIZE_SHIFT) & \ + GLB_PRFCNT_SIZE_FIRMWARE_SIZE_MASK)) #endif /* _KBASE_CSF_REGISTERS_H_ */ diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.c index cd55bc64c9a2..af3b6912845d 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.c @@ -236,7 +236,7 @@ static enum hrtimer_restart tick_timer_callback(struct hrtimer *timer) struct kbase_device *kbdev = container_of(timer, struct kbase_device, csf.scheduler.tick_timer); - kbase_csf_scheduler_advance_tick(kbdev); + kbase_csf_scheduler_tick_advance(kbdev); return HRTIMER_NORESTART; } @@ -476,7 +476,7 @@ void kbase_csf_scheduler_process_gpu_idle_event(struct kbase_device *kbdev) non_idle_offslot_grps = atomic_read(&scheduler->non_idle_offslot_grps); can_suspend_on_idle = kbase_pm_idle_groups_sched_suspendable(kbdev); - KBASE_KTRACE_ADD(kbdev, SCHEDULER_CAN_IDLE, NULL, + KBASE_KTRACE_ADD(kbdev, SCHEDULER_GPU_IDLE_EVENT_CAN_SUSPEND, NULL, ((u64)(u32)non_idle_offslot_grps) | (((u64)can_suspend_on_idle) << 32)); if (!non_idle_offslot_grps) { @@ -490,7 +490,7 @@ void kbase_csf_scheduler_process_gpu_idle_event(struct kbase_device *kbdev) } } else { /* Advance the scheduling tick to get the non-idle suspended groups loaded soon */ - kbase_csf_scheduler_advance_tick_nolock(kbdev); + kbase_csf_scheduler_tick_advance_nolock(kbdev); } } @@ -560,6 +560,12 @@ static bool on_slot_group_idle_locked(struct kbase_queue_group *group) return (group->run_state == KBASE_CSF_GROUP_IDLE); } +static bool can_schedule_idle_group(struct kbase_queue_group *group) +{ + return (on_slot_group_idle_locked(group) || + (group->priority == KBASE_QUEUE_GROUP_PRIORITY_REALTIME)); +} + static bool queue_group_scheduled(struct kbase_queue_group *group) { return (group->run_state != KBASE_CSF_GROUP_INACTIVE && @@ -575,7 +581,7 @@ static bool queue_group_scheduled_locked(struct kbase_queue_group *group) } /** - * scheduler_wait_protm_quit() - Wait for GPU to exit protected mode. + * scheduler_protm_wait_quit() - Wait for GPU to exit protected mode. * * @kbdev: Pointer to the GPU device * @@ -584,7 +590,7 @@ static bool queue_group_scheduled_locked(struct kbase_queue_group *group) * * Return: true on success, false otherwise. */ -static bool scheduler_wait_protm_quit(struct kbase_device *kbdev) +static bool scheduler_protm_wait_quit(struct kbase_device *kbdev) { struct kbase_csf_scheduler *const scheduler = &kbdev->csf.scheduler; long wt = kbase_csf_timeout_in_jiffies(kbdev->csf.fw_timeout_ms); @@ -593,8 +599,7 @@ static bool scheduler_wait_protm_quit(struct kbase_device *kbdev) lockdep_assert_held(&scheduler->lock); - KBASE_KTRACE_ADD(kbdev, SCHEDULER_WAIT_PROTM_QUIT, NULL, - jiffies_to_msecs(wt)); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_PROTM_WAIT_QUIT_START, NULL, jiffies_to_msecs(wt)); remaining = wait_event_timeout(kbdev->csf.event_wait, !kbase_csf_scheduler_protected_mode_in_use(kbdev), wt); @@ -606,8 +611,7 @@ static bool scheduler_wait_protm_quit(struct kbase_device *kbdev) success = false; } - KBASE_KTRACE_ADD(kbdev, SCHEDULER_WAIT_PROTM_QUIT_DONE, NULL, - jiffies_to_msecs(remaining)); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_PROTM_WAIT_QUIT_END, NULL, jiffies_to_msecs(remaining)); return success; } @@ -631,7 +635,7 @@ static void scheduler_force_protm_exit(struct kbase_device *kbdev) kbase_csf_firmware_ping(kbdev); - if (scheduler_wait_protm_quit(kbdev)) + if (scheduler_protm_wait_quit(kbdev)) return; dev_err(kbdev->dev, "Possible GPU hang in Protected mode"); @@ -958,8 +962,8 @@ static void update_idle_suspended_group_state(struct kbase_queue_group *group) return; new_val = atomic_inc_return(&scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(group->kctx->kbdev, SCHEDULER_NONIDLE_OFFSLOT_INC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(group->kctx->kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_INC, group, + new_val); } int kbase_csf_scheduler_group_get_slot_locked(struct kbase_queue_group *group) @@ -1086,7 +1090,7 @@ static int halt_stream_sync(struct kbase_queue *queue) kbase_csf_firmware_cs_input_mask(stream, CS_REQ, CS_REQ_STATE_STOP, CS_REQ_STATE_MASK); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_STOP_REQUESTED, group, queue, 0u); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_STOP_REQ, group, queue, 0u); kbase_csf_ring_cs_kernel_doorbell(kbdev, csi_index, group->csg_nr, true); /* Timed wait */ @@ -1159,8 +1163,7 @@ static int sched_halt_stream(struct kbase_queue *queue) long remaining; int slot; int err = 0; - const u32 group_schedule_timeout = - 20 * kbdev->csf.scheduler.csg_scheduling_period_ms; + const u32 group_schedule_timeout = kbase_get_timeout_ms(kbdev, CSF_CSG_SUSPEND_TIMEOUT); if (WARN_ON(!group)) return -EINVAL; @@ -1531,8 +1534,8 @@ int kbase_csf_scheduler_queue_start(struct kbase_queue *queue) KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_START, group, queue, group->run_state); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_STATUS_WAIT, queue->group, - queue, queue->status_wait); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_WAIT_STATUS, queue->group, queue, + queue->status_wait); if (group->run_state == KBASE_CSF_GROUP_FAULT_EVICTED) { err = -EIO; @@ -1564,9 +1567,9 @@ int kbase_csf_scheduler_queue_start(struct kbase_queue *queue) } else program_cs(kbdev, queue, true); } - queue_delayed_work(system_long_wq, - &kbdev->csf.scheduler.ping_work, - msecs_to_jiffies(FIRMWARE_PING_INTERVAL_MS)); + queue_delayed_work(system_long_wq, &kbdev->csf.scheduler.ping_work, + msecs_to_jiffies(kbase_get_timeout_ms( + kbdev, CSF_FIRMWARE_PING_TIMEOUT))); } } @@ -1601,7 +1604,8 @@ static enum kbase_csf_csg_slot_state update_csg_slot_status( slot_state = CSG_SLOT_RUNNING; atomic_set(&csg_slot->state, slot_state); csg_slot->trigger_jiffies = jiffies; - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_STARTED, csg_slot->resident_group, state); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_RUNNING, csg_slot->resident_group, + state); dev_dbg(kbdev->dev, "Group %u running on slot %d\n", csg_slot->resident_group->handle, slot); } @@ -1716,7 +1720,7 @@ static void halt_csg_slot(struct kbase_queue_group *group, bool suspend) flags); atomic_set(&csg_slot[slot].state, CSG_SLOT_DOWN2STOP); csg_slot[slot].trigger_jiffies = jiffies; - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_STOP, group, halt_cmd); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_STOP_REQ, group, halt_cmd); KBASE_TLSTREAM_TL_KBASE_DEVICE_HALT_CSG( kbdev, kbdev->gpu_props.props.raw_props.gpu_id, slot); @@ -1760,10 +1764,10 @@ static bool evaluate_sync_update(struct kbase_queue *queue) sync_ptr = kbase_phy_alloc_mapping_get(queue->kctx, queue->sync_ptr, &mapping); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE, queue->group, - queue, queue->sync_ptr); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_BLOCKED_REASON, - queue->group, queue, queue->blocked_reason); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_EVAL_START, queue->group, queue, + queue->sync_ptr); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_BLOCKED_REASON, queue->group, queue, + queue->blocked_reason); if (!sync_ptr) { dev_dbg(queue->kctx->kbdev->dev, "sync memory VA 0x%016llX already freed", @@ -1778,11 +1782,11 @@ static bool evaluate_sync_update(struct kbase_queue *queue) (sync_wait_cond != CS_STATUS_WAIT_SYNC_WAIT_CONDITION_LE)); sync_current_val = READ_ONCE(*sync_ptr); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_CURRENT_VAL, queue->group, - queue, sync_current_val); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_CUR_VAL, queue->group, queue, + sync_current_val); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_TEST_VAL, queue->group, - queue, queue->sync_value); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_TEST_VAL, queue->group, queue, + queue->sync_value); if (((sync_wait_cond == CS_STATUS_WAIT_SYNC_WAIT_CONDITION_GT) && (sync_current_val > queue->sync_value)) || @@ -1799,8 +1803,7 @@ static bool evaluate_sync_update(struct kbase_queue *queue) kbase_phy_alloc_mapping_put(queue->kctx, mapping); out: - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_EVALUATED, - queue->group, queue, updated); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_EVAL_END, queue->group, queue, updated); return updated; } @@ -1834,8 +1837,8 @@ bool save_slot_cs(struct kbase_csf_cmd_stream_group_info const *const ginfo, queue->saved_cmd_ptr = cmd_ptr; #endif - KBASE_KTRACE_ADD_CSF_GRP_Q(stream->kbdev, QUEUE_SYNC_STATUS_WAIT, - queue->group, queue, status); + KBASE_KTRACE_ADD_CSF_GRP_Q(stream->kbdev, QUEUE_SYNC_UPDATE_WAIT_STATUS, queue->group, + queue, status); if (CS_STATUS_WAIT_SYNC_WAIT_GET(status)) { queue->status_wait = status; @@ -1921,7 +1924,7 @@ void insert_group_to_runnable(struct kbase_csf_scheduler *const scheduler, list_add_tail(&group->link, &kctx->csf.sched.runnable_groups[group->priority]); kctx->csf.sched.num_runnable_grps++; - KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_INSERT_RUNNABLE, group, + KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_RUNNABLE_INSERT, group, kctx->csf.sched.num_runnable_grps); /* Add the kctx if not yet in runnable kctxs */ @@ -1929,7 +1932,7 @@ void insert_group_to_runnable(struct kbase_csf_scheduler *const scheduler, /* First runnable csg, adds to the runnable_kctxs */ INIT_LIST_HEAD(&kctx->csf.link); list_add_tail(&kctx->csf.link, &scheduler->runnable_kctxs); - KBASE_KTRACE_ADD(kbdev, SCHEDULER_INSERT_RUNNABLE, kctx, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_RUNNABLE_KCTX_INSERT, kctx, 0u); } scheduler->total_runnable_grps++; @@ -1986,7 +1989,7 @@ void remove_group_from_runnable(struct kbase_csf_scheduler *const scheduler, if (kbase_prepare_to_reset_gpu(kctx->kbdev, RESET_FLAGS_NONE)) kbase_reset_gpu(kctx->kbdev); - KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, SCHEDULER_EXIT_PROTM, + KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, SCHEDULER_PROTM_EXIT, scheduler->active_protm_grp, 0u); scheduler->active_protm_grp = NULL; } @@ -2016,13 +2019,12 @@ void remove_group_from_runnable(struct kbase_csf_scheduler *const scheduler, } kctx->csf.sched.num_runnable_grps--; - KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_REMOVE_RUNNABLE, group, + KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_RUNNABLE_REMOVE, group, kctx->csf.sched.num_runnable_grps); new_head_grp = (!list_empty(list)) ? list_first_entry(list, struct kbase_queue_group, link) : NULL; - KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_HEAD_RUNNABLE, new_head_grp, - 0u); + KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_RUNNABLE_HEAD, new_head_grp, 0u); if (kctx->csf.sched.num_runnable_grps == 0) { struct kbase_context *new_head_kctx; @@ -2031,13 +2033,11 @@ void remove_group_from_runnable(struct kbase_csf_scheduler *const scheduler, list_del_init(&kctx->csf.link); if (scheduler->top_ctx == kctx) scheduler->top_ctx = NULL; - KBASE_KTRACE_ADD(kctx->kbdev, SCHEDULER_REMOVE_RUNNABLE, kctx, - 0u); + KBASE_KTRACE_ADD(kctx->kbdev, SCHEDULER_RUNNABLE_KCTX_REMOVE, kctx, 0u); new_head_kctx = (!list_empty(kctx_list)) ? list_first_entry(kctx_list, struct kbase_context, csf.link) : NULL; - KBASE_KTRACE_ADD(kctx->kbdev, SCHEDULER_HEAD_RUNNABLE, - new_head_kctx, 0u); + KBASE_KTRACE_ADD(kctx->kbdev, SCHEDULER_RUNNABLE_KCTX_HEAD, new_head_kctx, 0u); } WARN_ON(scheduler->total_runnable_grps == 0); @@ -2064,7 +2064,7 @@ static void insert_group_to_idle_wait(struct kbase_queue_group *const group) list_add_tail(&group->link, &kctx->csf.sched.idle_wait_groups); kctx->csf.sched.num_idle_wait_grps++; - KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_INSERT_IDLE_WAIT, group, + KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_IDLE_WAIT_INSERT, group, kctx->csf.sched.num_idle_wait_grps); group->run_state = KBASE_CSF_GROUP_SUSPENDED_ON_WAIT_SYNC; dev_dbg(kctx->kbdev->dev, @@ -2085,13 +2085,12 @@ static void remove_group_from_idle_wait(struct kbase_queue_group *const group) list_del_init(&group->link); WARN_ON(kctx->csf.sched.num_idle_wait_grps == 0); kctx->csf.sched.num_idle_wait_grps--; - KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_REMOVE_IDLE_WAIT, group, + KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_IDLE_WAIT_REMOVE, group, kctx->csf.sched.num_idle_wait_grps); new_head_grp = (!list_empty(list)) ? list_first_entry(list, struct kbase_queue_group, link) : NULL; - KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_HEAD_IDLE_WAIT, - new_head_grp, 0u); + KBASE_KTRACE_ADD_CSF_GRP(kctx->kbdev, GROUP_IDLE_WAIT_HEAD, new_head_grp, 0u); group->run_state = KBASE_CSF_GROUP_INACTIVE; } @@ -2117,8 +2116,7 @@ static void update_offslot_non_idle_cnt_for_faulty_grp(struct kbase_queue_group if (group->prepared_seq_num < scheduler->non_idle_scanout_grps) { int new_val = atomic_dec_return(&scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_DEC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_DEC, group, new_val); } } @@ -2134,8 +2132,7 @@ static void update_offslot_non_idle_cnt_for_onslot_grp(struct kbase_queue_group if (group->prepared_seq_num < scheduler->non_idle_scanout_grps) { int new_val = atomic_dec_return(&scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_DEC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_DEC, group, new_val); } } @@ -2155,15 +2152,15 @@ static void update_offslot_non_idle_cnt_on_grp_suspend( if (group->run_state == KBASE_CSF_GROUP_SUSPENDED) { int new_val = atomic_inc_return( &scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_INC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_INC, + group, new_val); } } else { if (group->run_state != KBASE_CSF_GROUP_SUSPENDED) { int new_val = atomic_dec_return( &scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_DEC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_DEC, + group, new_val); } } } else { @@ -2171,8 +2168,8 @@ static void update_offslot_non_idle_cnt_on_grp_suspend( if (group->run_state == KBASE_CSF_GROUP_SUSPENDED) { int new_val = atomic_inc_return( &scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_INC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_INC, group, + new_val); } } } @@ -2411,7 +2408,7 @@ static void update_csg_slot_priority(struct kbase_queue_group *group, u8 prio) group->handle, group->kctx->tgid, group->kctx->id, slot, prev_prio, prio); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_PRIO_UPDATE, group, prev_prio); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_PRIO_UPDATE, group, prev_prio); kbase_csf_ring_csg_doorbell(kbdev, slot); set_bit(slot, kbdev->csf.scheduler.csg_slots_prio_update); @@ -2560,10 +2557,9 @@ static void program_csg_slot(struct kbase_queue_group *group, s8 slot, dev_dbg(kbdev->dev, "Starting group %d of context %d_%d on slot %d with priority %u\n", group->handle, kctx->tgid, kctx->id, slot, prio); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_START, group, - (((u64)ep_cfg) << 32) | - ((((u32)kctx->as_nr) & 0xF) << 16) | - (state & (CSG_REQ_STATE_MASK >> CS_REQ_STATE_SHIFT))); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_START_REQ, group, + (((u64)ep_cfg) << 32) | ((((u32)kctx->as_nr) & 0xF) << 16) | + (state & (CSG_REQ_STATE_MASK >> CS_REQ_STATE_SHIFT))); kbase_csf_ring_csg_doorbell(kbdev, slot); @@ -2605,8 +2601,8 @@ static void sched_evict_group(struct kbase_queue_group *group, bool fault, group->run_state == KBASE_CSF_GROUP_RUNNABLE)) { int new_val = atomic_dec_return( &scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_DEC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_DEC, group, + new_val); } for (i = 0; i < MAX_SUPPORTED_STREAMS_PER_GROUP; i++) { @@ -2630,9 +2626,9 @@ static void sched_evict_group(struct kbase_queue_group *group, bool fault, if (fault) group->run_state = KBASE_CSF_GROUP_FAULT_EVICTED; - KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_EVICT_SCHED, group, - (((u64)scheduler->total_runnable_grps) << 32) | - ((u32)group->run_state)); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_EVICT, group, + (((u64)scheduler->total_runnable_grps) << 32) | + ((u32)group->run_state)); dev_dbg(kbdev->dev, "group %d exited scheduler, num_runnable_grps %d\n", group->handle, scheduler->total_runnable_grps); /* Notify a group has been evicted */ @@ -2649,7 +2645,8 @@ static int term_group_sync(struct kbase_queue_group *group) term_csg_slot(group); remaining = wait_event_timeout(kbdev->csf.event_wait, - csg_slot_stopped_locked(kbdev, group->csg_nr), remaining); + group->cs_unrecoverable || csg_slot_stopped_locked(kbdev, group->csg_nr), + remaining); if (!remaining) { dev_warn(kbdev->dev, "[%llu] term request timeout (%d ms) for group %d of context %d_%d on slot %d", @@ -2783,6 +2780,8 @@ static int scheduler_group_schedule(struct kbase_queue_group *group) if (protm_grp && protm_grp != group) { clear_bit((unsigned int)group->csg_nr, scheduler->csg_slots_idle_mask); + /* Request the update to confirm the condition inferred. */ + group->reevaluate_idle_status = true; KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_IDLE_CLEAR, group, scheduler->csg_slots_idle_mask[0]); } @@ -2809,8 +2808,7 @@ static int scheduler_group_schedule(struct kbase_queue_group *group) /* A new group into the scheduler */ new_val = atomic_inc_return( &kbdev->csf.scheduler.non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_INC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_INC, group, new_val); } /* Since a group has become active now, check if GPU needs to be @@ -3448,6 +3446,17 @@ static void wait_csg_slots_finish_prio_update(struct kbase_device *kbdev) } } +static void report_csg_termination(struct kbase_queue_group *const group) +{ + struct base_gpu_queue_group_error + err = { .error_type = BASE_GPU_QUEUE_GROUP_ERROR_FATAL, + .payload = { .fatal_group = { + .status = GPU_EXCEPTION_TYPE_SW_FAULT_2, + } } }; + + kbase_csf_add_group_fatal_error(group, &err); +} + void kbase_csf_scheduler_evict_ctx_slots(struct kbase_device *kbdev, struct kbase_context *kctx, struct list_head *evicted_groups) { @@ -3465,16 +3474,21 @@ void kbase_csf_scheduler_evict_ctx_slots(struct kbase_device *kbdev, */ WARN_ON(!kbase_reset_gpu_is_active(kbdev)); - KBASE_KTRACE_ADD(kbdev, EVICT_CTX_SLOTS, kctx, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_EVICT_CTX_SLOTS_START, kctx, 0u); for (slot = 0; slot < num_groups; slot++) { group = kbdev->csf.scheduler.csg_slots[slot].resident_group; if (group && group->kctx == kctx) { bool as_fault; + dev_dbg(kbdev->dev, "Evicting group [%d] running on slot [%d] due to reset", + group->handle, group->csg_nr); + term_csg_slot(group); as_fault = cleanup_csg_slot(group); /* remove the group from the scheduler list */ sched_evict_group(group, as_fault, false); + /* signal Userspace that CSG is being terminated */ + report_csg_termination(group); /* return the evicted group to the caller */ list_add_tail(&group->link, evicted_groups); set_bit(slot, slot_mask); @@ -3484,6 +3498,15 @@ void kbase_csf_scheduler_evict_ctx_slots(struct kbase_device *kbdev, dev_info(kbdev->dev, "Evicting context %d_%d slots: 0x%*pb\n", kctx->tgid, kctx->id, num_groups, slot_mask); + /* Fatal errors may have been the cause of the GPU reset + * taking place, in which case we want to make sure that + * we wake up the fatal event queue to notify userspace + * only once. Otherwise, we may have duplicate event + * notifications between the time the first notification + * occurs and the time the GPU is reset. + */ + kbase_event_wakeup(kctx); + mutex_unlock(&scheduler->lock); } @@ -3528,8 +3551,8 @@ static bool scheduler_slot_protm_ack(struct kbase_device *const kbdev, struct kbase_queue *queue = group->bound_queues[i]; clear_bit(i, group->protm_pending_bitmap); - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, PROTM_PENDING_CLEAR, group, - queue, group->protm_pending_bitmap[0]); + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, CSI_PROTM_PEND_CLEAR, group, queue, + group->protm_pending_bitmap[0]); if (!WARN_ON(!queue) && queue->enabled) { struct kbase_csf_cmd_stream_info *stream = @@ -3564,6 +3587,42 @@ static bool scheduler_slot_protm_ack(struct kbase_device *const kbdev, return protm_ack; } +/** + * protm_enter_set_next_pending_seq - Update the scheduler's field of + * tick_protm_pending_seq to that from the next available on-slot protm + * pending CSG. + * + * @kbdev: Pointer to the GPU device. + * + * If applicable, the function updates the scheduler's tick_protm_pending_seq + * field from the next available on-slot protm pending CSG. If not, the field + * is set to KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID. + */ +static void protm_enter_set_next_pending_seq(struct kbase_device *const kbdev) +{ + struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; + u32 num_groups = kbdev->csf.global_iface.group_num; + u32 num_csis = kbdev->csf.global_iface.groups[0].stream_num; + DECLARE_BITMAP(active_csgs, MAX_SUPPORTED_CSGS) = { 0 }; + u32 i; + + kbase_csf_scheduler_spin_lock_assert_held(kbdev); + + bitmap_xor(active_csgs, scheduler->csg_slots_idle_mask, scheduler->csg_inuse_bitmap, + num_groups); + /* Reset the tick's pending protm seq number to invalid initially */ + scheduler->tick_protm_pending_seq = KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID; + for_each_set_bit(i, active_csgs, num_groups) { + struct kbase_queue_group *group = scheduler->csg_slots[i].resident_group; + + /* Set to the next pending protm group's scan_seq_number */ + if ((group != scheduler->active_protm_grp) && + (!bitmap_empty(group->protm_pending_bitmap, num_csis)) && + (group->scan_seq_num < scheduler->tick_protm_pending_seq)) + scheduler->tick_protm_pending_seq = group->scan_seq_num; + } +} + /** * scheduler_group_check_protm_enter - Request the given group to be evaluated * for triggering the protected mode. @@ -3600,8 +3659,7 @@ static void scheduler_group_check_protm_enter(struct kbase_device *const kbdev, */ protm_in_use = kbase_csf_scheduler_protected_mode_in_use(kbdev) || kbdev->protected_mode; - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_CHECK_PROTM_ENTER, input_grp, - protm_in_use); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_PROTM_ENTER_CHECK, input_grp, protm_in_use); /* Firmware samples the PROTM_PEND ACK bit for CSs when * Host sends PROTM_ENTER global request. So if PROTM_PEND ACK bit @@ -3641,13 +3699,13 @@ static void scheduler_group_check_protm_enter(struct kbase_device *const kbdev, /* Switch to protected mode */ scheduler->active_protm_grp = input_grp; - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_ENTER_PROTM, - input_grp, 0u); - /* Reset the tick's pending protm seq number */ - scheduler->tick_protm_pending_seq = - KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID; + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_PROTM_ENTER, input_grp, + 0u); kbase_csf_enter_protected_mode(kbdev); + /* Set the pending protm seq number to the next one */ + protm_enter_set_next_pending_seq(kbdev); + spin_unlock_irqrestore(&scheduler->interrupt_lock, flags); kbase_csf_wait_protected_mode_enter(kbdev); @@ -3812,7 +3870,7 @@ static void scheduler_ctx_scan_groups(struct kbase_device *kbdev, } if (queue_group_idle_locked(group)) { - if (on_slot_group_idle_locked(group)) + if (can_schedule_idle_group(group)) list_add_tail(&group->link_to_schedule, &scheduler->idle_groups_to_schedule); continue; @@ -3898,10 +3956,9 @@ static void scheduler_rotate_groups(struct kbase_device *kbdev) new_head_grp = (!list_empty(list)) ? list_first_entry(list, struct kbase_queue_group, link) : NULL; - KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_ROTATE_RUNNABLE, - top_grp, top_ctx->csf.sched.num_runnable_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_HEAD_RUNNABLE, - new_head_grp, 0u); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_RUNNABLE_ROTATE, top_grp, + top_ctx->csf.sched.num_runnable_grps); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, GROUP_RUNNABLE_HEAD, new_head_grp, 0u); dev_dbg(kbdev->dev, "groups rotated for a context, num_runnable_groups: %u\n", scheduler->top_ctx->csf.sched.num_runnable_grps); @@ -3932,13 +3989,12 @@ static void scheduler_rotate_ctxs(struct kbase_device *kbdev) struct kbase_context *new_head_kctx; list_move_tail(&pos->csf.link, list); - KBASE_KTRACE_ADD(kbdev, SCHEDULER_ROTATE_RUNNABLE, pos, - 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_RUNNABLE_KCTX_ROTATE, pos, 0u); new_head_kctx = (!list_empty(list)) ? list_first_entry(list, struct kbase_context, csf.link) : NULL; - KBASE_KTRACE_ADD(kbdev, SCHEDULER_HEAD_RUNNABLE, - new_head_kctx, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_RUNNABLE_KCTX_HEAD, new_head_kctx, + 0u); dev_dbg(kbdev->dev, "contexts rotated\n"); } } @@ -3953,12 +4009,17 @@ static void scheduler_rotate_ctxs(struct kbase_device *kbdev) * @kbdev: Pointer to the GPU device. * @csg_bitmap: Bitmap of the CSG slots for which * the status update request completed successfully. - * @failed_csg_bitmap: Bitmap of the CSG slots for which + * @failed_csg_bitmap: Bitmap of the idle CSG slots for which * the status update request timedout. * * This function sends a CSG status update request for all the CSG slots - * present in the bitmap scheduler->csg_slots_idle_mask and wait for the - * request to complete. + * present in the bitmap scheduler->csg_slots_idle_mask. Additionally, if + * the group's 'reevaluate_idle_status' field is set, the nominally non-idle + * slots are also included in the status update for a confirmation of their + * status. The function wait for the status update request to complete and + * returns the update completed slots bitmap and any timed out idle-flagged + * slots bitmap. + * * The bits set in the scheduler->csg_slots_idle_mask bitmap are cleared by * this function. */ @@ -3970,35 +4031,71 @@ static void scheduler_update_idle_slots_status(struct kbase_device *kbdev, struct kbase_csf_global_iface *const global_iface = &kbdev->csf.global_iface; unsigned long flags, i; + u32 active_chk = 0; lockdep_assert_held(&scheduler->lock); spin_lock_irqsave(&scheduler->interrupt_lock, flags); - for_each_set_bit(i, scheduler->csg_slots_idle_mask, num_groups) { + + for_each_set_bit(i, scheduler->csg_inuse_bitmap, num_groups) { struct kbase_csf_csg_slot *csg_slot = &scheduler->csg_slots[i]; struct kbase_queue_group *group = csg_slot->resident_group; struct kbase_csf_cmd_stream_group_info *const ginfo = &global_iface->groups[i]; u32 csg_req; + bool idle_flag; - clear_bit(i, scheduler->csg_slots_idle_mask); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_IDLE_CLEAR, group, - scheduler->csg_slots_idle_mask[0]); - if (WARN_ON(!group)) + if (WARN_ON(!group)) { + clear_bit(i, scheduler->csg_inuse_bitmap); + clear_bit(i, scheduler->csg_slots_idle_mask); continue; + } - KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_STATUS_UPDATE, group, - i); + idle_flag = test_bit(i, scheduler->csg_slots_idle_mask); + if (idle_flag || group->reevaluate_idle_status) { + if (idle_flag) { +#ifdef CONFIG_MALI_BIFROST_DEBUG + if (!bitmap_empty(group->protm_pending_bitmap, + ginfo->stream_num)) { + dev_warn(kbdev->dev, + "Idle bit set for group %d of ctx %d_%d on slot %d with pending protm execution", + group->handle, group->kctx->tgid, + group->kctx->id, (int)i); + } +#endif + clear_bit(i, scheduler->csg_slots_idle_mask); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_SLOT_IDLE_CLEAR, group, + scheduler->csg_slots_idle_mask[0]); + } else { + /* Updates include slots for which reevaluation is needed. + * Here one tracks the extra included slots in active_chk. + * For protm pending slots, their status of activeness are + * assured so no need to request an update. + */ + active_chk |= BIT(i); + group->reevaluate_idle_status = false; + } - csg_req = kbase_csf_firmware_csg_output(ginfo, CSG_ACK); - csg_req ^= CSG_REQ_STATUS_UPDATE_MASK; - kbase_csf_firmware_csg_input_mask(ginfo, CSG_REQ, csg_req, - CSG_REQ_STATUS_UPDATE_MASK); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSG_UPDATE_IDLE_SLOT_REQ, group, i); + csg_req = kbase_csf_firmware_csg_output(ginfo, CSG_ACK); + csg_req ^= CSG_REQ_STATUS_UPDATE_MASK; + kbase_csf_firmware_csg_input_mask(ginfo, CSG_REQ, csg_req, + CSG_REQ_STATUS_UPDATE_MASK); - set_bit(i, csg_bitmap); + /* Track the slot update requests in csg_bitmap. + * Note, if the scheduler requested extended update, the resulting + * csg_bitmap would be the idle_flags + active_chk. Otherwise it's + * identical to the idle_flags. + */ + set_bit(i, csg_bitmap); + } else { + group->run_state = KBASE_CSF_GROUP_RUNNABLE; + } } + spin_unlock_irqrestore(&scheduler->interrupt_lock, flags); + /* The groups are aggregated into a single kernel doorbell request */ if (!bitmap_empty(csg_bitmap, num_groups)) { long wt = @@ -4019,9 +4116,19 @@ static void scheduler_update_idle_slots_status(struct kbase_device *kbdev, /* Store the bitmap of timed out slots */ bitmap_copy(failed_csg_bitmap, csg_bitmap, num_groups); csg_bitmap[0] = ~csg_bitmap[0] & db_slots; + + /* Mask off any failed bit position contributed from active ones, as the + * intention is to retain the failed bit pattern contains only those from + * idle flags reporting back to the caller. This way, any failed to update + * original idle flag would be kept as 'idle' (an informed guess, as the + * update did not come to a conclusive result). So will be the failed + * active ones be treated as still 'non-idle'. This is for a graceful + * handling to the unexpected timeout condition. + */ + failed_csg_bitmap[0] &= ~active_chk; + } else { - KBASE_KTRACE_ADD(kbdev, SLOTS_STATUS_UPDATE_ACK, NULL, - db_slots); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_UPDATE_IDLE_SLOTS_ACK, NULL, db_slots); csg_bitmap[0] = db_slots; } } @@ -4100,8 +4207,7 @@ static void scheduler_scan_idle_groups(struct kbase_device *kbdev) list_for_each_entry_safe(group, n, &scheduler->idle_groups_to_schedule, link_to_schedule) { - - WARN_ON(!on_slot_group_idle_locked(group)); + WARN_ON(!can_schedule_idle_group(group)); if (!scheduler->ngrp_to_schedule) { /* keep the top csg's origin */ @@ -4235,7 +4341,7 @@ static bool all_on_slot_groups_remained_idle(struct kbase_device *kbdev) u64 const *output_addr; u64 cur_extract_ofs; - if (!queue) + if (!queue || !queue->user_io_addr) continue; output_addr = (u64 const *)(queue->user_io_addr + PAGE_SIZE); @@ -4336,7 +4442,7 @@ static bool scheduler_suspend_on_idle(struct kbase_device *kbdev) atomic_read( &kbdev->csf.scheduler.non_idle_offslot_grps)); /* Bring forward the next tick */ - kbase_csf_scheduler_advance_tick(kbdev); + kbase_csf_scheduler_tick_advance(kbdev); return false; } @@ -4354,14 +4460,14 @@ static void gpu_idle_worker(struct work_struct *work) bool scheduler_is_idle_suspendable = false; bool all_groups_suspended = false; - KBASE_KTRACE_ADD(kbdev, IDLE_WORKER_BEGIN, NULL, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_GPU_IDLE_WORKER_START, NULL, 0u); #define __ENCODE_KTRACE_INFO(reset, idle, all_suspend) \ (((u32)reset) | (((u32)idle) << 4) | (((u32)all_suspend) << 8)) if (kbase_reset_gpu_try_prevent(kbdev)) { dev_warn(kbdev->dev, "Quit idle for failing to prevent gpu reset.\n"); - KBASE_KTRACE_ADD(kbdev, IDLE_WORKER_END, NULL, + KBASE_KTRACE_ADD(kbdev, SCHEDULER_GPU_IDLE_WORKER_END, NULL, __ENCODE_KTRACE_INFO(true, false, false)); return; } @@ -4369,7 +4475,7 @@ static void gpu_idle_worker(struct work_struct *work) scheduler_is_idle_suspendable = scheduler_idle_suspendable(kbdev); if (scheduler_is_idle_suspendable) { - KBASE_KTRACE_ADD(kbdev, GPU_IDLE_HANDLING_START, NULL, + KBASE_KTRACE_ADD(kbdev, SCHEDULER_GPU_IDLE_WORKER_HANDLING_START, NULL, kbase_csf_ktrace_gpu_cycle_cnt(kbdev)); #ifdef KBASE_PM_RUNTIME if (kbase_pm_gpu_sleep_allowed(kbdev) && @@ -4382,9 +4488,8 @@ static void gpu_idle_worker(struct work_struct *work) mutex_unlock(&scheduler->lock); kbase_reset_gpu_allow(kbdev); - KBASE_KTRACE_ADD(kbdev, IDLE_WORKER_END, NULL, - __ENCODE_KTRACE_INFO(false, - scheduler_is_idle_suspendable, + KBASE_KTRACE_ADD(kbdev, SCHEDULER_GPU_IDLE_WORKER_END, NULL, + __ENCODE_KTRACE_INFO(false, scheduler_is_idle_suspendable, all_groups_suspended)); #undef __ENCODE_KTRACE_INFO } @@ -4440,7 +4545,7 @@ static int scheduler_prepare(struct kbase_device *kbdev) */ atomic_set(&scheduler->non_idle_offslot_grps, scheduler->non_idle_scanout_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_INC, NULL, + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_INC, NULL, scheduler->non_idle_scanout_grps); /* Adds those idle but runnable groups to the scanout list */ @@ -4629,8 +4734,8 @@ redo_local_tock: dev_dbg(kbdev->dev, "Scheduler keep protm exec: group-%d", protm_grp->handle); new_val = atomic_dec_return(&scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_DEC, - protm_grp, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_DEC, protm_grp, + new_val); spin_unlock_irqrestore(&scheduler->interrupt_lock, flags); @@ -4767,7 +4872,7 @@ static void schedule_on_tock(struct work_struct *work) scheduler->state = SCHED_BUSY; /* Undertaking schedule action steps */ - KBASE_KTRACE_ADD(kbdev, SCHEDULER_TOCK, NULL, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_TOCK_START, NULL, 0u); schedule_actions(kbdev, false); /* Record time information on a non-skipped tock */ @@ -4812,8 +4917,7 @@ static void schedule_on_tick(struct work_struct *work) scheduler->state = SCHED_BUSY; /* Undertaking schedule action steps */ - KBASE_KTRACE_ADD(kbdev, SCHEDULER_TICK, NULL, - scheduler->total_runnable_grps); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_TICK_START, NULL, scheduler->total_runnable_grps); schedule_actions(kbdev, true); /* Record time information */ @@ -5074,8 +5178,7 @@ static bool scheduler_handle_reset_in_protected_mode(struct kbase_device *kbdev) * anyways. */ new_val = atomic_inc_return(&scheduler->non_idle_offslot_grps); - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_INC, - group, new_val); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_NONIDLE_OFFSLOT_GRP_INC, group, new_val); } unlock: @@ -5109,8 +5212,8 @@ static void scheduler_inner_reset(struct kbase_device *kbdev) spin_lock_irqsave(&scheduler->interrupt_lock, flags); bitmap_fill(scheduler->csgs_events_enable_mask, MAX_SUPPORTED_CSGS); if (scheduler->active_protm_grp) - KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_EXIT_PROTM, - scheduler->active_protm_grp, 0u); + KBASE_KTRACE_ADD_CSF_GRP(kbdev, SCHEDULER_PROTM_EXIT, scheduler->active_protm_grp, + 0u); scheduler->active_protm_grp = NULL; memset(kbdev->csf.scheduler.csg_slots, 0, num_groups * sizeof(struct kbase_csf_csg_slot)); @@ -5133,7 +5236,7 @@ void kbase_csf_scheduler_reset(struct kbase_device *kbdev) WARN_ON(!kbase_reset_gpu_is_active(kbdev)); - KBASE_KTRACE_ADD(kbdev, SCHEDULER_RESET, NULL, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_RESET_START, NULL, 0u); if (scheduler_handle_reset_in_protected_mode(kbdev) && !suspend_active_queue_groups_on_reset(kbdev)) { @@ -5235,9 +5338,9 @@ static void firmware_aliveness_monitor(struct work_struct *work) kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) kbase_reset_gpu(kbdev); } else if (kbase_csf_scheduler_get_nr_active_csgs(kbdev) == 1) { - queue_delayed_work(system_long_wq, - &kbdev->csf.scheduler.ping_work, - msecs_to_jiffies(FIRMWARE_PING_INTERVAL_MS)); + queue_delayed_work( + system_long_wq, &kbdev->csf.scheduler.ping_work, + msecs_to_jiffies(kbase_get_timeout_ms(kbdev, CSF_FIRMWARE_PING_TIMEOUT))); } kbase_pm_context_idle(kbdev); @@ -5537,7 +5640,7 @@ static bool check_sync_update_for_on_slot_group( stream, CS_STATUS_WAIT); unsigned long flags; - KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_STATUS_WAIT, + KBASE_KTRACE_ADD_CSF_GRP_Q(kbdev, QUEUE_SYNC_UPDATE_WAIT_STATUS, queue->group, queue, status); if (!CS_STATUS_WAIT_SYNC_WAIT_GET(status)) @@ -5579,6 +5682,10 @@ static bool check_sync_update_for_on_slot_group( scheduler->csg_slots_idle_mask[0]); spin_unlock_irqrestore( &scheduler->interrupt_lock, flags); + /* Request the scheduler to confirm the condition inferred + * here inside the protected mode. + */ + group->reevaluate_idle_status = true; group->run_state = KBASE_CSF_GROUP_RUNNABLE; } @@ -5689,7 +5796,7 @@ static void check_group_sync_update_worker(struct work_struct *work) mutex_lock(&scheduler->lock); - KBASE_KTRACE_ADD(kbdev, GROUP_SYNC_UPDATE_WORKER_BEGIN, kctx, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_GROUP_SYNC_UPDATE_WORKER_START, kctx, 0u); if (kctx->csf.sched.num_idle_wait_grps != 0) { struct kbase_queue_group *group, *temp; @@ -5719,7 +5826,7 @@ static void check_group_sync_update_worker(struct work_struct *work) if (!sync_updated && (scheduler->state == SCHED_SLEEPING)) check_sync_update_in_sleep_mode(kbdev); - KBASE_KTRACE_ADD(kbdev, GROUP_SYNC_UPDATE_WORKER_END, kctx, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_GROUP_SYNC_UPDATE_WORKER_END, kctx, 0u); mutex_unlock(&scheduler->lock); } @@ -5729,7 +5836,7 @@ enum kbase_csf_event_callback_action check_group_sync_update_cb(void *param) { struct kbase_context *const kctx = param; - KBASE_KTRACE_ADD(kctx->kbdev, SYNC_UPDATE_EVENT, kctx, 0u); + KBASE_KTRACE_ADD(kctx->kbdev, SCHEDULER_GROUP_SYNC_UPDATE_EVENT, kctx, 0u); queue_work(kctx->csf.sched.sync_update_wq, &kctx->csf.sched.sync_update_work); @@ -5999,24 +6106,12 @@ out: mutex_unlock(&scheduler->lock); } -int kbase_csf_scheduler_pm_suspend(struct kbase_device *kbdev) +int kbase_csf_scheduler_pm_suspend_no_lock(struct kbase_device *kbdev) { - int result = 0; struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; + int result = 0; - /* Cancel any potential queued delayed work(s) */ - cancel_work_sync(&scheduler->tick_work); - cancel_tock_work(scheduler); - - result = kbase_reset_gpu_prevent_and_wait(kbdev); - if (result) { - dev_warn(kbdev->dev, - "Stop PM suspending for failing to prevent gpu reset.\n"); - return result; - } - - mutex_lock(&scheduler->lock); - + lockdep_assert_held(&scheduler->lock); #ifdef KBASE_PM_RUNTIME /* If scheduler is in sleeping state, then MCU needs to be activated * to suspend CSGs. @@ -6043,6 +6138,27 @@ int kbase_csf_scheduler_pm_suspend(struct kbase_device *kbdev) } exit: + return result; +} + +int kbase_csf_scheduler_pm_suspend(struct kbase_device *kbdev) +{ + int result = 0; + struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; + + /* Cancel any potential queued delayed work(s) */ + cancel_work_sync(&scheduler->tick_work); + cancel_tock_work(scheduler); + + result = kbase_reset_gpu_prevent_and_wait(kbdev); + if (result) { + dev_warn(kbdev->dev, "Stop PM suspending for failing to prevent gpu reset.\n"); + return result; + } + + mutex_lock(&scheduler->lock); + + result = kbase_csf_scheduler_pm_suspend_no_lock(kbdev); mutex_unlock(&scheduler->lock); kbase_reset_gpu_allow(kbdev); @@ -6051,17 +6167,24 @@ exit: } KBASE_EXPORT_TEST_API(kbase_csf_scheduler_pm_suspend); -void kbase_csf_scheduler_pm_resume(struct kbase_device *kbdev) +void kbase_csf_scheduler_pm_resume_no_lock(struct kbase_device *kbdev) { struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; - mutex_lock(&scheduler->lock); + lockdep_assert_held(&scheduler->lock); if ((scheduler->total_runnable_grps > 0) && (scheduler->state == SCHED_SUSPENDED)) { dev_info(kbdev->dev, "Scheduler PM resume"); scheduler_wakeup(kbdev, true); } - mutex_unlock(&scheduler->lock); +} + +void kbase_csf_scheduler_pm_resume(struct kbase_device *kbdev) +{ + mutex_lock(&kbdev->csf.scheduler.lock); + + kbase_csf_scheduler_pm_resume_no_lock(kbdev); + mutex_unlock(&kbdev->csf.scheduler.lock); } KBASE_EXPORT_TEST_API(kbase_csf_scheduler_pm_resume); diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.h index a00a9ca168a3..12df5054e573 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -409,6 +409,17 @@ void kbase_csf_scheduler_pm_idle(struct kbase_device *kbdev); */ int kbase_csf_scheduler_wait_mcu_active(struct kbase_device *kbdev); +/** + * kbase_csf_scheduler_pm_resume_no_lock - Reactivate the scheduler on system resume + * + * @kbdev: Instance of a GPU platform device that implements a CSF interface. + * + * This function will make the scheduler resume the scheduling of queue groups + * and take the power managemenet reference, if there are any runnable groups. + * The caller must have acquired the global Scheduler lock. + */ +void kbase_csf_scheduler_pm_resume_no_lock(struct kbase_device *kbdev); + /** * kbase_csf_scheduler_pm_resume - Reactivate the scheduler on system resume * @@ -419,6 +430,19 @@ int kbase_csf_scheduler_wait_mcu_active(struct kbase_device *kbdev); */ void kbase_csf_scheduler_pm_resume(struct kbase_device *kbdev); +/** + * kbase_csf_scheduler_pm_suspend_no_lock - Idle the scheduler on system suspend + * + * @kbdev: Instance of a GPU platform device that implements a CSF interface. + * + * This function will make the scheduler suspend all the running queue groups + * and drop its power managemenet reference. + * The caller must have acquired the global Scheduler lock. + * + * Return: 0 on success. + */ +int kbase_csf_scheduler_pm_suspend_no_lock(struct kbase_device *kbdev); + /** * kbase_csf_scheduler_pm_suspend - Idle the scheduler on system suspend * @@ -448,7 +472,7 @@ static inline bool kbase_csf_scheduler_all_csgs_idle(struct kbase_device *kbdev) } /** - * kbase_csf_scheduler_advance_tick_nolock() - Advance the scheduling tick + * kbase_csf_scheduler_tick_advance_nolock() - Advance the scheduling tick * * @kbdev: Pointer to the device * @@ -458,23 +482,23 @@ static inline bool kbase_csf_scheduler_all_csgs_idle(struct kbase_device *kbdev) * The caller must hold the interrupt lock. */ static inline void -kbase_csf_scheduler_advance_tick_nolock(struct kbase_device *kbdev) +kbase_csf_scheduler_tick_advance_nolock(struct kbase_device *kbdev) { struct kbase_csf_scheduler *const scheduler = &kbdev->csf.scheduler; lockdep_assert_held(&scheduler->interrupt_lock); if (scheduler->tick_timer_active) { - KBASE_KTRACE_ADD(kbdev, SCHEDULER_ADVANCE_TICK, NULL, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_TICK_ADVANCE, NULL, 0u); scheduler->tick_timer_active = false; queue_work(scheduler->wq, &scheduler->tick_work); } else { - KBASE_KTRACE_ADD(kbdev, SCHEDULER_NOADVANCE_TICK, NULL, 0u); + KBASE_KTRACE_ADD(kbdev, SCHEDULER_TICK_NOADVANCE, NULL, 0u); } } /** - * kbase_csf_scheduler_advance_tick() - Advance the scheduling tick + * kbase_csf_scheduler_tick_advance() - Advance the scheduling tick * * @kbdev: Pointer to the device * @@ -482,13 +506,13 @@ kbase_csf_scheduler_advance_tick_nolock(struct kbase_device *kbdev) * immediate execution, but only if the tick hrtimer is active. If the timer * is inactive then the tick work item is already in flight. */ -static inline void kbase_csf_scheduler_advance_tick(struct kbase_device *kbdev) +static inline void kbase_csf_scheduler_tick_advance(struct kbase_device *kbdev) { struct kbase_csf_scheduler *const scheduler = &kbdev->csf.scheduler; unsigned long flags; spin_lock_irqsave(&scheduler->interrupt_lock, flags); - kbase_csf_scheduler_advance_tick_nolock(kbdev); + kbase_csf_scheduler_tick_advance_nolock(kbdev); spin_unlock_irqrestore(&scheduler->interrupt_lock, flags); } diff --git a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_codes_csf.h b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_codes_csf.h index 2506ce184fcf..9e4da9f11787 100644 --- a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_codes_csf.h +++ b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_codes_csf.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -42,67 +42,67 @@ int dummy_array[] = { /* * Generic CSF events */ - KBASE_KTRACE_CODE_MAKE_CODE(EVICT_CTX_SLOTS), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_EVICT_CTX_SLOTS_START), /* info_val[0:7] == fw version_minor * info_val[15:8] == fw version_major * info_val[63:32] == fw version_hash */ - KBASE_KTRACE_CODE_MAKE_CODE(FIRMWARE_BOOT), - KBASE_KTRACE_CODE_MAKE_CODE(FIRMWARE_REBOOT), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TOCK), + KBASE_KTRACE_CODE_MAKE_CODE(CSF_FIRMWARE_BOOT), + KBASE_KTRACE_CODE_MAKE_CODE(CSF_FIRMWARE_REBOOT), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TOCK_START), KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TOCK_END), /* info_val == total number of runnable groups across all kctxs */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TICK), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TICK_START), KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TICK_END), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_RESET), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_RESET_START), /* info_val = timeout in ms */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_WAIT_PROTM_QUIT), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_PROTM_WAIT_QUIT_START), /* info_val = remaining ms timeout, or 0 if timedout */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_WAIT_PROTM_QUIT_DONE), - KBASE_KTRACE_CODE_MAKE_CODE(SYNC_UPDATE_EVENT), - KBASE_KTRACE_CODE_MAKE_CODE(SYNC_UPDATE_EVENT_NOTIFY_GPU), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_PROTM_WAIT_QUIT_END), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_GROUP_SYNC_UPDATE_EVENT), + KBASE_KTRACE_CODE_MAKE_CODE(CSF_SYNC_UPDATE_NOTIFY_GPU_EVENT), /* info_val = JOB_IRQ_STATUS */ - KBASE_KTRACE_CODE_MAKE_CODE(CSF_INTERRUPT), + KBASE_KTRACE_CODE_MAKE_CODE(CSF_INTERRUPT_START), /* info_val = JOB_IRQ_STATUS */ KBASE_KTRACE_CODE_MAKE_CODE(CSF_INTERRUPT_END), /* info_val = JOB_IRQ_STATUS */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_INTERRUPT_PROCESS), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_INTERRUPT_PROCESS_START), /* info_val = GLB_REQ ^ GLB_ACQ */ - KBASE_KTRACE_CODE_MAKE_CODE(GLB_REQ_ACQ), + KBASE_KTRACE_CODE_MAKE_CODE(CSF_INTERRUPT_GLB_REQ_ACK), /* info_val[31:0] = num non idle offslot groups * info_val[32] = scheduler can suspend on idle */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_CAN_IDLE), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_ADVANCE_TICK), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_NOADVANCE_TICK), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_GPU_IDLE_EVENT_CAN_SUSPEND), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TICK_ADVANCE), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_TICK_NOADVANCE), /* kctx is added to the back of the list */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_INSERT_RUNNABLE), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_REMOVE_RUNNABLE), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_RUNNABLE_KCTX_INSERT), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_RUNNABLE_KCTX_REMOVE), /* kctx is moved to the back of the list */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_ROTATE_RUNNABLE), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_HEAD_RUNNABLE), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_RUNNABLE_KCTX_ROTATE), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_RUNNABLE_KCTX_HEAD), - KBASE_KTRACE_CODE_MAKE_CODE(IDLE_WORKER_BEGIN), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_GPU_IDLE_WORKER_START), /* 4-bit encoding of boolean values (ease of reading as hex values) * * info_val[3:0] = was reset active/failed to be prevented * info_val[7:4] = whether scheduler was both idle and suspendable * info_val[11:8] = whether all groups were suspended */ - KBASE_KTRACE_CODE_MAKE_CODE(IDLE_WORKER_END), - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_SYNC_UPDATE_WORKER_BEGIN), - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_SYNC_UPDATE_WORKER_END), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_GPU_IDLE_WORKER_END), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_GROUP_SYNC_UPDATE_WORKER_START), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_GROUP_SYNC_UPDATE_WORKER_END), /* info_val = bitmask of slots that gave an ACK for STATUS_UPDATE */ - KBASE_KTRACE_CODE_MAKE_CODE(SLOTS_STATUS_UPDATE_ACK), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_UPDATE_IDLE_SLOTS_ACK), /* info_val[63:0] = GPU cycle counter, used mainly for benchmarking * purpose. */ - KBASE_KTRACE_CODE_MAKE_CODE(GPU_IDLE_HANDLING_START), - KBASE_KTRACE_CODE_MAKE_CODE(MCU_HALTED), - KBASE_KTRACE_CODE_MAKE_CODE(MCU_IN_SLEEP), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_GPU_IDLE_WORKER_HANDLING_START), + KBASE_KTRACE_CODE_MAKE_CODE(CSF_FIRMWARE_MCU_HALTED), + KBASE_KTRACE_CODE_MAKE_CODE(CSF_FIRMWARE_MCU_SLEEP), /* * Group events @@ -111,17 +111,17 @@ int dummy_array[] = { * info_val[19:16] == as_nr * info_val[63:32] == endpoint config (max number of endpoints allowed) */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_START), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_START_REQ), /* info_val == CSG_REQ state issued */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_STOP), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_STOP_REQ), /* info_val == CSG_ACK state */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_STARTED), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_RUNNING), /* info_val == CSG_ACK state */ KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_STOPPED), /* info_val == slot cleaned */ KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_CLEANED), /* info_val = slot requesting STATUS_UPDATE */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_STATUS_UPDATE), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_UPDATE_IDLE_SLOT_REQ), /* info_val = scheduler's new csg_slots_idle_mask[0] * group->csg_nr indicates which bit was set */ @@ -133,13 +133,13 @@ int dummy_array[] = { */ KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_IDLE_CLEAR), /* info_val == previous priority */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_PRIO_UPDATE), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_SLOT_PRIO_UPDATE), /* info_val == CSG_REQ ^ CSG_ACK */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_SYNC_UPDATE_INTERRUPT), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_INTERRUPT_SYNC_UPDATE), /* info_val == CSG_REQ ^ CSG_ACK */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_IDLE_INTERRUPT), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_INTERRUPT_IDLE), /* info_val == CSG_REQ ^ CSG_ACK */ - KBASE_KTRACE_CODE_MAKE_CODE(CSG_PROGRESS_TIMER_INTERRUPT), + KBASE_KTRACE_CODE_MAKE_CODE(CSG_INTERRUPT_PROGRESS_TIMER_EVENT), /* info_val[31:0] == CSG_REQ ^ CSG_ACQ * info_val[63:32] == CSG_IRQ_REQ ^ CSG_IRQ_ACK */ @@ -152,34 +152,34 @@ int dummy_array[] = { /* info_val[31:0] == new run state of the evicted group * info_val[63:32] == number of runnable groups */ - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_EVICT_SCHED), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_EVICT), /* info_val == new num_runnable_grps * group is added to the back of the list for its priority level */ - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_INSERT_RUNNABLE), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_RUNNABLE_INSERT), /* info_val == new num_runnable_grps */ - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_REMOVE_RUNNABLE), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_RUNNABLE_REMOVE), /* info_val == num_runnable_grps * group is moved to the back of the list for its priority level */ - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_ROTATE_RUNNABLE), - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_HEAD_RUNNABLE), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_RUNNABLE_ROTATE), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_RUNNABLE_HEAD), /* info_val == new num_idle_wait_grps * group is added to the back of the list */ - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_INSERT_IDLE_WAIT), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_IDLE_WAIT_INSERT), /* info_val == new num_idle_wait_grps * group is added to the back of the list */ - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_REMOVE_IDLE_WAIT), - KBASE_KTRACE_CODE_MAKE_CODE(GROUP_HEAD_IDLE_WAIT), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_IDLE_WAIT_REMOVE), + KBASE_KTRACE_CODE_MAKE_CODE(GROUP_IDLE_WAIT_HEAD), /* info_val == is scheduler running with protected mode tasks */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_CHECK_PROTM_ENTER), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_ENTER_PROTM), - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_EXIT_PROTM), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_PROTM_ENTER_CHECK), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_PROTM_ENTER), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_PROTM_EXIT), /* info_val[31:0] == number of GPU address space slots in use * info_val[63:32] == number of runnable groups */ @@ -187,11 +187,11 @@ int dummy_array[] = { /* info_val == new count of off-slot non-idle groups * no group indicates it was set rather than incremented */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_NONIDLE_OFFSLOT_INC), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_NONIDLE_OFFSLOT_GRP_INC), /* info_val == new count of off-slot non-idle groups */ - KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_NONIDLE_OFFSLOT_DEC), + KBASE_KTRACE_CODE_MAKE_CODE(SCHEDULER_NONIDLE_OFFSLOT_GRP_DEC), - KBASE_KTRACE_CODE_MAKE_CODE(PROTM_EVENT_WORKER_BEGIN), + KBASE_KTRACE_CODE_MAKE_CODE(PROTM_EVENT_WORKER_START), KBASE_KTRACE_CODE_MAKE_CODE(PROTM_EVENT_WORKER_END), /* @@ -201,42 +201,42 @@ int dummy_array[] = { KBASE_KTRACE_CODE_MAKE_CODE(CSI_START), /* info_val == queue->enabled before stop */ KBASE_KTRACE_CODE_MAKE_CODE(CSI_STOP), - KBASE_KTRACE_CODE_MAKE_CODE(CSI_STOP_REQUESTED), + KBASE_KTRACE_CODE_MAKE_CODE(CSI_STOP_REQ), /* info_val == CS_REQ ^ CS_ACK that were not processed due to the group * being suspended */ - KBASE_KTRACE_CODE_MAKE_CODE(CSI_IGNORED_INTERRUPTS_GROUP_SUSPEND), + KBASE_KTRACE_CODE_MAKE_CODE(CSI_INTERRUPT_GROUP_SUSPENDS_IGNORED), /* info_val == CS_REQ ^ CS_ACK */ - KBASE_KTRACE_CODE_MAKE_CODE(CSI_FAULT_INTERRUPT), + KBASE_KTRACE_CODE_MAKE_CODE(CSI_INTERRUPT_FAULT), /* info_val == CS_REQ ^ CS_ACK */ - KBASE_KTRACE_CODE_MAKE_CODE(CSI_TILER_OOM_INTERRUPT), + KBASE_KTRACE_CODE_MAKE_CODE(CSI_INTERRUPT_TILER_OOM), /* info_val == CS_REQ ^ CS_ACK */ - KBASE_KTRACE_CODE_MAKE_CODE(CSI_PROTM_PEND_INTERRUPT), + KBASE_KTRACE_CODE_MAKE_CODE(CSI_INTERRUPT_PROTM_PEND), /* info_val == CS_ACK_PROTM_PEND ^ CS_REQ_PROTM_PEND */ KBASE_KTRACE_CODE_MAKE_CODE(CSI_PROTM_ACK), /* info_val == group->run_State (for group the queue is bound to) */ KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_START), KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_STOP), /* info_val == contents of CS_STATUS_WAIT_SYNC_POINTER */ - KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE), + KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE_EVAL_START), /* info_val == bool for result of the evaluation */ - KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE_EVALUATED), + KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE_EVAL_END), /* info_val == contents of CS_STATUS_WAIT */ - KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_STATUS_WAIT), + KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE_WAIT_STATUS), /* info_val == current sync value pointed to by queue->sync_ptr */ - KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_CURRENT_VAL), + KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE_CUR_VAL), /* info_val == current value of CS_STATUS_WAIT_SYNC_VALUE */ - KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_TEST_VAL), + KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE_TEST_VAL), /* info_val == current value of CS_STATUS_BLOCKED_REASON */ - KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_BLOCKED_REASON), + KBASE_KTRACE_CODE_MAKE_CODE(QUEUE_SYNC_UPDATE_BLOCKED_REASON), /* info_val = group's new protm_pending_bitmap[0] * queue->csi_index indicates which bit was set */ - KBASE_KTRACE_CODE_MAKE_CODE(PROTM_PENDING_SET), + KBASE_KTRACE_CODE_MAKE_CODE(CSI_PROTM_PEND_SET), /* info_val = group's new protm_pending_bitmap[0] * queue->csi_index indicates which bit was cleared */ - KBASE_KTRACE_CODE_MAKE_CODE(PROTM_PENDING_CLEAR), + KBASE_KTRACE_CODE_MAKE_CODE(CSI_PROTM_PEND_CLEAR), /* * KCPU queue events @@ -244,42 +244,42 @@ int dummy_array[] = { /* KTrace info_val == KCPU queue fence context * KCPU extra_info_val == N/A. */ - KBASE_KTRACE_CODE_MAKE_CODE(KCPU_QUEUE_NEW), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_QUEUE_CREATE), /* KTrace info_val == Number of pending commands in KCPU queue when * it is destroyed. * KCPU extra_info_val == Number of CQS wait operations present in * the KCPU queue when it is destroyed. */ - KBASE_KTRACE_CODE_MAKE_CODE(KCPU_QUEUE_DESTROY), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_QUEUE_DELETE), /* KTrace info_val == CQS event memory address * KCPU extra_info_val == Upper 32 bits of event memory, i.e. contents * of error field. */ - KBASE_KTRACE_CODE_MAKE_CODE(CQS_SET), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_CQS_SET), /* KTrace info_val == Number of CQS objects to be waited upon * KCPU extra_info_val == N/A. */ - KBASE_KTRACE_CODE_MAKE_CODE(CQS_WAIT_START), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_CQS_WAIT_START), /* KTrace info_val == CQS event memory address * KCPU extra_info_val == 1 if CQS was signaled with an error and queue * inherited the error, otherwise 0. */ - KBASE_KTRACE_CODE_MAKE_CODE(CQS_WAIT_END), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_CQS_WAIT_END), /* KTrace info_val == Fence context * KCPU extra_info_val == Fence seqno. */ - KBASE_KTRACE_CODE_MAKE_CODE(FENCE_SIGNAL), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_FENCE_SIGNAL), /* KTrace info_val == Fence context * KCPU extra_info_val == Fence seqno. */ - KBASE_KTRACE_CODE_MAKE_CODE(FENCE_WAIT_START), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_FENCE_WAIT_START), /* KTrace info_val == Fence context * KCPU extra_info_val == Fence seqno. */ - KBASE_KTRACE_CODE_MAKE_CODE(FENCE_WAIT_END), + KBASE_KTRACE_CODE_MAKE_CODE(KCPU_FENCE_WAIT_END), #if 0 /* Dummy section to avoid breaking formatting */ }; #endif -/* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */ + /* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */ diff --git a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_csf.c b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_csf.c index 824ca4b87b36..cff6f8959c35 100644 --- a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_csf.c +++ b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_csf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -98,6 +98,9 @@ void kbasep_ktrace_add_csf(struct kbase_device *kbdev, struct kbase_ktrace_msg *trace_msg; struct kbase_context *kctx = NULL; + if (unlikely(!kbasep_ktrace_initialized(&kbdev->ktrace))) + return; + spin_lock_irqsave(&kbdev->ktrace.lock, irqflags); /* Reserve and update indices */ @@ -165,6 +168,9 @@ void kbasep_ktrace_add_csf_kcpu(struct kbase_device *kbdev, struct kbase_ktrace_msg *trace_msg; struct kbase_context *kctx = queue->kctx; + if (unlikely(!kbasep_ktrace_initialized(&kbdev->ktrace))) + return; + spin_lock_irqsave(&kbdev->ktrace.lock, irqflags); /* Reserve and update indices */ diff --git a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_defs_csf.h b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_defs_csf.h index 7f32cd2f23c8..1896e10ed4ab 100644 --- a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_defs_csf.h +++ b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_defs_csf.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -47,7 +47,7 @@ * 1.3: * Add a lot of extra new traces. Tweak some existing scheduler related traces * to contain extra information information/happen at slightly different times. - * SCHEDULER_EXIT_PROTM now has group information + * SCHEDULER_PROTM_EXIT now has group information */ #define KBASE_KTRACE_VERSION_MAJOR 1 #define KBASE_KTRACE_VERSION_MINOR 3 diff --git a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_jm.c b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_jm.c index 05d1677a43d3..6597a15e5000 100644 --- a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_jm.c +++ b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_ktrace_jm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -80,6 +80,9 @@ void kbasep_ktrace_add_jm(struct kbase_device *kbdev, unsigned long irqflags; struct kbase_ktrace_msg *trace_msg; + if (unlikely(!kbasep_ktrace_initialized(&kbdev->ktrace))) + return; + spin_lock_irqsave(&kbdev->ktrace.lock, irqflags); /* Reserve and update indices */ diff --git a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_linux_ktrace_csf.h b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_linux_ktrace_csf.h index 9ee7f8179336..86e81e510b47 100644 --- a/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_linux_ktrace_csf.h +++ b/drivers/gpu/arm/bifrost/debug/backend/mali_kbase_debug_linux_ktrace_csf.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -30,37 +30,36 @@ /* * Generic CSF events - using the common DEFINE_MALI_ADD_EVENT */ -DEFINE_MALI_ADD_EVENT(EVICT_CTX_SLOTS); -DEFINE_MALI_ADD_EVENT(FIRMWARE_BOOT); -DEFINE_MALI_ADD_EVENT(FIRMWARE_REBOOT); -DEFINE_MALI_ADD_EVENT(SCHEDULER_TOCK); +DEFINE_MALI_ADD_EVENT(SCHEDULER_EVICT_CTX_SLOTS_START); +DEFINE_MALI_ADD_EVENT(CSF_FIRMWARE_BOOT); +DEFINE_MALI_ADD_EVENT(CSF_FIRMWARE_REBOOT); +DEFINE_MALI_ADD_EVENT(SCHEDULER_TOCK_START); DEFINE_MALI_ADD_EVENT(SCHEDULER_TOCK_END); -DEFINE_MALI_ADD_EVENT(SCHEDULER_TICK); +DEFINE_MALI_ADD_EVENT(SCHEDULER_TICK_START); DEFINE_MALI_ADD_EVENT(SCHEDULER_TICK_END); -DEFINE_MALI_ADD_EVENT(SCHEDULER_RESET); -DEFINE_MALI_ADD_EVENT(SCHEDULER_WAIT_PROTM_QUIT); -DEFINE_MALI_ADD_EVENT(SCHEDULER_WAIT_PROTM_QUIT_DONE); -DEFINE_MALI_ADD_EVENT(SYNC_UPDATE_EVENT); -DEFINE_MALI_ADD_EVENT(SYNC_UPDATE_EVENT_NOTIFY_GPU); -DEFINE_MALI_ADD_EVENT(CSF_INTERRUPT); +DEFINE_MALI_ADD_EVENT(SCHEDULER_RESET_START); +DEFINE_MALI_ADD_EVENT(SCHEDULER_PROTM_WAIT_QUIT_START); +DEFINE_MALI_ADD_EVENT(SCHEDULER_PROTM_WAIT_QUIT_END); +DEFINE_MALI_ADD_EVENT(SCHEDULER_GROUP_SYNC_UPDATE_EVENT); +DEFINE_MALI_ADD_EVENT(CSF_SYNC_UPDATE_NOTIFY_GPU_EVENT); +DEFINE_MALI_ADD_EVENT(CSF_INTERRUPT_START); DEFINE_MALI_ADD_EVENT(CSF_INTERRUPT_END); -DEFINE_MALI_ADD_EVENT(CSG_INTERRUPT_PROCESS); -DEFINE_MALI_ADD_EVENT(GLB_REQ_ACQ); -DEFINE_MALI_ADD_EVENT(SCHEDULER_CAN_IDLE); -DEFINE_MALI_ADD_EVENT(SCHEDULER_ADVANCE_TICK); -DEFINE_MALI_ADD_EVENT(SCHEDULER_NOADVANCE_TICK); -DEFINE_MALI_ADD_EVENT(SCHEDULER_INSERT_RUNNABLE); -DEFINE_MALI_ADD_EVENT(SCHEDULER_REMOVE_RUNNABLE); -DEFINE_MALI_ADD_EVENT(SCHEDULER_ROTATE_RUNNABLE); -DEFINE_MALI_ADD_EVENT(SCHEDULER_HEAD_RUNNABLE); -DEFINE_MALI_ADD_EVENT(IDLE_WORKER_BEGIN); -DEFINE_MALI_ADD_EVENT(IDLE_WORKER_END); -DEFINE_MALI_ADD_EVENT(GROUP_SYNC_UPDATE_WORKER_BEGIN); -DEFINE_MALI_ADD_EVENT(GROUP_SYNC_UPDATE_WORKER_END); -DEFINE_MALI_ADD_EVENT(SLOTS_STATUS_UPDATE_ACK); -DEFINE_MALI_ADD_EVENT(GPU_IDLE_HANDLING_START); -DEFINE_MALI_ADD_EVENT(MCU_HALTED); -DEFINE_MALI_ADD_EVENT(MCU_IN_SLEEP); +DEFINE_MALI_ADD_EVENT(CSF_INTERRUPT_GLB_REQ_ACK); +DEFINE_MALI_ADD_EVENT(SCHEDULER_GPU_IDLE_EVENT_CAN_SUSPEND); +DEFINE_MALI_ADD_EVENT(SCHEDULER_TICK_ADVANCE); +DEFINE_MALI_ADD_EVENT(SCHEDULER_TICK_NOADVANCE); +DEFINE_MALI_ADD_EVENT(SCHEDULER_RUNNABLE_KCTX_INSERT); +DEFINE_MALI_ADD_EVENT(SCHEDULER_RUNNABLE_KCTX_REMOVE); +DEFINE_MALI_ADD_EVENT(SCHEDULER_RUNNABLE_KCTX_ROTATE); +DEFINE_MALI_ADD_EVENT(SCHEDULER_RUNNABLE_KCTX_HEAD); +DEFINE_MALI_ADD_EVENT(SCHEDULER_GPU_IDLE_WORKER_START); +DEFINE_MALI_ADD_EVENT(SCHEDULER_GPU_IDLE_WORKER_END); +DEFINE_MALI_ADD_EVENT(SCHEDULER_GROUP_SYNC_UPDATE_WORKER_START); +DEFINE_MALI_ADD_EVENT(SCHEDULER_GROUP_SYNC_UPDATE_WORKER_END); +DEFINE_MALI_ADD_EVENT(SCHEDULER_UPDATE_IDLE_SLOTS_ACK); +DEFINE_MALI_ADD_EVENT(SCHEDULER_GPU_IDLE_WORKER_HANDLING_START); +DEFINE_MALI_ADD_EVENT(CSF_FIRMWARE_MCU_HALTED); +DEFINE_MALI_ADD_EVENT(CSF_FIRMWARE_MCU_SLEEP); DECLARE_EVENT_CLASS(mali_csf_grp_q_template, TP_PROTO(struct kbase_device *kbdev, struct kbase_queue_group *group, @@ -130,37 +129,38 @@ DECLARE_EVENT_CLASS(mali_csf_grp_q_template, __entry->kctx_tgid, __entry->kctx_id, __entry->group_handle, \ __entry->csg_nr, __entry->slot_prio, __entry->info_val)) -DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_START); -DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_STOP); -DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_STARTED); +DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_START_REQ); +DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_STOP_REQ); +DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_RUNNING); DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_STOPPED); DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_CLEANED); -DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_STATUS_UPDATE); +DEFINE_MALI_CSF_GRP_EVENT(CSG_UPDATE_IDLE_SLOT_REQ); DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_IDLE_SET); DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_IDLE_CLEAR); -DEFINE_MALI_CSF_GRP_EVENT(CSG_PRIO_UPDATE); -DEFINE_MALI_CSF_GRP_EVENT(CSG_SYNC_UPDATE_INTERRUPT); -DEFINE_MALI_CSF_GRP_EVENT(CSG_IDLE_INTERRUPT); -DEFINE_MALI_CSF_GRP_EVENT(CSG_PROGRESS_TIMER_INTERRUPT); +DEFINE_MALI_CSF_GRP_EVENT(CSG_SLOT_PRIO_UPDATE); +DEFINE_MALI_CSF_GRP_EVENT(CSG_INTERRUPT_SYNC_UPDATE); +DEFINE_MALI_CSF_GRP_EVENT(CSG_INTERRUPT_IDLE); +DEFINE_MALI_CSF_GRP_EVENT(CSG_INTERRUPT_PROGRESS_TIMER_EVENT); +DEFINE_MALI_CSF_GRP_EVENT(CSG_INTERRUPT_PROCESS_START); DEFINE_MALI_CSF_GRP_EVENT(CSG_INTERRUPT_PROCESS_END); DEFINE_MALI_CSF_GRP_EVENT(GROUP_SYNC_UPDATE_DONE); DEFINE_MALI_CSF_GRP_EVENT(GROUP_DESCHEDULE); DEFINE_MALI_CSF_GRP_EVENT(GROUP_SCHEDULE); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_EVICT_SCHED); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_INSERT_RUNNABLE); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_REMOVE_RUNNABLE); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_ROTATE_RUNNABLE); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_HEAD_RUNNABLE); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_INSERT_IDLE_WAIT); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_REMOVE_IDLE_WAIT); -DEFINE_MALI_CSF_GRP_EVENT(GROUP_HEAD_IDLE_WAIT); -DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_CHECK_PROTM_ENTER); -DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_ENTER_PROTM); -DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_EXIT_PROTM); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_EVICT); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_RUNNABLE_INSERT); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_RUNNABLE_REMOVE); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_RUNNABLE_ROTATE); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_RUNNABLE_HEAD); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_IDLE_WAIT_INSERT); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_IDLE_WAIT_REMOVE); +DEFINE_MALI_CSF_GRP_EVENT(GROUP_IDLE_WAIT_HEAD); +DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_PROTM_ENTER_CHECK); +DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_PROTM_ENTER); +DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_PROTM_EXIT); DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_TOP_GRP); -DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_NONIDLE_OFFSLOT_INC); -DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_NONIDLE_OFFSLOT_DEC); -DEFINE_MALI_CSF_GRP_EVENT(PROTM_EVENT_WORKER_BEGIN); +DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_NONIDLE_OFFSLOT_GRP_INC); +DEFINE_MALI_CSF_GRP_EVENT(SCHEDULER_NONIDLE_OFFSLOT_GRP_DEC); +DEFINE_MALI_CSF_GRP_EVENT(PROTM_EVENT_WORKER_START); DEFINE_MALI_CSF_GRP_EVENT(PROTM_EVENT_WORKER_END); #undef DEFINE_MALI_CSF_GRP_EVENT @@ -176,22 +176,22 @@ DEFINE_MALI_CSF_GRP_EVENT(PROTM_EVENT_WORKER_END); DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_START); DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_STOP); -DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_STOP_REQUESTED); -DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_IGNORED_INTERRUPTS_GROUP_SUSPEND); -DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_FAULT_INTERRUPT); -DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_TILER_OOM_INTERRUPT); -DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_PROTM_PEND_INTERRUPT); +DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_STOP_REQ); +DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_INTERRUPT_GROUP_SUSPENDS_IGNORED); +DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_INTERRUPT_FAULT); +DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_INTERRUPT_TILER_OOM); +DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_INTERRUPT_PROTM_PEND); DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_PROTM_ACK); DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_START); DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_STOP); -DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE); -DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE_EVALUATED); -DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_STATUS_WAIT); -DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_CURRENT_VAL); -DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_TEST_VAL); -DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_BLOCKED_REASON); -DEFINE_MALI_CSF_GRP_Q_EVENT(PROTM_PENDING_SET); -DEFINE_MALI_CSF_GRP_Q_EVENT(PROTM_PENDING_CLEAR); +DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE_EVAL_START); +DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE_EVAL_END); +DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE_WAIT_STATUS); +DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE_CUR_VAL); +DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE_TEST_VAL); +DEFINE_MALI_CSF_GRP_Q_EVENT(QUEUE_SYNC_UPDATE_BLOCKED_REASON); +DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_PROTM_PEND_SET); +DEFINE_MALI_CSF_GRP_Q_EVENT(CSI_PROTM_PEND_CLEAR); #undef DEFINE_MALI_CSF_GRP_Q_EVENT @@ -230,14 +230,14 @@ DECLARE_EVENT_CLASS(mali_csf_kcpu_queue_template, u64 info_val1, u64 info_val2), \ TP_ARGS(queue, info_val1, info_val2)) -DEFINE_MALI_CSF_KCPU_EVENT(KCPU_QUEUE_NEW); -DEFINE_MALI_CSF_KCPU_EVENT(KCPU_QUEUE_DESTROY); -DEFINE_MALI_CSF_KCPU_EVENT(CQS_SET); -DEFINE_MALI_CSF_KCPU_EVENT(CQS_WAIT_START); -DEFINE_MALI_CSF_KCPU_EVENT(CQS_WAIT_END); -DEFINE_MALI_CSF_KCPU_EVENT(FENCE_SIGNAL); -DEFINE_MALI_CSF_KCPU_EVENT(FENCE_WAIT_START); -DEFINE_MALI_CSF_KCPU_EVENT(FENCE_WAIT_END); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_QUEUE_CREATE); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_QUEUE_DELETE); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_CQS_SET); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_CQS_WAIT_START); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_CQS_WAIT_END); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_FENCE_SIGNAL); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_FENCE_WAIT_START); +DEFINE_MALI_CSF_KCPU_EVENT(KCPU_FENCE_WAIT_END); #undef DEFINE_MALI_CSF_KCPU_EVENT diff --git a/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.c b/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.c index 9bf86108338f..f521b47120fb 100644 --- a/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.c +++ b/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -27,13 +27,13 @@ int kbase_ktrace_init(struct kbase_device *kbdev) #if KBASE_KTRACE_TARGET_RBUF struct kbase_ktrace_msg *rbuf; + spin_lock_init(&kbdev->ktrace.lock); rbuf = kmalloc_array(KBASE_KTRACE_SIZE, sizeof(*rbuf), GFP_KERNEL); if (!rbuf) return -EINVAL; kbdev->ktrace.rbuf = rbuf; - spin_lock_init(&kbdev->ktrace.lock); #endif /* KBASE_KTRACE_TARGET_RBUF */ return 0; } @@ -42,6 +42,7 @@ void kbase_ktrace_term(struct kbase_device *kbdev) { #if KBASE_KTRACE_TARGET_RBUF kfree(kbdev->ktrace.rbuf); + kbdev->ktrace.rbuf = NULL; #endif /* KBASE_KTRACE_TARGET_RBUF */ } @@ -183,6 +184,9 @@ void kbasep_ktrace_add(struct kbase_device *kbdev, enum kbase_ktrace_code code, unsigned long irqflags; struct kbase_ktrace_msg *trace_msg; + if (unlikely(!kbasep_ktrace_initialized(&kbdev->ktrace))) + return; + WARN_ON((flags & ~KBASE_KTRACE_FLAG_COMMON_ALL)); spin_lock_irqsave(&kbdev->ktrace.lock, irqflags); diff --git a/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.h b/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.h index cc4bfc075792..11f0b5c42c89 100644 --- a/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.h +++ b/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -81,6 +81,18 @@ void kbase_ktrace_debugfs_init(struct kbase_device *kbdev); * KTrace target for internal ringbuffer */ #if KBASE_KTRACE_TARGET_RBUF +/** + * kbasep_ktrace_initialized - Check whether kbase ktrace is initialized + * + * @ktrace: ktrace of kbase device. + * + * Return: true if ktrace has been initialized. + */ +static inline bool kbasep_ktrace_initialized(struct kbase_ktrace *ktrace) +{ + return ktrace->rbuf != NULL; +} + /** * kbasep_ktrace_add - internal function to add trace to the ringbuffer. * @kbdev: kbase device diff --git a/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_csf.c b/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_csf.c index 5602ff5409b0..1e84f6b2644d 100644 --- a/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_csf.c +++ b/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_csf.c @@ -315,10 +315,10 @@ static const struct kbase_device_init dev_init[] = { "GPU hwcnt backend creation failed" }, { kbase_device_hwcnt_context_init, kbase_device_hwcnt_context_term, "GPU hwcnt context initialization failed" }, - { kbase_backend_late_init, kbase_backend_late_term, - "Late backend initialization failed" }, { kbase_csf_early_init, kbase_csf_early_term, "Early CSF initialization failed" }, + { kbase_backend_late_init, kbase_backend_late_term, + "Late backend initialization failed" }, { NULL, kbase_device_firmware_hwcnt_term, NULL }, { kbase_device_debugfs_init, kbase_device_debugfs_term, "DebugFS initialization failed" }, diff --git a/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_hw_jm.c b/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_hw_jm.c index d1e978845431..52063fb0f533 100644 --- a/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_hw_jm.c +++ b/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_hw_jm.c @@ -109,8 +109,7 @@ void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val) #if !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) void kbase_reg_write(struct kbase_device *kbdev, u32 offset, u32 value) { - KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered); - KBASE_DEBUG_ASSERT(kbdev->dev != NULL); + WARN_ON(!kbdev->pm.backend.gpu_powered); writel(value, kbdev->reg + offset); @@ -127,8 +126,7 @@ u32 kbase_reg_read(struct kbase_device *kbdev, u32 offset) { u32 val; - KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered); - KBASE_DEBUG_ASSERT(kbdev->dev != NULL); + WARN_ON(!kbdev->pm.backend.gpu_powered); val = readl(kbdev->reg + offset); diff --git a/drivers/gpu/arm/bifrost/device/mali_kbase_device.c b/drivers/gpu/arm/bifrost/device/mali_kbase_device.c index 1949a211575d..7004e347fa1b 100644 --- a/drivers/gpu/arm/bifrost/device/mali_kbase_device.c +++ b/drivers/gpu/arm/bifrost/device/mali_kbase_device.c @@ -291,12 +291,9 @@ int kbase_device_misc_init(struct kbase_device * const kbdev) if (err) goto dma_set_mask_failed; - err = kbase_ktrace_init(kbdev); - if (err) - goto term_as; err = kbase_pbha_read_dtb(kbdev); if (err) - goto term_ktrace; + goto term_as; init_waitqueue_head(&kbdev->cache_clean_wait); @@ -326,10 +323,15 @@ int kbase_device_misc_init(struct kbase_device * const kbdev) "Unable to register OOM notifier for Mali - but will continue\n"); kbdev->oom_notifier_block.notifier_call = NULL; } + +#if !MALI_USE_CSF + spin_lock_init(&kbdev->quick_reset_lock); + kbdev->quick_reset_enabled = true; + kbdev->num_of_atoms_hw_completed = 0; +#endif + return 0; -term_ktrace: - kbase_ktrace_term(kbdev); term_as: kbase_device_all_as_term(kbdev); dma_set_mask_failed: @@ -346,9 +348,6 @@ void kbase_device_misc_term(struct kbase_device *kbdev) #if KBASE_KTRACE_ENABLE kbase_debug_assert_register_hook(NULL, NULL); #endif - - kbase_ktrace_term(kbdev); - kbase_device_all_as_term(kbdev); @@ -356,6 +355,33 @@ void kbase_device_misc_term(struct kbase_device *kbdev) unregister_oom_notifier(&kbdev->oom_notifier_block); } +#if !MALI_USE_CSF +void kbase_enable_quick_reset(struct kbase_device *kbdev) +{ + spin_lock(&kbdev->quick_reset_lock); + + kbdev->quick_reset_enabled = true; + kbdev->num_of_atoms_hw_completed = 0; + + spin_unlock(&kbdev->quick_reset_lock); +} + +void kbase_disable_quick_reset(struct kbase_device *kbdev) +{ + spin_lock(&kbdev->quick_reset_lock); + + kbdev->quick_reset_enabled = false; + kbdev->num_of_atoms_hw_completed = 0; + + spin_unlock(&kbdev->quick_reset_lock); +} + +bool kbase_is_quick_reset_enabled(struct kbase_device *kbdev) +{ + return kbdev->quick_reset_enabled; +} +#endif + void kbase_device_free(struct kbase_device *kbdev) { kfree(kbdev); @@ -488,10 +514,14 @@ int kbase_device_early_init(struct kbase_device *kbdev) { int err; + err = kbase_ktrace_init(kbdev); + if (err) + return err; + err = kbasep_platform_device_init(kbdev); if (err) - return err; + goto ktrace_term; err = kbase_pm_runtime_init(kbdev); if (err) @@ -505,7 +535,12 @@ int kbase_device_early_init(struct kbase_device *kbdev) /* Ensure we can access the GPU registers */ kbase_pm_register_access_enable(kbdev); - /* Find out GPU properties based on the GPU feature registers */ + /* + * Find out GPU properties based on the GPU feature registers. + * Note that this does not populate the few properties that depend on + * hw_features being initialized. Those are set by kbase_gpuprops_set_features + * soon after this in the init process. + */ kbase_gpuprops_set(kbdev); /* We're done accessing the GPU registers for now. */ @@ -528,6 +563,8 @@ fail_interrupts: kbase_pm_runtime_term(kbdev); fail_runtime_pm: kbasep_platform_device_term(kbdev); +ktrace_term: + kbase_ktrace_term(kbdev); return err; } @@ -544,6 +581,7 @@ void kbase_device_early_term(struct kbase_device *kbdev) #endif /* CONFIG_MALI_ARBITER_SUPPORT */ kbase_pm_runtime_term(kbdev); kbasep_platform_device_term(kbdev); + kbase_ktrace_term(kbdev); } int kbase_device_late_init(struct kbase_device *kbdev) diff --git a/drivers/gpu/arm/bifrost/device/mali_kbase_device.h b/drivers/gpu/arm/bifrost/device/mali_kbase_device.h index afd195cf3a3f..6706a61d5baa 100644 --- a/drivers/gpu/arm/bifrost/device/mali_kbase_device.h +++ b/drivers/gpu/arm/bifrost/device/mali_kbase_device.h @@ -115,6 +115,22 @@ u32 kbase_reg_read(struct kbase_device *kbdev, u32 offset); */ bool kbase_is_gpu_removed(struct kbase_device *kbdev); +/** + * kbase_gpu_cache_flush_pa_range_and_busy_wait() - Start a cache physical range flush + * and busy wait + * + * @kbdev: kbase device to issue the MMU operation on. + * @phys: Starting address of the physical range to start the operation on. + * @nr_bytes: Number of bytes to work on. + * @flush_op: Flush command register value to be sent to HW + * + * Issue a cache flush physical range command, then busy wait an irq status. + * This function will clear FLUSH_PA_RANGE_COMPLETED irq mask bit + * and busy-wait the rawstat register. + * + * Return: 0 if successful or a negative error code on failure. + */ +#define kbase_gpu_cache_flush_pa_range_and_busy_wait(kbdev, phys, nr_bytes, flush_op) (0) /** * kbase_gpu_cache_flush_and_busy_wait - Start a cache flush and busy wait * @kbdev: Kbase device @@ -188,7 +204,7 @@ int kbase_gpu_wait_cache_clean_timeout(struct kbase_device *kbdev, void kbase_gpu_cache_clean_wait_complete(struct kbase_device *kbdev); /** - * kbase_clean_caches_done - Issue preiously queued cache clean request or + * kbase_clean_caches_done - Issue previously queued cache clean request or * wake up the requester that issued cache clean. * @kbdev: Kbase device * diff --git a/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c b/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c index 6096bcc186e4..4bd545a82299 100644 --- a/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c +++ b/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2016, 2018-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2016, 2018-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -27,6 +27,9 @@ #include #include +#define U64_LO_MASK ((1ULL << 32) - 1) +#define U64_HI_MASK (~U64_LO_MASK) + #if !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) bool kbase_is_gpu_removed(struct kbase_device *kbdev) { @@ -38,8 +41,9 @@ bool kbase_is_gpu_removed(struct kbase_device *kbdev) } #endif /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */ -static int busy_wait_cache_clean_irq(struct kbase_device *kbdev) +static int busy_wait_on_irq(struct kbase_device *kbdev, u32 irq_bit) { + char *irq_flag_name; /* Previously MMU-AS command was used for L2 cache flush on page-table update. * And we're using the same max-loops count for GPU command, because amount of * L2 cache flush overhead are same between them. @@ -48,28 +52,42 @@ static int busy_wait_cache_clean_irq(struct kbase_device *kbdev) /* Wait for the GPU cache clean operation to complete */ while (--max_loops && - !(kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT)) & - CLEAN_CACHES_COMPLETED)) { + !(kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT)) & irq_bit)) { ; } /* reset gpu if time-out occurred */ if (max_loops == 0) { + switch (irq_bit) { + case CLEAN_CACHES_COMPLETED: + irq_flag_name = "CLEAN_CACHES_COMPLETED"; + break; + case FLUSH_PA_RANGE_COMPLETED: + irq_flag_name = "FLUSH_PA_RANGE_COMPLETED"; + break; + default: + irq_flag_name = "UNKNOWN"; + break; + } + dev_err(kbdev->dev, - "CLEAN_CACHES_COMPLETED bit stuck, might be caused by slow/unstable GPU clock or possible faulty FPGA connector\n"); + "Stuck waiting on %s bit, might be caused by slow/unstable GPU clock or possible faulty FPGA connector\n", + irq_flag_name); + if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_NONE)) kbase_reset_gpu_locked(kbdev); return -EBUSY; } - /* Clear the interrupt CLEAN_CACHES_COMPLETED bit. */ - KBASE_KTRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, CLEAN_CACHES_COMPLETED); - kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), - CLEAN_CACHES_COMPLETED); + /* Clear the interrupt bit. */ + KBASE_KTRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, irq_bit); + kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), irq_bit); return 0; } +#define kbase_gpu_cache_flush_pa_range_and_busy_wait(kbdev, phys, nr_bytes, flush_op) (0) + int kbase_gpu_cache_flush_and_busy_wait(struct kbase_device *kbdev, u32 flush_op) { @@ -97,7 +115,7 @@ int kbase_gpu_cache_flush_and_busy_wait(struct kbase_device *kbdev, irq_mask & ~CLEAN_CACHES_COMPLETED); /* busy wait irq status to be enabled */ - ret = busy_wait_cache_clean_irq(kbdev); + ret = busy_wait_on_irq(kbdev, (u32)CLEAN_CACHES_COMPLETED); if (ret) return ret; @@ -118,7 +136,7 @@ int kbase_gpu_cache_flush_and_busy_wait(struct kbase_device *kbdev, kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), flush_op); /* 3. Busy-wait irq status to be enabled. */ - ret = busy_wait_cache_clean_irq(kbdev); + ret = busy_wait_on_irq(kbdev, (u32)CLEAN_CACHES_COMPLETED); if (ret) return ret; diff --git a/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_fault_csf.c b/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_fault_csf.c index 893a3352a908..15bfd0375f0b 100644 --- a/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_fault_csf.c +++ b/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_fault_csf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -86,6 +86,9 @@ const char *kbase_gpu_exception_name(u32 const exception_code) case CS_FATAL_EXCEPTION_TYPE_FIRMWARE_INTERNAL_ERROR: e = "FIRMWARE_INTERNAL_ERROR"; break; + case CS_FATAL_EXCEPTION_TYPE_CS_UNRECOVERABLE: + e = "CS_UNRECOVERABLE"; + break; case CS_FAULT_EXCEPTION_TYPE_RESOURCE_EVICTION_TIMEOUT: e = "RESOURCE_EVICTION_TIMEOUT"; break; diff --git a/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_csf.h b/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_csf.h index d1c6b39eca28..06c725c0e757 100644 --- a/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_csf.h +++ b/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_csf.h @@ -138,6 +138,7 @@ #define GPU_COMMAND_CODE_SET_PROTECTED_MODE 0x05 /* Places the GPU in protected mode */ #define GPU_COMMAND_CODE_FINISH_HALT 0x06 /* Halt CSF */ #define GPU_COMMAND_CODE_CLEAR_FAULT 0x07 /* Clear GPU_FAULTSTATUS and GPU_FAULTADDRESS, TODX */ +#define GPU_COMMAND_CODE_FLUSH_PA_RANGE 0x08 /* Flush the GPU caches for a physical range, TITX */ /* GPU_COMMAND_RESET payloads */ @@ -161,18 +162,29 @@ #define GPU_COMMAND_TIME_ENABLE 0x01 /* Enable cycle counter */ /* GPU_COMMAND_FLUSH_CACHES payloads bits for L2 caches */ -#define GPU_COMMAND_FLUSH_PAYLOAD_L2_NONE 0x000 /* No flush */ -#define GPU_COMMAND_FLUSH_PAYLOAD_L2_CLEAN 0x001 /* CLN only */ -#define GPU_COMMAND_FLUSH_PAYLOAD_L2_CLEAN_INVALIDATE 0x003 /* CLN + INV */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_L2_NONE 0x000 /* No flush */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_L2_CLEAN 0x001 /* CLN only */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_L2_CLEAN_INVALIDATE 0x003 /* CLN + INV */ /* GPU_COMMAND_FLUSH_CACHES payloads bits for Load-store caches */ -#define GPU_COMMAND_FLUSH_PAYLOAD_LSC_NONE 0x000 /* No flush */ -#define GPU_COMMAND_FLUSH_PAYLOAD_LSC_CLEAN 0x010 /* CLN only */ -#define GPU_COMMAND_FLUSH_PAYLOAD_LSC_CLEAN_INVALIDATE 0x030 /* CLN + INV */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_LSC_NONE 0x000 /* No flush */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_LSC_CLEAN 0x010 /* CLN only */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_LSC_CLEAN_INVALIDATE 0x030 /* CLN + INV */ /* GPU_COMMAND_FLUSH_CACHES payloads bits for Other caches */ -#define GPU_COMMAND_FLUSH_PAYLOAD_OTHER_NONE 0x000 /* No flush */ -#define GPU_COMMAND_FLUSH_PAYLOAD_OTHER_INVALIDATE 0x200 /* INV only */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_OTHER_NONE 0x000 /* No flush */ +#define GPU_COMMAND_FLUSH_CACHES_PAYLOAD_OTHER_INVALIDATE 0x200 /* INV only */ + +/* GPU_COMMAND_FLUSH_PA_RANGE payload bits for flush modes */ +#define GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_MODE_NONE 0x00 /* No flush */ +#define GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_MODE_CLEAN 0x01 /* CLN only */ +#define GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_MODE_INVALIDATE 0x02 /* INV only */ +#define GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_MODE_CLEAN_INVALIDATE 0x03 /* CLN + INV */ + +/* GPU_COMMAND_FLUSH_PA_RANGE payload bits for which caches should be the target of the command */ +#define GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_OTHER_CACHE 0x10 /* Other caches */ +#define GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_LSC_CACHE 0x20 /* Load-store caches */ +#define GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_L2_CACHE 0x40 /* L2 caches */ /* GPU_COMMAND command + payload */ #define GPU_COMMAND_CODE_PAYLOAD(opcode, payload) \ @@ -200,28 +212,53 @@ GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_TIME, GPU_COMMAND_TIME_DISABLE) /* Clean and invalidate L2 cache (Equivalent to FLUSH_PT) */ -#define GPU_COMMAND_CACHE_CLN_INV_L2 \ - GPU_COMMAND_CODE_PAYLOAD( \ - GPU_COMMAND_CODE_FLUSH_CACHES, \ - (GPU_COMMAND_FLUSH_PAYLOAD_L2_CLEAN_INVALIDATE | \ - GPU_COMMAND_FLUSH_PAYLOAD_LSC_NONE | \ - GPU_COMMAND_FLUSH_PAYLOAD_OTHER_NONE)) +#define GPU_COMMAND_CACHE_CLN_INV_L2 \ + GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_FLUSH_CACHES, \ + (GPU_COMMAND_FLUSH_CACHES_PAYLOAD_L2_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_LSC_NONE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_OTHER_NONE)) /* Clean and invalidate L2 and LSC caches (Equivalent to FLUSH_MEM) */ -#define GPU_COMMAND_CACHE_CLN_INV_L2_LSC \ - GPU_COMMAND_CODE_PAYLOAD( \ - GPU_COMMAND_CODE_FLUSH_CACHES, \ - (GPU_COMMAND_FLUSH_PAYLOAD_L2_CLEAN_INVALIDATE | \ - GPU_COMMAND_FLUSH_PAYLOAD_LSC_CLEAN_INVALIDATE | \ - GPU_COMMAND_FLUSH_PAYLOAD_OTHER_NONE)) +#define GPU_COMMAND_CACHE_CLN_INV_L2_LSC \ + GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_FLUSH_CACHES, \ + (GPU_COMMAND_FLUSH_CACHES_PAYLOAD_L2_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_LSC_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_OTHER_NONE)) /* Clean and invalidate L2, LSC, and Other caches */ -#define GPU_COMMAND_CACHE_CLN_INV_FULL \ - GPU_COMMAND_CODE_PAYLOAD( \ - GPU_COMMAND_CODE_FLUSH_CACHES, \ - (GPU_COMMAND_FLUSH_PAYLOAD_L2_CLEAN_INVALIDATE | \ - GPU_COMMAND_FLUSH_PAYLOAD_LSC_CLEAN_INVALIDATE | \ - GPU_COMMAND_FLUSH_PAYLOAD_OTHER_INVALIDATE)) +#define GPU_COMMAND_CACHE_CLN_INV_FULL \ + GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_FLUSH_CACHES, \ + (GPU_COMMAND_FLUSH_CACHES_PAYLOAD_L2_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_LSC_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_OTHER_INVALIDATE)) + +/* Clean and invalidate only LSC cache */ +#define GPU_COMMAND_CACHE_CLN_INV_LSC \ + GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_FLUSH_CACHES, \ + (GPU_COMMAND_FLUSH_CACHES_PAYLOAD_L2_NONE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_LSC_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_CACHES_PAYLOAD_OTHER_NONE)) + +/* Clean and invalidate physical range L2 cache (equivalent to FLUSH_PT) */ +#define GPU_COMMAND_FLUSH_PA_RANGE_CLN_INV_L2 \ + GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_FLUSH_PA_RANGE, \ + (GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_MODE_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_L2_CACHE)) + +/* Clean and invalidate physical range L2 and LSC cache (equivalent to FLUSH_MEM) */ +#define GPU_COMMAND_FLUSH_PA_RANGE_CLN_INV_L2_LSC \ + GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_FLUSH_PA_RANGE, \ + (GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_MODE_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_LSC_CACHE | \ + GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_L2_CACHE)) + +/* Clean and invalidate physical range L2, LSC and Other caches */ +#define GPU_COMMAND_FLUSH_PA_RANGE_CLN_INV_FULL \ + GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_FLUSH_PA_RANGE, \ + (GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_MODE_CLEAN_INVALIDATE | \ + GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_OTHER_CACHE | \ + GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_LSC_CACHE | \ + GPU_COMMAND_FLUSH_PA_RANGE_PAYLOAD_L2_CACHE)) /* Merge cache flush commands */ #define GPU_COMMAND_FLUSH_CACHE_MERGE(cmd1, cmd2) ((cmd1) | (cmd2)) @@ -302,14 +339,16 @@ (((value) << GPU_FAULTSTATUS_ADDRESS_VALID_SHIFT) & GPU_FAULTSTATUS_ADDRESS_VALID_MASK)) /* IRQ flags */ -#define GPU_FAULT (1 << 0) /* A GPU Fault has occurred */ -#define GPU_PROTECTED_FAULT (1 << 1) /* A GPU fault has occurred in protected mode */ -#define RESET_COMPLETED (1 << 8) /* Set when a reset has completed. */ -#define POWER_CHANGED_SINGLE (1 << 9) /* Set when a single core has finished powering up or down. */ -#define POWER_CHANGED_ALL (1 << 10) /* Set when all cores have finished powering up or down. */ -#define CLEAN_CACHES_COMPLETED (1 << 17) /* Set when a cache clean operation has completed. */ -#define DOORBELL_MIRROR (1 << 18) /* Mirrors the doorbell interrupt line to the CPU */ -#define MCU_STATUS_GPU_IRQ (1 << 19) /* MCU requires attention */ +#define GPU_FAULT (1 << 0) /* A GPU Fault has occurred */ +#define GPU_PROTECTED_FAULT (1 << 1) /* A GPU fault has occurred in protected mode */ +#define RESET_COMPLETED (1 << 8) /* Set when a reset has completed. */ +#define POWER_CHANGED_SINGLE (1 << 9) /* Set when a single core has finished powering up or down. */ +#define POWER_CHANGED_ALL (1 << 10) /* Set when all cores have finished powering up or down. */ +#define CLEAN_CACHES_COMPLETED (1 << 17) /* Set when a cache clean operation has completed. */ +#define DOORBELL_MIRROR (1 << 18) /* Mirrors the doorbell interrupt line to the CPU */ +#define MCU_STATUS_GPU_IRQ (1 << 19) /* MCU requires attention */ +#define FLUSH_PA_RANGE_COMPLETED \ + (1 << 20) /* Set when a physical range cache clean operation has completed. */ /* * In Debug build, diff --git a/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_jm.h b/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_jm.h index d1cd8fc7d048..c349f4b058cd 100644 --- a/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_jm.h +++ b/drivers/gpu/arm/bifrost/gpu/backend/mali_kbase_gpu_regmap_jm.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -262,19 +262,22 @@ #define GPU_COMMAND_CACHE_CLN_INV_L2 GPU_COMMAND_CLEAN_INV_CACHES #define GPU_COMMAND_CACHE_CLN_INV_L2_LSC GPU_COMMAND_CLEAN_INV_CACHES #define GPU_COMMAND_CACHE_CLN_INV_FULL GPU_COMMAND_CLEAN_INV_CACHES +#define GPU_COMMAND_CACHE_CLN_INV_LSC GPU_COMMAND_CLEAN_INV_CACHES /* Merge cache flush commands */ #define GPU_COMMAND_FLUSH_CACHE_MERGE(cmd1, cmd2) \ ((cmd1) > (cmd2) ? (cmd1) : (cmd2)) /* IRQ flags */ -#define GPU_FAULT (1 << 0) /* A GPU Fault has occurred */ -#define MULTIPLE_GPU_FAULTS (1 << 7) /* More than one GPU Fault occurred. */ -#define RESET_COMPLETED (1 << 8) /* Set when a reset has completed. */ -#define POWER_CHANGED_SINGLE (1 << 9) /* Set when a single core has finished powering up or down. */ -#define POWER_CHANGED_ALL (1 << 10) /* Set when all cores have finished powering up or down. */ -#define PRFCNT_SAMPLE_COMPLETED (1 << 16) /* Set when a performance count sample has completed. */ -#define CLEAN_CACHES_COMPLETED (1 << 17) /* Set when a cache clean operation has completed. */ +#define GPU_FAULT (1 << 0) /* A GPU Fault has occurred */ +#define MULTIPLE_GPU_FAULTS (1 << 7) /* More than one GPU Fault occurred. */ +#define RESET_COMPLETED (1 << 8) /* Set when a reset has completed. */ +#define POWER_CHANGED_SINGLE (1 << 9) /* Set when a single core has finished powering up or down. */ +#define POWER_CHANGED_ALL (1 << 10) /* Set when all cores have finished powering up or down. */ +#define PRFCNT_SAMPLE_COMPLETED (1 << 16) /* Set when a performance count sample has completed. */ +#define CLEAN_CACHES_COMPLETED (1 << 17) /* Set when a cache clean operation has completed. */ +#define FLUSH_PA_RANGE_COMPLETED \ + (1 << 20) /* Set when a physical range cache clean operation has completed. */ /* * In Debug build, diff --git a/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_regmap.h b/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_regmap.h index b6033fea6440..396ebd5e21c9 100644 --- a/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_regmap.h +++ b/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_regmap.h @@ -100,6 +100,7 @@ #define TEXTURE_FEATURES_REG(n) GPU_CONTROL_REG(TEXTURE_FEATURES_0 + ((n) << 2)) + #define SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */ #define SHADER_PRESENT_HI 0x104 /* (RO) Shader core present bitmap, high word */ @@ -368,6 +369,11 @@ (((reg_val) & ~AS_LOCKADDR_LOCKADDR_BASE_MASK) | \ (((value) << AS_LOCKADDR_LOCKADDR_BASE_SHIFT) & \ AS_LOCKADDR_LOCKADDR_BASE_MASK)) +#define AS_LOCKADDR_FLUSH_SKIP_LEVELS_SHIFT (6) +#define AS_LOCKADDR_FLUSH_SKIP_LEVELS_MASK ((0xF) << AS_LOCKADDR_FLUSH_SKIP_LEVELS_SHIFT) +#define AS_LOCKADDR_FLUSH_SKIP_LEVELS_SET(reg_val, value) \ + (((reg_val) & ~AS_LOCKADDR_FLUSH_SKIP_LEVELS_MASK) | \ + ((value << AS_LOCKADDR_FLUSH_SKIP_LEVELS_SHIFT) & AS_LOCKADDR_FLUSH_SKIP_LEVELS_MASK)) /* GPU_STATUS values */ #define GPU_STATUS_PRFCNT_ACTIVE (1 << 2) /* Set if the performance counters are active. */ diff --git a/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_defs.h b/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_defs.h index a7103ecea4b5..f9e0099a5cbf 100644 --- a/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_defs.h +++ b/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_defs.h @@ -186,8 +186,6 @@ struct kbase_jd_atom_dependency { static inline const struct kbase_jd_atom * kbase_jd_katom_dep_atom(const struct kbase_jd_atom_dependency *dep) { - KBASE_DEBUG_ASSERT(dep != NULL); - return (const struct kbase_jd_atom *)(dep->atom); } @@ -201,8 +199,6 @@ kbase_jd_katom_dep_atom(const struct kbase_jd_atom_dependency *dep) static inline u8 kbase_jd_katom_dep_type( const struct kbase_jd_atom_dependency *dep) { - KBASE_DEBUG_ASSERT(dep != NULL); - return dep->dep_type; } @@ -219,8 +215,6 @@ static inline void kbase_jd_katom_dep_set( { struct kbase_jd_atom_dependency *dep; - KBASE_DEBUG_ASSERT(const_dep != NULL); - dep = (struct kbase_jd_atom_dependency *)const_dep; dep->atom = a; @@ -237,8 +231,6 @@ static inline void kbase_jd_katom_dep_clear( { struct kbase_jd_atom_dependency *dep; - KBASE_DEBUG_ASSERT(const_dep != NULL); - dep = (struct kbase_jd_atom_dependency *)const_dep; dep->atom = NULL; @@ -508,7 +500,6 @@ struct kbase_ext_res { * BASE_JD_REQ_START_RENDERPASS set in its core requirements * with an atom that has BASE_JD_REQ_END_RENDERPASS set. * @jc_fragment: Set of GPU fragment job chains - * @retry_count: TODO: Not used,to be removed */ struct kbase_jd_atom { struct work_struct work; @@ -619,8 +610,6 @@ struct kbase_jd_atom { u32 atom_flags; - int retry_count; - enum kbase_atom_gpu_rb_state gpu_rb_state; bool need_cache_flush_cores_retained; diff --git a/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_js.h b/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_js.h index f5d4084fe4fb..d03bcc0f27d8 100644 --- a/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_js.h +++ b/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_js.h @@ -29,6 +29,8 @@ #include "mali_kbase_js_ctx_attr.h" +#define JS_MAX_RUNNING_JOBS 8 + /** * kbasep_js_devdata_init - Initialize the Job Scheduler * @kbdev: The kbase_device to operate on @@ -705,8 +707,10 @@ static inline bool kbasep_js_is_submit_allowed( bool is_allowed; /* Ensure context really is scheduled in */ - KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); - KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); + if (WARN((kctx->as_nr == KBASEP_AS_NR_INVALID) || !kbase_ctx_flag(kctx, KCTX_SCHEDULED), + "%s: kctx %pK has assigned AS %d and context flag %d\n", __func__, (void *)kctx, + kctx->as_nr, atomic_read(&kctx->flags))) + return false; test_bit = (u16) (1u << kctx->as_nr); @@ -733,8 +737,10 @@ static inline void kbasep_js_set_submit_allowed( u16 set_bit; /* Ensure context really is scheduled in */ - KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); - KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); + if (WARN((kctx->as_nr == KBASEP_AS_NR_INVALID) || !kbase_ctx_flag(kctx, KCTX_SCHEDULED), + "%s: kctx %pK has assigned AS %d and context flag %d\n", __func__, (void *)kctx, + kctx->as_nr, atomic_read(&kctx->flags))) + return; set_bit = (u16) (1u << kctx->as_nr); @@ -763,8 +769,10 @@ static inline void kbasep_js_clear_submit_allowed( u16 clear_mask; /* Ensure context really is scheduled in */ - KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); - KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); + if (WARN((kctx->as_nr == KBASEP_AS_NR_INVALID) || !kbase_ctx_flag(kctx, KCTX_SCHEDULED), + "%s: kctx %pK has assigned AS %d and context flag %d\n", __func__, (void *)kctx, + kctx->as_nr, atomic_read(&kctx->flags))) + return; clear_bit = (u16) (1u << kctx->as_nr); clear_mask = ~clear_bit; @@ -798,7 +806,7 @@ static inline void kbasep_js_atom_retained_state_init_invalid( * @retained_state: where to copy * @katom: where to copy from * - * Copy atom state that can be made available after jd_done_nolock() is called + * Copy atom state that can be made available after kbase_jd_done_nolock() is called * on that atom. */ static inline void kbasep_js_atom_retained_state_copy( @@ -872,9 +880,6 @@ static inline void kbase_js_runpool_inc_context_count( struct kbasep_js_device_data *js_devdata; struct kbasep_js_kctx_info *js_kctx_info; - KBASE_DEBUG_ASSERT(kbdev != NULL); - KBASE_DEBUG_ASSERT(kctx != NULL); - js_devdata = &kbdev->js_data; js_kctx_info = &kctx->jctx.sched_info; @@ -882,13 +887,12 @@ static inline void kbase_js_runpool_inc_context_count( lockdep_assert_held(&js_devdata->runpool_mutex); /* Track total contexts */ - KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running < S8_MAX); + WARN_ON_ONCE(js_devdata->nr_all_contexts_running >= JS_MAX_RUNNING_JOBS); ++(js_devdata->nr_all_contexts_running); if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { /* Track contexts that can submit jobs */ - KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running < - S8_MAX); + WARN_ON_ONCE(js_devdata->nr_user_contexts_running >= JS_MAX_RUNNING_JOBS); ++(js_devdata->nr_user_contexts_running); } } @@ -909,9 +913,6 @@ static inline void kbase_js_runpool_dec_context_count( struct kbasep_js_device_data *js_devdata; struct kbasep_js_kctx_info *js_kctx_info; - KBASE_DEBUG_ASSERT(kbdev != NULL); - KBASE_DEBUG_ASSERT(kctx != NULL); - js_devdata = &kbdev->js_data; js_kctx_info = &kctx->jctx.sched_info; @@ -920,12 +921,12 @@ static inline void kbase_js_runpool_dec_context_count( /* Track total contexts */ --(js_devdata->nr_all_contexts_running); - KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running >= 0); + WARN_ON_ONCE(js_devdata->nr_all_contexts_running < 0); if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { /* Track contexts that can submit jobs */ --(js_devdata->nr_user_contexts_running); - KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running >= 0); + WARN_ON_ONCE(js_devdata->nr_user_contexts_running < 0); } } @@ -950,8 +951,8 @@ extern const base_jd_prio kbasep_js_relative_priority_to_atom[KBASE_JS_ATOM_SCHED_PRIO_COUNT]; /** - * kbasep_js_atom_prio_to_sched_prio(): - Convert atom priority (base_jd_prio) - * to relative ordering + * kbasep_js_atom_prio_to_sched_prio - Convert atom priority (base_jd_prio) + * to relative ordering. * @atom_prio: Priority ID to translate. * * Atom priority values for @ref base_jd_prio cannot be compared directly to @@ -980,16 +981,33 @@ static inline int kbasep_js_atom_prio_to_sched_prio(base_jd_prio atom_prio) return kbasep_js_atom_priority_to_relative[atom_prio]; } -static inline base_jd_prio kbasep_js_sched_prio_to_atom_prio(int sched_prio) +/** + * kbasep_js_sched_prio_to_atom_prio - Convert relative scheduler priority + * to atom priority (base_jd_prio). + * + * @kbdev: Device pointer + * @sched_prio: Relative scheduler priority to translate. + * + * This function will convert relative scheduler priority back into base_jd_prio + * values. It takes values which priorities are monotonically increasing + * and converts them to the corresponding base_jd_prio values. If an invalid number is + * passed in (i.e. not within the expected range) an error code is returned instead. + * + * The mapping is 1:1 and the size of the valid input range is the same as the + * size of the valid output range, i.e. + * KBASE_JS_ATOM_SCHED_PRIO_COUNT == BASE_JD_NR_PRIO_LEVELS + * + * Return: On success: a value in the inclusive range + * 0..BASE_JD_NR_PRIO_LEVELS-1. On failure: BASE_JD_PRIO_INVALID. + */ +static inline base_jd_prio kbasep_js_sched_prio_to_atom_prio(struct kbase_device *kbdev, + int sched_prio) { - unsigned int prio_idx; - - KBASE_DEBUG_ASSERT(sched_prio >= 0 && - sched_prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT); - - prio_idx = (unsigned int)sched_prio; - - return kbasep_js_relative_priority_to_atom[prio_idx]; + if (likely(sched_prio >= 0 && sched_prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT)) + return kbasep_js_relative_priority_to_atom[sched_prio]; + /* Invalid priority value if reached here */ + dev_warn(kbdev->dev, "Unknown JS scheduling priority %d", sched_prio); + return BASE_JD_PRIO_INVALID; } /** diff --git a/drivers/gpu/arm/bifrost/jm/mali_kbase_js_defs.h b/drivers/gpu/arm/bifrost/jm/mali_kbase_js_defs.h index 998fde6f7e52..3d91efdf9d72 100644 --- a/drivers/gpu/arm/bifrost/jm/mali_kbase_js_defs.h +++ b/drivers/gpu/arm/bifrost/jm/mali_kbase_js_defs.h @@ -387,7 +387,7 @@ struct kbasep_js_kctx_info { * @sched_priority: priority * @device_nr: Core group atom was executed on * - * Subset of atom state that can be available after jd_done_nolock() is called + * Subset of atom state that can be available after kbase_jd_done_nolock() is called * on that atom. A copy must be taken via kbasep_js_atom_retained_state_copy(), * because the original atom could disappear. */ diff --git a/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h b/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h index a713681c8316..3669f7e23fa6 100644 --- a/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h +++ b/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2014-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -38,6 +38,7 @@ enum base_hw_feature { BASE_HW_FEATURE_ASN_HASH, BASE_HW_FEATURE_GPU_SLEEP, BASE_HW_FEATURE_FLUSH_INV_SHADER_OTHER, + BASE_HW_FEATURE_CORE_FEATURES, BASE_HW_FEATURE_END }; @@ -87,6 +88,7 @@ __attribute__((unused)) static const enum base_hw_feature base_hw_features_tGOx[ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, BASE_HW_FEATURE_TLS_HASHING, BASE_HW_FEATURE_IDVS_GROUP_SIZE, + BASE_HW_FEATURE_CORE_FEATURES, BASE_HW_FEATURE_END }; @@ -151,6 +153,7 @@ __attribute__((unused)) static const enum base_hw_feature base_hw_features_tGRx[ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, BASE_HW_FEATURE_L2_CONFIG, BASE_HW_FEATURE_CLEAN_ONLY_SAFE, + BASE_HW_FEATURE_CORE_FEATURES, BASE_HW_FEATURE_END }; @@ -159,6 +162,7 @@ __attribute__((unused)) static const enum base_hw_feature base_hw_features_tVAx[ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, BASE_HW_FEATURE_L2_CONFIG, BASE_HW_FEATURE_CLEAN_ONLY_SAFE, + BASE_HW_FEATURE_CORE_FEATURES, BASE_HW_FEATURE_END }; @@ -169,6 +173,7 @@ __attribute__((unused)) static const enum base_hw_feature base_hw_features_tTUx[ BASE_HW_FEATURE_CLEAN_ONLY_SAFE, BASE_HW_FEATURE_ASN_HASH, BASE_HW_FEATURE_GPU_SLEEP, + BASE_HW_FEATURE_CORE_FEATURES, BASE_HW_FEATURE_END }; diff --git a/drivers/gpu/arm/bifrost/mali_base_hwconfig_issues.h b/drivers/gpu/arm/bifrost/mali_base_hwconfig_issues.h index 95bdd1718e06..391730106f6d 100644 --- a/drivers/gpu/arm/bifrost/mali_base_hwconfig_issues.h +++ b/drivers/gpu/arm/bifrost/mali_base_hwconfig_issues.h @@ -62,6 +62,8 @@ enum base_hw_issue { BASE_HW_ISSUE_TURSEHW_1997, BASE_HW_ISSUE_GPU2019_3878, BASE_HW_ISSUE_TURSEHW_2716, + BASE_HW_ISSUE_GPU2019_3901, + BASE_HW_ISSUE_GPU2021PRO_290, BASE_HW_ISSUE_END }; @@ -599,6 +601,7 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tODx_r0p0 BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3212, BASE_HW_ISSUE_GPU2019_3878, + BASE_HW_ISSUE_GPU2019_3901, BASE_HW_ISSUE_END }; @@ -609,6 +612,7 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_model_tOD BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3212, BASE_HW_ISSUE_GPU2019_3878, + BASE_HW_ISSUE_GPU2019_3901, BASE_HW_ISSUE_END }; @@ -617,6 +621,7 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tGRx_r0p0 BASE_HW_ISSUE_TSIX_2033, BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3878, + BASE_HW_ISSUE_GPU2019_3901, BASE_HW_ISSUE_END }; @@ -626,6 +631,7 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_model_tGR BASE_HW_ISSUE_TSIX_2033, BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3878, + BASE_HW_ISSUE_GPU2019_3901, BASE_HW_ISSUE_END }; @@ -634,6 +640,7 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tVAx_r0p0 BASE_HW_ISSUE_TSIX_2033, BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3878, + BASE_HW_ISSUE_GPU2019_3901, BASE_HW_ISSUE_END }; @@ -643,6 +650,7 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_model_tVA BASE_HW_ISSUE_TSIX_2033, BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3878, + BASE_HW_ISSUE_GPU2019_3901, BASE_HW_ISSUE_END }; @@ -653,6 +661,8 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r0p0 BASE_HW_ISSUE_TURSEHW_1997, BASE_HW_ISSUE_GPU2019_3878, BASE_HW_ISSUE_TURSEHW_2716, + BASE_HW_ISSUE_GPU2019_3901, + BASE_HW_ISSUE_GPU2021PRO_290, BASE_HW_ISSUE_END }; @@ -663,6 +673,8 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_model_tTU BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3878, BASE_HW_ISSUE_TURSEHW_2716, + BASE_HW_ISSUE_GPU2019_3901, + BASE_HW_ISSUE_GPU2021PRO_290, BASE_HW_ISSUE_END }; @@ -672,6 +684,8 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p0 BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3878, BASE_HW_ISSUE_TURSEHW_2716, + BASE_HW_ISSUE_GPU2019_3901, + BASE_HW_ISSUE_GPU2021PRO_290, BASE_HW_ISSUE_END }; @@ -681,6 +695,8 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p1 BASE_HW_ISSUE_TTRX_1337, BASE_HW_ISSUE_GPU2019_3878, BASE_HW_ISSUE_TURSEHW_2716, + BASE_HW_ISSUE_GPU2019_3901, + BASE_HW_ISSUE_GPU2021PRO_290, BASE_HW_ISSUE_END }; diff --git a/drivers/gpu/arm/bifrost/mali_kbase.h b/drivers/gpu/arm/bifrost/mali_kbase.h index 10faaf355f7b..7d0d0dae0279 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase.h +++ b/drivers/gpu/arm/bifrost/mali_kbase.h @@ -82,14 +82,7 @@ #if MALI_USE_CSF #include "csf/mali_kbase_csf.h" -#endif -#ifndef u64_to_user_ptr -/* Introduced in Linux v4.6 */ -#define u64_to_user_ptr(x) ((void __user *)(uintptr_t)x) -#endif - -#if MALI_USE_CSF /* Physical memory group ID for CSF user I/O. */ #define KBASE_MEM_GROUP_CSF_IO BASE_MEM_GROUP_DEFAULT @@ -115,6 +108,13 @@ struct kbase_device *kbase_device_alloc(void); int kbase_device_misc_init(struct kbase_device *kbdev); void kbase_device_misc_term(struct kbase_device *kbdev); + +#if !MALI_USE_CSF +void kbase_enable_quick_reset(struct kbase_device *kbdev); +void kbase_disable_quick_reset(struct kbase_device *kbdev); +bool kbase_is_quick_reset_enabled(struct kbase_device *kbdev); +#endif + void kbase_device_free(struct kbase_device *kbdev); int kbase_device_has_feature(struct kbase_device *kbdev, u32 feature); @@ -258,7 +258,7 @@ void kbase_jd_cancel(struct kbase_device *kbdev, struct kbase_jd_atom *katom); void kbase_jd_zap_context(struct kbase_context *kctx); /* - * jd_done_nolock - Perform the necessary handling of an atom that has completed + * kbase_jd_done_nolock - Perform the necessary handling of an atom that has completed * the execution. * * @katom: Pointer to the atom that completed the execution @@ -274,7 +274,7 @@ void kbase_jd_zap_context(struct kbase_context *kctx); * * The caller must hold the kbase_jd_context.lock. */ -bool jd_done_nolock(struct kbase_jd_atom *katom, bool post_immediately); +bool kbase_jd_done_nolock(struct kbase_jd_atom *katom, bool post_immediately); void kbase_jd_free_external_resources(struct kbase_jd_atom *katom); void kbase_jd_dep_clear_locked(struct kbase_jd_atom *katom); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h b/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h index 9972bc382441..152ae2dfda8d 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h @@ -176,7 +176,7 @@ enum { * Based on 75000ms timeout at nominal 100MHz, as is required for Android - based * on scaling from a 50MHz GPU system. */ -#define CSF_FIRMWARE_TIMEOUT_CYCLES (7500000000) +#define CSF_FIRMWARE_TIMEOUT_CYCLES (7500000000ull) /* Timeout in clock cycles for GPU Power Management to reach the desired * Shader, L2 and MCU state. @@ -203,6 +203,12 @@ enum { */ #define CSF_FIRMWARE_BOOT_TIMEOUT_CYCLES (25000000) +/* Waiting timeout for a ping request to be acknowledged, in clock cycles. + * + * Based on 6000ms timeout at 100MHz, scaled from a 50MHz GPU system. + */ +#define CSF_FIRMWARE_PING_TIMEOUT_CYCLES (600000000ull) + #else /* MALI_USE_CSF */ /* A default timeout in clock cycles to be used when an invalid timeout @@ -213,7 +219,7 @@ enum { /* Default number of milliseconds given for other jobs on the GPU to be * soft-stopped when the GPU needs to be reset. */ -#define JM_DEFAULT_RESET_TIMEOUT_MS (3000) /* 3s */ +#define JM_DEFAULT_RESET_TIMEOUT_MS (1) /* 1 ms */ #endif /* MALI_USE_CSF */ diff --git a/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c b/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c index 0d3fd653af9f..0c8f653a9bff 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c @@ -99,6 +99,7 @@ #include /* is_compat_task/in_compat_syscall */ #include #include +#include #include #if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) #include @@ -311,10 +312,9 @@ static int kbase_file_create_kctx(struct kbase_file *kfile, * * @kfile: A device file created by kbase_file_new() * - * This function returns an error code (encoded with ERR_PTR) if no context - * has been created for the given @kfile. This makes it safe to use in - * circumstances where the order of initialization cannot be enforced, but - * only if the caller checks the return value. + * This function returns NULL if no context has been created for the given @kfile. + * This makes it safe to use in circumstances where the order of initialization + * cannot be enforced, but only if the caller checks the return value. * * Return: Address of the kernel base context associated with the @kfile, or * NULL if no context exists. @@ -502,27 +502,6 @@ void kbase_release_device(struct kbase_device *kbdev) EXPORT_SYMBOL(kbase_release_device); #if IS_ENABLED(CONFIG_DEBUG_FS) -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && \ - !(KERNEL_VERSION(4, 4, 28) <= LINUX_VERSION_CODE && \ - KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) -/* - * Older versions, before v4.6, of the kernel doesn't have - * kstrtobool_from_user(), except longterm 4.4.y which had it added in 4.4.28 - */ -static int kstrtobool_from_user(const char __user *s, size_t count, bool *res) -{ - char buf[4]; - - count = min(count, sizeof(buf) - 1); - - if (copy_from_user(buf, s, count)) - return -EFAULT; - buf[count] = '\0'; - - return strtobool(buf, res); -} -#endif - static ssize_t write_ctx_infinite_cache(struct file *f, const char __user *ubuf, size_t size, loff_t *off) { struct kbase_context *kctx = f->private_data; @@ -634,13 +613,8 @@ static int kbase_file_create_kctx(struct kbase_file *const kfile, kbdev = kfile->kbdev; -#if (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) kctx = kbase_create_context(kbdev, in_compat_syscall(), flags, kfile->api_version, kfile->filp); -#else - kctx = kbase_create_context(kbdev, is_compat_task(), - flags, kfile->api_version, kfile->filp); -#endif /* (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) */ /* if bad flags, will stay stuck in setup mode */ if (!kctx) @@ -661,16 +635,8 @@ static int kbase_file_create_kctx(struct kbase_file *const kfile, /* we don't treat this as a fail - just warn about it */ dev_warn(kbdev->dev, "couldn't create debugfs dir for kctx\n"); } else { -#if (KERNEL_VERSION(4, 7, 0) > LINUX_VERSION_CODE) - /* prevent unprivileged use of debug file system - * in old kernel version - */ - debugfs_create_file("infinite_cache", 0600, kctx->kctx_dentry, - kctx, &kbase_infinite_cache_fops); -#else debugfs_create_file("infinite_cache", 0644, kctx->kctx_dentry, kctx, &kbase_infinite_cache_fops); -#endif debugfs_create_file("force_same_va", 0600, kctx->kctx_dentry, kctx, &kbase_force_same_va_fops); @@ -2200,18 +2166,28 @@ static ssize_t kbase_read(struct file *filp, char __user *buf, size_t count, lof } #endif /* MALI_USE_CSF */ -static unsigned int kbase_poll(struct file *filp, poll_table *wait) +static __poll_t kbase_poll(struct file *filp, poll_table *wait) { struct kbase_file *const kfile = filp->private_data; struct kbase_context *const kctx = kbase_file_get_kctx_if_setup_complete(kfile); - if (unlikely(!kctx)) + if (unlikely(!kctx)) { +#if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE) return POLLERR; +#else + return EPOLLERR; +#endif + } poll_wait(filp, &kctx->event_queue, wait); - if (kbase_event_pending(kctx)) + if (kbase_event_pending(kctx)) { +#if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE) return POLLIN | POLLRDNORM; +#else + return EPOLLIN | EPOLLRDNORM; +#endif + } return 0; } @@ -4542,7 +4518,7 @@ int power_control_init(struct kbase_device *kbdev) } } if (err == -EPROBE_DEFER) { - while ((i > 0) && (i < BASE_MAX_NR_CLOCKS_REGULATORS)) + while (i > 0) regulator_put(kbdev->regulators[--i]); return err; } @@ -4579,8 +4555,8 @@ int power_control_init(struct kbase_device *kbdev) } } if (err == -EPROBE_DEFER) { - while ((i > 0) && (i < BASE_MAX_NR_CLOCKS_REGULATORS)) { - clk_unprepare(kbdev->clocks[--i]); + while (i > 0) { + clk_disable_unprepare(kbdev->clocks[--i]); clk_put(kbdev->clocks[i]); } goto clocks_probe_defer; @@ -4627,6 +4603,19 @@ int power_control_init(struct kbase_device *kbdev) #endif /* CONFIG_PM_OPP */ return 0; +#if defined(CONFIG_PM_OPP) && \ + ((KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE) && defined(CONFIG_REGULATOR)) + for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) { + if (kbdev->clocks[i]) { + if (__clk_is_enabled(kbdev->clocks[i])) + clk_disable_unprepare(kbdev->clocks[i]); + clk_put(kbdev->clocks[i]); + kbdev->clocks[i] = NULL; + } else + break; + } +#endif + clocks_probe_defer: #if defined(CONFIG_REGULATOR) for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) @@ -4819,12 +4808,7 @@ int kbase_device_debugfs_init(struct kbase_device *kbdev) /* prevent unprivileged use of debug file system * in old kernel version */ -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) - /* only for newer kernel version debug file system is safe */ const mode_t mode = 0644; -#else - const mode_t mode = 0600; -#endif kbdev->mali_debugfs_directory = debugfs_create_dir(kbdev->devname, NULL); @@ -4930,6 +4914,7 @@ int kbase_device_debugfs_init(struct kbase_device *kbdev) #endif kbase_dvfs_status_debugfs_init(kbdev); + return 0; out: @@ -5126,10 +5111,11 @@ static ssize_t fw_timeout_store(struct device *dev, ret = kstrtouint(buf, 0, &fw_timeout); if (ret || fw_timeout == 0) { - dev_err(kbdev->dev, "%s\n%s\n%u", - "Couldn't process fw_timeout write operation.", - "Use format 'fw_timeout_ms', and fw_timeout_ms > 0", - FIRMWARE_PING_INTERVAL_MS); + dev_err(kbdev->dev, + "Couldn't process fw_timeout write operation.\n" + "Use format 'fw_timeout_ms', and fw_timeout_ms > 0\n" + "Default fw_timeout: %u", + kbase_get_timeout_ms(kbdev, CSF_FIRMWARE_PING_TIMEOUT)); return -EINVAL; } @@ -5564,6 +5550,11 @@ static int kbase_device_resume(struct device *dev) if (kbdev->devfreq) kbase_devfreq_enqueue_work(kbdev, DEVFREQ_WORK_RESUME); #endif + +#if !MALI_USE_CSF + kbase_enable_quick_reset(kbdev); +#endif + return 0; } diff --git a/drivers/gpu/arm/bifrost/mali_kbase_debug_job_fault.c b/drivers/gpu/arm/bifrost/mali_kbase_debug_job_fault.c index 4f021b316b83..d6518b476115 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_debug_job_fault.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_debug_job_fault.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2012-2016, 2018-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2012-2016, 2018-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -87,8 +87,7 @@ static bool kbase_ctx_has_no_event_pending(struct kbase_context *kctx) static int wait_for_job_fault(struct kbase_device *kbdev) { -#if KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE && \ - KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE +#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE int ret = wait_event_interruptible_timeout(kbdev->job_fault_wq, kbase_is_job_fault_event_pending(kbdev), msecs_to_jiffies(2000)); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_defs.h b/drivers/gpu/arm/bifrost/mali_kbase_defs.h index 26f1dab5401e..9fafe96d14a8 100755 --- a/drivers/gpu/arm/bifrost/mali_kbase_defs.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_defs.h @@ -579,7 +579,7 @@ struct kbase_mmu_mode { int (*pte_is_valid)(u64 pte, int level); void (*entry_set_ate)(u64 *entry, struct tagged_addr phy, unsigned long flags, int level); - void (*entry_set_pte)(u64 *pgd, u64 vpfn, phys_addr_t phy); + void (*entry_set_pte)(u64 *entry, phys_addr_t phy); void (*entry_invalidate)(u64 *entry); unsigned int (*get_num_valid_entries)(u64 *pgd); void (*set_num_valid_entries)(u64 *pgd, @@ -1154,11 +1154,8 @@ struct kbase_device { #endif bool poweroff_pending; -#if (KERNEL_VERSION(4, 4, 0) <= LINUX_VERSION_CODE) bool infinite_cache_active_default; -#else - u32 infinite_cache_active_default; -#endif + struct kbase_mem_pool_group_config mem_pool_defaults; u32 current_gpu_coherency_mode; @@ -1241,6 +1238,18 @@ struct kbase_device { struct notifier_block oom_notifier_block; +#if !MALI_USE_CSF + spinlock_t quick_reset_lock; + bool quick_reset_enabled; + /* + * 进入 quck_reset_mode 后 (quick_reset_enabled 为 true), + * 对已经进入 KBASE_JD_ATOM_STATE_HW_COMPLETED 状态的 atom 的计数. + * + * 若 num_of_atoms_hw_completed 达到一定值, 将退出 quck_reset_mode. + * 见 kbase_js_complete_atom() 对 num_of_atoms_hw_completed 的引用. + */ + u32 num_of_atoms_hw_completed; +#endif }; /** diff --git a/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.c b/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.c index 51d1bd178b7f..d5f4fae091e8 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.c @@ -161,7 +161,7 @@ kbase_dma_fence_cancel_atom(struct kbase_jd_atom *katom) if (katom->status == KBASE_JD_ATOM_STATE_QUEUED) { /* Wait was cancelled - zap the atom */ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; - if (jd_done_nolock(katom, true)) + if (kbase_jd_done_nolock(katom, true)) kbase_js_sched_all(katom->kctx->kbdev); } } @@ -193,10 +193,10 @@ kbase_dma_fence_work(struct work_struct *pwork) kbase_fence_free_callbacks(katom); /* * Queue atom on GPU, unless it has already completed due to a failing - * dependency. Run jd_done_nolock() on the katom if it is completed. + * dependency. Run kbase_jd_done_nolock() on the katom if it is completed. */ if (unlikely(katom->status == KBASE_JD_ATOM_STATE_COMPLETED)) - jd_done_nolock(katom, true); + kbase_jd_done_nolock(katom, true); else kbase_jd_dep_clear_locked(katom); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.h b/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.h index 36c34fe30107..f0c8d069b02c 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_dma_fence.h @@ -105,7 +105,7 @@ void kbase_dma_fence_cancel_all_atoms(struct kbase_context *kctx); * This function cancels all dma-buf fence callbacks on @katom, but does not * cancel the katom itself. * - * The caller is responsible for ensuring that jd_done_nolock is called on + * The caller is responsible for ensuring that kbase_jd_done_nolock is called on * @katom. * * Locking: jctx.lock must be held when calling this function. diff --git a/drivers/gpu/arm/bifrost/mali_kbase_dvfs_debugfs.c b/drivers/gpu/arm/bifrost/mali_kbase_dvfs_debugfs.c index 1e584deb0e33..e4cb71632aee 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_dvfs_debugfs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_dvfs_debugfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -68,11 +68,7 @@ static const struct file_operations kbasep_dvfs_utilization_debugfs_fops = { void kbase_dvfs_status_debugfs_init(struct kbase_device *kbdev) { struct dentry *file; -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) const mode_t mode = 0444; -#else - const mode_t mode = 0400; -#endif if (WARN_ON(!kbdev || IS_ERR_OR_NULL(kbdev->mali_debugfs_directory))) return; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_fence.h b/drivers/gpu/arm/bifrost/mali_kbase_fence.h index 1ed3b9bd7f1d..4f952ad4d509 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_fence.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_fence.h @@ -271,6 +271,16 @@ bool kbase_fence_free_callbacks(struct kbase_jd_atom *katom); #endif /* !MALI_USE_CSF */ +/** + * kbase_fence_get() - Retrieve fence for a KCPUQ fence command. + * @fence_info: KCPUQ fence command + * + * A ref will be taken for the fence, so use @kbase_fence_put() to release it + * + * Return: The fence, or NULL if there is no fence for KCPUQ fence command + */ +#define kbase_fence_get(fence_info) dma_fence_get((fence_info)->fence) + /** * kbase_fence_put() - Releases a reference to a fence * @fence: Fence to release reference for. diff --git a/drivers/gpu/arm/bifrost/mali_kbase_fence_ops.c b/drivers/gpu/arm/bifrost/mali_kbase_fence_ops.c index 14ddf0308317..be141553c674 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_fence_ops.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_fence_ops.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -69,9 +69,11 @@ kbase_fence_fence_value_str(struct dma_fence *fence, char *str, int size) } #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) +extern const struct fence_ops kbase_fence_ops; /* silence checker warning */ const struct fence_ops kbase_fence_ops = { .wait = fence_default_wait, #else +extern const struct dma_fence_ops kbase_fence_ops; /* silence checker warning */ const struct dma_fence_ops kbase_fence_ops = { .wait = dma_fence_default_wait, #endif diff --git a/drivers/gpu/arm/bifrost/mali_kbase_gpuprops.c b/drivers/gpu/arm/bifrost/mali_kbase_gpuprops.c index cd1ecba32b77..0bea655178d5 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_gpuprops.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_gpuprops.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -198,7 +198,6 @@ static int kbase_gpuprops_get_props(struct base_gpu_props * const gpu_props, gpu_props->raw_props.mem_features = regdump.mem_features; gpu_props->raw_props.mmu_features = regdump.mmu_features; gpu_props->raw_props.l2_features = regdump.l2_features; - gpu_props->raw_props.core_features = regdump.core_features; gpu_props->raw_props.as_present = regdump.as_present; gpu_props->raw_props.js_present = regdump.js_present; @@ -324,9 +323,6 @@ static void kbase_gpuprops_calculate_props( totalram_pages() << PAGE_SHIFT; #endif - gpu_props->core_props.num_exec_engines = - KBASE_UBFX32(gpu_props->raw_props.core_features, 0, 4); - for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++) gpu_props->core_props.texture_features[i] = gpu_props->raw_props.texture_features[i]; @@ -507,6 +503,21 @@ int kbase_gpuprops_set_features(struct kbase_device *kbdev) if (!kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_THREAD_GROUP_SPLIT)) gpu_props->thread_props.max_thread_group_split = 0; + /* + * The CORE_FEATURES register has different meanings depending on GPU. + * On tGOx, bits[3:0] encode num_exec_engines. + * On CSF GPUs, bits[7:0] is an enumeration that needs to be parsed, + * instead. + * GPUs like tTIx have additional fields like LSC_SIZE that are + * otherwise reserved/RAZ on older GPUs. + */ + gpu_props->raw_props.core_features = regdump.core_features; + +#if !MALI_USE_CSF + gpu_props->core_props.num_exec_engines = + KBASE_UBFX32(gpu_props->raw_props.core_features, 0, 4); +#endif + return err; } @@ -694,94 +705,102 @@ static struct { #define PROP(name, member) \ {KBASE_GPUPROP_ ## name, offsetof(struct base_gpu_props, member), \ sizeof(((struct base_gpu_props *)0)->member)} - PROP(PRODUCT_ID, core_props.product_id), - PROP(VERSION_STATUS, core_props.version_status), - PROP(MINOR_REVISION, core_props.minor_revision), - PROP(MAJOR_REVISION, core_props.major_revision), - PROP(GPU_FREQ_KHZ_MAX, core_props.gpu_freq_khz_max), - PROP(LOG2_PROGRAM_COUNTER_SIZE, core_props.log2_program_counter_size), - PROP(TEXTURE_FEATURES_0, core_props.texture_features[0]), - PROP(TEXTURE_FEATURES_1, core_props.texture_features[1]), - PROP(TEXTURE_FEATURES_2, core_props.texture_features[2]), - PROP(TEXTURE_FEATURES_3, core_props.texture_features[3]), - PROP(GPU_AVAILABLE_MEMORY_SIZE, core_props.gpu_available_memory_size), - PROP(NUM_EXEC_ENGINES, core_props.num_exec_engines), +#define BACKWARDS_COMPAT_PROP(name, type) \ + { \ + KBASE_GPUPROP_##name, SIZE_MAX, sizeof(type) \ + } + PROP(PRODUCT_ID, core_props.product_id), + PROP(VERSION_STATUS, core_props.version_status), + PROP(MINOR_REVISION, core_props.minor_revision), + PROP(MAJOR_REVISION, core_props.major_revision), + PROP(GPU_FREQ_KHZ_MAX, core_props.gpu_freq_khz_max), + PROP(LOG2_PROGRAM_COUNTER_SIZE, core_props.log2_program_counter_size), + PROP(TEXTURE_FEATURES_0, core_props.texture_features[0]), + PROP(TEXTURE_FEATURES_1, core_props.texture_features[1]), + PROP(TEXTURE_FEATURES_2, core_props.texture_features[2]), + PROP(TEXTURE_FEATURES_3, core_props.texture_features[3]), + PROP(GPU_AVAILABLE_MEMORY_SIZE, core_props.gpu_available_memory_size), - PROP(L2_LOG2_LINE_SIZE, l2_props.log2_line_size), - PROP(L2_LOG2_CACHE_SIZE, l2_props.log2_cache_size), - PROP(L2_NUM_L2_SLICES, l2_props.num_l2_slices), +#if MALI_USE_CSF + BACKWARDS_COMPAT_PROP(NUM_EXEC_ENGINES, u8), +#else + PROP(NUM_EXEC_ENGINES, core_props.num_exec_engines), +#endif - PROP(TILER_BIN_SIZE_BYTES, tiler_props.bin_size_bytes), - PROP(TILER_MAX_ACTIVE_LEVELS, tiler_props.max_active_levels), + PROP(L2_LOG2_LINE_SIZE, l2_props.log2_line_size), + PROP(L2_LOG2_CACHE_SIZE, l2_props.log2_cache_size), + PROP(L2_NUM_L2_SLICES, l2_props.num_l2_slices), - PROP(MAX_THREADS, thread_props.max_threads), - PROP(MAX_WORKGROUP_SIZE, thread_props.max_workgroup_size), - PROP(MAX_BARRIER_SIZE, thread_props.max_barrier_size), - PROP(MAX_REGISTERS, thread_props.max_registers), - PROP(MAX_TASK_QUEUE, thread_props.max_task_queue), - PROP(MAX_THREAD_GROUP_SPLIT, thread_props.max_thread_group_split), - PROP(IMPL_TECH, thread_props.impl_tech), - PROP(TLS_ALLOC, thread_props.tls_alloc), + PROP(TILER_BIN_SIZE_BYTES, tiler_props.bin_size_bytes), + PROP(TILER_MAX_ACTIVE_LEVELS, tiler_props.max_active_levels), - PROP(RAW_SHADER_PRESENT, raw_props.shader_present), - PROP(RAW_TILER_PRESENT, raw_props.tiler_present), - PROP(RAW_L2_PRESENT, raw_props.l2_present), - PROP(RAW_STACK_PRESENT, raw_props.stack_present), - PROP(RAW_L2_FEATURES, raw_props.l2_features), - PROP(RAW_CORE_FEATURES, raw_props.core_features), - PROP(RAW_MEM_FEATURES, raw_props.mem_features), - PROP(RAW_MMU_FEATURES, raw_props.mmu_features), - PROP(RAW_AS_PRESENT, raw_props.as_present), - PROP(RAW_JS_PRESENT, raw_props.js_present), - PROP(RAW_JS_FEATURES_0, raw_props.js_features[0]), - PROP(RAW_JS_FEATURES_1, raw_props.js_features[1]), - PROP(RAW_JS_FEATURES_2, raw_props.js_features[2]), - PROP(RAW_JS_FEATURES_3, raw_props.js_features[3]), - PROP(RAW_JS_FEATURES_4, raw_props.js_features[4]), - PROP(RAW_JS_FEATURES_5, raw_props.js_features[5]), - PROP(RAW_JS_FEATURES_6, raw_props.js_features[6]), - PROP(RAW_JS_FEATURES_7, raw_props.js_features[7]), - PROP(RAW_JS_FEATURES_8, raw_props.js_features[8]), - PROP(RAW_JS_FEATURES_9, raw_props.js_features[9]), - PROP(RAW_JS_FEATURES_10, raw_props.js_features[10]), - PROP(RAW_JS_FEATURES_11, raw_props.js_features[11]), - PROP(RAW_JS_FEATURES_12, raw_props.js_features[12]), - PROP(RAW_JS_FEATURES_13, raw_props.js_features[13]), - PROP(RAW_JS_FEATURES_14, raw_props.js_features[14]), - PROP(RAW_JS_FEATURES_15, raw_props.js_features[15]), - PROP(RAW_TILER_FEATURES, raw_props.tiler_features), - PROP(RAW_TEXTURE_FEATURES_0, raw_props.texture_features[0]), - PROP(RAW_TEXTURE_FEATURES_1, raw_props.texture_features[1]), - PROP(RAW_TEXTURE_FEATURES_2, raw_props.texture_features[2]), - PROP(RAW_TEXTURE_FEATURES_3, raw_props.texture_features[3]), - PROP(RAW_GPU_ID, raw_props.gpu_id), - PROP(RAW_THREAD_MAX_THREADS, raw_props.thread_max_threads), - PROP(RAW_THREAD_MAX_WORKGROUP_SIZE, - raw_props.thread_max_workgroup_size), + PROP(MAX_THREADS, thread_props.max_threads), + PROP(MAX_WORKGROUP_SIZE, thread_props.max_workgroup_size), + PROP(MAX_BARRIER_SIZE, thread_props.max_barrier_size), + PROP(MAX_REGISTERS, thread_props.max_registers), + PROP(MAX_TASK_QUEUE, thread_props.max_task_queue), + PROP(MAX_THREAD_GROUP_SPLIT, thread_props.max_thread_group_split), + PROP(IMPL_TECH, thread_props.impl_tech), + PROP(TLS_ALLOC, thread_props.tls_alloc), + + PROP(RAW_SHADER_PRESENT, raw_props.shader_present), + PROP(RAW_TILER_PRESENT, raw_props.tiler_present), + PROP(RAW_L2_PRESENT, raw_props.l2_present), + PROP(RAW_STACK_PRESENT, raw_props.stack_present), + PROP(RAW_L2_FEATURES, raw_props.l2_features), + PROP(RAW_CORE_FEATURES, raw_props.core_features), + PROP(RAW_MEM_FEATURES, raw_props.mem_features), + PROP(RAW_MMU_FEATURES, raw_props.mmu_features), + PROP(RAW_AS_PRESENT, raw_props.as_present), + PROP(RAW_JS_PRESENT, raw_props.js_present), + PROP(RAW_JS_FEATURES_0, raw_props.js_features[0]), + PROP(RAW_JS_FEATURES_1, raw_props.js_features[1]), + PROP(RAW_JS_FEATURES_2, raw_props.js_features[2]), + PROP(RAW_JS_FEATURES_3, raw_props.js_features[3]), + PROP(RAW_JS_FEATURES_4, raw_props.js_features[4]), + PROP(RAW_JS_FEATURES_5, raw_props.js_features[5]), + PROP(RAW_JS_FEATURES_6, raw_props.js_features[6]), + PROP(RAW_JS_FEATURES_7, raw_props.js_features[7]), + PROP(RAW_JS_FEATURES_8, raw_props.js_features[8]), + PROP(RAW_JS_FEATURES_9, raw_props.js_features[9]), + PROP(RAW_JS_FEATURES_10, raw_props.js_features[10]), + PROP(RAW_JS_FEATURES_11, raw_props.js_features[11]), + PROP(RAW_JS_FEATURES_12, raw_props.js_features[12]), + PROP(RAW_JS_FEATURES_13, raw_props.js_features[13]), + PROP(RAW_JS_FEATURES_14, raw_props.js_features[14]), + PROP(RAW_JS_FEATURES_15, raw_props.js_features[15]), + PROP(RAW_TILER_FEATURES, raw_props.tiler_features), + PROP(RAW_TEXTURE_FEATURES_0, raw_props.texture_features[0]), + PROP(RAW_TEXTURE_FEATURES_1, raw_props.texture_features[1]), + PROP(RAW_TEXTURE_FEATURES_2, raw_props.texture_features[2]), + PROP(RAW_TEXTURE_FEATURES_3, raw_props.texture_features[3]), + PROP(RAW_GPU_ID, raw_props.gpu_id), + PROP(RAW_THREAD_MAX_THREADS, raw_props.thread_max_threads), + PROP(RAW_THREAD_MAX_WORKGROUP_SIZE, raw_props.thread_max_workgroup_size), PROP(RAW_THREAD_MAX_BARRIER_SIZE, raw_props.thread_max_barrier_size), - PROP(RAW_THREAD_FEATURES, raw_props.thread_features), - PROP(RAW_COHERENCY_MODE, raw_props.coherency_mode), - PROP(RAW_THREAD_TLS_ALLOC, raw_props.thread_tls_alloc), - PROP(RAW_GPU_FEATURES, raw_props.gpu_features), - PROP(COHERENCY_NUM_GROUPS, coherency_info.num_groups), - PROP(COHERENCY_NUM_CORE_GROUPS, coherency_info.num_core_groups), - PROP(COHERENCY_COHERENCY, coherency_info.coherency), - PROP(COHERENCY_GROUP_0, coherency_info.group[0].core_mask), - PROP(COHERENCY_GROUP_1, coherency_info.group[1].core_mask), - PROP(COHERENCY_GROUP_2, coherency_info.group[2].core_mask), - PROP(COHERENCY_GROUP_3, coherency_info.group[3].core_mask), - PROP(COHERENCY_GROUP_4, coherency_info.group[4].core_mask), - PROP(COHERENCY_GROUP_5, coherency_info.group[5].core_mask), - PROP(COHERENCY_GROUP_6, coherency_info.group[6].core_mask), - PROP(COHERENCY_GROUP_7, coherency_info.group[7].core_mask), - PROP(COHERENCY_GROUP_8, coherency_info.group[8].core_mask), - PROP(COHERENCY_GROUP_9, coherency_info.group[9].core_mask), - PROP(COHERENCY_GROUP_10, coherency_info.group[10].core_mask), - PROP(COHERENCY_GROUP_11, coherency_info.group[11].core_mask), - PROP(COHERENCY_GROUP_12, coherency_info.group[12].core_mask), - PROP(COHERENCY_GROUP_13, coherency_info.group[13].core_mask), - PROP(COHERENCY_GROUP_14, coherency_info.group[14].core_mask), - PROP(COHERENCY_GROUP_15, coherency_info.group[15].core_mask), + PROP(RAW_THREAD_FEATURES, raw_props.thread_features), + PROP(RAW_COHERENCY_MODE, raw_props.coherency_mode), + PROP(RAW_THREAD_TLS_ALLOC, raw_props.thread_tls_alloc), + PROP(RAW_GPU_FEATURES, raw_props.gpu_features), + PROP(COHERENCY_NUM_GROUPS, coherency_info.num_groups), + PROP(COHERENCY_NUM_CORE_GROUPS, coherency_info.num_core_groups), + PROP(COHERENCY_COHERENCY, coherency_info.coherency), + PROP(COHERENCY_GROUP_0, coherency_info.group[0].core_mask), + PROP(COHERENCY_GROUP_1, coherency_info.group[1].core_mask), + PROP(COHERENCY_GROUP_2, coherency_info.group[2].core_mask), + PROP(COHERENCY_GROUP_3, coherency_info.group[3].core_mask), + PROP(COHERENCY_GROUP_4, coherency_info.group[4].core_mask), + PROP(COHERENCY_GROUP_5, coherency_info.group[5].core_mask), + PROP(COHERENCY_GROUP_6, coherency_info.group[6].core_mask), + PROP(COHERENCY_GROUP_7, coherency_info.group[7].core_mask), + PROP(COHERENCY_GROUP_8, coherency_info.group[8].core_mask), + PROP(COHERENCY_GROUP_9, coherency_info.group[9].core_mask), + PROP(COHERENCY_GROUP_10, coherency_info.group[10].core_mask), + PROP(COHERENCY_GROUP_11, coherency_info.group[11].core_mask), + PROP(COHERENCY_GROUP_12, coherency_info.group[12].core_mask), + PROP(COHERENCY_GROUP_13, coherency_info.group[13].core_mask), + PROP(COHERENCY_GROUP_14, coherency_info.group[14].core_mask), + PROP(COHERENCY_GROUP_15, coherency_info.group[15].core_mask), #undef PROP }; @@ -818,7 +837,14 @@ int kbase_gpuprops_populate_user_buffer(struct kbase_device *kbdev) for (i = 0; i < count; i++) { u32 type = gpu_property_mapping[i].type; u8 type_size; - void *field = ((u8 *)props) + gpu_property_mapping[i].offset; + const size_t offset = gpu_property_mapping[i].offset; + const u64 dummy_backwards_compat_value = (u64)0; + const void *field; + + if (likely(offset < sizeof(struct base_gpu_props))) + field = ((const u8 *)props) + offset; + else + field = &dummy_backwards_compat_value; switch (gpu_property_mapping[i].size) { case 1: @@ -844,16 +870,16 @@ int kbase_gpuprops_populate_user_buffer(struct kbase_device *kbdev) switch (type_size) { case KBASE_GPUPROP_VALUE_SIZE_U8: - WRITE_U8(*((u8 *)field)); + WRITE_U8(*((const u8 *)field)); break; case KBASE_GPUPROP_VALUE_SIZE_U16: - WRITE_U16(*((u16 *)field)); + WRITE_U16(*((const u16 *)field)); break; case KBASE_GPUPROP_VALUE_SIZE_U32: - WRITE_U32(*((u32 *)field)); + WRITE_U32(*((const u32 *)field)); break; case KBASE_GPUPROP_VALUE_SIZE_U64: - WRITE_U64(*((u64 *)field)); + WRITE_U64(*((const u64 *)field)); break; default: /* Cannot be reached */ WARN_ON(1); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf.c b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf.c index 016633164a9e..8afc990662da 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf.c @@ -173,23 +173,29 @@ struct kbase_hwcnt_backend_csf_info { /** * struct kbase_hwcnt_csf_physical_layout - HWC sample memory physical layout * information. + * @hw_block_cnt: Total number of hardware counters blocks. The hw counters blocks are + * sub-categorized into 4 classes: front-end, tiler, memory system, and shader. + * hw_block_cnt = fe_cnt + tiler_cnt + mmu_l2_cnt + shader_cnt. * @fe_cnt: Front end block count. * @tiler_cnt: Tiler block count. - * @mmu_l2_cnt: Memory system(MMU and L2 cache) block count. + * @mmu_l2_cnt: Memory system (MMU and L2 cache) block count. * @shader_cnt: Shader Core block count. - * @block_cnt: Total block count (sum of all other block counts). + * @fw_block_cnt: Total number of firmware counters blocks. + * @block_cnt: Total block count (sum of all counter blocks: hw_block_cnt + fw_block_cnt). * @shader_avail_mask: Bitmap of all shader cores in the system. * @enable_mask_offset: Offset in array elements of enable mask in each block * starting from the beginning of block. - * @headers_per_block: Header size per block. - * @counters_per_block: Counters size per block. - * @values_per_block: Total size per block. + * @headers_per_block: For any block, the number of counters designated as block's header. + * @counters_per_block: For any block, the number of counters designated as block's payload. + * @values_per_block: For any block, the number of counters in total (header + payload). */ struct kbase_hwcnt_csf_physical_layout { + u8 hw_block_cnt; u8 fe_cnt; u8 tiler_cnt; u8 mmu_l2_cnt; u8 shader_cnt; + u8 fw_block_cnt; u8 block_cnt; u64 shader_avail_mask; size_t enable_mask_offset; @@ -366,29 +372,38 @@ static void kbasep_hwcnt_backend_csf_init_layout( const struct kbase_hwcnt_backend_csf_if_prfcnt_info *prfcnt_info, struct kbase_hwcnt_csf_physical_layout *phys_layout) { - u8 shader_core_cnt; + size_t shader_core_cnt; size_t values_per_block; + size_t fw_blocks_count; + size_t hw_blocks_count; WARN_ON(!prfcnt_info); WARN_ON(!phys_layout); shader_core_cnt = fls64(prfcnt_info->core_mask); - values_per_block = - prfcnt_info->prfcnt_block_size / KBASE_HWCNT_VALUE_HW_BYTES; + values_per_block = prfcnt_info->prfcnt_block_size / KBASE_HWCNT_VALUE_HW_BYTES; + fw_blocks_count = div_u64(prfcnt_info->prfcnt_fw_size, prfcnt_info->prfcnt_block_size); + hw_blocks_count = div_u64(prfcnt_info->prfcnt_hw_size, prfcnt_info->prfcnt_block_size); + + /* The number of hardware counters reported by the GPU matches the legacy guess-work we + * have done in the past + */ + WARN_ON(hw_blocks_count != KBASE_HWCNT_V5_FE_BLOCK_COUNT + + KBASE_HWCNT_V5_TILER_BLOCK_COUNT + + prfcnt_info->l2_count + shader_core_cnt); *phys_layout = (struct kbase_hwcnt_csf_physical_layout){ .fe_cnt = KBASE_HWCNT_V5_FE_BLOCK_COUNT, .tiler_cnt = KBASE_HWCNT_V5_TILER_BLOCK_COUNT, .mmu_l2_cnt = prfcnt_info->l2_count, .shader_cnt = shader_core_cnt, - .block_cnt = KBASE_HWCNT_V5_FE_BLOCK_COUNT + - KBASE_HWCNT_V5_TILER_BLOCK_COUNT + - prfcnt_info->l2_count + shader_core_cnt, + .fw_block_cnt = fw_blocks_count, + .hw_block_cnt = hw_blocks_count, + .block_cnt = fw_blocks_count + hw_blocks_count, .shader_avail_mask = prfcnt_info->core_mask, .headers_per_block = KBASE_HWCNT_V5_HEADERS_PER_BLOCK, .values_per_block = values_per_block, - .counters_per_block = - values_per_block - KBASE_HWCNT_V5_HEADERS_PER_BLOCK, + .counters_per_block = values_per_block - KBASE_HWCNT_V5_HEADERS_PER_BLOCK, .enable_mask_offset = KBASE_HWCNT_V5_PRFCNT_EN_HEADER, }; } @@ -463,7 +478,15 @@ static void kbasep_hwcnt_backend_csf_accumulate_sample( u64 *acc_block = accum_buf; const size_t values_per_block = phys_layout->values_per_block; - for (block_idx = 0; block_idx < phys_layout->block_cnt; block_idx++) { + /* Performance counter blocks for firmware are stored before blocks for hardware. + * We skip over the firmware's performance counter blocks (counters dumping is not + * supported for firmware blocks, only hardware ones). + */ + old_block += values_per_block * phys_layout->fw_block_cnt; + new_block += values_per_block * phys_layout->fw_block_cnt; + + for (block_idx = phys_layout->fw_block_cnt; block_idx < phys_layout->block_cnt; + block_idx++) { const u32 old_enable_mask = old_block[phys_layout->enable_mask_offset]; const u32 new_enable_mask = @@ -551,8 +574,8 @@ static void kbasep_hwcnt_backend_csf_accumulate_sample( old_sample_buf + (dump_bytes / KBASE_HWCNT_VALUE_HW_BYTES)); WARN_ON(new_block != new_sample_buf + (dump_bytes / KBASE_HWCNT_VALUE_HW_BYTES)); - WARN_ON(acc_block != - accum_buf + (dump_bytes / KBASE_HWCNT_VALUE_HW_BYTES)); + WARN_ON(acc_block != accum_buf + (dump_bytes / KBASE_HWCNT_VALUE_HW_BYTES) - + (values_per_block * phys_layout->fw_block_cnt)); (void)dump_bytes; } @@ -1942,7 +1965,6 @@ void kbase_hwcnt_backend_csf_on_prfcnt_disable( int kbase_hwcnt_backend_csf_metadata_init( struct kbase_hwcnt_backend_interface *iface) { - int errcode; struct kbase_hwcnt_backend_csf_info *csf_info; struct kbase_hwcnt_gpu_info gpu_info; @@ -1968,19 +1990,8 @@ int kbase_hwcnt_backend_csf_metadata_init( gpu_info.prfcnt_values_per_block = csf_info->prfcnt_info.prfcnt_block_size / KBASE_HWCNT_VALUE_HW_BYTES; - errcode = kbase_hwcnt_csf_metadata_create( - &gpu_info, csf_info->counter_set, &csf_info->metadata); - if (errcode) - return errcode; - - /* - * Dump abstraction size should be exactly twice the size and layout as - * the physical dump size since 64-bit per value used in metadata. - */ - WARN_ON(csf_info->prfcnt_info.dump_bytes * 2 != - csf_info->metadata->dump_buf_bytes); - - return 0; + return kbase_hwcnt_csf_metadata_create(&gpu_info, csf_info->counter_set, + &csf_info->metadata); } void kbase_hwcnt_backend_csf_metadata_term( diff --git a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if.h b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if.h index a4355ffd4796..24b26c2bd6f4 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if.h @@ -55,8 +55,12 @@ struct kbase_hwcnt_backend_csf_if_enable { /** * struct kbase_hwcnt_backend_csf_if_prfcnt_info - Performance counter * information. + * @prfcnt_hw_size: Total length in bytes of all the hardware counters data. The hardware + * counters are sub-divided into 4 classes: front-end, shader, tiler, and + * memory system (l2 cache + MMU). + * @prfcnt_fw_size: Total length in bytes of all the firmware counters data. * @dump_bytes: Bytes of GPU memory required to perform a performance - * counter dump. + * counter dump. dump_bytes = prfcnt_hw_size + prfcnt_fw_size. * @prfcnt_block_size: Bytes of each performance counter block. * @l2_count: The MMU L2 cache count. * @core_mask: Shader core mask. @@ -65,6 +69,8 @@ struct kbase_hwcnt_backend_csf_if_enable { * is taken. */ struct kbase_hwcnt_backend_csf_if_prfcnt_info { + size_t prfcnt_hw_size; + size_t prfcnt_fw_size; size_t dump_bytes; size_t prfcnt_block_size; size_t l2_count; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if_fw.c b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if_fw.c index 46be35ae5974..ab33a0b26486 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if_fw.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_backend_csf_if_fw.c @@ -221,30 +221,29 @@ static void kbasep_hwcnt_backend_csf_if_fw_get_prfcnt_info( struct kbase_hwcnt_backend_csf_if_prfcnt_info *prfcnt_info) { #if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) - size_t dummy_model_blk_count; struct kbase_hwcnt_backend_csf_if_fw_ctx *fw_ctx = (struct kbase_hwcnt_backend_csf_if_fw_ctx *)ctx; - prfcnt_info->l2_count = KBASE_DUMMY_MODEL_MAX_MEMSYS_BLOCKS; - prfcnt_info->core_mask = - (1ull << KBASE_DUMMY_MODEL_MAX_SHADER_CORES) - 1; - /* 1 FE block + 1 Tiler block + l2_count blocks + shader_core blocks */ - dummy_model_blk_count = - 2 + prfcnt_info->l2_count + fls64(prfcnt_info->core_mask); - prfcnt_info->dump_bytes = - dummy_model_blk_count * KBASE_DUMMY_MODEL_BLOCK_SIZE; - prfcnt_info->prfcnt_block_size = - KBASE_HWCNT_V5_DEFAULT_VALUES_PER_BLOCK * - KBASE_HWCNT_VALUE_HW_BYTES; - prfcnt_info->clk_cnt = 1; - prfcnt_info->clearing_samples = true; + *prfcnt_info = (struct kbase_hwcnt_backend_csf_if_prfcnt_info){ + .l2_count = KBASE_DUMMY_MODEL_MAX_MEMSYS_BLOCKS, + .core_mask = (1ull << KBASE_DUMMY_MODEL_MAX_SHADER_CORES) - 1, + .prfcnt_hw_size = + KBASE_DUMMY_MODEL_MAX_NUM_HARDWARE_BLOCKS * KBASE_DUMMY_MODEL_BLOCK_SIZE, + .prfcnt_fw_size = + KBASE_DUMMY_MODEL_MAX_FIRMWARE_BLOCKS * KBASE_DUMMY_MODEL_BLOCK_SIZE, + .dump_bytes = KBASE_DUMMY_MODEL_MAX_SAMPLE_SIZE, + .prfcnt_block_size = KBASE_DUMMY_MODEL_BLOCK_SIZE, + .clk_cnt = 1, + .clearing_samples = true, + }; + fw_ctx->buf_bytes = prfcnt_info->dump_bytes; #else struct kbase_hwcnt_backend_csf_if_fw_ctx *fw_ctx; struct kbase_device *kbdev; u32 prfcnt_size; - u32 prfcnt_hw_size = 0; - u32 prfcnt_fw_size = 0; + u32 prfcnt_hw_size; + u32 prfcnt_fw_size; u32 prfcnt_block_size = KBASE_HWCNT_V5_DEFAULT_VALUES_PER_BLOCK * KBASE_HWCNT_VALUE_HW_BYTES; @@ -254,8 +253,8 @@ static void kbasep_hwcnt_backend_csf_if_fw_get_prfcnt_info( fw_ctx = (struct kbase_hwcnt_backend_csf_if_fw_ctx *)ctx; kbdev = fw_ctx->kbdev; prfcnt_size = kbdev->csf.global_iface.prfcnt_size; - prfcnt_hw_size = (prfcnt_size & 0xFF) << 8; - prfcnt_fw_size = (prfcnt_size >> 16) << 8; + prfcnt_hw_size = GLB_PRFCNT_SIZE_HARDWARE_SIZE_GET(prfcnt_size); + prfcnt_fw_size = GLB_PRFCNT_SIZE_FIRMWARE_SIZE_GET(prfcnt_size); fw_ctx->buf_bytes = prfcnt_hw_size + prfcnt_fw_size; /* Read the block size if the GPU has the register PRFCNT_FEATURES @@ -269,14 +268,16 @@ static void kbasep_hwcnt_backend_csf_if_fw_get_prfcnt_info( << 8; } - prfcnt_info->dump_bytes = fw_ctx->buf_bytes; - prfcnt_info->prfcnt_block_size = prfcnt_block_size; - prfcnt_info->l2_count = kbdev->gpu_props.props.l2_props.num_l2_slices; - prfcnt_info->core_mask = - kbdev->gpu_props.props.coherency_info.group[0].core_mask; - - prfcnt_info->clk_cnt = fw_ctx->clk_cnt; - prfcnt_info->clearing_samples = true; + *prfcnt_info = (struct kbase_hwcnt_backend_csf_if_prfcnt_info){ + .prfcnt_hw_size = prfcnt_hw_size, + .prfcnt_fw_size = prfcnt_fw_size, + .dump_bytes = fw_ctx->buf_bytes, + .prfcnt_block_size = prfcnt_block_size, + .l2_count = kbdev->gpu_props.props.l2_props.num_l2_slices, + .core_mask = kbdev->gpu_props.props.coherency_info.group[0].core_mask, + .clk_cnt = fw_ctx->clk_cnt, + .clearing_samples = true, + }; /* Block size must be multiple of counter size. */ WARN_ON((prfcnt_info->prfcnt_block_size % KBASE_HWCNT_VALUE_HW_BYTES) != @@ -506,10 +507,9 @@ static void kbasep_hwcnt_backend_csf_if_fw_ring_buf_free( if (fw_ring_buf->phys) { u64 gpu_va_base = KBASE_HWC_CSF_RING_BUFFER_VA_START; - WARN_ON(kbase_mmu_teardown_pages( - fw_ctx->kbdev, &fw_ctx->kbdev->csf.mcu_mmu, - gpu_va_base >> PAGE_SHIFT, fw_ring_buf->num_pages, - MCU_AS_NR)); + WARN_ON(kbase_mmu_teardown_pages(fw_ctx->kbdev, &fw_ctx->kbdev->csf.mcu_mmu, + gpu_va_base >> PAGE_SHIFT, fw_ring_buf->phys, + fw_ring_buf->num_pages, MCU_AS_NR)); vunmap(fw_ring_buf->cpu_dump_base); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_gpu_narrow.c b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_gpu_narrow.c index e2caa1c063d7..2a1cde79709b 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_gpu_narrow.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_hwcnt_gpu_narrow.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2021-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -161,7 +161,7 @@ void kbase_hwcnt_dump_buffer_narrow_free( return; kfree(dump_buf_narrow->dump_buf); - *dump_buf_narrow = (struct kbase_hwcnt_dump_buffer_narrow){ 0 }; + *dump_buf_narrow = (struct kbase_hwcnt_dump_buffer_narrow){ NULL }; } int kbase_hwcnt_dump_buffer_narrow_array_alloc( diff --git a/drivers/gpu/arm/bifrost/mali_kbase_jd.c b/drivers/gpu/arm/bifrost/mali_kbase_jd.c index d22e1bddb9bd..5a96f924bfbd 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_jd.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_jd.c @@ -82,7 +82,7 @@ static void jd_mark_atom_complete(struct kbase_jd_atom *katom) * Returns whether the JS needs a reschedule. * * Note that the caller must also check the atom status and - * if it is KBASE_JD_ATOM_STATE_COMPLETED must call jd_done_nolock + * if it is KBASE_JD_ATOM_STATE_COMPLETED must call kbase_jd_done_nolock */ static bool jd_run_atom(struct kbase_jd_atom *katom) { @@ -148,7 +148,7 @@ void kbase_jd_dep_clear_locked(struct kbase_jd_atom *katom) if (katom->status == KBASE_JD_ATOM_STATE_COMPLETED) { /* The atom has already finished */ - resched |= jd_done_nolock(katom, true); + resched |= kbase_jd_done_nolock(katom, true); } if (resched) @@ -703,7 +703,7 @@ static void jd_update_jit_usage(struct kbase_jd_atom *katom) } #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */ -bool jd_done_nolock(struct kbase_jd_atom *katom, bool post_immediately) +bool kbase_jd_done_nolock(struct kbase_jd_atom *katom, bool post_immediately) { struct kbase_context *kctx = katom->kctx; struct list_head completed_jobs; @@ -711,6 +711,8 @@ bool jd_done_nolock(struct kbase_jd_atom *katom, bool post_immediately) bool need_to_try_schedule_context = false; int i; + lockdep_assert_held(&kctx->jctx.lock); + KBASE_TLSTREAM_TL_JD_DONE_NO_LOCK_START(kctx->kbdev, katom); INIT_LIST_HEAD(&completed_jobs); @@ -820,7 +822,7 @@ bool jd_done_nolock(struct kbase_jd_atom *katom, bool post_immediately) return need_to_try_schedule_context; } -KBASE_EXPORT_TEST_API(jd_done_nolock); +KBASE_EXPORT_TEST_API(kbase_jd_done_nolock); #if IS_ENABLED(CONFIG_GPU_TRACEPOINTS) enum { @@ -928,7 +930,6 @@ static bool jd_submit_atom(struct kbase_context *const kctx, katom->jobslot = user_atom->jobslot; katom->seq_nr = user_atom->seq_nr; katom->atom_flags = 0; - katom->retry_count = 0; katom->need_cache_flush_cores_retained = 0; katom->pre_dep = NULL; katom->post_dep = NULL; @@ -989,7 +990,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, * dependencies. */ jd_trace_atom_submit(kctx, katom, NULL); - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } } } @@ -1053,7 +1054,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, if (err >= 0) kbase_finish_soft_job(katom); } - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } katom->will_fail_event_code = katom->event_code; @@ -1087,7 +1088,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, "Rejecting atom with unsupported core_req 0x%x\n", katom->core_req); katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } #endif /* !MALI_INCREMENTAL_RENDERING_JM */ @@ -1101,7 +1102,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, */ dev_err(kctx->kbdev->dev, "Rejecting atom with jc = NULL\n"); katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } /* Reject atoms with an invalid device_nr */ @@ -1111,7 +1112,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, "Rejecting atom with invalid device_nr %d\n", katom->device_nr); katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } /* Reject atoms with invalid core requirements */ @@ -1121,7 +1122,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, "Rejecting atom with invalid core requirements\n"); katom->event_code = BASE_JD_EVENT_JOB_INVALID; katom->core_req &= ~BASE_JD_REQ_EVENT_COALESCE; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } /* Reject soft-job atom of certain types from accessing external resources */ @@ -1132,7 +1133,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, dev_err(kctx->kbdev->dev, "Rejecting soft-job atom accessing external resources\n"); katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) { @@ -1140,7 +1141,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, if (kbase_jd_pre_external_resources(katom, user_atom) != 0) { /* setup failed (no access, bad resource, unknown resource types, etc.) */ katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } } @@ -1151,7 +1152,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, * JIT IDs - atom is invalid. */ katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */ @@ -1165,13 +1166,13 @@ static bool jd_submit_atom(struct kbase_context *const kctx, if ((katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0) { if (!kbase_js_is_atom_valid(kctx->kbdev, katom)) { katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } } else { /* Soft-job */ if (kbase_prepare_soft_job(katom) != 0) { katom->event_code = BASE_JD_EVENT_JOB_INVALID; - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } } @@ -1193,7 +1194,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, if (katom->core_req & BASE_JD_REQ_SOFT_JOB) { if (kbase_process_soft_job(katom) == 0) { kbase_finish_soft_job(katom); - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } return false; } @@ -1223,7 +1224,7 @@ static bool jd_submit_atom(struct kbase_context *const kctx, } /* This is a pure dependency. Resolve it immediately */ - return jd_done_nolock(katom, true); + return kbase_jd_done_nolock(katom, true); } int kbase_jd_submit(struct kbase_context *kctx, @@ -1464,11 +1465,13 @@ void kbase_jd_done_worker(struct work_struct *data) } if ((katom->event_code != BASE_JD_EVENT_DONE) && - (!kbase_ctx_flag(katom->kctx, KCTX_DYING))) - dev_err(kbdev->dev, - "t6xx: GPU fault 0x%02lx from job slot %d\n", - (unsigned long)katom->event_code, - katom->slot_nr); + (!kbase_ctx_flag(katom->kctx, KCTX_DYING))) { + if (!kbase_is_quick_reset_enabled(kbdev)) + dev_err(kbdev->dev, + "t6xx: GPU fault 0x%02lx from job slot %d\n", + (unsigned long)katom->event_code, + katom->slot_nr); + } /* Retain state before the katom disappears */ kbasep_js_atom_retained_state_copy(&katom_retained_state, katom); @@ -1480,8 +1483,8 @@ void kbase_jd_done_worker(struct work_struct *data) kbasep_js_remove_job(kbdev, kctx, katom); mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); mutex_unlock(&js_devdata->queue_mutex); - /* jd_done_nolock() requires the jsctx_mutex lock to be dropped */ - jd_done_nolock(katom, false); + /* kbase_jd_done_nolock() requires the jsctx_mutex lock to be dropped */ + kbase_jd_done_nolock(katom, false); /* katom may have been freed now, do not use! */ @@ -1547,7 +1550,7 @@ void kbase_jd_done_worker(struct work_struct *data) kbase_js_sched_all(kbdev); if (!atomic_dec_return(&kctx->work_count)) { - /* If worker now idle then post all events that jd_done_nolock() + /* If worker now idle then post all events that kbase_jd_done_nolock() * has queued */ mutex_lock(&jctx->lock); @@ -1621,7 +1624,7 @@ static void jd_cancel_worker(struct work_struct *data) mutex_lock(&jctx->lock); - need_to_try_schedule_context = jd_done_nolock(katom, true); + need_to_try_schedule_context = kbase_jd_done_nolock(katom, true); /* Because we're zapping, we're not adding any more jobs to this ctx, so no need to * schedule the context. There's also no need for the jsctx_mutex to have been taken * around this too. @@ -1665,6 +1668,8 @@ void kbase_jd_done(struct kbase_jd_atom *katom, int slot_nr, kbdev = kctx->kbdev; KBASE_DEBUG_ASSERT(kbdev); + lockdep_assert_held(&kbdev->hwaccess_lock); + if (done_code & KBASE_JS_ATOM_DONE_EVICTED_FROM_NEXT) katom->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_jd_debugfs.c b/drivers/gpu/arm/bifrost/mali_kbase_jd_debugfs.c index 3b9d6ebf8652..87c92330dfe2 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_jd_debugfs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_jd_debugfs.c @@ -72,9 +72,7 @@ static void kbase_jd_debugfs_fence_info(struct kbase_jd_atom *atom, #endif seq_printf(sfile, -#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE) - "Sd(%u#%u: %s) ", -#elif (KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE) +#if (KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE) "Sd(%llu#%u: %s) ", #else "Sd(%llu#%llu: %s) ", @@ -93,9 +91,7 @@ static void kbase_jd_debugfs_fence_info(struct kbase_jd_atom *atom, #endif seq_printf(sfile, -#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE) - "Wd(%u#%u: %s) ", -#elif (KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE) +#if (KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE) "Wd(%llu#%u: %s) ", #else "Wd(%llu#%llu: %s) ", @@ -230,11 +226,7 @@ static const struct file_operations kbasep_jd_debugfs_atoms_fops = { void kbasep_jd_debugfs_ctx_init(struct kbase_context *kctx) { -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) const mode_t mode = 0444; -#else - const mode_t mode = 0400; -#endif /* Caller already ensures this, but we keep the pattern for * maintenance safety. diff --git a/drivers/gpu/arm/bifrost/mali_kbase_js.c b/drivers/gpu/arm/bifrost/mali_kbase_js.c index 0de1cd75da89..1991bfa9532d 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_js.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_js.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -3484,6 +3484,11 @@ struct kbase_jd_atom *kbase_js_complete_atom(struct kbase_jd_atom *katom, katom->status = KBASE_JD_ATOM_STATE_HW_COMPLETED; dev_dbg(kbdev->dev, "Atom %pK status to HW completed\n", (void *)katom); + if (kbase_is_quick_reset_enabled(kbdev)) { + kbdev->num_of_atoms_hw_completed++; + if (kbdev->num_of_atoms_hw_completed >= 20) + kbase_disable_quick_reset(kbdev); + } if (katom->event_code != BASE_JD_EVENT_DONE) { kbase_js_evict_deps(kctx, katom, katom->slot_nr, @@ -4016,13 +4021,16 @@ base_jd_prio kbase_js_priority_check(struct kbase_device *kbdev, base_jd_prio pr { struct priority_control_manager_device *pcm_device = kbdev->pcm_dev; int req_priority, out_priority; - base_jd_prio out_jd_priority = priority; - if (pcm_device) { - req_priority = kbasep_js_atom_prio_to_sched_prio(priority); - out_priority = pcm_device->ops.pcm_scheduler_priority_check(pcm_device, current, req_priority); - out_jd_priority = kbasep_js_sched_prio_to_atom_prio(out_priority); - } - return out_jd_priority; + req_priority = kbasep_js_atom_prio_to_sched_prio(priority); + out_priority = req_priority; + /* Does not use pcm defined priority check if PCM not defined or if + * kbasep_js_atom_prio_to_sched_prio returns an error + * (KBASE_JS_ATOM_SCHED_PRIO_INVALID). + */ + if (pcm_device && (req_priority != KBASE_JS_ATOM_SCHED_PRIO_INVALID)) + out_priority = pcm_device->ops.pcm_scheduler_priority_check(pcm_device, current, + req_priority); + return kbasep_js_sched_prio_to_atom_prio(kbdev, out_priority); } diff --git a/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.c b/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.c index 6ebd35b73a8b..78fa6f37ef6c 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.c @@ -45,6 +45,7 @@ #include #include #include +#include #include /* Define static_assert(). @@ -60,10 +61,6 @@ #define __static_assert(e, msg, ...) _Static_assert(e, msg) #endif -#if KERNEL_VERSION(4, 16, 0) >= LINUX_VERSION_CODE -typedef unsigned int __poll_t; -#endif - #ifndef ENOTSUP #define ENOTSUP EOPNOTSUPP #endif @@ -637,11 +634,11 @@ static __poll_t reader_poll(struct file *const file, struct reader_changes *changes; if (unlikely(!file || !wait)) - return -EINVAL; + return (__poll_t)-EINVAL; reader = file->private_data; if (unlikely(!reader)) - return -EBADF; + return (__poll_t)-EBADF; changes = &reader->changes; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.h b/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.h index 6e9a8d23ec10..9451d4cd943d 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_kinstr_jm.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -71,8 +71,6 @@ #else /* empty wrapper macros for userspace */ #define static_branch_unlikely(key) (1) -#define KERNEL_VERSION(a, b, c) (0) -#define LINUX_VERSION_CODE (1) #endif /* __KERNEL__ */ /* Forward declarations */ diff --git a/drivers/gpu/arm/bifrost/mali_kbase_kinstr_prfcnt.c b/drivers/gpu/arm/bifrost/mali_kbase_kinstr_prfcnt.c index 17e12e5eb208..81758c32259c 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_kinstr_prfcnt.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_kinstr_prfcnt.c @@ -36,6 +36,7 @@ #include #include #include +#include #include /* The minimum allowed interval between dumps, in nanoseconds @@ -226,25 +227,19 @@ static struct prfcnt_enum_item kinstr_prfcnt_supported_requests[] = { * Return: POLLIN if data can be read without blocking, 0 if data can not be * read without blocking, else error code. */ -#if KERNEL_VERSION(4, 16, 0) >= LINUX_VERSION_CODE -static unsigned int -kbasep_kinstr_prfcnt_hwcnt_reader_poll(struct file *filp, - struct poll_table_struct *wait) -#else static __poll_t kbasep_kinstr_prfcnt_hwcnt_reader_poll(struct file *filp, struct poll_table_struct *wait) -#endif { struct kbase_kinstr_prfcnt_client *cli; if (!filp || !wait) - return -EINVAL; + return (__poll_t)-EINVAL; cli = filp->private_data; if (!cli) - return -EINVAL; + return (__poll_t)-EINVAL; poll_wait(filp, &cli->waitq, wait); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem.c b/drivers/gpu/arm/bifrost/mali_kbase_mem.c index 878cad62d580..e0785793e26a 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem.c @@ -1802,9 +1802,8 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, return err; bad_insert: - kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, - reg->start_pfn, reg->nr_pages, - kctx->as_nr); + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, + reg->nr_pages, kctx->as_nr); kbase_remove_va_region(kctx->kbdev, reg); @@ -1819,6 +1818,7 @@ static void kbase_jd_user_buf_unmap(struct kbase_context *kctx, int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg) { int err = 0; + struct kbase_mem_phy_alloc *alloc; if (reg->start_pfn == 0) return 0; @@ -1826,11 +1826,12 @@ int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg) if (!reg->gpu_alloc) return -EINVAL; + alloc = reg->gpu_alloc; + /* Tear down GPU page tables, depending on memory type. */ - switch (reg->gpu_alloc->type) { + switch (alloc->type) { case KBASE_MEM_TYPE_ALIAS: { size_t i = 0; - struct kbase_mem_phy_alloc *alloc = reg->gpu_alloc; /* Due to the way the number of valid PTEs and ATEs are tracked * currently, only the GPU virtual range that is backed & mapped @@ -1842,9 +1843,8 @@ int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg) if (alloc->imported.alias.aliased[i].alloc) { int err_loop = kbase_mmu_teardown_pages( kctx->kbdev, &kctx->mmu, - reg->start_pfn + - (i * - alloc->imported.alias.stride), + reg->start_pfn + (i * alloc->imported.alias.stride), + alloc->pages + (i * alloc->imported.alias.stride), alloc->imported.alias.aliased[i].length, kctx->as_nr); if (WARN_ON_ONCE(err_loop)) @@ -1854,39 +1854,37 @@ int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg) } break; case KBASE_MEM_TYPE_IMPORTED_UMM: - err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, - reg->start_pfn, reg->nr_pages, kctx->as_nr); + err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, reg->nr_pages, kctx->as_nr); break; default: - err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, - reg->start_pfn, kbase_reg_current_backed_size(reg), - kctx->as_nr); + err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, kbase_reg_current_backed_size(reg), + kctx->as_nr); break; } /* Update tracking, and other cleanup, depending on memory type. */ - switch (reg->gpu_alloc->type) { + switch (alloc->type) { case KBASE_MEM_TYPE_ALIAS: /* We mark the source allocs as unmapped from the GPU when * putting reg's allocs */ break; case KBASE_MEM_TYPE_IMPORTED_USER_BUF: { - struct kbase_alloc_import_user_buf *user_buf = - ®->gpu_alloc->imported.user_buf; + struct kbase_alloc_import_user_buf *user_buf = &alloc->imported.user_buf; - if (user_buf->current_mapping_usage_count & PINNED_ON_IMPORT) { - user_buf->current_mapping_usage_count &= - ~PINNED_ON_IMPORT; + if (user_buf->current_mapping_usage_count & PINNED_ON_IMPORT) { + user_buf->current_mapping_usage_count &= ~PINNED_ON_IMPORT; - /* The allocation could still have active mappings. */ - if (user_buf->current_mapping_usage_count == 0) { - kbase_jd_user_buf_unmap(kctx, reg->gpu_alloc, - (reg->flags & (KBASE_REG_CPU_WR | - KBASE_REG_GPU_WR))); - } + /* The allocation could still have active mappings. */ + if (user_buf->current_mapping_usage_count == 0) { + kbase_jd_user_buf_unmap(kctx, alloc, + (reg->flags & + (KBASE_REG_CPU_WR | KBASE_REG_GPU_WR))); } } + } fallthrough; default: kbase_mem_phy_alloc_gpu_unmapped(reg->gpu_alloc); @@ -3687,12 +3685,7 @@ void kbase_jit_debugfs_init(struct kbase_context *kctx) /* prevent unprivileged use of debug file system * in old kernel version */ -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) - /* only for newer kernel version debug file system is safe */ const mode_t mode = 0444; -#else - const mode_t mode = 0400; -#endif /* Caller already ensures this, but we keep the pattern for * maintenance safety. @@ -4809,18 +4802,7 @@ int kbase_jd_user_buf_pin_pages(struct kbase_context *kctx, write = reg->flags & (KBASE_REG_CPU_WR | KBASE_REG_GPU_WR); -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE - pinned_pages = get_user_pages(NULL, mm, address, alloc->imported.user_buf.nr_pages, -#if KERNEL_VERSION(4, 4, 168) <= LINUX_VERSION_CODE && \ -KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE - write ? FOLL_WRITE : 0, pages, NULL); -#else - write, 0, pages, NULL); -#endif -#elif KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE - pinned_pages = get_user_pages_remote(NULL, mm, address, alloc->imported.user_buf.nr_pages, - write, 0, pages, NULL); -#elif KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE +#if KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE pinned_pages = get_user_pages_remote(NULL, mm, address, alloc->imported.user_buf.nr_pages, write ? FOLL_WRITE : 0, pages, NULL); #elif KERNEL_VERSION(5, 9, 0) > LINUX_VERSION_CODE @@ -5056,12 +5038,10 @@ void kbase_unmap_external_resource(struct kbase_context *kctx, if (!kbase_is_region_invalid_or_free(reg) && reg->gpu_alloc == alloc) - kbase_mmu_teardown_pages( - kctx->kbdev, - &kctx->mmu, - reg->start_pfn, - kbase_reg_current_backed_size(reg), - kctx->as_nr); + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, + kbase_reg_current_backed_size(reg), + kctx->as_nr); if (reg && ((reg->flags & (KBASE_REG_CPU_WR | KBASE_REG_GPU_WR)) == 0)) writeable = false; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c b/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c index 6e3898ecedda..c373cf82ea37 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c @@ -31,9 +31,6 @@ #include #include #include -#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE) -#include -#endif /* LINUX_VERSION_CODE < 4.8.0 */ #include #include #include @@ -104,6 +101,23 @@ static int kbase_mem_shrink_gpu_mapping(struct kbase_context *kctx, struct kbase_va_region *reg, u64 new_pages, u64 old_pages); +static bool is_process_exiting(struct vm_area_struct *vma) +{ + /* PF_EXITING flag can't be reliably used here for the detection + * of process exit, as 'mm_users' counter could still be non-zero + * when all threads of the process have exited. Later when the + * thread (which took a reference on the 'mm' of process that + * exited) drops it reference, the vm_ops->close method would be + * called for all the vmas (owned by 'mm' of process that exited) + * but the PF_EXITING flag may not be neccessarily set for the + * thread at that time. + */ + if (atomic_read(&vma->vm_mm->mm_users)) + return false; + + return true; +} + /* Retrieve the associated region pointer if the GPU address corresponds to * one of the event memory pages. The enclosing region, if found, shouldn't * have been marked as free. @@ -1103,19 +1117,7 @@ int kbase_mem_do_sync_imported(struct kbase_context *kctx, ret = 0; } #else - /* Though the below version check could be superfluous depending upon the version condition - * used for enabling KBASE_MEM_ION_SYNC_WORKAROUND, we still keep this check here to allow - * ease of modification for non-ION systems or systems where ION has been patched. - */ -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && !defined(CONFIG_CHROMEOS) - dma_buf_end_cpu_access(dma_buf, - 0, dma_buf->size, - dir); - ret = 0; -#else - ret = dma_buf_end_cpu_access(dma_buf, - dir); -#endif + ret = dma_buf_end_cpu_access(dma_buf, dir); #endif /* KBASE_MEM_ION_SYNC_WORKAROUND */ break; case KBASE_SYNC_TO_CPU: @@ -1132,11 +1134,7 @@ int kbase_mem_do_sync_imported(struct kbase_context *kctx, ret = 0; } #else - ret = dma_buf_begin_cpu_access(dma_buf, -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && !defined(CONFIG_CHROMEOS) - 0, dma_buf->size, -#endif - dir); + ret = dma_buf_begin_cpu_access(dma_buf, dir); #endif /* KBASE_MEM_ION_SYNC_WORKAROUND */ break; } @@ -1315,11 +1313,8 @@ int kbase_mem_umm_map(struct kbase_context *kctx, return 0; bad_pad_insert: - kbase_mmu_teardown_pages(kctx->kbdev, - &kctx->mmu, - reg->start_pfn, - alloc->nents, - kctx->as_nr); + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, + alloc->nents, kctx->as_nr); bad_insert: kbase_mem_umm_unmap_attachment(kctx, alloc); bad_map_attachment: @@ -1347,11 +1342,8 @@ void kbase_mem_umm_unmap(struct kbase_context *kctx, if (!kbase_is_region_invalid_or_free(reg) && reg->gpu_alloc == alloc) { int err; - err = kbase_mmu_teardown_pages(kctx->kbdev, - &kctx->mmu, - reg->start_pfn, - reg->nr_pages, - kctx->as_nr); + err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, reg->nr_pages, kctx->as_nr); WARN_ON(err); } @@ -1669,18 +1661,7 @@ static struct kbase_va_region *kbase_mem_from_user_buffer( write = reg->flags & (KBASE_REG_CPU_WR | KBASE_REG_GPU_WR); -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE - faulted_pages = get_user_pages(current, current->mm, address, *va_pages, -#if KERNEL_VERSION(4, 4, 168) <= LINUX_VERSION_CODE && \ -KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE - write ? FOLL_WRITE : 0, pages, NULL); -#else - write, 0, pages, NULL); -#endif -#elif KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE - faulted_pages = get_user_pages(address, *va_pages, - write, 0, pages, NULL); -#elif KERNEL_VERSION(5, 9, 0) > LINUX_VERSION_CODE +#if KERNEL_VERSION(5, 9, 0) > LINUX_VERSION_CODE faulted_pages = get_user_pages(address, *va_pages, write ? FOLL_WRITE : 0, pages, NULL); #else @@ -2193,10 +2174,11 @@ static int kbase_mem_shrink_gpu_mapping(struct kbase_context *const kctx, u64 const new_pages, u64 const old_pages) { u64 delta = old_pages - new_pages; + struct kbase_mem_phy_alloc *alloc = reg->gpu_alloc; int ret = 0; - ret = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, - reg->start_pfn + new_pages, delta, kctx->as_nr); + ret = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn + new_pages, + alloc->pages + new_pages, delta, kctx->as_nr); return ret; } @@ -2414,7 +2396,7 @@ static void kbase_cpu_vm_close(struct vm_area_struct *vma) /* Avoid freeing memory on the process death which results in * GPU Page Fault. Memory will be freed in kbase_destroy_context */ - if (!(current->flags & PF_EXITING)) + if (!is_process_exiting(vma)) kbase_mem_free_region(map->kctx, map->region); } @@ -3314,7 +3296,7 @@ static void kbase_csf_user_io_pages_vm_close(struct vm_area_struct *vma) reset_prevented = true; mutex_lock(&kctx->csf.lock); - kbase_csf_queue_unbind(queue); + kbase_csf_queue_unbind(queue, is_process_exiting(vma)); mutex_unlock(&kctx->csf.lock); if (reset_prevented) @@ -3355,13 +3337,6 @@ static vm_fault_t kbase_csf_user_io_pages_vm_fault(struct vm_fault *vmf) /* Always map the doorbell page as uncached */ doorbell_pgprot = pgprot_device(vma->vm_page_prot); -#if ((KERNEL_VERSION(4, 4, 147) >= LINUX_VERSION_CODE) || \ - ((KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) && \ - (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE))) - vma->vm_page_prot = doorbell_pgprot; - input_page_pgprot = doorbell_pgprot; - output_page_pgprot = doorbell_pgprot; -#else if (kbdev->system_coherency == COHERENCY_NONE) { input_page_pgprot = pgprot_writecombine(vma->vm_page_prot); output_page_pgprot = pgprot_writecombine(vma->vm_page_prot); @@ -3369,7 +3344,6 @@ static vm_fault_t kbase_csf_user_io_pages_vm_fault(struct vm_fault *vmf) input_page_pgprot = vma->vm_page_prot; output_page_pgprot = vma->vm_page_prot; } -#endif doorbell_cpu_addr = vma->vm_start; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.h b/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.h index 1f6877aff758..5e5d991105a6 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.h @@ -439,18 +439,7 @@ u32 kbase_get_cache_line_alignment(struct kbase_device *kbdev); static inline vm_fault_t vmf_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, pgprot_t pgprot) { - int err; - -#if ((KERNEL_VERSION(4, 4, 147) >= LINUX_VERSION_CODE) || \ - ((KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) && \ - (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE))) - if (pgprot_val(pgprot) != pgprot_val(vma->vm_page_prot)) - return VM_FAULT_SIGBUS; - - err = vm_insert_pfn(vma, addr, pfn); -#else - err = vm_insert_pfn_prot(vma, addr, pfn, pgprot); -#endif + int err = vm_insert_pfn_prot(vma, addr, pfn, pgprot); if (unlikely(err == -ENOMEM)) return VM_FAULT_OOM; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem_pool_debugfs.c b/drivers/gpu/arm/bifrost/mali_kbase_mem_pool_debugfs.c index cfb43b029c6c..3b1b2bae15c8 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem_pool_debugfs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem_pool_debugfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -168,13 +168,7 @@ static const struct file_operations kbase_mem_pool_debugfs_max_size_fops = { void kbase_mem_pool_debugfs_init(struct dentry *parent, struct kbase_context *kctx) { - /* prevent unprivileged use of debug file in old kernel version */ -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) - /* only for newer kernel version debug file system is safe */ const mode_t mode = 0644; -#else - const mode_t mode = 0600; -#endif debugfs_create_file("mem_pool_size", mode, parent, &kctx->mem_pools.small, &kbase_mem_pool_debugfs_fops); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem_profile_debugfs.c b/drivers/gpu/arm/bifrost/mali_kbase_mem_profile_debugfs.c index 92ab1b8ffd2a..9317023b71bb 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem_profile_debugfs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem_profile_debugfs.c @@ -69,11 +69,7 @@ static const struct file_operations kbasep_mem_profile_debugfs_fops = { int kbasep_mem_profile_debugfs_insert(struct kbase_context *kctx, char *data, size_t size) { -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) const mode_t mode = 0444; -#else - const mode_t mode = 0400; -#endif int err = 0; mutex_lock(&kctx->mem_profile_lock); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_native_mgm.c b/drivers/gpu/arm/bifrost/mali_kbase_native_mgm.c index 4554bee783e7..10a7f506b1a4 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_native_mgm.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_native_mgm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -140,6 +140,30 @@ kbase_native_mgm_update_gpu_pte(struct memory_group_manager_device *mgm_dev, return pte; } +/** + * kbase_native_mgm_pte_to_original_pte - Native method to undo changes done in + * kbase_native_mgm_update_gpu_pte() + * + * @mgm_dev: The memory group manager the request is being made through. + * @group_id: A physical memory group ID, which must be valid but is not used. + * Its valid range is 0 .. MEMORY_GROUP_MANAGER_NR_GROUPS-1. + * @mmu_level: The level of the MMU page table where the page is getting mapped. + * @pte: The prepared page table entry. + * + * This function simply returns the @pte without modification. + * + * Return: A GPU page table entry to be stored in a page table. + */ +static u64 kbase_native_mgm_pte_to_original_pte(struct memory_group_manager_device *mgm_dev, + int group_id, int mmu_level, u64 pte) +{ + CSTD_UNUSED(mgm_dev); + CSTD_UNUSED(group_id); + CSTD_UNUSED(mmu_level); + + return pte; +} + struct memory_group_manager_device kbase_native_mgm_dev = { .ops = { .mgm_alloc_page = kbase_native_mgm_alloc, @@ -147,6 +171,7 @@ struct memory_group_manager_device kbase_native_mgm_dev = { .mgm_get_import_memory_id = NULL, .mgm_vmf_insert_pfn_prot = kbase_native_mgm_vmf_insert_pfn_prot, .mgm_update_gpu_pte = kbase_native_mgm_update_gpu_pte, + .mgm_pte_to_original_pte = kbase_native_mgm_pte_to_original_pte, }, .data = NULL }; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_pbha_debugfs.c b/drivers/gpu/arm/bifrost/mali_kbase_pbha_debugfs.c index 47eab63456f4..4130dd609157 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_pbha_debugfs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_pbha_debugfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2021-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -120,14 +120,10 @@ static const struct file_operations pbha_int_id_overrides_fops = { void kbase_pbha_debugfs_init(struct kbase_device *kbdev) { if (kbasep_pbha_supported(kbdev)) { -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) - /* only for newer kernel version debug file system is safe */ const mode_t mode = 0644; -#else - const mode_t mode = 0600; -#endif struct dentry *debugfs_pbha_dir = debugfs_create_dir( "pbha", kbdev->mali_debugfs_directory); + if (IS_ERR_OR_NULL(debugfs_pbha_dir)) { dev_err(kbdev->dev, "Couldn't create mali debugfs page-based hardware attributes directory\n"); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c b/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c index 78ab1c6a6bab..5808a2e893cc 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -213,7 +213,7 @@ void kbase_soft_event_wait_callback(struct kbase_jd_atom *katom) mutex_lock(&kctx->jctx.lock); kbasep_remove_waiting_soft_job(katom); kbase_finish_soft_job(katom); - if (jd_done_nolock(katom, true)) + if (kbase_jd_done_nolock(katom, true)) kbase_js_sched_all(kctx->kbdev); mutex_unlock(&kctx->jctx.lock); } @@ -227,7 +227,7 @@ static void kbasep_soft_event_complete_job(struct work_struct *work) int resched; mutex_lock(&kctx->jctx.lock); - resched = jd_done_nolock(katom, true); + resched = kbase_jd_done_nolock(katom, true); mutex_unlock(&kctx->jctx.lock); if (resched) @@ -498,7 +498,7 @@ out: static void kbasep_soft_event_cancel_job(struct kbase_jd_atom *katom) { katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; - if (jd_done_nolock(katom, true)) + if (kbase_jd_done_nolock(katom, true)) kbase_js_sched_all(katom->kctx->kbdev); } @@ -810,11 +810,7 @@ int kbase_mem_copy_from_extres(struct kbase_context *kctx, dma_to_copy = min(dma_buf->size, (size_t)(buf_data->nr_extres_pages * PAGE_SIZE)); - ret = dma_buf_begin_cpu_access(dma_buf, -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && !defined(CONFIG_CHROMEOS) - 0, dma_to_copy, -#endif - DMA_FROM_DEVICE); + ret = dma_buf_begin_cpu_access(dma_buf, DMA_FROM_DEVICE); if (ret) goto out_unlock; @@ -841,11 +837,7 @@ int kbase_mem_copy_from_extres(struct kbase_context *kctx, break; } } - dma_buf_end_cpu_access(dma_buf, -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && !defined(CONFIG_CHROMEOS) - 0, dma_to_copy, -#endif - DMA_FROM_DEVICE); + dma_buf_end_cpu_access(dma_buf, DMA_FROM_DEVICE); break; } default: @@ -1355,7 +1347,7 @@ static void kbasep_jit_finish_worker(struct work_struct *work) mutex_lock(&kctx->jctx.lock); kbase_finish_soft_job(katom); - resched = jd_done_nolock(katom, true); + resched = kbase_jd_done_nolock(katom, true); mutex_unlock(&kctx->jctx.lock); if (resched) @@ -1786,7 +1778,7 @@ void kbase_resume_suspended_soft_jobs(struct kbase_device *kbdev) if (kbase_process_soft_job(katom_iter) == 0) { kbase_finish_soft_job(katom_iter); - resched |= jd_done_nolock(katom_iter, true); + resched |= kbase_jd_done_nolock(katom_iter, true); #ifdef CONFIG_MALI_ARBITER_SUPPORT atomic_dec(&kbdev->pm.gpu_users_waiting); #endif /* CONFIG_MALI_ARBITER_SUPPORT */ diff --git a/drivers/gpu/arm/bifrost/mali_kbase_sync_android.c b/drivers/gpu/arm/bifrost/mali_kbase_sync_android.c index 8a8ea126aa70..8c5cb6c3838e 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_sync_android.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_sync_android.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2012-2017, 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2012-2017, 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -248,22 +248,17 @@ int kbase_sync_fence_out_create(struct kbase_jd_atom *katom, int tl_fd) /* create a fd representing the fence */ fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC); if (fd < 0) { + sync_pt_free(pt); sync_fence_put(fence); + katom->fence = NULL; goto out; } + /* Place the successfully created fence in katom */ + katom->fence = fence; + /* bind fence to the new fd */ sync_fence_install(fence, fd); - - katom->fence = sync_fence_fdget(fd); - if (katom->fence == NULL) { - /* The only way the fence can be NULL is if userspace closed it - * for us, so we don't need to clear it up - */ - fd = -EINVAL; - goto out; - } - out: fput(tl_file); @@ -445,7 +440,7 @@ void kbase_sync_fence_in_cancel_wait(struct kbase_jd_atom *katom) kbasep_remove_waiting_soft_job(katom); kbase_finish_soft_job(katom); - if (jd_done_nolock(katom, true)) + if (kbase_jd_done_nolock(katom, true)) kbase_js_sched_all(katom->kctx->kbdev); } diff --git a/drivers/gpu/arm/bifrost/mali_kbase_sync_file.c b/drivers/gpu/arm/bifrost/mali_kbase_sync_file.c index fca80e452c60..e08a87210fbc 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_sync_file.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_sync_file.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2012-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2012-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -262,7 +262,7 @@ void kbase_sync_fence_in_cancel_wait(struct kbase_jd_atom *katom) kbasep_remove_waiting_soft_job(katom); kbase_finish_soft_job(katom); - if (jd_done_nolock(katom, true)) + if (kbase_jd_done_nolock(katom, true)) kbase_js_sched_all(katom->kctx->kbdev); } @@ -309,10 +309,7 @@ void kbase_sync_fence_info_get(struct dma_fence *fence, info->status = 0; /* still active (unsignaled) */ } -#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE) - scnprintf(info->name, sizeof(info->name), "%u#%u", - fence->context, fence->seqno); -#elif (KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE) +#if (KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE) scnprintf(info->name, sizeof(info->name), "%llu#%u", fence->context, fence->seqno); #else diff --git a/drivers/gpu/arm/bifrost/mali_kbase_vinstr.c b/drivers/gpu/arm/bifrost/mali_kbase_vinstr.c index 34d0359eb2d9..abcf53041069 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_vinstr.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_vinstr.c @@ -38,6 +38,7 @@ #include #include #include +#include #include /* Hwcnt reader API version */ @@ -113,9 +114,7 @@ struct kbase_vinstr_client { wait_queue_head_t waitq; }; -static unsigned int kbasep_vinstr_hwcnt_reader_poll( - struct file *filp, - poll_table *wait); +static __poll_t kbasep_vinstr_hwcnt_reader_poll(struct file *filp, poll_table *wait); static long kbasep_vinstr_hwcnt_reader_ioctl( struct file *filp, @@ -1038,18 +1037,16 @@ static long kbasep_vinstr_hwcnt_reader_ioctl( * Return: POLLIN if data can be read without blocking, 0 if data can not be * read without blocking, else error code. */ -static unsigned int kbasep_vinstr_hwcnt_reader_poll( - struct file *filp, - poll_table *wait) +static __poll_t kbasep_vinstr_hwcnt_reader_poll(struct file *filp, poll_table *wait) { struct kbase_vinstr_client *cli; if (!filp || !wait) - return -EINVAL; + return (__poll_t)-EINVAL; cli = filp->private_data; if (!cli) - return -EINVAL; + return (__poll_t)-EINVAL; poll_wait(filp, &cli->waitq, wait); if (kbasep_vinstr_hwcnt_reader_buffer_ready(cli)) diff --git a/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_csf.c b/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_csf.c index c9ba3fcb91f5..04f5cdf42b84 100644 --- a/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_csf.c +++ b/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_csf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -152,8 +152,8 @@ void kbase_gpu_report_bus_fault_and_kill(struct kbase_context *kctx, /* terminal fault, print info about the fault */ dev_err(kbdev->dev, - "GPU bus fault in AS%d at VA 0x%016llX\n" - "VA_VALID: %s\n" + "GPU bus fault in AS%d at PA 0x%016llX\n" + "PA_VALID: %s\n" "raw fault status: 0x%X\n" "exception type 0x%X: %s\n" "access type 0x%X: %s\n" diff --git a/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_jm.c b/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_jm.c index fad55540feb1..3130b332dec2 100644 --- a/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_jm.c +++ b/drivers/gpu/arm/bifrost/mmu/backend/mali_kbase_mmu_jm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -66,7 +66,7 @@ void kbase_gpu_report_bus_fault_and_kill(struct kbase_context *kctx, /* terminal fault, print info about the fault */ dev_err(kbdev->dev, - "GPU bus fault in AS%d at VA 0x%016llX\n" + "GPU bus fault in AS%d at PA 0x%016llX\n" "raw fault status: 0x%X\n" "exception type 0x%X: %s\n" "exception data 0x%X\n" diff --git a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c index 9bc15097540e..fc7c8923ab07 100644 --- a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c +++ b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c @@ -49,6 +49,25 @@ #include #include +/* Threshold used to decide whether to flush full caches or just a physical range */ +#define KBASE_PA_RANGE_THRESHOLD_NR_PAGES 20 +#define MGM_DEFAULT_PTE_GROUP (0) + +/* Macro to convert updated PDGs to flags indicating levels skip in flush */ +#define pgd_level_to_skip_flush(dirty_pgds) (~(dirty_pgds) & 0xF) + +/* Small wrapper function to factor out GPU-dependent context releasing */ +static void release_ctx(struct kbase_device *kbdev, + struct kbase_context *kctx) +{ +#if MALI_USE_CSF + CSTD_UNUSED(kbdev); + kbase_ctx_sched_release_ctx_lock(kctx); +#else /* MALI_USE_CSF */ + kbasep_js_runpool_release_ctx(kbdev, kctx); +#endif /* MALI_USE_CSF */ +} + static void mmu_hw_operation_begin(struct kbase_device *kbdev) { #if !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) @@ -109,112 +128,227 @@ static bool mmu_flush_cache_on_gpu_ctrl(struct kbase_device *kbdev) } /** - * mmu_flush_invalidate_on_gpu_ctrl() - Flush and invalidate the GPU caches - * through GPU_CONTROL interface. - * @kbdev: kbase device to issue the MMU operation on. - * @as: address space to issue the MMU operation on. - * @op_param: parameters for the operation. + * mmu_flush_pa_range() - Flush physical address range * - * This wrapper function alternates AS_COMMAND_FLUSH_PT and AS_COMMAND_FLUSH_MEM - * to equivalent GPU_CONTROL command FLUSH_CACHES. - * The function first issue LOCK to MMU-AS with kbase_mmu_hw_do_operation(). - * And issues cache-flush with kbase_gpu_cache_flush_and_busy_wait() function - * then issue UNLOCK to MMU-AS with kbase_mmu_hw_do_operation(). + * @kbdev: kbase device to issue the MMU operation on. + * @phys: Starting address of the physical range to start the operation on. + * @nr_bytes: Number of bytes to work on. + * @op: Type of cache flush operation to perform. * - * Return: Zero if the operation was successful, non-zero otherwise. + * Issue a cache flush physical range command. */ -static int -mmu_flush_invalidate_on_gpu_ctrl(struct kbase_device *kbdev, - struct kbase_as *as, - struct kbase_mmu_hw_op_param *op_param) + +/** + * mmu_invalidate() - Perform an invalidate operation on MMU caches. + * @kbdev: The Kbase device. + * @kctx: The Kbase context. + * @as_nr: GPU address space number for which invalidate is required. + * @op_param: Non-NULL pointer to struct containing information about the MMU + * operation to perform. + * + * Perform an MMU invalidate operation on a particual address space + * by issuing a UNLOCK command. + */ +static void mmu_invalidate(struct kbase_device *kbdev, struct kbase_context *kctx, int as_nr, + const struct kbase_mmu_hw_op_param *op_param) { - u32 flush_op; - int ret, ret2; + int err = 0; + unsigned long flags; - if (WARN_ON(kbdev == NULL) || - WARN_ON(as == NULL) || - WARN_ON(op_param == NULL)) - return -EINVAL; + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); - lockdep_assert_held(&kbdev->hwaccess_lock); - lockdep_assert_held(&kbdev->mmu_hw_mutex); - - /* Translate operation to command */ - if (op_param->op == KBASE_MMU_OP_FLUSH_PT) { - flush_op = GPU_COMMAND_CACHE_CLN_INV_L2; - } else if (op_param->op == KBASE_MMU_OP_FLUSH_MEM) { - flush_op = GPU_COMMAND_CACHE_CLN_INV_L2_LSC; - } else { - dev_warn(kbdev->dev, "Invalid flush request (op = %d)\n", - op_param->op); - return -EINVAL; + if (kbdev->pm.backend.gpu_powered && (!kctx || kctx->as_nr >= 0)) { + as_nr = kctx ? kctx->as_nr : as_nr; + err = kbase_mmu_hw_do_unlock(kbdev, &kbdev->as[as_nr], op_param); } - /* 1. Issue MMU_AS_CONTROL.COMMAND.LOCK operation. */ - op_param->op = KBASE_MMU_OP_LOCK; - ret = kbase_mmu_hw_do_operation(kbdev, as, op_param); - if (ret) - return ret; + if (err) { + dev_err(kbdev->dev, + "Invalidate after GPU page table update did not complete. Issuing GPU soft-reset to recover"); + if (kbase_prepare_to_reset_gpu(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) + kbase_reset_gpu(kbdev); + } - /* 2. Issue GPU_CONTROL.COMMAND.FLUSH_CACHES operation */ - ret = kbase_gpu_cache_flush_and_busy_wait(kbdev, flush_op); + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); +} - /* 3. Issue MMU_AS_CONTROL.COMMAND.UNLOCK operation. */ - op_param->op = KBASE_MMU_OP_UNLOCK; - ret2 = kbase_mmu_hw_do_operation(kbdev, as, op_param); +/* Perform a flush/invalidate on a particular address space + */ +static void mmu_flush_invalidate_as(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param) +{ + int err; + bool gpu_powered; + unsigned long flags; - return ret ?: ret2; + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + gpu_powered = kbdev->pm.backend.gpu_powered; + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + + /* GPU is off so there's no need to perform flush/invalidate. + * But even if GPU is not actually powered down, after gpu_powered flag + * was set to false, it is still safe to skip the flush/invalidate. + * The TLB invalidation will anyways be performed due to AS_COMMAND_UPDATE + * which is sent when address spaces are restored after gpu_powered flag + * is set to true. Flushing of L2 cache is certainly not required as L2 + * cache is definitely off if gpu_powered is false. + */ + if (!gpu_powered) + return; + + if (kbase_pm_context_active_handle_suspend(kbdev, + KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) { + /* GPU has just been powered off due to system suspend. + * So again, no need to perform flush/invalidate. + */ + return; + } + + /* AS transaction begin */ + mutex_lock(&kbdev->mmu_hw_mutex); + + mmu_hw_operation_begin(kbdev); + err = kbase_mmu_hw_do_flush(kbdev, as, op_param); + mmu_hw_operation_end(kbdev); + + if (err) { + /* Flush failed to complete, assume the GPU has hung and + * perform a reset to recover. + */ + dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issuing GPU soft-reset to recover"); + + if (kbase_prepare_to_reset_gpu( + kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) + kbase_reset_gpu(kbdev); + } + + mutex_unlock(&kbdev->mmu_hw_mutex); + /* AS transaction end */ + + kbase_pm_context_idle(kbdev); } /** - * kbase_mmu_flush_invalidate() - Flush and invalidate the GPU caches. - * @kctx: The KBase context. - * @vpfn: The virtual page frame number to start the flush on. - * @nr: The number of pages to flush. - * @sync: Set if the operation should be synchronous or not. + * mmu_flush_invalidate() - Perform a flush operation on GPU caches. + * @kbdev: The Kbase device. + * @kctx: The Kbase context. + * @as_nr: GPU address space number for which flush + invalidate is required. + * @op_param: Non-NULL pointer to struct containing information about the MMU + * operation to perform. * - * Issue a cache flush + invalidate to the GPU caches and invalidate the TLBs. + * This function performs the cache flush operation described by @op_param. + * The function retains a reference to the given @kctx and releases it + * after performing the flush operation. * - * If sync is not set then transactions still in flight when the flush is issued - * may use the old page tables and the data they write will not be written out - * to memory, this function returns after the flush has been issued but - * before all accesses which might effect the flushed region have completed. + * If operation is set to KBASE_MMU_OP_FLUSH_PT then this function will issue + * a cache flush + invalidate to the L2 caches and invalidate the TLBs. * - * If sync is set then accesses in the flushed region will be drained - * before data is flush and invalidated through L1, L2 and into memory, - * after which point this function will return. - * @mmu_sync_info: Indicates whether this call is synchronous wrt MMU ops. + * If operation is set to KBASE_MMU_OP_FLUSH_MEM then this function will issue + * a cache flush + invalidate to the L2 and GPU Load/Store caches as well as + * invalidating the TLBs. + * + * If operation is set to KBASE_MMU_OP_UNLOCK then this function will only + * invalidate the MMU caches and TLBs. */ -static void -kbase_mmu_flush_invalidate(struct kbase_context *kctx, u64 vpfn, size_t nr, - bool sync, - enum kbase_caller_mmu_sync_info mmu_sync_info); +static void mmu_flush_invalidate(struct kbase_device *kbdev, struct kbase_context *kctx, int as_nr, + const struct kbase_mmu_hw_op_param *op_param) +{ + bool ctx_is_in_runpool; + + /* Early out if there is nothing to do */ + if (op_param->nr == 0) + return; + + /* If no context is provided then MMU operation is performed on address + * space which does not belong to user space context. Otherwise, retain + * refcount to context provided and release after flush operation. + */ + if (!kctx) { + mmu_flush_invalidate_as(kbdev, &kbdev->as[as_nr], op_param); + } else { +#if !MALI_USE_CSF + mutex_lock(&kbdev->js_data.queue_mutex); + ctx_is_in_runpool = kbase_ctx_sched_inc_refcount(kctx); + mutex_unlock(&kbdev->js_data.queue_mutex); +#else + ctx_is_in_runpool = kbase_ctx_sched_inc_refcount_if_as_valid(kctx); +#endif /* !MALI_USE_CSF */ + + if (ctx_is_in_runpool) { + KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); + + mmu_flush_invalidate_as(kbdev, &kbdev->as[kctx->as_nr], op_param); + + release_ctx(kbdev, kctx); + } + } +} /** - * kbase_mmu_flush_invalidate_no_ctx() - Flush and invalidate the GPU caches. - * @kbdev: Device pointer. - * @vpfn: The virtual page frame number to start the flush on. - * @nr: The number of pages to flush. - * @sync: Set if the operation should be synchronous or not. - * @as_nr: GPU address space number for which flush + invalidate is required. - * @mmu_sync_info: Indicates whether this call is synchronous wrt MMU ops. + * mmu_flush_invalidate_on_gpu_ctrl() - Perform a flush operation on GPU caches via + * the GPU_CONTROL interface + * @kbdev: The Kbase device. + * @kctx: The Kbase context. + * @as_nr: GPU address space number for which flush + invalidate is required. + * @op_param: Non-NULL pointer to struct containing information about the MMU + * operation to perform. * - * This is used for MMU tables which do not belong to a user space context. + * Perform a flush/invalidate on a particular address space via the GPU_CONTROL + * interface. */ -static void kbase_mmu_flush_invalidate_no_ctx( - struct kbase_device *kbdev, u64 vpfn, size_t nr, bool sync, int as_nr, - enum kbase_caller_mmu_sync_info mmu_sync_info); +static void mmu_flush_invalidate_on_gpu_ctrl(struct kbase_device *kbdev, struct kbase_context *kctx, + int as_nr, const struct kbase_mmu_hw_op_param *op_param) +{ + int err = 0; + unsigned long flags; + + /* AS transaction begin */ + mutex_lock(&kbdev->mmu_hw_mutex); + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + + if (kbdev->pm.backend.gpu_powered && (!kctx || kctx->as_nr >= 0)) { + as_nr = kctx ? kctx->as_nr : as_nr; + err = kbase_mmu_hw_do_flush_on_gpu_ctrl(kbdev, &kbdev->as[as_nr], + op_param); + } + + if (err) { + /* Flush failed to complete, assume the GPU has hung and + * perform a reset to recover. + */ + dev_err(kbdev->dev, + "Flush for GPU page table update did not complete. Issuing GPU soft-reset to recover\n"); + + if (kbase_prepare_to_reset_gpu(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) + kbase_reset_gpu(kbdev); + } + + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + mutex_unlock(&kbdev->mmu_hw_mutex); +} /** * kbase_mmu_sync_pgd() - sync page directory to memory when needed. - * @kbdev: Device pointer. - * @handle: Address of DMA region. - * @size: Size of the region to sync. + * @kbdev: Device pointer. + * @kctx: Context pointer. + * @phys: Starting physical address of the destination region. + * @handle: Address of DMA region. + * @size: Size of the region to sync. + * @flush_op: MMU cache flush operation to perform on the physical address + * range, if GPU control is available. + * + * This function is called whenever the association between a virtual address + * range and a physical address range changes, because a mapping is created or + * destroyed. + * One of the effects of this operation is performing an MMU cache flush + * operation only on the physical address range affected by this function, if + * GPU control is available. * * This should be called after each page directory update. */ -static void kbase_mmu_sync_pgd(struct kbase_device *kbdev, - dma_addr_t handle, size_t size) +static void kbase_mmu_sync_pgd(struct kbase_device *kbdev, struct kbase_context *kctx, + phys_addr_t phys, dma_addr_t handle, size_t size, + enum kbase_mmu_op_type flush_op) { /* In non-coherent system, ensure the GPU can read * the pages from memory @@ -222,6 +356,7 @@ static void kbase_mmu_sync_pgd(struct kbase_device *kbdev, if (kbdev->system_coherency == COHERENCY_NONE) dma_sync_single_for_device(kbdev->dev, handle, size, DMA_TO_DEVICE); + } /* @@ -234,23 +369,25 @@ static void kbase_mmu_sync_pgd(struct kbase_device *kbdev, */ static int kbase_mmu_update_pages_no_flush(struct kbase_context *kctx, u64 vpfn, - struct tagged_addr *phys, size_t nr, - unsigned long flags, int group_id); + struct tagged_addr *phys, size_t nr, unsigned long flags, + int group_id, u64 *dirty_pgds); /** * kbase_mmu_update_and_free_parent_pgds() - Update number of valid entries and * free memory of the page directories * - * @kbdev: Device pointer. - * @mmut: GPU MMU page table. - * @pgds: Physical addresses of page directories to be freed. - * @vpfn: The virtual page frame number. - * @level: The level of MMU page table. + * @kbdev: Device pointer. + * @mmut: GPU MMU page table. + * @pgds: Physical addresses of page directories to be freed. + * @vpfn: The virtual page frame number. + * @level: The level of MMU page table. + * @flush_op: The type of MMU flush operation to perform. + * @dirty_pgds: Flags to track every level where a PGD has been updated. */ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - phys_addr_t *pgds, u64 vpfn, - int level); + struct kbase_mmu_table *mmut, phys_addr_t *pgds, + u64 vpfn, int level, + enum kbase_mmu_op_type flush_op, u64 *dirty_pgds); /** * kbase_mmu_free_pgd() - Free memory of the page directory * @@ -345,8 +482,10 @@ static size_t reg_grow_calc_extra_pages(struct kbase_device *kbdev, static void kbase_gpu_mmu_handle_write_faulting_as(struct kbase_device *kbdev, struct kbase_as *faulting_as, u64 start_pfn, size_t nr, - u32 kctx_id) + u32 kctx_id, u64 dirty_pgds) { + int err; + /* Calls to this function are inherently synchronous, with respect to * MMU operations. */ @@ -359,22 +498,23 @@ static void kbase_gpu_mmu_handle_write_faulting_as(struct kbase_device *kbdev, KBASE_MMU_FAULT_TYPE_PAGE); /* flush L2 and unlock the VA (resumes the MMU) */ - op_param = (struct kbase_mmu_hw_op_param){ - .vpfn = start_pfn, - .nr = nr, - .op = KBASE_MMU_OP_FLUSH_PT, - .kctx_id = kctx_id, - .mmu_sync_info = mmu_sync_info, - }; + op_param.vpfn = start_pfn; + op_param.nr = nr; + op_param.op = KBASE_MMU_OP_FLUSH_PT; + op_param.kctx_id = kctx_id; + op_param.mmu_sync_info = mmu_sync_info; if (mmu_flush_cache_on_gpu_ctrl(kbdev)) { unsigned long irq_flags; spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags); - mmu_flush_invalidate_on_gpu_ctrl(kbdev, faulting_as, &op_param); + op_param.flush_skip_levels = + pgd_level_to_skip_flush(dirty_pgds); + err = kbase_mmu_hw_do_flush_on_gpu_ctrl(kbdev, faulting_as, + &op_param); spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags); } else { mmu_hw_operation_begin(kbdev); - kbase_mmu_hw_do_operation(kbdev, faulting_as, &op_param); + err = kbase_mmu_hw_do_flush(kbdev, faulting_as, &op_param); mmu_hw_operation_end(kbdev); } @@ -414,6 +554,7 @@ static void kbase_gpu_mmu_handle_write_fault(struct kbase_context *kctx, u64 fault_pfn, pfn_offset; int ret; int as_no; + u64 dirty_pgds = 0; as_no = faulting_as->number; kbdev = container_of(faulting_as, struct kbase_device, as[as_no]); @@ -472,12 +613,11 @@ static void kbase_gpu_mmu_handle_write_fault(struct kbase_context *kctx, } /* Now make this faulting page writable to GPU. */ - ret = kbase_mmu_update_pages_no_flush(kctx, fault_pfn, - fault_phys_addr, - 1, region->flags, region->gpu_alloc->group_id); + ret = kbase_mmu_update_pages_no_flush(kctx, fault_pfn, fault_phys_addr, 1, region->flags, + region->gpu_alloc->group_id, &dirty_pgds); kbase_gpu_mmu_handle_write_faulting_as(kbdev, faulting_as, fault_pfn, 1, - kctx->id); + kctx->id, dirty_pgds); kbase_gpu_vm_unlock(kctx); } @@ -712,18 +852,6 @@ static bool page_fault_try_alloc(struct kbase_context *kctx, return true; } -/* Small wrapper function to factor out GPU-dependent context releasing */ -static void release_ctx(struct kbase_device *kbdev, - struct kbase_context *kctx) -{ -#if MALI_USE_CSF - CSTD_UNUSED(kbdev); - kbase_ctx_sched_release_ctx_lock(kctx); -#else /* MALI_USE_CSF */ - kbasep_js_runpool_release_ctx(kbdev, kctx); -#endif /* MALI_USE_CSF */ -} - void kbase_mmu_page_fault_worker(struct work_struct *data) { u64 fault_pfn; @@ -938,16 +1066,29 @@ page_fault_retry: * transaction (which should cause the other page fault to be * raised again). */ - op_param = (struct kbase_mmu_hw_op_param){ - .vpfn = 0, - .nr = 0, - .op = KBASE_MMU_OP_UNLOCK, - .kctx_id = kctx->id, - .mmu_sync_info = mmu_sync_info, - }; - mmu_hw_operation_begin(kbdev); - kbase_mmu_hw_do_operation(kbdev, faulting_as, &op_param); - mmu_hw_operation_end(kbdev); + op_param.mmu_sync_info = mmu_sync_info; + op_param.kctx_id = kctx->id; + if (!mmu_flush_cache_on_gpu_ctrl(kbdev)) { + mmu_hw_operation_begin(kbdev); + err = kbase_mmu_hw_do_unlock_no_addr(kbdev, faulting_as, + &op_param); + mmu_hw_operation_end(kbdev); + } else { + /* Can safely skip the invalidate for all levels in case + * of duplicate page faults. + */ + op_param.flush_skip_levels = 0xF; + op_param.vpfn = fault_pfn; + op_param.nr = 1; + err = kbase_mmu_hw_do_unlock(kbdev, faulting_as, + &op_param); + } + + if (err) { + dev_err(kbdev->dev, + "Invalidation for MMU did not complete on handling page fault @ 0x%llx", + fault->addr); + } mutex_unlock(&kbdev->mmu_hw_mutex); @@ -975,16 +1116,29 @@ page_fault_retry: KBASE_MMU_FAULT_TYPE_PAGE); /* See comment [1] about UNLOCK usage */ - op_param = (struct kbase_mmu_hw_op_param){ - .vpfn = 0, - .nr = 0, - .op = KBASE_MMU_OP_UNLOCK, - .kctx_id = kctx->id, - .mmu_sync_info = mmu_sync_info, - }; - mmu_hw_operation_begin(kbdev); - kbase_mmu_hw_do_operation(kbdev, faulting_as, &op_param); - mmu_hw_operation_end(kbdev); + op_param.mmu_sync_info = mmu_sync_info; + op_param.kctx_id = kctx->id; + if (!mmu_flush_cache_on_gpu_ctrl(kbdev)) { + mmu_hw_operation_begin(kbdev); + err = kbase_mmu_hw_do_unlock_no_addr(kbdev, faulting_as, + &op_param); + mmu_hw_operation_end(kbdev); + } else { + /* Can safely skip the invalidate for all levels in case + * of duplicate page faults. + */ + op_param.flush_skip_levels = 0xF; + op_param.vpfn = fault_pfn; + op_param.nr = 1; + err = kbase_mmu_hw_do_unlock(kbdev, faulting_as, + &op_param); + } + + if (err) { + dev_err(kbdev->dev, + "Invalidation for MMU did not complete on handling page fault @ 0x%llx", + fault->addr); + } mutex_unlock(&kbdev->mmu_hw_mutex); @@ -1009,6 +1163,7 @@ page_fault_retry: spin_unlock(&kctx->mem_partials_lock); if (grown) { + u64 dirty_pgds = 0; u64 pfn_offset; struct kbase_mmu_hw_op_param op_param; @@ -1027,9 +1182,10 @@ page_fault_retry: * us to unlock the MMU as we see fit. */ err = kbase_mmu_insert_pages_no_flush(kbdev, &kctx->mmu, - region->start_pfn + pfn_offset, - &kbase_get_gpu_phy_pages(region)[pfn_offset], - new_pages, region->flags, region->gpu_alloc->group_id); + region->start_pfn + pfn_offset, + &kbase_get_gpu_phy_pages(region)[pfn_offset], + new_pages, region->flags, + region->gpu_alloc->group_id, &dirty_pgds); if (err) { kbase_free_phy_pages_helper(region->gpu_alloc, new_pages); @@ -1084,25 +1240,22 @@ page_fault_retry: kbase_mmu_hw_clear_fault(kbdev, faulting_as, KBASE_MMU_FAULT_TYPE_PAGE); - /* flush L2 and unlock the VA (resumes the MMU) */ - op_param = (struct kbase_mmu_hw_op_param){ - .vpfn = fault->addr >> PAGE_SHIFT, - .nr = new_pages, - .op = KBASE_MMU_OP_FLUSH_PT, - .kctx_id = kctx->id, - .mmu_sync_info = mmu_sync_info, - }; + op_param.vpfn = region->start_pfn + pfn_offset; + op_param.nr = new_pages; + op_param.op = KBASE_MMU_OP_FLUSH_PT; + op_param.kctx_id = kctx->id; + op_param.mmu_sync_info = mmu_sync_info; if (mmu_flush_cache_on_gpu_ctrl(kbdev)) { - unsigned long irq_flags; - - spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags); - err = mmu_flush_invalidate_on_gpu_ctrl(kbdev, faulting_as, - &op_param); - spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags); + /* Unlock to invalidate the TLB (and resume the MMU) */ + op_param.flush_skip_levels = + pgd_level_to_skip_flush(dirty_pgds); + err = kbase_mmu_hw_do_unlock(kbdev, faulting_as, + &op_param); } else { + /* flush L2 and unlock the VA (resumes the MMU) */ mmu_hw_operation_begin(kbdev); - err = kbase_mmu_hw_do_operation(kbdev, faulting_as, - &op_param); + err = kbase_mmu_hw_do_flush(kbdev, faulting_as, + &op_param); mmu_hw_operation_end(kbdev); } @@ -1221,6 +1374,7 @@ static phys_addr_t kbase_mmu_alloc_pgd(struct kbase_device *kbdev, u64 *page; int i; struct page *p; + phys_addr_t pgd; p = kbase_mem_pool_alloc(&kbdev->mem_pools.small[mmut->group_id]); if (!p) @@ -1230,6 +1384,8 @@ static phys_addr_t kbase_mmu_alloc_pgd(struct kbase_device *kbdev, if (page == NULL) goto alloc_free; + pgd = page_to_phys(p); + /* If the MMU tables belong to a context then account the memory usage * to that context, otherwise the MMU tables are device wide and are * only accounted to the device. @@ -1253,10 +1409,13 @@ static phys_addr_t kbase_mmu_alloc_pgd(struct kbase_device *kbdev, for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) kbdev->mmu_mode->entry_invalidate(&page[i]); - kbase_mmu_sync_pgd(kbdev, kbase_dma_addr(p), PAGE_SIZE); + /* MMU cache flush strategy is NONE because this page is newly created, therefore + * there is no content to clean or invalidate in the GPU caches. + */ + kbase_mmu_sync_pgd(kbdev, mmut->kctx, pgd, kbase_dma_addr(p), PAGE_SIZE, KBASE_MMU_OP_NONE); kunmap(p); - return page_to_phys(p); + return pgd; alloc_free: kbase_mem_pool_free(&kbdev->mem_pools.small[mmut->group_id], p, false); @@ -1267,9 +1426,9 @@ alloc_free: /* Given PGD PFN for level N, return PGD PFN for level N+1, allocating the * new table from the pool if needed and possible */ -static int mmu_get_next_pgd(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - phys_addr_t *pgd, u64 vpfn, int level) +static int mmu_get_next_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + phys_addr_t *pgd, u64 vpfn, int level, bool *newly_created_pgd, + u64 *dirty_pgds) { u64 *page; phys_addr_t target_pgd; @@ -1293,9 +1452,14 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, return -EINVAL; } - target_pgd = kbdev->mmu_mode->pte_to_phy_addr(page[vpfn]); + target_pgd = kbdev->mmu_mode->pte_to_phy_addr( + kbdev->mgm_dev->ops.mgm_pte_to_original_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, level, page[vpfn])); if (!target_pgd) { + enum kbase_mmu_op_type flush_op = KBASE_MMU_OP_NONE; + unsigned int current_valid_entries; + u64 managed_pte; target_pgd = kbase_mmu_alloc_pgd(kbdev, mmut); if (!target_pgd) { dev_dbg(kbdev->dev, "%s: kbase_mmu_alloc_pgd failure\n", @@ -1304,10 +1468,31 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, return -ENOMEM; } - kbdev->mmu_mode->entry_set_pte(page, vpfn, target_pgd); + current_valid_entries = kbdev->mmu_mode->get_num_valid_entries(page); + kbdev->mmu_mode->entry_set_pte(&managed_pte, target_pgd); + page[vpfn] = kbdev->mgm_dev->ops.mgm_update_gpu_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, level, managed_pte); + kbdev->mmu_mode->set_num_valid_entries(page, current_valid_entries + 1); - kbase_mmu_sync_pgd(kbdev, kbase_dma_addr(p), PAGE_SIZE); /* Rely on the caller to update the address space flags. */ + if (newly_created_pgd && !*newly_created_pgd) { + *newly_created_pgd = true; + /* If code reaches here we know parent PGD of target PGD was + * not newly created and should be flushed. + */ + flush_op = KBASE_MMU_OP_FLUSH_PT; + + if (dirty_pgds) + *dirty_pgds |= 1ULL << level; + } + + /* MMU cache flush strategy is FLUSH_PT because a new entry is added + * to an existing PGD which may be stored in GPU caches and needs a + * "clean" operation. An "invalidation" operation is not required here + * as this entry points to a new page and cannot be present in GPU + * caches. + */ + kbase_mmu_sync_pgd(kbdev, mmut->kctx, *pgd, kbase_dma_addr(p), PAGE_SIZE, flush_op); } kunmap(p); @@ -1319,11 +1504,9 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, /* * Returns the PGD for the specified level of translation */ -static int mmu_get_pgd_at_level(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - u64 vpfn, - int level, - phys_addr_t *out_pgd) +static int mmu_get_pgd_at_level(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn, + int level, phys_addr_t *out_pgd, bool *newly_created_pgd, + u64 *dirty_pgds) { phys_addr_t pgd; int l; @@ -1332,7 +1515,8 @@ static int mmu_get_pgd_at_level(struct kbase_device *kbdev, pgd = mmut->pgd; for (l = MIDGARD_MMU_TOPLEVEL; l < level; l++) { - int err = mmu_get_next_pgd(kbdev, mmut, &pgd, vpfn, l); + int err = + mmu_get_next_pgd(kbdev, mmut, &pgd, vpfn, l, newly_created_pgd, dirty_pgds); /* Handle failure condition */ if (err) { dev_dbg(kbdev->dev, @@ -1347,18 +1531,16 @@ static int mmu_get_pgd_at_level(struct kbase_device *kbdev, return 0; } -static int mmu_get_bottom_pgd(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - u64 vpfn, - phys_addr_t *out_pgd) +static int mmu_get_bottom_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn, + phys_addr_t *out_pgd, bool *newly_created_pgd, u64 *dirty_pgds) { - return mmu_get_pgd_at_level(kbdev, mmut, vpfn, MIDGARD_MMU_BOTTOMLEVEL, - out_pgd); + return mmu_get_pgd_at_level(kbdev, mmut, vpfn, MIDGARD_MMU_BOTTOMLEVEL, out_pgd, + newly_created_pgd, dirty_pgds); } static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - u64 from_vpfn, u64 to_vpfn) + struct kbase_mmu_table *mmut, u64 from_vpfn, + u64 to_vpfn, u64 *dirty_pgds) { phys_addr_t pgd; u64 vpfn = from_vpfn; @@ -1398,7 +1580,8 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev, if (mmu_mode->ate_is_valid(page[idx], level)) break; /* keep the mapping */ kunmap(phys_to_page(pgd)); - pgd = mmu_mode->pte_to_phy_addr(page[idx]); + pgd = mmu_mode->pte_to_phy_addr(kbdev->mgm_dev->ops.mgm_pte_to_original_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, level, page[idx])); } switch (level) { @@ -1416,6 +1599,9 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev, goto next; } + if (dirty_pgds && pcount > 0) + *dirty_pgds |= 1ULL << level; + num_of_valid_entries = mmu_mode->get_num_valid_entries(page); if (WARN_ON_ONCE(num_of_valid_entries < pcount)) num_of_valid_entries = 0; @@ -1427,8 +1613,8 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev, kbase_mmu_free_pgd(kbdev, mmut, pgd, true); - kbase_mmu_update_and_free_parent_pgds(kbdev, mmut, pgds, - vpfn, level); + kbase_mmu_update_and_free_parent_pgds(kbdev, mmut, pgds, vpfn, level, + KBASE_MMU_OP_NONE, dirty_pgds); vpfn += count; continue; } @@ -1439,9 +1625,12 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev, mmu_mode->set_num_valid_entries(page, num_of_valid_entries); - kbase_mmu_sync_pgd(kbdev, - kbase_dma_addr(phys_to_page(pgd)) + 8 * idx, - 8 * pcount); + /* MMU cache flush strategy is NONE because GPU cache maintenance is + * going to be done by the caller + */ + kbase_mmu_sync_pgd(kbdev, mmut->kctx, pgd + (idx * sizeof(u64)), + kbase_dma_addr(phys_to_page(pgd)) + 8 * idx, 8 * pcount, + KBASE_MMU_OP_NONE); kunmap(phys_to_page(pgd)); next: vpfn += count; @@ -1467,6 +1656,9 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, size_t remain = nr; int err; struct kbase_device *kbdev; + enum kbase_mmu_op_type flush_op; + struct kbase_mmu_hw_op_param op_param; + u64 dirty_pgds = 0; if (WARN_ON(kctx == NULL)) return -EINVAL; @@ -1480,6 +1672,15 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, if (nr == 0) return 0; + /* Set up MMU flush operation parameters. */ + op_param = (struct kbase_mmu_hw_op_param){ + .vpfn = vpfn, + .nr = nr, + .op = KBASE_MMU_OP_FLUSH_PT, + .kctx_id = kctx->id, + .mmu_sync_info = mmu_sync_info, + }; + mutex_lock(&kctx->mmu.mmu_lock); while (remain) { @@ -1488,6 +1689,7 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, unsigned int count = KBASE_MMU_PAGE_ENTRIES - index; struct page *p; register unsigned int num_of_valid_entries; + bool newly_created_pgd = false; if (count > remain) count = remain; @@ -1500,8 +1702,8 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, * 256 pages at once (on average). Do we really care? */ do { - err = mmu_get_bottom_pgd(kbdev, &kctx->mmu, - vpfn, &pgd); + err = mmu_get_bottom_pgd(kbdev, &kctx->mmu, vpfn, &pgd, &newly_created_pgd, + &dirty_pgds); if (err != -ENOMEM) break; /* Fill the memory pool with enough pages for @@ -1521,10 +1723,9 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, /* Invalidate the pages we have partially * completed */ - mmu_insert_pages_failure_recovery(kbdev, - &kctx->mmu, - start_vpfn, - start_vpfn + recover_count); + mmu_insert_pages_failure_recovery(kbdev, &kctx->mmu, start_vpfn, + start_vpfn + recover_count, + &dirty_pgds); } goto fail_unlock; } @@ -1537,10 +1738,9 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, /* Invalidate the pages we have partially * completed */ - mmu_insert_pages_failure_recovery(kbdev, - &kctx->mmu, - start_vpfn, - start_vpfn + recover_count); + mmu_insert_pages_failure_recovery(kbdev, &kctx->mmu, start_vpfn, + start_vpfn + recover_count, + &dirty_pgds); } err = -ENOMEM; goto fail_unlock; @@ -1565,9 +1765,21 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, vpfn += count; remain -= count; - kbase_mmu_sync_pgd(kbdev, - kbase_dma_addr(p) + (index * sizeof(u64)), - count * sizeof(u64)); + if (count > 0 && !newly_created_pgd) + dirty_pgds |= 1ULL << MIDGARD_MMU_BOTTOMLEVEL; + + /* MMU cache flush operation here will depend on whether bottom level + * PGD is newly created or not. + * + * If bottom level PGD is newly created then no cache maintenance is + * required as the PGD will not exist in GPU cache. Otherwise GPU cache + * maintenance is required for existing PGD. + */ + flush_op = newly_created_pgd ? KBASE_MMU_OP_NONE : KBASE_MMU_OP_FLUSH_PT; + + kbase_mmu_sync_pgd(kbdev, kctx, pgd + (index * sizeof(u64)), + kbase_dma_addr(p) + (index * sizeof(u64)), count * sizeof(u64), + flush_op); kunmap(p); /* We have started modifying the page table. @@ -1578,12 +1790,25 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, recover_count += count; } mutex_unlock(&kctx->mmu.mmu_lock); - kbase_mmu_flush_invalidate(kctx, start_vpfn, nr, false, mmu_sync_info); + + op_param.flush_skip_levels = pgd_level_to_skip_flush(dirty_pgds); + /* If FLUSH_PA_RANGE is supported then existing PGDs will have been flushed + * and all that remains is TLB (or MMU cache) invalidation which is done via + * MMU UNLOCK command. + */ + if (mmu_flush_cache_on_gpu_ctrl(kbdev)) + mmu_invalidate(kbdev, kctx, kctx->as_nr, &op_param); + else + mmu_flush_invalidate(kbdev, kctx, kctx->as_nr, &op_param); return 0; fail_unlock: mutex_unlock(&kctx->mmu.mmu_lock); - kbase_mmu_flush_invalidate(kctx, start_vpfn, nr, false, mmu_sync_info); + op_param.flush_skip_levels = pgd_level_to_skip_flush(dirty_pgds); + if (mmu_flush_cache_on_gpu_ctrl(kbdev)) + mmu_flush_invalidate_on_gpu_ctrl(kbdev, kctx, kctx->as_nr, &op_param); + else + mmu_flush_invalidate(kbdev, kctx, kctx->as_nr, &op_param); return err; } @@ -1624,12 +1849,9 @@ u64 kbase_mmu_create_ate(struct kbase_device *const kbdev, group_id, level, entry); } -int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - const u64 start_vpfn, - struct tagged_addr *phys, size_t nr, - unsigned long flags, - int const group_id) +int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + const u64 start_vpfn, struct tagged_addr *phys, size_t nr, + unsigned long flags, int const group_id, u64 *dirty_pgds) { phys_addr_t pgd; u64 *pgd_page; @@ -1657,6 +1879,8 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct page *p; int cur_level; register unsigned int num_of_valid_entries; + enum kbase_mmu_op_type flush_op; + bool newly_created_pgd = false; if (count > remain) count = remain; @@ -1674,8 +1898,8 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, * 256 pages at once (on average). Do we really care? */ do { - err = mmu_get_pgd_at_level(kbdev, mmut, insert_vpfn, - cur_level, &pgd); + err = mmu_get_pgd_at_level(kbdev, mmut, insert_vpfn, cur_level, &pgd, + &newly_created_pgd, dirty_pgds); if (err != -ENOMEM) break; /* Fill the memory pool with enough pages for @@ -1689,14 +1913,13 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, } while (!err); if (err) { - dev_warn(kbdev->dev, - "%s: mmu_get_bottom_pgd failure\n", __func__); + dev_warn(kbdev->dev, "%s: mmu_get_pgd_at_level failure\n", __func__); if (insert_vpfn != start_vpfn) { /* Invalidate the pages we have partially * completed */ - mmu_insert_pages_failure_recovery(kbdev, - mmut, start_vpfn, insert_vpfn); + mmu_insert_pages_failure_recovery(kbdev, mmut, start_vpfn, + insert_vpfn, dirty_pgds); } goto fail_unlock; } @@ -1710,8 +1933,8 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, /* Invalidate the pages we have partially * completed */ - mmu_insert_pages_failure_recovery(kbdev, - mmut, start_vpfn, insert_vpfn); + mmu_insert_pages_failure_recovery(kbdev, mmut, start_vpfn, + insert_vpfn, dirty_pgds); } err = -ENOMEM; goto fail_unlock; @@ -1728,7 +1951,9 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, kbase_mmu_free_pgd( kbdev, mmut, kbdev->mmu_mode->pte_to_phy_addr( - *target), + kbdev->mgm_dev->ops.mgm_pte_to_original_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, + cur_level, *target)), false); num_of_valid_entries--; } @@ -1758,13 +1983,28 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, mmu_mode->set_num_valid_entries(pgd_page, num_of_valid_entries); + if (dirty_pgds && count > 0 && !newly_created_pgd) + *dirty_pgds |= 1ULL << cur_level; + phys += count; insert_vpfn += count; remain -= count; - kbase_mmu_sync_pgd(kbdev, - kbase_dma_addr(p) + (vindex * sizeof(u64)), - count * sizeof(u64)); + /* For the most part, the creation of a new virtual memory mapping does + * not require cache flush operations, because the operation results + * into the creation of new memory pages which are not present in GPU + * caches. Therefore the defaul operation is NONE. + * + * However, it is quite common for the mapping to start and/or finish + * at an already existing PGD. Moreover, the PTEs modified are not + * necessarily aligned with GPU cache lines. Therefore, GPU cache + * maintenance is required for existing PGDs. + */ + flush_op = newly_created_pgd ? KBASE_MMU_OP_NONE : KBASE_MMU_OP_FLUSH_PT; + + kbase_mmu_sync_pgd(kbdev, mmut->kctx, pgd + (vindex * sizeof(u64)), + kbase_dma_addr(p) + (vindex * sizeof(u64)), count * sizeof(u64), + flush_op); kunmap(p); } @@ -1787,16 +2027,35 @@ int kbase_mmu_insert_pages(struct kbase_device *kbdev, enum kbase_caller_mmu_sync_info mmu_sync_info) { int err; + struct kbase_mmu_hw_op_param op_param = { 0 }; + u64 dirty_pgds = 0; - err = kbase_mmu_insert_pages_no_flush(kbdev, mmut, vpfn, - phys, nr, flags, group_id); + /* Early out if there is nothing to do */ + if (nr == 0) + return 0; - if (mmut->kctx) - kbase_mmu_flush_invalidate(mmut->kctx, vpfn, nr, false, - mmu_sync_info); + err = kbase_mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id, + &dirty_pgds); + + op_param.vpfn = vpfn; + op_param.nr = nr; + op_param.op = KBASE_MMU_OP_FLUSH_PT; + op_param.mmu_sync_info = mmu_sync_info; + op_param.kctx_id = mmut->kctx ? mmut->kctx->id : 0xFFFFFFFF; + op_param.flush_skip_levels = pgd_level_to_skip_flush(dirty_pgds); + + /* MMU cache flush strategy depends on whether GPU control commands for + * flushing physical address ranges are supported. The new physical pages + * are not present in GPU caches there for they don't need any cache + * maintenance, but PGDs in the page table may or may not be created anew. + * + * Operations that affect the whole GPU cache shall only be done if it's + * impossible to update physical ranges. + */ + if (mmu_flush_cache_on_gpu_ctrl(kbdev)) + mmu_invalidate(kbdev, mmut->kctx, as_nr, &op_param); else - kbase_mmu_flush_invalidate_no_ctx(kbdev, vpfn, nr, false, as_nr, - mmu_sync_info); + mmu_flush_invalidate(kbdev, mmut->kctx, as_nr, &op_param); return err; } @@ -1804,7 +2063,7 @@ int kbase_mmu_insert_pages(struct kbase_device *kbdev, KBASE_EXPORT_TEST_API(kbase_mmu_insert_pages); /** - * kbase_mmu_flush_invalidate_noretain() - Flush and invalidate the GPU caches + * kbase_mmu_flush_noretain() - Flush and invalidate the GPU caches * without retaining the kbase context. * @kctx: The KBase context. * @vpfn: The virtual page frame number to start the flush on. @@ -1813,17 +2072,15 @@ KBASE_EXPORT_TEST_API(kbase_mmu_insert_pages); * As per kbase_mmu_flush_invalidate but doesn't retain the kctx or do any * other locking. */ -static void kbase_mmu_flush_invalidate_noretain(struct kbase_context *kctx, - u64 vpfn, size_t nr) +static void kbase_mmu_flush_noretain(struct kbase_context *kctx, u64 vpfn, size_t nr) { struct kbase_device *kbdev = kctx->kbdev; - struct kbase_mmu_hw_op_param op_param; int err; - /* Calls to this function are inherently asynchronous, with respect to * MMU operations. */ const enum kbase_caller_mmu_sync_info mmu_sync_info = CALLER_MMU_ASYNC; + struct kbase_mmu_hw_op_param op_param; lockdep_assert_held(&kctx->kbdev->hwaccess_lock); lockdep_assert_held(&kctx->kbdev->mmu_hw_mutex); @@ -1833,155 +2090,32 @@ static void kbase_mmu_flush_invalidate_noretain(struct kbase_context *kctx, return; /* flush L2 and unlock the VA (resumes the MMU) */ - op_param = (struct kbase_mmu_hw_op_param){ - .vpfn = vpfn, - .nr = nr, - .op = KBASE_MMU_OP_FLUSH_MEM, - .kctx_id = kctx->id, - .mmu_sync_info = mmu_sync_info, - }; - + op_param.vpfn = vpfn; + op_param.nr = nr; + op_param.op = KBASE_MMU_OP_FLUSH_MEM; + op_param.kctx_id = kctx->id; + op_param.mmu_sync_info = mmu_sync_info; if (mmu_flush_cache_on_gpu_ctrl(kbdev)) { - err = mmu_flush_invalidate_on_gpu_ctrl( - kbdev, &kbdev->as[kctx->as_nr], &op_param); + /* Value used to prevent skipping of any levels when flushing */ + op_param.flush_skip_levels = pgd_level_to_skip_flush(0xF); + err = kbase_mmu_hw_do_flush_on_gpu_ctrl(kbdev, &kbdev->as[kctx->as_nr], + &op_param); } else { - err = kbase_mmu_hw_do_operation(kbdev, &kbdev->as[kctx->as_nr], - &op_param); + err = kbase_mmu_hw_do_flush_locked(kbdev, &kbdev->as[kctx->as_nr], + &op_param); } if (err) { /* Flush failed to complete, assume the * GPU has hung and perform a reset to recover */ - dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issuing GPU soft-reset to recover\n"); + dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issuing GPU soft-reset to recover"); if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_NONE)) kbase_reset_gpu_locked(kbdev); } } -/* Perform a flush/invalidate on a particular address space - */ -static void -kbase_mmu_flush_invalidate_as(struct kbase_device *kbdev, struct kbase_as *as, - u64 vpfn, size_t nr, bool sync, u32 kctx_id, - enum kbase_caller_mmu_sync_info mmu_sync_info) -{ - int err; - bool gpu_powered; - unsigned long flags; - struct kbase_mmu_hw_op_param op_param; - - spin_lock_irqsave(&kbdev->hwaccess_lock, flags); - gpu_powered = kbdev->pm.backend.gpu_powered; - spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); - - /* GPU is off so there's no need to perform flush/invalidate. - * But even if GPU is not actually powered down, after gpu_powered flag - * was set to false, it is still safe to skip the flush/invalidate. - * The TLB invalidation will anyways be performed due to AS_COMMAND_UPDATE - * which is sent when address spaces are restored after gpu_powered flag - * is set to true. Flushing of L2 cache is certainly not required as L2 - * cache is definitely off if gpu_powered is false. - */ - if (!gpu_powered) - return; - - if (kbase_pm_context_active_handle_suspend(kbdev, - KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) { - /* GPU has just been powered off due to system suspend. - * So again, no need to perform flush/invalidate. - */ - return; - } - - /* AS transaction begin */ - mutex_lock(&kbdev->mmu_hw_mutex); - - op_param = (struct kbase_mmu_hw_op_param){ - .vpfn = vpfn, - .nr = nr, - .kctx_id = kctx_id, - .mmu_sync_info = mmu_sync_info, - }; - - if (sync) - op_param.op = KBASE_MMU_OP_FLUSH_MEM; - else - op_param.op = KBASE_MMU_OP_FLUSH_PT; - - if (mmu_flush_cache_on_gpu_ctrl(kbdev)) { - spin_lock_irqsave(&kbdev->hwaccess_lock, flags); - err = mmu_flush_invalidate_on_gpu_ctrl(kbdev, as, &op_param); - spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); - } else { - mmu_hw_operation_begin(kbdev); - err = kbase_mmu_hw_do_operation(kbdev, as, &op_param); - mmu_hw_operation_end(kbdev); - } - - if (err) { - /* Flush failed to complete, assume the GPU has hung and - * perform a reset to recover - */ - dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issuing GPU soft-reset to recover\n"); - - if (kbase_prepare_to_reset_gpu( - kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) - kbase_reset_gpu(kbdev); - } - - mutex_unlock(&kbdev->mmu_hw_mutex); - /* AS transaction end */ - - kbase_pm_context_idle(kbdev); -} - -static void -kbase_mmu_flush_invalidate_no_ctx(struct kbase_device *kbdev, u64 vpfn, - size_t nr, bool sync, int as_nr, - enum kbase_caller_mmu_sync_info mmu_sync_info) -{ - /* Skip if there is nothing to do */ - if (nr) { - kbase_mmu_flush_invalidate_as(kbdev, &kbdev->as[as_nr], vpfn, - nr, sync, 0xFFFFFFFF, - mmu_sync_info); - } -} - -static void -kbase_mmu_flush_invalidate(struct kbase_context *kctx, u64 vpfn, size_t nr, - bool sync, - enum kbase_caller_mmu_sync_info mmu_sync_info) -{ - struct kbase_device *kbdev; - bool ctx_is_in_runpool; - - /* Early out if there is nothing to do */ - if (nr == 0) - return; - - kbdev = kctx->kbdev; -#if !MALI_USE_CSF - mutex_lock(&kbdev->js_data.queue_mutex); - ctx_is_in_runpool = kbase_ctx_sched_inc_refcount(kctx); - mutex_unlock(&kbdev->js_data.queue_mutex); -#else - ctx_is_in_runpool = kbase_ctx_sched_inc_refcount_if_as_valid(kctx); -#endif /* !MALI_USE_CSF */ - - if (ctx_is_in_runpool) { - KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); - - kbase_mmu_flush_invalidate_as(kbdev, &kbdev->as[kctx->as_nr], - vpfn, nr, sync, kctx->id, - mmu_sync_info); - - release_ctx(kbdev, kctx); - } -} - void kbase_mmu_update(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, int as_nr) @@ -2021,7 +2155,7 @@ void kbase_mmu_disable(struct kbase_context *kctx) * The job scheduler code will already be holding the locks and context * so just do the flush. */ - kbase_mmu_flush_invalidate_noretain(kctx, 0, ~0); + kbase_mmu_flush_noretain(kctx, 0, ~0); kctx->kbdev->mmu_mode->disable_as(kctx->kbdev, kctx->as_nr); #if !MALI_USE_CSF @@ -2037,9 +2171,9 @@ void kbase_mmu_disable(struct kbase_context *kctx) KBASE_EXPORT_TEST_API(kbase_mmu_disable); static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - phys_addr_t *pgds, u64 vpfn, - int level) + struct kbase_mmu_table *mmut, phys_addr_t *pgds, + u64 vpfn, int level, + enum kbase_mmu_op_type flush_op, u64 *dirty_pgds) { int current_level; @@ -2051,6 +2185,10 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, unsigned int current_valid_entries = kbdev->mmu_mode->get_num_valid_entries(current_page); + /* We need to track every level that needs updating */ + if (dirty_pgds) + *dirty_pgds |= 1ULL << current_level; + if (current_valid_entries == 1 && current_level != MIDGARD_MMU_LEVEL(0)) { kunmap(phys_to_page(pgds[current_level])); @@ -2067,11 +2205,10 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, kbdev->mmu_mode->set_num_valid_entries( current_page, current_valid_entries); - kbase_mmu_sync_pgd(kbdev, - kbase_dma_addr(phys_to_page( - pgds[current_level])) + - 8 * index, - 8 * 1); + kbase_mmu_sync_pgd( + kbdev, mmut->kctx, pgds[current_level] + (index * sizeof(u64)), + kbase_dma_addr(phys_to_page(pgds[current_level])) + 8 * index, + 8 * 1, flush_op); kunmap(phys_to_page(pgds[current_level])); break; @@ -2079,7 +2216,53 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, } } -/* +/** + * mmu_flush_invalidate_teardown_pages() - Perform flush operation after unmapping pages. + * + * @kbdev: Pointer to kbase device. + * @kctx: Pointer to kbase context. + * @as_nr: Address space number, for GPU cache maintenance operations + * that happen outside a specific kbase context. + * @phys: Array of physical pages to flush. + * @op_param: Non-NULL pointer to struct containing information about the flush + * operation to perform. + * + * This function will do one of three things: + * 1. Invalidate the MMU caches, followed by a partial GPU cache flush of the + * individual pages that were unmapped if feature is supported on GPU. + * 2. Perform a full GPU cache flush through the GPU_CONTROL interface if feature is + * supported on GPU or, + * 3. Perform a full GPU cache flush through the MMU_CONTROL interface. + */ +static void mmu_flush_invalidate_teardown_pages(struct kbase_device *kbdev, + struct kbase_context *kctx, int as_nr, + struct tagged_addr *phys, + struct kbase_mmu_hw_op_param *op_param) +{ + + if (!mmu_flush_cache_on_gpu_ctrl(kbdev)) { + mmu_flush_invalidate(kbdev, kctx, as_nr, op_param); + return; + } else if (op_param->op == KBASE_MMU_OP_FLUSH_MEM) { + mmu_flush_invalidate_on_gpu_ctrl(kbdev, kctx, as_nr, op_param); + return; + } + +} + +/** + * kbase_mmu_teardown_pages - Remove GPU virtual addresses from the MMU page table + * + * @kbdev: Pointer to kbase device. + * @mmut: Pointer to GPU MMU page table. + * @vpfn: Start page frame number of the GPU virtual pages to unmap. + * @phys: Array of physical pages currently mapped to the virtual + * pages to unmap, or NULL. This is only used for GPU cache + * maintenance. + * @nr: Number of pages to unmap. + * @as_nr: Address space number, for GPU cache maintenance operations + * that happen outside a specific kbase context. + * * We actually discard the ATE and free the page table pages if no valid entries * exist in PGD. * @@ -2088,15 +2271,26 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, * These locks must be taken in the correct order with respect to others * already held by the caller. Refer to kbasep_js_runpool_release_ctx() for more * information. + * + * The @p phys pointer to physical pages is not necessary for unmapping virtual memory, + * but it is used for fine-grained GPU cache maintenance. If @p phys is NULL, + * GPU cache maintenance will be done as usual, that is invalidating the whole GPU caches + * instead of specific physical address ranges. + * + * Return: 0 on success, otherwise an error code. */ -int kbase_mmu_teardown_pages(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, u64 vpfn, size_t nr, int as_nr) +int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn, + struct tagged_addr *phys, size_t nr, int as_nr) { phys_addr_t pgd; u64 start_vpfn = vpfn; size_t requested_nr = nr; + enum kbase_mmu_op_type flush_op = KBASE_MMU_OP_NONE; struct kbase_mmu_mode const *mmu_mode; + struct kbase_mmu_hw_op_param op_param; + unsigned int i; int err = -EFAULT; + u64 dirty_pgds = 0; /* Calls to this function are inherently asynchronous, with respect to * MMU operations. @@ -2108,12 +2302,25 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, return 0; } + /* MMU cache flush strategy depends on the number of pages to unmap. In both cases + * the operation is invalidate but the granularity of cache maintenance may change + * according to the situation. + * + * If GPU control command operations are present and the number of pages is "small", + * then the optimal strategy is flushing on the physical address range of the pages + * which are affected by the operation. That implies both the PGDs which are modified + * or removed from the page table and the physical pages which are freed from memory. + * + * Otherwise, there's no alternative to invalidating the whole GPU cache. + */ + if (mmu_flush_cache_on_gpu_ctrl(kbdev) && phys && nr <= KBASE_PA_RANGE_THRESHOLD_NR_PAGES) + flush_op = KBASE_MMU_OP_FLUSH_PT; + mutex_lock(&mmut->mmu_lock); mmu_mode = kbdev->mmu_mode; while (nr) { - unsigned int i; unsigned int index = vpfn & 0x1FF; unsigned int count = KBASE_MMU_PAGE_ENTRIES - index; unsigned int pcount; @@ -2156,7 +2363,9 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, count = nr; goto next; } - next_pgd = mmu_mode->pte_to_phy_addr(page[index]); + next_pgd = mmu_mode->pte_to_phy_addr( + kbdev->mgm_dev->ops.mgm_pte_to_original_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, level, page[index])); pgds[level] = pgd; kunmap(phys_to_page(pgd)); pgd = next_pgd; @@ -2194,6 +2403,9 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, continue; } + if (pcount > 0) + dirty_pgds |= 1ULL << level; + num_of_valid_entries = mmu_mode->get_num_valid_entries(page); if (WARN_ON_ONCE(num_of_valid_entries < pcount)) num_of_valid_entries = 0; @@ -2205,8 +2417,8 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, kbase_mmu_free_pgd(kbdev, mmut, pgd, true); - kbase_mmu_update_and_free_parent_pgds(kbdev, mmut, pgds, - vpfn, level); + kbase_mmu_update_and_free_parent_pgds(kbdev, mmut, pgds, vpfn, level, + flush_op, &dirty_pgds); vpfn += count; nr -= count; @@ -2219,9 +2431,9 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, mmu_mode->set_num_valid_entries(page, num_of_valid_entries); - kbase_mmu_sync_pgd( - kbdev, kbase_dma_addr(phys_to_page(pgd)) + 8 * index, - 8 * pcount); + kbase_mmu_sync_pgd(kbdev, mmut->kctx, pgd + (index * sizeof(u64)), + kbase_dma_addr(phys_to_page(pgd)) + 8 * index, 8 * pcount, + flush_op); next: kunmap(phys_to_page(pgd)); vpfn += count; @@ -2230,14 +2442,17 @@ next: err = 0; out: mutex_unlock(&mmut->mmu_lock); - - if (mmut->kctx) - kbase_mmu_flush_invalidate(mmut->kctx, start_vpfn, requested_nr, - true, mmu_sync_info); - else - kbase_mmu_flush_invalidate_no_ctx(kbdev, start_vpfn, - requested_nr, true, as_nr, - mmu_sync_info); + /* Set up MMU operation parameters. See above about MMU cache flush strategy. */ + op_param = (struct kbase_mmu_hw_op_param){ + .vpfn = start_vpfn, + .nr = requested_nr, + .mmu_sync_info = mmu_sync_info, + .kctx_id = mmut->kctx ? mmut->kctx->id : 0xFFFFFFFF, + .op = (flush_op == KBASE_MMU_OP_FLUSH_PT) ? KBASE_MMU_OP_FLUSH_PT : + KBASE_MMU_OP_FLUSH_MEM, + .flush_skip_levels = pgd_level_to_skip_flush(dirty_pgds), + }; + mmu_flush_invalidate_teardown_pages(kbdev, mmut->kctx, as_nr, phys, &op_param); return err; } @@ -2257,6 +2472,7 @@ KBASE_EXPORT_TEST_API(kbase_mmu_teardown_pages); * @flags: Flags * @group_id: The physical memory group in which the page was allocated. * Valid range is 0..(MEMORY_GROUP_MANAGER_NR_GROUPS-1). + * @dirty_pgds: Flags to track every level where a PGD has been updated. * * This will update page table entries that already exist on the GPU based on * the new flags that are passed (the physical pages pointed to by the page @@ -2269,8 +2485,8 @@ KBASE_EXPORT_TEST_API(kbase_mmu_teardown_pages); * successfully, otherwise an error code. */ static int kbase_mmu_update_pages_no_flush(struct kbase_context *kctx, u64 vpfn, - struct tagged_addr *phys, size_t nr, - unsigned long flags, int const group_id) + struct tagged_addr *phys, size_t nr, unsigned long flags, + int const group_id, u64 *dirty_pgds) { phys_addr_t pgd; u64 *pgd_page; @@ -2304,7 +2520,8 @@ static int kbase_mmu_update_pages_no_flush(struct kbase_context *kctx, u64 vpfn, if (is_huge(*phys) && (index == index_in_large_page(*phys))) cur_level = MIDGARD_MMU_LEVEL(2); - err = mmu_get_pgd_at_level(kbdev, &kctx->mmu, vpfn, cur_level, &pgd); + err = mmu_get_pgd_at_level(kbdev, &kctx->mmu, vpfn, cur_level, &pgd, NULL, + dirty_pgds); if (WARN_ON(err)) goto fail_unlock; @@ -2331,9 +2548,9 @@ static int kbase_mmu_update_pages_no_flush(struct kbase_context *kctx, u64 vpfn, pgd_page[level_index] = kbase_mmu_create_ate(kbdev, *target_phys, flags, MIDGARD_MMU_LEVEL(2), group_id); - kbase_mmu_sync_pgd(kbdev, - kbase_dma_addr(p) + (level_index * sizeof(u64)), - sizeof(u64)); + kbase_mmu_sync_pgd(kbdev, kctx, pgd + (level_index * sizeof(u64)), + kbase_dma_addr(p) + (level_index * sizeof(u64)), + sizeof(u64), KBASE_MMU_OP_NONE); } else { for (i = 0; i < count; i++) { #ifdef CONFIG_MALI_BIFROST_DEBUG @@ -2345,14 +2562,21 @@ static int kbase_mmu_update_pages_no_flush(struct kbase_context *kctx, u64 vpfn, phys[i], flags, MIDGARD_MMU_BOTTOMLEVEL, group_id); } - kbase_mmu_sync_pgd(kbdev, - kbase_dma_addr(p) + (index * sizeof(u64)), - count * sizeof(u64)); + + /* MMU cache flush strategy is NONE because GPU cache maintenance + * will be done by the caller. + */ + kbase_mmu_sync_pgd(kbdev, kctx, pgd + (index * sizeof(u64)), + kbase_dma_addr(p) + (index * sizeof(u64)), + count * sizeof(u64), KBASE_MMU_OP_NONE); } kbdev->mmu_mode->set_num_valid_entries(pgd_page, num_of_valid_entries); + if (dirty_pgds && count > 0) + *dirty_pgds |= 1ULL << cur_level; + phys += count; vpfn += count; nr -= count; @@ -2373,15 +2597,29 @@ int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn, unsigned long flags, int const group_id) { int err; + struct kbase_mmu_hw_op_param op_param; + u64 dirty_pgds = 0; /* Calls to this function are inherently asynchronous, with respect to * MMU operations. */ const enum kbase_caller_mmu_sync_info mmu_sync_info = CALLER_MMU_ASYNC; - err = kbase_mmu_update_pages_no_flush(kctx, vpfn, phys, nr, flags, - group_id); - kbase_mmu_flush_invalidate(kctx, vpfn, nr, true, mmu_sync_info); + err = kbase_mmu_update_pages_no_flush(kctx, vpfn, phys, nr, flags, group_id, &dirty_pgds); + + op_param = (const struct kbase_mmu_hw_op_param){ + .vpfn = vpfn, + .nr = nr, + .op = KBASE_MMU_OP_FLUSH_MEM, + .kctx_id = kctx->id, + .mmu_sync_info = mmu_sync_info, + .flush_skip_levels = pgd_level_to_skip_flush(dirty_pgds), + }; + + if (mmu_flush_cache_on_gpu_ctrl(kctx->kbdev)) + mmu_flush_invalidate_on_gpu_ctrl(kctx->kbdev, kctx, kctx->as_nr, &op_param); + else + mmu_flush_invalidate(kctx->kbdev, kctx, kctx->as_nr, &op_param); return err; } @@ -2418,7 +2656,9 @@ static void mmu_teardown_level(struct kbase_device *kbdev, mmu_mode = kbdev->mmu_mode; for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) { - target_pgd = mmu_mode->pte_to_phy_addr(pgd_page[i]); + target_pgd = mmu_mode->pte_to_phy_addr(kbdev->mgm_dev->ops.mgm_pte_to_original_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, + level, pgd_page[i])); if (target_pgd) { if (mmu_mode->pte_is_valid(pgd_page[i], level)) { @@ -2555,7 +2795,9 @@ static size_t kbasep_mmu_dump_level(struct kbase_context *kctx, phys_addr_t pgd, for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) { if (mmu_mode->pte_is_valid(pgd_page[i], level)) { target_pgd = mmu_mode->pte_to_phy_addr( - pgd_page[i]); + kbdev->mgm_dev->ops.mgm_pte_to_original_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, + level, pgd_page[i])); dump_size = kbasep_mmu_dump_level(kctx, target_pgd, level + 1, diff --git a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h index 017c96e67001..53d1d194eca7 100644 --- a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h +++ b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h @@ -129,11 +129,9 @@ void kbase_mmu_term(struct kbase_device *kbdev, struct kbase_mmu_table *mmut); u64 kbase_mmu_create_ate(struct kbase_device *kbdev, struct tagged_addr phy, unsigned long flags, int level, int group_id); -int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - const u64 start_vpfn, - struct tagged_addr *phys, size_t nr, - unsigned long flags, int group_id); +int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + const u64 start_vpfn, struct tagged_addr *phys, size_t nr, + unsigned long flags, int group_id, u64 *dirty_pgds); int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn, struct tagged_addr *phys, size_t nr, @@ -144,9 +142,8 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, unsigned long flags, int group_id, enum kbase_caller_mmu_sync_info mmu_sync_info); -int kbase_mmu_teardown_pages(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, u64 vpfn, - size_t nr, int as_nr); +int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn, + struct tagged_addr *phys, size_t nr, int as_nr); int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn, struct tagged_addr *phys, size_t nr, unsigned long flags, int const group_id); diff --git a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw.h b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw.h index 31658e0038b7..09b3fa809bea 100644 --- a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw.h +++ b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw.h @@ -75,12 +75,14 @@ enum kbase_mmu_op_type { }; /** - * struct kbase_mmu_hw_op_param - parameters for kbase_mmu_hw_do_operation() - * @vpfn: MMU Virtual Page Frame Number to start the operation on. - * @nr: Number of pages to work on. - * @op: Operation type (written to ASn_COMMAND). - * @kctx_id: Kernel context ID for MMU command tracepoint - * @mmu_sync_info: Indicates whether this call is synchronous wrt MMU ops. + * struct kbase_mmu_hw_op_param - parameters for kbase_mmu_hw_do_* functions + * @vpfn: MMU Virtual Page Frame Number to start the operation on. + * @nr: Number of pages to work on. + * @op: Operation type (written to ASn_COMMAND). + * @kctx_id: Kernel context ID for MMU command tracepoint. + * @mmu_sync_info: Indicates whether this call is synchronous wrt MMU ops. + * @flush_skip_levels: Page table levels to skip flushing. (Only + * applicable if GPU supports feature) */ struct kbase_mmu_hw_op_param { u64 vpfn; @@ -88,6 +90,7 @@ struct kbase_mmu_hw_op_param { enum kbase_mmu_op_type op; u32 kctx_id; enum kbase_caller_mmu_sync_info mmu_sync_info; + u64 flush_skip_levels; }; /** @@ -102,18 +105,86 @@ void kbase_mmu_hw_configure(struct kbase_device *kbdev, struct kbase_as *as); /** - * kbase_mmu_hw_do_operation - Issue an operation to the MMU. - * @kbdev: kbase device to issue the MMU operation on. - * @as: address space to issue the MMU operation on. - * @op_param: parameters for the operation. + * kbase_mmu_hw_do_unlock_no_addr - Issue UNLOCK command to the MMU without + * programming the LOCKADDR register and wait + * for it to complete before returning. * - * Issue an operation (MMU invalidate, MMU flush, etc) on the address space that - * is associated with the provided kbase_context over the specified range + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @op_param: Pointer to struct containing information about the MMU + * operation to perform. + * + * Return: 0 if issuing the command was successful, otherwise an error code. + */ +int kbase_mmu_hw_do_unlock_no_addr(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param); + +/** + * kbase_mmu_hw_do_unlock - Issue UNLOCK command to the MMU and wait for it + * to complete before returning. + * + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @op_param: Pointer to struct containing information about the MMU + * operation to perform. + * + * Return: 0 if issuing the command was successful, otherwise an error code. + */ +int kbase_mmu_hw_do_unlock(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param); +/** + * kbase_mmu_hw_do_flush - Issue a flush operation to the MMU. + * + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @op_param: Pointer to struct containing information about the MMU + * operation to perform. + * + * Issue a flush operation on the address space as per the information + * specified inside @op_param. This function should not be called for + * GPUs where MMU command to flush the cache(s) is deprecated. + * mmu_hw_mutex needs to be held when calling this function. * * Return: Zero if the operation was successful, non-zero otherwise. */ -int kbase_mmu_hw_do_operation(struct kbase_device *kbdev, struct kbase_as *as, - struct kbase_mmu_hw_op_param *op_param); +int kbase_mmu_hw_do_flush(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param); + +/** + * kbase_mmu_hw_do_flush_locked - Issue a flush operation to the MMU. + * + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @op_param: Pointer to struct containing information about the MMU + * operation to perform. + * + * Issue a flush operation on the address space as per the information + * specified inside @op_param. This function should not be called for + * GPUs where MMU command to flush the cache(s) is deprecated. + * Both mmu_hw_mutex and hwaccess_lock need to be held when calling this + * function. + * + * Return: Zero if the operation was successful, non-zero otherwise. + */ +int kbase_mmu_hw_do_flush_locked(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param); + +/** + * kbase_mmu_hw_do_flush_on_gpu_ctrl - Issue a flush operation to the MMU. + * + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @op_param: Pointer to struct containing information about the MMU + * operation to perform. + * + * Issue a flush operation on the address space as per the information + * specified inside @op_param. GPU command is used to flush the cache(s) + * instead of the MMU command. + * + * Return: Zero if the operation was successful, non-zero otherwise. + */ +int kbase_mmu_hw_do_flush_on_gpu_ctrl(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param); /** * kbase_mmu_hw_clear_fault - Clear a fault that has been previously reported by diff --git a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw_direct.c b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw_direct.c index 21c8798242e4..c9e5ef288ff8 100644 --- a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw_direct.c +++ b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw_direct.c @@ -26,13 +26,17 @@ #include #include #include +#include + /** * lock_region() - Generate lockaddr to lock memory region in MMU - * @gpu_props: GPU properties for finding the MMU lock region size - * @pfn: Starting page frame number of the region to lock - * @num_pages: Number of pages to lock. It must be greater than 0. - * @lockaddr: Address and size of memory region to lock + * + * @gpu_props: GPU properties for finding the MMU lock region size. + * @lockaddr: Address and size of memory region to lock. + * @op_param: Pointer to a struct containing the starting page frame number of + * the region to lock, the number of pages to lock and page table + * levels to skip when flushing (if supported). * * The lockaddr value is a combination of the starting address and * the size of the region that encompasses all the memory pages to lock. @@ -63,14 +67,14 @@ * * Return: 0 if success, or an error code on failure. */ -static int lock_region(struct kbase_gpu_props const *gpu_props, u64 pfn, u32 num_pages, - u64 *lockaddr) +static int lock_region(struct kbase_gpu_props const *gpu_props, u64 *lockaddr, + const struct kbase_mmu_hw_op_param *op_param) { - const u64 lockaddr_base = pfn << PAGE_SHIFT; - const u64 lockaddr_end = ((pfn + num_pages) << PAGE_SHIFT) - 1; + const u64 lockaddr_base = op_param->vpfn << PAGE_SHIFT; + const u64 lockaddr_end = ((op_param->vpfn + op_param->nr) << PAGE_SHIFT) - 1; u64 lockaddr_size_log2; - if (num_pages == 0) + if (op_param->nr == 0) return -EINVAL; /* The MMU lock region is a self-aligned region whose size @@ -122,7 +126,6 @@ static int lock_region(struct kbase_gpu_props const *gpu_props, u64 pfn, u32 num */ *lockaddr = lockaddr_base & ~((1ull << lockaddr_size_log2) - 1); *lockaddr |= lockaddr_size_log2 - 1; - return 0; } @@ -165,6 +168,100 @@ static int write_cmd(struct kbase_device *kbdev, int as_nr, u32 cmd) return status; } +#if MALI_USE_CSF && !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) +static int wait_cores_power_trans_complete(struct kbase_device *kbdev) +{ +#define WAIT_TIMEOUT 1000 /* 1ms timeout */ +#define DELAY_TIME_IN_US 1 + const int max_iterations = WAIT_TIMEOUT; + int loop; + + lockdep_assert_held(&kbdev->hwaccess_lock); + + for (loop = 0; loop < max_iterations; loop++) { + u32 lo = + kbase_reg_read(kbdev, GPU_CONTROL_REG(SHADER_PWRTRANS_LO)); + u32 hi = + kbase_reg_read(kbdev, GPU_CONTROL_REG(SHADER_PWRTRANS_HI)); + + if (!lo && !hi) + break; + + udelay(DELAY_TIME_IN_US); + } + + if (loop == max_iterations) { + dev_warn(kbdev->dev, "SHADER_PWRTRANS set for too long"); + return -ETIMEDOUT; + } + + return 0; +} + +/** + * apply_hw_issue_GPU2019_3901_wa - Apply WA for the HW issue GPU2019_3901 + * + * @kbdev: Kbase device to issue the MMU operation on. + * @mmu_cmd: Pointer to the variable contain the value of MMU command + * that needs to be sent to flush the L2 cache and do an + * implicit unlock. + * @as_nr: Address space number for which MMU command needs to be + * sent. + * @hwaccess_locked: Flag to indicate if hwaccess_lock is held by the caller. + * + * This functions ensures that the flush of LSC is not missed for the pages that + * were unmapped from the GPU, due to the power down transition of shader cores. + * + * Return: 0 if the WA was successfully applied, non-zero otherwise. + */ +static int apply_hw_issue_GPU2019_3901_wa(struct kbase_device *kbdev, + u32 *mmu_cmd, unsigned int as_nr, bool hwaccess_locked) +{ + unsigned long flags = 0; + int ret = 0; + + if (!hwaccess_locked) + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + + /* Check if L2 is OFF. The cores also must be OFF if L2 is not up, so + * the workaround can be safely skipped. + */ + if (kbdev->pm.backend.l2_state != KBASE_L2_OFF) { + if (*mmu_cmd != AS_COMMAND_FLUSH_MEM) { + dev_warn(kbdev->dev, + "Unexpected mmu command received"); + ret = -EINVAL; + goto unlock; + } + + /* Wait for the LOCK MMU command to complete, issued by the caller */ + ret = wait_ready(kbdev, as_nr); + if (ret) + goto unlock; + + ret = kbase_gpu_cache_flush_and_busy_wait(kbdev, + GPU_COMMAND_CACHE_CLN_INV_LSC); + if (ret) + goto unlock; + + ret = wait_cores_power_trans_complete(kbdev); + if (ret) + goto unlock; + + /* As LSC is guaranteed to have been flushed we can use FLUSH_PT + * MMU command to only flush the L2. + */ + *mmu_cmd = AS_COMMAND_FLUSH_PT; + } + +unlock: + if (!hwaccess_locked) + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + + return ret; +} +#endif + void kbase_mmu_hw_configure(struct kbase_device *kbdev, struct kbase_as *as) { struct kbase_mmu_setup *current_setup = &as->current_setup; @@ -222,95 +319,245 @@ void kbase_mmu_hw_configure(struct kbase_device *kbdev, struct kbase_as *as) #endif } -int kbase_mmu_hw_do_operation(struct kbase_device *kbdev, struct kbase_as *as, - struct kbase_mmu_hw_op_param *op_param) +/** + * mmu_command_instr - Record an MMU command for instrumentation purposes. + * + * @kbdev: Kbase device used to issue MMU operation on. + * @kctx_id: Kernel context ID for MMU command tracepoint. + * @cmd: Command issued to the MMU. + * @lock_addr: Address of memory region locked for the operation. + * @mmu_sync_info: Indicates whether this call is synchronous wrt MMU ops. + */ +static void mmu_command_instr(struct kbase_device *kbdev, u32 kctx_id, u32 cmd, u64 lock_addr, + enum kbase_caller_mmu_sync_info mmu_sync_info) +{ + u64 lock_addr_base = AS_LOCKADDR_LOCKADDR_BASE_GET(lock_addr); + u32 lock_addr_size = AS_LOCKADDR_LOCKADDR_SIZE_GET(lock_addr); + + bool is_mmu_synchronous = (mmu_sync_info == CALLER_MMU_SYNC); + + KBASE_TLSTREAM_AUX_MMU_COMMAND(kbdev, kctx_id, cmd, is_mmu_synchronous, lock_addr_base, + lock_addr_size); +} + +/* Helper function to program the LOCKADDR register before LOCK/UNLOCK command + * is issued. + */ +static int mmu_hw_set_lock_addr(struct kbase_device *kbdev, int as_nr, u64 *lock_addr, + const struct kbase_mmu_hw_op_param *op_param) +{ + int ret; + + ret = lock_region(&kbdev->gpu_props, lock_addr, op_param); + + if (!ret) { + /* Set the region that needs to be updated */ + kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_LOCKADDR_LO), + *lock_addr & 0xFFFFFFFFUL); + kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_LOCKADDR_HI), + (*lock_addr >> 32) & 0xFFFFFFFFUL); + } + return ret; +} + +/** + * mmu_hw_do_lock_no_wait - Issue LOCK command to the MMU and return without + * waiting for it's completion. + * + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @lock_addr: Address of memory region locked for this operation. + * @op_param: Pointer to a struct containing information about the MMU operation. + * + * Return: 0 if issuing the command was successful, otherwise an error code. + */ +static int mmu_hw_do_lock_no_wait(struct kbase_device *kbdev, struct kbase_as *as, u64 *lock_addr, + const struct kbase_mmu_hw_op_param *op_param) +{ + int ret; + + ret = mmu_hw_set_lock_addr(kbdev, as->number, lock_addr, op_param); + + if (!ret) + write_cmd(kbdev, as->number, AS_COMMAND_LOCK); + + return ret; +} + +static int mmu_hw_do_lock(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param) { int ret; u64 lock_addr = 0x0; - if (WARN_ON(kbdev == NULL) || - WARN_ON(as == NULL) || - WARN_ON(op_param == NULL)) + if (WARN_ON(kbdev == NULL) || WARN_ON(as == NULL)) return -EINVAL; - lockdep_assert_held(&kbdev->mmu_hw_mutex); + ret = mmu_hw_do_lock_no_wait(kbdev, as, &lock_addr, op_param); - if (op_param->op == KBASE_MMU_OP_UNLOCK) { - /* Unlock doesn't require a lock first */ - ret = write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK); - - /* Wait for UNLOCK command to complete */ + if (!ret) ret = wait_ready(kbdev, as->number); - if (!ret) { - /* read MMU_AS_CONTROL.LOCKADDR register */ - lock_addr |= (u64)kbase_reg_read(kbdev, - MMU_AS_REG(as->number, AS_LOCKADDR_HI)) << 32; - lock_addr |= (u64)kbase_reg_read(kbdev, - MMU_AS_REG(as->number, AS_LOCKADDR_LO)); - } - } else if (op_param->op >= KBASE_MMU_OP_FIRST && - op_param->op < KBASE_MMU_OP_COUNT) { - ret = lock_region(&kbdev->gpu_props, op_param->vpfn, op_param->nr, &lock_addr); + if (!ret) + mmu_command_instr(kbdev, op_param->kctx_id, AS_COMMAND_LOCK, lock_addr, + op_param->mmu_sync_info); - if (!ret) { - /* Lock the region that needs to be updated */ - kbase_reg_write(kbdev, - MMU_AS_REG(as->number, AS_LOCKADDR_LO), - lock_addr & 0xFFFFFFFFUL); - kbase_reg_write(kbdev, - MMU_AS_REG(as->number, AS_LOCKADDR_HI), - (lock_addr >> 32) & 0xFFFFFFFFUL); - write_cmd(kbdev, as->number, AS_COMMAND_LOCK); + return ret; +} - /* Translate and send operation to HW */ - switch (op_param->op) { - case KBASE_MMU_OP_FLUSH_PT: - write_cmd(kbdev, as->number, - AS_COMMAND_FLUSH_PT); - break; - case KBASE_MMU_OP_FLUSH_MEM: - write_cmd(kbdev, as->number, - AS_COMMAND_FLUSH_MEM); - break; - case KBASE_MMU_OP_LOCK: - /* No further operation. */ - break; - default: - dev_warn(kbdev->dev, - "Unsupported MMU operation (op=%d).\n", - op_param->op); - return -EINVAL; - }; +int kbase_mmu_hw_do_unlock_no_addr(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param) +{ + int ret = 0; - /* Wait for the command to complete */ - ret = wait_ready(kbdev, as->number); - } - } else { - /* Code should not reach here. */ - dev_warn(kbdev->dev, "Invalid mmu operation (op=%d).\n", - op_param->op); + if (WARN_ON(kbdev == NULL) || WARN_ON(as == NULL)) return -EINVAL; - } - /* MMU command instrumentation */ + ret = write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK); + + /* Wait for UNLOCK command to complete */ + if (!ret) + ret = wait_ready(kbdev, as->number); + if (!ret) { - u64 lock_addr_base = AS_LOCKADDR_LOCKADDR_BASE_GET(lock_addr); - u32 lock_addr_size = AS_LOCKADDR_LOCKADDR_SIZE_GET(lock_addr); + u64 lock_addr = 0x0; + /* read MMU_AS_CONTROL.LOCKADDR register */ + lock_addr |= (u64)kbase_reg_read(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_HI)) + << 32; + lock_addr |= (u64)kbase_reg_read(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_LO)); - bool is_mmu_synchronous = false; - - if (op_param->mmu_sync_info == CALLER_MMU_SYNC) - is_mmu_synchronous = true; - - KBASE_TLSTREAM_AUX_MMU_COMMAND(kbdev, op_param->kctx_id, - op_param->op, is_mmu_synchronous, - lock_addr_base, lock_addr_size); + mmu_command_instr(kbdev, op_param->kctx_id, AS_COMMAND_UNLOCK, + lock_addr, op_param->mmu_sync_info); } return ret; } +int kbase_mmu_hw_do_unlock(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param) +{ + int ret = 0; + u64 lock_addr = 0x0; + + if (WARN_ON(kbdev == NULL) || WARN_ON(as == NULL)) + return -EINVAL; + + ret = mmu_hw_set_lock_addr(kbdev, as->number, &lock_addr, op_param); + + if (!ret) + ret = kbase_mmu_hw_do_unlock_no_addr(kbdev, as, + op_param); + + return ret; +} + +static int mmu_hw_do_flush(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param, bool hwaccess_locked) +{ + int ret; + u64 lock_addr = 0x0; + u32 mmu_cmd = AS_COMMAND_FLUSH_MEM; + + if (WARN_ON(kbdev == NULL) || WARN_ON(as == NULL)) + return -EINVAL; + + /* MMU operations can be either FLUSH_PT or FLUSH_MEM, anything else at + * this point would be unexpected. + */ + if (op_param->op != KBASE_MMU_OP_FLUSH_PT && + op_param->op != KBASE_MMU_OP_FLUSH_MEM) { + dev_err(kbdev->dev, "Unexpected flush operation received"); + return -EINVAL; + } + + lockdep_assert_held(&kbdev->mmu_hw_mutex); + + if (op_param->op == KBASE_MMU_OP_FLUSH_PT) + mmu_cmd = AS_COMMAND_FLUSH_PT; + + /* Lock the region that needs to be updated */ + ret = mmu_hw_do_lock_no_wait(kbdev, as, &lock_addr, op_param); + if (ret) + return ret; + +#if MALI_USE_CSF && !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) + /* WA for the BASE_HW_ISSUE_GPU2019_3901. No runtime check is used here + * as the WA is applicable to all CSF GPUs where FLUSH_MEM/PT command is + * supported, and this function doesn't gets called for the GPUs where + * FLUSH_MEM/PT command is deprecated. + */ + if (mmu_cmd == AS_COMMAND_FLUSH_MEM) { + ret = apply_hw_issue_GPU2019_3901_wa(kbdev, &mmu_cmd, + as->number, hwaccess_locked); + if (ret) + return ret; + } +#endif + + write_cmd(kbdev, as->number, mmu_cmd); + + /* Wait for the command to complete */ + ret = wait_ready(kbdev, as->number); + + if (!ret) + mmu_command_instr(kbdev, op_param->kctx_id, mmu_cmd, lock_addr, + op_param->mmu_sync_info); + + return ret; +} + +int kbase_mmu_hw_do_flush_locked(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param) +{ + lockdep_assert_held(&kbdev->hwaccess_lock); + + return mmu_hw_do_flush(kbdev, as, op_param, true); +} + +int kbase_mmu_hw_do_flush(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param) +{ + return mmu_hw_do_flush(kbdev, as, op_param, false); +} + +int kbase_mmu_hw_do_flush_on_gpu_ctrl(struct kbase_device *kbdev, struct kbase_as *as, + const struct kbase_mmu_hw_op_param *op_param) +{ + int ret, ret2; + u32 gpu_cmd = GPU_COMMAND_CACHE_CLN_INV_L2_LSC; + + if (WARN_ON(kbdev == NULL) || WARN_ON(as == NULL)) + return -EINVAL; + + /* MMU operations can be either FLUSH_PT or FLUSH_MEM, anything else at + * this point would be unexpected. + */ + if (op_param->op != KBASE_MMU_OP_FLUSH_PT && + op_param->op != KBASE_MMU_OP_FLUSH_MEM) { + dev_err(kbdev->dev, "Unexpected flush operation received"); + return -EINVAL; + } + + lockdep_assert_held(&kbdev->hwaccess_lock); + lockdep_assert_held(&kbdev->mmu_hw_mutex); + + if (op_param->op == KBASE_MMU_OP_FLUSH_PT) + gpu_cmd = GPU_COMMAND_CACHE_CLN_INV_L2; + + /* 1. Issue MMU_AS_CONTROL.COMMAND.LOCK operation. */ + ret = mmu_hw_do_lock(kbdev, as, op_param); + if (ret) + return ret; + + /* 2. Issue GPU_CONTROL.COMMAND.FLUSH_CACHES operation */ + ret = kbase_gpu_cache_flush_and_busy_wait(kbdev, gpu_cmd); + + /* 3. Issue MMU_AS_CONTROL.COMMAND.UNLOCK operation. */ + ret2 = kbase_mmu_hw_do_unlock_no_addr(kbdev, as, op_param); + + return ret ?: ret2; +} + void kbase_mmu_hw_clear_fault(struct kbase_device *kbdev, struct kbase_as *as, enum kbase_mmu_fault_type type) { diff --git a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_mode_aarch64.c b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_mode_aarch64.c index c06109940dd0..dfbdee17782b 100644 --- a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_mode_aarch64.c +++ b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_mode_aarch64.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2014, 2016-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2014, 2016-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -189,14 +189,9 @@ static void set_num_valid_entries(u64 *pgd, unsigned int num_of_valid_entries) << UNUSED_BIT_POSITION_IN_PAGE_DESCRIPTOR); } -static void entry_set_pte(u64 *pgd, u64 vpfn, phys_addr_t phy) +static void entry_set_pte(u64 *entry, phys_addr_t phy) { - unsigned int nr_entries = get_num_valid_entries(pgd); - - page_table_entry_set(&pgd[vpfn], (phy & PAGE_MASK) | ENTRY_ACCESS_BIT | - ENTRY_IS_PTE); - - set_num_valid_entries(pgd, nr_entries + 1); + page_table_entry_set(entry, (phy & PAGE_MASK) | ENTRY_ACCESS_BIT | ENTRY_IS_PTE); } static void entry_invalidate(u64 *entry) diff --git a/drivers/gpu/arm/bifrost/platform/devicetree/mali_kbase_runtime_pm.c b/drivers/gpu/arm/bifrost/platform/devicetree/mali_kbase_runtime_pm.c index 5e4bf3f68d06..07b09f868735 100644 --- a/drivers/gpu/arm/bifrost/platform/devicetree/mali_kbase_runtime_pm.c +++ b/drivers/gpu/arm/bifrost/platform/devicetree/mali_kbase_runtime_pm.c @@ -29,6 +29,7 @@ #include "mali_kbase_config_platform.h" + static void enable_gpu_power_control(struct kbase_device *kbdev) { unsigned int i; @@ -50,7 +51,6 @@ static void enable_gpu_power_control(struct kbase_device *kbdev) } } - static void disable_gpu_power_control(struct kbase_device *kbdev) { unsigned int i; @@ -99,9 +99,8 @@ static int pm_callback_power_on(struct kbase_device *kbdev) #else spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); +#ifdef KBASE_PM_RUNTIME error = pm_runtime_get_sync(kbdev->dev); - enable_gpu_power_control(kbdev); - if (error == 1) { /* * Let core know that the chip has not been @@ -109,8 +108,11 @@ static int pm_callback_power_on(struct kbase_device *kbdev) */ ret = 0; } - dev_dbg(kbdev->dev, "pm_runtime_get_sync returned %d\n", error); +#else + enable_gpu_power_control(kbdev); +#endif /* KBASE_PM_RUNTIME */ + #endif /* MALI_USE_CSF */ return ret; @@ -243,7 +245,9 @@ static int pm_callback_runtime_on(struct kbase_device *kbdev) { dev_dbg(kbdev->dev, "%s\n", __func__); +#if !MALI_USE_CSF enable_gpu_power_control(kbdev); +#endif return 0; } @@ -251,7 +255,9 @@ static void pm_callback_runtime_off(struct kbase_device *kbdev) { dev_dbg(kbdev->dev, "%s\n", __func__); +#if !MALI_USE_CSF disable_gpu_power_control(kbdev); +#endif } static void pm_callback_resume(struct kbase_device *kbdev) diff --git a/drivers/gpu/arm/bifrost/tests/Kbuild b/drivers/gpu/arm/bifrost/tests/Kbuild index ee3de7b00652..38e4dd4d712a 100644 --- a/drivers/gpu/arm/bifrost/tests/Kbuild +++ b/drivers/gpu/arm/bifrost/tests/Kbuild @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2017, 2020-2021 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2017, 2020-2022 ARM Limited. All rights reserved. # # This program is free software and is provided to you under the terms of the # GNU General Public License version 2 as published by the Free Software @@ -27,4 +27,5 @@ subdir-ccflags-y += -I$(src)/include \ obj-$(CONFIG_MALI_KUTF) += kutf/ obj-$(CONFIG_MALI_KUTF_IRQ_TEST) += mali_kutf_irq_test/ obj-$(CONFIG_MALI_KUTF_CLK_RATE_TRACE) += mali_kutf_clk_rate_trace/kernel/ +obj-$(CONFIG_MALI_KUTF_MGM_INTEGRATION) += mali_kutf_mgm_integration_test/ diff --git a/drivers/gpu/arm/bifrost/tests/Kconfig b/drivers/gpu/arm/bifrost/tests/Kconfig index 820f11e65d87..e9fe22771416 100644 --- a/drivers/gpu/arm/bifrost/tests/Kconfig +++ b/drivers/gpu/arm/bifrost/tests/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2017, 2020-2021 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2017, 2020-2022 ARM Limited. All rights reserved. # # This program is free software and is provided to you under the terms of the # GNU General Public License version 2 as published by the Free Software @@ -52,6 +52,18 @@ config MALI_KUTF_CLK_RATE_TRACE Modules: - mali_kutf_clk_rate_trace_test_portal.ko +config MALI_KUTF_MGM_INTEGRATION_TEST + bool "Build Mali KUTF MGM integration test module" + depends on MALI_KUTF + default y + help + This option will build the MGM integration test module. + It can test the implementation of PTE translation for specific + group ids. + + Modules: + - mali_kutf_mgm_integration_test.ko + comment "Enable MALI_BIFROST_DEBUG for KUTF modules support" depends on MALI_BIFROST && !MALI_BIFROST_DEBUG && MALI_KUTF diff --git a/drivers/gpu/arm/bifrost/tests/Mconfig b/drivers/gpu/arm/bifrost/tests/Mconfig index f5fdeffe9b3c..738dbd42aac7 100644 --- a/drivers/gpu/arm/bifrost/tests/Mconfig +++ b/drivers/gpu/arm/bifrost/tests/Mconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2018-2021 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. # # This program is free software and is provided to you under the terms of the # GNU General Public License version 2 as published by the Free Software @@ -52,6 +52,18 @@ config MALI_KUTF_CLK_RATE_TRACE Modules: - mali_kutf_clk_rate_trace_test_portal.ko +config MALI_KUTF_MGM_INTEGRATION_TEST + bool "Build Mali KUTF MGM integration test module" + depends on MALI_KUTF + default y + help + This option will build the MGM integration test module. + It can test the implementation of PTE translation for specific + group ids. + + Modules: + - mali_kutf_mgm_integration_test.ko + # Enable MALI_BIFROST_DEBUG for KUTF modules support diff --git a/drivers/gpu/arm/bifrost/tests/kutf/kutf_helpers_user.c b/drivers/gpu/arm/bifrost/tests/kutf/kutf_helpers_user.c index f88e138c9030..c4e294325262 100644 --- a/drivers/gpu/arm/bifrost/tests/kutf/kutf_helpers_user.c +++ b/drivers/gpu/arm/bifrost/tests/kutf/kutf_helpers_user.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2017, 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2017, 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -28,7 +28,7 @@ #include #include -const char *valtype_names[] = { +static const char *const valtype_names[] = { "INVALID", "U64", "STR", diff --git a/drivers/gpu/arm/bifrost/tests/kutf/kutf_suite.c b/drivers/gpu/arm/bifrost/tests/kutf/kutf_suite.c index 91065b5820dd..4468066f1b27 100644 --- a/drivers/gpu/arm/bifrost/tests/kutf/kutf_suite.c +++ b/drivers/gpu/arm/bifrost/tests/kutf/kutf_suite.c @@ -106,22 +106,16 @@ struct kutf_convert_table { enum kutf_result_status result; }; -struct kutf_convert_table kutf_convert[] = { -#define ADD_UTF_RESULT(_name) \ -{ \ - #_name, \ - _name, \ -}, -ADD_UTF_RESULT(KUTF_RESULT_BENCHMARK) -ADD_UTF_RESULT(KUTF_RESULT_SKIP) -ADD_UTF_RESULT(KUTF_RESULT_UNKNOWN) -ADD_UTF_RESULT(KUTF_RESULT_PASS) -ADD_UTF_RESULT(KUTF_RESULT_DEBUG) -ADD_UTF_RESULT(KUTF_RESULT_INFO) -ADD_UTF_RESULT(KUTF_RESULT_WARN) -ADD_UTF_RESULT(KUTF_RESULT_FAIL) -ADD_UTF_RESULT(KUTF_RESULT_FATAL) -ADD_UTF_RESULT(KUTF_RESULT_ABORT) +static const struct kutf_convert_table kutf_convert[] = { +#define ADD_UTF_RESULT(_name) \ + { \ +#_name, _name, \ + } + ADD_UTF_RESULT(KUTF_RESULT_BENCHMARK), ADD_UTF_RESULT(KUTF_RESULT_SKIP), + ADD_UTF_RESULT(KUTF_RESULT_UNKNOWN), ADD_UTF_RESULT(KUTF_RESULT_PASS), + ADD_UTF_RESULT(KUTF_RESULT_DEBUG), ADD_UTF_RESULT(KUTF_RESULT_INFO), + ADD_UTF_RESULT(KUTF_RESULT_WARN), ADD_UTF_RESULT(KUTF_RESULT_FAIL), + ADD_UTF_RESULT(KUTF_RESULT_FATAL), ADD_UTF_RESULT(KUTF_RESULT_ABORT), }; #define UTF_CONVERT_SIZE (ARRAY_SIZE(kutf_convert)) @@ -191,8 +185,7 @@ static void kutf_set_expected_result(struct kutf_context *context, * * Return: 1 if test result was successfully converted to string, 0 otherwise */ -static int kutf_result_to_string(char **result_str, - enum kutf_result_status result) +static int kutf_result_to_string(const char **result_str, enum kutf_result_status result) { int i; int ret = 0; @@ -382,7 +375,7 @@ static ssize_t kutf_debugfs_run_read(struct file *file, char __user *buf, struct kutf_result *res; unsigned long bytes_not_copied; ssize_t bytes_copied = 0; - char *kutf_str_ptr = NULL; + const char *kutf_str_ptr = NULL; size_t kutf_str_len = 0; size_t message_len = 0; char separator = ':'; @@ -599,11 +592,7 @@ static int create_fixture_variant(struct kutf_test_function *test_func, goto fail_file; } -#if KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE tmp = debugfs_create_file_unsafe( -#else - tmp = debugfs_create_file( -#endif "run", 0600, test_fix->dir, test_fix, &kutf_debugfs_run_ops); diff --git a/drivers/gpu/arm/bifrost/tests/kutf/kutf_utils.c b/drivers/gpu/arm/bifrost/tests/kutf/kutf_utils.c index 2ae15109f109..21f5fadcc5f6 100644 --- a/drivers/gpu/arm/bifrost/tests/kutf/kutf_utils.c +++ b/drivers/gpu/arm/bifrost/tests/kutf/kutf_utils.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014, 2017, 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014, 2017, 2020-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -31,7 +31,7 @@ static char tmp_buffer[KUTF_MAX_DSPRINTF_LEN]; -DEFINE_MUTEX(buffer_lock); +static DEFINE_MUTEX(buffer_lock); const char *kutf_dsprintf(struct kutf_mempool *pool, const char *fmt, ...) diff --git a/drivers/gpu/arm/bifrost/tests/mali_kutf_clk_rate_trace/kernel/mali_kutf_clk_rate_trace_test.c b/drivers/gpu/arm/bifrost/tests/mali_kutf_clk_rate_trace/kernel/mali_kutf_clk_rate_trace_test.c index e64c44a0b1f9..2d7289daca20 100644 --- a/drivers/gpu/arm/bifrost/tests/mali_kutf_clk_rate_trace/kernel/mali_kutf_clk_rate_trace_test.c +++ b/drivers/gpu/arm/bifrost/tests/mali_kutf_clk_rate_trace/kernel/mali_kutf_clk_rate_trace_test.c @@ -46,7 +46,7 @@ #define MINOR_FOR_FIRST_KBASE_DEV (-1) /* KUTF test application pointer for this test */ -struct kutf_application *kutf_app; +static struct kutf_application *kutf_app; enum portal_server_state { PORTAL_STATE_NO_CLK, @@ -113,7 +113,7 @@ struct kbasep_cmd_name_pair { const char *name; }; -struct kbasep_cmd_name_pair kbasep_portal_cmd_name_map[] = { +static const struct kbasep_cmd_name_pair kbasep_portal_cmd_name_map[] = { { PORTAL_CMD_GET_PLATFORM, GET_PLATFORM }, { PORTAL_CMD_GET_CLK_RATE_MGR, GET_CLK_RATE_MGR }, { PORTAL_CMD_GET_CLK_RATE_TRACE, GET_CLK_RATE_TRACE }, @@ -128,7 +128,7 @@ struct kbasep_cmd_name_pair kbasep_portal_cmd_name_map[] = { * this pointer is engaged, new requests for create fixture will fail * hence limiting the use of the portal at any time to a singleton. */ -struct kutf_clk_rate_trace_fixture_data *g_ptr_portal_data; +static struct kutf_clk_rate_trace_fixture_data *g_ptr_portal_data; #define PORTAL_MSG_LEN (KUTF_MAX_LINE_LENGTH - MAX_REPLY_NAME_LEN) static char portal_msg_buf[PORTAL_MSG_LEN]; @@ -825,7 +825,7 @@ static void *mali_kutf_clk_rate_trace_create_fixture( if (!data) return NULL; - *data = (const struct kutf_clk_rate_trace_fixture_data) { 0 }; + *data = (const struct kutf_clk_rate_trace_fixture_data){ NULL }; pr_debug("Hooking up the test portal to kbdev clk rate trace\n"); spin_lock(&kbdev->pm.clk_rtm.lock); @@ -909,7 +909,7 @@ static int __init mali_kutf_clk_rate_trace_test_module_init(void) { struct kutf_suite *suite; unsigned int filters; - union kutf_callback_data suite_data = { 0 }; + union kutf_callback_data suite_data = { NULL }; pr_debug("Creating app\n"); diff --git a/drivers/gpu/arm/bifrost/tests/mali_kutf_irq_test/mali_kutf_irq_test_main.c b/drivers/gpu/arm/bifrost/tests/mali_kutf_irq_test/mali_kutf_irq_test_main.c index 5824a4c2c530..2d6e68946c00 100644 --- a/drivers/gpu/arm/bifrost/tests/mali_kutf_irq_test/mali_kutf_irq_test_main.c +++ b/drivers/gpu/arm/bifrost/tests/mali_kutf_irq_test/mali_kutf_irq_test_main.c @@ -40,7 +40,7 @@ */ /* KUTF test application pointer for this test */ -struct kutf_application *irq_app; +static struct kutf_application *irq_app; /** * struct kutf_irq_fixture_data - test fixture used by the test functions. diff --git a/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/Kbuild b/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/Kbuild new file mode 100644 index 000000000000..e9bff98b88b6 --- /dev/null +++ b/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/Kbuild @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note +# +# (C) COPYRIGHT 2022 ARM Limited. All rights reserved. +# +# This program is free software and is provided to you under the terms of the +# GNU General Public License version 2 as published by the Free Software +# Foundation, and any use by you of this program is subject to the terms +# of such GNU license. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# + +ifeq ($(CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST),y) +obj-m += mali_kutf_mgm_integration_test.o + +mali_kutf_mgm_integration_test-y := mali_kutf_mgm_integration_test_main.o +endif diff --git a/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/build.bp b/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/build.bp new file mode 100644 index 000000000000..2e4a083863e4 --- /dev/null +++ b/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/build.bp @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * + * (C) COPYRIGHT 2022 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + */ +bob_kernel_module { + name: "mali_kutf_mgm_integration_test", + defaults: [ + "mali_kbase_shared_config_defaults", + "kernel_test_configs", + "kernel_test_includes", + ], + srcs: [ + "Kbuild", + "mali_kutf_mgm_integration_test_main.c", + ], + extra_symbols: [ + "mali_kbase", + "kutf", + ], + enabled: false, + mali_kutf_mgm_integration_test: { + kbuild_options: ["CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST=y"], + enabled: true, + }, +} \ No newline at end of file diff --git a/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/mali_kutf_mgm_integration_test_main.c b/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/mali_kutf_mgm_integration_test_main.c new file mode 100644 index 000000000000..5a42bd675c2a --- /dev/null +++ b/drivers/gpu/arm/bifrost/tests/mali_kutf_mgm_integration_test/mali_kutf_mgm_integration_test_main.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note +/* + * + * (C) COPYRIGHT 2022 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + */ +#include +#include "mali_kbase.h" +#include +#include +#include +#include + +#define MINOR_FOR_FIRST_KBASE_DEV (-1) + +#define BASE_MEM_GROUP_COUNT (16) +#define PA_MAX ((1ULL << 48) - 1) +#define PA_START_BIT 12 +#define ENTRY_ACCESS_BIT (1ULL << 10) + +#define ENTRY_IS_ATE_L3 3ULL +#define ENTRY_IS_ATE_L02 1ULL + +#define MGM_INTEGRATION_SUITE_NAME "mgm_integration" +#define MGM_INTEGRATION_PTE_TRANSLATION "pte_translation" + +static char msg_buf[KUTF_MAX_LINE_LENGTH]; + +/* KUTF test application pointer for this test */ +struct kutf_application *mgm_app; + +/** + * struct kutf_mgm_fixture_data - test fixture used by test functions + * @kbdev: kbase device for the GPU. + * @group_id: Memory group ID to test based on fixture index. + */ +struct kutf_mgm_fixture_data { + struct kbase_device *kbdev; + int group_id; +}; + +/** + * mali_kutf_mgm_pte_translation_test() - Tests forward and reverse translation + * of PTE by the MGM module + * @context: KUTF context within which to perform the test. + * + * This test creates PTEs with physical addresses in the range + * 0x0000-0xFFFFFFFFF000 and tests that mgm_update_gpu_pte() returns a different + * PTE and mgm_pte_to_original_pte() returns the original PTE. This is tested + * at MMU level 2 and 3 as mgm_update_gpu_pte() is called for ATEs only. + * + * This test is run for a specific group_id depending on the fixture_id. + */ +static void mali_kutf_mgm_pte_translation_test(struct kutf_context *context) +{ + struct kutf_mgm_fixture_data *data = context->fixture; + struct kbase_device *kbdev = data->kbdev; + struct memory_group_manager_device *mgm_dev = kbdev->mgm_dev; + u64 addr; + + for (addr = 1 << (PA_START_BIT - 1); addr <= PA_MAX; addr <<= 1) { + /* Mask 1 << 11 by ~0xFFF to get 0x0000 at first iteration */ + phys_addr_t pa = addr; + u8 mmu_level; + + /* Test MMU level 3 and 2 (2MB pages) only */ + for (mmu_level = MIDGARD_MMU_LEVEL(2); mmu_level <= MIDGARD_MMU_LEVEL(3); + mmu_level++) { + u64 translated_pte; + u64 returned_pte; + u64 original_pte; + + if (mmu_level == MIDGARD_MMU_LEVEL(3)) + original_pte = + (pa & PAGE_MASK) | ENTRY_ACCESS_BIT | ENTRY_IS_ATE_L3; + else + original_pte = + (pa & PAGE_MASK) | ENTRY_ACCESS_BIT | ENTRY_IS_ATE_L02; + + dev_dbg(kbdev->dev, "Testing group_id=%u, mmu_level=%u, pte=0x%llx\n", + data->group_id, mmu_level, original_pte); + + translated_pte = mgm_dev->ops.mgm_update_gpu_pte(mgm_dev, data->group_id, + mmu_level, original_pte); + if (translated_pte == original_pte) { + snprintf( + msg_buf, sizeof(msg_buf), + "PTE unchanged. translated_pte (0x%llx) == original_pte (0x%llx) for mmu_level=%u, group_id=%d", + translated_pte, original_pte, mmu_level, data->group_id); + kutf_test_fail(context, msg_buf); + return; + } + + returned_pte = mgm_dev->ops.mgm_pte_to_original_pte( + mgm_dev, data->group_id, mmu_level, translated_pte); + dev_dbg(kbdev->dev, "\treturned_pte=%llx\n", returned_pte); + + if (returned_pte != original_pte) { + snprintf( + msg_buf, sizeof(msg_buf), + "Original PTE not returned. returned_pte (0x%llx) != origin al_pte (0x%llx) for mmu_level=%u, group_id=%d", + returned_pte, original_pte, mmu_level, data->group_id); + kutf_test_fail(context, msg_buf); + return; + } + } + } + snprintf(msg_buf, sizeof(msg_buf), "Translation passed for group_id=%d", data->group_id); + kutf_test_pass(context, msg_buf); +} + +/** + * mali_kutf_mgm_integration_create_fixture() - Creates the fixture data + * required for all tests in the mgm integration suite. + * @context: KUTF context. + * + * Return: Fixture data created on success or NULL on failure + */ +static void *mali_kutf_mgm_integration_create_fixture(struct kutf_context *context) +{ + struct kutf_mgm_fixture_data *data; + struct kbase_device *kbdev; + + pr_debug("Finding kbase device\n"); + kbdev = kbase_find_device(MINOR_FOR_FIRST_KBASE_DEV); + if (kbdev == NULL) { + kutf_test_fail(context, "Failed to find kbase device"); + return NULL; + } + pr_debug("Creating fixture\n"); + + data = kutf_mempool_alloc(&context->fixture_pool, sizeof(struct kutf_mgm_fixture_data)); + if (!data) + return NULL; + data->kbdev = kbdev; + data->group_id = context->fixture_index; + + pr_debug("Fixture created\n"); + return data; +} + +/** + * mali_kutf_mgm_integration_remove_fixture() - Destroy fixture data previously + * created by mali_kutf_mgm_integration_create_fixture. + * @context: KUTF context. + */ +static void mali_kutf_mgm_integration_remove_fixture(struct kutf_context *context) +{ + struct kutf_mgm_fixture_data *data = context->fixture; + struct kbase_device *kbdev = data->kbdev; + + kbase_release_device(kbdev); +} + +/** + * mali_kutf_mgm_integration_test_main_init() - Module entry point for this test. + * + * Return: 0 on success, error code on failure. + */ +static int __init mali_kutf_mgm_integration_test_main_init(void) +{ + struct kutf_suite *suite; + + mgm_app = kutf_create_application("mgm"); + + if (mgm_app == NULL) { + pr_warn("Creation of mgm KUTF app failed!\n"); + return -ENOMEM; + } + suite = kutf_create_suite(mgm_app, MGM_INTEGRATION_SUITE_NAME, BASE_MEM_GROUP_COUNT, + mali_kutf_mgm_integration_create_fixture, + mali_kutf_mgm_integration_remove_fixture); + if (suite == NULL) { + pr_warn("Creation of %s suite failed!\n", MGM_INTEGRATION_SUITE_NAME); + kutf_destroy_application(mgm_app); + return -ENOMEM; + } + kutf_add_test(suite, 0x0, MGM_INTEGRATION_PTE_TRANSLATION, + mali_kutf_mgm_pte_translation_test); + return 0; +} + +/** + * mali_kutf_mgm_integration_test_main_exit() - Module exit point for this test. + */ +static void __exit mali_kutf_mgm_integration_test_main_exit(void) +{ + kutf_destroy_application(mgm_app); +} + +module_init(mali_kutf_mgm_integration_test_main_init); +module_exit(mali_kutf_mgm_integration_test_main_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("ARM Ltd."); +MODULE_VERSION("1.0"); diff --git a/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline_io.c b/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline_io.c index d2443bee461b..af8b3d8c8c35 100644 --- a/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline_io.c +++ b/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline_io.c @@ -26,12 +26,12 @@ #include #include +#include /* The timeline stream file operations functions. */ static ssize_t kbasep_timeline_io_read(struct file *filp, char __user *buffer, size_t size, loff_t *f_pos); -static unsigned int kbasep_timeline_io_poll(struct file *filp, - poll_table *wait); +static __poll_t kbasep_timeline_io_poll(struct file *filp, poll_table *wait); static int kbasep_timeline_io_release(struct inode *inode, struct file *filp); static int kbasep_timeline_io_fsync(struct file *filp, loff_t start, loff_t end, int datasync); @@ -292,7 +292,7 @@ static ssize_t kbasep_timeline_io_read(struct file *filp, char __user *buffer, * * Return: POLLIN if data can be read without blocking, otherwise zero */ -static unsigned int kbasep_timeline_io_poll(struct file *filp, poll_table *wait) +static __poll_t kbasep_timeline_io_poll(struct file *filp, poll_table *wait) { struct kbase_tlstream *stream; unsigned int rb_idx; @@ -302,7 +302,7 @@ static unsigned int kbasep_timeline_io_poll(struct file *filp, poll_table *wait) KBASE_DEBUG_ASSERT(wait); if (WARN_ON(!filp->private_data)) - return -EFAULT; + return (__poll_t)-EFAULT; timeline = (struct kbase_timeline *)filp->private_data; diff --git a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c index 6aae4e0ac8b4..3ac78503ce1f 100644 --- a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c +++ b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c @@ -305,11 +305,11 @@ enum tl_msg_id_obj { "@p", \ "atom") \ TRACEPOINT_DESC(KBASE_TL_JD_DONE_NO_LOCK_START, \ - "Within function jd_done_nolock", \ + "Within function kbase_jd_done_nolock", \ "@p", \ "atom") \ TRACEPOINT_DESC(KBASE_TL_JD_DONE_NO_LOCK_END, \ - "Within function jd_done_nolock - end", \ + "Within function kbase_jd_done_nolock - end", \ "@p", \ "atom") \ TRACEPOINT_DESC(KBASE_TL_JD_DONE_START, \ diff --git a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h index 0bcd50abd597..cb1e63ef56f5 100644 --- a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h +++ b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h @@ -1686,7 +1686,7 @@ struct kbase_tlstream; } while (0) /** - * KBASE_TLSTREAM_TL_JD_DONE_NO_LOCK_START - Within function jd_done_nolock + * KBASE_TLSTREAM_TL_JD_DONE_NO_LOCK_START - Within function kbase_jd_done_nolock * * @kbdev: Kbase device * @atom: Atom identifier @@ -1705,7 +1705,7 @@ struct kbase_tlstream; } while (0) /** - * KBASE_TLSTREAM_TL_JD_DONE_NO_LOCK_END - Within function jd_done_nolock - end + * KBASE_TLSTREAM_TL_JD_DONE_NO_LOCK_END - Within function kbase_jd_done_nolock - end * * @kbdev: Kbase device * @atom: Atom identifier diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 09d9ee7fac55..ead215ff6183 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1714,6 +1714,12 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) dp->dpms_mode = DRM_MODE_DPMS_OFF; } +void analogix_dp_disable(struct analogix_dp_device *dp) +{ + analogix_dp_bridge_disable(&dp->bridge); +} +EXPORT_SYMBOL_GPL(analogix_dp_disable); + static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) @@ -1779,13 +1785,8 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, /* Input video interlaces & hsync pol & vsync pol */ video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); - if (dp->plat_data->dev_type == RK3588_EDP) { - video->v_sync_polarity = true; - video->h_sync_polarity = true; - } else { - video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); - video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); - } + video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); + video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); /* Input video dynamic_range & colorimetry */ vic = drm_match_cea_mode(mode); @@ -1997,6 +1998,8 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) video_info->video_bist_enable = of_property_read_bool(dp_node, "analogix,video-bist-enable"); + video_info->force_stream_valid = + of_property_read_bool(dp_node, "analogix,force-stream-valid"); prop = of_find_property(dp_node, "data-lanes", &len); if (!prop) { @@ -2098,6 +2101,7 @@ static void analogix_dp_link_train_restore(struct analogix_dp_device *dp) int analogix_dp_loader_protect(struct analogix_dp_device *dp) { + u8 link_status[DP_LINK_STATUS_SIZE]; int ret; ret = analogix_dp_phy_power_on(dp); @@ -2110,15 +2114,31 @@ int analogix_dp_loader_protect(struct analogix_dp_device *dp) ret = analogix_dp_fast_link_train_detection(dp); if (ret) - return ret; + goto err_disable; if (analogix_dp_detect_sink_psr(dp)) { ret = analogix_dp_enable_sink_psr(dp); if (ret) - return ret; + goto err_disable; + } + + ret = drm_dp_dpcd_read_link_status(&dp->aux, link_status); + if (ret < 0) { + dev_err(dp->dev, "Failed to read link status\n"); + goto err_disable; + } + + if (!drm_dp_channel_eq_ok(link_status, dp->link_train.lane_count)) { + dev_err(dp->dev, "Channel EQ or CR not ok\n"); + ret = -EINVAL; + goto err_disable; } return 0; + +err_disable: + analogix_dp_disable(dp); + return ret; } EXPORT_SYMBOL_GPL(analogix_dp_loader_protect); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 090bc255042b..a843a739b76c 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -142,6 +142,7 @@ struct video_info { u32 lane_map[4]; bool video_bist_enable; + bool force_stream_valid; }; struct link_train { diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 663c56144af8..e756d7cd3d41 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -790,9 +790,11 @@ void analogix_dp_init_video(struct analogix_dp_device *dp) reg = CHA_CRI(4) | CHA_CTRL; analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_2, reg); - reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3); - reg |= VALID_CTRL | F_VALID; - analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg); + if (dp->video_info.force_stream_valid) { + reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3); + reg |= VALID_CTRL | F_VALID; + analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg); + } reg = VID_HRES_TH(2) | VID_VRES_TH(0); analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_8, reg); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-cec.c index 05bcfcaec665..2d2320ed0769 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-cec.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-cec.c @@ -149,7 +149,7 @@ static irqreturn_t dw_hdmi_qp_cec_hardirq(int irq, void *data) len = sizeof(cec->rx_msg.msg); for (i = 0; i < 4; i++) { - val = dw_hdmi_qp_read(cec, CEC_RX_DATA3_0 + i); + val = dw_hdmi_qp_read(cec, CEC_RX_DATA3_0 + i * 4); cec->rx_msg.msg[i * 4] = val & 0xff; cec->rx_msg.msg[i * 4 + 1] = (val >> 8) & 0xff; cec->rx_msg.msg[i * 4 + 2] = (val >> 16) & 0xff; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index cc0090f39e72..927be632b9a4 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -252,6 +252,9 @@ struct dw_hdmi_qp { bool dclk_en; bool frl_switch; bool cec_enable; + bool allm_enable; + bool support_hdmi; + int force_output; struct mutex mutex; /* for state below and previous_mode */ struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */ @@ -1299,6 +1302,12 @@ static void hdmi_config_AVI(struct dw_hdmi_qp *hdmi, hdmi_modb(hdmi, PKTSCHED_AVI_TX_EN, PKTSCHED_AVI_TX_EN, PKTSCHED_PKT_EN); } +#define VSI_PKT_TYPE 0x81 +#define VSI_PKT_VERSION 1 +#define HDMI_FORUM_OUI 0xc45dd8 +#define ALLM_MODE BIT(1) +#define HDMI_FORUM_LEN 9 + static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi_qp *hdmi, const struct drm_connector *connector, const struct drm_display_mode *mode) @@ -1308,24 +1317,47 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi_qp *hdmi, u32 val; ssize_t err; int i, reg; + struct dw_hdmi_link_config *link_cfg = NULL; + void *data = hdmi->plat_data->phy_data; + + if (hdmi->plat_data->get_link_cfg) + link_cfg = hdmi->plat_data->get_link_cfg(data); hdmi_modb(hdmi, 0, PKTSCHED_VSI_TX_EN, PKTSCHED_PKT_EN); - err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, connector, - mode); - if (err < 0) - /* - * Going into that statement does not means vendor infoframe - * fails. It just informed us that vendor infoframe is not - * needed for the selected mode. Only 4k or stereoscopic 3D - * mode requires vendor infoframe. So just simply return. - */ - return; + for (i = 0; i <= 7; i++) + hdmi_writel(hdmi, 0, PKT_VSI_CONTENTS0 + i * 4); - err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - dev_err(hdmi->dev, "Failed to pack vendor infoframe: %zd\n", - err); - return; + if (hdmi->allm_enable && (link_cfg->add_func & SUPPORT_HDMI_ALLM)) { + buffer[0] = VSI_PKT_TYPE; + buffer[1] = VSI_PKT_VERSION; + buffer[2] = 5; + buffer[4] = HDMI_FORUM_OUI & 0xff; + buffer[5] = (HDMI_FORUM_OUI >> 8) & 0xff; + buffer[6] = (HDMI_FORUM_OUI >> 16) & 0xff; + buffer[7] = VSI_PKT_VERSION; + buffer[8] = ALLM_MODE; + + hdmi_infoframe_set_checksum(buffer, HDMI_FORUM_LEN); + + err = 9; + } else { + err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, connector, + mode); + if (err < 0) + /* + * Going into that statement does not means vendor infoframe + * fails. It just informed us that vendor infoframe is not + * needed for the selected mode. Only 4k or stereoscopic 3D + * mode requires vendor infoframe. So just simply return. + */ + return; + + err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (err < 0) { + dev_err(hdmi->dev, "Failed to pack vendor infoframe: %zd\n", + err); + return; + } } /* vsi header */ @@ -1568,6 +1600,9 @@ static int hdmi_start_flt(struct dw_hdmi_qp *hdmi, u8 rate) hdmi_modb(hdmi, AVP_DATAPATH_VIDEO_SWDISABLE, AVP_DATAPATH_VIDEO_SWDISABLE, GLOBAL_SWDISABLE); + /* reset avp data path */ + hdmi_writel(hdmi, BIT(6), GLOBAL_SWRESET_REQUEST); + /* FLT_READY & FFE_LEVELS read */ for (i = 0; i < 20; i++) { drm_scdc_readb(hdmi->ddc, SCDC_STATUS_FLAGS_0, &val); @@ -1947,6 +1982,25 @@ dw_hdmi_update_hdr_property(struct drm_connector *connector) return ret; } +static bool dw_hdmi_qp_check_output_type_changed(struct dw_hdmi_qp *hdmi) +{ + bool sink_hdmi; + + sink_hdmi = hdmi->sink_is_hdmi; + + if (hdmi->force_output == 1) + hdmi->sink_is_hdmi = true; + else if (hdmi->force_output == 2) + hdmi->sink_is_hdmi = false; + else + hdmi->sink_is_hdmi = hdmi->support_hdmi; + + if (sink_hdmi != hdmi->sink_is_hdmi) + return true; + + return false; +} + static int dw_hdmi_connector_get_modes(struct drm_connector *connector) { struct dw_hdmi_qp *hdmi = @@ -1968,7 +2022,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", edid->width_cm, edid->height_cm); - hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); + hdmi->support_hdmi = drm_detect_hdmi_monitor(edid); hdmi->sink_has_audio = drm_detect_monitor_audio(edid); drm_connector_update_edid_property(connector, edid); if (hdmi->cec_notifier) @@ -2003,7 +2057,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) } kfree(edid); } else { - hdmi->sink_is_hdmi = true; + hdmi->support_hdmi = true; hdmi->sink_has_audio = true; if (hdmi->plat_data->split_mode) { @@ -2040,10 +2094,42 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) dev_info(hdmi->dev, "failed to get edid\n"); } + dw_hdmi_qp_check_output_type_changed(hdmi); return ret; } +void dw_hdmi_qp_set_allm_enable(struct dw_hdmi_qp *hdmi, bool enable) +{ + struct dw_hdmi_link_config *link_cfg = NULL; + void *data; + + if (!hdmi || !hdmi->curr_conn) + return; + + data = hdmi->plat_data->phy_data; + + if (hdmi->plat_data->get_link_cfg) + link_cfg = hdmi->plat_data->get_link_cfg(data); + + if (!link_cfg) + return; + + if (enable == hdmi->allm_enable) + return; + + hdmi->allm_enable = enable; + + if (enable && !(link_cfg->add_func & SUPPORT_HDMI_ALLM)) { + hdmi->allm_enable = false; + dev_err(hdmi->dev, "sink don't support allm, allm won't be enabled\n"); + return; + } + + hdmi_config_vendor_specific_infoframe(hdmi, hdmi->curr_conn, &hdmi->previous_mode); +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_allm_enable); + static int dw_hdmi_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, @@ -2088,6 +2174,7 @@ dw_hdmi_connector_set_property(struct drm_connector *connector, static void dw_hdmi_attach_properties(struct dw_hdmi_qp *hdmi) { + u32 val; u64 color = MEDIA_BUS_FMT_YUV8_1X24; const struct dw_hdmi_property_ops *ops = hdmi->plat_data->property_ops; @@ -2095,14 +2182,21 @@ static void dw_hdmi_attach_properties(struct dw_hdmi_qp *hdmi) enum drm_connector_status connect_status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); - if (hdmi->plat_data->get_grf_color_fmt && - (connect_status == connector_status_connected) && - hdmi->initialized) - color = hdmi->plat_data->get_grf_color_fmt(data); + if ((connect_status == connector_status_connected) && + hdmi->initialized) { + if (hdmi->plat_data->get_grf_color_fmt) + color = hdmi->plat_data->get_grf_color_fmt(data); + + val = (hdmi_readl(hdmi, PKT_VSI_CONTENTS1) >> 8) & 0xffffff; + if (val == HDMI_FORUM_OUI) + hdmi->allm_enable = true; + else + hdmi->allm_enable = false; + } if (ops && ops->attach_properties) return ops->attach_properties(&hdmi->connector, color, 0, - hdmi->plat_data->phy_data); + hdmi->plat_data->phy_data, hdmi->allm_enable); } static void dw_hdmi_destroy_properties(struct dw_hdmi_qp *hdmi) @@ -2188,6 +2282,7 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, * drm_display_mode and set phy status to enabled. */ if (!vmode->mpixelclock) { + hdmi->curr_conn = connector; if (hdmi->plat_data->get_enc_in_encoding) hdmi->hdmi_data.enc_in_encoding = hdmi->plat_data->get_enc_in_encoding(data); @@ -2245,6 +2340,35 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, return 0; } +void dw_hdmi_qp_set_output_type(struct dw_hdmi_qp *hdmi, u64 val) +{ + hdmi->force_output = val; + + if (!dw_hdmi_qp_check_output_type_changed(hdmi)) + return; + + if (hdmi->disabled) + return; + + if (!hdmi->sink_is_hdmi) + hdmi_modb(hdmi, OPMODE_DVI, OPMODE_DVI, LINK_CONFIG0); + else + hdmi_modb(hdmi, 0, OPMODE_DVI, LINK_CONFIG0); +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_output_type); + +bool dw_hdmi_qp_get_output_whether_hdmi(struct dw_hdmi_qp *hdmi) +{ + return hdmi->sink_is_hdmi; +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_get_output_whether_hdmi); + +int dw_hdmi_qp_get_output_type_cap(struct dw_hdmi_qp *hdmi) +{ + return hdmi->support_hdmi; +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_get_output_type_cap); + static void dw_hdmi_connector_force(struct drm_connector *connector) { struct dw_hdmi_qp *hdmi = @@ -2265,14 +2389,8 @@ static void dw_hdmi_connector_force(struct drm_connector *connector) mutex_unlock(&hdmi->mutex); } -static int dw_hdmi_qp_fill_modes(struct drm_connector *connector, u32 max_x, - u32 max_y) -{ - return drm_helper_probe_single_connector_modes(connector, 9000, 9000); -} - static const struct drm_connector_funcs dw_hdmi_connector_funcs = { - .fill_modes = dw_hdmi_qp_fill_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .detect = dw_hdmi_connector_detect, .destroy = drm_connector_cleanup, .force = dw_hdmi_connector_force, @@ -2811,7 +2929,7 @@ static int dw_hdmi_status_show(struct seq_file *s, void *v) seq_printf(s, "TMDS Mode Pixel Clk: %luHz\t\tTMDS Clk: %uHz\n", hdmi->hdmi_data.video_mode.mpixelclock, val); } - + seq_printf(s, "ALLM: %d\n", hdmi->allm_enable); seq_puts(s, "Color Format: "); if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) seq_puts(s, "RGB"); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 4de8939e6ec0..a69b1295dae8 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -3240,7 +3240,7 @@ static void dw_hdmi_attach_properties(struct dw_hdmi *hdmi) if (ops && ops->attach_properties) return ops->attach_properties(&hdmi->connector, color, hdmi->version, - hdmi->plat_data->phy_data); + hdmi->plat_data->phy_data, 0); } static void dw_hdmi_destroy_properties(struct dw_hdmi *hdmi) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 325ddd1fb21a..3d489d9609f2 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -232,25 +232,35 @@ static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, return 0; } -static void rockchip_dp_loader_protect(struct drm_encoder *encoder, bool on) +static int rockchip_dp_loader_protect(struct drm_encoder *encoder, bool on) { struct rockchip_dp_device *dp = to_dp(encoder); struct analogix_dp_plat_data *plat_data = &dp->plat_data; + struct rockchip_dp_device *secondary = NULL; + int ret; if (plat_data->right) { - struct rockchip_dp_device *secondary = - rockchip_dp_find_by_id(dp->dev->driver, !dp->id); + secondary = rockchip_dp_find_by_id(dp->dev->driver, !dp->id); - rockchip_dp_loader_protect(&secondary->encoder, on); + ret = rockchip_dp_loader_protect(&secondary->encoder, on); + if (ret) + return ret; } if (!on) - return; + return 0; if (plat_data->panel) panel_simple_loader_protect(plat_data->panel); - analogix_dp_loader_protect(dp->adp); + ret = analogix_dp_loader_protect(dp->adp); + if (ret) { + if (secondary) + analogix_dp_disable(secondary->adp); + return ret; + } + + return 0; } static bool rockchip_dp_skip_connector(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index 37fb38b908cb..b0f2c05f4c83 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -2106,13 +2106,15 @@ static void _dw_dp_loader_protect(struct dw_dp *dp, bool on) } } -static void dw_dp_loader_protect(struct drm_encoder *encoder, bool on) +static int dw_dp_loader_protect(struct drm_encoder *encoder, bool on) { struct dw_dp *dp = encoder_to_dp(encoder); _dw_dp_loader_protect(dp, on); if (dp->right) _dw_dp_loader_protect(dp->right, on); + + return 0; } static int dw_dp_connector_init(struct dw_dp *dp) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index a052e6228f84..6922f56d1fad 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -830,7 +830,7 @@ static void dw_mipi_dsi_rockchip_loader_protect(struct dw_mipi_dsi_rockchip *dsi dw_mipi_dsi_rockchip_loader_protect(dsi->slave, on); } -static void dw_mipi_dsi_rockchip_encoder_loader_protect(struct drm_encoder *encoder, +static int dw_mipi_dsi_rockchip_encoder_loader_protect(struct drm_encoder *encoder, bool on) { struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder); @@ -839,6 +839,8 @@ static void dw_mipi_dsi_rockchip_encoder_loader_protect(struct drm_encoder *enco panel_simple_loader_protect(dsi->panel); dw_mipi_dsi_rockchip_loader_protect(dsi, on); + + return 0; } static const struct drm_encoder_helper_funcs diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index ff36a8aeb907..f55a3a5c5c7c 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -962,7 +962,7 @@ static void dw_mipi_dsi2_loader_protect(struct dw_mipi_dsi2 *dsi2, bool on) dw_mipi_dsi2_loader_protect(dsi2->slave, on); } -static void dw_mipi_dsi2_encoder_loader_protect(struct drm_encoder *encoder, +static int dw_mipi_dsi2_encoder_loader_protect(struct drm_encoder *encoder, bool on) { struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder); @@ -971,6 +971,8 @@ static void dw_mipi_dsi2_encoder_loader_protect(struct drm_encoder *encoder, panel_simple_loader_protect(dsi2->panel); dw_mipi_dsi2_loader_protect(dsi2, on); + + return 0; } static const struct drm_encoder_helper_funcs diff --git a/drivers/gpu/drm/rockchip/dw_hdcp2.c b/drivers/gpu/drm/rockchip/dw_hdcp2.c index 44bc4293d0fc..f8362ddea171 100644 --- a/drivers/gpu/drm/rockchip/dw_hdcp2.c +++ b/drivers/gpu/drm/rockchip/dw_hdcp2.c @@ -80,6 +80,46 @@ enum { HDCP_PORT2, }; +static void dw_hdcp_free_hl_dev_slot(struct hl_device *hl_dev); + +static void dw_hdcp_free_hl(struct dw_hdcp *hdcp) +{ + dw_hdcp_free_hl_dev_slot(&hdcp->hl_dev); + hdcp->hl_dev.code_loaded = false; +} + +static void dw_hdcp_reset(struct dw_hdcp *hdcp) +{ + int ret; + + reset_control_assert(hdcp->rsts_bulk); + udelay(20); + reset_control_deassert(hdcp->rsts_bulk); + + ret = sip_hdcpkey_init(hdcp->id); + if (ret) + dev_err(hdcp->dev, "load hdcp key failed\n"); +} + +static int dw_hdcp_set_reset(struct dw_hdcp *hdcp, void __user *arg) +{ + u32 reset; + + if (!arg) + return -EFAULT; + + if (copy_from_user(&reset, arg, sizeof(reset))) + return -EFAULT; + + if (reset) { + dev_info(hdcp->dev, "hdcp reset\n"); + dw_hdcp_free_hl(hdcp); + dw_hdcp_reset(hdcp); + } + + return 0; +} + static int dw_hdcp_get_status(struct dw_hdcp *hdcp, void __user *arg) { struct hl_drv_ioc_status status; @@ -410,6 +450,8 @@ static long dw_hdcp_hld_ioctl(struct file *f, unsigned int cmd, unsigned long ar case RK_DRV_IOC_GET_STATUS: return dw_hdcp_get_status(hdcp, data); + case RK_DRV_IOC_RESET: + return dw_hdcp_set_reset(hdcp, data); default: return -EINVAL; } @@ -551,8 +593,7 @@ static int dw_hdcp_runtime_suspend(struct device *dev) hdcp->is_suspend = true; clk_bulk_disable_unprepare(hdcp->num_clks, hdcp->clks); - dw_hdcp_free_hl_dev_slot(&hdcp->hl_dev); - hdcp->hl_dev.code_loaded = false; + dw_hdcp_free_hl(hdcp); return 0; } @@ -566,13 +607,7 @@ static int dw_hdcp_runtime_resume(struct device *dev) if (ret) dev_err(dev, "prepare enable clk bulk failed\n"); - reset_control_assert(hdcp->rsts_bulk); - udelay(10); - reset_control_deassert(hdcp->rsts_bulk); - - ret = sip_hdcpkey_init(hdcp->id); - if (ret) - dev_err(dev, "load hdcp key failed\n"); + dw_hdcp_reset(hdcp); hdcp->is_suspend = false; return 0; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 1360dc38f57b..69801ca30474 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -196,6 +196,8 @@ struct rockchip_hdmi { struct drm_property *output_hdmi_dvi; struct drm_property *output_type_capacity; struct drm_property *user_split_mode_prop; + struct drm_property *allm_capacity; + struct drm_property *allm_enable; struct drm_property_blob *hdr_panel_blob_ptr; struct drm_property_blob *next_hdr_data_ptr; @@ -204,11 +206,13 @@ struct rockchip_hdmi { unsigned int colorimetry; unsigned int hdmi_quant_range; unsigned int phy_bus_width; + unsigned int enable_allm; enum rk_if_color_format hdmi_output; struct rockchip_drm_sub_dev sub_dev; u8 max_frl_rate_per_lane; u8 max_lanes; + u8 add_func; struct rockchip_drm_dsc_cap dsc_cap; struct next_hdr_sink_data next_hdr_data; struct dw_hdmi_link_config link_cfg; @@ -800,6 +804,7 @@ static void hdmi_select_link_config(struct rockchip_hdmi *hdmi, hdmi->link_cfg.dsc_mode = false; hdmi->link_cfg.frl_lanes = max_lanes; hdmi->link_cfg.rate_per_lane = max_rate_per_lane; + hdmi->link_cfg.add_func = hdmi->add_func; if (!max_frl_rate || (tmdsclk < HDMI20_MAX_RATE && mode.clock < HDMI20_MAX_RATE)) { dev_info(hdmi->dev, "use tmds mode\n"); @@ -1568,7 +1573,7 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) ret ? "LIT" : "BIG"); } -static void dw_hdmi_rockchip_encoder_loader_protect(struct drm_encoder *encoder, +static int dw_hdmi_rockchip_encoder_loader_protect(struct drm_encoder *encoder, bool on) { struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); @@ -1579,7 +1584,7 @@ static void dw_hdmi_rockchip_encoder_loader_protect(struct drm_encoder *encoder, ret = clk_prepare_enable(hdmi->link_clk); if (ret < 0) { DRM_DEV_ERROR(hdmi->dev, "failed to enable link_clk %d\n", ret); - return; + return ret; } } @@ -1588,6 +1593,8 @@ static void dw_hdmi_rockchip_encoder_loader_protect(struct drm_encoder *encoder, clk_disable_unprepare(hdmi->link_clk); hdmi->phy->power_count--; } + + return 0; } static void rk3588_set_link_mode(struct rockchip_hdmi *hdmi) @@ -1759,6 +1766,8 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state, if (!hdmi->is_hdmi_qp) sink_is_hdmi = dw_hdmi_get_output_whether_hdmi(hdmi->hdmi); + else + sink_is_hdmi = dw_hdmi_qp_get_output_whether_hdmi(hdmi->hdmi_qp); *color_format = RK_IF_FORMAT_RGB; @@ -2167,9 +2176,14 @@ dw_hdmi_rockchip_get_edid_dsc_info(void *data, struct edid *edid) if (!edid) return -EINVAL; + memset(&hdmi->dsc_cap, 0, sizeof(hdmi->dsc_cap)); + hdmi->max_frl_rate_per_lane = 0; + hdmi->max_lanes = 0; + hdmi->add_func = 0; + return rockchip_drm_parse_cea_ext(&hdmi->dsc_cap, &hdmi->max_frl_rate_per_lane, - &hdmi->max_lanes, edid); + &hdmi->max_lanes, &hdmi->add_func, edid); } static int @@ -2296,10 +2310,15 @@ static const struct drm_prop_enum_list output_type_cap_list[] = { { 1, "HDMI" }, }; +static const struct drm_prop_enum_list allm_enable_list[] = { + { 0, "disable" }, + { 1, "enable" }, +}; + static void dw_hdmi_rockchip_attach_properties(struct drm_connector *connector, unsigned int color, int version, - void *data) + void *data, bool allm_en) { struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; struct drm_property *prop; @@ -2414,25 +2433,42 @@ dw_hdmi_rockchip_attach_properties(struct drm_connector *connector, hdmi->user_split_mode ? 1 : 0); } + prop = drm_property_create_bool(connector->dev, 0, "allm_capacity"); + if (prop) { + hdmi->allm_capacity = prop; + drm_object_attach_property(&connector->base, prop, + !!(hdmi->add_func & SUPPORT_HDMI_ALLM)); + } + + prop = drm_property_create_enum(connector->dev, 0, + "allm_enable", + allm_enable_list, + ARRAY_SIZE(allm_enable_list)); + if (prop) { + hdmi->allm_enable = prop; + drm_object_attach_property(&connector->base, prop, 0); + } + hdmi->enable_allm = allm_en; + + prop = drm_property_create_enum(connector->dev, 0, + "output_hdmi_dvi", + output_hdmi_dvi_enum_list, + ARRAY_SIZE(output_hdmi_dvi_enum_list)); + if (prop) { + hdmi->output_hdmi_dvi = prop; + drm_object_attach_property(&connector->base, prop, 0); + } + + prop = drm_property_create_enum(connector->dev, 0, + "output_type_capacity", + output_type_cap_list, + ARRAY_SIZE(output_type_cap_list)); + if (prop) { + hdmi->output_type_capacity = prop; + drm_object_attach_property(&connector->base, prop, 0); + } + if (!hdmi->is_hdmi_qp) { - prop = drm_property_create_enum(connector->dev, 0, - "output_hdmi_dvi", - output_hdmi_dvi_enum_list, - ARRAY_SIZE(output_hdmi_dvi_enum_list)); - if (prop) { - hdmi->output_hdmi_dvi = prop; - drm_object_attach_property(&connector->base, prop, 0); - } - - prop = drm_property_create_enum(connector->dev, 0, - "output_type_capacity", - output_type_cap_list, - ARRAY_SIZE(output_type_cap_list)); - if (prop) { - hdmi->output_type_capacity = prop; - drm_object_attach_property(&connector->base, prop, 0); - } - prop = drm_property_create_enum(connector->dev, 0, "hdmi_quant_range", quant_range_enum_list, @@ -2518,6 +2554,17 @@ dw_hdmi_rockchip_destroy_properties(struct drm_connector *connector, hdmi->user_split_mode_prop); hdmi->user_split_mode_prop = NULL; } + + if (hdmi->allm_capacity) { + drm_property_destroy(connector->dev, + hdmi->allm_capacity); + hdmi->allm_capacity = NULL; + } + + if (hdmi->allm_enable) { + drm_property_destroy(connector->dev, hdmi->allm_enable); + hdmi->allm_enable = NULL; + } } static int @@ -2555,10 +2602,15 @@ dw_hdmi_rockchip_set_property(struct drm_connector *connector, } else if (property == config->hdr_output_metadata_property) { return 0; } else if (property == hdmi->output_hdmi_dvi) { - if (hdmi->force_output != val) - hdmi->color_changed++; - hdmi->force_output = val; - dw_hdmi_set_output_type(hdmi->hdmi, val); + if (!hdmi->is_hdmi_qp) { + if (hdmi->force_output != val) + hdmi->color_changed++; + hdmi->force_output = val; + dw_hdmi_set_output_type(hdmi->hdmi, val); + } else { + hdmi->force_output = val; + dw_hdmi_qp_set_output_type(hdmi->hdmi_qp, val); + } return 0; } else if (property == hdmi->colordepth_capacity) { return 0; @@ -2566,6 +2618,15 @@ dw_hdmi_rockchip_set_property(struct drm_connector *connector, return 0; } else if (property == hdmi->output_type_capacity) { return 0; + } else if (property == hdmi->allm_capacity) { + return 0; + } else if (property == hdmi->allm_enable) { + u64 allm_enable = hdmi->enable_allm; + + hdmi->enable_allm = val; + if (allm_enable != hdmi->enable_allm) + dw_hdmi_qp_set_allm_enable(hdmi->hdmi_qp, hdmi->enable_allm); + return 0; } DRM_ERROR("Unknown property [PROP:%d:%s]\n", @@ -2630,11 +2691,20 @@ dw_hdmi_rockchip_get_property(struct drm_connector *connector, *val = hdmi->force_output; return 0; } else if (property == hdmi->output_type_capacity) { - *val = dw_hdmi_get_output_type_cap(hdmi->hdmi); + if (!hdmi->is_hdmi_qp) + *val = dw_hdmi_get_output_type_cap(hdmi->hdmi); + else + *val = dw_hdmi_qp_get_output_type_cap(hdmi->hdmi_qp); return 0; } else if (property == hdmi->user_split_mode_prop) { *val = hdmi->user_split_mode; return 0; + } else if (property == hdmi->allm_capacity) { + *val = !!(hdmi->add_func & SUPPORT_HDMI_ALLM); + return 0; + } else if (property == hdmi->allm_enable) { + *val = hdmi->enable_allm; + return 0; } DRM_ERROR("Unknown property [PROP:%d:%s]\n", @@ -3399,6 +3469,8 @@ static void dw_hdmi_rockchip_shutdown(struct platform_device *pdev) return; if (hdmi->is_hdmi_qp) { + if (hdmi->hpd_irq) + disable_irq(hdmi->hpd_irq); cancel_delayed_work(&hdmi->work); flush_workqueue(hdmi->workqueue); dw_hdmi_qp_suspend(hdmi->dev, hdmi->hdmi_qp); @@ -3420,10 +3492,13 @@ static int dw_hdmi_rockchip_suspend(struct device *dev) { struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); - if (hdmi->is_hdmi_qp) + if (hdmi->is_hdmi_qp) { + if (hdmi->hpd_irq) + disable_irq(hdmi->hpd_irq); dw_hdmi_qp_suspend(dev, hdmi->hdmi_qp); - else + } else { dw_hdmi_suspend(hdmi->hdmi); + } pm_runtime_put_sync(dev); return 0; @@ -3466,6 +3541,8 @@ static int dw_hdmi_rockchip_resume(struct device *dev) } dw_hdmi_qp_resume(dev, hdmi->hdmi_qp); + if (hdmi->hpd_irq) + enable_irq(hdmi->hpd_irq); drm_helper_hpd_irq_event(hdmi->drm_dev); } else { dw_hdmi_resume(hdmi->hdmi); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c index 6679689f3316..9989820b5fc6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c @@ -172,7 +172,7 @@ void rockchip_drm_direct_show_free_buffer(struct drm_device *drm, drm_gem_object_put(obj); } -struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, char *name) +struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, const char *name) { struct drm_plane *plane; @@ -190,15 +190,23 @@ struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, cha return plane; } -struct drm_crtc *rockchip_drm_direct_show_get_crtc(struct drm_device *drm) +struct drm_crtc *rockchip_drm_direct_show_get_crtc(struct drm_device *drm, const char *name) { struct drm_crtc *crtc = NULL; bool crtc_active = false; drm_for_each_crtc(crtc, drm) { - if (crtc->state && crtc->state->active) { - crtc_active = true; - break; + if (name == NULL) { + if (crtc->state && crtc->state->active) { + crtc_active = true; + break; + } + } else { + if (crtc->state && crtc->state->active && + !strncmp(crtc->name, name, DRM_PROP_NAME_LEN)) { + crtc_active = true; + break; + } } } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h index 14a542fd63e2..939f0d451057 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h @@ -56,8 +56,8 @@ int rockchip_drm_direct_show_alloc_buffer(struct drm_device *drm, struct rockchip_drm_direct_show_buffer *buffer); void rockchip_drm_direct_show_free_buffer(struct drm_device *drm, struct rockchip_drm_direct_show_buffer *buffer); -struct drm_crtc *rockchip_drm_direct_show_get_crtc(struct drm_device *drm); -struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, char *name); +struct drm_crtc *rockchip_drm_direct_show_get_crtc(struct drm_device *drm, const char *name); +struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, const char *name); int rockchip_drm_direct_show_commit(struct drm_device *drm, struct rockchip_drm_direct_show_commit_info *commit_info); int rockchip_drm_direct_show_disable_plane(struct drm_device *drm, struct drm_plane *plane); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 286a9db986c7..185f0387da81 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -620,7 +620,7 @@ void get_max_frl_rate(int max_frl_rate, u8 *max_lanes, u8 *max_rate_per_lane) static void parse_edid_forum_vsdb(struct rockchip_drm_dsc_cap *dsc_cap, - u8 *max_frl_rate_per_lane, u8 *max_lanes, + u8 *max_frl_rate_per_lane, u8 *max_lanes, u8 *add_func, const u8 *hf_vsdb) { u8 max_frl_rate; @@ -635,6 +635,8 @@ void parse_edid_forum_vsdb(struct rockchip_drm_dsc_cap *dsc_cap, get_max_frl_rate(max_frl_rate, max_lanes, max_frl_rate_per_lane); + *add_func = hf_vsdb[8]; + if (cea_db_payload_len(hf_vsdb) < 13) return; @@ -844,13 +846,13 @@ void parse_next_hdr_block(struct next_hdr_sink_data *sink_data, } int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, - u8 *max_frl_rate_per_lane, u8 *max_lanes, + u8 *max_frl_rate_per_lane, u8 *max_lanes, u8 *add_func, const struct edid *edid) { const u8 *edid_ext; int i, start, end; - if (!dsc_cap || !max_frl_rate_per_lane || !max_lanes || !edid) + if (!dsc_cap || !max_frl_rate_per_lane || !max_lanes || !edid || !add_func) return -EINVAL; edid_ext = find_cea_extension(edid); @@ -865,7 +867,7 @@ int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, if (cea_db_is_hdmi_forum_vsdb(db)) parse_edid_forum_vsdb(dsc_cap, max_frl_rate_per_lane, - max_lanes, db); + max_lanes, add_func, db); } return 0; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index b19fcf3363fc..434d3c93271b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -90,7 +90,7 @@ struct rockchip_drm_sub_dev { struct list_head list; struct drm_connector *connector; struct device_node *of_node; - void (*loader_protect)(struct drm_encoder *encoder, bool on); + int (*loader_protect)(struct drm_encoder *encoder, bool on); void (*oob_hotplug_event)(struct drm_connector *connector); void (*update_vfp_for_vrr)(struct drm_connector *connector, struct drm_display_mode *mode, int vfp); @@ -486,7 +486,7 @@ uint32_t rockchip_drm_get_bpp(const struct drm_format_info *info); int rockchip_drm_get_yuv422_format(struct drm_connector *connector, struct edid *edid); int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, - u8 *max_frl_rate_per_lane, u8 *max_lanes, + u8 *max_frl_rate_per_lane, u8 *max_lanes, u8 *add_func, const struct edid *edid); int rockchip_drm_parse_next_hdr(struct next_hdr_sink_data *sink_data, const struct edid *edid); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index e4b4c349a94f..e442befd850c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -26,7 +26,7 @@ static bool is_rockchip_logo_fb(struct drm_framebuffer *fb) return fb->flags & ROCKCHIP_DRM_MODE_LOGO_FB ? true : false; } -static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) +static void __rockchip_drm_fb_destroy(struct drm_framebuffer *fb) { int i = 0; @@ -49,6 +49,27 @@ static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) } } +static void rockchip_drm_fb_destroy_work(struct work_struct *work) +{ + struct rockchip_drm_logo_fb *fb; + + fb = container_of(to_delayed_work(work), struct rockchip_drm_logo_fb, destroy_work); + + __rockchip_drm_fb_destroy(&fb->fb); +} + +static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) +{ + + if (is_rockchip_logo_fb(fb)) { + struct rockchip_drm_logo_fb *rockchip_logo_fb = to_rockchip_logo_fb(fb); + + schedule_delayed_work(&rockchip_logo_fb->destroy_work, HZ); + } else { + __rockchip_drm_fb_destroy(fb); + } +} + static int rockchip_drm_gem_fb_create_handle(struct drm_framebuffer *fb, struct drm_file *file, unsigned int *handle) @@ -123,7 +144,7 @@ rockchip_drm_logo_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 rockchip_logo_fb->rk_obj.dma_addr = logo->dma_addr; rockchip_logo_fb->rk_obj.kvaddr = logo->kvaddr; logo->count++; - + INIT_DELAYED_WORK(&rockchip_logo_fb->destroy_work, rockchip_drm_fb_destroy_work); return &rockchip_logo_fb->fb; } @@ -198,12 +219,20 @@ rockchip_fb_create(struct drm_device *dev, struct drm_file *file, { struct drm_afbc_framebuffer *afbc_fb; const struct drm_format_info *info; - int ret; + int ret, i; info = drm_get_format_info(dev, mode_cmd); if (!info) return ERR_PTR(-ENOMEM); + for (i = 0; i < info->num_planes; ++i) { + if (mode_cmd->pitches[i] % 4) { + DRM_DEV_ERROR_RATELIMITED(dev->dev, + "fb pitch[%d] must be 4 byte aligned: %d\n", i, mode_cmd->pitches[i]); + return ERR_PTR(-EINVAL); + } + } + afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL); if (!afbc_fb) return ERR_PTR(-ENOMEM); @@ -216,8 +245,6 @@ rockchip_fb_create(struct drm_device *dev, struct drm_file *file, } if (drm_is_afbc(mode_cmd->modifier[0])) { - int i; - ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb); if (ret) { struct drm_gem_object **obj = afbc_fb->base.obj; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h index e5577c2bb7c0..4442719270ab 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h @@ -31,6 +31,10 @@ struct rockchip_drm_logo_fb { struct drm_framebuffer fb; struct rockchip_logo *logo; struct rockchip_gem_object rk_obj; + /* + * Used for delayed logo fb release + */ + struct delayed_work destroy_work; }; #endif /* _ROCKCHIP_DRM_FB_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_logo.c b/drivers/gpu/drm/rockchip/rockchip_drm_logo.c index aaccb9e59928..d0fcbb5c47a4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_logo.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_logo.c @@ -657,8 +657,16 @@ static int setup_initial_state(struct drm_device *drm_dev, else conn_state->best_encoder = rockchip_drm_connector_get_single_encoder(connector); - if (set->sub_dev->loader_protect) - set->sub_dev->loader_protect(conn_state->best_encoder, true); + if (set->sub_dev->loader_protect) { + ret = set->sub_dev->loader_protect(conn_state->best_encoder, true); + if (ret) { + dev_err(drm_dev->dev, + "connector[%s] loader protect failed\n", + connector->name); + return ret; + } + } + num_modes = rockchip_drm_fill_connector_modes(connector, 7680, 7680, set->force_output); if (!num_modes) { dev_err(drm_dev->dev, "connector[%s] can't found any modes\n", @@ -869,6 +877,18 @@ static int update_state(struct drm_device *drm_dev, return ret; } +static void rockchip_drm_copy_mode_from_mode_set(struct drm_display_mode *mode, + struct rockchip_drm_mode_set *set) +{ + mode->clock = set->clock; + mode->hdisplay = set->hdisplay; + mode->vdisplay = set->vdisplay; + mode->crtc_hsync_end = set->crtc_hsync_end; + mode->crtc_vsync_end = set->crtc_vsync_end; + mode->flags = set->flags & DRM_MODE_FLAG_ALL; + mode->picture_aspect_ratio = set->picture_aspect_ratio; +} + void rockchip_drm_show_logo(struct drm_device *drm_dev) { struct drm_atomic_state *state, *old_state; @@ -942,11 +962,22 @@ void rockchip_drm_show_logo(struct drm_device *drm_dev) if (!find_used_crtc) { struct drm_crtc *crtc = unset->crtc; + struct drm_crtc_state *crtc_state; int pipe = drm_crtc_index(crtc); struct rockchip_drm_private *priv = drm_dev->dev_private; + /* + * The display timing information of mode_set is parsed from dts, which + * written in uboot. If the mode_set is added into mode_unset_list, it + * should be converted to crtc_state->adjusted_mode, in order to check + * splice_mode flag in loader_protect(). + */ if (unset->hdisplay && unset->vdisplay) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (crtc_state) + rockchip_drm_copy_mode_from_mode_set(&crtc_state->adjusted_mode, + unset); if (priv->crtc_funcs[pipe] && priv->crtc_funcs[pipe]->loader_protect) priv->crtc_funcs[pipe]->loader_protect(crtc, true); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_self_test.c b/drivers/gpu/drm/rockchip/rockchip_drm_self_test.c index b26bc2a7e466..7c764fca154d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_self_test.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_self_test.c @@ -145,7 +145,7 @@ static void rockchip_drm_self_test_commit(struct work_struct *work) rockchip_drm_draw_color_bar(self_test->drm_buffer[1]); /* get crtc and plane */ - self_test->crtc = rockchip_drm_direct_show_get_crtc(self_test->dev); + self_test->crtc = rockchip_drm_direct_show_get_crtc(self_test->dev, NULL); if (self_test->crtc == NULL) { pr_info("error: failed to get crtc\n"); goto free_buffer; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 9dbd88daed2a..fcfce8bf55f9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -118,6 +118,9 @@ #define VOP_WIN_GET(vop2, win, name) \ vop2_read_reg(vop2, win->offset, &VOP_WIN_NAME(win, name)) +#define VOP_WIN_GET_REG_BAK(vop2, win, name) \ + vop2_read_reg_bak(vop2, win->offset, &VOP_WIN_NAME(win, name)) + #define VOP_WIN_NAME(win, name) \ (vop2_get_win_regs(win, &win->regs->name)->name) @@ -893,6 +896,12 @@ static inline uint32_t vop2_read_reg(struct vop2 *vop2, uint32_t base, return (vop2_readl(vop2, base + reg->offset) >> reg->shift) & reg->mask; } +static inline uint32_t vop2_read_reg_bak(struct vop2 *vop2, uint32_t base, + const struct vop_reg *reg) +{ + return (vop2->regsbak[(base + reg->offset) >> 2] >> reg->shift) & reg->mask; +} + static inline uint32_t vop2_read_grf_reg(struct regmap *regmap, const struct vop_reg *reg) { return (vop2_grf_readl(regmap, reg) >> reg->shift) & reg->mask; @@ -1665,7 +1674,7 @@ static void vop2_win_disable(struct vop2_win *win, bool skip_splice_win) win->splice_win = NULL; } - if (VOP_WIN_GET(vop2, win, enable)) { + if (VOP_WIN_GET(vop2, win, enable) || VOP_WIN_GET_REG_BAK(vop2, win, enable)) { VOP_WIN_SET(vop2, win, enable, 0); if (win->feature & WIN_FEATURE_CLUSTER_MAIN) { struct vop2_win *sub_win; @@ -4344,6 +4353,8 @@ static void vop2_calc_drm_rect_for_splice(struct vop2_plane_state *vpstate, int dst_w = drm_rect_width(dst); int src_w = drm_rect_width(src) >> 16; int left_src_w, left_dst_w, right_dst_w; + struct drm_plane_state *pstate = &vpstate->base; + struct drm_framebuffer *fb = pstate->fb; left_dst_w = min_t(u16, half_hdisplay, dst->x2) - dst->x1; if (left_dst_w < 0) @@ -4354,6 +4365,17 @@ static void vop2_calc_drm_rect_for_splice(struct vop2_plane_state *vpstate, left_src_w = src_w; else left_src_w = (left_dst_w * hscale) >> 16; + + /* + * Make sure the yrgb/uv mst of right win are byte aligned + * with full pixel. + */ + if (right_dst_w) { + if (fb->format->format == DRM_FORMAT_NV15) + left_src_w &= ~0x7; + else if (fb->format->format == DRM_FORMAT_NV12) + left_src_w &= ~0x1; + } left_src->x1 = src->x1; left_src->x2 = src->x1 + (left_src_w << 16); left_dst->x1 = dst->x1; @@ -4361,6 +4383,9 @@ static void vop2_calc_drm_rect_for_splice(struct vop2_plane_state *vpstate, right_src->x1 = left_src->x2; right_src->x2 = src->x2; right_dst->x1 = dst->x1 + left_dst_w - half_hdisplay; + if (right_dst->x1 < 0) + right_dst->x1 = 0; + right_dst->x2 = right_dst->x1 + right_dst_w; left_src->y1 = src->y1; @@ -5194,6 +5219,7 @@ static void vop2_crtc_disable_line_flag_event(struct drm_crtc *crtc) static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on) { struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); struct vop2 *vop2 = vp->vop2; struct rockchip_drm_private *private = crtc->dev->dev_private; const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id]; @@ -5224,6 +5250,7 @@ static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on) crtc_state = drm_atomic_get_crtc_state(crtc->state->state, crtc); mode = &crtc_state->adjusted_mode; if (mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) { + vcstate->splice_mode = true; splice_win = vop2_find_win_by_phys_id(vop2, win->splice_win_id); splice_win->splice_mode_right = true; @@ -6357,19 +6384,38 @@ static void vop2_crtc_enable_dsc(struct drm_crtc *crtc, struct drm_crtc_state *o * dly_num = delay_line_num * T(one-line) / T (dsc_cds) * T (one-line) = 1/v_pixclk_mhz * htotal = htotal/v_pixclk_mhz * T (dsc_cds) = 1 / dsc_cds_rate_mhz + * + * HDMI: * delay_line_num: according the pps initial_xmit_delay to adjust vop dsc delay * delay_line_num = 4 - BPP / 8 * = (64 - target_bpp / 8) / 16 - * * dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * (64 - target_bpp / 8) / 16; + * + * MIPI DSI[4320 and 9216 is buffer size for DSC]: + * DSC0:delay_line_num = 4320 * 8 / slince_num / chunk_size; + * delay_line_num = delay_line_num > 5 ? 5 : delay_line_num; + * DSC1:delay_line_num = 9216 * 2 / slince_num / chunk_size; + * delay_line_num = delay_line_num > 5 ? 5 : delay_line_num; + * dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * delay_line_num */ do_div(dsc_cds_rate, 1000000); /* hz to Mhz */ dsc_cds_rate_mhz = dsc_cds_rate; - dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * (64 - target_bpp / 8) / 16; + dsc_hsync = hsync_len / 2; + if (dsc_interface_mode == VOP_DSC_IF_HDMI) { + dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * (64 - target_bpp / 8) / 16; + } else { + int dsc_buf_size = dsc->id == 0 ? 4320 * 8 : 9216 * 2; + int delay_line_num = dsc_buf_size / vcstate->dsc_slice_num / be16_to_cpu(vcstate->pps.chunk_size); + + delay_line_num = delay_line_num > 5 ? 5 : delay_line_num; + dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * delay_line_num; + + /* The dsc mipi video mode dsc_hsync minimum size is 8 pixels */ + if (dsc_hsync < 8) + dsc_hsync = 8; + } VOP_MODULE_SET(vop2, dsc, dsc_init_dly_mode, 0); VOP_MODULE_SET(vop2, dsc, dsc_init_dly_num, dly_num); - - dsc_hsync = hsync_len / 2; /* * htotal / dclk_core = dsc_htotal /cds_clk * @@ -6591,11 +6637,6 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state vcstate->mode_update = vop2_crtc_mode_update(crtc); if (vcstate->mode_update) vop2_disable_all_planes_for_crtc(crtc); - /* - * restore the lut table. - */ - if (vp->gamma_lut_active) - vop2_crtc_load_lut(crtc); dclk_inv = (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) ? 1 : 0; val = (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : BIT(HSYNC_POSITIVE); @@ -6958,8 +6999,12 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state vop2_clk_reset(vp->dclk_rst); if (vcstate->dsc_enable) rk3588_vop2_dsc_cfg_done(crtc); - drm_crtc_vblank_on(crtc); + /* + * restore the lut table. + */ + if (vp->gamma_lut_active) + vop2_crtc_load_lut(crtc); out: vop2_unlock(vop2); } @@ -6996,7 +7041,8 @@ static int vop2_crtc_atomic_check(struct drm_crtc *crtc, } } - if (vcstate->request_refresh_rate != new_vcstate->request_refresh_rate) + if ((vcstate->request_refresh_rate != new_vcstate->request_refresh_rate) || + crtc_state->active_changed || crtc_state->mode_changed) vp->refresh_rate_change = true; else vp->refresh_rate_change = false; diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index ca2838db89eb..ce4b3a251146 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -318,13 +318,15 @@ static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder) drm_panel_unprepare(lvds->panel); } -static void rockchip_lvds_encoder_loader_protect(struct drm_encoder *encoder, - bool on) +static int rockchip_lvds_encoder_loader_protect(struct drm_encoder *encoder, + bool on) { struct rockchip_lvds *lvds = encoder_to_lvds(encoder); if (lvds->panel) panel_simple_loader_protect(lvds->panel); + + return 0; } static const diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c index 972cbc8a6708..c6ca9596ca1f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_rgb.c +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c @@ -308,8 +308,8 @@ rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder, return 0; } -static void rockchip_rgb_encoder_loader_protect(struct drm_encoder *encoder, - bool on) +static int rockchip_rgb_encoder_loader_protect(struct drm_encoder *encoder, + bool on) { struct rockchip_rgb *rgb = encoder_to_rgb(encoder); @@ -319,11 +319,13 @@ static void rockchip_rgb_encoder_loader_protect(struct drm_encoder *encoder, mcu_panel->prepared = true; mcu_panel->enabled = true; - return; + return 0; } if (rgb->panel) panel_simple_loader_protect(rgb->panel); + + return 0; } static enum drm_mode_status diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index ec171f2b684a..6298da53ef14 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -19,9 +19,15 @@ #include #include #include +#include #define MAX_PWM 255 +struct thermal_trips { + int temp; + int state; +}; + struct pwm_fan_ctx { struct mutex lock; struct pwm_device *pwm; @@ -39,6 +45,9 @@ struct pwm_fan_ctx { unsigned int pwm_fan_max_state; unsigned int *pwm_fan_cooling_levels; struct thermal_cooling_device *cdev; + struct notifier_block thermal_nb; + struct thermal_trips *thermal_trips; + bool thermal_notifier_is_ok; }; /* This handler assumes self resetting edge triggered interrupt. */ @@ -278,6 +287,94 @@ static void pwm_fan_pwm_disable(void *__ctx) del_timer_sync(&ctx->rpm_timer); } +static int pwm_fan_get_thermal_trips(struct device *dev, char *porp_name, + struct thermal_trips **trips) +{ + struct device_node *np = dev->of_node; + struct thermal_trips *thermal_trips; + const struct property *prop; + int count, i; + + prop = of_find_property(np, porp_name, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + count = of_property_count_u32_elems(np, porp_name); + if (count < 0) + return -EINVAL; + if (count % 2) + return -EINVAL; + thermal_trips = devm_kzalloc(dev, + sizeof(*thermal_trips) * (count / 2 + 1), + GFP_KERNEL); + if (!thermal_trips) + return -ENOMEM; + + for (i = 0; i < count / 2; i++) { + of_property_read_u32_index(np, porp_name, 2 * i, + &thermal_trips[i].temp); + of_property_read_u32_index(np, porp_name, 2 * i + 1, + &thermal_trips[i].state); + } + thermal_trips[i].temp = 0; + thermal_trips[i].state = INT_MAX; + + *trips = thermal_trips; + + return 0; +} + +static int pwm_fan_temp_to_state(struct pwm_fan_ctx *ctx, int temp) +{ + struct thermal_trips *trips = ctx->thermal_trips; + int i, state = 0; + + for (i = 0; trips[i].state != INT_MAX; i++) { + if (temp >= trips[i].temp) + state = trips[i].state; + } + + return state; +} + +static int pwm_fan_thermal_notifier_call(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct pwm_fan_ctx *ctx = container_of(nb, struct pwm_fan_ctx, thermal_nb); + struct system_monitor_event_data *event_data = data; + int state, ret; + + if (event != SYSTEM_MONITOR_CHANGE_TEMP) + return NOTIFY_OK; + + state = pwm_fan_temp_to_state(ctx, event_data->temp); + if (state > ctx->pwm_fan_max_state) + return NOTIFY_BAD; + if (state == ctx->pwm_fan_state) + return NOTIFY_OK; + + ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); + if (ret) + return NOTIFY_BAD; + + ctx->pwm_fan_state = state; + + return NOTIFY_OK; +} + +static int pwm_fan_register_thermal_notifier(struct device *dev, + struct pwm_fan_ctx *ctx) +{ + if (pwm_fan_get_thermal_trips(dev, "rockchip,temp-trips", + &ctx->thermal_trips)) + return -EINVAL; + + ctx->thermal_nb.notifier_call = pwm_fan_thermal_notifier_call; + + return rockchip_system_monitor_register_notifier(&ctx->thermal_nb); +} + static int pwm_fan_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; @@ -379,6 +476,15 @@ static int pwm_fan_probe(struct platform_device *pdev) return ret; ctx->pwm_fan_state = ctx->pwm_fan_max_state; + if (IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR) && + of_find_property(dev->of_node, "rockchip,temp-trips", NULL)) { + ret = pwm_fan_register_thermal_notifier(dev, ctx); + if (ret) + dev_err(dev, "Failed to register thermal notifier: %d\n", ret); + else + ctx->thermal_notifier_is_ok = true; + return 0; + } if (IS_ENABLED(CONFIG_THERMAL)) { cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops); @@ -404,7 +510,7 @@ static int pwm_fan_disable(struct device *dev) pwm_get_args(ctx->pwm, &args); - if (ctx->pwm_value) { + if (ctx->pwm_value || ctx->thermal_notifier_is_ok) { ret = pwm_config(ctx->pwm, 0, args.period); if (ret < 0) return ret; @@ -449,7 +555,7 @@ static int pwm_fan_resume(struct device *dev) } } - if (ctx->pwm_value == 0) + if (ctx->pwm_value == 0 && !ctx->thermal_notifier_is_ok) return 0; pwm_get_args(ctx->pwm, &pargs); diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index 32cd26352f38..1760015ba302 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -28,6 +28,16 @@ config HWSPINLOCK_QCOM If unsure, say N. +config HWSPINLOCK_ROCKCHIP + tristate "Rockchip Hardware Spinlock device" + depends on ARCH_ROCKCHIP || COMPILE_TEST + help + Say y here to support the Rockchip Hardware Spinlock device, which + provides a synchronisation mechanism for the various processors + on the SoC. + + If unsure, say N. + config HWSPINLOCK_SIRF tristate "SIRF Hardware Spinlock device" depends on ARCH_SIRF || COMPILE_TEST diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index ed053e3f02be..6b74ba1569a1 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_ROCKCHIP) += rockchip_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_SPRD) += sprd_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o diff --git a/drivers/hwspinlock/rockchip_hwspinlock.c b/drivers/hwspinlock/rockchip_hwspinlock.c index 2d62aff57f72..26ba8ec31f01 100644 --- a/drivers/hwspinlock/rockchip_hwspinlock.c +++ b/drivers/hwspinlock/rockchip_hwspinlock.c @@ -5,13 +5,10 @@ #include #include #include -#include #include -#include #include #include #include -#include #include "hwspinlock_internal.h" @@ -59,19 +56,15 @@ static int rockchip_hwspinlock_probe(struct platform_device *pdev) { struct rockchip_hwspinlock *hwspin; struct hwspinlock *hwlock; - struct resource *res; - int idx, ret; + int idx; - if (!pdev->dev.of_node) - return -ENODEV; - - hwspin = devm_kzalloc(&pdev->dev, sizeof(*hwspin) + - sizeof(*hwlock) * HWSPINLOCK_NUMBER, GFP_KERNEL); + hwspin = devm_kzalloc(&pdev->dev, + struct_size(hwspin, bank.lock, HWSPINLOCK_NUMBER), + GFP_KERNEL); if (!hwspin) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hwspin->io_base = devm_ioremap_resource(&pdev->dev, res); + hwspin->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hwspin->io_base)) return PTR_ERR(hwspin->io_base); @@ -82,39 +75,9 @@ static int rockchip_hwspinlock_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hwspin); - pm_runtime_enable(&pdev->dev); - - ret = hwspin_lock_register(&hwspin->bank, &pdev->dev, - &rockchip_hwspinlock_ops, 0, - HWSPINLOCK_NUMBER); - if (ret) - goto reg_fail; - - return 0; - -reg_fail: - pm_runtime_disable(&pdev->dev); - iounmap(hwspin->io_base); - - return ret; -} - -static int rockchip_hwspinlock_remove(struct platform_device *pdev) -{ - struct rockchip_hwspinlock *hwspin = platform_get_drvdata(pdev); - int ret; - - ret = hwspin_lock_unregister(&hwspin->bank); - if (ret) { - dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); - return ret; - } - - pm_runtime_disable(&pdev->dev); - - iounmap(hwspin->io_base); - - return 0; + return devm_hwspin_lock_register(&pdev->dev, &hwspin->bank, + &rockchip_hwspinlock_ops, 0, + HWSPINLOCK_NUMBER); } static const struct of_device_id rockchip_hwpinlock_ids[] = { @@ -125,7 +88,6 @@ MODULE_DEVICE_TABLE(of, rockchip_hwpinlock_ids); static struct platform_driver rockchip_hwspinlock_driver = { .probe = rockchip_hwspinlock_probe, - .remove = rockchip_hwspinlock_remove, .driver = { .name = "rockchip_hwspinlock", .of_match_table = of_match_ptr(rockchip_hwpinlock_ids), diff --git a/drivers/iio/light/ucs12cm0.c b/drivers/iio/light/ucs12cm0.c index b04df7a09689..16b31d635cbf 100644 --- a/drivers/iio/light/ucs12cm0.c +++ b/drivers/iio/light/ucs12cm0.c @@ -619,10 +619,29 @@ static const struct i2c_device_id ucs12cm0_id[] = { }; MODULE_DEVICE_TABLE(i2c, ucs12cm0_id); +static int ucs12cm0_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ucs12cm0_data *data = iio_priv(indio_dev); + int ret; + + ret = ucs12cm0_init(data); + if (ret < 0) + return ret; + + return 0; +} + +static const struct dev_pm_ops ucs12cm0_pm_ops = { + .resume = ucs12cm0_resume, +}; + static struct i2c_driver ucs12cm0_driver = { .driver = { .name = "ucs12cm0", .of_match_table = ucs12cm0_of_match, + .pm = &ucs12cm0_pm_ops, }, .probe = ucs12cm0_probe, .id_table = ucs12cm0_id, diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 0e0baa944c2c..5d22c575b295 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1720,7 +1720,7 @@ static int rk_iommu_of_xlate(struct device *dev, return 0; } -void rk_iommu_mask_irq(struct device *dev) +void rockchip_iommu_mask_irq(struct device *dev) { struct rk_iommu *iommu = rk_iommu_from_dev(dev); int i; @@ -1731,9 +1731,9 @@ void rk_iommu_mask_irq(struct device *dev) for (i = 0; i < iommu->num_mmu; i++) rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0); } -EXPORT_SYMBOL(rk_iommu_mask_irq); +EXPORT_SYMBOL(rockchip_iommu_mask_irq); -void rk_iommu_unmask_irq(struct device *dev) +void rockchip_iommu_unmask_irq(struct device *dev) { struct rk_iommu *iommu = rk_iommu_from_dev(dev); int i; @@ -1749,7 +1749,7 @@ void rk_iommu_unmask_irq(struct device *dev) rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_PAGE_FAULT_DONE); } } -EXPORT_SYMBOL(rk_iommu_unmask_irq); +EXPORT_SYMBOL(rockchip_iommu_unmask_irq); static struct iommu_ops rk_iommu_ops = { .domain_alloc = rk_iommu_domain_alloc, diff --git a/drivers/media/i2c/lt7911uxc.c b/drivers/media/i2c/lt7911uxc.c index 1618d01d1ec4..8fea3659d1cd 100644 --- a/drivers/media/i2c/lt7911uxc.c +++ b/drivers/media/i2c/lt7911uxc.c @@ -10,6 +10,7 @@ * V0.0X01.0X01 support DPHY 4K60. * V0.0X01.0X02 add CPHY support. * V0.0X01.0X03 add rk3588 dcphy param. + * V0.0X01.0X04 add 5K60 support for CPHY. * */ @@ -37,7 +38,7 @@ #include #include -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x04) static int debug; module_param(debug, int, 0644); @@ -48,7 +49,8 @@ MODULE_PARM_DESC(debug, "debug level (0-3)"); #define LT7911UXC_LINK_FREQ_HIGH 1250000000 #define LT7911UXC_LINK_FREQ_LOW 400000000 -#define LT7911UXC_PIXEL_RATE 600000000 +#define LT7911UXC_LINK_FREQ_700M 700000000 +#define LT7911UXC_PIXEL_RATE 800000000 #define LT7911UXC_CHIPID 0x0119 #define CHIPID_REGH 0xe101 @@ -96,6 +98,7 @@ MODULE_PARM_DESC(debug, "debug level (0-3)"); static const s64 link_freq_menu_items[] = { LT7911UXC_LINK_FREQ_HIGH, LT7911UXC_LINK_FREQ_LOW, + LT7911UXC_LINK_FREQ_700M, }; struct lt7911uxc { @@ -139,7 +142,7 @@ struct lt7911uxc { static const struct v4l2_dv_timings_cap lt7911uxc_timings_cap = { .type = V4L2_DV_BT_656_1120, .reserved = { 0 }, - V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 600000000, + V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 800000000, V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED | @@ -224,6 +227,16 @@ static const struct lt7911uxc_mode supported_modes_dphy[] = { static const struct lt7911uxc_mode supported_modes_cphy[] = { { + .width = 5120, + .height = 2160, + .max_fps = { + .numerator = 10000, + .denominator = 600000, + }, + .hts_def = 5500, + .vts_def = 2250, + .mipi_freq_idx = 2, + }, { .width = 3840, .height = 2160, .max_fps = { diff --git a/drivers/media/i2c/ov13855.c b/drivers/media/i2c/ov13855.c index 9beeddedfe2c..c05c5cea46f1 100644 --- a/drivers/media/i2c/ov13855.c +++ b/drivers/media/i2c/ov13855.c @@ -10,6 +10,7 @@ * V0.0X01.0X03 * 1. 4224x3136@15fps & 2114x1568@60fps only enable for debug. * 2. fix some regs setting. + * V0.0X01.0X04 fix power on sequence */ //#define DEBUG #include @@ -31,7 +32,7 @@ #include #include -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x04) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN @@ -1127,6 +1128,8 @@ static int ov13855_set_fmt(struct v4l2_subdev *sd, __v4l2_ctrl_s_ctrl(ov13855->link_freq, mode->link_freq_idx); } + dev_info(&ov13855->client->dev, "%s: mode->link_freq_idx(%d)", + __func__, mode->link_freq_idx); mutex_unlock(&ov13855->mutex); @@ -1470,13 +1473,13 @@ static int __ov13855_power_on(struct ov13855 *ov13855) if (!IS_ERR(ov13855->reset_gpio)) gpiod_set_value_cansleep(ov13855->reset_gpio, 1); - usleep_range(500, 1000); + usleep_range(5000, 6000); if (!IS_ERR(ov13855->pwdn_gpio)) gpiod_set_value_cansleep(ov13855->pwdn_gpio, 1); /* 8192 cycles prior to first SCCB transaction */ delay_us = ov13855_cal_delay(8192); - usleep_range(delay_us, delay_us * 2); + usleep_range(delay_us * 2, delay_us * 3); return 0; diff --git a/drivers/media/i2c/sc031gs.c b/drivers/media/i2c/sc031gs.c index bd6f9eeb7bc7..854c2a0f9ee7 100644 --- a/drivers/media/i2c/sc031gs.c +++ b/drivers/media/i2c/sc031gs.c @@ -999,8 +999,8 @@ static void sc031gs_modify_fps_info(struct sc031gs *sc031gs) { const struct sc031gs_mode *mode = sc031gs->cur_mode; - sc031gs->cur_fps.denominator = mode->max_fps.denominator * sc031gs->cur_vts / - mode->vts_def; + sc031gs->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc031gs->cur_vts; } static int sc031gs_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc035gs.c b/drivers/media/i2c/sc035gs.c index 5814e3f69bda..0001f37d65f8 100644 --- a/drivers/media/i2c/sc035gs.c +++ b/drivers/media/i2c/sc035gs.c @@ -983,8 +983,8 @@ static void sc035gs_modify_fps_info(struct sc035gs *sc035gs) { const struct sc035gs_mode *mode = sc035gs->cur_mode; - sc035gs->cur_fps.denominator = mode->max_fps.denominator * sc035gs->cur_vts / - mode->vts_def; + sc035gs->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc035gs->cur_vts; } static int sc035gs_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc132gs.c b/drivers/media/i2c/sc132gs.c index ae2f3177be7f..dd6b63e28db2 100644 --- a/drivers/media/i2c/sc132gs.c +++ b/drivers/media/i2c/sc132gs.c @@ -1098,8 +1098,8 @@ static void sc132gs_modify_fps_info(struct sc132gs *sc132gs) { const struct sc132gs_mode *mode = sc132gs->cur_mode; - sc132gs->cur_fps.denominator = mode->max_fps.denominator * sc132gs->cur_vts / - mode->vts_def; + sc132gs->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc132gs->cur_vts; } static int sc132gs_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc200ai.c b/drivers/media/i2c/sc200ai.c index 2b1c1a49fb9e..d26f576714b2 100644 --- a/drivers/media/i2c/sc200ai.c +++ b/drivers/media/i2c/sc200ai.c @@ -33,6 +33,7 @@ #include #include #include +#include "../platform/rockchip/isp/rkisp_tb_helper.h" #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x07) @@ -46,6 +47,7 @@ #define PIXEL_RATE_WITH_371M_10BIT (SC200AI_LINK_FREQ_371 * 2 * \ SC200AI_LANES / SC200AI_BITS_PER_SAMPLE) + #define SC200AI_XVCLK_FREQ 27000000 #define CHIP_ID 0xcb1c @@ -174,6 +176,8 @@ struct sc200ai { const char *len_name; u32 cur_vts; bool has_init_exp; + bool is_thunderboot; + bool is_first_streamoff; struct preisp_hdrae_exp_s init_hdrae_exp; }; @@ -188,10 +192,10 @@ static const struct regval sc200ai_global_regs[] = { /* * Xclk 24Mhz - * max_framerate 90fps + * max_framerate 60fps * mipi_datarate per lane 1008Mbps, 4lane */ -static const struct regval sc200ai_linear_10_1920x1080_regs[] = { +static const struct regval sc200ai_linear_10_1920x1080_60fps_regs[] = { {0x0103, 0x01}, {0x0100, 0x00}, {0x36e9, 0x80}, @@ -328,6 +332,113 @@ static const struct regval sc200ai_linear_10_1920x1080_regs[] = { {REG_NULL, 0x00}, }; +/* + * Xclk 27Mhz + * max_framerate 30fps + * mipi_datarate per lane 371.25Mbps, 2lane + */ +static const struct regval sc200ai_linear_10_1920x1080_30fps_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x36e9, 0x80}, + {0x36f9, 0x80}, + {0x301f, 0x03}, + //HTS=1100*2=2200 + {0x320c, 0x04}, + {0x320d, 0x4c}, + //VTS=1125 + {0x320e, 0x04}, + {0x320f, 0x65}, + {0x3243, 0x01}, + {0x3248, 0x02}, + {0x3249, 0x09}, + {0x3253, 0x08}, + {0x3271, 0x0a}, + {0x3301, 0x20}, + {0x3304, 0x40}, + {0x3306, 0x32}, + {0x330b, 0x88}, + {0x330f, 0x02}, + {0x331e, 0x39}, + {0x3333, 0x10}, + {0x3621, 0xe8}, + {0x3622, 0x16}, + {0x3637, 0x1b}, + {0x363a, 0x1f}, + {0x363b, 0xc6}, + {0x363c, 0x0e}, + {0x3670, 0x0a}, + {0x3674, 0x82}, + {0x3675, 0x76}, + {0x3676, 0x78}, + {0x367c, 0x48}, + {0x367d, 0x58}, + {0x3690, 0x34}, + {0x3691, 0x33}, + {0x3692, 0x44}, + {0x369c, 0x40}, + {0x369d, 0x48}, + {0x3901, 0x02}, + {0x3904, 0x04}, + {0x3908, 0x41}, + {0x391d, 0x14}, + {0x391f, 0x18}, + {0x3e01, 0x8c}, + {0x3e02, 0x20}, + {0x3e16, 0x00}, + {0x3e17, 0x80}, + {0x3f09, 0x48}, + {0x5787, 0x10}, + {0x5788, 0x06}, + {0x578a, 0x10}, + {0x578b, 0x06}, + {0x5790, 0x10}, + {0x5791, 0x10}, + {0x5792, 0x00}, + {0x5793, 0x10}, + {0x5794, 0x10}, + {0x5795, 0x00}, + {0x5799, 0x00}, + {0x57c7, 0x10}, + {0x57c8, 0x06}, + {0x57ca, 0x10}, + {0x57cb, 0x06}, + {0x57d1, 0x10}, + {0x57d4, 0x10}, + {0x57d9, 0x00}, + {0x59e0, 0x60}, + {0x59e1, 0x08}, + {0x59e2, 0x3f}, + {0x59e3, 0x18}, + {0x59e4, 0x18}, + {0x59e5, 0x3f}, + {0x59e6, 0x06}, + {0x59e7, 0x02}, + {0x59e8, 0x38}, + {0x59e9, 0x10}, + {0x59ea, 0x0c}, + {0x59eb, 0x10}, + {0x59ec, 0x04}, + {0x59ed, 0x02}, + {0x59ee, 0xa0}, + {0x59ef, 0x08}, + {0x59f4, 0x18}, + {0x59f5, 0x10}, + {0x59f6, 0x0c}, + {0x59f7, 0x10}, + {0x59f8, 0x06}, + {0x59f9, 0x02}, + {0x59fa, 0x18}, + {0x59fb, 0x10}, + {0x59fc, 0x0c}, + {0x59fd, 0x10}, + {0x59fe, 0x04}, + {0x59ff, 0x02}, + {0x36e9, 0x20}, + {0x36f9, 0x27}, + {REG_NULL, 0x00}, +}; + /* * Xclk 27Mhz * max_framerate 30fps @@ -339,8 +450,12 @@ static const struct regval sc200ai_hdr_10_1920x1080_regs[] = { {0x36e9, 0x80}, {0x36f9, 0x80}, {0x301f, 0x02}, + //HTS=1100*2=2200 + {0x320c, 0x04}, + {0x320d, 0x4c}, + //VTS =2252 {0x320e, 0x08}, - {0x320f, 0xca}, + {0x320f, 0xcc}, {0x3220, 0x53}, {0x3243, 0x01}, {0x3248, 0x02}, @@ -365,9 +480,11 @@ static const struct regval sc200ai_hdr_10_1920x1080_regs[] = { {0x331f, 0x61}, {0x3320, 0x07}, {0x3333, 0x10}, + {0x3347, 0x77}, {0x334c, 0x08}, {0x3356, 0x09}, {0x3364, 0x17}, + {0x336c, 0xcc}, {0x3390, 0x08}, {0x3391, 0x18}, {0x3392, 0x38}, @@ -424,8 +541,8 @@ static const struct regval sc200ai_hdr_10_1920x1080_regs[] = { {0x3e13, 0x40}, {0x3e16, 0x00}, {0x3e17, 0x80}, - {0x3e23, 0x00}, - {0x3e24, 0x40}, + {0x3e23, 0x01}, + {0x3e24, 0x9e}, {0x3f09, 0x48}, {0x4816, 0xb1}, {0x4819, 0x09}, @@ -490,6 +607,20 @@ static const struct regval sc200ai_hdr_10_1920x1080_regs[] = { static const struct sc200ai_mode supported_modes[] = { { + .width = 1920, + .height = 1080, + .max_fps = { + .numerator = 10000, + .denominator = 300000, + }, + .exp_def = 0x0080, + .hts_def = 0x44C * 2, + .vts_def = 0x0465, + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, + .reg_list = sc200ai_linear_10_1920x1080_30fps_regs, + .hdr_mode = NO_HDR, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + }, { .width = 1920, .height = 1080, .max_fps = { @@ -500,7 +631,7 @@ static const struct sc200ai_mode supported_modes[] = { .hts_def = 0x44C * 2, .vts_def = 0x0465, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .reg_list = sc200ai_linear_10_1920x1080_regs, + .reg_list = sc200ai_linear_10_1920x1080_60fps_regs, .hdr_mode = NO_HDR, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, }, { @@ -512,7 +643,7 @@ static const struct sc200ai_mode supported_modes[] = { }, .exp_def = 0x0080, .hts_def = 0x44C * 2, - .vts_def = 0x08CA, + .vts_def = 0x08CC, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, .reg_list = sc200ai_hdr_10_1920x1080_regs, .hdr_mode = HDR_X2, @@ -807,8 +938,8 @@ static int sc200ai_set_hdrae(struct sc200ai *sc200ai, s_exp_time = s_exp_time * 2; if (l_exp_time > 4362) //(2250 - 64 - 5) * 2 l_exp_time = 4362; - if (s_exp_time > 118) //(64 - 5) * 2 - s_exp_time = 118; + if (s_exp_time > 404) //(64 - 5) * 2 + s_exp_time = 404; ret = sc200ai_write_reg(sc200ai->client, SC200AI_REG_EXPOSURE_H, @@ -831,7 +962,6 @@ static int sc200ai_set_hdrae(struct sc200ai *sc200ai, SC200AI_REG_VALUE_08BIT, SC200AI_FETCH_EXP_L(s_exp_time)); - ret |= sc200ai_set_gain_reg(sc200ai, l_a_gain, SC200AI_LGAIN); ret |= sc200ai_set_gain_reg(sc200ai, s_a_gain, SC200AI_SGAIN); return ret; @@ -1230,21 +1360,30 @@ static int __sc200ai_start_stream(struct sc200ai *sc200ai) { int ret; - ret = sc200ai_write_array(sc200ai->client, sc200ai->cur_mode->reg_list); - if (ret) - return ret; - - /* In case these controls are set before streaming */ - ret = __v4l2_ctrl_handler_setup(&sc200ai->ctrl_handler); - if (ret) - return ret; - if (sc200ai->has_init_exp && sc200ai->cur_mode->hdr_mode != NO_HDR) { - ret = sc200ai_ioctl(&sc200ai->subdev, PREISP_CMD_SET_HDRAE_EXP, - &sc200ai->init_hdrae_exp); - if (ret) { - dev_err(&sc200ai->client->dev, - "init exp fail in hdr mode\n"); + dev_info(&sc200ai->client->dev, + "%dx%d@%d, mode %d, vts 0x%x\n", + sc200ai->cur_mode->width, + sc200ai->cur_mode->height, + sc200ai->cur_fps.denominator / sc200ai->cur_fps.numerator, + sc200ai->cur_mode->hdr_mode, + sc200ai->cur_vts); + if (!sc200ai->is_thunderboot) { + ret = sc200ai_write_array(sc200ai->client, sc200ai->cur_mode->reg_list); + if (ret) return ret; + + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&sc200ai->ctrl_handler); + if (ret) + return ret; + if (sc200ai->has_init_exp && sc200ai->cur_mode->hdr_mode != NO_HDR) { + ret = sc200ai_ioctl(&sc200ai->subdev, PREISP_CMD_SET_HDRAE_EXP, + &sc200ai->init_hdrae_exp); + if (ret) { + dev_err(&sc200ai->client->dev, + "init exp fail in hdr mode\n"); + return ret; + } } } @@ -1255,10 +1394,13 @@ static int __sc200ai_start_stream(struct sc200ai *sc200ai) static int __sc200ai_stop_stream(struct sc200ai *sc200ai) { sc200ai->has_init_exp = false; + if (sc200ai->is_thunderboot) + sc200ai->is_first_streamoff = true; return sc200ai_write_reg(sc200ai->client, SC200AI_REG_CTRL_MODE, SC200AI_REG_VALUE_08BIT, SC200AI_MODE_SW_STANDBY); } +static int __sc200ai_power_on(struct sc200ai *sc200ai); static int sc200ai_s_stream(struct v4l2_subdev *sd, int on) { struct sc200ai *sc200ai = to_sc200ai(sd); @@ -1271,6 +1413,10 @@ static int sc200ai_s_stream(struct v4l2_subdev *sd, int on) goto unlock_and_return; if (on) { + if (sc200ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { + sc200ai->is_thunderboot = false; + __sc200ai_power_on(sc200ai); + } ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { pm_runtime_put_noidle(&client->dev); @@ -1315,11 +1461,13 @@ static int sc200ai_s_power(struct v4l2_subdev *sd, int on) goto unlock_and_return; } - ret = sc200ai_write_array(sc200ai->client, sc200ai_global_regs); - if (ret) { - v4l2_err(sd, "could not set init registers\n"); - pm_runtime_put_noidle(&client->dev); - goto unlock_and_return; + if (!sc200ai->is_thunderboot) { + ret = sc200ai_write_array(sc200ai->client, sc200ai_global_regs); + if (ret) { + v4l2_err(sd, "could not set init registers\n"); + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } } sc200ai->power_on = true; @@ -1362,6 +1510,9 @@ static int __sc200ai_power_on(struct sc200ai *sc200ai) dev_err(dev, "Failed to enable xvclk\n"); return ret; } + if (sc200ai->is_thunderboot) + return 0; + if (!IS_ERR(sc200ai->reset_gpio)) gpiod_set_value_cansleep(sc200ai->reset_gpio, 0); @@ -1400,6 +1551,15 @@ static void __sc200ai_power_off(struct sc200ai *sc200ai) int ret; struct device *dev = &sc200ai->client->dev; + clk_disable_unprepare(sc200ai->xvclk); + if (sc200ai->is_thunderboot) { + if (sc200ai->is_first_streamoff) { + sc200ai->is_thunderboot = false; + sc200ai->is_first_streamoff = false; + } else { + return; + } + } if (!IS_ERR(sc200ai->pwdn_gpio)) gpiod_set_value_cansleep(sc200ai->pwdn_gpio, 0); clk_disable_unprepare(sc200ai->xvclk); @@ -1514,8 +1674,8 @@ static void sc200ai_modify_fps_info(struct sc200ai *sc200ai) { const struct sc200ai_mode *mode = sc200ai->cur_mode; - sc200ai->cur_fps.denominator = mode->max_fps.denominator * sc200ai->cur_vts / - mode->vts_def; + sc200ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def/ + sc200ai->cur_vts; } static int sc200ai_set_ctrl(struct v4l2_ctrl *ctrl) @@ -1646,12 +1806,14 @@ static int sc200ai_initialize_controls(struct sc200ai *sc200ai) h_blank, h_blank, 1, h_blank); if (sc200ai->hblank) sc200ai->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sc200ai->cur_fps = mode->max_fps; vblank_def = mode->vts_def - mode->height; + sc200ai->cur_vts = mode->vts_def; sc200ai->vblank = v4l2_ctrl_new_std(handler, &sc200ai_ctrl_ops, V4L2_CID_VBLANK, vblank_def, SC200AI_VTS_MAX - mode->height, 1, vblank_def); - exposure_max = mode->vts_def - 4; + exposure_max = 2 * mode->vts_def - 8; sc200ai->exposure = v4l2_ctrl_new_std(handler, &sc200ai_ctrl_ops, V4L2_CID_EXPOSURE, SC200AI_EXPOSURE_MIN, exposure_max, SC200AI_EXPOSURE_STEP, @@ -1680,8 +1842,6 @@ static int sc200ai_initialize_controls(struct sc200ai *sc200ai) sc200ai->subdev.ctrl_handler = handler; sc200ai->has_init_exp = false; - sc200ai->cur_fps = mode->max_fps; - sc200ai->cur_vts = mode->vts_def; return 0; @@ -1698,6 +1858,11 @@ static int sc200ai_check_sensor_id(struct sc200ai *sc200ai, u32 id = 0; int ret; + if (sc200ai->is_thunderboot) { + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); + return 0; + } + ret = sc200ai_read_reg(client, SC200AI_REG_CHIP_ID, SC200AI_REG_VALUE_16BIT, &id); if (id != CHIP_ID) { @@ -1722,6 +1887,132 @@ static int sc200ai_configure_regulators(struct sc200ai *sc200ai) sc200ai->supplies); } +#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP +static u32 rk_cam_hdr; +static u32 rk_cam_w; +static u32 rk_cam_h; +static u32 rk_cam_fps; + +static int __init __maybe_unused rk_cam_hdr_setup(char *str) +{ + int ret = 0; + unsigned long val = 0; + + ret = kstrtoul(str, 0, &val); + if (!ret) + rk_cam_hdr = (u32)val; + else + pr_err("get rk_cam_hdr fail\n"); + return 1; +} + +static int __init __maybe_unused rk_cam_w_setup(char *str) +{ + int ret = 0; + unsigned long val = 0; + + ret = kstrtoul(str, 0, &val); + if (!ret) + rk_cam_w = (u32)val; + else + pr_err("get rk_cam_w fail\n"); + return 1; +} + +static int __init __maybe_unused rk_cam_h_setup(char *str) +{ + int ret = 0; + unsigned long val = 0; + + ret = kstrtoul(str, 0, &val); + if (!ret) + rk_cam_h = (u32)val; + else + pr_err("get rk_cam_h fail\n"); + return 1; +} + +static int __init __maybe_unused rk_cam_fps_setup(char *str) +{ + int ret = 0; + unsigned long val = 0; + + ret = kstrtoul(str, 0, &val); + if (!ret) + rk_cam_fps = (u32)val; + else + pr_err("get rk_cam_fps fail\n"); + return 1; +} + +__setup("rk_cam_hdr=", rk_cam_hdr_setup); +__setup("rk_cam_w=", rk_cam_w_setup); +__setup("rk_cam_h=", rk_cam_h_setup); +__setup("rk_cam_fps", rk_cam_fps_setup); + +static void find_terminal_resolution(struct sc200ai *sc200ai) +{ + int i = 0; + const struct sc200ai_mode *mode = NULL; + const struct sc200ai_mode *fit_mode = NULL; + u32 cur_fps = 0; + u32 dst_fps = 0; + u32 tmp_fps = 0; + + if (rk_cam_w == 0 || rk_cam_h == 0 || + rk_cam_fps == 0) + goto err_find_res; + + dst_fps = rk_cam_fps; + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { + mode = &supported_modes[i]; + cur_fps = mode->max_fps.denominator / mode->max_fps.numerator; + if (mode->width == rk_cam_w && mode->height == rk_cam_h && + mode->hdr_mode == rk_cam_hdr) { + if (cur_fps == dst_fps) { + sc200ai->cur_mode = mode; + return; + } + if (cur_fps >= dst_fps) { + if (fit_mode) { + tmp_fps = fit_mode->max_fps.denominator / fit_mode->max_fps.numerator; + if (tmp_fps - dst_fps > cur_fps - dst_fps) + fit_mode = mode; + } else { + fit_mode = mode; + } + } + } + } + if (fit_mode) { + sc200ai->cur_mode = fit_mode; + return; + } +err_find_res: + dev_err(&sc200ai->client->dev, "not match %dx%d@%dfps mode %d\n!", + rk_cam_w, rk_cam_h, dst_fps, rk_cam_hdr); + sc200ai->cur_mode = &supported_modes[0]; +} +#else +static void find_terminal_resolution(struct sc200ai *sc200ai) +{ + u32 hdr_mode = 0; + struct device_node *node = sc200ai->client->dev.of_node; + int i = 0; + + of_property_read_u32(node, OF_CAMERA_HDR_MODE, &hdr_mode); + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { + if (hdr_mode == supported_modes[i].hdr_mode) { + sc200ai->cur_mode = &supported_modes[i]; + break; + } + } + if (i == ARRAY_SIZE(supported_modes)) + sc200ai->cur_mode = &supported_modes[0]; + +} +#endif + static int sc200ai_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1731,7 +2022,6 @@ static int sc200ai_probe(struct i2c_client *client, struct v4l2_subdev *sd; char facing[2]; int ret; - u32 i, hdr_mode = 0; dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, @@ -1742,7 +2032,6 @@ static int sc200ai_probe(struct i2c_client *client, if (!sc200ai) return -ENOMEM; - of_property_read_u32(node, OF_CAMERA_HDR_MODE, &hdr_mode); ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, &sc200ai->module_index); ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, @@ -1756,15 +2045,10 @@ static int sc200ai_probe(struct i2c_client *client, return -EINVAL; } + sc200ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); sc200ai->client = client; - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - if (hdr_mode == supported_modes[i].hdr_mode) { - sc200ai->cur_mode = &supported_modes[i]; - break; - } - } - if (i == ARRAY_SIZE(supported_modes)) - sc200ai->cur_mode = &supported_modes[0]; + + find_terminal_resolution(sc200ai); sc200ai->xvclk = devm_clk_get(dev, "xvclk"); if (IS_ERR(sc200ai->xvclk)) { @@ -1772,11 +2056,11 @@ static int sc200ai_probe(struct i2c_client *client, return -EINVAL; } - sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); if (IS_ERR(sc200ai->reset_gpio)) dev_warn(dev, "Failed to get reset-gpios\n"); - sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); + sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); if (IS_ERR(sc200ai->pwdn_gpio)) dev_warn(dev, "Failed to get pwdn-gpios\n"); @@ -1921,8 +2205,12 @@ static void __exit sensor_mod_exit(void) i2c_del_driver(&sc200ai_i2c_driver); } +#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) +subsys_initcall(sensor_mod_init); +#else device_initcall_sync(sensor_mod_init); +#endif module_exit(sensor_mod_exit); MODULE_DESCRIPTION("smartsens sc200ai sensor driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/sc210iot.c b/drivers/media/i2c/sc210iot.c index ba1d93534558..d5a2f6777395 100644 --- a/drivers/media/i2c/sc210iot.c +++ b/drivers/media/i2c/sc210iot.c @@ -369,8 +369,8 @@ static void sc210iot_modify_fps_info(struct sc210iot *sc210iot) { const struct sc210iot_mode *mode = sc210iot->cur_mode; - sc210iot->cur_fps.denominator = mode->max_fps.denominator * sc210iot->cur_vts / - mode->vts_def; + sc210iot->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc210iot->cur_vts; } static int sc210iot_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc2232.c b/drivers/media/i2c/sc2232.c index 30294828f872..0278d2f31b55 100644 --- a/drivers/media/i2c/sc2232.c +++ b/drivers/media/i2c/sc2232.c @@ -1161,8 +1161,8 @@ static void sc2232_modify_fps_info(struct sc2232 *sc2232) { const struct sc2232_mode *mode = sc2232->cur_mode; - sc2232->cur_fps.denominator = mode->max_fps.denominator * sc2232->cur_vts / - mode->vts_def; + sc2232->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc2232->cur_vts; } static int sc2232_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc2239.c b/drivers/media/i2c/sc2239.c index c23cee7dd18a..ddc3a90a073e 100644 --- a/drivers/media/i2c/sc2239.c +++ b/drivers/media/i2c/sc2239.c @@ -927,8 +927,8 @@ static void sc2239_modify_fps_info(struct sc2239 *sc2239) { const struct sc2239_mode *mode = sc2239->cur_mode; - sc2239->cur_fps.denominator = mode->max_fps.denominator * sc2239->cur_vts / - mode->vts_def; + sc2239->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc2239->cur_vts; } static int sc2239_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc230ai.c b/drivers/media/i2c/sc230ai.c index 9e76ce5b4db7..e7975c80fa85 100644 --- a/drivers/media/i2c/sc230ai.c +++ b/drivers/media/i2c/sc230ai.c @@ -1385,8 +1385,8 @@ static void sc230ai_modify_fps_info(struct sc230ai *sc230ai) { const struct sc230ai_mode *mode = sc230ai->cur_mode; - sc230ai->cur_fps.denominator = mode->max_fps.denominator * sc230ai->cur_vts / - mode->vts_def; + sc230ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc230ai->cur_vts; } static int sc230ai_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc2310.c b/drivers/media/i2c/sc2310.c index 54fad6c12fe7..ac76a27afc83 100644 --- a/drivers/media/i2c/sc2310.c +++ b/drivers/media/i2c/sc2310.c @@ -1574,8 +1574,8 @@ static void sc2310_modify_fps_info(struct sc2310 *sc2310) { const struct sc2310_mode *mode = sc2310->cur_mode; - sc2310->cur_fps.denominator = mode->max_fps.denominator * sc2310->cur_vts / - mode->vts_def; + sc2310->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc2310->cur_vts; } static int sc2310_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc301iot.c b/drivers/media/i2c/sc301iot.c index 4d81b30aa3ba..ff0fa6520284 100644 --- a/drivers/media/i2c/sc301iot.c +++ b/drivers/media/i2c/sc301iot.c @@ -1869,8 +1869,8 @@ static void SC301IOT_modify_fps_info(struct SC301IOT *SC301IOT) { const struct SC301IOT_mode *mode = SC301IOT->cur_mode; - SC301IOT->cur_fps.denominator = mode->max_fps.denominator * SC301IOT->cur_vts / - mode->vts_def; + SC301IOT->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + SC301IOT->cur_vts; } static int SC301IOT_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc3336.c b/drivers/media/i2c/sc3336.c index 44fc244a8e1b..431a0384bebf 100644 --- a/drivers/media/i2c/sc3336.c +++ b/drivers/media/i2c/sc3336.c @@ -186,19 +186,17 @@ static const struct regval sc3336_linear_10_2304x1296_25fps_regs[] = { {0x0103, 0x01}, {0x36e9, 0x80}, {0x37f9, 0x80}, - {0x301f, 0x62}, + {0x301f, 0x01}, {0x30b8, 0x33}, - {0x320c, 0x05}, - {0x320d, 0xdc}, + {0x320e, 0x06}, + {0x320f, 0x54}, {0x3253, 0x10}, {0x325f, 0x20}, {0x3301, 0x04}, - {0x3302, 0xa0}, {0x3306, 0x50}, {0x3309, 0xa8}, {0x330a, 0x00}, {0x330b, 0xd8}, - {0x330d, 0xa0}, {0x3314, 0x13}, {0x331f, 0x99}, {0x3333, 0x10}, @@ -220,7 +218,7 @@ static const struct regval sc3336_linear_10_2304x1296_25fps_regs[] = { {0x3399, 0x04}, {0x339a, 0x0a}, {0x339b, 0x3a}, - {0x339c, 0xa0}, + {0x339c, 0xb4}, {0x33a2, 0x04}, {0x33ac, 0x08}, {0x33ad, 0x1c}, @@ -471,7 +469,7 @@ static const struct sc3336_mode supported_modes[] = { }, .exp_def = 0x0080, .hts_def = 0x05dc, - .vts_def = 0x0546, + .vts_def = 0x0654, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, .reg_list = sc3336_linear_10_2304x1296_25fps_regs, .hdr_mode = NO_HDR, @@ -1316,8 +1314,8 @@ static void sc3336_modify_fps_info(struct sc3336 *sc3336) { const struct sc3336_mode *mode = sc3336->cur_mode; - sc3336->cur_fps.denominator = mode->max_fps.denominator * sc3336->cur_vts / - mode->vts_def; + sc3336->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc3336->cur_vts; } static int sc3336_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc3338.c b/drivers/media/i2c/sc3338.c index 3cec60ed2490..ff451cd696a2 100644 --- a/drivers/media/i2c/sc3338.c +++ b/drivers/media/i2c/sc3338.c @@ -417,54 +417,55 @@ static int sc3338_set_gain_reg(struct sc3338 *sc3338, u32 gain) { struct i2c_client *client = sc3338->client; u32 coarse_again = 0, coarse_dgain = 0, fine_dgain = 0; - int ret = 0; + int ret = 0, gain_factor; if (gain < 128) gain = 128; else if (gain > SC3338_GAIN_MAX) gain = SC3338_GAIN_MAX; - if (gain < 1520) { + gain_factor = gain * 1000 / 128; + if (gain_factor < 1520) { coarse_again = 0x00; coarse_dgain = 0x00; - fine_dgain = gain * 128 / 1000; - } else if (gain < 3040) { + fine_dgain = gain_factor * 128 / 1000; + } else if (gain_factor < 3040) { coarse_again = 0x40; coarse_dgain = 0x00; - fine_dgain = gain * 128 / 1520; - } else if (gain < 6080) { + fine_dgain = gain_factor * 128 / 1520; + } else if (gain_factor < 6080) { coarse_again = 0x48; coarse_dgain = 0x00; - fine_dgain = gain * 128 / 3040; - } else if (gain < 12160) { + fine_dgain = gain_factor * 128 / 3040; + } else if (gain_factor < 12160) { coarse_again = 0x49; coarse_dgain = 0x00; - fine_dgain = gain * 128 / 6080; - } else if (gain < 24320) { + fine_dgain = gain_factor * 128 / 6080; + } else if (gain_factor < 24320) { coarse_again = 0x4b; coarse_dgain = 0x00; - fine_dgain = gain * 128 / 12160; - } else if (gain < 48640) { + fine_dgain = gain_factor * 128 / 12160; + } else if (gain_factor < 48640) { coarse_again = 0x4f; coarse_dgain = 0x00; - fine_dgain = gain * 128 / 24320; - } else if (gain < 48640 * 2) { + fine_dgain = gain_factor * 128 / 24320; + } else if (gain_factor < 48640 * 2) { //open dgain begin max digital gain 4X coarse_again = 0x5f; coarse_dgain = 0x00; - fine_dgain = gain * 128 / 48640; - } else if (gain < 48640 * 4) { + fine_dgain = gain_factor * 128 / 48640; + } else if (gain_factor < 48640 * 4) { coarse_again = 0x5f; coarse_dgain = 0x01; - fine_dgain = gain * 128 / 48640 / 2; - } else if (gain < 48640 * 8) { + fine_dgain = gain_factor * 128 / 48640 / 2; + } else if (gain_factor < 48640 * 8) { coarse_again = 0x5f; coarse_dgain = 0x03; - fine_dgain = gain * 128 / 48640 / 4; - } else if (gain < 48640 * 16) { + fine_dgain = gain_factor * 128 / 48640 / 4; + } else if (gain_factor < 48640 * 16) { coarse_again = 0x5f; coarse_dgain = 0x07; - fine_dgain = gain * 128 / 48640 / 8; + fine_dgain = gain_factor * 128 / 48640 / 8; } dev_dbg(&client->dev, "c_again: 0x%x, c_dgain: 0x%x, f_dgain: 0x%0x\n", coarse_again, coarse_dgain, fine_dgain); @@ -1132,8 +1133,8 @@ static void sc3338_modify_fps_info(struct sc3338 *sc3338) { const struct sc3338_mode *mode = sc3338->cur_mode; - sc3338->cur_fps.denominator = mode->max_fps.denominator * sc3338->cur_vts / - mode->vts_def; + sc3338->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc3338->cur_vts; } static int sc3338_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc401ai.c b/drivers/media/i2c/sc401ai.c index 42e43eb39f5a..450fbd8baaf0 100644 --- a/drivers/media/i2c/sc401ai.c +++ b/drivers/media/i2c/sc401ai.c @@ -1267,8 +1267,8 @@ static void sc401ai_modify_fps_info(struct sc401ai *sc401ai) { const struct sc401ai_mode *mode = sc401ai->cur_mode; - sc401ai->cur_fps.denominator = mode->max_fps.denominator * sc401ai->cur_vts / - mode->vts_def; + sc401ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc401ai->cur_vts; } static int sc401ai_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc4210.c b/drivers/media/i2c/sc4210.c index 787c1383517f..5f8958f1ad87 100644 --- a/drivers/media/i2c/sc4210.c +++ b/drivers/media/i2c/sc4210.c @@ -2325,8 +2325,8 @@ static void sc4210_modify_fps_info(struct sc4210 *sc4210) { const struct sc4210_mode *mode = sc4210->cur_mode; - sc4210->cur_fps.denominator = mode->max_fps.denominator * sc4210->cur_vts / - mode->vts_def; + sc4210->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc4210->cur_vts; } static int sc4210_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc4238.c b/drivers/media/i2c/sc4238.c index 3ca0a61d461f..8750d5a43427 100644 --- a/drivers/media/i2c/sc4238.c +++ b/drivers/media/i2c/sc4238.c @@ -2410,8 +2410,8 @@ static void sc4238_modify_fps_info(struct sc4238 *sc4238) { const struct sc4238_mode *mode = sc4238->cur_mode; - sc4238->cur_fps.denominator = mode->max_fps.denominator * sc4238->cur_vts / - mode->vts_def; + sc4238->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc4238->cur_vts; } static int sc4238_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc430cs.c b/drivers/media/i2c/sc430cs.c index 1783fd37926f..5900da6887fa 100644 --- a/drivers/media/i2c/sc430cs.c +++ b/drivers/media/i2c/sc430cs.c @@ -1138,8 +1138,8 @@ static void sc430cs_modify_fps_info(struct sc430cs *sc430cs) { const struct sc430cs_mode *mode = sc430cs->cur_mode; - sc430cs->cur_fps.denominator = mode->max_fps.denominator * sc430cs->cur_vts / - mode->vts_def; + sc430cs->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc430cs->cur_vts; } static int sc430cs_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc4336.c b/drivers/media/i2c/sc4336.c index abbfeb37e385..2fdf63b86f0c 100644 --- a/drivers/media/i2c/sc4336.c +++ b/drivers/media/i2c/sc4336.c @@ -1104,8 +1104,8 @@ static void sc4336_modify_fps_info(struct sc4336 *sc4336) { const struct sc4336_mode *mode = sc4336->cur_mode; - sc4336->cur_fps.denominator = mode->max_fps.denominator * sc4336->cur_vts / - mode->vts_def; + sc4336->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc4336->cur_vts; } static int sc4336_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc500ai.c b/drivers/media/i2c/sc500ai.c index 7797885804a0..00456f9b3b41 100644 --- a/drivers/media/i2c/sc500ai.c +++ b/drivers/media/i2c/sc500ai.c @@ -1396,8 +1396,8 @@ static void sc500ai_modify_fps_info(struct sc500ai *sc500ai) { const struct sc500ai_mode *mode = sc500ai->cur_mode; - sc500ai->cur_fps.denominator = mode->max_fps.denominator * sc500ai->cur_vts / - mode->vts_def; + sc500ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc500ai->cur_vts; } static int sc500ai_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/i2c/sc530ai.c b/drivers/media/i2c/sc530ai.c index b8d818cbe30d..b582ed65dd37 100644 --- a/drivers/media/i2c/sc530ai.c +++ b/drivers/media/i2c/sc530ai.c @@ -950,9 +950,10 @@ static int sc530ai_g_frame_interval(struct v4l2_subdev *sd, struct sc530ai *sc530ai = to_sc530ai(sd); const struct sc530ai_mode *mode = sc530ai->cur_mode; - mutex_lock(&sc530ai->mutex); - fi->interval = mode->max_fps; - mutex_unlock(&sc530ai->mutex); + if (sc530ai->streaming) + fi->interval = sc530ai->cur_fps; + else + fi->interval = mode->max_fps; return 0; } @@ -1635,8 +1636,8 @@ static void sc530ai_modify_fps_info(struct sc530ai *sc5330ai) { const struct sc530ai_mode *mode = sc5330ai->cur_mode; - sc5330ai->cur_fps.denominator = mode->max_fps.denominator * sc5330ai->cur_vts / - mode->vts_def; + sc5330ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc5330ai->cur_vts; } static int sc530ai_set_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 59592c0d8d15..1b41157eebc4 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1305,7 +1305,7 @@ int rkcif_get_linetime(struct rkcif_stream *stream) /***************************** stream operations ******************************/ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, - enum rkcif_yuvaddr_state stat) + enum rkcif_yuvaddr_state stat) { struct rkcif_device *dev = stream->cifdev; struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; @@ -1434,7 +1434,9 @@ static void rkcif_rx_buffer_free(struct rkcif_stream *stream) while (!list_empty(&stream->rx_buf_head_vicap)) { dbufs = list_first_entry(&stream->rx_buf_head_vicap, struct rkisp_rx_buf, list); - v4l2_subdev_call(sd, core, ioctl, RKISP_VICAP_CMD_RX_BUFFER_FREE, dbufs); + if (dbufs->is_init) + v4l2_subdev_call(sd, core, ioctl, + RKISP_VICAP_CMD_RX_BUFFER_FREE, dbufs); dma_buf_put(dbufs->dbuf); list_del(&dbufs->list); kfree(dbufs); @@ -1463,8 +1465,8 @@ static void rkcif_s_rx_buffer(struct rkcif_device *dev, struct rkisp_rx_buf *dbu dbufs->sequence < 15) { rx_buf = to_cif_rx_buf(dbufs); v4l2_info(&dev->v4l2_dev, - "s_buf seq %d dma addr %x, %lld\n", - dbufs->sequence, (u32)rx_buf->dummy.dma_addr, + "s_buf seq %d type %d, dma addr %x, %lld\n", + dbufs->sequence, dbufs->type, (u32)rx_buf->dummy.dma_addr, ktime_get_ns()); } v4l2_subdev_call(sd, video, s_rx_buffer, dbufs, NULL); @@ -1492,11 +1494,124 @@ static void rkcif_disable_skip_frame(struct rkcif_stream *stream) stream->skip_info.skip_en = false; } -static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, - int channel_id) +static void rkcif_rdbk_frame_end_toisp(struct rkcif_stream *stream, + struct rkcif_rx_buffer *buffer) { struct rkcif_device *dev = stream->cifdev; - struct rkisp_rx_buf *dbufs; + struct rkcif_sensor_info *sensor = &stream->cifdev->terminal_sensor; + u32 denominator, numerator; + u64 l_ts, m_ts, s_ts, time = 30000000LL; + int ret, fps = -1; + unsigned long flags; + + spin_lock_irqsave(&dev->hdr_lock, flags); + if (dev->rdbk_rx_buf[stream->id]) { + list_add_tail(&dev->rdbk_rx_buf[stream->id]->list, &stream->rx_buf_head); + dev->rdbk_rx_buf[stream->id] = buffer; + } else { + dev->rdbk_rx_buf[stream->id] = buffer; + } + + numerator = sensor->fi.interval.numerator; + denominator = sensor->fi.interval.denominator; + if (denominator && numerator) + time = numerator * 1000 / denominator * 1000 * 1000; + + if (dev->hdr.hdr_mode == HDR_X3 && + dev->rdbk_rx_buf[RDBK_L] && + dev->rdbk_rx_buf[RDBK_M] && + dev->rdbk_rx_buf[RDBK_S]) { + l_ts = dev->rdbk_rx_buf[RDBK_L]->dbufs.timestamp; + m_ts = dev->rdbk_rx_buf[RDBK_M]->dbufs.timestamp; + s_ts = dev->rdbk_rx_buf[RDBK_S]->dbufs.timestamp; + + if (m_ts < l_ts || s_ts < m_ts) { + v4l2_err(&dev->v4l2_dev, + "s/m/l frame err, timestamp s:%lld m:%lld l:%lld\n", + s_ts, m_ts, l_ts); + goto RDBK_TOISP_UNMATCH; + } + + if ((m_ts - l_ts) > time || (s_ts - m_ts) > time) { + ret = v4l2_subdev_call(sensor->sd, + video, + g_frame_interval, + &sensor->fi); + if (!ret) { + denominator = sensor->fi.interval.denominator; + numerator = sensor->fi.interval.numerator; + if (denominator && numerator) { + time = numerator * 1000 / denominator * 1000 * 1000; + fps = denominator / numerator; + } + } + + if ((m_ts - l_ts) > time || (s_ts - m_ts) > time) { + v4l2_err(&dev->v4l2_dev, + "timestamp no match, s:%lld m:%lld l:%lld, fps:%d\n", + s_ts, m_ts, l_ts, fps); + goto RDBK_TOISP_UNMATCH; + } + } + dev->rdbk_rx_buf[RDBK_M]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence; + dev->rdbk_rx_buf[RDBK_S]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence; + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs); + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs); + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_S]->dbufs); + dev->rdbk_rx_buf[RDBK_L] = NULL; + dev->rdbk_rx_buf[RDBK_M] = NULL; + dev->rdbk_rx_buf[RDBK_S] = NULL; + } else if (dev->hdr.hdr_mode == HDR_X2 && + dev->rdbk_rx_buf[RDBK_L] && dev->rdbk_rx_buf[RDBK_M]) { + l_ts = dev->rdbk_rx_buf[RDBK_L]->dbufs.timestamp; + s_ts = dev->rdbk_rx_buf[RDBK_M]->dbufs.timestamp; + + if (s_ts < l_ts) { + v4l2_err(&dev->v4l2_dev, + "s/l frame err, timestamp s:%lld l:%lld\n", + s_ts, l_ts); + goto RDBK_TOISP_UNMATCH; + } + + if ((s_ts - l_ts) > time) { + ret = v4l2_subdev_call(sensor->sd, + video, + g_frame_interval, + &sensor->fi); + if (!ret) { + denominator = sensor->fi.interval.denominator; + numerator = sensor->fi.interval.numerator; + if (denominator && numerator) { + time = numerator * 1000 / denominator * 1000 * 1000; + fps = denominator / numerator; + } + } + if ((s_ts - l_ts) > time) { + v4l2_err(&dev->v4l2_dev, + "timestamp no match, s:%lld l:%lld, fps:%d\n", + s_ts, l_ts, fps); + goto RDBK_TOISP_UNMATCH; + } + } + dev->rdbk_rx_buf[RDBK_M]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence; + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs); + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs); + dev->rdbk_rx_buf[RDBK_L] = NULL; + dev->rdbk_rx_buf[RDBK_M] = NULL; + } + + spin_unlock_irqrestore(&dev->hdr_lock, flags); + return; + +RDBK_TOISP_UNMATCH: + spin_unlock_irqrestore(&dev->hdr_lock, flags); +} + +static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_rx_buffer *rx_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; u32 frm0_addr_y; u32 frm1_addr_y; @@ -1516,12 +1631,12 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, if (!stream->curr_buf_toisp) { if (!list_empty(&stream->rx_buf_head)) { - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, + rx_buf = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); - if (dbufs) { - list_del(&dbufs->list); - stream->curr_buf_toisp = to_cif_rx_buf(dbufs); + if (rx_buf) { + list_del(&rx_buf->list); + stream->curr_buf_toisp = rx_buf; } } } @@ -1532,11 +1647,11 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, if (!stream->next_buf_toisp) { if (!list_empty(&stream->rx_buf_head)) { - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - stream->next_buf_toisp = to_cif_rx_buf(dbufs); + rx_buf = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (rx_buf) { + list_del(&rx_buf->list); + stream->next_buf_toisp = rx_buf; } else { stream->next_buf_toisp = stream->curr_buf_toisp; } @@ -1554,12 +1669,11 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, } static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, - int channel_id) + int channel_id) { struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_rx_buffer *buffer = NULL; - struct rkisp_rx_buf *dbufs = NULL; struct rkcif_rx_buffer *active_buf = NULL; struct sditf_priv *priv = dev->sditf[0]; u32 frm_addr_y; @@ -1584,12 +1698,11 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, else active_buf = stream->curr_buf_toisp; - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - stream->curr_buf_toisp = to_cif_rx_buf(dbufs); - buffer = stream->curr_buf_toisp; + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->curr_buf_toisp = buffer; } if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { if (!active_buf) @@ -1599,7 +1712,10 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; stream->last_frame_idx = stream->frame_idx; - rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->hdr.hdr_mode == NO_HDR) + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + else + rkcif_rdbk_frame_end_toisp(stream, active_buf); stream->buf_num_toisp--; } else { rkcif_s_rx_buffer(dev, &stream->next_buf_toisp->dbufs); @@ -1610,12 +1726,11 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf = NULL; else active_buf = stream->next_buf_toisp; - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - stream->next_buf_toisp = to_cif_rx_buf(dbufs); - buffer = stream->next_buf_toisp; + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->next_buf_toisp = buffer; } if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { if (!active_buf) @@ -1625,7 +1740,10 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; stream->last_frame_idx = stream->frame_idx; - rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->hdr.hdr_mode == NO_HDR) + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + else + rkcif_rdbk_frame_end_toisp(stream, active_buf); stream->buf_num_toisp--; } else { rkcif_s_rx_buffer(dev, &stream->curr_buf_toisp->dbufs); @@ -1635,6 +1753,8 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, if (stream->lack_buf_cnt) stream->lack_buf_cnt--; } else { + if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) + goto out_get_buf; if (stream->lack_buf_cnt < 2) stream->lack_buf_cnt++; if (dev->dummy_buf.vaddr) { @@ -1658,35 +1778,43 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, } if (stream->cifdev->rdbk_debug) v4l2_info(&stream->cifdev->v4l2_dev, - "hold buf %x\n", + "stream[%d] hold buf %x\n", + stream->id, (u32)stream->next_buf_toisp->dummy.dma_addr); } - if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO && active_buf) { + if (active_buf) { if (stream->frame_idx == 1) active_buf->dbufs.is_first = true; active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; stream->last_frame_idx = stream->frame_idx; - rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->hdr.hdr_mode == NO_HDR) + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + else + rkcif_rdbk_frame_end_toisp(stream, active_buf); } else { if (stream->cifdev->rdbk_debug && dev->dummy_buf.vaddr) v4l2_info(&stream->cifdev->v4l2_dev, - "loss frame %d\n", + "stream[%d] loss frame %d\n", + stream->id, stream->frame_idx - 1); } } out_get_buf: + stream->frame_phase_cache = stream->frame_phase; if (buffer) { rkcif_write_register(dev, frm_addr_y, buffer->dummy.dma_addr); if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "update, seq %d, reg %x, buf %x\n", + "stream[%d] update, seq %d, reg %x, buf %x\n", + stream->id, stream->frame_idx - 1, frm_addr_y, (u32)buffer->dummy.dma_addr); - } else if (dev->dummy_buf.vaddr) { + } else if (dev->dummy_buf.vaddr && priv && + priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { rkcif_write_register(dev, frm_addr_y, dev->dummy_buf.dma_addr); } @@ -1695,7 +1823,7 @@ out_get_buf: } static int rkcif_assign_new_buffer_pingpong_toisp(struct rkcif_stream *stream, - int init, int channel_id) + int init, int channel_id) { int ret = 0; @@ -1710,7 +1838,7 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) { struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; - struct rkisp_rx_buf *dbufs = NULL; + struct rkcif_rx_buffer *buffer = NULL; struct rkcif_rx_buffer *active_buf = NULL; u32 frm_addr_y; u32 vblank = 0; @@ -1724,7 +1852,8 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (dev->rdbk_debug > 2 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "addr check not equal 0x%x 0x%x\n", + "stream[%d] addr check not equal 0x%x 0x%x\n", + stream->id, (u32)stream->curr_buf_toisp->dummy.dma_addr, (u32)stream->next_buf_toisp->dummy.dma_addr); return; @@ -1751,7 +1880,8 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (dev->rdbk_debug > 2 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "check update, cur %lld, fe %lld, vb %u lack_buf %d\n", + "stream[%d] check update, cur %lld, fe %lld, vb %u lack_buf %d\n", + stream->id, cur_time, stream->readout.fe_timestamp, vblank_ns, stream->lack_buf_cnt); if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -1768,34 +1898,36 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (!list_empty(&stream->rx_buf_head)) { if (frame_phase == CIF_CSI_FRAME0_READY) { active_buf = stream->curr_buf_toisp; - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - stream->curr_buf_toisp = to_cif_rx_buf(dbufs); + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->curr_buf_toisp = buffer; rkcif_write_register(dev, frm_addr_y, stream->curr_buf_toisp->dummy.dma_addr); if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "check update, seq %d, addr 0x%x, buf 0x%x\n", + "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n", + stream->id, stream->frame_idx - 1, frm_addr_y, (u32)stream->curr_buf_toisp->dummy.dma_addr); stream->buf_num_toisp--; } } else if (frame_phase == CIF_CSI_FRAME1_READY) { active_buf = stream->next_buf_toisp; - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - stream->next_buf_toisp = to_cif_rx_buf(dbufs); + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->next_buf_toisp = buffer; rkcif_write_register(dev, frm_addr_y, stream->next_buf_toisp->dummy.dma_addr); if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "check update, seq %d, addr 0x%x, buf 0x%x\n", + "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n", + stream->id, stream->frame_idx - 1, frm_addr_y, (u32)stream->next_buf_toisp->dummy.dma_addr); stream->buf_num_toisp--; @@ -1808,7 +1940,8 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "early update, seq %d\n", + "stream[%d] early update, seq %d\n", + stream->id, stream->frame_idx - 1); if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) @@ -1972,7 +2105,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, } static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, - int channel_id) + int channel_id) { struct rkcif_device *dev = stream->cifdev; struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; @@ -2029,6 +2162,9 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, if (stream->curr_buf) { list_del(&stream->curr_buf->queue); buffer = stream->curr_buf; + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "stream[%d] update curr_buf 0x%x\n", + stream->id, buffer->buff_addr[0]); } } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { if (!stream->next_buf) @@ -2047,6 +2183,9 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, if (stream->next_buf) { list_del(&stream->next_buf->queue); buffer = stream->next_buf; + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "stream[%d] update next_buf 0x%x\n", + stream->id, buffer->buff_addr[0]); } } } @@ -2107,13 +2246,13 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, dbuf = stream->curr_buf->dbuf; if (dbuf) { - list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) + list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) { if (dbufs->dbuf == dbuf) break; - } else { - dbufs = &stream->curr_buf_toisp->dbufs; + } } - rkcif_s_rx_buffer(dev, dbufs); + if (dbufs) + rkcif_s_rx_buffer(dev, dbufs); stream->buf_num_toisp--; } } else { @@ -2187,12 +2326,16 @@ stop_dma: } else { dbufs = &stream->curr_buf_toisp->dbufs; } - rkcif_s_rx_buffer(dev, dbufs); + if (dbufs) + rkcif_s_rx_buffer(dev, dbufs); stream->buf_num_toisp--; - if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + + if (stream->frame_phase == CIF_CSI_FRAME0_READY && + stream->curr_buf) { list_add_tail(&stream->curr_buf->queue, &stream->buf_head); stream->curr_buf = NULL; - } else { + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY && + stream->next_buf) { list_add_tail(&stream->next_buf->queue, &stream->buf_head); stream->next_buf = NULL; } @@ -2326,28 +2469,33 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) static int rkcif_get_new_buffer_wake_up_mode_rdbk(struct rkcif_stream *stream) { - struct rkisp_rx_buf *dbufs = NULL; + struct rkcif_rx_buffer *buffer = NULL; + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; int ret = 0; unsigned long flags; + u32 frm_addr_y; + int frame_phase = 0; spin_lock_irqsave(&stream->vbq_lock, flags); if (!list_empty(&stream->rx_buf_head)) { if (stream->line_int_cnt % 2) { - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - stream->curr_buf_toisp = to_cif_rx_buf(dbufs); + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->curr_buf_toisp = buffer; } + frame_phase = CIF_CSI_FRAME0_READY; } else { - dbufs = list_first_entry(&stream->rx_buf_head, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - stream->next_buf_toisp = to_cif_rx_buf(dbufs); + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->next_buf_toisp = buffer; } + frame_phase = CIF_CSI_FRAME1_READY; } - stream->is_buf_active = true; if (stream->lack_buf_cnt) stream->lack_buf_cnt--; } else { @@ -2359,61 +2507,41 @@ static int rkcif_get_new_buffer_wake_up_mode_rdbk(struct rkcif_stream *stream) stream->curr_buf_toisp = stream->next_buf_toisp; else stream->next_buf_toisp = stream->curr_buf_toisp; - stream->is_buf_active = true; + buffer = stream->curr_buf_toisp; ret = 0; if (stream->cifdev->rdbk_debug) v4l2_info(&stream->cifdev->v4l2_dev, - "hold buf %x\n", + "stream[%d] hold buf %x\n", + stream->id, (u32)stream->next_buf_toisp->dummy.dma_addr); } else { - stream->is_buf_active = false; ret = -EINVAL; } } - spin_unlock_irqrestore(&stream->vbq_lock, flags); - - return ret; -} - -static int rkcif_update_new_buffer_wake_up_mode_rdbk(struct rkcif_stream *stream) -{ - struct rkcif_device *dev = stream->cifdev; - struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; - struct rkcif_rx_buffer *buffer = NULL; - u32 frm_addr_y; - int channel_id = stream->id; - int ret = 0; - unsigned long flags; - - if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || - mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || - mbus_cfg->type == V4L2_MBUS_CCP2) { - frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? - get_reg_index_of_frm0_y_addr(channel_id) : - get_reg_index_of_frm1_y_addr(channel_id); - } else { - frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? - get_dvp_reg_index_of_frm0_y_addr(channel_id) : - get_dvp_reg_index_of_frm1_y_addr(channel_id); - } - spin_lock_irqsave(&stream->vbq_lock, flags); - if (stream->is_buf_active) { - if (stream->frame_phase == CIF_CSI_FRAME0_READY) - buffer = stream->curr_buf_toisp; - else if (stream->frame_phase == CIF_CSI_FRAME1_READY) - buffer = stream->next_buf_toisp; - } - spin_unlock_irqrestore(&stream->vbq_lock, flags); if (buffer) { + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(stream->id) : + get_reg_index_of_frm1_y_addr(stream->id); + } else { + frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(stream->id) : + get_dvp_reg_index_of_frm1_y_addr(stream->id); + } rkcif_write_register(dev, frm_addr_y, buffer->dummy.dma_addr); if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "rdbk update, seq %d, reg %x, buf %x\n", + "stream[%d] rdbk update, seq %d, reg %x, buf %x\n", + stream->id, stream->frame_idx - 1, frm_addr_y, (u32)buffer->dummy.dma_addr); } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + return ret; } @@ -2557,7 +2685,7 @@ static void rkcif_csi_set_lvds_sav_eav(struct rkcif_stream *stream, } static unsigned char get_csi_fmt_val(const struct cif_input_fmt *cif_fmt_in, - struct csi_channel_info *csi_info) + struct csi_channel_info *csi_info) { unsigned char csi_fmt_val = 0; @@ -2697,8 +2825,8 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, } static int rkcif_csi_channel_set(struct rkcif_stream *stream, - struct csi_channel_info *channel, - enum v4l2_mbus_type mbus_type) + struct csi_channel_info *channel, + enum v4l2_mbus_type mbus_type) { unsigned int val = 0x0; struct rkcif_device *dev = stream->cifdev; @@ -2719,10 +2847,9 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream, CSI_DMA_END_INTSTAT(channel->id) | CSI_LINE_INTSTAT(channel->id))); - /* enable id0 frame start int for sof(long frame, for hdr) */ - if (channel->id == RKCIF_STREAM_MIPI_ID0) - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_START_INTEN(channel->id)); + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_START_INTEN(channel->id)); + if (detect_stream->is_line_wake_up) { rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, CSI_LINE_INTEN(channel->id)); @@ -3009,8 +3136,8 @@ static void rkcif_modify_frame_skip_config(struct rkcif_stream *stream) /*config reg for rk3588*/ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, - struct csi_channel_info *channel, - enum v4l2_mbus_type mbus_type, unsigned int mode) + struct csi_channel_info *channel, + enum v4l2_mbus_type mbus_type, unsigned int mode) { unsigned int val = 0x0; struct rkcif_device *dev = stream->cifdev; @@ -3223,7 +3350,6 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode (!stream->dma_en)) stream->to_en_dma = RKCIF_DMAEN_BY_ISP; } - rkcif_enable_dma_capture(stream, false); } } if (stream->state != RKCIF_STATE_STREAMING) { @@ -3299,8 +3425,8 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) } static bool rkcif_is_extending_line_for_height(struct rkcif_device *dev, - struct rkcif_stream *stream, - const struct cif_input_fmt *fmt) + struct rkcif_stream *stream, + const struct cif_input_fmt *fmt) { bool is_extended = false; struct rkmodule_hdr_cfg hdr_cfg; @@ -3381,7 +3507,7 @@ static int rkcif_queue_setup(struct vb2_queue *queue, } static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream, - int channel_id) + int channel_id) { struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; @@ -3578,8 +3704,8 @@ void rkcif_buf_queue(struct vb2_buffer *vb) stream->lack_buf_cnt) rkcif_check_buffer_update_pingpong(stream, stream->id); v4l2_dbg(2, rkcif_debug, &stream->cifdev->v4l2_dev, - "stream[%d] buf queue, index: %d\n", - stream->id, vb->index); + "stream[%d] buf queue, index: %d, dma_addr 0x%x\n", + stream->id, vb->index, cifbuf->buff_addr[0]); } void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num) @@ -3608,13 +3734,12 @@ void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num) if (!dev->is_thunderboot) rkcif_free_buffer(dev, &buf->dummy); else - list_add_tail(&buf->dbufs.list, &priv->buf_free_list); + list_add_tail(&buf->list_free, &priv->buf_free_list); } if (dev->is_thunderboot) { spin_unlock_irqrestore(&dev->buffree_lock, flags); schedule_work(&priv->buffree_work.work); - dev->is_thunderboot = false; } stream->dma_en &= ~RKCIF_DMAEN_BY_ISP; v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, @@ -3672,16 +3797,20 @@ int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) ret = rkcif_alloc_reserved_mem_buf(dev, buf); if (ret) { priv->buf_num = i; - v4l2_err(&dev->v4l2_dev, + v4l2_info(&dev->v4l2_dev, "reserved mem support alloc buf num %d, require buf num %d\n", i, buf_num); break; } + if (dev->rdbk_debug) + v4l2_info(&dev->v4l2_dev, + "stream[%d] buf addr 0x%llx\n", + stream->id, (u64)dummy->dma_addr); } else { ret = rkcif_alloc_buffer(dev, dummy); if (ret) { priv->buf_num = i; - v4l2_err(&dev->v4l2_dev, + v4l2_info(&dev->v4l2_dev, "alloc buf num %d, require buf num %d\n", i, buf_num); break; @@ -3690,7 +3819,7 @@ int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) } buf->dbufs.is_init = false; buf->dbufs.type = frm_type; - list_add_tail(&buf->dbufs.list, &stream->rx_buf_head); + list_add_tail(&buf->list, &stream->rx_buf_head); dummy->is_free = false; if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && i == 0) { buf->dbufs.is_first = true; @@ -3698,8 +3827,14 @@ int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) stream->buf_num_toisp--; } i++; - if (!dev->is_thunderboot && i >= buf_num) + if (!dev->is_thunderboot && i >= buf_num) { break; + } else if (i >= RKISP_VICAP_BUF_CNT_MAX) { + priv->buf_num = i; + v4l2_info(&dev->v4l2_dev, + "reserved mem alloc buf num %d\n", i); + break; + } v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "init rx_buf,dma_addr 0x%llx size: 0x%x\n", (u64)dummy->dma_addr, pixm->plane_fmt[0].sizeimage); @@ -3906,7 +4041,7 @@ static void rkcif_detach_sync_mode(struct rkcif_device *cif_dev) } void rkcif_do_stop_stream(struct rkcif_stream *stream, - unsigned int mode) + unsigned int mode) { struct rkcif_vdev_node *node = &stream->vnode; struct rkcif_device *dev = stream->cifdev; @@ -3917,6 +4052,10 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, bool can_reset = true; int i; unsigned long flags; + u32 vblank = 0; + u32 vblank_ns = 0; + u64 cur_time = 0; + u64 fe_time = 0; mutex_lock(&dev->stream_lock); @@ -3925,13 +4064,25 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, if (mode == stream->cur_stream_mode) { stream->stopping = true; - - ret = wait_event_timeout(stream->wq_stopped, - stream->state != RKCIF_STATE_STREAMING, - msecs_to_jiffies(1000)); - if (!ret) { + if (!dev->sensor_linetime) + dev->sensor_linetime = rkcif_get_linetime(stream); + vblank = rkcif_get_sensor_vblank(dev); + vblank_ns = vblank * dev->sensor_linetime; + spin_lock_irqsave(&stream->fps_lock, flags); + fe_time = stream->readout.fe_timestamp; + spin_unlock_irqrestore(&stream->fps_lock, flags); + cur_time = ktime_get_ns(); + if (cur_time > fe_time && cur_time - fe_time < (vblank_ns - 200000)) { rkcif_stream_stop(stream); stream->stopping = false; + } else { + ret = wait_event_timeout(stream->wq_stopped, + stream->state != RKCIF_STATE_STREAMING, + msecs_to_jiffies(1000)); + if (!ret) { + rkcif_stream_stop(stream); + stream->stopping = false; + } } media_pipeline_stop(&node->vdev.entity); @@ -3977,8 +4128,12 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, rkcif_release_rdbk_buf(stream); rkcif_rx_buffer_free(stream); - list_for_each_entry(buf, &stream->buf_head, queue) + list_for_each_entry(buf, &stream->buf_head, queue) { + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "stream[%d] buf return addr 0x%x\n", + stream->id, buf->buff_addr[0]); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } INIT_LIST_HEAD(&stream->buf_head); stream->lack_buf_cnt = 0; stream->dma_en &= ~RKCIF_DMAEN_BY_VICAP; @@ -3988,18 +4143,6 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, ret = dev->pipe.close(&dev->pipe); if (ret < 0) v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", ret); - pm_runtime_put_sync(dev->dev); - v4l2_pipeline_pm_put(&node->vdev.entity); - if (dev->sditf_cnt > 1) { - for (i = 0; i < dev->sditf_cnt; i++) - ret |= v4l2_subdev_call(dev->sditf[i]->sensor_sd, - core, - s_power, - 0); - if (ret < 0) - v4l2_err(v4l2_dev, "set power off fail, ret %d\n", - ret); - } if (dev->hdr.hdr_mode == HDR_X2) { if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY && dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY) { @@ -4024,7 +4167,6 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, if (dev->can_be_reset && dev->chip_id >= CHIP_RK3588_CIF) rkcif_do_soft_reset(dev); if (dev->can_be_reset && can_reset) { - rkcif_do_cru_reset(dev); dev->can_be_reset = false; dev->reset_work_cancel = true; dev->early_line = 0; @@ -4949,7 +5091,6 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) struct rkmodule_hdr_cfg hdr_cfg; int rkmodule_stream_seq = RKMODULE_START_STREAM_DEFAULT; int ret; - int i = 0; v4l2_info(&dev->v4l2_dev, "stream[%d] start streaming\n", stream->id); @@ -5018,29 +5159,6 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) } if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) { - /* enable clocks/power-domains */ - ret = pm_runtime_resume_and_get(dev->dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Failed to get runtime pm, %d\n", - ret); - goto destroy_buf; - } - ret = v4l2_pipeline_pm_get(&node->vdev.entity); - if (ret < 0) { - v4l2_err(v4l2_dev, "cif pipeline_pm_get fail %d\n", - ret); - goto destroy_buf; - } - if (dev->sditf_cnt > 1) { - for (i = 0; i < dev->sditf_cnt; i++) - ret |= v4l2_subdev_call(dev->sditf[i]->sensor_sd, - core, - s_power, - 1); - if (ret < 0) - v4l2_err(v4l2_dev, "set power on fail, ret %d\n", - ret); - } ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true); if (ret < 0) { v4l2_err(v4l2_dev, "open cif pipeline failed %d\n", @@ -5189,8 +5307,8 @@ static int rkcif_init_vb2_queue(struct vb2_queue *q, } int rkcif_set_fmt(struct rkcif_stream *stream, - struct v4l2_pix_format_mplane *pixm, - bool try) + struct v4l2_pix_format_mplane *pixm, + bool try) { struct rkcif_device *dev = stream->cifdev; const struct cif_output_fmt *fmt; @@ -5438,6 +5556,7 @@ static int rkcif_fh_open(struct file *filp) struct rkcif_stream *stream = to_rkcif_stream(vnode); struct rkcif_device *cifdev = stream->cifdev; int ret; + int i = 0; ret = rkcif_attach_hw(cifdev); if (ret) @@ -5466,7 +5585,18 @@ static int rkcif_fh_open(struct file *filp) if (ret < 0) vb2_fop_release(filp); } - + if (cifdev->sditf_cnt > 1) { + for (i = 0; i < cifdev->sditf_cnt; i++) { + if (cifdev->sditf[i]->sensor_sd) + ret |= v4l2_subdev_call(cifdev->sditf[i]->sensor_sd, + core, + s_power, + 1); + } + if (ret < 0) + v4l2_err(vdev, "set sensor power on fail, ret %d\n", + ret); + } return ret; } @@ -5477,12 +5607,25 @@ static int rkcif_fh_release(struct file *filp) struct rkcif_stream *stream = to_rkcif_stream(vnode); struct rkcif_device *cifdev = stream->cifdev; int ret = 0; + int i = 0; ret = vb2_fop_release(filp); if (!ret) v4l2_pipeline_pm_put(&vnode->vdev.entity); pm_runtime_put_sync(cifdev->dev); + if (cifdev->sditf_cnt > 1) { + for (i = 0; i < cifdev->sditf_cnt; i++) { + if (cifdev->sditf[i]->sensor_sd) + ret |= v4l2_subdev_call(cifdev->sditf[i]->sensor_sd, + core, + s_power, + 0); + } + if (ret < 0) + v4l2_err(vdev, "set sensor power on fail, ret %d\n", + ret); + } return ret; } @@ -5675,7 +5818,7 @@ static int rkcif_querycap(struct file *file, void *priv, } static __maybe_unused int rkcif_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cap) + struct v4l2_cropcap *cap) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; @@ -5702,7 +5845,7 @@ static __maybe_unused int rkcif_cropcap(struct file *file, void *fh, } static int rkcif_s_selection(struct file *file, void *fh, - struct v4l2_selection *s) + struct v4l2_selection *s) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; @@ -5737,7 +5880,7 @@ err: } static int rkcif_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) + struct v4l2_selection *s) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; @@ -5770,9 +5913,7 @@ static int rkcif_g_selection(struct file *file, void *fh, s->r.width = stream->pixm.width; s->r.height = stream->pixm.height; } - } - - if (s->target == V4L2_SEL_TGT_CROP) { + } else if (s->target == V4L2_SEL_TGT_CROP) { if (stream->crop_mask & (CROP_SRC_USR_MASK | CROP_SRC_SENSOR_MASK)) { s->r = stream->crop[CROP_SRC_ACT]; } else { @@ -5781,6 +5922,8 @@ static int rkcif_g_selection(struct file *file, void *fh, s->r.width = stream->pixm.width; s->r.height = stream->pixm.height; } + } else { + goto err; } return ret; @@ -5897,10 +6040,10 @@ void rkcif_set_fps(struct rkcif_stream *stream, struct rkcif_fps *fps) } static int rkcif_do_reset_work(struct rkcif_device *cif_dev, - enum rkmodule_reset_src reset_src); + enum rkmodule_reset_src reset_src); static long rkcif_ioctl_default(struct file *file, void *fh, - bool valid_prio, unsigned int cmd, void *arg) + bool valid_prio, unsigned int cmd, void *arg) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; @@ -6202,8 +6345,8 @@ static int rkcif_lvds_sd_get_fmt(struct v4l2_subdev *sd, } static struct v4l2_rect *rkcif_lvds_sd_get_crop(struct rkcif_lvds_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - enum v4l2_subdev_format_whence which) + struct v4l2_subdev_pad_config *cfg, + enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_crop(&subdev->sd, cfg, RKCIF_LVDS_PAD_SINK); @@ -6212,8 +6355,8 @@ static struct v4l2_rect *rkcif_lvds_sd_get_crop(struct rkcif_lvds_subdev *subdev } static int rkcif_lvds_sd_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) { struct rkcif_lvds_subdev *subdev = container_of(sd, struct rkcif_lvds_subdev, sd); struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd); @@ -6228,8 +6371,8 @@ static int rkcif_lvds_sd_set_selection(struct v4l2_subdev *sd, } static int rkcif_lvds_sd_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) { struct rkcif_lvds_subdev *subdev = container_of(sd, struct rkcif_lvds_subdev, sd); struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd); @@ -6314,7 +6457,7 @@ static int rkcif_lvds_sd_s_power(struct v4l2_subdev *sd, int on) } static int rkcif_sof_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { if (sub->type == V4L2_EVENT_FRAME_SYNC || sub->type == V4L2_EVENT_RESET_DEV) @@ -6534,7 +6677,7 @@ void rkcif_unregister_dvp_sof_subdev(struct rkcif_device *dev) } void rkcif_vb_done_oneframe(struct rkcif_stream *stream, - struct vb2_v4l2_buffer *vb_done) + struct vb2_v4l2_buffer *vb_done) { const struct cif_output_fmt *fmt = stream->cif_fmt_out; u32 i; @@ -6642,7 +6785,7 @@ void rkcif_irq_oneframe(struct rkcif_device *cif_dev) } static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev, - unsigned int intstat) + unsigned int intstat) { if (intstat & CSI_FRAME_END_ID0) { if ((intstat & CSI_FRAME_END_ID0) == @@ -6716,7 +6859,7 @@ static int rkcif_dvp_g_ch_id(struct v4l2_device *v4l2_dev, } static int rkcif_dvp_g_ch_id_by_fe(struct v4l2_device *v4l2_dev, - u32 intstat) + u32 intstat) { if (intstat & DVP_ALL_END_ID0) { if ((intstat & DVP_ALL_END_ID0) == @@ -7269,9 +7412,9 @@ RDBK_FRM_UNMATCH: } static void rkcif_buf_done_prepare(struct rkcif_stream *stream, - struct rkcif_buffer *active_buf, - int mipi_id, - u32 mode) + struct rkcif_buffer *active_buf, + int mipi_id, + u32 mode) { unsigned long flags; struct vb2_v4l2_buffer *vb_done = NULL; @@ -7421,6 +7564,50 @@ static void rkcif_line_wake_up(struct rkcif_stream *stream, int mipi_id) rkcif_buf_done_prepare(stream, active_buf, mipi_id, mode); } +static void rkcif_store_last_buf_for_online(struct rkcif_stream *stream, + struct rkcif_rx_buffer *buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + u32 frm0_addr_y, frm1_addr_y; + + INIT_LIST_HEAD(&stream->rx_buf_head); + stream->curr_buf_toisp = buf; + stream->next_buf_toisp = buf; + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm0_addr_y = get_reg_index_of_frm0_y_addr(stream->id); + frm1_addr_y = get_reg_index_of_frm1_y_addr(stream->id); + } else { + frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(stream->id); + frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(stream->id); + } + rkcif_write_register(dev, frm0_addr_y, + buf->dummy.dma_addr); + rkcif_write_register(dev, frm1_addr_y, + buf->dummy.dma_addr); +} + +static void rkcif_release_unnecessary_buf_for_online(struct rkcif_stream *stream, + struct rkcif_rx_buffer *buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; + struct rkcif_rx_buffer *rx_buf = NULL; + unsigned long flags; + int i = 0; + + spin_lock_irqsave(&priv->cif_dev->buffree_lock, flags); + for (i = 0; i < priv->buf_num; i++) { + rx_buf = &stream->rx_buf[i]; + if (rx_buf && (!rx_buf->dummy.is_free) && rx_buf != buf) + list_add_tail(&rx_buf->list_free, &priv->buf_free_list); + } + spin_unlock_irqrestore(&priv->cif_dev->buffree_lock, flags); + schedule_work(&priv->buffree_work.work); +} + static int rkcif_stop_dma_capture(struct rkcif_stream *stream); static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) { @@ -7457,24 +7644,35 @@ static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) (u32)active_buf->dummy.dma_addr); if (!ret) { priv = stream->cifdev->sditf[0]; - if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + if (stream->cur_stream_mode & RKCIF_STREAM_MODE_TOISP_RDBK) { spin_lock_irqsave(&stream->vbq_lock, flags); - if ((stream->frame_idx - 1) == stream->last_rx_buf_idx && - stream->cifdev->is_thunderboot) { + if (stream->cifdev->is_thunderboot && + (stream->frame_idx - 1) == stream->last_rx_buf_idx) { stream->cur_stream_mode &= ~RKCIF_STREAM_MODE_TOISP_RDBK; stream->cur_stream_mode |= RKCIF_STREAM_MODE_TOISP; - if (stream->cifdev->hdr.hdr_mode == NO_HDR) - stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; - rkcif_stop_dma_capture(stream); - active_buf->dbufs.is_switch = true; stream->cifdev->wait_line = 0; stream->is_line_wake_up = false; + if (stream->cifdev->hdr.hdr_mode == NO_HDR || + (priv->hdr_cfg.hdr_mode == HDR_X2 && stream->id == 1) || + (priv->hdr_cfg.hdr_mode == HDR_X3 && stream->id == 2)) { + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + rkcif_stop_dma_capture(stream); + } + active_buf->dbufs.is_switch = true; + if ((priv->hdr_cfg.hdr_mode == HDR_X2 && stream->id != 1) || + (priv->hdr_cfg.hdr_mode == HDR_X3 && stream->id != 2)) { + rkcif_store_last_buf_for_online(stream, active_buf); + stream->is_change_toisp = true; + } } spin_unlock_irqrestore(&stream->vbq_lock, flags); active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; stream->last_frame_idx = stream->frame_idx; - rkcif_s_rx_buffer(stream->cifdev, &active_buf->dbufs); + if (stream->cifdev->hdr.hdr_mode == NO_HDR) + rkcif_s_rx_buffer(stream->cifdev, &active_buf->dbufs); + else + rkcif_rdbk_frame_end_toisp(stream, active_buf); stream->buf_num_toisp--; } } @@ -7488,6 +7686,12 @@ static void rkcif_deal_readout_time(struct rkcif_stream *stream) spin_lock_irqsave(&stream->fps_lock, flags); stream->readout.fe_timestamp = ktime_get_ns(); + + if (cif_dev->inf_id == RKCIF_DVP) { + spin_unlock_irqrestore(&stream->fps_lock, flags); + return; + } + if (stream->id == RKCIF_STREAM_MIPI_ID0) detect_stream->readout.readout_time = stream->readout.fe_timestamp - stream->readout.fs_timestamp; @@ -7538,8 +7742,7 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, spin_unlock_irqrestore(&stream->fps_lock, flags); } - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) - rkcif_deal_readout_time(stream); + rkcif_deal_readout_time(stream); if (!stream->is_line_wake_up) { ret = rkcif_assign_new_buffer_pingpong(stream, @@ -7562,8 +7765,8 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, } static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev, - struct rkcif_stream *stream, - int mipi_id) + struct rkcif_stream *stream, + int mipi_id) { if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) { @@ -7586,8 +7789,6 @@ static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev, rkcif_assign_new_buffer_pingpong_toisp(stream, RKCIF_YUV_ADDR_STATE_UPDATE, mipi_id); - else - rkcif_update_new_buffer_wake_up_mode_rdbk(stream); } static u32 rkcif_get_sof(struct rkcif_device *cif_dev) @@ -7627,7 +7828,7 @@ static void rkcif_set_sof(struct rkcif_device *cif_dev, u32 seq) } static int rkcif_do_reset_work(struct rkcif_device *cif_dev, - enum rkmodule_reset_src reset_src) + enum rkmodule_reset_src reset_src) { struct rkcif_pipeline *p = &cif_dev->pipe; struct rkcif_stream *stream = NULL; @@ -8225,6 +8426,18 @@ static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream) } if (stream->is_line_wake_up) { rkcif_modify_line_int(stream, true); + if (cif_dev->hdr.hdr_mode == HDR_X2) { + cif_dev->stream[0].is_line_wake_up = true; + cif_dev->stream[0].is_line_inten = true; + cif_dev->stream[0].line_int_cnt = stream->line_int_cnt; + } else if (cif_dev->hdr.hdr_mode == HDR_X3) { + cif_dev->stream[0].is_line_wake_up = true; + cif_dev->stream[1].is_line_wake_up = true; + cif_dev->stream[0].is_line_inten = true; + cif_dev->stream[1].is_line_inten = true; + cif_dev->stream[0].line_int_cnt = stream->line_int_cnt; + cif_dev->stream[1].line_int_cnt = stream->line_int_cnt; + } stream->is_line_inten = true; } } @@ -8502,15 +8715,10 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, if (stream->cifdev->rdbk_debug && stream->frame_idx < 15) v4l2_info(&priv->cif_dev->v4l2_dev, - "toisp fe %d\n", + "stream[%d] toisp fe %d\n", + stream->id, stream->frame_idx - 1); - if (stream->to_en_dma) - rkcif_enable_dma_capture(stream, false); - if (stream->to_en_scale) { - stream->to_en_scale = false; - rkcif_scale_start(stream->scale_vdev); - } switch (ch) { case RKCIF_TOISP_CH0: val = TOISP_END_CH0(index); @@ -8539,8 +8747,15 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, if (stream->cifdev->rdbk_debug && stream->frame_idx < 15) v4l2_info(&priv->cif_dev->v4l2_dev, - "toisp sof seq %d\n", + "stream[%d] toisp sof seq %d\n", + stream->id, stream->frame_idx - 1); + if (stream->to_en_dma) + rkcif_enable_dma_capture(stream, false); + if (stream->to_en_scale) { + stream->to_en_scale = false; + rkcif_scale_start(stream->scale_vdev); + } switch (ch) { case RKCIF_TOISP_CH0: val = TOISP_FS_CH0(index); @@ -8707,9 +8922,11 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode) detect_stream->frame_idx++; if (detect_stream->cifdev->rdbk_debug && - detect_stream->frame_idx < 15) + detect_stream->frame_idx < 15 && + (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode)) v4l2_info(&cif_dev->v4l2_dev, - "sof %d %lld\n", + "stream[%d] sof %d %lld\n", + detect_stream->id, detect_stream->frame_idx - 1, ktime_get_ns()); } @@ -8874,9 +9091,11 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) break; } if (stream->cifdev->rdbk_debug && - stream->frame_idx < 15) + stream->frame_idx < 15 && + (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode)) v4l2_info(&cif_dev->v4l2_dev, - "fe %d, phase %d, %lld\n", + "stream[%d] fe %d, phase %d, %lld\n", + stream->id, stream->frame_idx - 1, stream->frame_phase, ktime_get_ns()); @@ -8895,8 +9114,15 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) rkcif_modify_frame_skip_config(stream); } else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { rkcif_update_stream_toisp(cif_dev, stream, mipi_id); - } else if (stream->is_change_toisp) { - sditf_change_to_online(cif_dev->sditf[0]); + } + if (stream->is_change_toisp) { + stream->is_change_toisp = false; + if ((cif_dev->hdr.hdr_mode == HDR_X2 && stream->id != 1) || + (cif_dev->hdr.hdr_mode == HDR_X3 && stream->id != 2)) + rkcif_release_unnecessary_buf_for_online(stream, + stream->curr_buf_toisp); + else + sditf_change_to_online(cif_dev->sditf[0]); } spin_lock_irqsave(&stream->vbq_lock, flags); @@ -8950,6 +9176,8 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (!ret) stream->is_finish_stop_dma = true; } + if (stream->to_en_dma) + rkcif_enable_dma_capture(stream, false); } if (intstat & CSI_LINE_INTSTAT_V1(i)) { stream = &cif_dev->stream[i]; @@ -9122,9 +9350,6 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) __func__); } - if (intstat & CSI_FRAME0_START_ID0 || intstat & CSI_FRAME1_START_ID0) - rkcif_deal_sof(cif_dev); - for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { if (intstat & CSI_LINE_INTSTAT(i)) { stream = &cif_dev->stream[i]; @@ -9139,11 +9364,6 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) } } - /* if do not reach frame dma end, return irq */ - mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat); - if (mipi_id < 0) - return; - for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat); @@ -9200,8 +9420,33 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) detect_stream->fs_cnt_in_single_frame--; } } + cif_dev->irq_stats.all_frm_end_cnt++; + } + for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + if (intstat & CSI_START_INTSTAT(i)) { + stream = &cif_dev->stream[i]; + if (i == 0) { + rkcif_deal_sof(cif_dev); + } else { + spin_lock_irqsave(&stream->fps_lock, flags); + stream->readout.fs_timestamp = ktime_get_ns(); + stream->frame_idx++; + spin_unlock_irqrestore(&stream->fps_lock, flags); + } + stream->is_in_vblank = false; + } + if (intstat & CSI_LINE_INTSTAT(i)) { + stream = &cif_dev->stream[i]; + if (stream->is_line_inten) { + stream->line_int_cnt++; + rkcif_line_wake_up(stream, stream->id); + rkcif_modify_line_int(stream, false); + stream->is_line_inten = false; + } + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "%s: id0 cur line:%d\n", __func__, lastline & 0x3fff); + } } - cif_dev->irq_stats.all_frm_end_cnt++; } else { u32 lastline, lastpix, ctl; u32 cif_frmst, frmid, int_en; diff --git a/drivers/media/platform/rockchip/cif/common.c b/drivers/media/platform/rockchip/cif/common.c index d9493b2adf6c..76a4d1ade82b 100644 --- a/drivers/media/platform/rockchip/cif/common.c +++ b/drivers/media/platform/rockchip/cif/common.c @@ -345,6 +345,8 @@ int rkcif_alloc_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffe void rkcif_free_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf) { struct rkcif_dummy_buffer *dummy = &buf->dummy; + struct media_pad *pad = NULL; + struct v4l2_subdev *sd; if (buf->dummy.is_free) return; @@ -353,7 +355,26 @@ void rkcif_free_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffe v4l2_info(&dev->v4l2_dev, "free reserved mem addr 0x%x\n", (u32)dummy->dma_addr); - + if (dev->sditf[0]) { + if (dev->sditf[0]->is_combine_mode) + pad = media_entity_remote_pad(&dev->sditf[0]->pads[1]); + else + pad = media_entity_remote_pad(&dev->sditf[0]->pads[0]); + } else { + v4l2_info(&dev->v4l2_dev, + "not find sditf\n"); + return; + } + if (pad) { + sd = media_entity_to_v4l2_subdev(pad->entity); + } else { + v4l2_info(&dev->v4l2_dev, + "not find remote pad\n"); + return; + } + if (buf->dbufs.is_init) + v4l2_subdev_call(sd, core, ioctl, + RKISP_VICAP_CMD_RX_BUFFER_FREE, &buf->dbufs); if (dummy->is_need_vaddr) dummy->dbuf->ops->vunmap(dummy->dbuf, dummy->vaddr); #ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index edcb6690f7b4..58fbc4682795 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -442,8 +442,14 @@ enum rkcif_capture_mode { RKCIF_TO_ISP_DMA, }; +/* + * list: used for buf rotation + * list_free: only used to release buf asynchronously + */ struct rkcif_rx_buffer { int buf_idx; + struct list_head list; + struct list_head list_free; struct rkisp_rx_buf dbufs; struct rkcif_dummy_buffer dummy; struct rkisp_thunderboot_shmem shmem; @@ -789,6 +795,7 @@ struct rkcif_device { bool can_be_reset; struct rkmodule_hdr_cfg hdr; struct rkcif_buffer *rdbk_buf[RDBK_MAX]; + struct rkcif_rx_buffer *rdbk_rx_buf[RDBK_MAX]; struct rkcif_luma_vdev luma_vdev; struct rkcif_lvds_subdev lvds_subdev; struct rkcif_dvp_sof_subdev dvp_sof_subdev; diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 7075a19b70d4..847da7af7875 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -38,20 +38,17 @@ static void sditf_buffree_work(struct work_struct *work) struct sditf_priv, buffree_work); struct rkcif_rx_buffer *rx_buf = NULL; - struct rkisp_rx_buf *dbufs = NULL; unsigned long flags; LIST_HEAD(local_list); spin_lock_irqsave(&priv->cif_dev->buffree_lock, flags); list_replace_init(&priv->buf_free_list, &local_list); while (!list_empty(&local_list)) { - dbufs = list_first_entry(&local_list, - struct rkisp_rx_buf, list); - if (dbufs) { - list_del(&dbufs->list); - rx_buf = container_of(dbufs, struct rkcif_rx_buffer, dbufs); - if (rx_buf) - rkcif_free_reserved_mem_buf(priv->cif_dev, rx_buf); + rx_buf = list_first_entry(&local_list, + struct rkcif_rx_buffer, list_free); + if (rx_buf) { + list_del(&rx_buf->list_free); + rkcif_free_reserved_mem_buf(priv->cif_dev, rx_buf); } } spin_unlock_irqrestore(&priv->cif_dev->buffree_lock, flags); @@ -218,14 +215,31 @@ static int sditf_init_buf(struct sditf_priv *priv) int ret = 0; if (priv->hdr_cfg.hdr_mode == HDR_X2) { - ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num); - if (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) - ret = rkcif_init_rx_buf(&cif_dev->stream[1], priv->buf_num); + if (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + if (cif_dev->is_thunderboot) + cif_dev->resmem_size /= 2; + ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num); + if (cif_dev->is_thunderboot) + cif_dev->resmem_pa += cif_dev->resmem_size; + ret |= rkcif_init_rx_buf(&cif_dev->stream[1], priv->buf_num); + } else { + ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num); + } } else if (priv->hdr_cfg.hdr_mode == HDR_X3) { - ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num); - ret |= rkcif_init_rx_buf(&cif_dev->stream[1], priv->buf_num); - if (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) - ret = rkcif_init_rx_buf(&cif_dev->stream[2], priv->buf_num); + if (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + if (cif_dev->is_thunderboot) + cif_dev->resmem_size /= 3; + ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num); + if (cif_dev->is_thunderboot) + cif_dev->resmem_pa += cif_dev->resmem_size; + ret |= rkcif_init_rx_buf(&cif_dev->stream[1], priv->buf_num); + if (cif_dev->is_thunderboot) + cif_dev->resmem_pa += cif_dev->resmem_size; + ret |= rkcif_init_rx_buf(&cif_dev->stream[2], priv->buf_num); + } else { + ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num); + ret |= rkcif_init_rx_buf(&cif_dev->stream[1], priv->buf_num); + } } else { if (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num); @@ -249,6 +263,7 @@ static void sditf_free_buf(struct sditf_priv *priv) } else { rkcif_free_rx_buf(&cif_dev->stream[0], priv->buf_num); } + cif_dev->is_thunderboot = false; } static int sditf_get_selection(struct v4l2_subdev *sd, @@ -518,6 +533,10 @@ void sditf_change_to_online(struct sditf_priv *priv) } if (priv->hdr_cfg.hdr_mode == NO_HDR) rkcif_free_rx_buf(&cif_dev->stream[0], priv->buf_num); + else if (priv->hdr_cfg.hdr_mode == HDR_X2) + rkcif_free_rx_buf(&cif_dev->stream[1], priv->buf_num); + else if (priv->hdr_cfg.hdr_mode == HDR_X3) + rkcif_free_rx_buf(&cif_dev->stream[2], priv->buf_num); } static int sditf_start_stream(struct sditf_priv *priv) @@ -622,6 +641,7 @@ static int sditf_s_power(struct v4l2_subdev *sd, int on) { struct sditf_priv *priv = to_sditf_priv(sd); struct rkcif_device *cif_dev = priv->cif_dev; + struct rkcif_vdev_node *node = &cif_dev->stream[0].vnode; int ret = 0; if (!on && atomic_dec_return(&priv->power_cnt)) @@ -634,10 +654,13 @@ static int sditf_s_power(struct v4l2_subdev *sd, int on) v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, "%s, toisp mode %d, hdr %d, set power %d\n", __func__, priv->toisp_inf.link_mode, priv->hdr_cfg.hdr_mode, on); - if (on) + if (on) { ret = pm_runtime_resume_and_get(cif_dev->dev); - else + ret |= v4l2_pipeline_pm_get(&node->vdev.entity); + } else { + v4l2_pipeline_pm_put(&node->vdev.entity); pm_runtime_put_sync(cif_dev->dev); + } } return ret; } @@ -654,6 +677,7 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, unsigned long flags, buffree_flags; u32 diff_time = 1000000; u32 early_time = 0; + bool is_free = false; if (!buf) { v4l2_err(&cif_dev->v4l2_dev, "buf is NULL\n"); @@ -694,15 +718,18 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, stream->last_rx_buf_idx = dbufs->sequence + 1; if (!list_empty(&stream->rx_buf_head) && - cif_dev->is_thunderboot) { + cif_dev->is_thunderboot && + (dbufs->type == BUF_SHORT || + (dbufs->type != BUF_SHORT && (!dbufs->is_switch)))) { spin_lock_irqsave(&cif_dev->buffree_lock, buffree_flags); - list_add_tail(&dbufs->list, &priv->buf_free_list); + list_add_tail(&rx_buf->list_free, &priv->buf_free_list); spin_unlock_irqrestore(&cif_dev->buffree_lock, buffree_flags); schedule_work(&priv->buffree_work.work); + is_free = true; } - if (!rx_buf->dummy.is_free) { - list_add_tail(&dbufs->list, &stream->rx_buf_head); + if (!is_free && (!dbufs->is_switch)) { + list_add_tail(&rx_buf->list, &stream->rx_buf_head); rkcif_assign_check_buffer_update_toisp(stream); if (cif_dev->rdbk_debug) { u32 offset = 0; @@ -721,7 +748,7 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, } } - if (dbufs->is_switch) { + if (dbufs->is_switch && dbufs->type == BUF_SHORT) { if (stream->is_in_vblank) sditf_change_to_online(priv); else @@ -732,7 +759,7 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, spin_unlock_irqrestore(&stream->vbq_lock, flags); if (dbufs->runtime_us && cif_dev->early_line == 0) { - if (cif_dev->sensor_linetime) + if (!cif_dev->sensor_linetime) cif_dev->sensor_linetime = rkcif_get_linetime(stream); cif_dev->isp_runtime_max = dbufs->runtime_us; if (cif_dev->is_thunderboot) @@ -748,10 +775,10 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, if (cif_dev->rdbk_debug && dbufs->sequence < 15) v4l2_info(&cif_dev->v4l2_dev, - "%s, isp runtime %d, line time %d, early_line %d, line_intr_cnt %d, seq %d, dma_addr %x\n", + "%s, isp runtime %d, line time %d, early_line %d, line_intr_cnt %d, seq %d, type %d, dma_addr %x\n", __func__, dbufs->runtime_us, cif_dev->sensor_linetime, cif_dev->early_line, cif_dev->wait_line_cache, - dbufs->sequence, (u32)rx_buf->dummy.dma_addr); + dbufs->sequence, dbufs->type, (u32)rx_buf->dummy.dma_addr); } else { if (dbufs->runtime_us < cif_dev->isp_runtime_max) { cif_dev->isp_runtime_max = dbufs->runtime_us; @@ -769,8 +796,8 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, if (cif_dev->rdbk_debug && dbufs->sequence < 15) v4l2_info(&cif_dev->v4l2_dev, - "isp runtime %d, seq %d, early_line %d, dma addr %x\n", - dbufs->runtime_us, dbufs->sequence, + "isp runtime %d, seq %d, type %d, early_line %d, dma addr %x\n", + dbufs->runtime_us, dbufs->sequence, dbufs->type, cif_dev->early_line, (u32)rx_buf->dummy.dma_addr); } return 0; diff --git a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c index bddcdf1f3076..18b06d4dcb03 100644 --- a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c +++ b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c @@ -68,6 +68,10 @@ MODULE_PARM_DESC(debug, "debug level (0-3)"); #define RK_IRQ_HDMIRX_HDMI 210 #define FILTER_FRAME_CNT 6 #define CPU_LIMIT_FREQ_KHZ 1200000 +#define WAIT_PHY_REG_TIME 50 +#define WAIT_TIMER_LOCK_TIME 50 +#define WAIT_SIGNAL_LOCK_TIME 600 /* if 5V present: 7ms each time */ +#define WAIT_AVI_PKT_TIME 300 #define is_validfs(x) (x == 32000 || \ x == 44100 || \ @@ -221,6 +225,8 @@ struct rk_hdmirx_dev { bool freq_qos_add; bool get_timing; bool cec_enable; + bool hpd_on; + bool force_off; u8 hdcp_enable; u32 num_clks; u32 edid_blocks_written; @@ -271,22 +277,22 @@ static u8 edid_init_data_340M[] = { 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xA7, - 0x02, 0x03, 0x2F, 0xF1, 0x51, 0x07, 0x16, 0x14, + 0x02, 0x03, 0x2E, 0xF1, 0x51, 0x07, 0x16, 0x14, 0x05, 0x01, 0x03, 0x12, 0x13, 0x84, 0x22, 0x1F, 0x90, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x67, 0x03, - 0x0C, 0x00, 0x30, 0x00, 0x18, 0x44, 0xE3, 0x05, - 0x03, 0x01, 0xE4, 0x0F, 0x00, 0x80, 0x01, 0x02, - 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, - 0x2C, 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x30, 0x00, 0x00, 0x44, 0xE3, 0x05, + 0x03, 0x01, 0xE3, 0x0E, 0x60, 0x61, 0x02, 0x3A, + 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, + 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, }; static u8 edid_init_data_600M[] = { @@ -307,13 +313,13 @@ static u8 edid_init_data_600M[] = { 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x39, - 0x02, 0x03, 0x21, 0xF2, 0x41, 0x61, 0x23, 0x09, - 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x66, 0x03, - 0x0C, 0x00, 0x30, 0x00, 0x18, 0x67, 0xD8, 0x5D, - 0xC4, 0x01, 0x78, 0xC0, 0x07, 0xE3, 0x05, 0x03, - 0x01, 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, 0x5A, - 0x80, 0xB0, 0x58, 0x8A, 0x00, 0xC4, 0x8E, 0x21, - 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x03, 0x22, 0xF2, 0x41, 0x61, 0x23, 0x09, + 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x67, 0x03, + 0x0C, 0x00, 0x30, 0x00, 0x00, 0x78, 0x67, 0xD8, + 0x5D, 0xC4, 0x01, 0x78, 0xC0, 0x00, 0xE3, 0x05, + 0x03, 0x01, 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, + 0x5A, 0x80, 0xB0, 0x58, 0x8A, 0x00, 0xC4, 0x8E, + 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -322,7 +328,7 @@ static u8 edid_init_data_600M[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, }; static char *hdmirx_color_space[8] = { @@ -441,6 +447,8 @@ static int hdmirx_subscribe_event(struct v4l2_fh *fh, break; case V4L2_EVENT_CTRL: return v4l2_ctrl_subscribe_event(fh, sub); + case RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST: + return v4l2_event_subscribe(fh, sub, 0, NULL); default: return v4l2_ctrl_subscribe_event(fh, sub); @@ -815,7 +823,7 @@ static int hdmirx_get_detected_timings(struct rk_hdmirx_dev *hdmirx_dev, tmp_data = tmds_clk * 24; do_div(tmp_data, color_depth); pix_clk = tmp_data; - bt->pixelclock = pix_clk; + bt->pixelclock = tmds_clk; hdmirx_get_timings(hdmirx_dev, bt, from_dma); if (bt->interlaced == V4L2_DV_INTERLACED) { @@ -823,7 +831,7 @@ static int hdmirx_get_detected_timings(struct rk_hdmirx_dev *hdmirx_dev, bt->il_vsync = bt->vsync + 1; } - v4l2_dbg(2, debug, v4l2_dev, "tmds_clk:%llu\n", tmds_clk); + v4l2_dbg(2, debug, v4l2_dev, "tmds_clk:%llu, pix_clk:%d\n", tmds_clk, pix_clk); v4l2_dbg(1, debug, v4l2_dev, "interlace:%d, fmt:%d, vic:%d, color:%d, mode:%s\n", bt->interlaced, hdmirx_dev->pix_fmt, hdmirx_dev->cur_vic, hdmirx_dev->color_depth, @@ -873,11 +881,21 @@ static int hdmirx_try_to_get_timings(struct rk_hdmirx_dev *hdmirx_dev, int i, cnt = 0, fail_cnt = 0, ret = 0; bool from_dma = false; struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + u32 last_w, last_h; + struct v4l2_bt_timings *bt = &timings->bt; + last_w = 0; + last_h = 0; hdmirx_set_negative_pol(hdmirx_dev, false); for (i = 0; i < try_cnt; i++) { ret = hdmirx_get_detected_timings(hdmirx_dev, timings, from_dma); - if (ret) { + + if ((last_w == 0) && (last_h == 0)) { + last_w = bt->width; + last_h = bt->height; + } + + if (ret || (last_w != bt->width) || (last_h != bt->height)) { cnt = 0; fail_cnt++; if (fail_cnt > 3) { @@ -888,9 +906,11 @@ static int hdmirx_try_to_get_timings(struct rk_hdmirx_dev *hdmirx_dev, cnt++; } - if (cnt >= 5) + if (cnt >= 8) break; + last_w = bt->width; + last_h = bt->height; usleep_range(10*1000, 10*1100); } @@ -973,6 +993,9 @@ static void hdmirx_hpd_ctrl(struct rk_hdmirx_dev *hdmirx_dev, bool en) { struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + if (hdmirx_dev->force_off && en) + return; + v4l2_dbg(1, debug, v4l2_dev, "%s: %sable, hpd_trigger_level:%d\n", __func__, en ? "en" : "dis", hdmirx_dev->hpd_trigger_level); @@ -982,6 +1005,7 @@ static void hdmirx_hpd_ctrl(struct rk_hdmirx_dev *hdmirx_dev, bool en) HDCP1_P0_GPIO_IN_SEL | HDCP1_P0_GPIO_IN_SEL << 16); hdmirx_dev->hdcp->hdcp2_connect_ctrl(hdmirx_dev->hdcp, en); } + hdmirx_dev->hpd_on = en; } static int hdmirx_write_edid(struct rk_hdmirx_dev *hdmirx_dev, @@ -1208,13 +1232,13 @@ static int hdmirx_phy_register_read(struct rk_hdmirx_dev *hdmirx_dev, /* config read enable */ hdmirx_writel(hdmirx_dev, PHYCREG_CONTROL, PHYCREG_CR_PARA_READ_P); - for (i = 0; i < 50; i++) { + for (i = 0; i < WAIT_PHY_REG_TIME; i++) { usleep_range(200, 210); if (hdmirx_dev->cr_read_done) break; } - if (i == 50) { + if (i == WAIT_PHY_REG_TIME) { dev_err(dev, "%s wait cr read done failed!\n", __func__); return -1; } @@ -1244,13 +1268,13 @@ static int hdmirx_phy_register_write(struct rk_hdmirx_dev *hdmirx_dev, /* config write enable */ hdmirx_writel(hdmirx_dev, PHYCREG_CONTROL, PHYCREG_CR_PARA_WRITE_P); - for (i = 0; i < 50; i++) { + for (i = 0; i < WAIT_PHY_REG_TIME; i++) { usleep_range(200, 210); if (hdmirx_dev->cr_write_done) break; } - if (i == 50) { + if (i == WAIT_PHY_REG_TIME) { dev_err(dev, "%s wait cr write done failed!\n", __func__); return -1; } @@ -1314,6 +1338,22 @@ static void hdmirx_phy_config(struct rk_hdmirx_dev *hdmirx_dev) hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); + hdmirx_phy_register_write(hdmirx_dev, + HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG, + CDR_SETTING_BOUNDARY_3_DEFAULT); + hdmirx_phy_register_write(hdmirx_dev, + HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG, + CDR_SETTING_BOUNDARY_4_DEFAULT); + hdmirx_phy_register_write(hdmirx_dev, + HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG, + CDR_SETTING_BOUNDARY_5_DEFAULT); + hdmirx_phy_register_write(hdmirx_dev, + HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG, + CDR_SETTING_BOUNDARY_6_DEFAULT); + hdmirx_phy_register_write(hdmirx_dev, + HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG, + CDR_SETTING_BOUNDARY_7_DEFAULT); + hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_PDDQ, 0); if (wait_reg_bit_status(hdmirx_dev, PHY_STATUS, PDDQ_ACK, 0, false, 10)) dev_err(dev, "%s wait pddq ack failed!\n", __func__); @@ -1338,13 +1378,13 @@ static void hdmirx_controller_init(struct rk_hdmirx_dev *hdmirx_dev) TIMER_BASE_LOCKED_IRQ, TIMER_BASE_LOCKED_IRQ); /* write irefclk freq */ hdmirx_writel(hdmirx_dev, GLOBAL_TIMER_REF_BASE, IREF_CLK_FREQ_HZ); - for (i = 0; i < 50; i++) { + for (i = 0; i < WAIT_TIMER_LOCK_TIME; i++) { usleep_range(200, 210); if (hdmirx_dev->timer_base_lock) break; } - if (i == 50) + if (i == WAIT_TIMER_LOCK_TIME) dev_err(dev, "%s wait timer base lock failed!\n", __func__); hdmirx_update_bits(hdmirx_dev, CMU_CONFIG0, @@ -1440,7 +1480,7 @@ static int hdmirx_wait_lock_and_get_timing(struct rk_hdmirx_dev *hdmirx_dev) u32 mu_status, scdc_status, dma_st10, cmu_st; struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; - for (i = 0; i < 300; i++) { + for (i = 0; i < WAIT_SIGNAL_LOCK_TIME; i++) { mu_status = hdmirx_readl(hdmirx_dev, MAINUNIT_STATUS); scdc_status = hdmirx_readl(hdmirx_dev, SCDC_REGBANK_STATUS3); dma_st10 = hdmirx_readl(hdmirx_dev, DMA_STATUS10); @@ -1459,7 +1499,7 @@ static int hdmirx_wait_lock_and_get_timing(struct rk_hdmirx_dev *hdmirx_dev) hdmirx_tmds_clk_ratio_config(hdmirx_dev); } - if (i == 300) { + if (i == WAIT_SIGNAL_LOCK_TIME) { v4l2_err(v4l2_dev, "%s signal not lock, tmds_clk_ratio:%d\n", __func__, hdmirx_dev->tmds_clk_ratio); v4l2_err(v4l2_dev, "%s mu_st:%#x, scdc_st:%#x, dma_st10:%#x\n", @@ -1476,7 +1516,7 @@ static int hdmirx_wait_lock_and_get_timing(struct rk_hdmirx_dev *hdmirx_dev) hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, PKTDEC_AVIIF_RCV_IRQ, PKTDEC_AVIIF_RCV_IRQ); - for (i = 0; i < 300; i++) { + for (i = 0; i < WAIT_AVI_PKT_TIME; i++) { usleep_range(1000, 1100); if (hdmirx_dev->avi_pkt_rcv) { v4l2_dbg(1, debug, v4l2_dev, @@ -1485,13 +1525,13 @@ static int hdmirx_wait_lock_and_get_timing(struct rk_hdmirx_dev *hdmirx_dev) } } - if (i == 300) { + if (i == WAIT_AVI_PKT_TIME) { v4l2_err(v4l2_dev, "%s wait avi_pkt_rcv failed!\n", __func__); hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, PKTDEC_AVIIF_RCV_IRQ, 0); } - usleep_range(50*1000, 50*1010); + usleep_range(200*1000, 200*1010); hdmirx_format_change(hdmirx_dev); return 0; @@ -1889,7 +1929,7 @@ static void hdmirx_stop_streaming(struct vb2_queue *queue) /* wait last irq to return the buffer */ ret = wait_event_timeout(stream->wq_stopped, stream->stopping != true, - msecs_to_jiffies(500)); + msecs_to_jiffies(50)); if (!ret) { v4l2_err(v4l2_dev, "%s wait last irq timeout, return bufs!\n", __func__); @@ -2201,6 +2241,11 @@ static int hdmirx_register_stream_vdev(struct hdmirx_stream *stream) static void process_signal_change(struct rk_hdmirx_dev *hdmirx_dev) { + struct hdmirx_stream *stream = &hdmirx_dev->stream; + const struct v4l2_event evt_signal_lost = { + .type = RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST, + }; + hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, LINE_FLAG_INT_EN | @@ -2212,6 +2257,7 @@ static void process_signal_change(struct rk_hdmirx_dev *hdmirx_dev) HDMIRX_AXI_ERROR_INT_EN, 0); hdmirx_reset_dma(hdmirx_dev); hdmirx_dev->get_timing = false; + v4l2_event_queue(&stream->vdev, &evt_signal_lost); if (hdmirx_dev->hdcp && hdmirx_dev->hdcp->hdcp_stop) hdmirx_dev->hdcp->hdcp_stop(hdmirx_dev->hdcp); schedule_delayed_work_on(hdmirx_dev->bound_cpu, @@ -2665,10 +2711,15 @@ static void hdmirx_delayed_work_hotplug(struct work_struct *work) struct rk_hdmirx_dev *hdmirx_dev = container_of(dwork, struct rk_hdmirx_dev, delayed_work_hotplug); struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + struct hdmirx_stream *stream = &hdmirx_dev->stream; + const struct v4l2_event evt_signal_lost = { + .type = RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST, + }; bool plugin; mutex_lock(&hdmirx_dev->work_lock); hdmirx_dev->get_timing = false; + v4l2_event_queue(&stream->vdev, &evt_signal_lost); plugin = tx_5v_power_present(hdmirx_dev); v4l2_ctrl_s_ctrl(hdmirx_dev->detect_tx_5v_ctrl, plugin); v4l2_dbg(1, debug, v4l2_dev, "%s: plugin:%d\n", __func__, plugin); @@ -3386,14 +3437,54 @@ static ssize_t edid_store(struct device *dev, return count; } +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rk_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); + + if (!hdmirx_dev) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%s\n", + hdmirx_dev->hpd_on ? "connected" : "disconnected"); +} + +static ssize_t status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rk_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); + + if (!hdmirx_dev) + return -EINVAL; + + if (sysfs_streq(buf, "on")) { + hdmirx_dev->force_off = false; + if (!tx_5v_power_present(hdmirx_dev)) + return count; + hdmirx_hpd_ctrl(hdmirx_dev, true); + } else if (sysfs_streq(buf, "off")) { + hdmirx_dev->force_off = true; + if (!tx_5v_power_present(hdmirx_dev)) + return count; + hdmirx_hpd_ctrl(hdmirx_dev, false); + } else { + return -EINVAL; + } + + return count; +} + static DEVICE_ATTR_RO(audio_rate); static DEVICE_ATTR_RO(audio_present); static DEVICE_ATTR_RW(edid); +static DEVICE_ATTR_RW(status); static struct attribute *hdmirx_attrs[] = { &dev_attr_audio_rate.attr, &dev_attr_audio_present.attr, &dev_attr_edid.attr, + &dev_attr_status.attr, NULL }; ATTRIBUTE_GROUPS(hdmirx); @@ -3751,7 +3842,7 @@ static int hdmirx_status_show(struct seq_file *s, void *v) else seq_puts(s, "UNKNOWN\n"); - seq_printf(s, "Mode: %ux%u%s%u (%ux%u)", + seq_printf(s, "Timing: %ux%u%s%u (%ux%u)", bt->width, bt->height, bt->interlaced ? "i" : "p", fps, htot, vtot); @@ -3759,6 +3850,23 @@ static int hdmirx_status_show(struct seq_file *s, void *v) bt->hfrontporch, bt->hsync, bt->hbackporch, bt->vfrontporch, bt->vsync, bt->vbackporch); seq_printf(s, "Pixel Clk: %llu\n", bt->pixelclock); + seq_printf(s, "Mode: %s\n", hdmirx_dev->is_dvi_mode ? "DVI" : "HDMI"); + + hdmirx_get_color_range(hdmirx_dev); + seq_puts(s, "Color Range: "); + if (hdmirx_dev->cur_color_range == HDMIRX_DEFAULT_RANGE) + seq_puts(s, "DEFAULT\n"); + else if (hdmirx_dev->cur_color_range == HDMIRX_FULL_RANGE) + seq_puts(s, "FULL\n"); + else + seq_puts(s, "LIMITED\n"); + + hdmirx_get_color_space(hdmirx_dev); + seq_puts(s, "Color Space: "); + if (hdmirx_dev->cur_color_space < 8) + seq_printf(s, "%s\n", hdmirx_color_space[hdmirx_dev->cur_color_space]); + else + seq_puts(s, "Unknown\n"); return 0; } diff --git a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h index ea7d40176b18..7f57c464df24 100644 --- a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h +++ b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h @@ -51,6 +51,16 @@ #define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_FSM_CONFIG 0x20c4 #define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_ADAPT_REF_FOM 0x20c7 +#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG 0x20e9 +#define CDR_SETTING_BOUNDARY_3_DEFAULT 0x52da +#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG 0x20ea +#define CDR_SETTING_BOUNDARY_4_DEFAULT 0x43cd +#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG 0x20eb +#define CDR_SETTING_BOUNDARY_5_DEFAULT 0x35b3 +#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG 0x20fb +#define CDR_SETTING_BOUNDARY_6_DEFAULT 0x2799 +#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG 0x20fc +#define CDR_SETTING_BOUNDARY_7_DEFAULT 0x1b65 #define RAWLANE0_DIG_PCS_XF_RX_OVRD_OUT 0x300e #define RAWLANE1_DIG_PCS_XF_RX_OVRD_OUT 0x310e diff --git a/drivers/media/platform/rockchip/isp/capture_v21.c b/drivers/media/platform/rockchip/isp/capture_v21.c index 650b8cb85659..2dc077a48d25 100644 --- a/drivers/media/platform/rockchip/isp/capture_v21.c +++ b/drivers/media/platform/rockchip/isp/capture_v21.c @@ -1331,6 +1331,7 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) struct v4l2_device *v4l2_dev = &dev->v4l2_dev; unsigned long lock_flags = 0; int ret = 0; + bool is_wait = true; if (!dev->dmarx_dev.trigger && (is_rdbk_stream(stream) || is_hdr_stream(stream))) { @@ -1348,12 +1349,13 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) if (IS_HDR_RDBK(dev->rd_mode)) { spin_lock_irqsave(&dev->hw_dev->rdbk_lock, lock_flags); if (dev->hw_dev->cur_dev_id != dev->dev_id || dev->hw_dev->is_idle) + is_wait = false; + if (atomic_read(&dev->cap_dev.refcnt) == 1 && !is_wait) dev->isp_state = ISP_STOP; spin_unlock_irqrestore(&dev->hw_dev->rdbk_lock, lock_flags); } } - if (dev->isp_state & ISP_START && - !stream->ops->is_stream_stopped(stream)) { + if (is_wait && !stream->ops->is_stream_stopped(stream)) { ret = wait_event_timeout(stream->done, !stream->streaming, msecs_to_jiffies(500)); diff --git a/drivers/media/platform/rockchip/isp/capture_v30.c b/drivers/media/platform/rockchip/isp/capture_v30.c index 683df04e317a..d0ff8e295e0a 100644 --- a/drivers/media/platform/rockchip/isp/capture_v30.c +++ b/drivers/media/platform/rockchip/isp/capture_v30.c @@ -966,6 +966,7 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) struct v4l2_device *v4l2_dev = &dev->v4l2_dev; unsigned long lock_flags = 0; int ret = 0; + bool is_wait = true; stream->stopping = true; if (dev->hw_dev->is_single) @@ -973,11 +974,12 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) if (IS_HDR_RDBK(dev->rd_mode)) { spin_lock_irqsave(&dev->hw_dev->rdbk_lock, lock_flags); if (dev->hw_dev->cur_dev_id != dev->dev_id || dev->hw_dev->is_idle) + is_wait = false; + if (atomic_read(&dev->cap_dev.refcnt) == 1 && !is_wait) dev->isp_state = ISP_STOP; spin_unlock_irqrestore(&dev->hw_dev->rdbk_lock, lock_flags); } - if (dev->isp_state & ISP_START && - !stream->ops->is_stream_stopped(stream)) { + if (is_wait && !stream->ops->is_stream_stopped(stream)) { ret = wait_event_timeout(stream->done, !stream->streaming, msecs_to_jiffies(500)); diff --git a/drivers/media/platform/rockchip/isp/capture_v32.c b/drivers/media/platform/rockchip/isp/capture_v32.c index 219f49ad4f10..67cb27c320eb 100644 --- a/drivers/media/platform/rockchip/isp/capture_v32.c +++ b/drivers/media/platform/rockchip/isp/capture_v32.c @@ -1253,6 +1253,7 @@ static int mi_frame_start(struct rkisp_stream *stream, u32 mis) */ static int mi_frame_end(struct rkisp_stream *stream) { + struct rkisp_device *dev = stream->ispdev; struct capture_fmt *isp_fmt = &stream->out_isp_fmt; unsigned long lock_flags = 0; u32 i; @@ -1262,6 +1263,13 @@ static int mi_frame_end(struct rkisp_stream *stream) if (stream->curr_buf) { struct vb2_buffer *vb2_buf = &stream->curr_buf->vb.vb2_buf; + if (dev->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); + goto next; + } + for (i = 0; i < isp_fmt->mplanes; i++) { u32 payload_size = stream->out_fmt.plane_fmt[i].sizeimage; @@ -1273,7 +1281,7 @@ static int mi_frame_end(struct rkisp_stream *stream) else rkisp_rockit_buf_done(stream, ROCKIT_DVBM_END); } - +next: spin_lock_irqsave(&stream->vbq_lock, lock_flags); stream->curr_buf = stream->next_buf; stream->next_buf = NULL; @@ -1299,6 +1307,7 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) struct v4l2_device *v4l2_dev = &dev->v4l2_dev; unsigned long lock_flags = 0; int ret = 0; + bool is_wait = true; stream->stopping = true; stream->is_pause = false; @@ -1307,11 +1316,12 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) if (IS_HDR_RDBK(dev->rd_mode)) { spin_lock_irqsave(&dev->hw_dev->rdbk_lock, lock_flags); if (dev->hw_dev->cur_dev_id != dev->dev_id || dev->hw_dev->is_idle) + is_wait = false; + if (atomic_read(&dev->cap_dev.refcnt) == 1 && !is_wait) dev->isp_state = ISP_STOP; spin_unlock_irqrestore(&dev->hw_dev->rdbk_lock, lock_flags); } - if (dev->isp_state & ISP_START && - !stream->ops->is_stream_stopped(stream)) { + if (is_wait && !stream->ops->is_stream_stopped(stream)) { ret = wait_event_timeout(stream->done, !stream->streaming, msecs_to_jiffies(500)); diff --git a/drivers/media/platform/rockchip/isp/hw.c b/drivers/media/platform/rockchip/isp/hw.c index db52cfe18017..65934f24a6e8 100644 --- a/drivers/media/platform/rockchip/isp/hw.c +++ b/drivers/media/platform/rockchip/isp/hw.c @@ -594,7 +594,15 @@ static inline bool is_iommu_enable(struct device *dev) void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure) { void __iomem *base = dev->base_addr; - u32 val; + u32 val, iccl0, iccl1, clk_ctrl0, clk_ctrl1; + + /* record clk config and recover */ + iccl0 = readl(base + CIF_ICCL); + clk_ctrl0 = readl(base + CTRL_VI_ISP_CLK_CTRL); + if (dev->is_unite) { + iccl1 = readl(dev->base_next_addr + CIF_ICCL); + clk_ctrl1 = readl(dev->base_next_addr + CTRL_VI_ISP_CLK_CTRL); + } if (is_secure) { /* if isp working, cru reset isn't secure. @@ -633,6 +641,29 @@ void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure) rockchip_iommu_disable(dev->dev); rockchip_iommu_enable(dev->dev); } + + writel(iccl0, base + CIF_ICCL); + writel(clk_ctrl0, base + CTRL_VI_ISP_CLK_CTRL); + if (dev->is_unite) { + writel(iccl1, dev->base_next_addr + CIF_ICCL); + writel(clk_ctrl1, dev->base_next_addr + CTRL_VI_ISP_CLK_CTRL); + } + + /* default config */ + if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) { + /* disable csi_rx interrupt */ + writel(0, dev->base_addr + CIF_ISP_CSI0_CTRL0); + writel(0, dev->base_addr + CIF_ISP_CSI0_MASK1); + writel(0, dev->base_addr + CIF_ISP_CSI0_MASK2); + writel(0, dev->base_addr + CIF_ISP_CSI0_MASK3); + } else if (dev->isp_ver == ISP_V32) { + /* disable down samplling default */ + writel(ISP32_DS_DS_DIS, dev->base_addr + ISP32_MI_MPDS_WR_CTRL); + writel(ISP32_DS_DS_DIS, dev->base_addr + ISP32_MI_BPDS_WR_CTRL); + + writel(0, dev->base_addr + ISP32_BLS_ISP_OB_PREDGAIN); + writel(0x37, dev->base_addr + ISP32_MI_WR_WRAP_CTRL); + } } static void isp_config_clk(struct rkisp_hw_dev *dev, int on) @@ -722,22 +753,6 @@ static int enable_sys_clk(struct rkisp_hw_dev *dev) rkisp_set_clk_rate(dev->clks[5], rate); rkisp_soft_reset(dev, false); isp_config_clk(dev, true); - - if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) { - /* disable csi_rx interrupt */ - writel(0, dev->base_addr + CIF_ISP_CSI0_CTRL0); - writel(0, dev->base_addr + CIF_ISP_CSI0_MASK1); - writel(0, dev->base_addr + CIF_ISP_CSI0_MASK2); - writel(0, dev->base_addr + CIF_ISP_CSI0_MASK3); - } else if (dev->isp_ver == ISP_V32) { - /* disable down samplling default */ - writel(ISP32_DS_DS_DIS, dev->base_addr + ISP32_MI_MPDS_WR_CTRL); - writel(ISP32_DS_DS_DIS, dev->base_addr + ISP32_MI_BPDS_WR_CTRL); - - writel(0, dev->base_addr + ISP32_BLS_ISP_OB_PREDGAIN); - writel(0x37, dev->base_addr + ISP32_MI_WR_WRAP_CTRL); - } - return 0; err: for (--i; i >= 0; --i) diff --git a/drivers/media/platform/rockchip/isp/isp_params_v32.c b/drivers/media/platform/rockchip/isp/isp_params_v32.c index dd6ae74508d4..12b276c1e9e6 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v32.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v32.c @@ -3419,11 +3419,7 @@ isp_gain_enable(struct rkisp_isp_params_vdev *params_vdev, bool en) { struct rkisp_isp_params_val_v32 *priv_val = (struct rkisp_isp_params_val_v32 *)params_vdev->priv_val; - u32 val = isp3_param_read_cache(params_vdev, ISP3X_LDCH_STS); - - /* gain will affect ldch, no support for ldch and gain enable */ - if (val & ISP32_MODULE_EN && en) - return; + u32 val = 0; val = isp3_param_read_cache(params_vdev, ISP3X_GAIN_CTRL); if (en) { diff --git a/drivers/media/platform/rockchip/isp/regs.c b/drivers/media/platform/rockchip/isp/regs.c index fd77e13c4d4b..eef92d66eee3 100644 --- a/drivers/media/platform/rockchip/isp/regs.c +++ b/drivers/media/platform/rockchip/isp/regs.c @@ -233,24 +233,35 @@ static void set_scale(struct rkisp_stream *stream, struct v4l2_rect *in_y, ISP3X_MAIN_RESIZE_IN_CROP_OFFSET : ISP3X_SELF_RESIZE_IN_CROP_OFFSET; u32 isp_in_w = in_y->width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL; u32 scl_w = out_y->width / 2; - u32 left_y = DIV_ROUND_UP(scl_w * 65536, scale_hy); - u32 left_c = DIV_ROUND_UP(scl_w * 65536 / 2, scale_hc); + u32 left_y = scale_hy == 1 ? scl_w : DIV_ROUND_UP(scl_w * 65536, scale_hy); + u32 left_c = scale_hc == 1 ? scl_w / 2 : DIV_ROUND_UP(scl_w * 65536 / 2, scale_hc); u32 phase_src_y = left_y * scale_hy; u32 phase_dst_y = scl_w * 65536; - u32 phase_left_y = scale_hy - (phase_src_y - phase_dst_y); + u32 phase_left_y = scale_hy == 1 ? 0 : scale_hy - (phase_src_y - phase_dst_y); u32 phase_src_c = left_c * scale_hc; u32 phase_dst_c = scl_w * 65536 / 2; - u32 phase_left_c = scale_hc - (phase_src_c - phase_dst_c); - u32 right_y = phase_left_y ? - in_y->width - (left_y - 1) : - in_y->width - left_y; - u32 right_c = phase_left_c ? - in_y->width - (left_c - 1) * 2 : - in_y->width - left_c * 2; + u32 phase_left_c = scale_hc == 1 ? 0 : scale_hc - (phase_src_c - phase_dst_c); + u32 right_y = phase_left_y ? in_y->width - (left_y - 1) : in_y->width - left_y; + u32 right_c = phase_left_c ? in_y->width - (left_c - 1) * 2 : in_y->width - left_c * 2; u32 right_crop_y = isp_in_w - right_y; u32 right_crop_c = isp_in_w - right_c; - u32 right_scl_in_y = right_crop_y - RKMOUDLE_UNITE_EXTEND_PIXEL; - u32 right_scl_in_c = right_crop_c - RKMOUDLE_UNITE_EXTEND_PIXEL; + u32 extend = RKMOUDLE_UNITE_EXTEND_PIXEL; + u32 right_scl_in_y; + u32 right_scl_in_c; + + if (right_crop_y < RKMOUDLE_UNITE_EXTEND_PIXEL) { + u32 reg; + + extend = right_crop_y & ~0x1; + reg = stream->config->dual_crop.h_offset; + rkisp_next_write(dev, reg, extend, false); + reg = stream->config->dual_crop.h_size; + rkisp_next_write(dev, reg, isp_in_w - extend, false); + reg = stream->config->dual_crop.ctrl; + rkisp_next_write(dev, reg, rkisp_next_read_reg_cache(dev, reg), false); + } + right_scl_in_y = right_crop_y - extend; + right_scl_in_c = right_crop_c - extend; /* left isp */ rkisp_write(dev, hy_size_reg, scl_w, false); diff --git a/drivers/media/platform/rockchip/isp/regs.h b/drivers/media/platform/rockchip/isp/regs.h index 48b6bc44c081..c902dc0044e5 100644 --- a/drivers/media/platform/rockchip/isp/regs.h +++ b/drivers/media/platform/rockchip/isp/regs.h @@ -1915,6 +1915,10 @@ static inline void force_cfg_update(struct rkisp_device *dev) u32 val = CIF_MI_CTRL_INIT_OFFSET_EN | CIF_MI_CTRL_INIT_BASE_EN; bool is_unite = dev->hw_dev->is_unite; + if (dev->isp_ver == ISP_V21) { + val |= rkisp_read_reg_cache(dev, CIF_MI_CTRL); + rkisp_write(dev, CIF_MI_CTRL, val, true); + } dev->hw_dev->is_mi_update = true; rkisp_unite_set_bits(dev, CIF_MI_CTRL, 0, val, false, is_unite); val = CIF_MI_INIT_SOFT_UPD; diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index d2b6a13a53ab..7597539eb919 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -789,8 +789,10 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) isp->sw_rd_cnt = 1; times = 0; } - if (dev->is_pre_on && t.frame_id == 0) + if (dev->is_pre_on && t.frame_id == 0) { dev->is_first_double = true; + dev->skip_frame = 1; + } } end: spin_unlock_irqrestore(&hw->rdbk_lock, lock_flags); @@ -847,8 +849,6 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq) { u32 val = 0; - if (dev->is_first_double) - return; if (dev->hw_dev->is_multi_overflow && dev->sw_rd_cnt && irq & ISP_FRAME_END) @@ -867,6 +867,12 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq) if (dev->irq_ends != dev->irq_ends_mask || !IS_HDR_RDBK(dev->rd_mode)) return; + if (dev->is_first_double) { + dev->skip_frame = 0; + dev->irq_ends = 0; + return; + } + /* check output stream is off */ val = ISP_FRAME_MP | ISP_FRAME_SP | ISP_FRAME_MPFBC | ISP_FRAME_BP; if (!(dev->irq_ends_mask & val)) { @@ -1935,7 +1941,6 @@ static int rkisp_isp_stop(struct rkisp_device *dev) "MI_CTRL:%x, ISP_CTRL:%x\n", readl(base + CIF_MI_CTRL), readl(base + CIF_ISP_CTRL)); - val = rkisp_read(dev, CTRL_VI_ISP_CLK_CTRL, true); if (!in_interrupt()) { /* normal case */ /* check the isp_clk before isp reset operation */ @@ -1949,7 +1954,6 @@ static int rkisp_isp_stop(struct rkisp_device *dev) } rkisp_soft_reset(dev->hw_dev, false); } - rkisp_write(dev, CTRL_VI_ISP_CLK_CTRL, val, true); if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) { writel(0, base + CIF_ISP_CSI0_CSI2_RESETN); diff --git a/drivers/media/platform/rockchip/isp/version.h b/drivers/media/platform/rockchip/isp/version.h index c3eda612db71..01bd28330c38 100644 --- a/drivers/media/platform/rockchip/isp/version.h +++ b/drivers/media/platform/rockchip/isp/version.h @@ -274,6 +274,89 @@ * 53.procfs build with different isp version * 54.fix isp debug time for fe/fs irq together * 55.awb or gain debug info to ddr for isp32 + * + * v2.0.0: + * 1.fix bay3d ds size for isp32 + * 2.to support vicap merge raw + * 3.isp32 fix ae no working with af + * 4.api to free mesh buf for user + * 5.lock for buf alloc and free + * 6.for sdmmc lock + * 7.limit bay3d bwsaving config for isp32 + * 8.fix imx327 hdr mode for isp21 + * 9.ctrl the fps for isp32 + * 10.add the bp stream async for isp32 + * 11.fix info2ddr buf free for isp32 + * 12.fix csm range to full + * 13.add the pause, config, resume stream for isp32 + * 14.isp32 min clk to 200M + * 15.module auto gating for isp30/isp32 + * 16.add the max size dummybuf and shd stop for isp32 + * 17.add the config dvbm_init in wrap for isp32 + * 18.sync params state + * 19.delete the buf_done log for isp32 + * 20.params buf alloc remove to first buf queue + * 21.read the color_ctrl reg for isp32 + * 22.use lager clk in 4 vir-isp mode + * 23.rockit: support set wrap_line + * 24.tb helper add clk on/off + * 25.remove stream limit for dvbm for isp32 + * 26.fix hold at lsc ram data config + * 27.fix cac on/off for isp32 + * 28.thunderboot for isp32 + * 29.fix isp32 stream buf update double + * 30.add the double isp_dev in rockit for isp32 + * 31.isp32: fix wrap error for fast stream + * 32.check rockit pointer + * 33.support free rx buffer + * 34.initcall cif/isp early when ROCKCHIP_THUNDER_BOOT_ISP=y + * 35.fix rockit set fps fail + * 36.fix module exit + * 37.api get fast stream output info + * 38.api for video to free tb reserved memory + * 39.fix warp size error + * 40.fix isp30 cgc limit config + * 41.remove associated of cproc and ie for isp3x + * 42.Add missing sentinel to rkisp_hw_of_match + * 43.support mesh buf count from user for isp30 and isp32 + * 44.add tb api for rockit + * 45.fix isp30 cgc and cproc range + * 46.add slab.h fix compile + * 47.vb2 buf done in tasklet + * 48.rdbk to tasklet + * 49.set afen off before config af + * 50.remove isp1x compatible + * 51.frame end config params_v32 for fast output + * 52.match stream info for fast output + * 53.fix bug the second frame pts is 0 + * 54.fix error of lsc repeat switch + * 55.fix dhaz config for multi isp21 + * 56.cif/isp support compat_ioctl32 for video + * 57.unite mode to support multi dev for isp30 + * 58.enum multi isp size at power on + * 59.2 readback for support multishot large resolution + * 60.disable link vir isp when hw working + * 61.fill extend line data for fix dhaz bug + * 62.fix isp20 and isp21 default to online with vicap + * 63.add procfs write for debug + * 64.fix isp20 error + * 65.support rdbk without aiq + * 66.fast to vicap capture raw + * 67.first frame run double for isp32 fast mode + * 68.fix pm runtime return -EACCES for thunderboot + * 69.record isp read time for fast mode + * 70.first params from rtt for thunderboot + * 71.fix pm runtime return -EACCES for thunderboot + * 72.record isp read time for fast mode + * 73.first params from rtt for thunderboot + * 74.enum formats for different isp version + * 75.change the limit of height + * 76.enum the max frame size to isp input size + * 77.stop without waiting if isp idle for readback mode + * 78.fix limit of dcrop + * 79.fix isp32 stream force to update enable + * 80.fix mi no disable for multi sensor unite mode + * 81.fix size for multi isp composite mode */ #define RKISP_DRIVER_VERSION RKISP_API_VERSION diff --git a/drivers/misc/rk803.c b/drivers/misc/rk803.c index a6a229aa7f05..b97b607af3af 100644 --- a/drivers/misc/rk803.c +++ b/drivers/misc/rk803.c @@ -25,8 +25,7 @@ #define RK803_TIMEOUT 1000 /* usec */ enum SL_LED_CURRENT { - LED_0MA = 0, - LED_100MA, + LED_100MA = 0, LED_200MA, LED_300MA, LED_400MA, @@ -40,12 +39,12 @@ enum SL_LED_CURRENT { LED_1200MA, LED_1300MA, LED_1400MA, - LED_1544MA = 15, + LED_1500MA, LED_1600MA, LED_1700MA, LED_1800MA, LED_1900MA, - LED_2000MA = 20, + LED_2000MA, LED_2100MA, LED_2200MA, LED_2300MA, @@ -55,7 +54,7 @@ enum SL_LED_CURRENT { LED_2700MA, LED_2800MA, LED_2900MA, - LED_3000MA = 30, + LED_3000MA, LED_3100MA, LED_3200MA }; diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index f473d67334e0..157d1c4d3ccd 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -584,14 +584,11 @@ static int dwcmshc_resume(struct device *dev) static int dwcmshc_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u16 data; - priv->actual_clk = host->mmc->actual_clock; - sdhci_set_clock(host, 0); - priv->cclk_rate = clk_get_rate(pltfm_host->clk); - clk_set_rate(pltfm_host->clk, 24000000); - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); + data = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + data &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, data, SDHCI_CLOCK_CONTROL); return 0; } @@ -599,20 +596,13 @@ static int dwcmshc_runtime_suspend(struct device *dev) static int dwcmshc_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); - int ret = 0; + u16 data; - clk_set_rate(pltfm_host->clk, priv->cclk_rate); - sdhci_set_clock(host, priv->actual_clk); - ret = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); - /* - * DLL will not LOCK after frequency reduction, - * and it needs to be reconfigured. - */ - dwcmshc_rk_set_clock(host, priv->cclk_rate); + data = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + data |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, data, SDHCI_CLOCK_CONTROL); - return ret; + return 0; } #endif diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c index 4061aa8fbf4e..e8eff658391c 100644 --- a/drivers/mtd/nand/spi/foresee.c +++ b/drivers/mtd/nand/spi/foresee.c @@ -97,6 +97,24 @@ static const struct spinand_info foresee_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)), + SPINAND_INFO("F35SQA512M", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x70), + NAND_MEMORG(1, 2048, 64, 64, 512, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)), + SPINAND_INFO("F35UQA512M", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x60), + NAND_MEMORG(1, 2048, 64, 64, 512, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)), }; static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = { diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index 5c4e36c8e861..f38fe26908c6 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -297,7 +297,36 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), - + SPINAND_INFO("MX35UF1GE4AD", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF2GE4AD", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA6), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF4GE4AD", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB7), + NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), }; static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = { diff --git a/drivers/net/can/rockchip/rockchip_canfd.c b/drivers/net/can/rockchip/rockchip_canfd.c index d6bb345a876c..434a7d45c733 100644 --- a/drivers/net/can/rockchip/rockchip_canfd.c +++ b/drivers/net/can/rockchip/rockchip_canfd.c @@ -41,6 +41,7 @@ enum rockchip_canfd_reg { CAN_TX_ERR_CNT = 0x38, CAN_IDCODE = 0x3c, CAN_IDMASK = 0x40, + CAN_TX_CHECK_FIC = 0x50, CAN_NBTP = 0x100, CAN_DBTP = 0x104, CAN_TDCR = 0x108, @@ -103,6 +104,7 @@ enum rockchip_canfd_reg { enum { ROCKCHIP_CANFD_MODE = 0, ROCKCHIP_CAN_MODE, + ROCKCHIP_RK3568_CAN_MODE, }; #define DATE_LENGTH_12_BYTE (0x9) @@ -188,6 +190,10 @@ enum { #define TX_FD_BRS_ENABLE BIT(4) #define FIFO_ENABLE BIT(0) +#define RX_FIFO_CNT0_SHIFT 4 +#define RX_FIFO_CNT0_MASK (0x7 << RX_FIFO_CNT0_SHIFT) +#define RX_FIFO_CNT1_SHIFT 5 +#define RX_FIFO_CNT1_MASK (0x7 << RX_FIFO_CNT1_SHIFT) #define FORMAT_SHIFT 7 #define FORMAT_MASK (0x1 << FORMAT_SHIFT) @@ -220,6 +226,10 @@ struct rockchip_canfd { void __iomem *base; u32 irqstatus; unsigned long mode; + int rx_fifo_shift; + u32 rx_fifo_mask; + bool txtorx; + u32 tx_invalid[4]; }; static inline u32 rockchip_canfd_read(const struct rockchip_canfd *priv, @@ -281,6 +291,8 @@ static int set_normal_mode(struct net_device *ndev) val = rockchip_canfd_read(rcan, CAN_MODE); val |= WORK_MODE; + if (rcan->mode >= ROCKCHIP_CAN_MODE && rcan->txtorx) + val |= MODE_RXSTX; rockchip_canfd_write(rcan, CAN_MODE, val); netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__, @@ -409,9 +421,6 @@ static int rockchip_canfd_start(struct net_device *ndev) /* Mode */ val |= MODE_FDOE; - rockchip_canfd_write(rcan, CAN_TXFIC, - rockchip_canfd_read(rcan, CAN_TXFIC) | - TX_FD_ENABLE); /* Loopback Mode */ if (rcan->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) @@ -487,6 +496,7 @@ static int rockchip_canfd_start_xmit(struct sk_buff *skb, u32 id, dlc; u32 cmd = CAN_TX0_REQ; int i; + unsigned long flags; if (can_dropped_invalid_skb(ndev, skb)) return NETDEV_TX_OK; @@ -522,6 +532,30 @@ static int rockchip_canfd_start_xmit(struct sk_buff *skb, dlc |= TX_FD_BRS_ENABLE; } + if (!rcan->txtorx && rcan->mode >= ROCKCHIP_CAN_MODE && cf->can_id & CAN_EFF_FLAG) { + /* Two frames are sent consecutively. + * Before the first frame is tx finished, + * the register of the second frame is configured. + * Don't be interrupted in the middle. + */ + local_irq_save(flags); + rockchip_canfd_write(rcan, CAN_TXID, rcan->tx_invalid[1]); + rockchip_canfd_write(rcan, CAN_TXFIC, rcan->tx_invalid[0]); + rockchip_canfd_write(rcan, CAN_TXDAT0, rcan->tx_invalid[2]); + rockchip_canfd_write(rcan, CAN_TXDAT1, rcan->tx_invalid[3]); + rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ); + rockchip_canfd_write(rcan, CAN_TXID, id); + rockchip_canfd_write(rcan, CAN_TXFIC, dlc); + for (i = 0; i < cf->len; i += 4) + rockchip_canfd_write(rcan, CAN_TXDAT0 + i, + *(u32 *)(cf->data + i)); + rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); + local_irq_restore(flags); + can_put_echo_skb(skb, ndev, 0); + + return NETDEV_TX_OK; + } + rockchip_canfd_write(rcan, CAN_TXID, id); rockchip_canfd_write(rcan, CAN_TXFIC, dlc); @@ -529,9 +563,9 @@ static int rockchip_canfd_start_xmit(struct sk_buff *skb, rockchip_canfd_write(rcan, CAN_TXDAT0 + i, *(u32 *)(cf->data + i)); - can_put_echo_skb(skb, ndev, 0); + rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); - rockchip_canfd_write(rcan, CAN_CMD, cmd); + can_put_echo_skb(skb, ndev, 0); return NETDEV_TX_OK; } @@ -553,6 +587,23 @@ static int rockchip_canfd_rx(struct net_device *ndev) for (i = 0; i < 16; i++) data[i] = rockchip_canfd_read(rcan, CAN_RXFRD); + if (rcan->mode >= ROCKCHIP_CAN_MODE) { + /* may be an empty frame */ + if (!dlc && !id_rockchip_canfd) + return 1; + + if (rcan->txtorx) { + if (rockchip_canfd_read(rcan, CAN_TX_CHECK_FIC) & FORMAT_MASK) { + ret = rockchip_canfd_read(rcan, CAN_TXID) & CAN_SFF_MASK; + if (id_rockchip_canfd == ret) { + rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, + ts | CAN_TX0_REQ); + return 1; + } + } + } + } + /* create zero'ed CAN frame buffer */ if (dlc & FDF_MASK) skb = alloc_canfd_skb(ndev, &cf); @@ -560,7 +611,7 @@ static int rockchip_canfd_rx(struct net_device *ndev) skb = alloc_can_skb(ndev, (struct can_frame **)&cf); if (!skb) { stats->rx_dropped++; - return 0; + return 1; } /* Change CAN data length format to socketCAN data format */ @@ -669,6 +720,7 @@ static irqreturn_t rockchip_canfd_interrupt(int irq, void *dev_id) TX_LOSTARB_INT | BUS_ERR_INT | BUS_OFF_INT; u32 isr; u32 dlc = 0; + u32 quota, work_done = 0; isr = rockchip_canfd_read(rcan, CAN_INT); if (isr & TX_FINISH_INT) { @@ -679,14 +731,33 @@ static irqreturn_t rockchip_canfd_interrupt(int irq, void *dev_id) else stats->tx_bytes += (dlc & DLC_MASK); stats->tx_packets++; + if (rcan->txtorx && rcan->mode >= ROCKCHIP_CAN_MODE && dlc & FORMAT_MASK) { + rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, FORMAT_MASK); + quota = (rockchip_canfd_read(rcan, CAN_RXFC) & + rcan->rx_fifo_mask) >> + rcan->rx_fifo_shift; + if (quota) { + while (work_done < quota) + work_done += rockchip_canfd_rx(ndev); + } + if (rockchip_canfd_read(rcan, CAN_TX_CHECK_FIC) & CAN_TX0_REQ) + rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); + rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, 0); + } rockchip_canfd_write(rcan, CAN_CMD, 0); can_get_echo_skb(ndev, 0); netif_wake_queue(ndev); can_led_event(ndev, CAN_LED_EVENT_TX); } - if (isr & RX_FINISH_INT) - rockchip_canfd_rx(ndev); + if (isr & RX_FINISH_INT) { + quota = (rockchip_canfd_read(rcan, CAN_RXFC) & rcan->rx_fifo_mask) >> + rcan->rx_fifo_shift; + if (quota) { + while (work_done < quota) + work_done += rockchip_canfd_rx(ndev); + } + } if (isr & err_int) { /* error interrupt */ @@ -861,6 +932,10 @@ static const struct of_device_id rockchip_canfd_of_match[] = { .compatible = "rockchip,can-2.0", .data = (void *)ROCKCHIP_CAN_MODE }, + { + .compatible = "rockchip,rk3568-can-2.0", + .data = (void *)ROCKCHIP_RK3568_CAN_MODE + }, {}, }; MODULE_DEVICE_TABLE(of, rockchip_canfd_of_match); @@ -927,8 +1002,11 @@ static int rockchip_canfd_probe(struct platform_device *pdev) /* IFI CANFD can do both Bosch FD and ISO FD */ rcan->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_FD; + rcan->rx_fifo_shift = RX_FIFO_CNT0_SHIFT; + rcan->rx_fifo_mask = RX_FIFO_CNT0_MASK; break; case ROCKCHIP_CAN_MODE: + case ROCKCHIP_RK3568_CAN_MODE: rcan->can.bittiming_const = &rockchip_canfd_bittiming_const; rcan->can.do_set_mode = rockchip_canfd_set_mode; rcan->can.do_get_berr_counter = rockchip_canfd_get_berr_counter; @@ -936,11 +1014,23 @@ static int rockchip_canfd_probe(struct platform_device *pdev) CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_3_SAMPLES; + rcan->rx_fifo_shift = RX_FIFO_CNT0_SHIFT; + rcan->rx_fifo_mask = RX_FIFO_CNT0_MASK; break; default: return -EINVAL; } + if (rcan->mode == ROCKCHIP_CAN_MODE) { + rcan->rx_fifo_shift = RX_FIFO_CNT1_SHIFT; + rcan->rx_fifo_mask = RX_FIFO_CNT1_MASK; + } + + if (device_property_read_u32_array(&pdev->dev, + "rockchip,tx-invalid-info", + rcan->tx_invalid, 4)) + rcan->txtorx = 1; + ndev->netdev_ops = &rockchip_canfd_netdev_ops; ndev->irq = irq; ndev->flags |= IFF_ECHO; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile index e9e2403c968a..2a618ef1ef74 100755 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile @@ -31,6 +31,7 @@ CONFIG_MACH_PLATFORM := y DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time \ -Wno-implicit-fallthrough -Wno-declaration-after-statement \ + -Wno-vla -Wno-vla-extension \ -Dlinux -DLINUX -DBCMDRIVER \ -DBCMDONGLEHOST -DBCMDMA32 -DBCMFILEIMAGE \ -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DGET_OTP_MAC_ENABLE \ @@ -41,7 +42,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time \ -DPOWERUP_MAX_RETRY=0 -DIFACE_HANG_FORCE_DEV_CLOSE -DWAIT_DEQUEUE \ -DUSE_NEW_RSPEC_DEFS -DBCM_USE_PLATFORM_STRLCPY \ -DWL_EXT_IAPSTA -DWL_ESCAN -DCCODE_LIST -DSUSPEND_EVENT \ - -DEAPOL_RESEND -DEAPOL_DYNAMATIC_RESEND \ + -DEAPOL_RESEND -DEAPOL_DYNAMATIC_RESEND -DWL_SCHED_SCAN \ -DENABLE_INSMOD_NO_FW_LOAD -Wframe-larger-than=2048 DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \ diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 29d8450912bc..90b02c763507 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -98,6 +98,13 @@ config PCIE_RK_THREADED_INIT help Enables threaded initialize Rockchip DW based PCIe controller. +config PCIE_DW_DMATEST + bool "DesignWare PCIe DMA test" + depends on PCIE_DW_ROCKCHIP + depends on !ROCKCHIP_PCIE_DMA_OBJ + help + Enables support for the DW PCIe controller DMA test. + config PCI_EXYNOS bool "Samsung Exynos PCIe controller" depends on SOC_EXYNOS5440 || COMPILE_TEST diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile index fa790f08faad..7e91eb5c4507 100644 --- a/drivers/pci/controller/dwc/Makefile +++ b/drivers/pci/controller/dwc/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie-dw-rockchip.o +obj-$(CONFIG_PCIE_DW_DMATEST) += pcie-dw-dmatest.o # The following drivers are for devices that use the generic ACPI # pci_root.c driver but don't support standard ECAM config access. diff --git a/drivers/pci/controller/dwc/pcie-dw-dmatest.c b/drivers/pci/controller/dwc/pcie-dw-dmatest.c new file mode 100644 index 000000000000..f6d2cbe159b1 --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-dw-dmatest.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie-designware.h" +#include "pcie-dw-dmatest.h" +#include "../rockchip-pcie-dma.h" + +static int test_size = 0x20; +module_param_named(size, test_size, int, 0644); +MODULE_PARM_DESC(size, "each packet size in bytes"); + +static unsigned int cycles_count = 1; +module_param(cycles_count, uint, 0644); +MODULE_PARM_DESC(cycles_count, "how many erase cycles to do (default 1)"); + +static unsigned int chn_en = 1; +module_param(chn_en, uint, 0644); +MODULE_PARM_DESC(chn_en, "Each bits for one dma channel, up to 2 channels, (default enable channel 0)"); + +static unsigned int rw_test = 3; +module_param(rw_test, uint, 0644); +MODULE_PARM_DESC(rw_test, "Read/Write test, 1-read 2-write 3-both(default 3)"); + +static unsigned int bus_addr = 0x3c000000; +module_param(bus_addr, uint, 0644); +MODULE_PARM_DESC(bus_addr, "Dmatest chn0 bus_addr(remote), chn1 add offset 0x100000, (default 0x3c000000)"); + +static unsigned int local_addr = 0x3c000000; +module_param(local_addr, uint, 0644); +MODULE_PARM_DESC(local_addr, "Dmatest chn0 local_addr(local), chn1 add offset 0x100000, (default 0x3c000000)"); + +static unsigned int test_dev; +module_param(test_dev, uint, 0644); +MODULE_PARM_DESC(test_dev, "Choose dma_obj device,(default 0)"); + +#define PCIE_DW_MISC_DMATEST_DEV_MAX 5 + +#define PCIE_DMA_OFFSET 0x380000 + +#define PCIE_DMA_CTRL_OFF 0x8 +#define PCIE_DMA_WR_ENB 0xc +#define PCIE_DMA_WR_CTRL_LO 0x200 +#define PCIE_DMA_WR_CTRL_HI 0x204 +#define PCIE_DMA_WR_XFERSIZE 0x208 +#define PCIE_DMA_WR_SAR_PTR_LO 0x20c +#define PCIE_DMA_WR_SAR_PTR_HI 0x210 +#define PCIE_DMA_WR_DAR_PTR_LO 0x214 +#define PCIE_DMA_WR_DAR_PTR_HI 0x218 +#define PCIE_DMA_WR_WEILO 0x18 +#define PCIE_DMA_WR_WEIHI 0x1c +#define PCIE_DMA_WR_DOORBELL 0x10 +#define PCIE_DMA_WR_INT_STATUS 0x4c +#define PCIE_DMA_WR_INT_MASK 0x54 +#define PCIE_DMA_WR_INT_CLEAR 0x58 + +#define PCIE_DMA_RD_ENB 0x2c +#define PCIE_DMA_RD_CTRL_LO 0x300 +#define PCIE_DMA_RD_CTRL_HI 0x304 +#define PCIE_DMA_RD_XFERSIZE 0x308 +#define PCIE_DMA_RD_SAR_PTR_LO 0x30c +#define PCIE_DMA_RD_SAR_PTR_HI 0x310 +#define PCIE_DMA_RD_DAR_PTR_LO 0x314 +#define PCIE_DMA_RD_DAR_PTR_HI 0x318 +#define PCIE_DMA_RD_WEILO 0x38 +#define PCIE_DMA_RD_WEIHI 0x3c +#define PCIE_DMA_RD_DOORBELL 0x30 +#define PCIE_DMA_RD_INT_STATUS 0xa0 +#define PCIE_DMA_RD_INT_MASK 0xa8 +#define PCIE_DMA_RD_INT_CLEAR 0xac + +#define PCIE_DMA_CHANEL_MAX_NUM 2 + +struct pcie_dw_dmatest_dev { + struct dma_trx_obj *obj; + struct dw_pcie *pci; + + bool irq_en; + struct completion rd_done[PCIE_DMA_CHANEL_MAX_NUM]; + struct completion wr_done[PCIE_DMA_CHANEL_MAX_NUM]; + + struct mutex rd_lock[PCIE_DMA_CHANEL_MAX_NUM]; /* Corresponding to each read DMA channel */ + struct mutex wr_lock[PCIE_DMA_CHANEL_MAX_NUM]; /* Corresponding to each write DMA channel */ +}; + +static struct pcie_dw_dmatest_dev s_dmatest_dev[PCIE_DW_MISC_DMATEST_DEV_MAX]; +static int cur_dmatest_dev; + +static void pcie_dw_dmatest_show(void) +{ + int i; + + for (i = 0; i < PCIE_DW_MISC_DMATEST_DEV_MAX; i++) { + if (s_dmatest_dev[i].obj) + dev_info(s_dmatest_dev[i].obj->dev, " test_dev index %d\n", i); + else + break; + } + + dev_info(s_dmatest_dev[test_dev].obj->dev, " is current test_dev\n"); +} + +static int rk_pcie_get_dma_status(struct dw_pcie *pci, u8 chn, enum dma_dir dir) +{ + union int_status status; + union int_clear clears; + int ret = 0; + + dev_dbg(pci->dev, "%s %x %x\n", __func__, dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS), + dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS)); + + if (dir == DMA_TO_BUS) { + status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS); + if (status.donesta & BIT(chn)) { + clears.doneclr = 0x1 << chn; + dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_CLEAR, clears.asdword); + ret = 1; + } + + if (status.abortsta & BIT(chn)) { + dev_err(pci->dev, "%s, write abort\n", __func__); + clears.abortclr = 0x1 << chn; + dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_CLEAR, clears.asdword); + ret = -1; + } + } else { + status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS); + + if (status.donesta & BIT(chn)) { + clears.doneclr = 0x1 << chn; + dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_CLEAR, clears.asdword); + ret = 1; + } + + if (status.abortsta & BIT(chn)) { + dev_err(pci->dev, "%s, read abort %x\n", __func__, status.asdword); + clears.abortclr = 0x1 << chn; + dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_CLEAR, clears.asdword); + ret = -1; + } + } + + return ret; +} + +static int rk_pcie_dma_wait_for_finised(struct dma_trx_obj *obj, struct dw_pcie *pci, struct dma_table *table) +{ + int ret; + + do { + ret = rk_pcie_get_dma_status(pci, table->chn, table->dir); + } while (!ret); + + return ret; +} + +static int rk_pcie_dma_frombus(struct pcie_dw_dmatest_dev *dmatest_dev, u32 chn, + u32 local_paddr, u32 bus_paddr, u32 size) +{ + struct dma_table *table; + struct dma_trx_obj *obj = dmatest_dev->obj; + struct dw_pcie *pci = dmatest_dev->pci; + int ret; + + if (chn >= PCIE_DMA_CHANEL_MAX_NUM) + return -1; + + table = kzalloc(sizeof(struct dma_table), GFP_KERNEL); + if (!table) + return -ENOMEM; + + mutex_lock(&dmatest_dev->rd_lock[chn]); + if (dmatest_dev->irq_en) + reinit_completion(&dmatest_dev->rd_done[chn]); + + table->buf_size = size; + table->bus = bus_paddr; + table->local = local_paddr; + table->chn = chn; + table->dir = DMA_FROM_BUS; + + obj->config_dma_func(table); + obj->start_dma_func(obj, table); + + if (dmatest_dev->irq_en) { + ret = wait_for_completion_interruptible_timeout(&dmatest_dev->rd_done[chn], HZ); + if (ret < 0) + dev_err(obj->dev, "%s interrupted\n", __func__); + else if (ret == 0) + dev_err(obj->dev, "%s timed out\n", __func__); + } else { + ret = rk_pcie_dma_wait_for_finised(obj, pci, table); + } + mutex_unlock(&dmatest_dev->rd_lock[chn]); + + kfree(table); + + return ret; +} + +static int rk_pcie_dma_tobus(struct pcie_dw_dmatest_dev *dmatest_dev, u32 chn, + u32 bus_paddr, u32 local_paddr, u32 size) +{ + struct dma_table *table; + struct dma_trx_obj *obj = dmatest_dev->obj; + struct dw_pcie *pci = dmatest_dev->pci; + int ret; + + if (chn >= PCIE_DMA_CHANEL_MAX_NUM) + return -1; + + table = kzalloc(sizeof(struct dma_table), GFP_KERNEL); + if (!table) + return -ENOMEM; + + mutex_lock(&dmatest_dev->wr_lock[chn]); + if (dmatest_dev->irq_en) + reinit_completion(&dmatest_dev->wr_done[chn]); + + table->buf_size = size; + table->bus = bus_paddr; + table->local = local_paddr; + table->chn = chn; + table->dir = DMA_TO_BUS; + + obj->config_dma_func(table); + obj->start_dma_func(obj, table); + + if (dmatest_dev->irq_en) { + ret = wait_for_completion_interruptible_timeout(&dmatest_dev->wr_done[chn], HZ); + if (ret < 0) + dev_err(obj->dev, "%s interrupted\n", __func__); + else if (ret == 0) + dev_err(obj->dev, "%s timed out\n", __func__); + } else { + ret = rk_pcie_dma_wait_for_finised(obj, pci, table); + } + mutex_unlock(&dmatest_dev->wr_lock[chn]); + + kfree(table); + + return ret; +} + +static int rk_pcie_dma_interrupt_handler_call_back(struct dma_trx_obj *obj, u32 chn, enum dma_dir dir) +{ + struct pcie_dw_dmatest_dev *dmatest_dev = (struct pcie_dw_dmatest_dev *)obj->priv; + + if (chn >= PCIE_DMA_CHANEL_MAX_NUM) + return -1; + + if (dir == DMA_FROM_BUS) + complete(&dmatest_dev->rd_done[chn]); + else + complete(&dmatest_dev->wr_done[chn]); + + return 0; +} + +struct dma_trx_obj *pcie_dw_dmatest_register(struct dw_pcie *pci, bool irq_en) +{ + struct dma_trx_obj *obj; + struct pcie_dw_dmatest_dev *dmatest_dev = &s_dmatest_dev[cur_dmatest_dev]; + int i; + + obj = devm_kzalloc(pci->dev, sizeof(struct dma_trx_obj), GFP_KERNEL); + if (!obj) + return ERR_PTR(-ENOMEM); + + obj->dev = pci->dev; + obj->priv = dmatest_dev; + obj->cb = rk_pcie_dma_interrupt_handler_call_back; + + /* Save for dmatest */ + dmatest_dev->obj = obj; + dmatest_dev->pci = pci; + for (i = 0; i < PCIE_DMA_CHANEL_MAX_NUM; i++) { + init_completion(&dmatest_dev->rd_done[i]); + init_completion(&dmatest_dev->wr_done[i]); + mutex_init(&dmatest_dev->rd_lock[i]); + mutex_init(&dmatest_dev->wr_lock[i]); + } + + /* Enable IRQ transfer as default */ + dmatest_dev->irq_en = irq_en; + cur_dmatest_dev++; + + return obj; +} + +static int dma_test(struct pcie_dw_dmatest_dev *dmatest_dev, u32 chn, + u32 bus_paddr, u32 local_paddr, u32 size, u32 loop, u8 rd_en, u8 wr_en) +{ + ktime_t start_time; + ktime_t end_time; + ktime_t cost_time; + u32 i; + long long total_byte; + long long us = 0; + struct dma_trx_obj *obj = dmatest_dev->obj; + + start_time = ktime_get(); + for (i = 0; i < loop; i++) { + if (rd_en) { + rk_pcie_dma_frombus(dmatest_dev, chn, local_paddr, bus_paddr, size); + dma_sync_single_for_cpu(obj->dev, local_paddr, size, DMA_FROM_DEVICE); + } + + if (wr_en) { + dma_sync_single_for_device(obj->dev, local_paddr, size, DMA_TO_DEVICE); + rk_pcie_dma_tobus(dmatest_dev, chn, bus_paddr, local_paddr, size); + } + } + end_time = ktime_get(); + cost_time = ktime_sub(end_time, start_time); + us = ktime_to_us(cost_time); + + total_byte = (wr_en + rd_en) * size * loop; /* 1 rd,1 wr */ + total_byte = total_byte * (1000000 / 1024) / us; + pr_err("pcie dma %s/%s test (%d+%d)*%d*%d cost %lldus speed:%lldKB/S\n", + wr_en ? "wr" : "", rd_en ? "rd" : "", wr_en, rd_en, size, loop, us, total_byte); + + return 0; +} + +static int dma_test_ch0(void *p) +{ + dma_test(&s_dmatest_dev[test_dev], 0, bus_addr, local_addr, test_size, + cycles_count, rw_test & 0x1, (rw_test & 0x2) >> 1); + + return 0; +} + +static int dma_test_ch1(void *p) +{ + /* Test in different area with ch0 */ + if (chn_en == 3) + dma_test(&s_dmatest_dev[test_dev], 1, bus_addr + test_size, local_addr + test_size, test_size, + cycles_count, rw_test & 0x1, (rw_test & 0x2) >> 1); + else + dma_test(&s_dmatest_dev[test_dev], 1, bus_addr, local_addr, test_size, + cycles_count, rw_test & 0x1, (rw_test & 0x2) >> 1); + + return 0; +} + +static int dma_run(void) +{ + if (chn_en == 3) { + kthread_run(dma_test_ch0, NULL, "dma_test_ch0"); + kthread_run(dma_test_ch1, NULL, "dma_test_ch1"); + } else if (chn_en == 2) { + dma_test_ch1(NULL); + } else { + dma_test_ch0(NULL); + } + + return 0; +} + +static int pcie_dw_dmatest(const char *val, const struct kernel_param *kp) +{ + char tmp[8]; + + if (!s_dmatest_dev[0].obj) { + pr_err("dmatest dev not exits\n"); + kfree(tmp); + + return -1; + } + + strncpy(tmp, val, 8); + if (!strncmp(tmp, "run", 3)) { + dma_run(); + } else if (!strncmp(tmp, "show", 4)) { + pcie_dw_dmatest_show(); + } else { + pr_info("input error\n"); + } + + return 0; +} + +static const struct kernel_param_ops pcie_dw_dmatest_ops = { + .set = pcie_dw_dmatest, + .get = param_get_uint, +}; + +module_param_cb(dmatest, &pcie_dw_dmatest_ops, &pcie_dw_dmatest, 0644); +MODULE_PARM_DESC(dmatest, "test rockchip pcie dma module"); + +MODULE_AUTHOR("Jon Lin"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pci/controller/dwc/pcie-dw-dmatest.h b/drivers/pci/controller/dwc/pcie-dw-dmatest.h new file mode 100644 index 000000000000..524f5b53f361 --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-dw-dmatest.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. + */ +#ifndef __PCIE_DW_DMATEST_H +#define __PCIE_DW_DMATEST_H + +#if IS_ENABLED(CONFIG_PCIE_DW_DMATEST) +struct dma_trx_obj *pcie_dw_dmatest_register(struct dw_pcie *pci, bool irq_en); +#else +static inline struct dma_trx_obj *pcie_dw_dmatest_register(struct dw_pcie *pci, bool irq_en) +{ + return NULL; +} +#endif + +#endif diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index ec9489fa4e07..ff517ce76623 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -46,6 +46,7 @@ #include "pcie-designware.h" #include "../../pci.h" #include "../rockchip-pcie-dma.h" +#include "pcie-dw-dmatest.h" enum rk_pcie_device_mode { RK_PCIE_EP_TYPE, @@ -87,6 +88,8 @@ enum rk_pcie_device_mode { #define PCIE_DMA_RD_INT_MASK 0xa8 #define PCIE_DMA_RD_INT_CLEAR 0xac +#define PCIE_DMA_CHANEL_MAX_NUM 2 + /* Parameters for the waiting for iATU enabled routine */ #define LINK_WAIT_IATU_MIN 9000 #define LINK_WAIT_IATU_MAX 10000 @@ -835,7 +838,7 @@ static bool rk_pcie_udma_enabled(struct rk_pcie *rk_pcie) PCIE_DMA_CTRL_OFF); } -static int rk_pcie_host_init_dma_trx(struct rk_pcie *rk_pcie) +static int rk_pcie_init_dma_trx(struct rk_pcie *rk_pcie) { if (!rk_pcie_udma_enabled(rk_pcie)) return 0; @@ -846,6 +849,12 @@ static int rk_pcie_host_init_dma_trx(struct rk_pcie *rk_pcie) return -EINVAL; } + rk_pcie->dma_obj = pcie_dw_dmatest_register(rk_pcie->pci, true); + if (IS_ERR(rk_pcie->dma_obj)) { + dev_err(rk_pcie->pci->dev, "failed to prepare dmatest\n"); + return -EINVAL; + } + /* Enable client write and read interrupt */ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xc000000); @@ -1130,11 +1139,6 @@ static int rk_add_pcie_port(struct rk_pcie *rk_pcie, struct platform_device *pde return ret; } - ret = rk_pcie_host_init_dma_trx(rk_pcie); - if (ret) { - dev_err(dev, "failed to init host dma trx\n"); - return ret; - } return 0; } @@ -1330,10 +1334,9 @@ static int rk_pcie_reset_grant_ctrl(struct rk_pcie *rk_pcie, return ret; } -static void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, int ctr_off) +static void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, struct dma_table *cur, int ctr_off) { struct rk_pcie *rk_pcie = dev_get_drvdata(obj->dev); - struct dma_table *cur = obj->cur; dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_ENB, cur->enb.asdword); @@ -1355,10 +1358,9 @@ static void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, int ctr_off) cur->start.asdword); } -static void rk_pcie_start_dma_wr(struct dma_trx_obj *obj, int ctr_off) +static void rk_pcie_start_dma_wr(struct dma_trx_obj *obj, struct dma_table *cur, int ctr_off) { struct rk_pcie *rk_pcie = dev_get_drvdata(obj->dev); - struct dma_table *cur = obj->cur; dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_ENB, cur->enb.asdword); @@ -1382,17 +1384,17 @@ static void rk_pcie_start_dma_wr(struct dma_trx_obj *obj, int ctr_off) cur->start.asdword); } -static void rk_pcie_start_dma_dwc(struct dma_trx_obj *obj) +static void rk_pcie_start_dma_dwc(struct dma_trx_obj *obj, struct dma_table *table) { - int dir = obj->cur->dir; - int chn = obj->cur->chn; + int dir = table->dir; + int chn = table->chn; int ctr_off = PCIE_DMA_OFFSET + chn * 0x200; if (dir == DMA_FROM_BUS) - rk_pcie_start_dma_rd(obj, ctr_off); + rk_pcie_start_dma_rd(obj, table, ctr_off); else if (dir == DMA_TO_BUS) - rk_pcie_start_dma_wr(obj, ctr_off); + rk_pcie_start_dma_wr(obj, table, ctr_off); } static void rk_pcie_config_dma_dwc(struct dma_table *table) @@ -1419,76 +1421,50 @@ static void rk_pcie_config_dma_dwc(struct dma_table *table) table->start.chnl = table->chn; } -static inline void -rk_pcie_handle_dma_interrupt(struct rk_pcie *rk_pcie) -{ - struct dma_trx_obj *obj = rk_pcie->dma_obj; - struct dma_table *cur; - - if (!obj) - return; - - cur = obj->cur; - if (!cur) { - pr_err("no pcie dma table\n"); - return; - } - - obj->dma_free = true; - obj->irq_num++; - - if (cur->dir == DMA_TO_BUS) { - if (list_empty(&obj->tbl_list)) { - if (obj->dma_free && - obj->loop_count >= obj->loop_count_threshold) - complete(&obj->done); - } - } -} - static irqreturn_t rk_pcie_sys_irq_handler(int irq, void *arg) { struct rk_pcie *rk_pcie = arg; - u32 chn = 0; + u32 chn; union int_status status; union int_clear clears; u32 reg, val; status.asdword = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS); + for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) { + if (status.donesta & BIT(chn)) { + clears.doneclr = 0x1 << chn; + dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + + PCIE_DMA_WR_INT_CLEAR, clears.asdword); + if (rk_pcie->dma_obj && rk_pcie->dma_obj->cb) + rk_pcie->dma_obj->cb(rk_pcie->dma_obj, chn, DMA_TO_BUS); + } - if (rk_pcie->dma_obj && rk_pcie->dma_obj->cur) - chn = rk_pcie->dma_obj->cur->chn; - - if (status.donesta & BIT(chn)) { - clears.doneclr = 0x1 << chn; - dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + - PCIE_DMA_WR_INT_CLEAR, clears.asdword); - rk_pcie_handle_dma_interrupt(rk_pcie); - } - - if (status.abortsta & BIT(chn)) { - dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__); - clears.abortclr = 0x1 << chn; - dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + - PCIE_DMA_WR_INT_CLEAR, clears.asdword); + if (status.abortsta & BIT(chn)) { + dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__); + clears.abortclr = 0x1 << chn; + dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + + PCIE_DMA_WR_INT_CLEAR, clears.asdword); + } } status.asdword = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS); + for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) { + if (status.donesta & BIT(chn)) { + clears.doneclr = 0x1 << chn; + dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + + PCIE_DMA_RD_INT_CLEAR, clears.asdword); + if (rk_pcie->dma_obj && rk_pcie->dma_obj->cb) + rk_pcie->dma_obj->cb(rk_pcie->dma_obj, chn, DMA_FROM_BUS); + } - if (status.donesta & BIT(chn)) { - clears.doneclr = 0x1 << chn; - dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + - PCIE_DMA_RD_INT_CLEAR, clears.asdword); - rk_pcie_handle_dma_interrupt(rk_pcie); - } - - if (status.abortsta & BIT(chn)) { - dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__); - clears.abortclr = 0x1 << chn; - dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + - PCIE_DMA_RD_INT_CLEAR, clears.asdword); + if (status.abortsta & BIT(chn)) { + dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__); + clears.abortclr = 0x1 << chn; + dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + + PCIE_DMA_RD_INT_CLEAR, clears.asdword); + } } reg = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_MISC); @@ -2106,6 +2082,12 @@ retry_regulator: if (ret) goto remove_irq_domain; + ret = rk_pcie_init_dma_trx(rk_pcie); + if (ret) { + dev_err(dev, "failed to add dma extension\n"); + return ret; + } + if (rk_pcie->dma_obj) { rk_pcie->dma_obj->start_dma_func = rk_pcie_start_dma_dwc; rk_pcie->dma_obj->config_dma_func = rk_pcie_config_dma_dwc; diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 8d273c1c7c13..c6fcbcbc7291 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -40,10 +40,10 @@ #include "pcie-rockchip.h" #include "rockchip-pcie-dma.h" -static void rk_pcie_start_dma_rk3399(struct dma_trx_obj *obj) +static void rk_pcie_start_dma_rk3399(struct dma_trx_obj *obj, struct dma_table *cur) { struct rockchip_pcie *rockchip = dev_get_drvdata(obj->dev); - struct dma_table *tbl = obj->cur; + struct dma_table *tbl = cur; int chn = tbl->chn; rockchip_pcie_write(rockchip, (u32)(tbl->phys_descs & 0xffffffff), diff --git a/drivers/pci/controller/rockchip-pcie-dma.c b/drivers/pci/controller/rockchip-pcie-dma.c index 458f012c2ddd..6ffd33514095 100644 --- a/drivers/pci/controller/rockchip-pcie-dma.c +++ b/drivers/pci/controller/rockchip-pcie-dma.c @@ -154,6 +154,30 @@ static unsigned int rk_pcie_check_sum(unsigned int *src, int size) return result; } +static int rk_pcie_handle_dma_interrupt(struct dma_trx_obj *obj, u32 chn, enum dma_dir dir) +{ + struct dma_table *cur; + + cur = obj->cur; + if (!cur) { + pr_err("no pcie dma table\n"); + return 0; + } + + obj->dma_free = true; + obj->irq_num++; + + if (cur->dir == DMA_TO_BUS) { + if (list_empty(&obj->tbl_list)) { + if (obj->dma_free && + obj->loop_count >= obj->loop_count_threshold) + complete(&obj->done); + } + } + + return 0; +} + static void rk_pcie_prepare_dma(struct dma_trx_obj *obj, unsigned int idx, unsigned int bus_idx, unsigned int local_idx, size_t buf_size, @@ -295,7 +319,7 @@ static void rk_pcie_dma_trx_work(struct work_struct *work) return; } reinit_completion(&obj->done); - obj->start_dma_func(obj); + obj->start_dma_func(obj, table); } } } @@ -483,7 +507,7 @@ static void rk_pcie_send_addr_to_remote(struct dma_trx_obj *obj) table->chn = PCIE_DMA_DEFAULT_CHN; obj->config_dma_func(table); obj->cur = table; - obj->start_dma_func(obj); + obj->start_dma_func(obj, table); } static long rk_pcie_misc_ioctl(struct file *filp, unsigned int cmd, @@ -940,8 +964,9 @@ struct dma_trx_obj *rk_pcie_dma_obj_probe(struct device *dev) obj->irq_num = 0; obj->loop_count_threshold = 0; obj->ref_count = 0; - obj->version = 0x3; + obj->version = 0x4; init_completion(&obj->done); + obj->cb = rk_pcie_handle_dma_interrupt; mutex_init(&obj->count_mutex); rk_pcie_add_misc(obj); diff --git a/drivers/pci/controller/rockchip-pcie-dma.h b/drivers/pci/controller/rockchip-pcie-dma.h index 01f41947dac4..8ac55f021025 100644 --- a/drivers/pci/controller/rockchip-pcie-dma.h +++ b/drivers/pci/controller/rockchip-pcie-dma.h @@ -188,8 +188,9 @@ struct dma_trx_obj { unsigned long irq_num; struct dentry *pcie_root; struct pcie_misc_dev *pcie_dev; - void (*start_dma_func)(struct dma_trx_obj *obj); + void (*start_dma_func)(struct dma_trx_obj *obj, struct dma_table *table); void (*config_dma_func)(struct dma_table *table); + int (*cb)(struct dma_trx_obj *obj, u32 chn, enum dma_dir dir); ktime_t begin; ktime_t end; u64 cache_time_total; diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index c234b9ddedad..238668ea5394 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -746,6 +746,7 @@ static int rockchip_usb2phy_init(struct phy *phy) struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); int ret = 0; + unsigned int ul, ul_mask; mutex_lock(&rport->mutex); @@ -779,7 +780,12 @@ static int rockchip_usb2phy_init(struct phy *phy) } } else if (rport->port_id == USB2PHY_PORT_HOST) { if (rport->port_cfg->disfall_en.offset) { - rport->host_disconnect = true; + ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul); + if (ret < 0) + goto out; + ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend, + rport->port_cfg->utmi_ls.bitstart); + rport->host_disconnect = (ul & ul_mask) == 0 ? true : false; ret = rockchip_usb2phy_enable_host_disc_irq(rphy, rport, true); if (ret) { dev_err(rphy->dev, "failed to enable disconnect irq\n"); diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 6f7aa8ebc292..f32b831b941b 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -664,6 +664,12 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->mode) { case PHY_TYPE_PCIE: + /* Set SSC downward spread spectrum */ + val = readl(priv->mmio + (0x1f << 2)); + val &= ~GENMASK(5, 4); + val |= 0x01 << 4; + writel(val, priv->mmio + 0x7c); + param_write(priv->phy_grf, &cfg->con0_for_pcie, true); param_write(priv->phy_grf, &cfg->con1_for_pcie, true); param_write(priv->phy_grf, &cfg->con2_for_pcie, true); @@ -841,6 +847,26 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) } } + if (device_property_read_bool(priv->dev, "rockchip,enable-ssc")) { + val = readl(priv->mmio + (0x7 << 2)); + val |= BIT(4); + writel(val, priv->mmio + (0x7 << 2)); + + if (priv->mode == PHY_TYPE_PCIE && rate == 24000000) { + /* Xin24M T0_1 650mV */ + writel(0x00, priv->mmio + (0x10 << 2)); + writel(0x32, priv->mmio + (0x11 << 2)); + writel(0x00, priv->mmio + (0x1b << 2)); + writel(0x90, priv->mmio + (0x0a << 2)); + writel(0x02, priv->mmio + (0x0b << 2)); + writel(0x08, priv->mmio + (0x0c << 2)); + writel(0x57, priv->mmio + (0x0d << 2)); + writel(0x40, priv->mmio + (0x0e << 2)); + writel(0x5f, priv->mmio + (0x0f << 2)); + writel(0x10, priv->mmio + (0x20 << 2)); + } + } + return 0; } diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 7a1bdb739074..9bf56f0d93c9 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -40,7 +40,7 @@ #include "pinconf.h" #include "pinctrl-rockchip.h" -/** +/* * Generate a bitmask for setting a value (v) with a write mask bit in hiword * register 31:16 area. */ @@ -334,6 +334,7 @@ static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev, { struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); const struct rockchip_pin_group *grp; + struct device *dev = info->dev; struct pinctrl_map *new_map; struct device_node *parent; int map_num = 1; @@ -345,8 +346,7 @@ static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev, */ grp = pinctrl_name_to_group(info, np->name); if (!grp) { - dev_err(info->dev, "unable to find group for node %pOFn\n", - np); + dev_err(dev, "unable to find group for node %pOFn\n", np); return -EINVAL; } @@ -380,7 +380,7 @@ static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev, new_map[i].data.configs.num_configs = grp->data[i].nconfigs; } - dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", + dev_dbg(dev, "maps: function %s group %s num %d\n", (*map)->data.mux.function, (*map)->data.mux.group, map_num); return 0; @@ -535,95 +535,110 @@ static struct rockchip_mux_recalced_data rk3128_mux_recalced_data[] = { static struct rockchip_mux_recalced_data rk3308_mux_recalced_data[] = { { + /* gpio1b6_sel */ .num = 1, .pin = 14, .reg = 0x28, .bit = 12, .mask = 0xf }, { + /* gpio1b7_sel */ .num = 1, .pin = 15, .reg = 0x2c, .bit = 0, .mask = 0x3 }, { + /* gpio1c2_sel */ .num = 1, .pin = 18, .reg = 0x30, .bit = 4, .mask = 0xf }, { + /* gpio1c3_sel */ .num = 1, .pin = 19, .reg = 0x30, .bit = 8, .mask = 0xf }, { + /* gpio1c4_sel */ .num = 1, .pin = 20, .reg = 0x30, .bit = 12, .mask = 0xf }, { + /* gpio1c5_sel */ .num = 1, .pin = 21, .reg = 0x34, .bit = 0, .mask = 0xf }, { + /* gpio1c6_sel */ .num = 1, .pin = 22, .reg = 0x34, .bit = 4, .mask = 0xf }, { + /* gpio1c7_sel */ .num = 1, .pin = 23, .reg = 0x34, .bit = 8, .mask = 0xf }, { - .num = 3, - .pin = 12, - .reg = 0x68, - .bit = 8, - .mask = 0xf - }, { - .num = 3, - .pin = 13, - .reg = 0x68, - .bit = 12, - .mask = 0xf - }, { + /* gpio2a2_sel_plus */ .num = 2, .pin = 2, .reg = 0x608, .bit = 0, .mask = 0x7 }, { + /* gpio2a3_sel_plus */ .num = 2, .pin = 3, .reg = 0x608, .bit = 4, .mask = 0x7 }, { + /* gpio2c0_sel_plus */ .num = 2, .pin = 16, .reg = 0x610, .bit = 8, .mask = 0x7 }, { + /* gpio3b2_sel_plus */ .num = 3, .pin = 10, .reg = 0x610, .bit = 0, .mask = 0x7 }, { + /* gpio3b3_sel_plus */ .num = 3, .pin = 11, - .reg = 0x610, - .bit = 4, - .mask = 0x7 + .reg = 0x68, + .bit = 6, + .mask = 0x3 + }, { + /* gpio3b4_sel */ + .num = 3, + .pin = 12, + .reg = 0x68, + .bit = 8, + .mask = 0xf + }, { + /* gpio3b5_sel */ + .num = 3, + .pin = 13, + .reg = 0x68, + .bit = 12, + .mask = 0xf }, }; @@ -1126,20 +1141,20 @@ static int rockchip_verify_mux(struct rockchip_pin_bank *bank, int pin, int mux) { struct rockchip_pinctrl *info = bank->drvdata; + struct device *dev = info->dev; int iomux_num = (pin / 8); if (iomux_num > 3) return -EINVAL; if (bank->iomux[iomux_num].type & IOMUX_UNROUTED) { - dev_err(info->dev, "pin %d is unrouted\n", pin); + dev_err(dev, "pin %d is unrouted\n", pin); return -EINVAL; } if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY) { if (mux != RK_FUNC_GPIO) { - dev_err(info->dev, - "pin %d only supports a gpio mux\n", pin); + dev_err(dev, "pin %d only supports a gpio mux\n", pin); return -ENOTSUPP; } } @@ -1164,6 +1179,7 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct device *dev = info->dev; int iomux_num = (pin / 8); struct regmap *regmap; int reg, ret, mask, mux_type; @@ -1177,8 +1193,7 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY) return 0; - dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n", - bank->bank_num, pin, mux); + dev_dbg(dev, "setting mux of GPIO%d-%d to %d\n", bank->bank_num, pin, mux); if (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU) regmap = info->regmap_pmu; @@ -1301,9 +1316,9 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) #define PX30_PULL_PINS_PER_REG 8 #define PX30_PULL_BANK_STRIDE 16 -static void px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1323,6 +1338,8 @@ static void px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / PX30_PULL_PINS_PER_REG) * 4); *bit = (pin_num % PX30_PULL_PINS_PER_REG); *bit *= PX30_PULL_BITS_PER_PIN; + + return 0; } #define PX30_DRV_PMU_OFFSET 0x20 @@ -1331,9 +1348,9 @@ static void px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, #define PX30_DRV_PINS_PER_REG 8 #define PX30_DRV_BANK_STRIDE 16 -static void px30_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int px30_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1353,6 +1370,8 @@ static void px30_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / PX30_DRV_PINS_PER_REG) * 4); *bit = (pin_num % PX30_DRV_PINS_PER_REG); *bit *= PX30_DRV_BITS_PER_PIN; + + return 0; } #define PX30_SCHMITT_PMU_OFFSET 0x38 @@ -1394,9 +1413,9 @@ static int px30_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, #define RV1106_DRV_GPIO3_OFFSET 0x20100 #define RV1106_DRV_GPIO4_OFFSET 0x30020 -static void rv1106_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rv1106_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1435,6 +1454,8 @@ static void rv1106_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RV1106_DRV_PINS_PER_REG) * 4); *bit = pin_num % RV1106_DRV_PINS_PER_REG; *bit *= RV1106_DRV_BITS_PER_PIN; + + return 0; } #define RV1106_PULL_BITS_PER_PIN 2 @@ -1445,9 +1466,9 @@ static void rv1106_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, #define RV1106_PULL_GPIO3_OFFSET 0x201E0 #define RV1106_PULL_GPIO4_OFFSET 0x30070 -static void rv1106_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rv1106_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1486,6 +1507,8 @@ static void rv1106_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RV1106_PULL_PINS_PER_REG) * 4); *bit = pin_num % RV1106_PULL_PINS_PER_REG; *bit *= RV1106_PULL_BITS_PER_PIN; + + return 0; } #define RV1106_SMT_BITS_PER_PIN 1 @@ -1548,9 +1571,9 @@ static int rv1106_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, #define RV1108_PULL_BITS_PER_PIN 2 #define RV1108_PULL_BANK_STRIDE 16 -static void rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1569,6 +1592,8 @@ static void rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RV1108_PULL_PINS_PER_REG) * 4); *bit = (pin_num % RV1108_PULL_PINS_PER_REG); *bit *= RV1108_PULL_BITS_PER_PIN; + + return 0; } #define RV1108_DRV_PMU_OFFSET 0x20 @@ -1577,9 +1602,9 @@ static void rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, #define RV1108_DRV_PINS_PER_REG 8 #define RV1108_DRV_BANK_STRIDE 16 -static void rv1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rv1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1599,6 +1624,8 @@ static void rv1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RV1108_DRV_PINS_PER_REG) * 4); *bit = pin_num % RV1108_DRV_PINS_PER_REG; *bit *= RV1108_DRV_BITS_PER_PIN; + + return 0; } #define RV1108_SCHMITT_PMU_OFFSET 0x30 @@ -1638,9 +1665,9 @@ static int rv1108_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, #define RV1126_PULL_BANK_STRIDE 16 #define RV1126_GPIO_C4_D7(p) (p >= 20 && p <= 31) /* GPIO0_C4 ~ GPIO0_D7 */ -static void rv1126_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rv1126_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1652,7 +1679,7 @@ static void rv1126_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg -= (((31 - pin_num) / RV1126_PULL_PINS_PER_REG + 1) * 4); *bit = pin_num % RV1126_PULL_PINS_PER_REG; *bit *= RV1126_PULL_BITS_PER_PIN; - return; + return 0; } *regmap = info->regmap_pmu; *reg = RV1126_PULL_PMU_OFFSET; @@ -1665,6 +1692,8 @@ static void rv1126_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RV1126_PULL_PINS_PER_REG) * 4); *bit = (pin_num % RV1126_PULL_PINS_PER_REG); *bit *= RV1126_PULL_BITS_PER_PIN; + + return 0; } #define RV1126_DRV_PMU_OFFSET 0x20 @@ -1673,9 +1702,9 @@ static void rv1126_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, #define RV1126_DRV_PINS_PER_REG 4 #define RV1126_DRV_BANK_STRIDE 32 -static void rv1126_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rv1126_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1688,7 +1717,7 @@ static void rv1126_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *reg -= 0x4; *bit = pin_num % RV1126_DRV_PINS_PER_REG; *bit *= RV1126_DRV_BITS_PER_PIN; - return; + return 0; } *regmap = info->regmap_pmu; *reg = RV1126_DRV_PMU_OFFSET; @@ -1701,6 +1730,8 @@ static void rv1126_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RV1126_DRV_PINS_PER_REG) * 4); *bit = pin_num % RV1126_DRV_PINS_PER_REG; *bit *= RV1126_DRV_BITS_PER_PIN; + + return 0; } #define RV1126_SCHMITT_PMU_OFFSET 0x60 @@ -1766,9 +1797,9 @@ static int rk3308_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, #define RK1808_PULL_BITS_PER_PIN 2 #define RK1808_PULL_BANK_STRIDE 16 -static void rk1808_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk1808_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1784,6 +1815,8 @@ static void rk1808_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RK1808_PULL_PINS_PER_REG) * 4); *bit = (pin_num % RK1808_PULL_PINS_PER_REG); *bit *= RK1808_PULL_BITS_PER_PIN; + + return 0; } #define RK1808_DRV_PMU_OFFSET 0x20 @@ -1792,10 +1825,10 @@ static void rk1808_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, #define RK1808_DRV_PINS_PER_REG 8 #define RK1808_DRV_BANK_STRIDE 16 -static void rk1808_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, - struct regmap **regmap, - int *reg, u8 *bit) +static int rk1808_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, + struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1811,6 +1844,8 @@ static void rk1808_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RK1808_DRV_PINS_PER_REG) * 4); *bit = pin_num % RK1808_DRV_PINS_PER_REG; *bit *= RK1808_DRV_BITS_PER_PIN; + + return 0; } #define RK1808_SR_PMU_OFFSET 0x0030 @@ -1869,9 +1904,9 @@ static int rk1808_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, #define RK2928_PULL_PINS_PER_REG 16 #define RK2928_PULL_BANK_STRIDE 8 -static void rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1881,13 +1916,15 @@ static void rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += (pin_num / RK2928_PULL_PINS_PER_REG) * 4; *bit = pin_num % RK2928_PULL_PINS_PER_REG; + + return 0; }; #define RK3128_PULL_OFFSET 0x118 -static void rk3128_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3128_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1897,6 +1934,8 @@ static void rk3128_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin_num / RK2928_PULL_PINS_PER_REG) * 4); *bit = pin_num % RK2928_PULL_PINS_PER_REG; + + return 0; } #define RK3188_PULL_OFFSET 0x164 @@ -1905,9 +1944,9 @@ static void rk3128_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, #define RK3188_PULL_BANK_STRIDE 16 #define RK3188_PULL_PMU_OFFSET 0x64 -static void rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1937,12 +1976,14 @@ static void rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = 7 - (pin_num % RK3188_PULL_PINS_PER_REG); *bit *= RK3188_PULL_BITS_PER_PIN; } + + return 0; } #define RK3288_PULL_OFFSET 0x140 -static void rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -1966,6 +2007,8 @@ static void rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3188_PULL_PINS_PER_REG); *bit *= RK3188_PULL_BITS_PER_PIN; } + + return 0; } #define RK3288_DRV_PMU_OFFSET 0x70 @@ -1974,9 +2017,9 @@ static void rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, #define RK3288_DRV_PINS_PER_REG 8 #define RK3288_DRV_BANK_STRIDE 16 -static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2000,13 +2043,15 @@ static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3288_DRV_PINS_PER_REG); *bit *= RK3288_DRV_BITS_PER_PIN; } + + return 0; } #define RK3228_PULL_OFFSET 0x100 -static void rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2017,13 +2062,15 @@ static void rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3188_PULL_PINS_PER_REG); *bit *= RK3188_PULL_BITS_PER_PIN; + + return 0; } #define RK3228_DRV_GRF_OFFSET 0x200 -static void rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2034,13 +2081,15 @@ static void rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3288_DRV_PINS_PER_REG); *bit *= RK3288_DRV_BITS_PER_PIN; + + return 0; } #define RK3308_PULL_OFFSET 0xa0 -static void rk3308_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3308_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2051,13 +2100,15 @@ static void rk3308_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3188_PULL_PINS_PER_REG); *bit *= RK3188_PULL_BITS_PER_PIN; + + return 0; } #define RK3308_DRV_GRF_OFFSET 0x100 -static void rk3308_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3308_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2068,6 +2119,8 @@ static void rk3308_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3288_DRV_PINS_PER_REG); *bit *= RK3288_DRV_BITS_PER_PIN; + + return 0; } #define RK3308_SLEW_RATE_GRF_OFFSET 0x150 @@ -2096,9 +2149,9 @@ static int rk3308_calc_slew_rate_reg_and_bit(struct rockchip_pin_bank *bank, #define RK3368_PULL_GRF_OFFSET 0x100 #define RK3368_PULL_PMU_OFFSET 0x10 -static void rk3368_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3368_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2122,14 +2175,16 @@ static void rk3368_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3188_PULL_PINS_PER_REG); *bit *= RK3188_PULL_BITS_PER_PIN; } + + return 0; } #define RK3368_DRV_PMU_OFFSET 0x20 #define RK3368_DRV_GRF_OFFSET 0x200 -static void rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2153,15 +2208,17 @@ static void rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3288_DRV_PINS_PER_REG); *bit *= RK3288_DRV_BITS_PER_PIN; } + + return 0; } #define RK3399_PULL_GRF_OFFSET 0xe040 #define RK3399_PULL_PMU_OFFSET 0x40 #define RK3399_DRV_3BITS_PER_PIN 3 -static void rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2187,11 +2244,13 @@ static void rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3188_PULL_PINS_PER_REG); *bit *= RK3188_PULL_BITS_PER_PIN; } + + return 0; } -static void rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; int drv_num = (pin_num / 8); @@ -2208,6 +2267,8 @@ static void rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % 8) * 3; else *bit = (pin_num % 8) * 2; + + return 0; } #define RK3568_SR_PMU_OFFSET 0x60 @@ -2244,9 +2305,9 @@ static int rk3568_calc_slew_rate_reg_and_bit(struct rockchip_pin_bank *bank, #define RK3568_PULL_PINS_PER_REG 8 #define RK3568_PULL_BANK_STRIDE 0x10 -static void rk3568_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3568_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2267,6 +2328,8 @@ static void rk3568_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3568_PULL_PINS_PER_REG); *bit *= RK3568_PULL_BITS_PER_PIN; } + + return 0; } #define RK3568_DRV_PMU_OFFSET 0x70 @@ -2275,9 +2338,9 @@ static void rk3568_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, #define RK3568_DRV_PINS_PER_REG 2 #define RK3568_DRV_BANK_STRIDE 0x40 -static void rk3568_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3568_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; @@ -2304,6 +2367,8 @@ static void rk3568_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, ((bank->bank_num == 2 || bank->bank_num == 3 || bank->bank_num == 4) && (pin_num == 7 || pin_num == 15 || pin_num == 23 || pin_num == 31))) *bit -= RK3568_DRV_BITS_PER_PIN; + + return 0; } #define RK3588_PMU1_IOC_REG 0x0000 @@ -2413,9 +2478,9 @@ static const u32 rk3588_smt_regs[][2] = { #define RK3588_PULL_BITS_PER_PIN 2 #define RK3588_PULL_PINS_PER_REG 8 -static void rk3588_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3588_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; u8 bank_num = bank->bank_num; @@ -2434,14 +2499,16 @@ static void rk3588_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin - rk3588_p_regs[i][0]) / RK3588_PULL_PINS_PER_REG) * 4; *bit = pin_num % RK3588_PULL_PINS_PER_REG; *bit *= RK3588_PULL_BITS_PER_PIN; + + return 0; } #define RK3588_DRV_BITS_PER_PIN 4 #define RK3588_DRV_PINS_PER_REG 4 -static void rk3588_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit) +static int rk3588_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) { struct rockchip_pinctrl *info = bank->drvdata; u8 bank_num = bank->bank_num; @@ -2460,6 +2527,8 @@ static void rk3588_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *reg += ((pin - rk3588_ds_regs[i][0]) / RK3588_DRV_PINS_PER_REG) * 4; *bit = pin_num % RK3588_DRV_PINS_PER_REG; *bit *= RK3588_DRV_BITS_PER_PIN; + + return 0; } #define RK3588_SMT_BITS_PER_PIN 1 @@ -2505,13 +2574,16 @@ static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank, { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct device *dev = info->dev; struct regmap *regmap; int reg, ret; u32 data, temp, rmask_bits; u8 bit; int drv_type = bank->drv[pin_num / 8].drv_type; - ctrl->drv_calc_reg(bank, pin_num, ®map, ®, &bit); + ret = ctrl->drv_calc_reg(bank, pin_num, ®map, ®, &bit); + if (ret) + return ret; switch (drv_type) { case DRV_TYPE_IO_1V8_3V0_AUTO: @@ -2550,7 +2622,7 @@ static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank, bit -= 16; break; default: - dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n", + dev_err(dev, "unsupported bit: %d for pinctrl drive type: %d\n", bit, drv_type); return -EINVAL; } @@ -2563,8 +2635,7 @@ static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank, rmask_bits = RK3288_DRV_BITS_PER_PIN; break; default: - dev_err(info->dev, "unsupported pinctrl drive type: %d\n", - drv_type); + dev_err(dev, "unsupported pinctrl drive type: %d\n", drv_type); return -EINVAL; } @@ -2597,16 +2668,20 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct device *dev = info->dev; struct regmap *regmap; int reg, ret, i, err; u32 data, rmask, rmask_bits, temp; u8 bit; int drv_type = bank->drv[pin_num / 8].drv_type; - dev_dbg(info->dev, "setting drive of GPIO%d-%d to %d\n", + dev_dbg(dev, "setting drive of GPIO%d-%d to %d\n", bank->bank_num, pin_num, strength); - ctrl->drv_calc_reg(bank, pin_num, ®map, ®, &bit); + ret = ctrl->drv_calc_reg(bank, pin_num, ®map, ®, &bit); + if (ret) + return ret; + if (ctrl->type == RV1126 || ctrl->type == RK3588) { rmask_bits = RV1126_DRV_BITS_PER_PIN; ret = strength; @@ -2629,8 +2704,7 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, } if (ret < 0) { - dev_err(info->dev, "unsupported driver strength %d\n", - strength); + dev_err(dev, "unsupported driver strength %d\n", strength); return ret; } @@ -2669,7 +2743,7 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, bit -= 16; break; default: - dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n", + dev_err(dev, "unsupported bit: %d for pinctrl drive type: %d\n", bit, drv_type); return -EINVAL; } @@ -2681,8 +2755,7 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, rmask_bits = RK3288_DRV_BITS_PER_PIN; break; default: - dev_err(info->dev, "unsupported pinctrl drive type: %d\n", - drv_type); + dev_err(dev, "unsupported pinctrl drive type: %d\n", drv_type); return -EINVAL; } @@ -2751,6 +2824,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct device *dev = info->dev; struct regmap *regmap; int reg, ret, pull_type; u8 bit; @@ -2760,7 +2834,9 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) if (ctrl->type == RK3066B) return PIN_CONFIG_BIAS_DISABLE; - ctrl->pull_calc_reg(bank, pin_num, ®map, ®, &bit); + ret = ctrl->pull_calc_reg(bank, pin_num, ®map, ®, &bit); + if (ret) + return ret; ret = regmap_read(regmap, reg, &data); if (ret) @@ -2790,7 +2866,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) return rockchip_pull_list[pull_type][data]; default: - dev_err(info->dev, "unsupported pinctrl type\n"); + dev_err(dev, "unsupported pinctrl type\n"); return -EINVAL; }; } @@ -2800,19 +2876,21 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct device *dev = info->dev; struct regmap *regmap; int reg, ret, i, pull_type; u8 bit; u32 data, rmask; - dev_dbg(info->dev, "setting pull of GPIO%d-%d to %d\n", - bank->bank_num, pin_num, pull); + dev_dbg(dev, "setting pull of GPIO%d-%d to %d\n", bank->bank_num, pin_num, pull); /* rk3066b does support any pulls */ if (ctrl->type == RK3066B) return pull ? -EINVAL : 0; - ctrl->pull_calc_reg(bank, pin_num, ®map, ®, &bit); + ret = ctrl->pull_calc_reg(bank, pin_num, ®map, ®, &bit); + if (ret) + return ret; switch (ctrl->type) { case RK2928: @@ -2853,8 +2931,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, } if (ret < 0) { - dev_err(info->dev, "unsupported pull setting %d\n", - pull); + dev_err(dev, "unsupported pull setting %d\n", pull); return ret; } @@ -2866,7 +2943,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, ret = regmap_update_bits(regmap, reg, rmask, data); break; default: - dev_err(info->dev, "unsupported pinctrl type\n"); + dev_err(dev, "unsupported pinctrl type\n"); return -EINVAL; } @@ -2957,12 +3034,13 @@ static int rockchip_set_schmitt(struct rockchip_pin_bank *bank, { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; + struct device *dev = info->dev; struct regmap *regmap; int reg, ret; u8 bit; u32 data, rmask; - dev_dbg(info->dev, "setting input schmitt of GPIO%d-%d to %d\n", + dev_dbg(dev, "setting input schmitt of GPIO%d-%d to %d\n", bank->bank_num, pin_num, enable); ret = ctrl->schmitt_calc_reg(bank, pin_num, ®map, ®, &bit); @@ -3105,10 +3183,11 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); const unsigned int *pins = info->groups[group].pins; const struct rockchip_pin_config *data = info->groups[group].data; + struct device *dev = info->dev; struct rockchip_pin_bank *bank; int cnt, ret = 0; - dev_dbg(info->dev, "enable function %s group %s\n", + dev_dbg(dev, "enable function %s group %s\n", info->functions[selector].name, info->groups[group].name); /* @@ -3173,19 +3252,20 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, return false; } -static int rockchip_pinconf_defer_output(struct rockchip_pin_bank *bank, - unsigned int pin, u32 arg) +static int rockchip_pinconf_defer_pin(struct rockchip_pin_bank *bank, + unsigned int pin, u32 param, u32 arg) { - struct rockchip_pin_output_deferred *cfg; + struct rockchip_pin_deferred *cfg; cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; cfg->pin = pin; + cfg->param = param; cfg->arg = arg; - list_add_tail(&cfg->head, &bank->deferred_output); + list_add_tail(&cfg->head, &bank->deferred_pins); return 0; } @@ -3206,6 +3286,25 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); + if (param == PIN_CONFIG_OUTPUT || param == PIN_CONFIG_INPUT_ENABLE) { + /* + * Check for gpio driver not being probed yet. + * The lock makes sure that either gpio-probe has completed + * or the gpio driver hasn't probed yet. + */ + mutex_lock(&bank->deferred_lock); + if (!gpio || !gpio->direction_output) { + rc = rockchip_pinconf_defer_pin(bank, pin - bank->pin_base, param, + arg); + mutex_unlock(&bank->deferred_lock); + if (rc) + return rc; + + break; + } + mutex_unlock(&bank->deferred_lock); + } + switch (param) { case PIN_CONFIG_BIAS_DISABLE: rc = rockchip_set_pull(bank, pin - bank->pin_base, @@ -3234,27 +3333,21 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, if (rc != RK_FUNC_GPIO) return -EINVAL; - /* - * Check for gpio driver not being probed yet. - * The lock makes sure that either gpio-probe has completed - * or the gpio driver hasn't probed yet. - */ - mutex_lock(&bank->deferred_lock); - if (!gpio || !gpio->direction_output) { - rc = rockchip_pinconf_defer_output(bank, pin - bank->pin_base, arg); - mutex_unlock(&bank->deferred_lock); - if (rc) - return rc; - - break; - } - mutex_unlock(&bank->deferred_lock); - rc = gpio->direction_output(gpio, pin - bank->pin_base, arg); if (rc) return rc; break; + case PIN_CONFIG_INPUT_ENABLE: + rc = rockchip_set_mux(bank, pin - bank->pin_base, + RK_FUNC_GPIO); + if (rc != RK_FUNC_GPIO) + return -EINVAL; + + rc = gpio->direction_input(gpio, pin - bank->pin_base); + if (rc) + return rc; + break; case PIN_CONFIG_DRIVE_STRENGTH: /* rk3288 is the first with per-pin drive-strength */ if (!info->ctrl->drv_calc_reg) @@ -3408,6 +3501,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, struct rockchip_pinctrl *info, u32 index) { + struct device *dev = info->dev; struct rockchip_pin_bank *bank; int size; const __be32 *list; @@ -3415,7 +3509,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, int i, j; int ret; - dev_dbg(info->dev, "group(%d): %pOFn\n", index, np); + dev_dbg(dev, "group(%d): %pOFn\n", index, np); /* Initialise group */ grp->name = np->name; @@ -3427,19 +3521,13 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, list = of_get_property(np, "rockchip,pins", &size); /* we do not check return since it's safe node passed down */ size /= sizeof(*list); - if (!size || size % 4) { - dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n"); - return -EINVAL; - } + if (!size || size % 4) + return dev_err_probe(dev, -EINVAL, "wrong pins number or pins and configs should be by 4\n"); grp->npins = size / 4; - grp->pins = devm_kcalloc(info->dev, grp->npins, sizeof(unsigned int), - GFP_KERNEL); - grp->data = devm_kcalloc(info->dev, - grp->npins, - sizeof(struct rockchip_pin_config), - GFP_KERNEL); + grp->pins = devm_kcalloc(dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL); + grp->data = devm_kcalloc(dev, grp->npins, sizeof(*grp->data), GFP_KERNEL); if (!grp->pins || !grp->data) return -ENOMEM; @@ -3473,6 +3561,7 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np, struct rockchip_pinctrl *info, u32 index) { + struct device *dev = info->dev; struct device_node *child; struct rockchip_pmx_func *func; struct rockchip_pin_group *grp; @@ -3480,7 +3569,7 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np, static u32 grp_index; u32 i = 0; - dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np); + dev_dbg(dev, "parse function(%d): %pOFn\n", index, np); func = &info->functions[index]; @@ -3490,8 +3579,7 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np, if (func->ngroups <= 0) return 0; - func->groups = devm_kcalloc(info->dev, - func->ngroups, sizeof(char *), GFP_KERNEL); + func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), GFP_KERNEL); if (!func->groups) return -ENOMEM; @@ -3519,20 +3607,14 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, rockchip_pinctrl_child_count(info, np); - dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); - dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + dev_dbg(dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(dev, "ngroups = %d\n", info->ngroups); - info->functions = devm_kcalloc(dev, - info->nfunctions, - sizeof(struct rockchip_pmx_func), - GFP_KERNEL); + info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), GFP_KERNEL); if (!info->functions) return -ENOMEM; - info->groups = devm_kcalloc(dev, - info->ngroups, - sizeof(struct rockchip_pin_group), - GFP_KERNEL); + info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), GFP_KERNEL); if (!info->groups) return -ENOMEM; @@ -3544,7 +3626,7 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, ret = rockchip_pinctrl_parse_functions(child, info, i++); if (ret) { - dev_err(&pdev->dev, "failed to parse function\n"); + dev_err(dev, "failed to parse function\n"); of_node_put(child); return ret; } @@ -3559,6 +3641,7 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, struct pinctrl_desc *ctrldesc = &info->pctl; struct pinctrl_pin_desc *pindesc, *pdesc; struct rockchip_pin_bank *pin_bank; + struct device *dev = &pdev->dev; int pin, bank, ret; int k; @@ -3568,9 +3651,7 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, ctrldesc->pmxops = &rockchip_pmx_ops; ctrldesc->confops = &rockchip_pinconf_ops; - pindesc = devm_kcalloc(&pdev->dev, - info->ctrl->nr_pins, sizeof(*pindesc), - GFP_KERNEL); + pindesc = devm_kcalloc(dev, info->ctrl->nr_pins, sizeof(*pindesc), GFP_KERNEL); if (!pindesc) return -ENOMEM; @@ -3587,7 +3668,7 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, pdesc++; } - INIT_LIST_HEAD(&pin_bank->deferred_output); + INIT_LIST_HEAD(&pin_bank->deferred_pins); mutex_init(&pin_bank->deferred_lock); } @@ -3595,11 +3676,9 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, if (ret) return ret; - info->pctl_dev = devm_pinctrl_register(&pdev->dev, ctrldesc, info); - if (IS_ERR(info->pctl_dev)) { - dev_err(&pdev->dev, "could not register pinctrl driver\n"); - return PTR_ERR(info->pctl_dev); - } + info->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info); + if (IS_ERR(info->pctl_dev)) + return dev_err_probe(dev, PTR_ERR(info->pctl_dev), "could not register pinctrl driver\n"); return 0; } @@ -3613,8 +3692,9 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( struct rockchip_pinctrl *d, struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; const struct of_device_id *match; - struct device_node *node = pdev->dev.of_node; struct rockchip_pin_ctrl *ctrl; struct rockchip_pin_bank *bank; int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j; @@ -3671,7 +3751,7 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( drv_pmu_offs : drv_grf_offs; } - dev_dbg(d->dev, "bank %d, iomux %d has iom_offset 0x%x drv_offset 0x%x\n", + dev_dbg(dev, "bank %d, iomux %d has iom_offset 0x%x drv_offset 0x%x\n", i, j, iom->offset, drv->offset); /* @@ -3820,16 +3900,14 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) { struct rockchip_pinctrl *info; struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node, *node; struct rockchip_pin_ctrl *ctrl; - struct device_node *np = pdev->dev.of_node, *node; struct resource *res; void __iomem *base; int ret; - if (!dev->of_node) { - dev_err(dev, "device tree node not found\n"); - return -ENODEV; - } + if (!dev->of_node) + return dev_err_probe(dev, -ENODEV, "device tree node not found\n"); info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -3838,10 +3916,8 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) info->dev = dev; ctrl = rockchip_pinctrl_get_soc_data(info, pdev); - if (!ctrl) { - dev_err(dev, "driver data not available\n"); - return -EINVAL; - } + if (!ctrl) + return dev_err_probe(dev, -EINVAL, "driver data not available\n"); info->ctrl = ctrl; node = of_parse_phandle(np, "rockchip,grf", 0); @@ -3850,32 +3926,28 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) if (IS_ERR(info->regmap_base)) return PTR_ERR(info->regmap_base); } else { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); rockchip_regmap_config.max_register = resource_size(res) - 4; rockchip_regmap_config.name = "rockchip,pinctrl"; - info->regmap_base = devm_regmap_init_mmio(&pdev->dev, base, - &rockchip_regmap_config); + info->regmap_base = + devm_regmap_init_mmio(dev, base, &rockchip_regmap_config); /* to check for the old dt-bindings */ info->reg_size = resource_size(res); /* Honor the old binding, with pull registers as 2nd resource */ if (ctrl->type == RK3188 && info->reg_size < 0x200) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 1, &res); if (IS_ERR(base)) return PTR_ERR(base); - rockchip_regmap_config.max_register = - resource_size(res) - 4; + rockchip_regmap_config.max_register = resource_size(res) - 4; rockchip_regmap_config.name = "rockchip,pinctrl-pull"; - info->regmap_pull = devm_regmap_init_mmio(&pdev->dev, - base, - &rockchip_regmap_config); + info->regmap_pull = + devm_regmap_init_mmio(dev, base, &rockchip_regmap_config); } } @@ -3887,9 +3959,8 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) return PTR_ERR(info->regmap_pmu); } - /* Special handle for some Socs */ - if (ctrl->soc_data_init) { - ret = ctrl->soc_data_init(info); + if (IS_ENABLED(CONFIG_CPU_RK3308) && ctrl->type == RK3308) { + ret = rk3308_soc_data_init(info); if (ret) return ret; } @@ -3901,11 +3972,10 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, info); g_pctldev = info->pctl_dev; - ret = of_platform_populate(np, rockchip_bank_match, NULL, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to register gpio device\n"); - return ret; - } + ret = of_platform_populate(np, NULL, NULL, &pdev->dev); + if (ret) + return dev_err_probe(dev, ret, "failed to register gpio device\n"); + dev_info(dev, "probed %s\n", dev_name(dev)); return 0; @@ -3915,7 +3985,7 @@ static int rockchip_pinctrl_remove(struct platform_device *pdev) { struct rockchip_pinctrl *info = platform_get_drvdata(pdev); struct rockchip_pin_bank *bank; - struct rockchip_pin_output_deferred *cfg; + struct rockchip_pin_deferred *cfg; int i; g_pctldev = NULL; @@ -3925,9 +3995,9 @@ static int rockchip_pinctrl_remove(struct platform_device *pdev) bank = &info->ctrl->pin_banks[i]; mutex_lock(&bank->deferred_lock); - while (!list_empty(&bank->deferred_output)) { - cfg = list_first_entry(&bank->deferred_output, - struct rockchip_pin_output_deferred, head); + while (!list_empty(&bank->deferred_pins)) { + cfg = list_first_entry(&bank->deferred_pins, + struct rockchip_pin_deferred, head); list_del(&cfg->head); kfree(cfg); } @@ -4335,7 +4405,6 @@ static struct rockchip_pin_ctrl rk3308_pin_ctrl __maybe_unused = { .niomux_recalced = ARRAY_SIZE(rk3308_mux_recalced_data), .iomux_routes = rk3308_mux_route_data, .niomux_routes = ARRAY_SIZE(rk3308_mux_route_data), - .soc_data_init = rk3308_soc_data_init, .pull_calc_reg = rk3308_calc_pull_reg_and_bit, .drv_calc_reg = rk3308_calc_drv_reg_and_bit, .schmitt_calc_reg = rk3308_calc_schmitt_reg_and_bit, diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h index de40db3244fc..2faedfb9ac24 100644 --- a/drivers/pinctrl/pinctrl-rockchip.h +++ b/drivers/pinctrl/pinctrl-rockchip.h @@ -343,7 +343,7 @@ struct rockchip_pin_bank { u32 toggle_edge_mode; u32 recalced_mask; u32 route_mask; - struct list_head deferred_output; + struct list_head deferred_pins; struct mutex deferred_lock; }; @@ -401,17 +401,12 @@ struct rockchip_pin_ctrl { u32 niomux_recalced; struct rockchip_mux_route_data *iomux_routes; u32 niomux_routes; - - int (*ctrl_data_re_init)(struct rockchip_pin_ctrl *ctrl); - - int (*soc_data_init)(struct rockchip_pinctrl *info); - - void (*pull_calc_reg)(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit); - void (*drv_calc_reg)(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit); + int (*pull_calc_reg)(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit); + int (*drv_calc_reg)(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit); int (*schmitt_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, struct regmap **regmap, int *reg, u8 *bit); @@ -426,9 +421,12 @@ struct rockchip_pin_config { unsigned int nconfigs; }; -struct rockchip_pin_output_deferred { +enum pin_config_param; + +struct rockchip_pin_deferred { struct list_head head; unsigned int pin; + enum pin_config_param param; u32 arg; }; diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index feaaa80caa9f..b0bb534f241e 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -51,6 +51,8 @@ static int get_reboot_mode_magic(struct reboot_mode_driver *reboot, return magic; } +static int last_magic; + static void reboot_mode_write(struct reboot_mode_driver *reboot, const void *cmd) { @@ -59,8 +61,10 @@ static void reboot_mode_write(struct reboot_mode_driver *reboot, magic = get_reboot_mode_magic(reboot, cmd); if (!magic) magic = get_reboot_mode_magic(reboot, NULL); - if (magic) + if (magic) { reboot->write(reboot, magic); + last_magic = magic; + } } static int reboot_mode_notify(struct notifier_block *this, @@ -74,6 +78,18 @@ static int reboot_mode_notify(struct notifier_block *this, return NOTIFY_DONE; } +static int reboot_mode_pre_restart_notify(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct reboot_mode_driver *reboot; + + reboot = container_of(this, struct reboot_mode_driver, pre_restart_notifier); + if (cmd || !last_magic) + reboot_mode_write(reboot, cmd); + + return NOTIFY_DONE; +} + static int reboot_mode_panic_notify(struct notifier_block *this, unsigned long ev, void *ptr) { @@ -151,9 +167,10 @@ int reboot_mode_register(struct reboot_mode_driver *reboot) boot_mode_parse(reboot); reboot->reboot_notifier.notifier_call = reboot_mode_notify; + reboot->pre_restart_notifier.notifier_call = reboot_mode_pre_restart_notify; reboot->panic_notifier.notifier_call = reboot_mode_panic_notify; register_reboot_notifier(&reboot->reboot_notifier); - register_pre_restart_handler(&reboot->reboot_notifier); + register_pre_restart_handler(&reboot->pre_restart_notifier); atomic_notifier_chain_register(&panic_notifier_list, &reboot->panic_notifier); ret = sysfs_create_file(kernel_kobj, &kobj_boot_mode.attr); diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index b5ed7a16e3d3..474f05629457 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -633,7 +633,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) return 0; if (!power_on && soc_is_px30s()) { - if (genpd->name && !strcmp(genpd->name, "pd_gpu")) + if (genpd->name && !strcmp(genpd->name, "gpu")) return 0; } diff --git a/drivers/soc/rockchip/rockchip_opp_select.c b/drivers/soc/rockchip/rockchip_opp_select.c index 2c50c0e57215..4a50b4a6a347 100644 --- a/drivers/soc/rockchip/rockchip_opp_select.c +++ b/drivers/soc/rockchip/rockchip_opp_select.c @@ -1728,6 +1728,48 @@ out: } EXPORT_SYMBOL(rockchip_init_opp_table); +int rockchip_opp_dump_cur_state(struct device *dev) +{ + struct clk *clk; + struct opp_table *opp_table; + int volt_vdd, volt_mem; + + if (!dev) + return -ENODEV; + + opp_table = dev_pm_opp_get_opp_table(dev); + if (IS_ERR(opp_table)) { + dev_err(dev, "%s: device opp doesn't exist\n", __func__); + return PTR_ERR(opp_table); + } + + clk = opp_table->clk; + if (IS_ERR(clk)) { + dev_err(dev, "%s: No clock available for the device\n", + __func__); + dev_pm_opp_put_opp_table(opp_table); + return PTR_ERR(clk); + } + + if (opp_table->regulator_count == 1) { + volt_vdd = regulator_get_voltage(opp_table->regulators[0]); + dev_info(dev, "cur_freq: %lu Hz, volt: %d uV\n", + clk_get_rate(clk), volt_vdd); + } + + if (opp_table->regulator_count == 2) { + volt_vdd = regulator_get_voltage(opp_table->regulators[0]); + volt_mem = regulator_get_voltage(opp_table->regulators[1]); + dev_info(dev, "cur_freq: %lu Hz, volt_vdd: %d uV, volt_mem: %d uV\n", + clk_get_rate(clk), volt_vdd, volt_mem); + } + + dev_pm_opp_put_opp_table(opp_table); + + return 0; +} +EXPORT_SYMBOL(rockchip_opp_dump_cur_state); + MODULE_DESCRIPTION("ROCKCHIP OPP Select"); MODULE_AUTHOR("Finley Xiao , Liang Chen "); MODULE_LICENSE("GPL"); diff --git a/drivers/soc/rockchip/rockchip_ramdisk.c b/drivers/soc/rockchip/rockchip_ramdisk.c index 245dff4b89e4..e2118ac52d2a 100644 --- a/drivers/soc/rockchip/rockchip_ramdisk.c +++ b/drivers/soc/rockchip/rockchip_ramdisk.c @@ -7,9 +7,12 @@ */ #include +#include #include #include +#include #include +#include #define PAGE_SECTORS_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) #define PAGE_SECTORS (1 << PAGE_SECTORS_SHIFT) @@ -21,6 +24,9 @@ struct rd_device { struct device *dev; phys_addr_t mem_addr; size_t mem_size; + size_t mem_pages; + void *mem_kaddr; + struct dax_device *dax_dev; }; static int rd_major; @@ -182,8 +188,65 @@ static const struct block_device_operations rd_fops = { .rw_page = rd_rw_page, }; +static long rd_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, + long nr_pages, void **kaddr, pfn_t *pfn) +{ + struct rd_device *rd = dax_get_private(dax_dev); + + phys_addr_t offset = PFN_PHYS(pgoff); + size_t max_nr_pages = rd->mem_pages - pgoff; + + if (kaddr) + *kaddr = rd->mem_kaddr + offset; + if (pfn) + *pfn = phys_to_pfn_t(rd->mem_addr + offset, PFN_DEV | PFN_MAP); + + return nr_pages > max_nr_pages ? max_nr_pages : nr_pages; +} + +static bool rd_dax_supported(struct dax_device *dax_dev, + struct block_device *bdev, int blocksize, + sector_t start, sector_t sectors) +{ + return true; +} + +static size_t rd_dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, + void *addr, size_t bytes, struct iov_iter *i) +{ + return copy_from_iter(addr, bytes, i); +} + +static size_t rd_dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, + void *addr, size_t bytes, struct iov_iter *i) +{ + return copy_to_iter(addr, bytes, i); +} + +static int rd_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff, size_t nr_pages) +{ + long rc; + void *kaddr; + + rc = dax_direct_access(dax_dev, pgoff, nr_pages, &kaddr, NULL); + if (rc < 0) + return rc; + memset(kaddr, 0, nr_pages << PAGE_SHIFT); + + return 0; +} + +static const struct dax_operations rd_dax_ops = { + .direct_access = rd_dax_direct_access, + .dax_supported = rd_dax_supported, + .copy_from_iter = rd_dax_copy_from_iter, + .copy_to_iter = rd_dax_copy_to_iter, + .zero_page_range = rd_dax_zero_page_range, +}; + static int rd_init(struct rd_device *rd, int major, int minor) { + int ret; struct gendisk *disk; rd->rd_queue = blk_alloc_queue(NUMA_NO_NODE); @@ -198,8 +261,10 @@ static int rd_init(struct rd_device *rd, int major, int minor) */ blk_queue_physical_block_size(rd->rd_queue, PAGE_SIZE); disk = alloc_disk(1); - if (!disk) + if (!disk) { + ret = -ENOMEM; goto out_free_queue; + } disk->major = major; disk->first_minor = 0; disk->fops = &rd_fops; @@ -209,9 +274,21 @@ static int rd_init(struct rd_device *rd, int major, int minor) set_capacity(disk, rd->mem_size >> SECTOR_SHIFT); rd->rd_disk = disk; + rd->mem_kaddr = phys_to_virt(rd->mem_addr); + rd->mem_pages = PHYS_PFN(rd->mem_size); + rd->dax_dev = alloc_dax(rd, disk->disk_name, &rd_dax_ops, DAXDEV_F_SYNC); + if (IS_ERR(rd->dax_dev)) { + ret = PTR_ERR(rd->dax_dev); + dev_err(rd->dev, "alloc_dax failed %d\n", ret); + rd->dax_dev = NULL; + goto out_free_queue; + } + /* Tell the block layer that this is not a rotational device */ blk_queue_flag_set(QUEUE_FLAG_NONROT, rd->rd_queue); blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, rd->rd_queue); + if (rd->dax_dev) + blk_queue_flag_set(QUEUE_FLAG_DAX, rd->rd_queue); rd->rd_disk->queue = rd->rd_queue; add_disk(rd->rd_disk); @@ -220,7 +297,7 @@ static int rd_init(struct rd_device *rd, int major, int minor) out_free_queue: blk_cleanup_queue(rd->rd_queue); - return -ENOMEM; + return ret; } static int rd_probe(struct platform_device *pdev) @@ -253,6 +330,8 @@ static int rd_probe(struct platform_device *pdev) rd->mem_size = resource_size(®); ret = rd_init(rd, rd_major, 0); + dev_info(dev, "0x%zx@%pa -> 0x%px dax:%d ret:%d\n", + rd->mem_size, &rd->mem_addr, rd->mem_kaddr, (bool)rd->dax_dev, ret); return ret; } diff --git a/drivers/soc/rockchip/rockchip_system_monitor.c b/drivers/soc/rockchip/rockchip_system_monitor.c index c2dd057a5f3e..4f3f46364355 100644 --- a/drivers/soc/rockchip/rockchip_system_monitor.c +++ b/drivers/soc/rockchip/rockchip_system_monitor.c @@ -71,6 +71,7 @@ struct system_monitor { struct thermal_zone_device *tz; struct delayed_work thermal_work; + int last_temp; int offline_cpus_temp; int temp_hysteresis; unsigned int delay; @@ -91,6 +92,7 @@ static LIST_HEAD(monitor_dev_list); static struct system_monitor *system_monitor; static atomic_t monitor_in_suspend; +static BLOCKING_NOTIFIER_HEAD(system_monitor_notifier_list); static BLOCKING_NOTIFIER_HEAD(system_status_notifier_list); int rockchip_register_system_status_notifier(struct notifier_block *nb) @@ -1448,6 +1450,31 @@ void rockchip_system_monitor_unregister(struct monitor_dev_info *info) } EXPORT_SYMBOL(rockchip_system_monitor_unregister); +int rockchip_system_monitor_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&system_monitor_notifier_list, nb); +} +EXPORT_SYMBOL(rockchip_system_monitor_register_notifier); + +void rockchip_system_monitor_unregister_notifier(struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&system_monitor_notifier_list, nb); +} +EXPORT_SYMBOL(rockchip_system_monitor_unregister_notifier); + +static int rockchip_system_monitor_temp_notify(int temp) +{ + struct system_monitor_event_data event_data; + int ret; + + event_data.temp = temp; + ret = blocking_notifier_call_chain(&system_monitor_notifier_list, + SYSTEM_MONITOR_CHANGE_TEMP, + (void *)&event_data); + + return notifier_to_errno(ret); +} + static int notify_dummy(struct thermal_zone_device *tz, int trip) { return 0; @@ -1564,7 +1591,6 @@ static void rockchip_system_monitor_thermal_update(void) { int temp, ret; struct monitor_dev_info *info; - static int last_temp = INT_MAX; ret = thermal_zone_get_temp(system_monitor->tz, &temp); if (ret || temp == THERMAL_TEMP_INVALID) @@ -1572,9 +1598,12 @@ static void rockchip_system_monitor_thermal_update(void) dev_dbg(system_monitor->dev, "temperature=%d\n", temp); - if (temp < last_temp && last_temp - temp <= 2000) + if (temp < system_monitor->last_temp && + system_monitor->last_temp - temp <= 2000) goto out; - last_temp = temp; + system_monitor->last_temp = temp; + + rockchip_system_monitor_temp_notify(temp); down_read(&mdev_list_sem); list_for_each_entry(info, &monitor_dev_list, node) @@ -1700,6 +1729,7 @@ static int monitor_pm_notify(struct notifier_block *nb, rockchip_system_monitor_thermal_update(); atomic_set(&monitor_in_suspend, 0); rockchip_system_monitor_set_cpu_uevent_suppress(false); + system_monitor->last_temp = INT_MAX; break; default: break; @@ -1819,6 +1849,7 @@ static int rockchip_system_monitor_probe(struct platform_device *pdev) rockchip_system_monitor_parse_dt(system_monitor); if (system_monitor->tz) { + system_monitor->last_temp = INT_MAX; INIT_DELAYED_WORK(&system_monitor->thermal_work, rockchip_system_monitor_thermal_check); mod_delayed_work(system_freezable_wq, diff --git a/drivers/soc/rockchip/rockchip_thunderboot_service.c b/drivers/soc/rockchip/rockchip_thunderboot_service.c index e552ed162389..fb40492c0685 100644 --- a/drivers/soc/rockchip/rockchip_thunderboot_service.c +++ b/drivers/soc/rockchip/rockchip_thunderboot_service.c @@ -2,11 +2,15 @@ /* * Copyright (C) 2022 Rockchip Electronics Co., Ltd. */ +#include #include #include +#include #include +#include #include #include +#include #include #include @@ -17,6 +21,9 @@ struct rk_tb_serv { struct device *dev; struct mbox_chan *mbox_rx_chan; struct mbox_client mbox_cl; + struct reset_control *rsts; + phys_addr_t mem_start; + size_t mem_size; }; static atomic_t mcu_done = ATOMIC_INIT(0); @@ -55,6 +62,16 @@ static void do_mcu_done(struct rk_tb_serv *serv) rockchip_mbox_read_msg(serv->mbox_rx_chan, &msg); if (msg.cmd == CMD_MCU_STATUS && msg.data == MCU_STATUS_DONE) { + void *start, *end; + + /* make sure mcu is wfi */ + udelay(15); + reset_control_assert(serv->rsts); + + start = phys_to_virt(serv->mem_start); + end = start + serv->mem_size; + free_reserved_area(start, end, -1, "rtos"); + spin_lock(&lock); if (atomic_read(&mcu_done)) { spin_unlock(&lock); @@ -85,11 +102,34 @@ static int rk_tb_serv_probe(struct platform_device *pdev) { struct rk_tb_serv *serv; struct mbox_client *mbox_cl; + struct device_node *mem; + struct resource reg; + int ret; serv = devm_kzalloc(&pdev->dev, sizeof(*serv), GFP_KERNEL); if (!serv) return -ENOMEM; + mem = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + if (!mem) { + dev_err(&pdev->dev, "missing \"memory-region\" property\n"); + return -ENODEV; + } + + ret = of_address_to_resource(mem, 0, ®); + of_node_put(mem); + if (ret) { + dev_err(&pdev->dev, "missing \"reg\" property\n"); + return -ENODEV; + } + + serv->mem_start = reg.start; + serv->mem_size = resource_size(®); + + serv->rsts = devm_reset_control_array_get_optional_exclusive(&pdev->dev); + if (IS_ERR(serv->rsts) && PTR_ERR(serv->rsts) == -EPROBE_DEFER) + return -EPROBE_DEFER; + platform_set_drvdata(pdev, serv); mbox_cl = &serv->mbox_cl; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4469a177751a..0bdd5fe31d66 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -640,6 +640,16 @@ config SPI_ROCKCHIP The main usecase of this controller is to use spi flash as boot device. +config SPI_ROCKCHIP_MISCDEV + bool "Rockchip SPI controller misc devices" + depends on SPI_ROCKCHIP + help + This selects a misc driver for Rockchip SPI controller. + + If you say yes to this option, It will register rkspi-devN misc device + for each spi controller and support to get the controller register + resource by calling mmap. + config SPI_ROCKCHIP_SFC tristate "Rockchip Serial Flash Controller (SFC)" imply ROCKCHIP_MTD_VENDOR_STORAGE diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index be61a77901e4..c8302e38f4c2 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -169,6 +170,8 @@ #define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002 #define ROCKCHIP_SPI_VER2_TYPE2 0x00110002 +#define ROCKCHIP_SPI_REGISTER_SIZE 0x1000 + struct rockchip_spi_quirks { u32 max_baud_div_in_cpha; }; @@ -209,6 +212,8 @@ struct rockchip_spi { bool cs_high_supported; /* native CS supports active-high polarity */ struct spi_transfer *xfer; /* Store xfer temporarily */ + phys_addr_t base_addr_phy; + struct miscdevice miscdev; /* quirks */ u32 max_baud_div_in_cpha; @@ -785,6 +790,60 @@ static int rockchip_spi_setup(struct spi_device *spi) return 0; } +static int rockchip_spi_misc_open(struct inode *inode, struct file *filp) +{ + struct miscdevice *misc = filp->private_data; + struct spi_controller *ctlr = dev_get_drvdata(misc->parent); + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + + pm_runtime_get_sync(rs->dev); + + return 0; +} + +static int rockchip_spi_misc_release(struct inode *inode, struct file *filp) +{ + struct miscdevice *misc = filp->private_data; + struct spi_controller *ctlr = dev_get_drvdata(misc->parent); + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + + pm_runtime_put(rs->dev); + + return 0; +} + +static int rockchip_spi_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct miscdevice *misc = filp->private_data; + struct spi_controller *ctlr = dev_get_drvdata(misc->parent); + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + size_t size = vma->vm_end - vma->vm_start; + int err; + + if (size > ROCKCHIP_SPI_REGISTER_SIZE) { + dev_warn(misc->parent, "mmap size is out of limitation\n"); + return -EINVAL; + } + + vma->vm_flags |= VM_IO; + vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + err = remap_pfn_range(vma, vma->vm_start, + __phys_to_pfn(rs->base_addr_phy), + size, vma->vm_page_prot); + if (err) + return -EAGAIN; + + return 0; +} + +static const struct file_operations rockchip_spi_misc_fops = { + .open = rockchip_spi_misc_open, + .release = rockchip_spi_misc_release, + .mmap = rockchip_spi_mmap, +}; + static int rockchip_spi_probe(struct platform_device *pdev) { int ret; @@ -821,6 +880,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) ret = PTR_ERR(rs->regs); goto err_put_ctlr; } + rs->base_addr_phy = mem->start; if (!has_acpi_companion(&pdev->dev)) rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk"); @@ -999,6 +1059,22 @@ static int rockchip_spi_probe(struct platform_device *pdev) goto err_free_dma_rx; } + if (IS_ENABLED(CONFIG_SPI_ROCKCHIP_MISCDEV)) { + char misc_name[20]; + + snprintf(misc_name, sizeof(misc_name), "rkspi-dev%d", ctlr->bus_num); + rs->miscdev.minor = MISC_DYNAMIC_MINOR; + rs->miscdev.name = misc_name; + rs->miscdev.fops = &rockchip_spi_misc_fops; + rs->miscdev.parent = &pdev->dev; + + ret = misc_register(&rs->miscdev); + if (ret) + dev_err(&pdev->dev, "failed to register misc device %s\n", misc_name); + else + dev_info(&pdev->dev, "register misc device %s\n", misc_name); + } + return 0; err_free_dma_rx: @@ -1026,6 +1102,9 @@ static int rockchip_spi_remove(struct platform_device *pdev) struct spi_controller *ctlr = spi_controller_get(platform_get_drvdata(pdev)); struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + if (IS_ENABLED(CONFIG_SPI_ROCKCHIP_MISCDEV)) + misc_deregister(&rs->miscdev); + pm_runtime_get_sync(&pdev->dev); clk_disable_unprepare(rs->sclk_in); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 5acf9fa3d446..ad57ebf49154 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -416,6 +416,7 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM }, /* Sonix FaceBlack device */ + { USB_DEVICE(0x0c45, 0x636a), .driver_info = USB_QUIRK_AUTO_SUSPEND }, { USB_DEVICE(0x0c45, 0x64ab), .driver_info = USB_QUIRK_AUTO_SUSPEND }, { USB_DEVICE(0x0c45, 0x64ac), .driver_info = USB_QUIRK_AUTO_SUSPEND }, diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index e195176580de..a66f16e8816e 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -44,7 +44,7 @@ out: int dwc3_host_init(struct dwc3 *dwc) { - struct property_entry props[4]; + struct property_entry props[5]; struct platform_device *xhci; int ret, irq; struct resource *res; @@ -107,6 +107,9 @@ int dwc3_host_init(struct dwc3 *dwc) if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A)) props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped"); + if (!dwc->dis_u2_susphy_quirk) + props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-u2-broken-suspend"); + if (prop_idx) { ret = platform_device_add_properties(xhci, props); if (ret) { diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 3e48737f893f..e6f0871375b9 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -276,6 +276,8 @@ static int ehci_platform_probe(struct platform_device *dev) struct ehci_platform_priv *priv; struct ehci_hcd *ehci; int err, irq, clk = 0; + struct device *companion_dev; + struct device_link *link; if (usb_disabled()) return -ENODEV; @@ -414,6 +416,21 @@ static int ehci_platform_probe(struct platform_device *dev) if (of_usb_get_phy_mode(dev->dev.of_node) == USBPHY_INTERFACE_MODE_HSIC) ehci_usic_init(hcd); + if (of_device_is_compatible(dev->dev.of_node, + "rockchip,rk3588-ehci")) { + companion_dev = usb_of_get_companion_dev(hcd->self.controller); + if (companion_dev) { + link = device_link_add(companion_dev, hcd->self.controller, + DL_FLAG_STATELESS); + if (!link) { + dev_err(&dev->dev, "Unable to link %s\n", + dev_name(companion_dev)); + err = -EINVAL; + goto err_power; + } + } + } + device_wakeup_enable(hcd->self.controller); device_enable_async_suspend(hcd->self.controller); platform_set_drvdata(dev, hcd); @@ -447,11 +464,19 @@ static int ehci_platform_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + struct device *companion_dev; int clk; if (priv->quirk_poll) quirk_poll_end(priv); + if (of_device_is_compatible(dev->dev.of_node, + "rockchip,rk3588-ehci")) { + companion_dev = usb_of_get_companion_dev(hcd->self.controller); + if (companion_dev) + device_link_remove(companion_dev, hcd->self.controller); + } + usb_remove_hcd(hcd); if (pdata->power_off) @@ -510,7 +535,7 @@ static int __maybe_unused ehci_platform_resume(struct device *dev) } companion_dev = usb_of_get_companion_dev(hcd->self.controller); - if (companion_dev) { + if (companion_dev && !device_is_dependent(hcd->self.controller, companion_dev)) { device_pm_wait_for_dev(hcd->self.controller, companion_dev); put_device(companion_dev); } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index e0cd2825fcdc..10f76c5594f6 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1671,7 +1671,21 @@ retry: t2 &= ~PORT_PLS_MASK; t2 |= PORT_LINK_STROBE | XDEV_U3; set_bit(port_index, &bus_state->bus_suspended); + } else if ((xhci->quirks & XHCI_U2_BROKEN_SUSPEND) && + (hcd->speed < HCD_USB3) && + (t1 & PORT_PLS_MASK) == XDEV_U3) { + /* + * Rockchip SNPS xHC 3.0 set USB 2.0 PHY enter + * suspend mode from DWC3 core if the suspend + * conditions are valid. In this case, it need + * to set the bus_suspended bit for USB 2.0, so + * that in xhci_bus_resume, it can set the xHC + * link state to XDEV_RESUME and send USB resume + * signal to USB 2.0 device. + */ + set_bit(port_index, &bus_state->bus_suspended); } + /* USB core sets remote wake mask for USB 3.0 hubs, * including the USB 3.0 roothub, but only if CONFIG_PM * is enabled, so also enable remote wake here. diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index bd62f03523f1..f76cdb306ea8 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -363,6 +363,10 @@ static int xhci_plat_probe(struct platform_device *pdev) if (device_property_read_bool(tmpdev, "quirk-skip-phy-init")) xhci->quirks |= XHCI_SKIP_PHY_INIT; + if (device_property_read_bool(tmpdev, + "xhci-u2-broken-suspend")) + xhci->quirks |= XHCI_U2_BROKEN_SUSPEND; + device_property_read_u32(tmpdev, "imod-interval-ns", &xhci->imod_interval); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2bba700a7805..3eadc34d646d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1903,6 +1903,7 @@ struct xhci_hcd { #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39) #define XHCI_NO_SOFT_RETRY BIT_ULL(40) #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42) +#define XHCI_U2_BROKEN_SUSPEND BIT_ULL(43) unsigned int num_active_eps; unsigned int limit_active_eps; diff --git a/drivers/video/rockchip/mpp/mpp_av1dec.c b/drivers/video/rockchip/mpp/mpp_av1dec.c index 26ef14a3fe79..33e118ae6450 100644 --- a/drivers/video/rockchip/mpp/mpp_av1dec.c +++ b/drivers/video/rockchip/mpp/mpp_av1dec.c @@ -534,11 +534,11 @@ static int av1dec_set_l2_cache(struct av1dec_dev *dec, struct av1dec_task *task) writel_relaxed(AV1_L2_CACHE_SHAPER_EN, dec->reg_base[AV1DEC_CLASS_CACHE] + AV1_L2_CACHE_SHAPER_CTRL); - /* TODO: set exception list */ - - /* multi id enable bit */ - writel_relaxed(0x00000001, dec->reg_base[AV1DEC_CLASS_CACHE] + - AV1_L2_CACHE_RD_ONLY_CONFIG); + /* not enable cache en when multi tiles */ + if (!(regs[10] & BIT(1))) + /* cache all en */ + writel_relaxed(0x00000001, dec->reg_base[AV1DEC_CLASS_CACHE] + + AV1_L2_CACHE_RD_ONLY_CONFIG); /* reorder_e and cache_e */ writel_relaxed(0x00000081, dec->reg_base[AV1DEC_CLASS_CACHE] + AV1_L2_CACHE_RD_ONLY_CTRL); @@ -1199,25 +1199,8 @@ int av1dec_driver_register(struct platform_driver *drv) return driver_register(&drv->driver); } -static irqreturn_t av1dec_cache_irq(int irq, void *dev_id) -{ - struct av1dec_dev *dec = dev_id; - u32 shaper_st, rd_st; - - shaper_st = readl(dec->reg_base[AV1DEC_CLASS_CACHE] + 0x2c); - rd_st = readl(dec->reg_base[AV1DEC_CLASS_CACHE] + 0x204); - - mpp_debug(DEBUG_IRQ_STATUS, "cache irq st shaper 0x%x read 0x%x\n", shaper_st, rd_st); - - writel(shaper_st, dec->reg_base[AV1DEC_CLASS_CACHE] + 0x2c); - writel(rd_st, dec->reg_base[AV1DEC_CLASS_CACHE] + 0x204); - - return IRQ_HANDLED; -} - static int av1dec_cache_init(struct platform_device *pdev, struct av1dec_dev *dec) { - int ret; struct resource *res; struct device *dev = &pdev->dev; @@ -1230,14 +1213,7 @@ static int av1dec_cache_init(struct platform_device *pdev, struct av1dec_dev *de dev_err(dev, "ioremap failed for resource %pR\n", res); return -EINVAL; } - - dec->irq[AV1DEC_CLASS_CACHE] = platform_get_irq(pdev, 1); - - ret = devm_request_irq(dev, dec->irq[AV1DEC_CLASS_CACHE], - av1dec_cache_irq, IRQF_SHARED, "irq_cache", dec); - if (ret) - mpp_err("ret=%d\n", ret); - return ret; + return 0; } static int av1dec_afbc_init(struct platform_device *pdev, struct av1dec_dev *dec) diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2.c b/drivers/video/rockchip/mpp/mpp_rkvdec2.c index 5c5ca8f38c90..ada9df5961ad 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2.c @@ -1595,17 +1595,8 @@ static int __maybe_unused rkvdec2_runtime_suspend(struct device *dev) mpp_clk_safe_disable(ccu->aclk_info.clk); } else { - u32 val; struct mpp_dev *mpp = dev_get_drvdata(dev); - /* soft reset */ - mpp_write(mpp, RKVDEC_REG_IMPORTANT_BASE, RKVDEC_SOFTREST_EN); - udelay(5); - val = mpp_read(mpp, RKVDEC_REG_INT_EN); - if (!(val & RKVDEC_SOFT_RESET_READY)) - mpp_err("soft reset fail, int %08x\n", val); - mpp_write(mpp, RKVDEC_REG_INT_EN, 0); - if (mpp->is_irq_startup) { /* disable core irq */ disable_irq(mpp->irq); diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c index 0dd7c21d85af..b62bc01589f5 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.c @@ -71,6 +71,7 @@ struct rkvdec_link_info rkvdec_link_v2_hw_info = { .reg_num = 28, }, .tb_reg_int = 180, + .hack_setup = 0, }; /* vdpu34x link hw info for rk356x */ @@ -123,6 +124,7 @@ struct rkvdec_link_info rkvdec_link_rk356x_hw_info = { .reg_num = 28, }, .tb_reg_int = 164, + .hack_setup = 1, }; static void rkvdec_link_status_update(struct rkvdec_link_dev *dev) @@ -601,7 +603,7 @@ static int rkvdec_link_isr_recv_task(struct mpp_dev *mpp, task->irq_status = irq_status ? irq_status : mpp->irq_status; - cancel_delayed_work_sync(&mpp_task->timeout_work); + cancel_delayed_work(&mpp_task->timeout_work); set_bit(TASK_STATE_HANDLE, &mpp_task->state); if (link_dec->statistic_count && @@ -768,7 +770,7 @@ static int rkvdec2_link_isr(struct mpp_dev *mpp) rkvdec_link_reg_dump("timeout", link_dec); val = mpp_read(mpp, 224 * 4); - if (!(val & BIT(2))) { + if (link_dec->info->hack_setup && !(val & BIT(2))) { dev_info(mpp->dev, "frame not complete\n"); link_dec->decoded++; } @@ -955,6 +957,9 @@ int rkvdec2_link_init(struct platform_device *pdev, struct rkvdec2_dev *dec) if (ret) goto done; + if (dec->fix) + rkvdec2_link_hack_data_setup(dec->fix); + link_dec->mpp = mpp; link_dec->dev = dev; atomic_set(&link_dec->task_timeout, 0); @@ -1282,6 +1287,7 @@ int rkvdec2_link_process_task(struct mpp_session *session, { struct mpp_task *task = NULL; struct mpp_dev *mpp = session->mpp; + struct rkvdec_link_info *link_info = mpp->var->hw_info->link_info; task = rkvdec2_alloc_task(session, msgs); if (!task) { @@ -1289,6 +1295,15 @@ int rkvdec2_link_process_task(struct mpp_session *session, return -ENOMEM; } + if (link_info->hack_setup) { + u32 fmt; + struct rkvdec2_task *dec_task = NULL; + + dec_task = to_rkvdec2_task(task); + fmt = RKVDEC_GET_FORMAT(dec_task->reg[RKVDEC_REG_FORMAT_INDEX]); + dec_task->need_hack = (fmt == RKVDEC_FMT_H264D); + } + kref_init(&task->ref); atomic_set(&task->abort_request, 0); task->task_index = atomic_fetch_inc(&mpp->task_index); @@ -1782,7 +1797,7 @@ int rkvdec2_ccu_iommu_fault_handle(struct iommu_domain *iommu, atomic_inc(&mpp->queue->reset_request); for (i = 0; i < mpp->queue->core_count; i++) - rk_iommu_mask_irq(mpp->queue->cores[i]->dev); + rockchip_iommu_mask_irq(mpp->queue->cores[i]->dev); kthread_queue_work(&mpp->queue->worker, &mpp->work); diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.h b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.h index 208789c7c36b..635516ae3262 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec2_link.h +++ b/drivers/video/rockchip/mpp/mpp_rkvdec2_link.h @@ -112,6 +112,7 @@ struct rkvdec_link_info { /* interrupt read back in table buffer */ u32 tb_reg_int; + bool hack_setup; }; struct rkvdec_link_dev { diff --git a/drivers/video/rockchip/mpp/mpp_rkvenc.c b/drivers/video/rockchip/mpp/mpp_rkvenc.c index 3d142a05e8c9..36a888193246 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvenc.c +++ b/drivers/video/rockchip/mpp/mpp_rkvenc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1143,7 +1144,7 @@ static void rkvenc_iommu_handle_work(struct work_struct *work_s) else enc->aux_iova = page_iova; - rk_iommu_unmask_irq(mpp->dev); + rockchip_iommu_unmask_irq(mpp->dev); mpp_iommu_up_write(mpp->iommu_info); mpp_debug_leave(); @@ -1160,7 +1161,7 @@ static int rkvenc_iommu_fault_handle(struct iommu_domain *iommu, mpp_debug(DEBUG_IOMMU, "IOMMU_GET_BUS_ID(status)=%d\n", IOMMU_GET_BUS_ID(status)); if (IOMMU_GET_BUS_ID(status)) { enc->fault_iova = iova; - rk_iommu_mask_irq(mpp->dev); + rockchip_iommu_mask_irq(mpp->dev); queue_work(enc->iommu_wq, &enc->iommu_work); } mpp_debug_leave(); diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h index 6b8bac5fec2f..7f94456bc497 100644 --- a/drivers/video/rockchip/rga3/include/rga_drv.h +++ b/drivers/video/rockchip/rga3/include/rga_drv.h @@ -87,7 +87,7 @@ #define DRIVER_MAJOR_VERISON 1 #define DRIVER_MINOR_VERSION 2 -#define DRIVER_REVISION_VERSION 19 +#define DRIVER_REVISION_VERSION 20 #define DRIVER_PATCH_VERSION #define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \ diff --git a/drivers/video/rockchip/rga3/include/rga_hw_config.h b/drivers/video/rockchip/rga3/include/rga_hw_config.h index ae5c53d23f4c..73f05f7f517d 100644 --- a/drivers/video/rockchip/rga3/include/rga_hw_config.h +++ b/drivers/video/rockchip/rga3/include/rga_hw_config.h @@ -67,6 +67,7 @@ struct rga_hw_data { extern const struct rga_hw_data rga3_data; extern const struct rga_hw_data rga2e_data; extern const struct rga_hw_data rga2e_1106_data; +extern const struct rga_hw_data rga2e_iommu_data; /* Returns false if in range, true otherwise */ static inline bool rga_hw_out_of_range(const struct rga_rect_range *range, int width, int height) diff --git a/drivers/video/rockchip/rga3/rga2_reg_info.c b/drivers/video/rockchip/rga3/rga2_reg_info.c index 4216ffb3b8f4..923c1f30625d 100644 --- a/drivers/video/rockchip/rga3/rga2_reg_info.c +++ b/drivers/video/rockchip/rga3/rga2_reg_info.c @@ -2064,6 +2064,10 @@ void rga2_soft_reset(struct rga_scheduler_t *scheduler) { u32 i; u32 reg; + u32 iommu_dte_addr; + + if (scheduler->data->mmu == RGA_IOMMU) + iommu_dte_addr = rga_read(0xf00, scheduler); rga_write((1 << 3) | (1 << 4) | (1 << 6), RGA2_SYS_CTRL, scheduler); @@ -2077,6 +2081,12 @@ void rga2_soft_reset(struct rga_scheduler_t *scheduler) udelay(1); } + if (scheduler->data->mmu == RGA_IOMMU) { + rga_write(iommu_dte_addr, 0xf00, scheduler); + /* enable iommu */ + rga_write(0, 0xf08, scheduler); + } + if (i == RGA_RESET_TIMEOUT) pr_err("soft reset timeout.\n"); } diff --git a/drivers/video/rockchip/rga3/rga3_reg_info.c b/drivers/video/rockchip/rga3/rga3_reg_info.c index 85925a051a85..e065b820ca92 100644 --- a/drivers/video/rockchip/rga3/rga3_reg_info.c +++ b/drivers/video/rockchip/rga3/rga3_reg_info.c @@ -914,7 +914,7 @@ static void RGA3_set_reg_wr_info(u8 *base, struct rga3_req *msg) (s_RGA3_WR_CTRL_SW_WR_FORMAT(wr_interleaved))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN)) | - (s_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN(0))); + (s_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN(1))); reg = ((reg & (~m_RGA3_WR_CTRL_SW_OUTSTANDING_MAX)) | diff --git a/drivers/video/rockchip/rga3/rga_common.c b/drivers/video/rockchip/rga3/rga_common.c index a96e9fba0f7c..0e21326c4cda 100644 --- a/drivers/video/rockchip/rga3/rga_common.c +++ b/drivers/video/rockchip/rga3/rga_common.c @@ -619,6 +619,9 @@ int rga_image_size_cal(int w, int h, int format, /* YUV FORMAT */ case RGA_FORMAT_YCbCr_422_SP: case RGA_FORMAT_YCrCb_422_SP: + /* 10bit format stride is externally configured. */ + case RGA_FORMAT_YCbCr_422_SP_10B: + case RGA_FORMAT_YCrCb_422_SP_10B: yrgb = w * h; uv = w * h; break; diff --git a/drivers/video/rockchip/rga3/rga_drv.c b/drivers/video/rockchip/rga3/rga_drv.c index 5b809d143ab5..576b460f91f3 100644 --- a/drivers/video/rockchip/rga3/rga_drv.c +++ b/drivers/video/rockchip/rga3/rga_drv.c @@ -1502,6 +1502,9 @@ static int rga_drv_probe(struct platform_device *pdev) } else if (scheduler->core == RGA2_SCHEDULER_CORE0) { if (!strcmp(scheduler->version.str, "3.3.87975")) scheduler->data = &rga2e_1106_data; + else if (!strcmp(scheduler->version.str, "3.6.92812") || + !strcmp(scheduler->version.str, "3.7.93215")) + scheduler->data = &rga2e_iommu_data; else scheduler->data = &rga2e_data; } diff --git a/drivers/video/rockchip/rga3/rga_hw_config.c b/drivers/video/rockchip/rga3/rga_hw_config.c index 797ab676b053..42d7bdb52a54 100644 --- a/drivers/video/rockchip/rga3/rga_hw_config.c +++ b/drivers/video/rockchip/rga3/rga_hw_config.c @@ -325,3 +325,29 @@ const struct rga_hw_data rga2e_1106_data = { RGA_MODE_CSC_BT709, .mmu = RGA_NONE_MMU, }; + +const struct rga_hw_data rga2e_iommu_data = { + .version = 0, + .input_range = {{2, 2}, {8192, 8192}}, + .output_range = {{2, 2}, {4096, 4096}}, + + .win = rga2e_win_data, + .win_size = ARRAY_SIZE(rga2e_win_data), + /* 1 << factor mean real factor */ + .max_upscale_factor = 4, + .max_downscale_factor = 4, + + .byte_stride_align = 4, + .max_byte_stride = WORD_TO_BYTE(8192), + + .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE | + RGA_COLOR_KEY | RGA_ROP_CALCULATE | + RGA_NN_QUANTIZE | RGA_DITHER | RGA_MOSAIC | + RGA_YIN_YOUT | RGA_YUV_HDS | RGA_YUV_VDS | + RGA_OSD | RGA_PRE_INTR, + .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | + RGA_MODE_CSC_BT709, + .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | + RGA_MODE_CSC_BT709, + .mmu = RGA_IOMMU, +}; diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c index 4c5a667311bb..7d59472d0888 100644 --- a/drivers/video/rockchip/rga3/rga_mm.c +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -1042,15 +1042,24 @@ static int rga_mm_sgt_to_page_table(struct sg_table *sg, uint32_t break_flag = 0; do { - len = sg_dma_len(sgl) >> PAGE_SHIFT; - if (len == 0) - len = sgl->length >> PAGE_SHIFT; + /* + * The length of each sgl is expected to be obtained here, not + * the length of the entire dma_buf, so sg_dma_len() is not used. + */ + len = sgl->length >> PAGE_SHIFT; if (use_dma_address) /* - * The fd passed by user space gets sg through - * dma_buf_map_attachment, - * so dma_address can be use here. + * The fd passed by user space gets sg through + * dma_buf_map_attachment, so dma_address can + * be use here. + * When the mapped device does not have iommu, it will + * return the first address of the real physical page + * when it meets the requirements of the current device, + * and will trigger swiotlb when it does not meet the + * requirements to obtain a software-mapped physical + * address that is mapped to meet the device address + * requirements. */ Address = sg_dma_address(sgl); else @@ -1061,15 +1070,13 @@ static int rga_mm_sgt_to_page_table(struct sg_table *sg, break_flag = 1; break; } - page_table[mapped_size + i] = - (uint32_t) (Address + (i << PAGE_SHIFT)); + page_table[mapped_size + i] = (uint32_t)(Address + (i << PAGE_SHIFT)); } if (break_flag) break; mapped_size += len; sg_num += 1; - } while ((sgl = sg_next(sgl)) && (mapped_size < pageCount) - && (sg_num < sg->nents)); + } while ((sgl = sg_next(sgl)) && (mapped_size < pageCount) && (sg_num < sg->orig_nents)); return 0; } diff --git a/fs/Kconfig b/fs/Kconfig index a6a721108d1c..f6ba03a5a9b4 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -45,7 +45,7 @@ source "fs/zonefs/Kconfig" config FS_DAX bool "Direct Access (DAX) support" depends on MMU - depends on !(ARM || MIPS || SPARC) + depends on !(ARM || MIPS || SPARC) || (ROCKCHIP_RAMDISK && ARM) select DEV_PAGEMAP_OPS if (ZONE_DEVICE && !FS_DAX_LIMITED) select FS_IOMAP select DAX diff --git a/fs/dax.c b/fs/dax.c index d5d7b9393bca..61e73b6a2314 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -728,6 +728,11 @@ static int copy_cow_page_dax(struct block_device *bdev, struct dax_device *dax_d return rc; } vto = kmap_atomic(to); +#ifdef CONFIG_ARM +#ifndef copy_user_page +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) +#endif +#endif copy_user_page(vto, (void __force *)kaddr, vaddr, to); kunmap_atomic(vto); dax_read_unlock(id); diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 69454382f680..0766836dac6b 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -377,6 +377,9 @@ static int erofs_file_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &erofs_dax_vm_ops; vma->vm_flags |= VM_HUGEPAGE; +#if defined(CONFIG_ROCKCHIP_RAMDISK) && defined(CONFIG_ARM) + vma->vm_flags |= VM_MIXEDMAP; +#endif return 0; } #else diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index 208c9c4a83d7..d6303964a274 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -142,6 +142,10 @@ static int meminfo_proc_show(struct seq_file *m, void *v) #ifdef CONFIG_CMA show_val_kb(m, "CmaTotal: ", totalcma_pages); +#ifdef CONFIG_NO_GKI + show_val_kb(m, "CmaAllocated: ", cma_used_pages()); + show_val_kb(m, "CmaReleased: ", totalcma_pages - cma_used_pages()); +#endif show_val_kb(m, "CmaFree: ", global_zone_page_state(NR_FREE_CMA_PAGES)); #endif diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 45e20bfa427c..d51c74600f96 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -264,10 +264,10 @@ config PSTORE_BLK_FTRACE_SIZE NOTE that, both Kconfig and module parameters can configure pstore/blk, but module parameters have priority over Kconfig. -config PSTORE_MCU_LOG - bool "Print mcu log by linux" +config PSTORE_BOOT_LOG + bool "Print boot log by linux" depends on PSTORE help - When your soc has several mcu, you can get their log by cat command + Collect log from loader,uboot,ATF and so on, you can get their log by cat command through linux shell If unsure, say N. diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 32318e6d6519..29c91fda081d 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -24,7 +24,7 @@ #include #include -#ifdef CONFIG_PSTORE_MCU_LOG +#ifdef CONFIG_PSTORE_BOOT_LOG #include #include #endif @@ -135,12 +135,12 @@ static ssize_t pstore_file_read(struct file *file, char __user *userbuf, { struct seq_file *sf = file->private_data; struct pstore_private *ps = sf->private; -#ifdef CONFIG_PSTORE_MCU_LOG +#ifdef CONFIG_PSTORE_BOOT_LOG size_t size = 0; struct pstore_record *record = ps->record; - if (record->type == PSTORE_TYPE_MCU_LOG) { - size = ramoops_pstore_read_for_mcu_log(ps->record); + if (record->type == PSTORE_TYPE_BOOT_LOG) { + size = ramoops_pstore_read_for_boot_log(ps->record); size = simple_read_from_buffer(userbuf, count, ppos, record->buf, size); return size; } diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 1673f3cb23f3..417582b41757 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -58,8 +58,8 @@ static const char * const pstore_type_names[] = { "powerpc-common", "pmsg", "powerpc-opal", -#ifdef CONFIG_PSTORE_MCU_LOG - "mcu-log", +#ifdef CONFIG_PSTORE_BOOT_LOG + "boot-log", #endif }; diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 026782e95c74..143e94395987 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -81,8 +81,8 @@ struct ramoops_context { struct persistent_ram_zone *cprz; /* Console zone */ struct persistent_ram_zone **fprzs; /* Ftrace zones */ struct persistent_ram_zone *mprz; /* PMSG zone */ -#ifdef CONFIG_PSTORE_MCU_LOG - struct persistent_ram_zone **mcu_przs; /* MCU log zones */ +#ifdef CONFIG_PSTORE_BOOT_LOG + struct persistent_ram_zone **boot_przs; /* BOOT log zones */ #endif phys_addr_t phys_addr; unsigned long size; @@ -91,8 +91,8 @@ struct ramoops_context { size_t console_size; size_t ftrace_size; size_t pmsg_size; -#ifdef CONFIG_PSTORE_MCU_LOG - size_t mcu_log_size; +#ifdef CONFIG_PSTORE_BOOT_LOG + size_t boot_log_size; #endif u32 flags; struct persistent_ram_ecc_info ecc_info; @@ -104,9 +104,9 @@ struct ramoops_context { unsigned int max_ftrace_cnt; unsigned int ftrace_read_cnt; unsigned int pmsg_read_cnt; -#ifdef CONFIG_PSTORE_MCU_LOG - unsigned int mcu_log_read_cnt; - unsigned int max_mcu_log_cnt; +#ifdef CONFIG_PSTORE_BOOT_LOG + unsigned int boot_log_read_cnt; + unsigned int max_boot_log_cnt; #endif struct pstore_info pstore; }; @@ -184,8 +184,8 @@ static bool prz_ok(struct persistent_ram_zone *prz) persistent_ram_ecc_string(prz, NULL, 0)); } -#ifdef CONFIG_PSTORE_MCU_LOG -ssize_t ramoops_pstore_read_for_mcu_log(struct pstore_record *record) +#ifdef CONFIG_PSTORE_BOOT_LOG +ssize_t ramoops_pstore_read_for_boot_log(struct pstore_record *record) { struct ramoops_context *cxt = record->psi->data; struct persistent_ram_zone *prz; @@ -193,7 +193,7 @@ ssize_t ramoops_pstore_read_for_mcu_log(struct pstore_record *record) if (!cxt) return 0; - prz = cxt->mcu_przs[record->id]; + prz = cxt->boot_przs[record->id]; if (!prz) return 0; @@ -290,10 +290,10 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) } } -#ifdef CONFIG_PSTORE_MCU_LOG +#ifdef CONFIG_PSTORE_BOOT_LOG if (!prz_ok(prz)) { - while (cxt->mcu_log_read_cnt < cxt->max_mcu_log_cnt && !prz) { - prz = ramoops_get_next_prz(cxt->mcu_przs, cxt->mcu_log_read_cnt++, record); + while (cxt->boot_log_read_cnt < cxt->max_boot_log_cnt && !prz) { + prz = ramoops_get_next_prz(cxt->boot_przs, cxt->boot_log_read_cnt++, record); if (!prz_ok(prz)) continue; } @@ -305,8 +305,8 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) goto out; } -#ifdef CONFIG_PSTORE_MCU_LOG - if (record->type == PSTORE_TYPE_MCU_LOG) { +#ifdef CONFIG_PSTORE_BOOT_LOG + if (record->type == PSTORE_TYPE_BOOT_LOG) { persistent_ram_free_old(prz); persistent_ram_save_old(prz); } @@ -517,13 +517,13 @@ static void ramoops_free_przs(struct ramoops_context *cxt) kfree(cxt->fprzs); cxt->max_ftrace_cnt = 0; } -#ifdef CONFIG_PSTORE_MCU_LOG - /* Free mcu log PRZs */ - if (cxt->mcu_przs) { - for (i = 0; i < cxt->max_mcu_log_cnt; i++) - persistent_ram_free(cxt->mcu_przs[i]); - kfree(cxt->mcu_przs); - cxt->max_mcu_log_cnt = 0; +#ifdef CONFIG_PSTORE_BOOT_LOG + /* Free boot log PRZs */ + if (cxt->boot_przs) { + for (i = 0; i < cxt->max_boot_log_cnt; i++) + persistent_ram_free(cxt->boot_przs[i]); + kfree(cxt->boot_przs); + cxt->max_boot_log_cnt = 0; } #endif } @@ -745,9 +745,9 @@ static int ramoops_parse_dt(struct platform_device *pdev, parse_u32("ecc-size", pdata->ecc_info.ecc_size, 0); parse_u32("flags", pdata->flags, 0); parse_u32("max-reason", pdata->max_reason, pdata->max_reason); -#ifdef CONFIG_PSTORE_MCU_LOG - parse_u32("mcu-log-size", pdata->mcu_log_size, 0); - parse_u32("mcu-log-count", pdata->max_mcu_log_cnt, 0); +#ifdef CONFIG_PSTORE_BOOT_LOG + parse_u32("boot-log-size", pdata->boot_log_size, 0); + parse_u32("boot-log-count", pdata->max_boot_log_cnt, 0); #endif #undef parse_u32 @@ -810,9 +810,9 @@ static int ramoops_probe(struct platform_device *pdev) goto fail_out; } -#ifdef CONFIG_PSTORE_MCU_LOG +#ifdef CONFIG_PSTORE_BOOT_LOG if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && - !pdata->ftrace_size && !pdata->pmsg_size && !pdata->mcu_log_size)) { + !pdata->ftrace_size && !pdata->pmsg_size && !pdata->boot_log_size)) { pr_err("The memory size and the record/console size must be " "non-zero\n"); goto fail_out; @@ -846,18 +846,28 @@ static int ramoops_probe(struct platform_device *pdev) cxt->pmsg_size = pdata->pmsg_size; cxt->flags = pdata->flags; cxt->ecc_info = pdata->ecc_info; -#ifdef CONFIG_PSTORE_MCU_LOG - cxt->mcu_log_size = pdata->mcu_log_size; - cxt->max_mcu_log_cnt = pdata->max_mcu_log_cnt; +#ifdef CONFIG_PSTORE_BOOT_LOG + cxt->boot_log_size = pdata->boot_log_size; + cxt->max_boot_log_cnt = pdata->max_boot_log_cnt; #endif paddr = cxt->phys_addr; dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size - cxt->pmsg_size; +#ifdef CONFIG_PSTORE_BOOT_LOG + dump_mem_sz -= cxt->boot_log_size; +#endif -#ifdef CONFIG_PSTORE_MCU_LOG - dump_mem_sz -= cxt->mcu_log_size; +#ifdef CONFIG_PSTORE_BOOT_LOG + err = ramoops_init_przs("boot-log", dev, cxt, &cxt->boot_przs, &paddr, + cxt->boot_log_size, -1, + &cxt->max_boot_log_cnt, 0, 0); + if (err) + goto fail_clear; + if (cxt->boot_log_size > 0) + for (i = 0; i < cxt->max_boot_log_cnt; i++) + pr_info("boot-log-%d\t0x%zx@%pa\n", i, cxt->boot_przs[i]->size, &cxt->boot_przs[i]->paddr); #endif err = ramoops_init_przs("dmesg", dev, cxt, &cxt->dprzs, &paddr, @@ -897,17 +907,6 @@ static int ramoops_probe(struct platform_device *pdev) if (cxt->pmsg_size > 0) pr_info("pmsg\t0x%zx@%pa\n", cxt->mprz->size, &cxt->mprz->paddr); -#ifdef CONFIG_PSTORE_MCU_LOG - err = ramoops_init_przs("mcu-log", dev, cxt, &cxt->mcu_przs, &paddr, - cxt->mcu_log_size, -1, - &cxt->max_mcu_log_cnt, 0, 0); - if (err) - goto fail_clear; - if (cxt->mcu_log_size > 0) - for (i = 0; i < cxt->max_mcu_log_cnt; i++) - pr_info("mcu-log-%d\t0x%zx@%pa\n", i, cxt->mcu_przs[i]->size, &cxt->mcu_przs[i]->paddr); -#endif - cxt->pstore.data = cxt; /* * Prepare frontend flags based on which areas are initialized. @@ -926,9 +925,9 @@ static int ramoops_probe(struct platform_device *pdev) cxt->pstore.flags |= PSTORE_FLAGS_FTRACE; if (cxt->pmsg_size) cxt->pstore.flags |= PSTORE_FLAGS_PMSG; -#ifdef CONFIG_PSTORE_MCU_LOG - if (cxt->mcu_log_size) - cxt->pstore.flags |= PSTORE_FLAGS_MCU_LOG; +#ifdef CONFIG_PSTORE_BOOT_LOG + if (cxt->boot_log_size) + cxt->pstore.flags |= PSTORE_FLAGS_BOOT_LOG; #endif /* diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index bc5e8edf8d7d..e912503a9149 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -80,5 +80,6 @@ int analogix_dp_audio_startup(struct analogix_dp_device *dp); int analogix_dp_audio_get_eld(struct analogix_dp_device *dp, u8 *buf, size_t len); int analogix_dp_loader_protect(struct analogix_dp_device *dp); +void analogix_dp_disable(struct analogix_dp_device *dp); #endif /* _ANALOGIX_DP_H_ */ diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 600c87339ecf..3e2c6ecb6575 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -78,6 +78,8 @@ struct platform_device; * +----------------------+----------------------------------+------------------------------+ */ +#define SUPPORT_HDMI_ALLM BIT(1) + enum { DW_HDMI_RES_8, DW_HDMI_RES_10, @@ -135,6 +137,7 @@ struct dw_hdmi_link_config { int frl_lanes; int rate_per_lane; int hcactive; + u8 add_func; u8 pps_payload[128]; }; @@ -165,7 +168,7 @@ struct dw_hdmi_qp_phy_ops { struct dw_hdmi_property_ops { void (*attach_properties)(struct drm_connector *connector, unsigned int color, int version, - void *data); + void *data, bool allm_en); void (*destroy_properties)(struct drm_connector *connector, void *data); int (*set_property)(struct drm_connector *connector, @@ -296,6 +299,7 @@ void dw_hdmi_set_output_type(struct dw_hdmi *hdmi, u64 val); bool dw_hdmi_get_output_whether_hdmi(struct dw_hdmi *hdmi); int dw_hdmi_get_output_type_cap(struct dw_hdmi *hdmi); void dw_hdmi_set_cec_adap(struct dw_hdmi *hdmi, struct cec_adapter *adap); +void dw_hdmi_qp_set_allm_enable(struct dw_hdmi_qp *hdmi_qp, bool enable); void dw_hdmi_qp_unbind(struct dw_hdmi_qp *hdmi); struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, @@ -317,5 +321,8 @@ void dw_hdmi_qp_audio_enable(struct dw_hdmi_qp *hdmi); void dw_hdmi_qp_audio_disable(struct dw_hdmi_qp *hdmi); int dw_hdmi_qp_set_plugged_cb(struct dw_hdmi_qp *hdmi, hdmi_codec_plugged_cb fn, struct device *codec_dev); +void dw_hdmi_qp_set_output_type(struct dw_hdmi_qp *hdmi, u64 val); +bool dw_hdmi_qp_get_output_whether_hdmi(struct dw_hdmi_qp *hdmi); +int dw_hdmi_qp_get_output_type_cap(struct dw_hdmi_qp *hdmi); #endif /* __IMX_HDMI_H__ */ diff --git a/include/linux/cma.h b/include/linux/cma.h index 4f29ac17067d..a60e6745bcaa 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -56,6 +56,8 @@ extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, extern struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align, gfp_t gfp_mask); extern bool cma_release(struct cma *cma, const struct page *pages, unsigned int count); - +#ifdef CONFIG_NO_GKI +extern unsigned long cma_used_pages(void); +#endif extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data); #endif diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 2476f1a97fb6..f7f6ada34836 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -588,8 +588,6 @@ static inline void iommu_iotlb_gather_add_page(struct iommu_domain *domain, extern struct iommu_group *pci_device_group(struct device *dev); /* Generic device grouping function */ extern struct iommu_group *generic_device_group(struct device *dev); -extern void rk_iommu_mask_irq(struct device *dev); -extern void rk_iommu_unmask_irq(struct device *dev); /* FSL-MC device grouping function */ struct iommu_group *fsl_mc_device_group(struct device *dev); @@ -1098,14 +1096,6 @@ static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev) { return NULL; } - -static inline void rk_iommu_mask_irq(struct device *dev) -{ -} - -static inline void rk_iommu_unmask_irq(struct device *dev) -{ -} #endif /* CONFIG_IOMMU_API */ /** diff --git a/include/linux/memory_group_manager.h b/include/linux/memory_group_manager.h index efa35f5714f7..c4667803b361 100644 --- a/include/linux/memory_group_manager.h +++ b/include/linux/memory_group_manager.h @@ -127,6 +127,16 @@ struct memory_group_manager_ops { u64 (*mgm_update_gpu_pte)(struct memory_group_manager_device *mgm_dev, int group_id, int mmu_level, u64 pte); + /* + * Undo any modifications done during mgm_update_gpu_pte(). + * This function allows getting back the original PTE entry as given + * to mgm_update_gpu_pte(). + * + * Return: PTE entry as originally specified to mgm_update_gpu_pte() + */ + u64 (*mgm_pte_to_original_pte)(struct memory_group_manager_device *mgm_dev, int group_id, + int mmu_level, u64 pte); + /* * mgm_vmf_insert_pfn_prot - Map a physical page in a group for the CPU * diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 2aac7a063196..3029c7f571b8 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -38,8 +38,8 @@ enum pstore_type_id { PSTORE_TYPE_PPC_COMMON = 6, PSTORE_TYPE_PMSG = 7, PSTORE_TYPE_PPC_OPAL = 8, -#ifdef CONFIG_PSTORE_MCU_LOG - PSTORE_TYPE_MCU_LOG = 9, +#ifdef CONFIG_PSTORE_BOOT_LOG + PSTORE_TYPE_BOOT_LOG = 9, #endif /* End of the list */ @@ -205,8 +205,8 @@ struct pstore_info { #define PSTORE_FLAGS_CONSOLE BIT(1) #define PSTORE_FLAGS_FTRACE BIT(2) #define PSTORE_FLAGS_PMSG BIT(3) -#ifdef CONFIG_PSTORE_MCU_LOG -#define PSTORE_FLAGS_MCU_LOG BIT(4) +#ifdef CONFIG_PSTORE_BOOT_LOG +#define PSTORE_FLAGS_BOOT_LOG BIT(4) #endif extern int pstore_register(struct pstore_info *); diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index ff42d9a3fc90..ad7e88a34d60 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -116,8 +116,8 @@ void *persistent_ram_old(struct persistent_ram_zone *prz); void persistent_ram_free_old(struct persistent_ram_zone *prz); ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, char *str, size_t len); -#ifdef CONFIG_PSTORE_MCU_LOG -ssize_t ramoops_pstore_read_for_mcu_log(struct pstore_record *record); +#ifdef CONFIG_PSTORE_BOOT_LOG +ssize_t ramoops_pstore_read_for_boot_log(struct pstore_record *record); #endif /* @@ -136,9 +136,9 @@ struct ramoops_platform_data { unsigned long console_size; unsigned long ftrace_size; unsigned long pmsg_size; -#ifdef CONFIG_PSTORE_MCU_LOG - unsigned long mcu_log_size; - unsigned long max_mcu_log_cnt; +#ifdef CONFIG_PSTORE_BOOT_LOG + unsigned long boot_log_size; + unsigned long max_boot_log_cnt; #endif int max_reason; u32 flags; diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h index a7aa69d004c4..250147abb6f3 100644 --- a/include/linux/reboot-mode.h +++ b/include/linux/reboot-mode.h @@ -8,6 +8,7 @@ struct reboot_mode_driver { int (*write)(struct reboot_mode_driver *reboot, unsigned int magic); int (*read)(struct reboot_mode_driver *reboot); struct notifier_block reboot_notifier; + struct notifier_block pre_restart_notifier; struct notifier_block panic_notifier; }; diff --git a/include/linux/version_compat_defs.h b/include/linux/version_compat_defs.h new file mode 100644 index 000000000000..a8e08742069d --- /dev/null +++ b/include/linux/version_compat_defs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * + * (C) COPYRIGHT 2022 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + */ + +#ifndef _VERSION_COMPAT_DEFS_H_ +#define _VERSION_COMPAT_DEFS_H_ + +#include + +#if KERNEL_VERSION(4, 16, 0) >= LINUX_VERSION_CODE +typedef unsigned int __poll_t; +#endif + +#endif /* _VERSION_COMPAT_DEFS_H_ */ diff --git a/include/soc/rockchip/rockchip-system-status.h b/include/soc/rockchip/rockchip-system-status.h index 200b1ee89602..e04921240450 100644 --- a/include/soc/rockchip/rockchip-system-status.h +++ b/include/soc/rockchip/rockchip-system-status.h @@ -6,7 +6,7 @@ #ifndef __SOC_ROCKCHIP_SYSTEM_STATUS_H #define __SOC_ROCKCHIP_SYSTEM_STATUS_H -#if IS_ENABLED(CONFIG_ROCKCHIP_SYSTEM_MONITOR) +#if IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR) int rockchip_register_system_status_notifier(struct notifier_block *nb); int rockchip_unregister_system_status_notifier(struct notifier_block *nb); void rockchip_set_system_status(unsigned long status); diff --git a/include/soc/rockchip/rockchip_iommu.h b/include/soc/rockchip/rockchip_iommu.h index 804f0fdc44a4..10a5d62ae35d 100644 --- a/include/soc/rockchip/rockchip_iommu.h +++ b/include/soc/rockchip/rockchip_iommu.h @@ -13,6 +13,8 @@ int rockchip_iommu_disable(struct device *dev); int rockchip_pagefault_done(struct device *master_dev); void __iomem *rockchip_get_iommu_base(struct device *master_dev, int idx); bool rockchip_iommu_is_enabled(struct device *dev); +void rockchip_iommu_mask_irq(struct device *dev); +void rockchip_iommu_unmask_irq(struct device *dev); #else static inline int rockchip_iommu_enable(struct device *dev) { @@ -34,6 +36,12 @@ static inline bool rockchip_iommu_is_enabled(struct device *dev) { return false; } +static inline void rockchip_iommu_mask_irq(struct device *dev) +{ +} +static inline void rockchip_iommu_unmask_irq(struct device *dev) +{ +} #endif #endif diff --git a/include/soc/rockchip/rockchip_opp_select.h b/include/soc/rockchip/rockchip_opp_select.h index da9cab568295..35353d8ade6d 100644 --- a/include/soc/rockchip/rockchip_opp_select.h +++ b/include/soc/rockchip/rockchip_opp_select.h @@ -107,6 +107,7 @@ int rockchip_set_intermediate_rate(struct device *dev, int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info, char *lkg_name, char *reg_name); +int rockchip_opp_dump_cur_state(struct device *dev); #else static inline int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage) @@ -226,6 +227,11 @@ static inline int rockchip_init_opp_table(struct device *dev, return -EOPNOTSUPP; } +static inline int rockchip_opp_dump_cur_state(struct device *dev) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_ROCKCHIP_OPP */ #endif diff --git a/include/soc/rockchip/rockchip_system_monitor.h b/include/soc/rockchip/rockchip_system_monitor.h index a8f500651165..8613838416ea 100644 --- a/include/soc/rockchip/rockchip_system_monitor.h +++ b/include/soc/rockchip/rockchip_system_monitor.h @@ -6,11 +6,23 @@ #ifndef __SOC_ROCKCHIP_SYSTEM_MONITOR_H #define __SOC_ROCKCHIP_SYSTEM_MONITOR_H +#include +#include +#include + enum monitor_dev_type { MONITOR_TPYE_CPU = 0, /* CPU */ MONITOR_TPYE_DEV, /* GPU, NPU, DMC, and so on */ }; +enum system_monitor_event_type { + SYSTEM_MONITOR_CHANGE_TEMP = 0, +}; + +struct system_monitor_event_data { + int temp; +}; + struct volt_adjust_table { unsigned int min; /* Minimum frequency in MHz */ unsigned int max; /* Maximum frequency in MHz */ @@ -131,7 +143,7 @@ struct monitor_dev_profile { struct rockchip_opp_info *opp_info; }; -#if IS_ENABLED(CONFIG_ROCKCHIP_SYSTEM_MONITOR) +#if IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR) struct monitor_dev_info * rockchip_system_monitor_register(struct device *dev, struct monitor_dev_profile *devp); @@ -148,6 +160,8 @@ int rockchip_monitor_dev_low_temp_adjust(struct monitor_dev_info *info, int rockchip_monitor_dev_high_temp_adjust(struct monitor_dev_info *info, bool is_high); int rockchip_monitor_suspend_low_temp_adjust(int cpu); +int rockchip_system_monitor_register_notifier(struct notifier_block *nb); +void rockchip_system_monitor_unregister_notifier(struct notifier_block *nb); #else static inline struct monitor_dev_info * rockchip_system_monitor_register(struct device *dev, @@ -208,6 +222,16 @@ static inline int rockchip_monitor_suspend_low_temp_adjust(int cpu) return 0; }; +static inline int +rockchip_system_monitor_register_notifier(struct notifier_block *nb) +{ + return 0; +}; + +static inline void +rockchip_system_monitor_unregister_notifier(struct notifier_block *nb) +{ +}; #endif /* CONFIG_ROCKCHIP_SYSTEM_MONITOR */ #endif diff --git a/include/uapi/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.h b/include/uapi/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.h index 8a3cc6bea6ac..613eb1fdd081 100644 --- a/include/uapi/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.h +++ b/include/uapi/gpu/arm/bifrost/backend/gpu/mali_kbase_model_dummy.h @@ -43,8 +43,11 @@ (KBASE_DUMMY_MODEL_VALUES_PER_BLOCK * sizeof(__u32)) #define KBASE_DUMMY_MODEL_MAX_MEMSYS_BLOCKS 8 #define KBASE_DUMMY_MODEL_MAX_SHADER_CORES 32 -#define KBASE_DUMMY_MODEL_MAX_NUM_PERF_BLOCKS \ +#define KBASE_DUMMY_MODEL_MAX_FIRMWARE_BLOCKS 0 +#define KBASE_DUMMY_MODEL_MAX_NUM_HARDWARE_BLOCKS \ (1 + 1 + KBASE_DUMMY_MODEL_MAX_MEMSYS_BLOCKS + KBASE_DUMMY_MODEL_MAX_SHADER_CORES) +#define KBASE_DUMMY_MODEL_MAX_NUM_PERF_BLOCKS \ + (KBASE_DUMMY_MODEL_MAX_NUM_HARDWARE_BLOCKS + KBASE_DUMMY_MODEL_MAX_FIRMWARE_BLOCKS) #define KBASE_DUMMY_MODEL_COUNTER_TOTAL \ (KBASE_DUMMY_MODEL_MAX_NUM_PERF_BLOCKS * \ KBASE_DUMMY_MODEL_COUNTER_PER_CORE) diff --git a/include/uapi/gpu/arm/bifrost/csf/mali_base_csf_kernel.h b/include/uapi/gpu/arm/bifrost/csf/mali_base_csf_kernel.h index 0543da02f20f..3b02350c08bf 100644 --- a/include/uapi/gpu/arm/bifrost/csf/mali_base_csf_kernel.h +++ b/include/uapi/gpu/arm/bifrost/csf/mali_base_csf_kernel.h @@ -23,99 +23,16 @@ #define _UAPI_BASE_CSF_KERNEL_H_ #include +#include "../mali_base_common_kernel.h" -/* Memory allocation, access/hint flags. +/* Memory allocation, access/hint flags & mask specific to CSF GPU. * * See base_mem_alloc_flags. */ -/* IN */ -/* Read access CPU side - */ -#define BASE_MEM_PROT_CPU_RD ((base_mem_alloc_flags)1 << 0) - -/* Write access CPU side - */ -#define BASE_MEM_PROT_CPU_WR ((base_mem_alloc_flags)1 << 1) - -/* Read access GPU side - */ -#define BASE_MEM_PROT_GPU_RD ((base_mem_alloc_flags)1 << 2) - -/* Write access GPU side - */ -#define BASE_MEM_PROT_GPU_WR ((base_mem_alloc_flags)1 << 3) - -/* Execute allowed on the GPU side - */ -#define BASE_MEM_PROT_GPU_EX ((base_mem_alloc_flags)1 << 4) - -/* Will be permanently mapped in kernel space. - * Flag is only allowed on allocations originating from kbase. - */ -#define BASEP_MEM_PERMANENT_KERNEL_MAPPING ((base_mem_alloc_flags)1 << 5) - -/* The allocation will completely reside within the same 4GB chunk in the GPU - * virtual space. - * Since this flag is primarily required only for the TLS memory which will - * not be used to contain executable code and also not used for Tiler heap, - * it can't be used along with BASE_MEM_PROT_GPU_EX and TILER_ALIGN_TOP flags. - */ -#define BASE_MEM_GPU_VA_SAME_4GB_PAGE ((base_mem_alloc_flags)1 << 6) - -/* Userspace is not allowed to free this memory. - * Flag is only allowed on allocations originating from kbase. - */ -#define BASEP_MEM_NO_USER_FREE ((base_mem_alloc_flags)1 << 7) - /* Must be FIXED memory. */ #define BASE_MEM_FIXED ((base_mem_alloc_flags)1 << 8) -/* Grow backing store on GPU Page Fault - */ -#define BASE_MEM_GROW_ON_GPF ((base_mem_alloc_flags)1 << 9) - -/* Page coherence Outer shareable, if available - */ -#define BASE_MEM_COHERENT_SYSTEM ((base_mem_alloc_flags)1 << 10) - -/* Page coherence Inner shareable - */ -#define BASE_MEM_COHERENT_LOCAL ((base_mem_alloc_flags)1 << 11) - -/* IN/OUT */ -/* Should be cached on the CPU, returned if actually cached - */ -#define BASE_MEM_CACHED_CPU ((base_mem_alloc_flags)1 << 12) - -/* IN/OUT */ -/* Must have same VA on both the GPU and the CPU - */ -#define BASE_MEM_SAME_VA ((base_mem_alloc_flags)1 << 13) - -/* OUT */ -/* Must call mmap to acquire a GPU address for the alloc - */ -#define BASE_MEM_NEED_MMAP ((base_mem_alloc_flags)1 << 14) - -/* IN */ -/* Page coherence Outer shareable, required. - */ -#define BASE_MEM_COHERENT_SYSTEM_REQUIRED ((base_mem_alloc_flags)1 << 15) - -/* Protected memory - */ -#define BASE_MEM_PROTECTED ((base_mem_alloc_flags)1 << 16) - -/* Not needed physical memory - */ -#define BASE_MEM_DONT_NEED ((base_mem_alloc_flags)1 << 17) - -/* Must use shared CPU/GPU zone (SAME_VA zone) but doesn't require the - * addresses to be the same - */ -#define BASE_MEM_IMPORT_SHARED ((base_mem_alloc_flags)1 << 18) - /* CSF event memory * * If Outer shareable coherence is not specified or not available, then on @@ -131,46 +48,15 @@ #define BASE_MEM_RESERVED_BIT_20 ((base_mem_alloc_flags)1 << 20) -/* Should be uncached on the GPU, will work only for GPUs using AARCH64 mmu - * mode. Some components within the GPU might only be able to access memory - * that is GPU cacheable. Refer to the specific GPU implementation for more - * details. The 3 shareability flags will be ignored for GPU uncached memory. - * If used while importing USER_BUFFER type memory, then the import will fail - * if the memory is not aligned to GPU and CPU cache line width. - */ -#define BASE_MEM_UNCACHED_GPU ((base_mem_alloc_flags)1 << 21) - -/* - * Bits [22:25] for group_id (0~15). - * - * base_mem_group_id_set() should be used to pack a memory group ID into a - * base_mem_alloc_flags value instead of accessing the bits directly. - * base_mem_group_id_get() should be used to extract the memory group ID from - * a base_mem_alloc_flags value. - */ -#define BASEP_MEM_GROUP_ID_SHIFT 22 -#define BASE_MEM_GROUP_ID_MASK \ - ((base_mem_alloc_flags)0xF << BASEP_MEM_GROUP_ID_SHIFT) - -/* Must do CPU cache maintenance when imported memory is mapped/unmapped - * on GPU. Currently applicable to dma-buf type only. - */ -#define BASE_MEM_IMPORT_SYNC_ON_MAP_UNMAP ((base_mem_alloc_flags)1 << 26) - -/* OUT */ -/* Kernel side cache sync ops required */ -#define BASE_MEM_KERNEL_SYNC ((base_mem_alloc_flags)1 << 28) /* Must be FIXABLE memory: its GPU VA will be determined at a later point, * at which time it will be at a fixed GPU VA. */ #define BASE_MEM_FIXABLE ((base_mem_alloc_flags)1 << 29) -/* Number of bits used as flags for base memory management - * - * Must be kept in sync with the base_mem_alloc_flags flags +/* Note that the number of bits used for base_mem_alloc_flags + * must be less than BASE_MEM_FLAGS_NR_BITS !!! */ -#define BASE_MEM_FLAGS_NR_BITS 30 /* A mask of all the flags which are only valid for allocations within kbase, * and may not be passed from user space. @@ -178,30 +64,14 @@ #define BASEP_MEM_FLAGS_KERNEL_ONLY \ (BASEP_MEM_PERMANENT_KERNEL_MAPPING | BASEP_MEM_NO_USER_FREE) -/* A mask for all output bits, excluding IN/OUT bits. - */ -#define BASE_MEM_FLAGS_OUTPUT_MASK BASE_MEM_NEED_MMAP - -/* A mask for all input bits, including IN/OUT bits. - */ -#define BASE_MEM_FLAGS_INPUT_MASK \ - (((1 << BASE_MEM_FLAGS_NR_BITS) - 1) & ~BASE_MEM_FLAGS_OUTPUT_MASK) - /* A mask of all currently reserved flags */ #define BASE_MEM_FLAGS_RESERVED BASE_MEM_RESERVED_BIT_20 -#define BASEP_MEM_INVALID_HANDLE (0ul) -#define BASE_MEM_MMU_DUMP_HANDLE (1ul << LOCAL_PAGE_SHIFT) -#define BASE_MEM_TRACE_BUFFER_HANDLE (2ul << LOCAL_PAGE_SHIFT) -#define BASE_MEM_MAP_TRACKING_HANDLE (3ul << LOCAL_PAGE_SHIFT) -#define BASEP_MEM_WRITE_ALLOC_PAGES_HANDLE (4ul << LOCAL_PAGE_SHIFT) -/* reserved handles ..-47< for future special handles */ +/* Special base mem handles specific to CSF. + */ #define BASEP_MEM_CSF_USER_REG_PAGE_HANDLE (47ul << LOCAL_PAGE_SHIFT) #define BASEP_MEM_CSF_USER_IO_PAGES_HANDLE (48ul << LOCAL_PAGE_SHIFT) -#define BASE_MEM_COOKIE_BASE (64ul << LOCAL_PAGE_SHIFT) -#define BASE_MEM_FIRST_FREE_ADDRESS \ - ((BITS_PER_LONG << LOCAL_PAGE_SHIFT) + BASE_MEM_COOKIE_BASE) #define KBASE_CSF_NUM_USER_IO_PAGES_HANDLE \ ((BASE_MEM_COOKIE_BASE - BASEP_MEM_CSF_USER_IO_PAGES_HANDLE) >> \ @@ -210,28 +80,7 @@ /* Valid set of just-in-time memory allocation flags */ #define BASE_JIT_ALLOC_VALID_FLAGS ((__u8)0) -/* Flags to pass to ::base_context_init. - * Flags can be ORed together to enable multiple things. - * - * These share the same space as BASEP_CONTEXT_FLAG_*, and so must - * not collide with them. - */ -typedef __u32 base_context_create_flags; - -/* No flags set */ -#define BASE_CONTEXT_CREATE_FLAG_NONE ((base_context_create_flags)0) - -/* Base context is embedded in a cctx object (flag used for CINSTR - * software counter macros) - */ -#define BASE_CONTEXT_CCTX_EMBEDDED ((base_context_create_flags)1 << 0) - -/* Base context is a 'System Monitor' context for Hardware counters. - * - * One important side effect of this is that job submission is disabled. - */ -#define BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED \ - ((base_context_create_flags)1 << 1) +/* flags for base context specific to CSF */ /* Base context creates a CSF event notification thread. * @@ -240,22 +89,6 @@ typedef __u32 base_context_create_flags; */ #define BASE_CONTEXT_CSF_EVENT_THREAD ((base_context_create_flags)1 << 2) -/* Bit-shift used to encode a memory group ID in base_context_create_flags - */ -#define BASEP_CONTEXT_MMU_GROUP_ID_SHIFT (3) - -/* Bitmask used to encode a memory group ID in base_context_create_flags - */ -#define BASEP_CONTEXT_MMU_GROUP_ID_MASK \ - ((base_context_create_flags)0xF << BASEP_CONTEXT_MMU_GROUP_ID_SHIFT) - -/* Bitpattern describing the base_context_create_flags that can be - * passed to the kernel - */ -#define BASEP_CONTEXT_CREATE_KERNEL_FLAGS \ - (BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED | \ - BASEP_CONTEXT_MMU_GROUP_ID_MASK) - /* Bitpattern describing the ::base_context_create_flags that can be * passed to base_context_init() */ @@ -264,15 +97,7 @@ typedef __u32 base_context_create_flags; BASE_CONTEXT_CSF_EVENT_THREAD | \ BASEP_CONTEXT_CREATE_KERNEL_FLAGS) -/* Enable additional tracepoints for latency measurements (TL_ATOM_READY, - * TL_ATOM_DONE, TL_ATOM_PRIO_CHANGE, TL_ATOM_EVENT_POST) - */ -#define BASE_TLSTREAM_ENABLE_LATENCY_TRACEPOINTS (1 << 0) - -/* Indicate that job dumping is enabled. This could affect certain timers - * to account for the performance impact. - */ -#define BASE_TLSTREAM_JOB_DUMPING_ENABLED (1 << 1) +/* Flags for base tracepoint specific to CSF */ /* Enable KBase tracepoints for CSF builds */ #define BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS (1 << 2) @@ -304,6 +129,10 @@ typedef __u32 base_context_create_flags; */ #define BASEP_KCPU_CQS_MAX_NUM_OBJS ((size_t)32) +/* CSF CSI EXCEPTION_HANDLER_FLAGS */ +#define BASE_CSF_TILER_OOM_EXCEPTION_FLAG (1u << 0) +#define BASE_CSF_EXCEPTION_HANDLER_FLAGS_MASK (BASE_CSF_TILER_OOM_EXCEPTION_FLAG) + /** * enum base_kcpu_command_type - Kernel CPU queue command type. * @BASE_KCPU_COMMAND_TYPE_FENCE_SIGNAL: fence_signal, @@ -723,4 +552,45 @@ struct base_csf_notification { } payload; }; +/** + * struct mali_base_gpu_core_props - GPU core props info + * + * @product_id: Pro specific value. + * @version_status: Status of the GPU release. No defined values, but starts at + * 0 and increases by one for each release status (alpha, beta, EAC, etc.). + * 4 bit values (0-15). + * @minor_revision: Minor release number of the GPU. "P" part of an "RnPn" + * release number. + * 8 bit values (0-255). + * @major_revision: Major release number of the GPU. "R" part of an "RnPn" + * release number. + * 4 bit values (0-15). + * @padding: padding to align to 8-byte + * @gpu_freq_khz_max: The maximum GPU frequency. Reported to applications by + * clGetDeviceInfo() + * @log2_program_counter_size: Size of the shader program counter, in bits. + * @texture_features: TEXTURE_FEATURES_x registers, as exposed by the GPU. This + * is a bitpattern where a set bit indicates that the format is supported. + * Before using a texture format, it is recommended that the corresponding + * bit be checked. + * @gpu_available_memory_size: Theoretical maximum memory available to the GPU. + * It is unlikely that a client will be able to allocate all of this memory + * for their own purposes, but this at least provides an upper bound on the + * memory available to the GPU. + * This is required for OpenCL's clGetDeviceInfo() call when + * CL_DEVICE_GLOBAL_MEM_SIZE is requested, for OpenCL GPU devices. The + * client will not be expecting to allocate anywhere near this value. + */ +struct mali_base_gpu_core_props { + __u32 product_id; + __u16 version_status; + __u16 minor_revision; + __u16 major_revision; + __u16 padding; + __u32 gpu_freq_khz_max; + __u32 log2_program_counter_size; + __u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS]; + __u64 gpu_available_memory_size; +}; + #endif /* _UAPI_BASE_CSF_KERNEL_H_ */ diff --git a/include/uapi/gpu/arm/bifrost/csf/mali_kbase_csf_ioctl.h b/include/uapi/gpu/arm/bifrost/csf/mali_kbase_csf_ioctl.h index 00d2585f4aef..db7252605f06 100644 --- a/include/uapi/gpu/arm/bifrost/csf/mali_kbase_csf_ioctl.h +++ b/include/uapi/gpu/arm/bifrost/csf/mali_kbase_csf_ioctl.h @@ -58,10 +58,12 @@ * - First release of new HW performance counters interface. * 1.11: * - Dummy model (no mali) backend will now clear HWC values after each sample + * 1.12: + * - Added support for incremental rendering flag in CSG create call */ #define BASE_UK_VERSION_MAJOR 1 -#define BASE_UK_VERSION_MINOR 11 +#define BASE_UK_VERSION_MINOR 12 /** * struct kbase_ioctl_version_check - Check version compatibility between @@ -247,6 +249,9 @@ union kbase_ioctl_cs_queue_group_create_1_6 { * allowed to use. * @in.compute_max: Maximum number of compute endpoints the group is allowed * to use. + * @in.csi_handlers: Flags to signal that the application intends to use CSI + * exception handlers in some linear buffers to deal with + * the given exception types. * @in.padding: Currently unused, must be zero * @out: Output parameters * @out.group_handle: Handle of a newly created queue group. @@ -263,7 +268,8 @@ union kbase_ioctl_cs_queue_group_create { __u8 tiler_max; __u8 fragment_max; __u8 compute_max; - __u8 padding[3]; + __u8 csi_handlers; + __u8 padding[2]; /** * @in.reserved: Reserved */ diff --git a/include/uapi/gpu/arm/bifrost/jm/mali_base_jm_kernel.h b/include/uapi/gpu/arm/bifrost/jm/mali_base_jm_kernel.h index 94f4dc701be2..ae43908b9360 100644 --- a/include/uapi/gpu/arm/bifrost/jm/mali_base_jm_kernel.h +++ b/include/uapi/gpu/arm/bifrost/jm/mali_base_jm_kernel.h @@ -23,100 +23,16 @@ #define _UAPI_BASE_JM_KERNEL_H_ #include +#include "../mali_base_common_kernel.h" -/* Memory allocation, access/hint flags. +/* Memory allocation, access/hint flags & mask specific to JM GPU. * * See base_mem_alloc_flags. */ -/* IN */ -/* Read access CPU side - */ -#define BASE_MEM_PROT_CPU_RD ((base_mem_alloc_flags)1 << 0) - -/* Write access CPU side - */ -#define BASE_MEM_PROT_CPU_WR ((base_mem_alloc_flags)1 << 1) - -/* Read access GPU side - */ -#define BASE_MEM_PROT_GPU_RD ((base_mem_alloc_flags)1 << 2) - -/* Write access GPU side - */ -#define BASE_MEM_PROT_GPU_WR ((base_mem_alloc_flags)1 << 3) - -/* Execute allowed on the GPU side - */ -#define BASE_MEM_PROT_GPU_EX ((base_mem_alloc_flags)1 << 4) - -/* Will be permanently mapped in kernel space. - * Flag is only allowed on allocations originating from kbase. - */ -#define BASEP_MEM_PERMANENT_KERNEL_MAPPING ((base_mem_alloc_flags)1 << 5) - -/* The allocation will completely reside within the same 4GB chunk in the GPU - * virtual space. - * Since this flag is primarily required only for the TLS memory which will - * not be used to contain executable code and also not used for Tiler heap, - * it can't be used along with BASE_MEM_PROT_GPU_EX and TILER_ALIGN_TOP flags. - */ -#define BASE_MEM_GPU_VA_SAME_4GB_PAGE ((base_mem_alloc_flags)1 << 6) - -/* Userspace is not allowed to free this memory. - * Flag is only allowed on allocations originating from kbase. - */ -#define BASEP_MEM_NO_USER_FREE ((base_mem_alloc_flags)1 << 7) - -/* Used as BASE_MEM_FIXED in other backends - */ +/* Used as BASE_MEM_FIXED in other backends */ #define BASE_MEM_RESERVED_BIT_8 ((base_mem_alloc_flags)1 << 8) -/* Grow backing store on GPU Page Fault - */ -#define BASE_MEM_GROW_ON_GPF ((base_mem_alloc_flags)1 << 9) - -/* Page coherence Outer shareable, if available - */ -#define BASE_MEM_COHERENT_SYSTEM ((base_mem_alloc_flags)1 << 10) - -/* Page coherence Inner shareable - */ -#define BASE_MEM_COHERENT_LOCAL ((base_mem_alloc_flags)1 << 11) - -/* IN/OUT */ -/* Should be cached on the CPU, returned if actually cached - */ -#define BASE_MEM_CACHED_CPU ((base_mem_alloc_flags)1 << 12) - -/* IN/OUT */ -/* Must have same VA on both the GPU and the CPU - */ -#define BASE_MEM_SAME_VA ((base_mem_alloc_flags)1 << 13) - -/* OUT */ -/* Must call mmap to acquire a GPU address for the allocation - */ -#define BASE_MEM_NEED_MMAP ((base_mem_alloc_flags)1 << 14) - -/* IN */ -/* Page coherence Outer shareable, required. - */ -#define BASE_MEM_COHERENT_SYSTEM_REQUIRED ((base_mem_alloc_flags)1 << 15) - -/* Protected memory - */ -#define BASE_MEM_PROTECTED ((base_mem_alloc_flags)1 << 16) - -/* Not needed physical memory - */ -#define BASE_MEM_DONT_NEED ((base_mem_alloc_flags)1 << 17) - -/* Must use shared CPU/GPU zone (SAME_VA zone) but doesn't require the - * addresses to be the same - */ -#define BASE_MEM_IMPORT_SHARED ((base_mem_alloc_flags)1 << 18) - /** * BASE_MEM_RESERVED_BIT_19 - Bit 19 is reserved. * @@ -131,47 +47,15 @@ */ #define BASE_MEM_TILER_ALIGN_TOP ((base_mem_alloc_flags)1 << 20) -/* Should be uncached on the GPU, will work only for GPUs using AARCH64 mmu - * mode. Some components within the GPU might only be able to access memory - * that is GPU cacheable. Refer to the specific GPU implementation for more - * details. The 3 shareability flags will be ignored for GPU uncached memory. - * If used while importing USER_BUFFER type memory, then the import will fail - * if the memory is not aligned to GPU and CPU cache line width. - */ -#define BASE_MEM_UNCACHED_GPU ((base_mem_alloc_flags)1 << 21) - -/* - * Bits [22:25] for group_id (0~15). - * - * base_mem_group_id_set() should be used to pack a memory group ID into a - * base_mem_alloc_flags value instead of accessing the bits directly. - * base_mem_group_id_get() should be used to extract the memory group ID from - * a base_mem_alloc_flags value. - */ -#define BASEP_MEM_GROUP_ID_SHIFT 22 -#define BASE_MEM_GROUP_ID_MASK \ - ((base_mem_alloc_flags)0xF << BASEP_MEM_GROUP_ID_SHIFT) - -/* Must do CPU cache maintenance when imported memory is mapped/unmapped - * on GPU. Currently applicable to dma-buf type only. - */ -#define BASE_MEM_IMPORT_SYNC_ON_MAP_UNMAP ((base_mem_alloc_flags)1 << 26) - /* Use the GPU VA chosen by the kernel client */ #define BASE_MEM_FLAG_MAP_FIXED ((base_mem_alloc_flags)1 << 27) -/* OUT */ -/* Kernel side cache sync ops required */ -#define BASE_MEM_KERNEL_SYNC ((base_mem_alloc_flags)1 << 28) - /* Force trimming of JIT allocations when creating a new allocation */ #define BASEP_MEM_PERFORM_JIT_TRIM ((base_mem_alloc_flags)1 << 29) -/* Number of bits used as flags for base memory management - * - * Must be kept in sync with the base_mem_alloc_flags flags +/* Note that the number of bits used for base_mem_alloc_flags + * must be less than BASE_MEM_FLAGS_NR_BITS !!! */ -#define BASE_MEM_FLAGS_NR_BITS 30 /* A mask of all the flags which are only valid for allocations within kbase, * and may not be passed from user space. @@ -180,29 +64,11 @@ (BASEP_MEM_PERMANENT_KERNEL_MAPPING | BASEP_MEM_NO_USER_FREE | \ BASE_MEM_FLAG_MAP_FIXED | BASEP_MEM_PERFORM_JIT_TRIM) -/* A mask for all output bits, excluding IN/OUT bits. - */ -#define BASE_MEM_FLAGS_OUTPUT_MASK BASE_MEM_NEED_MMAP - -/* A mask for all input bits, including IN/OUT bits. - */ -#define BASE_MEM_FLAGS_INPUT_MASK \ - (((1 << BASE_MEM_FLAGS_NR_BITS) - 1) & ~BASE_MEM_FLAGS_OUTPUT_MASK) - /* A mask of all currently reserved flags */ #define BASE_MEM_FLAGS_RESERVED \ (BASE_MEM_RESERVED_BIT_8 | BASE_MEM_RESERVED_BIT_19) -#define BASEP_MEM_INVALID_HANDLE (0ul) -#define BASE_MEM_MMU_DUMP_HANDLE (1ul << LOCAL_PAGE_SHIFT) -#define BASE_MEM_TRACE_BUFFER_HANDLE (2ul << LOCAL_PAGE_SHIFT) -#define BASE_MEM_MAP_TRACKING_HANDLE (3ul << LOCAL_PAGE_SHIFT) -#define BASEP_MEM_WRITE_ALLOC_PAGES_HANDLE (4ul << LOCAL_PAGE_SHIFT) -/* reserved handles ..-47< for future special handles */ -#define BASE_MEM_COOKIE_BASE (64ul << LOCAL_PAGE_SHIFT) -#define BASE_MEM_FIRST_FREE_ADDRESS \ - ((BITS_PER_LONG << LOCAL_PAGE_SHIFT) + BASE_MEM_COOKIE_BASE) /* Similar to BASE_MEM_TILER_ALIGN_TOP, memory starting from the end of the * initial commit is aligned to 'extension' pages, where 'extension' must be a power @@ -227,47 +93,6 @@ #define BASE_JIT_ALLOC_VALID_FLAGS \ (BASE_JIT_ALLOC_MEM_TILER_ALIGN_TOP | BASE_JIT_ALLOC_HEAP_INFO_IS_SIZE) -/** - * typedef base_context_create_flags - Flags to pass to ::base_context_init. - * - * Flags can be ORed together to enable multiple things. - * - * These share the same space as BASEP_CONTEXT_FLAG_*, and so must - * not collide with them. - */ -typedef __u32 base_context_create_flags; - -/* No flags set */ -#define BASE_CONTEXT_CREATE_FLAG_NONE ((base_context_create_flags)0) - -/* Base context is embedded in a cctx object (flag used for CINSTR - * software counter macros) - */ -#define BASE_CONTEXT_CCTX_EMBEDDED ((base_context_create_flags)1 << 0) - -/* Base context is a 'System Monitor' context for Hardware counters. - * - * One important side effect of this is that job submission is disabled. - */ -#define BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED \ - ((base_context_create_flags)1 << 1) - -/* Bit-shift used to encode a memory group ID in base_context_create_flags - */ -#define BASEP_CONTEXT_MMU_GROUP_ID_SHIFT (3) - -/* Bitmask used to encode a memory group ID in base_context_create_flags - */ -#define BASEP_CONTEXT_MMU_GROUP_ID_MASK \ - ((base_context_create_flags)0xF << BASEP_CONTEXT_MMU_GROUP_ID_SHIFT) - -/* Bitpattern describing the base_context_create_flags that can be - * passed to the kernel - */ -#define BASEP_CONTEXT_CREATE_KERNEL_FLAGS \ - (BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED | \ - BASEP_CONTEXT_MMU_GROUP_ID_MASK) - /* Bitpattern describing the ::base_context_create_flags that can be * passed to base_context_init() */ @@ -287,16 +112,7 @@ typedef __u32 base_context_create_flags; #define BASEP_CONTEXT_FLAG_JOB_DUMP_DISABLED \ ((base_context_create_flags)(1 << 31)) -/* Enable additional tracepoints for latency measurements (TL_ATOM_READY, - * TL_ATOM_DONE, TL_ATOM_PRIO_CHANGE, TL_ATOM_EVENT_POST) - */ -#define BASE_TLSTREAM_ENABLE_LATENCY_TRACEPOINTS (1 << 0) - -/* Indicate that job dumping is enabled. This could affect certain timers - * to account for the performance impact. - */ -#define BASE_TLSTREAM_JOB_DUMPING_ENABLED (1 << 1) - +/* Flags for base tracepoint specific to JM */ #define BASE_TLSTREAM_FLAGS_MASK (BASE_TLSTREAM_ENABLE_LATENCY_TRACEPOINTS | \ BASE_TLSTREAM_JOB_DUMPING_ENABLED) /* @@ -509,9 +325,6 @@ typedef __u32 base_jd_core_req; * takes priority * * This is only guaranteed to work for BASE_JD_REQ_ONLY_COMPUTE atoms. - * - * If the core availability policy is keeping the required core group turned - * off, then the job will fail with a BASE_JD_EVENT_PM_EVENT error code. */ #define BASE_JD_REQ_SPECIFIC_COHERENT_GROUP ((base_jd_core_req)1 << 11) @@ -770,6 +583,9 @@ typedef __u8 base_jd_prio; */ #define BASE_JD_PRIO_REALTIME ((base_jd_prio)3) +/* Invalid atom priority (max uint8_t value) */ +#define BASE_JD_PRIO_INVALID ((base_jd_prio)255) + /* Count of the number of priority levels. This itself is not a valid * base_jd_prio setting */ @@ -1016,11 +832,6 @@ enum { * BASE_JD_EVENT_JOB_CONFIG_FAULT, or if the * platform doesn't support the feature specified in * the atom. - * @BASE_JD_EVENT_PM_EVENT: TODO: remove as it's not used - * @BASE_JD_EVENT_TIMED_OUT: TODO: remove as it's not used - * @BASE_JD_EVENT_BAG_INVALID: TODO: remove as it's not used - * @BASE_JD_EVENT_PROGRESS_REPORT: TODO: remove as it's not used - * @BASE_JD_EVENT_BAG_DONE: TODO: remove as it's not used * @BASE_JD_EVENT_DRV_TERMINATED: this is a special event generated to indicate * to userspace that the KBase context has been * destroyed and Base should stop listening for @@ -1115,17 +926,10 @@ enum base_jd_event_code { /* SW defined exceptions */ BASE_JD_EVENT_MEM_GROWTH_FAILED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x000, - BASE_JD_EVENT_TIMED_OUT = - BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x001, BASE_JD_EVENT_JOB_CANCELLED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x002, BASE_JD_EVENT_JOB_INVALID = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x003, - BASE_JD_EVENT_PM_EVENT = - BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x004, - - BASE_JD_EVENT_BAG_INVALID = - BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_BAG | 0x003, BASE_JD_EVENT_RANGE_HW_FAULT_OR_SW_ERROR_END = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_RESERVED | 0x3FF, @@ -1133,10 +937,6 @@ enum base_jd_event_code { BASE_JD_EVENT_RANGE_SW_SUCCESS_START = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | 0x000, - BASE_JD_EVENT_PROGRESS_REPORT = BASE_JD_SW_EVENT | - BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_JOB | 0x000, - BASE_JD_EVENT_BAG_DONE = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | - BASE_JD_SW_EVENT_BAG | 0x000, BASE_JD_EVENT_DRV_TERMINATED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_INFO | 0x000, @@ -1203,4 +1003,49 @@ struct base_dump_cpu_gpu_counters { __u8 padding[36]; }; +/** + * struct mali_base_gpu_core_props - GPU core props info + * + * @product_id: Pro specific value. + * @version_status: Status of the GPU release. No defined values, but starts at + * 0 and increases by one for each release status (alpha, beta, EAC, etc.). + * 4 bit values (0-15). + * @minor_revision: Minor release number of the GPU. "P" part of an "RnPn" + * release number. + * 8 bit values (0-255). + * @major_revision: Major release number of the GPU. "R" part of an "RnPn" + * release number. + * 4 bit values (0-15). + * @padding: padding to align to 8-byte + * @gpu_freq_khz_max: The maximum GPU frequency. Reported to applications by + * clGetDeviceInfo() + * @log2_program_counter_size: Size of the shader program counter, in bits. + * @texture_features: TEXTURE_FEATURES_x registers, as exposed by the GPU. This + * is a bitpattern where a set bit indicates that the format is supported. + * Before using a texture format, it is recommended that the corresponding + * bit be checked. + * @gpu_available_memory_size: Theoretical maximum memory available to the GPU. + * It is unlikely that a client will be able to allocate all of this memory + * for their own purposes, but this at least provides an upper bound on the + * memory available to the GPU. + * This is required for OpenCL's clGetDeviceInfo() call when + * CL_DEVICE_GLOBAL_MEM_SIZE is requested, for OpenCL GPU devices. The + * client will not be expecting to allocate anywhere near this value. + * @num_exec_engines: The number of execution engines. Only valid for tGOX + * (Bifrost) GPUs, where GPU_HAS_REG_CORE_FEATURES is defined. Otherwise, + * this is always 0. + */ +struct mali_base_gpu_core_props { + __u32 product_id; + __u16 version_status; + __u16 minor_revision; + __u16 major_revision; + __u16 padding; + __u32 gpu_freq_khz_max; + __u32 log2_program_counter_size; + __u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS]; + __u64 gpu_available_memory_size; + __u8 num_exec_engines; +}; + #endif /* _UAPI_BASE_JM_KERNEL_H_ */ diff --git a/include/uapi/gpu/arm/bifrost/mali_base_common_kernel.h b/include/uapi/gpu/arm/bifrost/mali_base_common_kernel.h new file mode 100644 index 000000000000..f8378146aceb --- /dev/null +++ b/include/uapi/gpu/arm/bifrost/mali_base_common_kernel.h @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * + * (C) COPYRIGHT 2022 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + */ + +#ifndef _UAPI_BASE_COMMON_KERNEL_H_ +#define _UAPI_BASE_COMMON_KERNEL_H_ + +#include + +struct base_mem_handle { + struct { + __u64 handle; + } basep; +}; + +#define BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS 4 + +/* Memory allocation, access/hint flags & mask. + * + * See base_mem_alloc_flags. + */ + +/* IN */ +/* Read access CPU side + */ +#define BASE_MEM_PROT_CPU_RD ((base_mem_alloc_flags)1 << 0) + +/* Write access CPU side + */ +#define BASE_MEM_PROT_CPU_WR ((base_mem_alloc_flags)1 << 1) + +/* Read access GPU side + */ +#define BASE_MEM_PROT_GPU_RD ((base_mem_alloc_flags)1 << 2) + +/* Write access GPU side + */ +#define BASE_MEM_PROT_GPU_WR ((base_mem_alloc_flags)1 << 3) + +/* Execute allowed on the GPU side + */ +#define BASE_MEM_PROT_GPU_EX ((base_mem_alloc_flags)1 << 4) + +/* Will be permanently mapped in kernel space. + * Flag is only allowed on allocations originating from kbase. + */ +#define BASEP_MEM_PERMANENT_KERNEL_MAPPING ((base_mem_alloc_flags)1 << 5) + +/* The allocation will completely reside within the same 4GB chunk in the GPU + * virtual space. + * Since this flag is primarily required only for the TLS memory which will + * not be used to contain executable code and also not used for Tiler heap, + * it can't be used along with BASE_MEM_PROT_GPU_EX and TILER_ALIGN_TOP flags. + */ +#define BASE_MEM_GPU_VA_SAME_4GB_PAGE ((base_mem_alloc_flags)1 << 6) + +/* Userspace is not allowed to free this memory. + * Flag is only allowed on allocations originating from kbase. + */ +#define BASEP_MEM_NO_USER_FREE ((base_mem_alloc_flags)1 << 7) + +/* Grow backing store on GPU Page Fault + */ +#define BASE_MEM_GROW_ON_GPF ((base_mem_alloc_flags)1 << 9) + +/* Page coherence Outer shareable, if available + */ +#define BASE_MEM_COHERENT_SYSTEM ((base_mem_alloc_flags)1 << 10) + +/* Page coherence Inner shareable + */ +#define BASE_MEM_COHERENT_LOCAL ((base_mem_alloc_flags)1 << 11) + +/* IN/OUT */ +/* Should be cached on the CPU, returned if actually cached + */ +#define BASE_MEM_CACHED_CPU ((base_mem_alloc_flags)1 << 12) + +/* IN/OUT */ +/* Must have same VA on both the GPU and the CPU + */ +#define BASE_MEM_SAME_VA ((base_mem_alloc_flags)1 << 13) + +/* OUT */ +/* Must call mmap to acquire a GPU address for the allocation + */ +#define BASE_MEM_NEED_MMAP ((base_mem_alloc_flags)1 << 14) + +/* IN */ +/* Page coherence Outer shareable, required. + */ +#define BASE_MEM_COHERENT_SYSTEM_REQUIRED ((base_mem_alloc_flags)1 << 15) + +/* Protected memory + */ +#define BASE_MEM_PROTECTED ((base_mem_alloc_flags)1 << 16) + +/* Not needed physical memory + */ +#define BASE_MEM_DONT_NEED ((base_mem_alloc_flags)1 << 17) + +/* Must use shared CPU/GPU zone (SAME_VA zone) but doesn't require the + * addresses to be the same + */ +#define BASE_MEM_IMPORT_SHARED ((base_mem_alloc_flags)1 << 18) + +/* Should be uncached on the GPU, will work only for GPUs using AARCH64 mmu + * mode. Some components within the GPU might only be able to access memory + * that is GPU cacheable. Refer to the specific GPU implementation for more + * details. The 3 shareability flags will be ignored for GPU uncached memory. + * If used while importing USER_BUFFER type memory, then the import will fail + * if the memory is not aligned to GPU and CPU cache line width. + */ +#define BASE_MEM_UNCACHED_GPU ((base_mem_alloc_flags)1 << 21) + +/* + * Bits [22:25] for group_id (0~15). + * + * base_mem_group_id_set() should be used to pack a memory group ID into a + * base_mem_alloc_flags value instead of accessing the bits directly. + * base_mem_group_id_get() should be used to extract the memory group ID from + * a base_mem_alloc_flags value. + */ +#define BASEP_MEM_GROUP_ID_SHIFT 22 +#define BASE_MEM_GROUP_ID_MASK ((base_mem_alloc_flags)0xF << BASEP_MEM_GROUP_ID_SHIFT) + +/* Must do CPU cache maintenance when imported memory is mapped/unmapped + * on GPU. Currently applicable to dma-buf type only. + */ +#define BASE_MEM_IMPORT_SYNC_ON_MAP_UNMAP ((base_mem_alloc_flags)1 << 26) + +/* OUT */ +/* Kernel side cache sync ops required */ +#define BASE_MEM_KERNEL_SYNC ((base_mem_alloc_flags)1 << 28) + +/* Number of bits used as flags for base memory management + * + * Must be kept in sync with the base_mem_alloc_flags flags + */ +#define BASE_MEM_FLAGS_NR_BITS 30 + +/* A mask for all output bits, excluding IN/OUT bits. + */ +#define BASE_MEM_FLAGS_OUTPUT_MASK BASE_MEM_NEED_MMAP + +/* A mask for all input bits, including IN/OUT bits. + */ +#define BASE_MEM_FLAGS_INPUT_MASK \ + (((1 << BASE_MEM_FLAGS_NR_BITS) - 1) & ~BASE_MEM_FLAGS_OUTPUT_MASK) + +/* Special base mem handles. + */ +#define BASEP_MEM_INVALID_HANDLE (0ul) +#define BASE_MEM_MMU_DUMP_HANDLE (1ul << LOCAL_PAGE_SHIFT) +#define BASE_MEM_TRACE_BUFFER_HANDLE (2ul << LOCAL_PAGE_SHIFT) +#define BASE_MEM_MAP_TRACKING_HANDLE (3ul << LOCAL_PAGE_SHIFT) +#define BASEP_MEM_WRITE_ALLOC_PAGES_HANDLE (4ul << LOCAL_PAGE_SHIFT) +/* reserved handles ..-47< for future special handles */ +#define BASE_MEM_COOKIE_BASE (64ul << LOCAL_PAGE_SHIFT) +#define BASE_MEM_FIRST_FREE_ADDRESS ((BITS_PER_LONG << LOCAL_PAGE_SHIFT) + BASE_MEM_COOKIE_BASE) + +/* Flags to pass to ::base_context_init. + * Flags can be ORed together to enable multiple things. + * + * These share the same space as BASEP_CONTEXT_FLAG_*, and so must + * not collide with them. + */ +typedef __u32 base_context_create_flags; + +/* Flags for base context */ + +/* No flags set */ +#define BASE_CONTEXT_CREATE_FLAG_NONE ((base_context_create_flags)0) + +/* Base context is embedded in a cctx object (flag used for CINSTR + * software counter macros) + */ +#define BASE_CONTEXT_CCTX_EMBEDDED ((base_context_create_flags)1 << 0) + +/* Base context is a 'System Monitor' context for Hardware counters. + * + * One important side effect of this is that job submission is disabled. + */ +#define BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED ((base_context_create_flags)1 << 1) + +/* Bit-shift used to encode a memory group ID in base_context_create_flags + */ +#define BASEP_CONTEXT_MMU_GROUP_ID_SHIFT (3) + +/* Bitmask used to encode a memory group ID in base_context_create_flags + */ +#define BASEP_CONTEXT_MMU_GROUP_ID_MASK \ + ((base_context_create_flags)0xF << BASEP_CONTEXT_MMU_GROUP_ID_SHIFT) + +/* Bitpattern describing the base_context_create_flags that can be + * passed to the kernel + */ +#define BASEP_CONTEXT_CREATE_KERNEL_FLAGS \ + (BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED | BASEP_CONTEXT_MMU_GROUP_ID_MASK) + +/* Flags for base tracepoint + */ + +/* Enable additional tracepoints for latency measurements (TL_ATOM_READY, + * TL_ATOM_DONE, TL_ATOM_PRIO_CHANGE, TL_ATOM_EVENT_POST) + */ +#define BASE_TLSTREAM_ENABLE_LATENCY_TRACEPOINTS (1 << 0) + +/* Indicate that job dumping is enabled. This could affect certain timers + * to account for the performance impact. + */ +#define BASE_TLSTREAM_JOB_DUMPING_ENABLED (1 << 1) + +#endif /* _UAPI_BASE_COMMON_KERNEL_H_ */ diff --git a/include/uapi/gpu/arm/bifrost/mali_base_kernel.h b/include/uapi/gpu/arm/bifrost/mali_base_kernel.h index f3ffb361ea2c..6adbd81bcc70 100644 --- a/include/uapi/gpu/arm/bifrost/mali_base_kernel.h +++ b/include/uapi/gpu/arm/bifrost/mali_base_kernel.h @@ -27,19 +27,10 @@ #define _UAPI_BASE_KERNEL_H_ #include - -struct base_mem_handle { - struct { - __u64 handle; - } basep; -}; - #include "mali_base_mem_priv.h" #include "gpu/mali_kbase_gpu_id.h" #include "gpu/mali_kbase_gpu_coherency.h" -#define BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS 4 - #define BASE_MAX_COHERENT_GROUPS 16 #if defined(PAGE_MASK) && defined(PAGE_SHIFT) @@ -458,49 +449,6 @@ struct base_jd_debug_copy_buffer { * 16 coherent groups, since core groups are typically 4 cores. */ -/** - * struct mali_base_gpu_core_props - GPU core props info - * - * @product_id: Pro specific value. - * @version_status: Status of the GPU release. No defined values, but starts at - * 0 and increases by one for each release status (alpha, beta, EAC, etc.). - * 4 bit values (0-15). - * @minor_revision: Minor release number of the GPU. "P" part of an "RnPn" - * release number. - * 8 bit values (0-255). - * @major_revision: Major release number of the GPU. "R" part of an "RnPn" - * release number. - * 4 bit values (0-15). - * @padding: padding to allign to 8-byte - * @gpu_freq_khz_max: The maximum GPU frequency. Reported to applications by - * clGetDeviceInfo() - * @log2_program_counter_size: Size of the shader program counter, in bits. - * @texture_features: TEXTURE_FEATURES_x registers, as exposed by the GPU. This - * is a bitpattern where a set bit indicates that the format is supported. - * Before using a texture format, it is recommended that the corresponding - * bit be checked. - * @gpu_available_memory_size: Theoretical maximum memory available to the GPU. - * It is unlikely that a client will be able to allocate all of this memory - * for their own purposes, but this at least provides an upper bound on the - * memory available to the GPU. - * This is required for OpenCL's clGetDeviceInfo() call when - * CL_DEVICE_GLOBAL_MEM_SIZE is requested, for OpenCL GPU devices. The - * client will not be expecting to allocate anywhere near this value. - * @num_exec_engines: The number of execution engines. - */ -struct mali_base_gpu_core_props { - __u32 product_id; - __u16 version_status; - __u16 minor_revision; - __u16 major_revision; - __u16 padding; - __u32 gpu_freq_khz_max; - __u32 log2_program_counter_size; - __u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS]; - __u64 gpu_available_memory_size; - __u8 num_exec_engines; -}; - /* * More information is possible - but associativity and bus width are not * required by upper-level apis. @@ -531,7 +479,7 @@ struct mali_base_gpu_tiler_props { * field. * @impl_tech: 0 = Not specified, 1 = Silicon, 2 = FPGA, * 3 = SW Model/Emulation - * @padding: padding to allign to 8-byte + * @padding: padding to align to 8-byte * @tls_alloc: Number of threads per core that TLS must be * allocated for */ @@ -551,7 +499,7 @@ struct mali_base_gpu_thread_props { * struct mali_base_gpu_coherent_group - descriptor for a coherent group * @core_mask: Core restriction mask required for the group * @num_cores: Number of cores in the group - * @padding: padding to allign to 8-byte + * @padding: padding to align to 8-byte * * \c core_mask exposes all cores in that coherent group, and \c num_cores * provides a cached population-count for that mask. @@ -581,7 +529,7 @@ struct mali_base_gpu_coherent_group { * are in the group[] member. Use num_groups instead. * @coherency: Coherency features of the memory, accessed by gpu_mem_features * methods - * @padding: padding to allign to 8-byte + * @padding: padding to align to 8-byte * @group: Descriptors of coherent groups * * Note that the sizes of the members could be reduced. However, the \c group @@ -599,6 +547,12 @@ struct mali_base_gpu_coherent_group_info { struct mali_base_gpu_coherent_group group[BASE_MAX_COHERENT_GROUPS]; }; +#if MALI_USE_CSF +#include "csf/mali_base_csf_kernel.h" +#else +#include "jm/mali_base_jm_kernel.h" +#endif + /** * struct gpu_raw_gpu_props - A complete description of the GPU's Hardware * Configuration Discovery registers. @@ -696,12 +650,6 @@ struct base_gpu_props { struct mali_base_gpu_coherent_group_info coherency_info; }; -#if MALI_USE_CSF -#include "csf/mali_base_csf_kernel.h" -#else -#include "jm/mali_base_jm_kernel.h" -#endif - #define BASE_MEM_GROUP_ID_GET(flags) \ ((flags & BASE_MEM_GROUP_ID_MASK) >> BASEP_MEM_GROUP_ID_SHIFT) diff --git a/include/uapi/gpu/arm/bifrost/mali_base_mem_priv.h b/include/uapi/gpu/arm/bifrost/mali_base_mem_priv.h index 290662045134..70f5b0977520 100644 --- a/include/uapi/gpu/arm/bifrost/mali_base_mem_priv.h +++ b/include/uapi/gpu/arm/bifrost/mali_base_mem_priv.h @@ -23,8 +23,7 @@ #define _UAPI_BASE_MEM_PRIV_H_ #include - -#include "mali_base_kernel.h" +#include "mali_base_common_kernel.h" #define BASE_SYNCSET_OP_MSYNC (1U << 0) #define BASE_SYNCSET_OP_CSYNC (1U << 1) diff --git a/include/uapi/gpu/arm/bifrost/mali_uk.h b/include/uapi/gpu/arm/bifrost/mali_uk.h deleted file mode 100644 index 78946f675efa..000000000000 --- a/include/uapi/gpu/arm/bifrost/mali_uk.h +++ /dev/null @@ -1,70 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * - * (C) COPYRIGHT 2010, 2012-2015, 2018, 2020-2022 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the - * GNU General Public License version 2 as published by the Free Software - * Foundation, and any use by you of this program is subject to the terms - * of such GNU license. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - */ - -/** - * DOC: Types and definitions that are common across OSs for both the user - * and kernel side of the User-Kernel interface. - */ - -#ifndef _UAPI_UK_H_ -#define _UAPI_UK_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** - * DOC: uk_api User-Kernel Interface API - * - * The User-Kernel Interface abstracts the communication mechanism between the user and kernel-side code of device - * drivers developed as part of the Midgard DDK. Currently that includes the Base driver. - * - * It exposes an OS independent API to user-side code (UKU) which routes functions calls to an OS-independent - * kernel-side API (UKK) via an OS-specific communication mechanism. - * - * This API is internal to the Midgard DDK and is not exposed to any applications. - * - */ - -/** - * enum uk_client_id - These are identifiers for kernel-side drivers - * implementing a UK interface, aka UKK clients. - * @UK_CLIENT_MALI_T600_BASE: Value used to identify the Base driver UK client. - * @UK_CLIENT_COUNT: The number of uk clients supported. This must be - * the last member of the enum - * - * The UK module maps this to an OS specific device name, e.g. "gpu_base" -> "GPU0:". Specify this - * identifier to select a UKK client to the uku_open() function. - * - * When a new UKK client driver is created a new identifier needs to be added to the uk_client_id - * enumeration and the uku_open() implemenation for the various OS ports need to be updated to - * provide a mapping of the identifier to the OS specific device name. - * - */ -enum uk_client_id { - UK_CLIENT_MALI_T600_BASE, - UK_CLIENT_COUNT -}; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* _UAPI_UK_H_ */ diff --git a/include/uapi/linux/rk_hdmirx_config.h b/include/uapi/linux/rk_hdmirx_config.h index 3cf5b0c293b0..3e158f941af2 100644 --- a/include/uapi/linux/rk_hdmirx_config.h +++ b/include/uapi/linux/rk_hdmirx_config.h @@ -44,6 +44,7 @@ enum hdmirx_video_standard { HDMIRX_BT2020_RGB = 6, }; +/* Private v4l2 ioctl */ #define RK_HDMIRX_CMD_GET_FPS \ _IOR('V', BASE_VIDIOC_PRIVATE + 0, int) @@ -77,4 +78,8 @@ enum hdmirx_video_standard { #define RK_HDMIRX_CMD_GET_COLOR_SPACE \ _IOR('V', BASE_VIDIOC_PRIVATE + 10, int) +/* Private v4l2 event */ +#define RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST \ + (V4L2_EVENT_PRIVATE_START + 1) + #endif /* _UAPI_RK_HDMIRX_CONFIG_H */ diff --git a/include/uapi/linux/rkisp2-config.h b/include/uapi/linux/rkisp2-config.h index 20b9174cffc3..fa7e50911a71 100644 --- a/include/uapi/linux/rkisp2-config.h +++ b/include/uapi/linux/rkisp2-config.h @@ -10,7 +10,7 @@ #include #include -#define RKISP_API_VERSION KERNEL_VERSION(1, 9, 0) +#define RKISP_API_VERSION KERNEL_VERSION(2, 0, 0) /****************ISP SUBDEV IOCTL*****************************/ diff --git a/include/uapi/misc/dw_hdcp2.h b/include/uapi/misc/dw_hdcp2.h index d4bbc995aba3..65b58ff67ca3 100644 --- a/include/uapi/misc/dw_hdcp2.h +++ b/include/uapi/misc/dw_hdcp2.h @@ -25,6 +25,7 @@ enum { HL_DRV_NR_WRITE_HPI, RK_DRV_NR_GET_STATUS, + RK_DRV_NR_RESET, HL_DRV_NR_MAX }; @@ -124,4 +125,6 @@ struct hl_drv_ioc_status { __u32 booted_status; }; +#define RK_DRV_IOC_RESET _IOR('H', RK_DRV_NR_RESET, __u32) + #endif // _DW_HDCP_HOST_LIB_DRIVER_LINUX_IF_H_ diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 2ee872716c5f..25019893da40 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -19,6 +19,9 @@ struct sugov_tunables { struct gov_attr_set attr_set; unsigned int rate_limit_us; +#ifdef CONFIG_ARCH_ROCKCHIP + unsigned int target_load; +#endif }; struct sugov_policy { @@ -173,7 +176,11 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, if (next_freq) freq = next_freq; else +#ifdef CONFIG_ARCH_ROCKCHIP + freq = div64_ul((u64)(100 * freq / sg_policy->tunables->target_load) * util, max); +#else freq = map_util_freq(util, freq, max); +#endif if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update) return sg_policy->next_freq; @@ -620,8 +627,39 @@ rate_limit_us_store(struct gov_attr_set *attr_set, const char *buf, size_t count static struct governor_attr rate_limit_us = __ATTR_RW(rate_limit_us); +#ifdef CONFIG_ARCH_ROCKCHIP +static ssize_t target_load_show(struct gov_attr_set *attr_set, char *buf) +{ + struct sugov_tunables *tunables = to_sugov_tunables(attr_set); + + return sprintf(buf, "%u\n", tunables->target_load); +} + +static ssize_t +target_load_store(struct gov_attr_set *attr_set, const char *buf, size_t count) +{ + struct sugov_tunables *tunables = to_sugov_tunables(attr_set); + unsigned int target_load; + + if (kstrtouint(buf, 10, &target_load)) + return -EINVAL; + + if (!target_load || (target_load > 100)) + return -EINVAL; + + tunables->target_load = target_load; + + return count; +} + +static struct governor_attr target_load = __ATTR_RW(target_load); +#endif + static struct attribute *sugov_attrs[] = { &rate_limit_us.attr, +#ifdef CONFIG_ARCH_ROCKCHIP + &target_load.attr, +#endif NULL }; ATTRIBUTE_GROUPS(sugov); @@ -785,6 +823,9 @@ static int sugov_init(struct cpufreq_policy *policy) } tunables->rate_limit_us = cpufreq_policy_transition_delay_us(policy); +#ifdef CONFIG_ARCH_ROCKCHIP + tunables->target_load = 80; +#endif policy->governor_data = sg_policy; sg_policy->tunables = tunables; diff --git a/mm/cma.c b/mm/cma.c index 53f77bcd5496..769f4ebb7217 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -638,6 +638,26 @@ bool cma_release(struct cma *cma, const struct page *pages, unsigned int count) } EXPORT_SYMBOL_GPL(cma_release); +#ifdef CONFIG_NO_GKI +unsigned long cma_used_pages(void) +{ + struct cma *cma; + unsigned long used; + unsigned long val = 0; + int i; + + for (i = 0; i < cma_area_count; i++) { + cma = &cma_areas[i]; + mutex_lock(&cma->lock); + used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma)); + mutex_unlock(&cma->lock); + val += used << cma->order_per_bit; + } + return val; +} +EXPORT_SYMBOL_GPL(cma_used_pages); +#endif + int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data) { int i; diff --git a/mm/page_isolation.c b/mm/page_isolation.c index b391091bfd5c..48ff14250004 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -279,6 +279,10 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn, else break; } +#ifdef CONFIG_NO_GKI + if (pfn < end_pfn) + dump_page_owner(page); +#endif return pfn; } diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index c9314c9e87f1..c54dce1e6aef 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -18,6 +18,7 @@ #include #include +#include "pcm_local.h" struct dmaengine_pcm_runtime_data { struct dma_chan *dma_chan; @@ -133,11 +134,20 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data); static void dmaengine_pcm_dma_complete(void *arg) { struct snd_pcm_substream *substream = arg; - struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + struct dmaengine_pcm_runtime_data *prtd; + + snd_pcm_stream_lock_irq(substream); + if (PCM_RUNTIME_CHECK(substream)) { + snd_pcm_stream_unlock_irq(substream); + return; + } + + prtd = substream_to_prtd(substream); prtd->pos += snd_pcm_lib_period_bytes(substream); if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream)) prtd->pos = 0; + snd_pcm_stream_unlock_irq(substream); snd_pcm_period_elapsed(substream); } diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index 4ed82d328704..b6a25fa79885 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -26,15 +26,11 @@ #include #include "rk817_codec.h" -static int dbg_enable; -module_param_named(dbg_level, dbg_enable, int, 0644); - -#define DBG(args...) \ - do { \ - if (dbg_enable) { \ - pr_info(args); \ - } \ - } while (0) +#ifdef CONFIG_SND_DEBUG +#define DBG(args...) pr_info(args) +#else +#define DBG(args...) +#endif /* For route */ #define RK817_CODEC_PLAYBACK 1 @@ -92,6 +88,7 @@ struct rk817_codec_priv { struct gpio_desc *hp_ctl_gpio; int spk_mute_delay; int hp_mute_delay; + int chip_ver; }; static const struct reg_default rk817_reg_defaults[] = { @@ -157,6 +154,8 @@ static bool rk817_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case RK817_CODEC_DTOP_LPT_SRST: + case RK817_PMIC_CHIP_NAME: + case RK817_PMIC_CHIP_VER: return true; default: return false; @@ -222,6 +221,8 @@ static bool rk817_codec_register(struct device *dev, unsigned int reg) case RK817_CODEC_DI2S_TXCR1: case RK817_CODEC_DI2S_TXCR2: case RK817_CODEC_DI2S_TXCR3_TXCMD: + case RK817_PMIC_CHIP_NAME: + case RK817_PMIC_CHIP_VER: return true; default: return false; @@ -868,8 +869,17 @@ static int rk817_hw_params(struct snd_pcm_substream *substream, unsigned char dtop_digen_sr_lmt0; unsigned char dtop_digen_clke; - DBG("%s : MCLK = %dHz, sample rate = %dHz\n", - __func__, rk817->stereo_sysclk, rate); + DBG("%s : sample rate = %dHz\n", __func__, rate); + + if (rk817->chip_ver <= 0x4) { + DBG("%s: SMIC TudorAG and previous versions\n", __func__); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG0, 0x0c); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0x95); + } else { + DBG("%s: SMIC TudorAG version later\n", __func__); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG0, 0x04); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0xa5); + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dtop_digen_clke = DAC_DIG_CLK_EN; @@ -941,26 +951,27 @@ static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream) struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); DBG("%s %d\n", __func__, mute); + if (mute) { + rk817_codec_ctl_gpio(rk817, CODEC_SET_SPK, 0); + rk817_codec_ctl_gpio(rk817, CODEC_SET_HP, 0); + snd_soc_component_update_bits(component, RK817_CODEC_DDAC_MUTE_MIXCTL, DACMT_ENABLE, DACMT_ENABLE); + snd_soc_component_write(component, RK817_CODEC_ADAC_CFG1, + PWD_DACBIAS_DOWN | PWD_DACD_DOWN | + PWD_DACL_DOWN | PWD_DACR_DOWN); /* Reset DAC DTOP_DIGEN_CLKE for playback stopped */ snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, DAC_DIG_CLK_EN, DAC_DIG_CLK_DIS); snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, DAC_DIG_CLK_EN, DAC_DIG_CLK_EN); - } else { snd_soc_component_update_bits(component, RK817_CODEC_DDAC_MUTE_MIXCTL, DACMT_ENABLE, DACMT_DISABLE); - } - if (mute) { - rk817_codec_ctl_gpio(rk817, CODEC_SET_SPK, 0); - rk817_codec_ctl_gpio(rk817, CODEC_SET_HP, 0); - } else { switch (rk817->playback_path) { case SPK_PATH: case RING_SPK: @@ -1089,6 +1100,8 @@ static int rk817_resume(struct snd_soc_component *component) static int rk817_probe(struct snd_soc_component *component) { struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); + int chip_name = 0; + int chip_ver = 0; DBG("%s\n", __func__); @@ -1102,7 +1115,15 @@ static int rk817_probe(struct snd_soc_component *component) rk817->playback_path = OFF; rk817->capture_path = MIC_OFF; + chip_name = snd_soc_component_read(component, RK817_PMIC_CHIP_NAME); + chip_ver = snd_soc_component_read(component, RK817_PMIC_CHIP_VER); + rk817->chip_ver = (chip_ver & 0x0f); + dev_info(component->dev, "%s: chip_name:0x%x, chip_ver:0x%x\n", __func__, chip_name, chip_ver); + + clk_prepare_enable(rk817->mclk); rk817_reset(component); + clk_disable_unprepare(rk817->mclk); + snd_soc_add_component_controls(component, rk817_snd_path_controls, ARRAY_SIZE(rk817_snd_path_controls)); return 0; @@ -1238,7 +1259,7 @@ static const struct regmap_config rk817_codec_regmap_config = { .reg_bits = 8, .val_bits = 8, .reg_stride = 1, - .max_register = 0x4f, + .max_register = 0xfe, .cache_type = REGCACHE_FLAT, .volatile_reg = rk817_volatile_register, .writeable_reg = rk817_codec_register, diff --git a/sound/soc/codecs/rk817_codec.h b/sound/soc/codecs/rk817_codec.h index a928c323928b..5c4a1bc89d84 100644 --- a/sound/soc/codecs/rk817_codec.h +++ b/sound/soc/codecs/rk817_codec.h @@ -74,6 +74,8 @@ #define RK817_CODEC_DI2S_TXCR1 (RK817_CODEC_BASE + 0x4d) #define RK817_CODEC_DI2S_TXCR2 (RK817_CODEC_BASE + 0x4e) #define RK817_CODEC_DI2S_TXCR3_TXCMD (RK817_CODEC_BASE + 0x4f) +#define RK817_PMIC_CHIP_NAME (RK817_CODEC_BASE + 0xed) +#define RK817_PMIC_CHIP_VER (RK817_CODEC_BASE + 0xee) /* RK817_CODEC_DTOP_DIGEN_CLKE */ #define ADC_DIG_CLK_MASK (0xf << 4) diff --git a/sound/soc/codecs/rv1106_codec.c b/sound/soc/codecs/rv1106_codec.c index e8f98ccfc1a6..d84dbff79fff 100644 --- a/sound/soc/codecs/rv1106_codec.c +++ b/sound/soc/codecs/rv1106_codec.c @@ -1348,7 +1348,7 @@ static int rv1106_codec_adc_enable(struct rv1106_codec_priv *rv1106) return ret; } - /* vendor step 1 */ + /* vendor step 00 */ if (rv1106->soc_id == SOC_RV1103 && rv1106->adc_mode == DIFF_ADCL) { /* The ADCL is differential mode on rv1103 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, @@ -1370,86 +1370,81 @@ static int rv1106_codec_adc_enable(struct rv1106_codec_priv *rv1106) R(lr, ACODEC_ADC_R_SINGLE_END)); } - regmap_update_bits(rv1106->regmap, - ACODEC_ADC_ANA_CTL3, - L(lr, ACODEC_MIC_L_MSK) | - R(lr, ACODEC_MIC_R_MSK), - L(lr, ACODEC_MIC_L_EN) | - R(lr, ACODEC_MIC_R_EN)); - - /* vendor step 2 */ + /* vendor step 01 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, L(lr, ACODEC_ADC_L_MIC_MSK) | R(lr, ACODEC_ADC_R_MIC_MSK), L(lr, ACODEC_ADC_L_MIC_WORK) | R(lr, ACODEC_ADC_R_MIC_WORK)); - /* vendor step 3 */ + /* vendor step 02 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, - ACODEC_ADC_CUR_SRC_MSK, - ACODEC_ADC_CUR_SRC_EN); + ACODEC_ADC_IBIAS_MSK, + ACODEC_ADC_IBIAS_EN); - /* vendor step 4*/ + /* vendor step 03 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, L(lr, ACODEC_ADC_L_REF_VOL_BUF_MSK) | R(lr, ACODEC_ADC_R_REF_VOL_BUF_MSK), L(lr, ACODEC_ADC_L_REF_VOL_BUF_EN) | R(lr, ACODEC_ADC_R_REF_VOL_BUF_EN)); + /* waiting VREF be stable */ + msleep(100); - /* vendor step 5 */ + /* vendor step 04 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, L(lr, ACODEC_MIC_L_MSK) | R(lr, ACODEC_MIC_R_MSK), L(lr, ACODEC_MIC_L_EN) | R(lr, ACODEC_MIC_R_EN)); - /* vendor step 6 */ + /* vendor step 05 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, L(lr, ACODEC_ADC_L_MSK) | R(lr, ACODEC_ADC_R_MSK), L(lr, ACODEC_ADC_L_EN) | R(lr, ACODEC_ADC_R_EN)); - /* vendor step 7 */ + /* vendor step 06 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, L(lr, ACODEC_ADC_L_CLK_MSK) | R(lr, ACODEC_ADC_R_CLK_MSK), L(lr, ACODEC_ADC_L_CLK_WORK) | R(lr, ACODEC_ADC_R_CLK_WORK)); - /* vendor step 8 */ + /* vendor step 07 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, L(lr, ACODEC_ADC_L_WORK) | R(lr, ACODEC_ADC_R_WORK), L(lr, ACODEC_ADC_L_WORK) | R(lr, ACODEC_ADC_R_WORK)); - /* vendor step 9 */ + /* vendor step 08 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, L(lr, ACODEC_ADC_L_SIGNAL_EN) | R(lr, ACODEC_ADC_R_SIGNAL_EN), L(lr, ACODEC_ADC_L_SIGNAL_EN) | R(lr, ACODEC_ADC_R_SIGNAL_EN)); - /* vendor step 10 */ + /* vendor step 09 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, L(lr, ACODEC_ADC_L_ALC_MSK) | R(lr, ACODEC_ADC_R_ALC_MSK), L(lr, ACODEC_ADC_L_ALC_WORK) | R(lr, ACODEC_ADC_R_ALC_WORK)); - /* vendor step 11 */ + /* vendor step 10 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, L(lr, ACODEC_ADC_L_MIC_SIGNAL_MSK) | R(lr, ACODEC_ADC_R_MIC_SIGNAL_MSK), L(lr, ACODEC_ADC_L_MIC_SIGNAL_WORK) | R(lr, ACODEC_ADC_R_MIC_SIGNAL_WORK)); - /* vendor step 12 */ + /* vendor step 11, configure GAIN_MICL/R by user */ + + /* vendor step 12, configure GAIN_ALCL/R by user */ /* vendor step 13 */ - - /* vendor step 14 */ regmap_read(rv1106->regmap, ACODEC_ADC_ANA_CTL1, &agc_func_en); if (agc_func_en & ACODEC_AGC_FUNC_SEL_EN) { regmap_update_bits(rv1106->regmap, @@ -1511,8 +1506,8 @@ static int rv1106_codec_adc_disable(struct rv1106_codec_priv *rv1106) /* vendor step 7 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, - ACODEC_ADC_CUR_SRC_MSK, - ACODEC_ADC_CUR_SRC_DIS); + ACODEC_ADC_IBIAS_MSK, + ACODEC_ADC_IBIAS_DIS); /* vendor step 8 */ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, diff --git a/sound/soc/codecs/rv1106_codec.h b/sound/soc/codecs/rv1106_codec.h index 6311957c16ef..a62fd549f348 100644 --- a/sound/soc/codecs/rv1106_codec.h +++ b/sound/soc/codecs/rv1106_codec.h @@ -265,9 +265,9 @@ #define ACODEC_ADC_REF_VOL_MSK (0x1 << 5) #define ACODEC_ADC_REF_VOL_EN (0x1 << 5) #define ACODEC_ADC_REF_VOL_DIS (0x0 << 5) -#define ACODEC_ADC_CUR_SRC_MSK (0x1 << 4) -#define ACODEC_ADC_CUR_SRC_EN (0x1 << 4) -#define ACODEC_ADC_CUR_SRC_DIS (0x0 << 4) +#define ACODEC_ADC_IBIAS_MSK (0x1 << 4) +#define ACODEC_ADC_IBIAS_EN (0x1 << 4) +#define ACODEC_ADC_IBIAS_DIS (0x0 << 4) #define ACODEC_MICBIAS_SFT 3 #define ACODEC_MICBIAS_MSK (0x1 << 3) #define ACODEC_MICBIAS_WORK (0x1 << 3) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index e192befa027b..19691b6d5a39 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -85,6 +85,7 @@ struct rk_i2s_tdm_dev { struct regmap *grf; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; + struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1]; struct reset_control *tx_reset; struct reset_control *rx_reset; const struct rk_i2s_soc_data *soc_data; @@ -438,9 +439,32 @@ static void rockchip_i2s_tdm_tx_fifo_padding(struct rk_i2s_tdm_dev *i2s_tdm, boo regmap_write(i2s_tdm->regmap, I2S_TXDR, 0x0); } +static void rockchip_i2s_tdm_fifo_xrun_detect(struct rk_i2s_tdm_dev *i2s_tdm, + int stream, bool en) +{ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* clear irq status which was asserted before TXUIE enabled */ + regmap_update_bits(i2s_tdm->regmap, I2S_INTCR, + I2S_INTCR_TXUIC, I2S_INTCR_TXUIC); + regmap_update_bits(i2s_tdm->regmap, I2S_INTCR, + I2S_INTCR_TXUIE_MASK, + I2S_INTCR_TXUIE(en)); + } else { + /* clear irq status which was asserted before RXOIE enabled */ + regmap_update_bits(i2s_tdm->regmap, I2S_INTCR, + I2S_INTCR_RXOIC, I2S_INTCR_RXOIC); + regmap_update_bits(i2s_tdm->regmap, I2S_INTCR, + I2S_INTCR_RXOIE_MASK, + I2S_INTCR_RXOIE(en)); + } +} + static void rockchip_i2s_tdm_dma_ctrl(struct rk_i2s_tdm_dev *i2s_tdm, int stream, bool en) { + if (!en) + rockchip_i2s_tdm_fifo_xrun_detect(i2s_tdm, stream, 0); + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { if (i2s_tdm->quirks & QUIRK_HDMI_PATH) rockchip_i2s_tdm_tx_fifo_padding(i2s_tdm, en); @@ -463,6 +487,9 @@ static void rockchip_i2s_tdm_dma_ctrl(struct rk_i2s_tdm_dev *i2s_tdm, I2S_DMACR_RDE_MASK, I2S_DMACR_RDE(en)); } + + if (en) + rockchip_i2s_tdm_fifo_xrun_detect(i2s_tdm, stream, 1); } static void rockchip_i2s_tdm_xfer_start(struct rk_i2s_tdm_dev *i2s_tdm, @@ -564,6 +591,17 @@ static void rockchip_i2s_tdm_trcm_resume(struct snd_pcm_substream *substream, static void rockchip_i2s_tdm_start(struct rk_i2s_tdm_dev *i2s_tdm, int stream) { + /* + * On HDMI-PATH-ALWAYS-ON situation, we almost keep XFER always on, + * so, for new data start, suggested to STOP-CLEAR-START to make sure + * data aligned. + */ + if ((i2s_tdm->quirks & QUIRK_HDMI_PATH) && + (i2s_tdm->quirks & QUIRK_ALWAYS_ON) && + (stream == SNDRV_PCM_STREAM_PLAYBACK)) { + rockchip_i2s_tdm_xfer_stop(i2s_tdm, stream, true); + } + rockchip_i2s_tdm_dma_ctrl(i2s_tdm, stream, 1); if (i2s_tdm->clk_trcm) @@ -1100,6 +1138,17 @@ static int rockchip_i2s_tdm_params(struct snd_pcm_substream *substream, fmt); } + /* + * Bring back CLK ASAP after cfg changed to make SINK devices active + * on HDMI-PATH-ALWAYS-ON situation, this workaround for some TVs no + * sound issue. at the moment, it's 8K@60Hz display situation. + */ + if ((i2s_tdm->quirks & QUIRK_HDMI_PATH) && + (i2s_tdm->quirks & QUIRK_ALWAYS_ON) && + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) { + rockchip_i2s_tdm_xfer_start(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK); + } + return 0; } @@ -1466,21 +1515,25 @@ static int rockchip_i2s_tdm_startup(struct snd_pcm_substream *substream, { struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); - /* - * Suggested to stop audio source before HDMI configure to make - * sure audio data integrity on HDMI-PATH-ALWAYS-ON situation. - */ - if ((i2s_tdm->quirks & QUIRK_HDMI_PATH) && - (i2s_tdm->quirks & QUIRK_ALWAYS_ON) && - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) { - rockchip_i2s_tdm_xfer_stop(i2s_tdm, substream->stream, true); - } + if (i2s_tdm->substreams[substream->stream]) + return -EBUSY; + + i2s_tdm->substreams[substream->stream] = substream; return 0; } +static void rockchip_i2s_tdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); + + i2s_tdm->substreams[substream->stream] = NULL; +} + static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { .startup = rockchip_i2s_tdm_startup, + .shutdown = rockchip_i2s_tdm_shutdown, .hw_params = rockchip_i2s_tdm_hw_params, .set_sysclk = rockchip_i2s_tdm_set_sysclk, .set_fmt = rockchip_i2s_tdm_set_fmt, @@ -1542,6 +1595,7 @@ static bool rockchip_i2s_tdm_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case I2S_TXFIFOLR: + case I2S_INTCR: case I2S_INTSR: case I2S_CLR: case I2S_TXDR: @@ -1932,6 +1986,34 @@ static const struct snd_dlp_config dconfig = { .get_fifo_count = rockchip_i2s_tdm_get_fifo_count, }; +static irqreturn_t rockchip_i2s_tdm_isr(int irq, void *devid) +{ + struct rk_i2s_tdm_dev *i2s_tdm = (struct rk_i2s_tdm_dev *)devid; + struct snd_pcm_substream *substream; + u32 val; + + regmap_read(i2s_tdm->regmap, I2S_INTSR, &val); + if (val & I2S_INTSR_TXUI_ACT) { + dev_warn_ratelimited(i2s_tdm->dev, "TX FIFO Underrun\n"); + regmap_update_bits(i2s_tdm->regmap, I2S_INTCR, + I2S_INTCR_TXUIC, I2S_INTCR_TXUIC); + substream = i2s_tdm->substreams[SNDRV_PCM_STREAM_PLAYBACK]; + if (substream) + snd_pcm_stop_xrun(substream); + } + + if (val & I2S_INTSR_RXOI_ACT) { + dev_warn_ratelimited(i2s_tdm->dev, "RX FIFO Overrun\n"); + regmap_update_bits(i2s_tdm->regmap, I2S_INTCR, + I2S_INTCR_RXOIC, I2S_INTCR_RXOIC); + substream = i2s_tdm->substreams[SNDRV_PCM_STREAM_CAPTURE]; + if (substream) + snd_pcm_stop_xrun(substream); + } + + return IRQ_HANDLED; +} + static int rockchip_i2s_tdm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -1943,7 +2025,7 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) #ifdef HAVE_SYNC_RESET bool sync; #endif - int ret, val, i; + int ret, val, i, irq; ret = rockchip_i2s_tdm_dai_prepare(pdev, &soc_dai); if (ret) @@ -2076,6 +2158,16 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) if (IS_ERR(i2s_tdm->regmap)) return PTR_ERR(i2s_tdm->regmap); + irq = platform_get_irq_optional(pdev, 0); + if (irq > 0) { + ret = devm_request_irq(&pdev->dev, irq, rockchip_i2s_tdm_isr, + IRQF_SHARED, node->name, i2s_tdm); + if (ret) { + dev_err(&pdev->dev, "failed to request irq %u\n", irq); + return ret; + } + } + i2s_tdm->playback_dma_data.addr = res->start + I2S_TXDR; i2s_tdm->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; i2s_tdm->playback_dma_data.maxburst = MAXBURST_PER_FIFO; diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.h b/sound/soc/rockchip/rockchip_i2s_tdm.h index e46b63031ca0..2a8c48930aa6 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.h +++ b/sound/soc/rockchip/rockchip_i2s_tdm.h @@ -166,8 +166,8 @@ #define I2S_INTCR_RFT(x) (((x) - 1) << I2S_INTCR_RFT_SHIFT) #define I2S_INTCR_RXOIC BIT(18) #define I2S_INTCR_RXOIE_SHIFT 17 -#define I2S_INTCR_RXOIE_DISABLE (0 << I2S_INTCR_RXOIE_SHIFT) -#define I2S_INTCR_RXOIE_ENABLE (1 << I2S_INTCR_RXOIE_SHIFT) +#define I2S_INTCR_RXOIE_MASK (1 << I2S_INTCR_RXOIE_SHIFT) +#define I2S_INTCR_RXOIE(x) ((x) << I2S_INTCR_RXOIE_SHIFT) #define I2S_INTCR_RXFIE_SHIFT 16 #define I2S_INTCR_RXFIE_DISABLE (0 << I2S_INTCR_RXFIE_SHIFT) #define I2S_INTCR_RXFIE_ENABLE (1 << I2S_INTCR_RXFIE_SHIFT) @@ -176,8 +176,8 @@ #define I2S_INTCR_TFT_MASK (0x1f << I2S_INTCR_TFT_SHIFT) #define I2S_INTCR_TXUIC BIT(2) #define I2S_INTCR_TXUIE_SHIFT 1 -#define I2S_INTCR_TXUIE_DISABLE (0 << I2S_INTCR_TXUIE_SHIFT) -#define I2S_INTCR_TXUIE_ENABLE (1 << I2S_INTCR_TXUIE_SHIFT) +#define I2S_INTCR_TXUIE_MASK (1 << I2S_INTCR_TXUIE_SHIFT) +#define I2S_INTCR_TXUIE(x) ((x) << I2S_INTCR_TXUIE_SHIFT) /* * INTSR diff --git a/sound/soc/rockchip/rockchip_vad.c b/sound/soc/rockchip/rockchip_vad.c index d69278aa5317..e37312f80702 100644 --- a/sound/soc/rockchip/rockchip_vad.c +++ b/sound/soc/rockchip/rockchip_vad.c @@ -872,11 +872,20 @@ static int rockchip_vad_enable_cpudai(struct rockchip_vad *vad) return 0; pm_runtime_get_sync(cpu_dai->dev); + if (cpu_dai->driver->ops) { + if (cpu_dai->driver->ops->startup) + ret = cpu_dai->driver->ops->startup(substream, + cpu_dai); - if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) - ret = cpu_dai->driver->ops->trigger(substream, - SNDRV_PCM_TRIGGER_START, - cpu_dai); + if (cpu_dai->driver->ops->prepare) + ret |= cpu_dai->driver->ops->prepare(substream, + cpu_dai); + + if (cpu_dai->driver->ops->trigger) + ret |= cpu_dai->driver->ops->trigger(substream, + SNDRV_PCM_TRIGGER_START, + cpu_dai); + } return ret; }