diff --git a/Documentation/ABI/testing/sysfs-device-mali b/Documentation/ABI/testing/sysfs-device-mali index cd011dae9b50..9a36528d93a9 100644 --- a/Documentation/ABI/testing/sysfs-device-mali +++ b/Documentation/ABI/testing/sysfs-device-mali @@ -62,8 +62,11 @@ What: /sys/class/misc/mali%u/device/idle_hysteresis_time Description: This attribute is available only with mali platform device-driver that supports a CSF GPU. This attribute is - used to set the duration value in milliseconds for the - configuring hysteresis field for determining GPU idle detection. + used to configure the timeout value in microseconds for the + GPU idle handling. If GPU has been idle for this timeout + period, then it is put to sleep for GPUs where sleep feature + is supported or is powered down after suspending command + stream groups. What: /sys/class/misc/mali%u/device/js_ctx_scheduling_mode Description: diff --git a/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt b/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt index 8534c99d9f00..11207b77bfa8 100644 --- a/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt +++ b/Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt @@ -10,6 +10,7 @@ Required properties: - "rockchip,rk3328-dfi" - for RK3328 SoCs. - "rockchip,rk3368-dfi" - for RK3368 SoCs. - "rockchip,rk3399-dfi" - for RK3399 SoCs. + - "rockchip,rk3528-dfi" - for RK3528 SoCs. - "rockchip,rk3562-dfi" - for RK3562 SoCs. - "rockchip,rk3568-dfi" - for RK3568 SoCs. - "rockchip,rv1126-dfi" - for RV1126 SoCs. diff --git a/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt b/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt index ff5c92f570ec..3f1f99c221a4 100644 --- a/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt +++ b/Documentation/devicetree/bindings/devfreq/rockchip_dmc.txt @@ -10,6 +10,7 @@ Required properties: - "rockchip,rk3308-dmc" - for RK3308 SoCs. - "rockchip,rk3328-dmc" - for RK3328 SoCs. - "rockchip,rk3399-dmc" - for RK3399 SoCs. + - "rockchip,rk3528-dmc" - for RK3528 SoCs. - "rockchip,rk3562-dmc" - for RK3562 SoCs. - "rockchip,rk3568-dmc" - for RK3568 SoCs. - "rockchip,rk3588-dmc" - for RK3588 SoCs. diff --git a/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt b/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt index aba0813f1054..c3a5be01c1e4 100644 --- a/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt +++ b/Documentation/devicetree/bindings/mailbox/rockchip-mailbox.txt @@ -20,6 +20,7 @@ Required properties: Optional properties : - wakeup-source: Mailbox irq can be used as a wakeup source. + - rockchip,txpoll-period-ms: TX Done polling interval in milliseconds. Example: -------- diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index 0df43c84020a..c49fa4be649a 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -271,6 +271,11 @@ properties: is supported. For example, this is used in case of SGMII and MAC2MAC connection. + snps,flow-ctrl: + $ref: /schemas/types.yaml#definitions/uint32 + description: + Disable or enable flow control for controller. + mdio: type: object description: diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-secure-otp.yaml b/Documentation/devicetree/bindings/nvmem/rockchip-secure-otp.yaml new file mode 100644 index 000000000000..d78a348e8b13 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/rockchip-secure-otp.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/rockchip-secure-otp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip secure otp device tree bindings + +maintainers: + - Hisping + +allOf: + - $ref: "nvmem.yaml#" + +properties: + compatible: + enum: + - rockchip,secure-otp + + rockchip,otp-size: + description: + size of non-protected oem zone in secure otp, In bytes. + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - rockchip,otp-size + +unevaluatedProperties: false + +examples: + - | + secure_otp: secure-otp { + compatible = "rockchip,secure-otp"; + rockchip,otp-size = <32>; + }; +... diff --git a/arch/arm/boot/dts/rv1103-evb-v10.dtsi b/arch/arm/boot/dts/rv1103-evb-v10.dtsi index 45200019a59d..8cd27939ff21 100644 --- a/arch/arm/boot/dts/rv1103-evb-v10.dtsi +++ b/arch/arm/boot/dts/rv1103-evb-v10.dtsi @@ -81,8 +81,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts b/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts index c96f6f4f43cb..ee95a1819db7 100644 --- a/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts +++ b/arch/arm/boot/dts/rv1103g-battery-ipc-v10.dts @@ -286,8 +286,9 @@ cap-sdio-irq; keep-power-in-suspend; non-removable; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc1m1_cmd &sdmmc1m1_clk &sdmmc1m1_bus4>; + pinctrl-1 = <&sdmmc1m1_idle_pins>; no-prescan-powerup; post-power-on-delay-ms = <0>; status = "okay"; diff --git a/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts b/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts index c5468385309b..e8a6f79d9bc7 100644 --- a/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts +++ b/arch/arm/boot/dts/rv1103g-battery-ipc-v11.dts @@ -287,8 +287,9 @@ cap-sdio-irq; keep-power-in-suspend; non-removable; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc1m1_cmd &sdmmc1m1_clk &sdmmc1m1_bus4>; + pinctrl-1 = <&sdmmc1m1_idle_pins>; no-prescan-powerup; post-power-on-delay-ms = <0>; status = "okay"; diff --git a/arch/arm/boot/dts/rv1103g-evb-v11.dts b/arch/arm/boot/dts/rv1103g-evb-v11.dts index 3d56f7515b47..a2c86c5d8b6f 100644 --- a/arch/arm/boot/dts/rv1103g-evb-v11.dts +++ b/arch/arm/boot/dts/rv1103g-evb-v11.dts @@ -81,3 +81,9 @@ &usbdrd_dwc3 { dr_mode = "host"; }; + +&vdd_arm { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1000000>; + regulator-init-microvolt = <900000>; +}; diff --git a/arch/arm/boot/dts/rv1106-ipc.dtsi b/arch/arm/boot/dts/rv1106-ipc.dtsi index d4ac29301f1f..f1f3cf6eb8b4 100644 --- a/arch/arm/boot/dts/rv1106-ipc.dtsi +++ b/arch/arm/boot/dts/rv1106-ipc.dtsi @@ -288,8 +288,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106-pinctrl.dtsi b/arch/arm/boot/dts/rv1106-pinctrl.dtsi index f0c4cf3b8ad0..a7bd376a2a65 100644 --- a/arch/arm/boot/dts/rv1106-pinctrl.dtsi +++ b/arch/arm/boot/dts/rv1106-pinctrl.dtsi @@ -731,6 +731,17 @@ /* sdmmc0_det */ <3 RK_PA1 1 &pcfg_pull_up>; }; + + /omit-if-no-ref/ + sdmmc0_idle_pins: sdmmc0-idle-pins { + rockchip,pins = + <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>, + <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>; + }; }; sdmmc1 { @@ -768,6 +779,17 @@ <2 RK_PA3 1 &pcfg_pull_up_drv_level_2>; }; + /omit-if-no-ref/ + sdmmc1m0_idle_pins: sdmmc1m0-idle-pins { + rockchip,pins = + <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, + <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>; + }; + /omit-if-no-ref/ sdmmc1m1_bus4: sdmmc1m1-bus4 { rockchip,pins = @@ -794,6 +816,17 @@ /* sdmmc1_cmd_m1 */ <1 RK_PC3 5 &pcfg_pull_up_drv_level_2>; }; + + /omit-if-no-ref/ + sdmmc1m1_idle_pins: sdmmc1m1-idle-pins { + rockchip,pins = + <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>; + }; }; spi0 { diff --git a/arch/arm/boot/dts/rv1106.dtsi b/arch/arm/boot/dts/rv1106.dtsi index 0ca00e89ffa3..f877096e8060 100644 --- a/arch/arm/boot/dts/rv1106.dtsi +++ b/arch/arm/boot/dts/rv1106.dtsi @@ -119,51 +119,54 @@ rockchip,pvtpll-min-rate = <1104000>; rockchip,pvtpll-volt-step = <12500>; rockchip,grf = <&grf>; + rockchip,temp-hysteresis = <5000>; + rockchip,low-temp = <10000>; + rockchip,low-temp-min-volt = <900000>; opp-408000000 { opp-hz = /bits/ 64 <408000000>; - opp-microvolt = <850000 850000 1050000>; + opp-microvolt = <850000 850000 1000000>; clock-latency-ns = <40000>; }; opp-600000000 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <850000 850000 1050000>; + opp-microvolt = <850000 850000 1000000>; clock-latency-ns = <40000>; }; opp-816000000 { opp-hz = /bits/ 64 <816000000>; - opp-microvolt = <850000 850000 1050000>; + opp-microvolt = <850000 850000 1000000>; clock-latency-ns = <40000>; opp-suspend; }; opp-1104000000 { opp-hz = /bits/ 64 <1104000000>; - opp-microvolt = <850000 850000 1050000>; + opp-microvolt = <850000 850000 1000000>; clock-latency-ns = <40000>; }; opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <850000 850000 1050000>; + opp-microvolt = <850000 850000 1000000>; clock-latency-ns = <40000>; }; opp-1296000000 { opp-hz = /bits/ 64 <1296000000>; - opp-microvolt = <875000 850000 1050000>; + opp-microvolt = <875000 850000 1000000>; clock-latency-ns = <40000>; }; opp-1416000000 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <925000 850000 1050000>; + opp-microvolt = <925000 850000 1000000>; clock-latency-ns = <40000>; }; opp-1512000000 { opp-hz = /bits/ 64 <1512000000>; - opp-microvolt = <975000 850000 1050000>; + opp-microvolt = <975000 850000 1000000>; clock-latency-ns = <40000>; }; opp-1608000000 { opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <1012500 850000 1050000>; + opp-microvolt = <1000000 850000 1000000>; clock-latency-ns = <40000>; }; }; @@ -228,6 +231,14 @@ status = "disabled"; }; + firmware { + optee: optee { + compatible = "linaro,optee-tz"; + method = "smc"; + status = "disabled"; + }; + }; + mpp_srv: mpp-srv { compatible = "rockchip,mpp-service"; rockchip,taskqueue-count = <2>; @@ -239,6 +250,11 @@ status = "disabled"; }; + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + rkcif_dvp: rkcif-dvp { compatible = "rockchip,rkcif-dvp"; rockchip,hw = <&rkcif>; @@ -337,7 +353,8 @@ timer { compatible = "arm,armv7-timer"; - interrupts = ; + interrupts = , + ; clock-frequency = <24000000>; }; @@ -1248,7 +1265,7 @@ snps,tso; tx-dma-size = <256>; - rx-dma-size = <16>; + rx-dma-size = <128>; snps,axi-config = <&stmmac_axi_setup>; snps,mtl-rx-config = <&mtl_rx_setup>; @@ -1258,6 +1275,9 @@ clock_in_out = "input"; phy-handle = <&rmii_phy>; + /* FLOW_OFF: 0, FLOW_RX: 1, FLOW_TX: 2, FLOW_AUTO: 3 */ + snps,flow-ctrl = <0>; + nvmem-cells = <&macphy_bgs>; nvmem-cell-names = "bgs"; status = "disabled"; @@ -1274,6 +1294,7 @@ phy-is-integrated; nvmem-cells = <&macphy_txlevel>; nvmem-cell-names = "txlevel"; + bgs,increment = <2>; }; }; diff --git a/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts b/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts index 3452c2c20dd3..d7c76712c194 100644 --- a/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts +++ b/arch/arm/boot/dts/rv1106g-38x38-ipc-v10-spi-nand.dts @@ -61,8 +61,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts b/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts index 7997f8f1f543..2451564f35b3 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v10-dual-cam.dts @@ -150,8 +150,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v10.dts b/arch/arm/boot/dts/rv1106g-evb1-v10.dts index 9966352dbaa9..8f820d60fecc 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v10.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v10.dts @@ -150,8 +150,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts b/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts index cb295ebd6a5d..0368b0f6575d 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v11-cvr-dual-cam.dts @@ -140,8 +140,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; diff --git a/arch/arm/boot/dts/rv1106g-evb1-v11.dts b/arch/arm/boot/dts/rv1106g-evb1-v11.dts index da292aa7b804..00faf0588980 100644 --- a/arch/arm/boot/dts/rv1106g-evb1-v11.dts +++ b/arch/arm/boot/dts/rv1106g-evb1-v11.dts @@ -37,3 +37,9 @@ &usbdrd_dwc3 { dr_mode = "peripheral"; }; + +&vdd_arm { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1000000>; + regulator-init-microvolt = <900000>; +}; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts b/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts index 06cc1407fb6c..e748e20ca5aa 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v10-dual-camera.dts @@ -393,8 +393,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v10.dts b/arch/arm/boot/dts/rv1106g-evb2-v10.dts index 9efd2a1f1a1b..90274546bad1 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v10.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v10.dts @@ -263,8 +263,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts b/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts index 50b7378a7b72..653c4eb44af7 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v11-emmc.dts @@ -45,6 +45,11 @@ pinctrl-0 = <&sdmmc_pwren>; }; + wireless_wlan: wireless-wlan { + compatible = "wlan-platdata"; + WIFI,host_wake_irq = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; }; &csi2_dphy_hw { @@ -258,8 +263,9 @@ cap-mmc-highspeed; cap-sd-highspeed; disable-wp; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; vmmc-supply = <&vcc3v3_sd>; status = "okay"; }; diff --git a/arch/arm/boot/dts/rv1126-pinctrl.dtsi b/arch/arm/boot/dts/rv1126-pinctrl.dtsi index b6ad54a71a5d..47c8874d8935 100644 --- a/arch/arm/boot/dts/rv1126-pinctrl.dtsi +++ b/arch/arm/boot/dts/rv1126-pinctrl.dtsi @@ -1220,6 +1220,17 @@ /* sdmmc0_pwr */ <0 RK_PC0 1 &pcfg_pull_none>; }; + + /omit-if-no-ref/ + sdmmc0_idle_pins: sdmmc0-idle-pins { + rockchip,pins = + <1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>, + <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>; + }; }; spi0 { /omit-if-no-ref/ diff --git a/arch/arm/boot/dts/rv1126.dtsi b/arch/arm/boot/dts/rv1126.dtsi index 4705beded656..1c64f55d9929 100644 --- a/arch/arm/boot/dts/rv1126.dtsi +++ b/arch/arm/boot/dts/rv1126.dtsi @@ -2371,8 +2371,9 @@ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; max-frequency = <200000000>; - pinctrl-names = "default"; + pinctrl-names = "normal", "idle"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>; + pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>; status = "disabled"; }; diff --git a/arch/arm/configs/rv1106-nand.config b/arch/arm/configs/rv1106-nand.config new file mode 100644 index 000000000000..00af96cd9eb9 --- /dev/null +++ b/arch/arm/configs/rv1106-nand.config @@ -0,0 +1,122 @@ +CONFIG_CRC16=y +CONFIG_CRYPTO=y +CONFIG_MTD_SPI_NAND=y +CONFIG_MTD_UBI=y +# CONFIG_ARM_CRYPTO is not set +# CONFIG_CRYPTO_842 is not set +CONFIG_CRYPTO_ACOMP2=y +# 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 is not set +# 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=y +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set +# CONFIG_CRYPTO_DEV_CCREE is not set +# CONFIG_CRYPTO_DEV_ROCKCHIP is not set +# CONFIG_CRYPTO_DEV_SAFEXCEL 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_INFO=y +# CONFIG_CRYPTO_HMAC is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_LZO=y +# 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_LIB_MEMNEQ=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MTD_NAND_BBT_USING_FLASH=y +CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_SGL_ALLOC=y +# CONFIG_UBIFS_ATIME_SUPPORT is not set +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +# CONFIG_UBIFS_FS_AUTHENTICATION is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_SECURITY=y +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_ZSTD is not set diff --git a/arch/arm/configs/rv1106-pm.config b/arch/arm/configs/rv1106-pm.config new file mode 100644 index 000000000000..5ab8a461f11f --- /dev/null +++ b/arch/arm/configs/rv1106-pm.config @@ -0,0 +1,5 @@ +CONFIG_PM_DEBUG=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_DEBUG=y +CONFIG_PM_WAKELOCKS=y +CONFIG_SUSPEND=y diff --git a/arch/arm/configs/rv1106-rndis.config b/arch/arm/configs/rv1106-rndis.config index 098ef60900f1..7d2be8b38ccb 100644 --- a/arch/arm/configs/rv1106-rndis.config +++ b/arch/arm/configs/rv1106-rndis.config @@ -15,12 +15,11 @@ CONFIG_USB_SUPPORT=y # CONFIG_I2C_ROBOTFUZZ_OSIF is not set # CONFIG_I2C_TINY_USB is not set # CONFIG_LTE_GDM724X is not set +# CONFIG_MDIO_MVUSB is not set # CONFIG_MEDIA_USB_SUPPORT is not set # CONFIG_MFD_DLN2 is not set # CONFIG_MFD_VIPERBOARD is not set # CONFIG_MISC_RTSX_USB is not set -# CONFIG_MMC_USHC is not set -# CONFIG_MMC_VUB300 is not set # CONFIG_MOST is not set # CONFIG_NOP_USB_XCEIV is not set # CONFIG_NVME_TARGET is not set @@ -62,7 +61,7 @@ CONFIG_USB_CONFIGFS_F_FS=y # CONFIG_USB_CONFIGFS_F_UAC1 is not set # CONFIG_USB_CONFIGFS_F_UAC1_LEGACY is not set # CONFIG_USB_CONFIGFS_F_UAC2 is not set -# CONFIG_USB_CONFIGFS_F_UVC is not set +CONFIG_USB_CONFIGFS_F_UVC=y # CONFIG_USB_CONFIGFS_MASS_STORAGE is not set # CONFIG_USB_CONFIGFS_NCM is not set # CONFIG_USB_CONFIGFS_OBEX is not set @@ -95,6 +94,7 @@ CONFIG_USB_DWC3_OF_SIMPLE=m # CONFIG_USB_FUSB300 is not set CONFIG_USB_F_FS=m CONFIG_USB_F_RNDIS=m +CONFIG_USB_F_UVC=m CONFIG_USB_GADGET=m # CONFIG_USB_GADGETFS is not set # CONFIG_USB_GADGET_DEBUG is not set @@ -129,8 +129,6 @@ CONFIG_USB_LIBCOMPOSITE=m # CONFIG_USB_LINK_LAYER_TEST is not set # CONFIG_USB_M66592 is not set # CONFIG_USB_MASS_STORAGE is not set -# CONFIG_USB_MAX3420_UDC is not set -# CONFIG_USB_MAX3421_HCD is not set # CONFIG_USB_MDC800 is not set # CONFIG_USB_MIDI_GADGET is not set # CONFIG_USB_MON is not set diff --git a/arch/arm/configs/rv1106-smart-door.config b/arch/arm/configs/rv1106-smart-door.config index a6e88490018c..7bc919762e56 100644 --- a/arch/arm/configs/rv1106-smart-door.config +++ b/arch/arm/configs/rv1106-smart-door.config @@ -1,4 +1,5 @@ CONFIG_CONFIGFS_FS=m +CONFIG_CRC16=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_CMAC=m @@ -11,6 +12,7 @@ CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_RSA=y CONFIG_CRYPTO_SHA256=m CONFIG_EEPROM_AT24=y +CONFIG_EXT4_FS=m CONFIG_EXTCON=m CONFIG_JFFS2_FS=y CONFIG_KEYS=y @@ -138,6 +140,10 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_EEPROM_93XX46 is not set # CONFIG_EEPROM_AT25 is not set # CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_USE_FOR_EXT2=y # CONFIG_EXTCON_ADC_JACK is not set # CONFIG_EXTCON_GPIO is not set # CONFIG_EXTCON_MAX3355 is not set @@ -146,6 +152,7 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_EXTCON_SM5502 is not set # CONFIG_EXTCON_USB_GPIO is not set # CONFIG_EZX_PCAP is not set +CONFIG_FS_MBCACHE=m # CONFIG_FXOS8700_SPI is not set # CONFIG_GPIO_74X164 is not set # CONFIG_GPIO_MAX3191X is not set @@ -158,6 +165,8 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_INFINEON_DHD is not set # CONFIG_INV_ICM42600_SPI is not set # CONFIG_INV_MPU6050_SPI is not set +CONFIG_JBD2=m +# CONFIG_JBD2_DEBUG is not set # CONFIG_JFFS2_CMODE_FAVOURLZO is not set # CONFIG_JFFS2_CMODE_NONE is not set CONFIG_JFFS2_CMODE_PRIORITY=y diff --git a/arch/arm/configs/rv1106-tee.config b/arch/arm/configs/rv1106-tee.config new file mode 100644 index 000000000000..430a40d2ba4e --- /dev/null +++ b/arch/arm/configs/rv1106-tee.config @@ -0,0 +1,13 @@ +CONFIG_ARM_PSCI=y +# CONFIG_FIQ_DEBUGGER_FIQ_GLUE is not set +CONFIG_FIQ_DEBUGGER_TRUST_ZONE=y +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_HIGHBANK_CPUIDLE is not set +# CONFIG_ARM_PSCI_CPUIDLE is not set +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SCMI_PROTOCOL is not set +CONFIG_ARM_SMCCC_SOC_ID=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y +CONFIG_SOC_BUS=y diff --git a/arch/arm/configs/rv1106_defconfig b/arch/arm/configs/rv1106_defconfig index 8b85fa1083e5..dfe7208ad22c 100644 --- a/arch/arm/configs/rv1106_defconfig +++ b/arch/arm/configs/rv1106_defconfig @@ -4,8 +4,6 @@ CONFIG_DEFAULT_HOSTNAME="localhost" # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT_VOLUNTARY=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_CC_OPTIMIZE_FOR_SIZE=y # CONFIG_BUG is not set @@ -18,7 +16,6 @@ CONFIG_EMBEDDED=y CONFIG_ARCH_ROCKCHIP=y # CONFIG_VDSO is not set CONFIG_VMSPLIT_3G_OPT=y -CONFIG_HZ_300=y CONFIG_THUMB2_KERNEL=y # CONFIG_CPU_SW_DOMAIN_PAN is not set CONFIG_FORCE_MAX_ZONEORDER=9 @@ -180,12 +177,6 @@ CONFIG_DMABUF_RK_HEAPS_DEBUG=y # CONFIG_VIRTIO_MENU is not set # CONFIG_VHOST_MENU is not set CONFIG_STAGING=y -CONFIG_FIQ_DEBUGGER=y -CONFIG_FIQ_DEBUGGER_NO_SLEEP=y -CONFIG_FIQ_DEBUGGER_CONSOLE=y -CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y -CONFIG_RK_CONSOLE_THREAD=y -CONFIG_FIQ_DEBUGGER_FIQ_GLUE=y CONFIG_COMMON_CLK_PROCFS=y # CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set # CONFIG_IOMMU_SUPPORT is not set @@ -193,6 +184,13 @@ CONFIG_CPU_RV1106=y CONFIG_ROCKCHIP_AMP=y CONFIG_ROCKCHIP_CPUINFO=y CONFIG_ROCKCHIP_PVTM=y +CONFIG_ROCKCHIP_SYSTEM_MONITOR=y +CONFIG_FIQ_DEBUGGER=y +CONFIG_FIQ_DEBUGGER_NO_SLEEP=y +CONFIG_FIQ_DEBUGGER_CONSOLE=y +CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y +CONFIG_RK_CONSOLE_THREAD=y +CONFIG_FIQ_DEBUGGER_FIQ_GLUE=y CONFIG_ROCKCHIP_NPOR_POWERGOOD=y CONFIG_PM_DEVFREQ=y CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 312112782478..f8df2cb4f742 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -10,6 +10,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb-ddr4-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-evb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308b-evb-amic-v10-amp.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308bs-evb-amic-v11.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308bs-evb-ddr3-v20-rk618-rgb2dsi.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308bs-evb-dmic-pdm-v11.dtb @@ -76,6 +77,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-evb2-ddr3-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-evb3-lp4x-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-evb4-ddr4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-iotest-lp3-v10.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-dictpen-test3-v20.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-evb1-lp4x-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-evb1-lp4x-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-evb1-lp4x-v10-linux-amp.dtb @@ -96,6 +98,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-iotest-lp3-v10-dsm.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-rk817-tablet-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-test1-ddr3-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-test2-ddr4-v10.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562j-core-ddr4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-box-demo-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-evb-mipitest-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-evb1-ddr4-v10.dtb @@ -141,6 +144,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-nvr-demo-v10-linux-spi-nand.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-nvr-demo-v12-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-nvr-demo-v12-linux-spi-nand.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-ipc-6x-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-linux-ipc.dtb @@ -162,8 +166,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb6-lp4-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-lp4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-lp4-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-lp4-v10-rk1608-ipc-8x-linux.dtb -dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-h0-v10.dtb -dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-h0-v10-linux.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-lp4-v11-linux-ipc.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-v11.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-v11-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nvr-demo-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nvr-demo-v10-android.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nvr-demo-v10-ipc-4x-linux.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3308b-amp.dtsi b/arch/arm64/boot/dts/rockchip/rk3308b-amp.dtsi index 4dbd89aa3561..72f3029c62c0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308b-amp.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308b-amp.dtsi @@ -20,10 +20,13 @@ ranges; /* remote amp core address */ - amp_shmem_reserved: amp-shmem@2f00000 { - reg = <0x0 0x2f00000 0x0 0x100000>; + amp_reserved: amp@2e00000 { + reg = <0x0 0x2e00000 0x0 0x1200000>; no-map; }; }; }; +&cpu3 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3308b-evb-amic-v10-amp.dts b/arch/arm64/boot/dts/rockchip/rk3308b-evb-amic-v10-amp.dts new file mode 100644 index 000000000000..3120c0a357e3 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3308b-evb-amic-v10-amp.dts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd + */ + +/dts-v1/; + +#include "rk3308b-evb-v10.dtsi" +#include "rk3308b-amp.dtsi" + + +/ { + model = "Rockchip RK3308b evb analog mic v10 board"; + compatible = "rockchip,rk3308b-evb-amic-v10", "rockchip,rk3308"; + + vad_acodec_sound: vad-acodec-sound { + status = "okay"; + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip,rk3308-vad"; + rockchip,codec-hp-det; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&i2s_8ch_2>; + rockchip,codec = <&acodec>, <&vad>; + }; +}; + +&acodec { + rockchip,micbias1; + rockchip,micbias2; + rockchip,en-always-grps = <1 2 3>; + rockchip,adc-grps-route = <1 2 3 0>; +}; + +&acodec_sound { + status = "disabled"; +}; + +&bluetooth_sound { + status = "okay"; +}; + +&i2s_8ch_0 { + status = "okay"; + #sound-dai-cells = <0>; + rockchip,clk-trcm = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s_8ch_0_sclktx + &i2s_8ch_0_lrcktx + &i2s_8ch_0_sdi0 + &i2s_8ch_0_sdo2>; +}; + +&vad { + status = "okay"; + rockchip,audio-src = <&i2s_8ch_2>; + rockchip,det-channel = <0>; + rockchip,buffer-time-ms = <200>; + rockchip,mode = <1>; + #sound-dai-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi b/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi index 548391f6da8b..d9310275cf5f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528-demo.dtsi @@ -40,6 +40,27 @@ }; }; + bt_sco: bt-sco { + status = "disabled"; + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <0>; + }; + + bt_sound: bt-sound { + status = "disabled"; + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion = <0>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "rockchip,bt"; + simple-audio-card,cpu { + sound-dai = <&sai0>; + }; + simple-audio-card,codec { + sound-dai = <&bt_sco>; + }; + }; + dc_12v: dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; @@ -237,6 +258,10 @@ status = "okay"; }; +&dfi { + status = "okay"; +}; + &display_subsystem { status = "okay"; }; @@ -369,6 +394,11 @@ >; }; +&sai0 { + pinctrl-0 = <&i2s0m0_lrck &i2s0m0_sclk &i2s0m0_sdi &i2s0m0_sdo>; + status = "disabled"; +}; + &sai2 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi index d316f3c45751..915a42c20b09 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528-evb.dtsi @@ -39,6 +39,27 @@ }; }; + bt_sco: bt-sco { + status = "disabled"; + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <0>; + }; + + bt_sound: bt-sound { + status = "disabled"; + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion = <0>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "rockchip,bt"; + simple-audio-card,cpu { + sound-dai = <&sai0>; + }; + simple-audio-card,codec { + sound-dai = <&bt_sco>; + }; + }; + dc_12v: dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; @@ -271,6 +292,10 @@ status = "okay"; }; +&dfi { + status = "okay"; +}; + &display_subsystem { status = "okay"; }; @@ -530,6 +555,11 @@ >; }; +&sai0 { + pinctrl-0 = <&i2s0m1_lrck &i2s0m1_sclk &i2s0m1_sdi &i2s0m1_sdo>; + status = "disabled"; +}; + &sai2 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3528-evb3-lp4x-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3528-evb3-lp4x-v10.dtsi index 153f9dc528f1..a427da4e2376 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-evb3-lp4x-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528-evb3-lp4x-v10.dtsi @@ -85,6 +85,11 @@ status = "okay"; }; +&sai0 { + pinctrl-0 = <&i2s0m0_lrck &i2s0m0_sclk &i2s0m0_sdi &i2s0m0_sdo>; + status = "disabled"; +}; + &uart2 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/rockchip/rk3528-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3528-pinctrl.dtsi index 969b8c09ec23..2b8b2d38bf6b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-pinctrl.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528-pinctrl.dtsi @@ -363,60 +363,148 @@ i2s0 { /omit-if-no-ref/ - i2s0m0_pins: i2s0m0-pins { + i2s0m0_lrck: i2s0m0-lrck { rockchip,pins = /* i2s0_lrck_m0 */ - <3 RK_PB6 1 &pcfg_pull_none>, + <3 RK_PB6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s0m0_mclk: i2s0m0-mclk { + rockchip,pins = /* i2s0_mclk_m0 */ - <3 RK_PB4 1 &pcfg_pull_none>, + <3 RK_PB4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s0m0_sclk: i2s0m0-sclk { + rockchip,pins = /* i2s0_sclk_m0 */ - <3 RK_PB5 1 &pcfg_pull_none>, - /* i2s0_sdi_m0 */ - <3 RK_PB7 1 &pcfg_pull_none>, - /* i2s0_sdo_m0 */ + <3 RK_PB5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s0m0_sdi: i2s0m0-sdi { + rockchip,pins = + /* i2s0m0_sdi */ + <3 RK_PB7 1 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + i2s0m0_sdo: i2s0m0-sdo { + rockchip,pins = + /* i2s0m0_sdo */ <3 RK_PC0 1 &pcfg_pull_none>; }; /omit-if-no-ref/ - i2s0m1_pins: i2s0m1-pins { + i2s0m1_lrck: i2s0m1-lrck { rockchip,pins = /* i2s0_lrck_m1 */ - <1 RK_PB6 1 &pcfg_pull_none>, + <1 RK_PB6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s0m1_mclk: i2s0m1-mclk { + rockchip,pins = /* i2s0_mclk_m1 */ - <1 RK_PB4 1 &pcfg_pull_none>, + <1 RK_PB4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s0m1_sclk: i2s0m1-sclk { + rockchip,pins = /* i2s0_sclk_m1 */ - <1 RK_PB5 1 &pcfg_pull_none>, - /* i2s0_sdi_m1 */ - <1 RK_PB7 1 &pcfg_pull_none>, - /* i2s0_sdo_m1 */ + <1 RK_PB5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s0m1_sdi: i2s0m1-sdi { + rockchip,pins = + /* i2s0m1_sdi */ + <1 RK_PB7 1 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + i2s0m1_sdo: i2s0m1-sdo { + rockchip,pins = + /* i2s0m1_sdo */ <1 RK_PC0 1 &pcfg_pull_none>; }; }; i2s1 { /omit-if-no-ref/ - i2s1_pins: i2s1-pins { + i2s1_lrck: i2s1-lrck { rockchip,pins = /* i2s1_lrck */ - <4 RK_PA6 1 &pcfg_pull_none>, + <4 RK_PA6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_mclk: i2s1-mclk { + rockchip,pins = /* i2s1_mclk */ - <4 RK_PA4 1 &pcfg_pull_none>, + <4 RK_PA4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sclk: i2s1-sclk { + rockchip,pins = /* i2s1_sclk */ - <4 RK_PA5 1 &pcfg_pull_none>, + <4 RK_PA5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdi0: i2s1-sdi0 { + rockchip,pins = /* i2s1_sdi0 */ - <4 RK_PB4 1 &pcfg_pull_none>, + <4 RK_PB4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdi1: i2s1-sdi1 { + rockchip,pins = /* i2s1_sdi1 */ - <4 RK_PB3 1 &pcfg_pull_none>, + <4 RK_PB3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdi2: i2s1-sdi2 { + rockchip,pins = /* i2s1_sdi2 */ - <4 RK_PA3 1 &pcfg_pull_none>, + <4 RK_PA3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdi3: i2s1-sdi3 { + rockchip,pins = /* i2s1_sdi3 */ - <4 RK_PA2 1 &pcfg_pull_none>, + <4 RK_PA2 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdo0: i2s1-sdo0 { + rockchip,pins = /* i2s1_sdo0 */ - <4 RK_PA7 1 &pcfg_pull_none>, + <4 RK_PA7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdo1: i2s1-sdo1 { + rockchip,pins = /* i2s1_sdo1 */ - <4 RK_PB0 1 &pcfg_pull_none>, + <4 RK_PB0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdo2: i2s1-sdo2 { + rockchip,pins = /* i2s1_sdo2 */ - <4 RK_PB1 1 &pcfg_pull_none>, + <4 RK_PB1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1_sdo3: i2s1-sdo3 { + rockchip,pins = /* i2s1_sdo3 */ <4 RK_PB2 1 &pcfg_pull_none>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3528.dtsi b/arch/arm64/boot/dts/rockchip/rk3528.dtsi index 545e21f74327..c3edb864822e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528.dtsi @@ -192,8 +192,9 @@ compatible = "operating-points-v2"; opp-shared; - nvmem-cells = <&cpu_leakage>, <&cpu_opp_info>; - nvmem-cell-names = "leakage", "opp-info"; + mbist-vmin = <825000 925000 975000>; + nvmem-cells = <&cpu_leakage>, <&cpu_opp_info>, <&cpu_mbist_vmin>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin"; rockchip,video-4k-freq = <1200000>; rockchip,pvtm-voltage-sel = < @@ -223,46 +224,46 @@ opp-408000000 { opp-hz = /bits/ 64 <408000000>; opp-microvolt = <825000 825000 1100000>; - opp-microvolt-L0 = <862500 862500 1100000>; - opp-microvolt-L1 = <862500 862500 1100000>; - opp-microvolt-L2 = <862500 862500 1100000>; - opp-microvolt-L3 = <862500 862500 1100000>; - opp-microvolt-L4 = <862500 862500 1100000>; - opp-microvolt-L5 = <837500 837500 1100000>; + opp-microvolt-L0 = <875000 875000 1100000>; + opp-microvolt-L1 = <875000 875000 1100000>; + opp-microvolt-L2 = <875000 875000 1100000>; + opp-microvolt-L3 = <875000 875000 1100000>; + opp-microvolt-L4 = <875000 875000 1100000>; + opp-microvolt-L5 = <850000 850000 1100000>; clock-latency-ns = <40000>; opp-suspend; }; opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <825000 825000 1100000>; - opp-microvolt-L0 = <862500 862500 1100000>; - opp-microvolt-L1 = <862500 862500 1100000>; - opp-microvolt-L2 = <862500 862500 1100000>; - opp-microvolt-L3 = <862500 862500 1100000>; - opp-microvolt-L4 = <862500 862500 1100000>; - opp-microvolt-L5 = <837500 837500 1100000>; + opp-microvolt-L0 = <875000 875000 1100000>; + opp-microvolt-L1 = <875000 875000 1100000>; + opp-microvolt-L2 = <875000 875000 1100000>; + opp-microvolt-L3 = <875000 875000 1100000>; + opp-microvolt-L4 = <875000 875000 1100000>; + opp-microvolt-L5 = <850000 850000 1100000>; clock-latency-ns = <40000>; }; opp-816000000 { opp-hz = /bits/ 64 <816000000>; opp-microvolt = <825000 825000 1100000>; - opp-microvolt-L0 = <862500 862500 1100000>; - opp-microvolt-L1 = <862500 862500 1100000>; - opp-microvolt-L2 = <862500 862500 1100000>; - opp-microvolt-L3 = <862500 862500 1100000>; - opp-microvolt-L4 = <862500 862500 1100000>; - opp-microvolt-L5 = <837500 837500 1100000>; + opp-microvolt-L0 = <875000 875000 1100000>; + opp-microvolt-L1 = <875000 875000 1100000>; + opp-microvolt-L2 = <875000 875000 1100000>; + opp-microvolt-L3 = <875000 875000 1100000>; + opp-microvolt-L4 = <875000 875000 1100000>; + opp-microvolt-L5 = <850000 850000 1100000>; clock-latency-ns = <40000>; }; opp-1008000000 { opp-hz = /bits/ 64 <1008000000>; opp-microvolt = <825000 825000 1100000>; - opp-microvolt-L0 = <862500 862500 1100000>; - opp-microvolt-L1 = <862500 862500 1100000>; - opp-microvolt-L2 = <862500 862500 1100000>; - opp-microvolt-L3 = <862500 862500 1100000>; - opp-microvolt-L4 = <862500 862500 1100000>; - opp-microvolt-L5 = <837500 837500 1100000>; + opp-microvolt-L0 = <875000 875000 1100000>; + opp-microvolt-L1 = <875000 875000 1100000>; + opp-microvolt-L2 = <875000 875000 1100000>; + opp-microvolt-L3 = <875000 875000 1100000>; + opp-microvolt-L4 = <875000 875000 1100000>; + opp-microvolt-L5 = <850000 850000 1100000>; clock-latency-ns = <40000>; }; opp-1200000000 { @@ -272,9 +273,9 @@ opp-microvolt-L1 = <887500 887500 1100000>; opp-microvolt-L2 = <875000 875000 1100000>; opp-microvolt-L3 = <875000 875000 1100000>; - opp-microvolt-L4 = <862500 862500 1100000>; - opp-microvolt-L5 = <850000 850000 1100000>; - opp-microvolt-L6 = <837500 837500 1100000>; + opp-microvolt-L4 = <875000 875000 1100000>; + opp-microvolt-L5 = <862500 862500 1100000>; + opp-microvolt-L6 = <850000 850000 1100000>; clock-latency-ns = <40000>; }; opp-1416000000 { @@ -365,17 +366,29 @@ dmc: dmc { compatible = "rockchip,rk3528-dmc"; + interrupts = ; + interrupt-names = "complete"; + devfreq-events = <&dfi>; clocks = <&scmi_clk SCMI_CLK_DDR>; clock-names = "dmc_clk"; operating-points-v2 = <&dmc_opp_table>; + upthreshold = <40>; + downdifferential = <20>; + system-status-level = < + /* system status freq level */ + SYS_STATUS_NORMAL DMC_FREQ_LEVEL_HIGH + >; + auto-min-freq = <324000>; + auto-freq-en = <0>; status = "disabled"; }; dmc_opp_table: dmc-opp-table { compatible = "operating-points-v2"; - nvmem-cells = <&log_leakage>, <&dmc_opp_info>; - nvmem-cell-names = "leakage", "opp-info"; + mbist-vmin = <850000 900000>; + nvmem-cells = <&log_leakage>, <&dmc_opp_info>, <&logic_mbist_vmin>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin"; rockchip,temp-hysteresis = <5000>; rockchip,low-temp = <10000>; @@ -476,6 +489,12 @@ rockchip,temp-offline-cpus = "2-3"; }; + secure_otp: secure-otp { + compatible = "rockchip,secure-otp"; + rockchip,otp-size = <32>; + status = "disabled"; + }; + thermal_zones: thermal-zones { soc_thermal: soc-thermal { polling-delay-passive = <20>; /* milliseconds */ @@ -1027,8 +1046,9 @@ gpu_opp_table: gpu-opp-table { compatible = "operating-points-v2"; - nvmem-cells = <&gpu_leakage>, <&gpu_opp_info>; - nvmem-cell-names = "leakage", "opp-info"; + mbist-vmin = <825000 925000>; + nvmem-cells = <&gpu_leakage>, <&gpu_opp_info>, <&gpu_mbist_vmin>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin"; rockchip,pvtm-voltage-sel = < 0 750 0 @@ -1535,6 +1555,13 @@ }; }; + dfi: dfi@ff930000 { + reg = <0x0 0xff930000 0x0 0x400>; + compatible = "rockchip,rk3528-dfi"; + rockchip,grf = <&grf>; + status = "disabled"; + }; + spi0: spi@ff9c0000 { compatible = "rockchip,rk3066-spi"; reg = <0x0 0xff9c0000 0x0 0x1000>; @@ -1929,7 +1956,10 @@ resets = <&cru SRST_MRESETN_SAI_I2S0>, <&cru SRST_HRESETN_SAI_I2S0>; reset-names = "m", "h"; pinctrl-names = "default"; - pinctrl-0 = <&i2s0m0_pins>; + pinctrl-0 = <&i2s0m0_lrck + &i2s0m0_sclk + &i2s0m0_sdi + &i2s0m0_sdo>; #sound-dai-cells = <0>; status = "disabled"; }; @@ -1959,7 +1989,16 @@ resets = <&cru SRST_MRESETN_SAI_I2S1>, <&cru SRST_HRESETN_SAI_I2S1>; reset-names = "m", "h"; pinctrl-names = "default"; - pinctrl-0 = <&i2s1_pins>; + pinctrl-0 = <&i2s1_sclk + &i2s1_lrck + &i2s1_sdi0 + &i2s1_sdi1 + &i2s1_sdi2 + &i2s1_sdi3 + &i2s1_sdo0 + &i2s1_sdo1 + &i2s1_sdo2 + &i2s1_sdo3>; #sound-dai-cells = <0>; status = "disabled"; }; @@ -2232,6 +2271,18 @@ reg = <0x08 0x1>; bits = <3 3>; }; + cpu_mbist_vmin: cpu-mbist-vmin@9 { + reg = <0x09 0x1>; + bits = <0 3>; + }; + gpu_mbist_vmin: gpu-mbist-vmin@9 { + reg = <0x09 0x1>; + bits = <3 2>; + }; + logic_mbist_vmin: logic-mbist-vmin@9 { + reg = <0x09 0x1>; + bits = <5 2>; + }; otp_id: id@a { reg = <0x0a 0x10>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3562-dictpen-test3-v20.dts b/arch/arm64/boot/dts/rockchip/rk3562-dictpen-test3-v20.dts new file mode 100644 index 000000000000..f2198a8b3e8d --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3562-dictpen-test3-v20.dts @@ -0,0 +1,1243 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ +/dts-v1/; + +#include +#include +#include +#include +#include +#include "dt-bindings/usb/pd.h" +#include "rk3562.dtsi" +#include "rk3562-linux.dtsi" + +/ { + model = "Rockchip RK3562 DICTPEN TEST3 LP4 V20 Board"; + compatible = "rockchip,rk3562-dictpen-test3-v20", "rockchip,rk3562"; + + adc_keys: adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc0 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + vol-up-key { + label = "volume up"; + linux,code = ; + press-threshold-microvolt = <17000>; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm12 0 25000 0>; + brightness-levels = < + 0 20 20 21 21 22 22 23 + 23 24 24 25 25 26 26 27 + 27 28 28 29 29 30 30 31 + 31 32 32 33 33 34 34 35 + 35 36 36 37 37 38 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 50 51 52 53 54 + 55 55 56 57 58 59 60 61 + 62 63 64 64 65 65 66 67 + 68 69 70 71 71 72 73 74 + 75 76 77 78 79 79 80 81 + 82 83 84 85 86 86 87 88 + 89 90 91 92 93 94 94 95 + 96 97 98 99 100 101 101 102 + 103 104 105 106 107 107 108 109 + 110 111 112 113 114 115 115 116 + 117 118 119 120 121 122 123 123 + 124 125 126 127 128 129 130 130 + 131 132 133 134 135 136 136 137 + 138 139 140 141 142 143 143 144 + 145 146 147 147 148 149 150 151 + 152 153 154 155 156 156 157 158 + 159 157 158 159 160 161 162 162 + 163 164 165 166 167 168 169 169 + 170 171 172 173 174 175 175 176 + 177 178 179 180 181 182 182 183 + 184 185 186 187 188 189 190 190 + 191 192 193 194 195 196 197 197 + 198 199 200 201 202 203 204 204 + 205 206 207 208 209 209 210 211 + 212 213 213 214 214 215 215 216 + 216 217 217 218 218 219 219 220 + >; + default-brightness-level = <60>; + }; + + charge-animation { + compatible = "rockchip,uboot-charge"; + rockchip,uboot-charge-on = <0>; + rockchip,android-charge-on = <0>; + rockchip,uboot-low-power-voltage = <2800>; + rockchip,screen-on-voltage = <3000>; + status = "okay"; + }; + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + pinctrl-names = "default"; + pinctrl-0 = <&scan_key>; + + button@0 { + label = "home"; + linux,code = ; + gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + }; + + rk817-sound { + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk817"; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&sai0>; + rockchip,codec = <&rk817_codec>; + }; + + vcc_sys: vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + }; + + vccsys_lcd: vccsys-lcd { + compatible = "regulator-fixed"; + regulator-name = "vccsys_lcd"; + regulator-boot-on; + enable-active-high; + gpio = <&gpio3 RK_PB6 GPIO_ACTIVE_HIGH>; + vin-supply = <&vcc3v3_lcd>; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_enable_l>; + + /* + * 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) + */ + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio2 RK_PA0 GPIO_ACTIVE_HIGH>; + }; + + wireless-wlan { + compatible = "wlan-platdata"; + rockchip,grf = <&sys_grf>; + wifi_chip_type = "ap6203"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_irq>; + WIFI,host_wake_irq = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + + wireless-bluetooth { + compatible = "bluetooth-platdata"; + clocks = <&rk817 1>; + clock-names = "ext_clock"; + uart_rts_gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>; + pinctrl-names = "default", "rts_gpio"; + pinctrl-0 = <&uart1m0_rtsn>; + pinctrl-1 = <&uart1_gpios>; + BT,power_gpio = <&gpio1 RK_PD7 GPIO_ACTIVE_LOW>; + //BT,wake_gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; + //BT,wake_host_irq = <&gpio1 RK_PD6 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu0_opp_table { + opp-408000000 { + /delete-property/ opp-suspend; + }; + + opp-1200000000 { + opp-suspend; + }; + /delete-node/ opp-1608000000; + /delete-node/ opp-1800000000; + /delete-node/ opp-2016000000; +}; + +&csi2_dphy0 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_ucam0: endpoint@1 { + reg = <1>; + remote-endpoint = <&sc031gs_out>; + data-lanes = <1>; + }; + + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidcphy0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi0_csi2_input>; + }; + }; + }; +}; + +&csi2_dphy0_hw { + status = "okay"; +}; + +&dfi { + status = "okay"; +}; + +&display_subsystem { + status = "okay"; +}; + +&dmc { + center-supply = <&vdd_logic>; + status = "okay"; +}; + +&dsi { + status = "okay"; + + panel@0 { + status = "okay"; + compatible = "simple-panel-dsi"; + reg = <0>; + backlight = <&backlight>; + power-supply=<&vccsys_lcd>; + reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; + enable-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>; + + reset-delay-ms = <60>; + enable-delay-ms = <60>; + prepare-delay-ms = <60>; + unprepare-delay-ms = <60>; + disable-delay-ms = <60>; + 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 = [ + 23 00 02 FE 21 + 23 00 02 04 00 + 23 00 02 00 64 + 23 00 02 2A 00 + 23 00 02 26 64 + 23 00 02 54 00 + 23 00 02 50 64 + 23 00 02 7B 00 + 23 00 02 77 64 + 23 00 02 A2 00 + 23 00 02 9D 64 + 23 00 02 C9 00 + 23 00 02 C5 64 + 23 00 02 01 71 + 23 00 02 27 71 + 23 00 02 51 71 + 23 00 02 78 71 + 23 00 02 9E 71 + 23 00 02 C6 71 + 23 00 02 02 89 + 23 00 02 28 89 + 23 00 02 52 89 + 23 00 02 79 89 + 23 00 02 9F 89 + 23 00 02 C7 89 + 23 00 02 03 9E + 23 00 02 29 9E + 23 00 02 53 9E + 23 00 02 7A 9E + 23 00 02 A0 9E + 23 00 02 C8 9E + 23 00 02 09 00 + 23 00 02 05 B0 + 23 00 02 31 00 + 23 00 02 2B B0 + 23 00 02 5A 00 + 23 00 02 55 B0 + 23 00 02 80 00 + 23 00 02 7C B0 + 23 00 02 A7 00 + 23 00 02 A3 B0 + 23 00 02 CE 00 + 23 00 02 CA B0 + 23 00 02 06 C0 + 23 00 02 2D C0 + 23 00 02 56 C0 + 23 00 02 7D C0 + 23 00 02 A4 C0 + 23 00 02 CB C0 + 23 00 02 07 CF + 23 00 02 2F CF + 23 00 02 58 CF + 23 00 02 7E CF + 23 00 02 A5 CF + 23 00 02 CC CF + 23 00 02 08 DD + 23 00 02 30 DD + 23 00 02 59 DD + 23 00 02 7F DD + 23 00 02 A6 DD + 23 00 02 CD DD + 23 00 02 0E 15 + 23 00 02 0A E9 + 23 00 02 36 15 + 23 00 02 32 E9 + 23 00 02 5F 15 + 23 00 02 5B E9 + 23 00 02 85 15 + 23 00 02 81 E9 + 23 00 02 AD 15 + 23 00 02 A9 E9 + 23 00 02 D3 15 + 23 00 02 CF E9 + 23 00 02 0B 14 + 23 00 02 33 14 + 23 00 02 5C 14 + 23 00 02 82 14 + 23 00 02 AA 14 + 23 00 02 D0 14 + 23 00 02 0C 36 + 23 00 02 34 36 + 23 00 02 5D 36 + 23 00 02 83 36 + 23 00 02 AB 36 + 23 00 02 D1 36 + 23 00 02 0D 6B + 23 00 02 35 6B + 23 00 02 5E 6B + 23 00 02 84 6B + 23 00 02 AC 6B + 23 00 02 D2 6B + 23 00 02 13 5A + 23 00 02 0F 94 + 23 00 02 3B 5A + 23 00 02 37 94 + 23 00 02 64 5A + 23 00 02 60 94 + 23 00 02 8A 5A + 23 00 02 86 94 + 23 00 02 B2 5A + 23 00 02 AE 94 + 23 00 02 D8 5A + 23 00 02 D4 94 + 23 00 02 10 D1 + 23 00 02 38 D1 + 23 00 02 61 D1 + 23 00 02 87 D1 + 23 00 02 AF D1 + 23 00 02 D5 D1 + 23 00 02 11 04 + 23 00 02 39 04 + 23 00 02 62 04 + 23 00 02 88 04 + 23 00 02 B0 04 + 23 00 02 D6 04 + 23 00 02 12 05 + 23 00 02 3A 05 + 23 00 02 63 05 + 23 00 02 89 05 + 23 00 02 B1 05 + 23 00 02 D7 05 + 23 00 02 18 AA + 23 00 02 14 36 + 23 00 02 42 AA + 23 00 02 3D 36 + 23 00 02 69 AA + 23 00 02 65 36 + 23 00 02 8F AA + 23 00 02 8B 36 + 23 00 02 B7 AA + 23 00 02 B3 36 + 23 00 02 DD AA + 23 00 02 D9 36 + 23 00 02 15 74 + 23 00 02 3F 74 + 23 00 02 66 74 + 23 00 02 8C 74 + 23 00 02 B4 74 + 23 00 02 DA 74 + 23 00 02 16 9F + 23 00 02 40 9F + 23 00 02 67 9F + 23 00 02 8D 9F + 23 00 02 B5 9F + 23 00 02 DB 9F + 23 00 02 17 DC + 23 00 02 41 DC + 23 00 02 68 DC + 23 00 02 8E DC + 23 00 02 B6 DC + 23 00 02 DC DC + 23 00 02 1D FF + 23 00 02 19 03 + 23 00 02 47 FF + 23 00 02 43 03 + 23 00 02 6E FF + 23 00 02 6A 03 + 23 00 02 94 FF + 23 00 02 90 03 + 23 00 02 BC FF + 23 00 02 B8 03 + 23 00 02 E2 FF + 23 00 02 DE 03 + 23 00 02 1A 35 + 23 00 02 44 35 + 23 00 02 6B 35 + 23 00 02 91 35 + 23 00 02 B9 35 + 23 00 02 DF 35 + 23 00 02 1B 45 + 23 00 02 45 45 + 23 00 02 6C 45 + 23 00 02 92 45 + 23 00 02 BA 45 + 23 00 02 E0 45 + 23 00 02 1C 55 + 23 00 02 46 55 + 23 00 02 6D 55 + 23 00 02 93 55 + 23 00 02 BB 55 + 23 00 02 E1 55 + 23 00 02 22 FF + 23 00 02 1E 68 + 23 00 02 4C FF + 23 00 02 48 68 + 23 00 02 73 FF + 23 00 02 6F 68 + 23 00 02 99 FF + 23 00 02 95 68 + 23 00 02 C1 FF + 23 00 02 BD 68 + 23 00 02 E7 FF + 23 00 02 E3 68 + 23 00 02 1F 7E + 23 00 02 49 7E + 23 00 02 70 7E + 23 00 02 96 7E + 23 00 02 BE 7E + 23 00 02 E4 7E + 23 00 02 20 97 + 23 00 02 4A 97 + 23 00 02 71 97 + 23 00 02 97 97 + 23 00 02 BF 97 + 23 00 02 E5 97 + 23 00 02 21 B5 + 23 00 02 4B B5 + 23 00 02 72 B5 + 23 00 02 98 B5 + 23 00 02 C0 B5 + 23 00 02 E6 B5 + 23 00 02 25 F0 + 23 00 02 23 E8 + 23 00 02 4F F0 + 23 00 02 4D E8 + 23 00 02 76 F0 + 23 00 02 74 E8 + 23 00 02 9C F0 + 23 00 02 9A E8 + 23 00 02 C4 F0 + 23 00 02 C2 E8 + 23 00 02 EA F0 + 23 00 02 E8 E8 + 23 00 02 24 FF + 23 00 02 4E FF + 23 00 02 75 FF + 23 00 02 9B FF + 23 00 02 C3 FF + 23 00 02 E9 FF + 23 00 02 FE 3D + 23 00 02 00 04 + 23 00 02 FE 23 + 23 00 02 08 82 + 23 00 02 0A 00 + 23 00 02 0B 00 + 23 00 02 0C 01 + 23 00 02 16 00 + 23 00 02 18 02 + 23 00 02 1B 04 + 23 00 02 19 04 + 23 00 02 1C 81 + 23 00 02 1F 00 + 23 00 02 20 03 + 23 00 02 23 04 + 23 00 02 21 01 + 23 00 02 54 63 + 23 00 02 55 54 + 23 00 02 6E 45 + 23 00 02 6D 36 + 23 00 02 FE 3D + 23 00 02 55 78 + 23 00 02 FE 20 + 23 00 02 26 30 + 23 00 02 FE 3D + 23 00 02 20 71 + 23 00 02 50 8F + 23 00 02 51 8F + 23 00 02 FE 00 + 23 00 02 35 00 + 05 78 01 11 + 05 1E 01 29 + ]; + + panel-exit-sequence = [ + 05 00 01 28 + 05 00 01 10 + ]; + + disp_timings0: display-timings { + native-mode = <&dsi_timing0>; + + dsi_timing0: timing0 { + clock-frequency = <132000000>; + hactive = <1080>; + vactive = <1920>; + hfront-porch = <15>; + hsync-len = <2>; + hback-porch = <30>; + vfront-porch = <15>; + vsync-len = <2>; + vback-porch = <15>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <1>; + }; + }; + + 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_vp0 { + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu>; + status = "okay"; +}; + +&gpu_opp_table { + /delete-node/ opp-800000000; + /delete-node/ opp-900000000; +}; + +&i2c0 { + status = "okay"; + clock-frequency = <400000>; + + usbc0: fusb302@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + interrupt-parent = <&gpio3>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&usbc0_int>; + vbus-supply = <&otg_switch>; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usbc0_role_sw: endpoint@0 { + remote-endpoint = <&dwc3_role_switch>; + }; + }; + }; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + op-sink-microwatt = <1000000>; + sink-pdos = + ; + source-pdos = + ; + }; + }; + + rk817: pmic@20 { + compatible = "rockchip,rk817"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = <3 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_gpio>, <&rk817_slppin_rst>; + rockchip,system-power-controller; + wakeup-source; + #clock-cells = <1>; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + /* 1: rst regs (default in codes), 0: rst the pmic */ + pmic-reset-func = <0>; + not-save-power-en = <1>; + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&dcdc_boost>; + 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 { + vdda_0v9: vdd_logic: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1350000>; + regulator-init-microvolt = <900000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vdd_npu: vdd_gpu: vdd_cpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <1350000>; + regulator-init-microvolt = <900000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_cpu"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_sys: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = <0x2>; + regulator-name = "vcc3v3_sys"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_ldo1: LDO_REG1 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_ldo1"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v5_dvp: LDO_REG2 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-name = "vcc1v5_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v9_pmu: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda0v9_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vccio_acodec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_acodec"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_lcd: LDO_REG5 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_lcd"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_pmu: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3000000>; + }; + }; + + vcc_ldo7: LDO_REG7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_ldo7"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_dvp: LDO_REG8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc1v8_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc2v8_dvp: LDO_REG9 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "vcc2v8_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + dcdc_boost: BOOST { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-name = "boost"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + otg_switch: OTG_SWITCH { + regulator-name = "otg_switch"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + + battery { + compatible = "rk817,battery"; + ntc_table = <42450 40570 38780 37080 35460 33930 + 32460 31070 29750 28490 27280 26140 + 25050 24010 23020 22070 21170 20310 + 19490 18710 17960 17250 16570 15910 + 15290 14700 14130 13590 13070 12570 + 12090 11640 11200 10780 10380 10000 + 9633 9282 8945 8622 8312 8015 7730 + 7456 7194 6942 6700 6468 6245 6031 + 5826 5628 5438 5255 5080 4911 4749 + 4592 4442 4297 4158 4024 3895 3771 + 3651 3536 3425 3318 3215 3115 3019 + 2927 2837 2751 2668 2588>; + ntc_degree_from = <1 10>; + ocv_table = <3400 3653 3679 3704 3731 3750 + 3771 3788 3806 3828 3855 3890 + 3943 3993 4043 4095 4149 4206 + 4264 4321 4377>; + design_capacity = <1000>; + design_qmax = <1010>; + bat_res = <110>; + sleep_enter_current = <30>; + sleep_exit_current = <30>; + sleep_filter_current = <20>; + power_off_thresd = <3400>; + zero_algorithm_vol = <3000>; + max_soc_offset = <60>; + monitor_sec = <5>; + sample_res = <26>; + virtual_power = <0>; + chrg_finish_cur = <50>; + }; + + charger { + compatible = "rk817,charger"; + min_input_voltage = <4500>; + max_input_current = <2000>; + max_chrg_current = <500>; + max_chrg_voltage = <4400>; + otg5v_suspend_enable = <0>; + chrg_term_mode = <0>; + chrg_finish_cur = <50>; + virtual_power = <0>; + dc_det_adc = <0>; + sample_res = <26>; + extcon = <&u2phy>; + gate_function_disable = <1>; + }; + + rk817_codec: codec { + #sound-dai-cells = <0>; + compatible = "rockchip,rk817-codec"; + clocks = <&mclkout_sai0>; + clock-names = "mclk"; + assigned-clocks = <&mclkout_sai0>; + assigned-clock-rates = <12288000>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0m0_mclk>; + hp-volume = <20>; + spk-volume = <3>; + mic-in-differential; + status = "okay"; + }; + }; +}; + +&i2c2 { + status = "okay"; + clock-frequency = <400000>; + + gt1x: gt1x@14 { + compatible = "goodix,gt1x"; + reg = <0x14>; + pinctrl-names = "default"; + pinctrl-0 = <&touch_gpio>; + goodix,rst-gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; + goodix,irq-gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_LOW>; + + power-supply = <&vcc3v3_lcd>; + }; +}; + +&i2c5 { + status = "okay"; + clock-frequency = <400000>; + + sc031gs: sc031gs@30 { + status = "okay"; + compatible = "smartsens,sc031gs"; + reg = <0x30>; + clocks = <&cru CLK_CAM0_OUT2IO>; + clock-names = "xvclk"; + pinctrl-names = "default"; + pinctrl-0 = <&camm0_clk0_out>; + pwdn-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; + avdd-supply = <&vcc2v8_dvp>; + dovdd-supply = <&vcc1v8_dvp>; + dvdd-supply = <&vcc1v5_dvp>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "default"; + rockchip,camera-module-lens-name = "default"; + + port { + sc031gs_out: endpoint { + remote-endpoint = <&mipi_in_ucam0>; + data-lanes = <1>; + }; + }; + }; +}; + +&jpegd { + status = "okay"; +}; + +&jpegd_mmu { + status = "okay"; +}; + +&mipi0_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi0_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidcphy0_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi0_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi_in0>; + }; + }; + }; +}; + +&mpp_srv { + status = "okay"; +}; + +&npu_opp_table { + /delete-node/ opp-900000000; + /delete-node/ opp-1000000000; +}; + +&pinctrl { + led_control { + scan_key: scan-key { + rockchip,pins = <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + touch { + touch_gpio: touch-gpio { + rockchip,pins = + <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>, + <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sdio-pwrseq { + wifi_enable_l: wifi-enable-l { + rockchip,pins = <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usbc0_int: usbc0-int { + rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wireless-wlan { + wifi_host_wake_irq: wifi-host-wake-irq { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + wireless-bluetooth { + uart1_gpios: uart1-gpios { + rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm12 { + status = "okay"; + pinctrl-0 = <&pwm12m1_pins>; +}; + +&rga2 { + status = "okay"; +}; + +&rga2_mmu { + status = "okay"; +}; + +&rkcif { + status = "okay"; +}; + +&rkcif_mipi_lvds { + status = "okay"; + + port { + cif_mipi_in0: endpoint { + remote-endpoint = <&mipi0_csi2_output>; + }; + }; +}; + +&rkcif_mipi_lvds_sditf { + status = "okay"; + + port { + mipi_lvds_sditf: endpoint { + remote-endpoint = <&isp_vir0>; + }; + }; +}; + +&rkcif_mmu { + status = "okay"; +}; + +&rkisp { + status = "okay"; +}; + +&rkisp_mmu { + status = "okay"; +}; + +&rkisp_vir0 { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + isp_vir0: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi_lvds_sditf>; + }; + }; +}; + +&rknpu { + rknpu-supply = <&vdd_npu>; + status = "okay"; +}; + +&rknpu_mmu { + status = "okay"; +}; + +&rkvdec { + status = "okay"; +}; + +&rkvdec_mmu { + status = "okay"; +}; + +&rockchip_suspend { + status = "okay"; + + rockchip,sleep-mode-config = < + (0 + | RKPM_SLP_ULTRA_MODE + | RKPM_SLP_PMIC_LP + | RKPM_SLP_HW_PLLS_OFF + | RKPM_SLP_PMUALIVE_32K + | RKPM_SLP_OSC_DIS + | RKPM_SLP_32K_PVTM + ) + >; +}; + +&route_dsi { + status = "okay"; +}; + +&sai0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0m0_lrck + &i2s0m0_sclk + &i2s0m0_sdi0 + &i2s0m0_sdo0>; +}; + +&saradc0 { + status = "okay"; + vref-supply = <&vcc_1v8>; +}; + +&sdhci { + bus-width = <8>; + no-sdio; + no-sd; + non-removable; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + status = "okay"; +}; + +&sdmmc1 { + no-sd; + no-mmc; + bus-width = <4>; + disable-wp; + cap-sd-highspeed; + cap-sdio-irq; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + keep-power-in-suspend; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk>; + sd-uhs-sdr104; + status = "disabled"; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy { + status = "okay"; +}; + +/* for inno usb2 phy driver probe and set to phy_sus status */ +&u2phy_host { + /delete-property/ phy-supply; + status = "okay"; +}; + +&u2phy_otg { + status = "okay"; + vbus-supply = <&otg_switch>; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn>; +}; + +&usbdrd30 { + status = "okay"; +}; + +&usbdrd_dwc3 { + status = "okay"; + dr_mode = "otg"; + maximum-speed = "high-speed"; + phys = <&u2phy_otg>; + phy-names = "usb2-phy"; + snps,dis_u2_susphy_quirk; + snps,usb2-lpm-disable; + + usb-role-switch; + port { + #address-cells = <1>; + #size-cells = <0>; + dwc3_role_switch: endpoint@0 { + reg = <0>; + remote-endpoint = <&usbc0_role_sw>; + }; + }; +}; + +&video_phy { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb2-ddr4-v10-linux.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb2-ddr4-v10-linux.dts index fe9c20f71ee9..f95406bf86fa 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562-evb2-ddr4-v10-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3562-evb2-ddr4-v10-linux.dts @@ -7,3 +7,4 @@ #include "rk3562-evb2-ddr4-v10.dtsi" #include "rk3562-linux.dtsi" #include "rk3562-rk809.dtsi" +#include "rk3562-evb2-cam.dtsi" diff --git a/arch/arm64/boot/dts/rockchip/rk3562j-core-ddr4-v10.dts b/arch/arm64/boot/dts/rockchip/rk3562j-core-ddr4-v10.dts new file mode 100644 index 000000000000..bdd68af31952 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3562j-core-ddr4-v10.dts @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include +#include +#include "rk3562j-electric.dtsi" + +/ { + model = "Rockchip RK3562J CORE DDR4 V10 Board"; + compatible = "rockchip,rk3562j-core-ddr4-v10", "rockchip,rk3562"; + + chosen: chosen { + bootargs = "earlycon=uart8250,mmio32,0xff210000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rw rootwait"; + }; + + fiq-debugger { + compatible = "rockchip,fiq-debugger"; + rockchip,serial-id = <0>; + rockchip,wake-irq = <0>; + /* If enable uart uses irq instead of fiq */ + rockchip,irq-mode-enable = <1>; + rockchip,baudrate = <1500000>; /* Only 115200 and 1500000 */ + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&uart0m0_xfer>; + status = "okay"; + }; + + dc_12v: dc-12v { + compatible = "regulator-fixed"; + regulator-name = "dc_12v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc5v0_sys: vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_12v>; + }; + + vcc5v0_host: vcc5v0-host-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_host"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_HIGH>; + vin-supply = <&vcc5v0_sys>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_host_en>; + }; + + vcc5v0_otg: vcc5v0-otg-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_otg"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&expander0 11 GPIO_ACTIVE_HIGH>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&combphy_pu { + status = "disabled"; +}; + +&cpu0 { + cpu-supply = <&vdd_cpu>; +}; + +&gmac0 { + phy-mode = "rmii"; + clock_in_out = "input"; + + snps,reset-gpio = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + /* Reset time is 20ms, 100ms for rtl8211f */ + snps,reset-delays-us = <0 20000 100000>; + + pinctrl-names = "default"; + pinctrl-0 = <&rgmiim0_miim + &rgmiim0_tx_bus2 + &rgmiim0_rx_bus2 + &rgmiim0_clk>; + + phy-handle = <&rmii_phy>; + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + expander0: pca953x@26 { + vcc-supply = <&vcc_3v3>; + compatible = "nxp,pca9555"; + reg = <0x26>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + rk809: pmic@20 { + compatible = "rockchip,rk809"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = <3 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_gpio>, <&rk817_slppin_rst>; + rockchip,system-power-controller; + wakeup-source; + #clock-cells = <1>; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + /* 1: rst regs (default in codes), 0: rst the pmic */ + pmic-reset-func = <0>; + /* not save the PMIC_POWER_EN register in uboot */ + not-save-power-en = <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 = <500000>; + regulator-max-microvolt = <1350000>; + regulator-init-microvolt = <900000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-init-microvolt = <900000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_cpu"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + 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; + }; + }; + + vdd_buck4: DCDC_REG4 { + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_buck4"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda_0v9: LDO_REG1 { + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda_0v9"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_1v8: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca_1v8"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ldo3: LDO_REG3 { + regulator-name = "vcc_ldo3"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ldo5: LDO_REG5 { + regulator-name = "vcc_ldo5"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ldo6: LDO_REG6 { + regulator-name = "vcc_ldo6"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ldo7: LDO_REG7 { + regulator-name = "vcc_ldo7"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ldo8: LDO_REG8 { + regulator-name = "vcc_ldo8"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ldo9: LDO_REG9 { + regulator-name = "vcc_ldo9"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + 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-off-in-suspend; + }; + }; + + vcc_sw1: SWITCH_REG1 { + regulator-name = "vcc_sw1"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3: SWITCH_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_3v3"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&i2c1 { + status = "okay"; + pinctrl-0 = <&i2c1m0_xfer>; +}; + +&i2c2 { + status = "okay"; + pinctrl-0 = <&i2c2m0_xfer>; +}; + +&i2c4 { + status = "okay"; + pinctrl-0 = <&i2c4m1_xfer>; +}; + +&mdio0 { + rmii_phy: phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + clocks = <&cru CLK_GMAC_ETH_OUT2IO>; + assigned-clocks = <&cru CLK_GMAC_ETH_OUT2IO>; + assigned-clock-rates = <25000000>; + }; +}; + +&pinctrl { + usb { + vcc5v0_host_en: vcc5v0-host-en { + rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0m1_pins>; +}; + +&pwm3 { + status = "okay"; + pinctrl-0 = <&pwm3m0_pins>; +}; + +&pwm4 { + status = "okay"; + pinctrl-0 = <&pwm4m0_pins>; +}; + +&pwm7 { + status = "okay"; + pinctrl-0 = <&pwm7m0_pins>; +}; + +&pwm8 { + status = "okay"; + pinctrl-0 = <&pwm8m0_pins>; +}; + +&pwm9 { + status = "okay"; + pinctrl-0 = <&pwm9m0_pins>; +}; + +&rng { + status = "okay"; +}; + +&saradc0 { + status = "okay"; + vref-supply = <&vcca_1v8>; +}; + +&sdhci { + status = "okay"; +}; + +&spi1 { + status = "okay"; + pinctrl-0 = <&spi1m1_csn0 &spi1m1_pins>; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2m1_csn0 &spi2m1_pins>; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy { + status = "okay"; +}; + +&u2phy_host { + phy-supply = <&vcc5v0_host>; + status = "okay"; +}; + +&u2phy_otg { + vbus-supply = <&vcc5v0_otg>; + status = "okay"; +}; + +&uart2 { + status = "okay"; + pinctrl-0 = <&uart2m1_xfer &uart2m1_ctsn &uart2m1_rtsn>; +}; + +&uart4 { + status = "okay"; + pinctrl-0 = <&uart4m0_xfer &uart4m0_ctsn &uart4m0_rtsn>; +}; + +&uart5 { + status = "okay"; + pinctrl-0 = <&uart5m1_xfer>; +}; + +&uart6 { + status = "okay"; + pinctrl-0 = <&uart6m0_xfer>; +}; + +&uart7 { + status = "okay"; + pinctrl-0 = <&uart7m0_xfer>; +}; + +&uart8 { + status = "okay"; + pinctrl-0 = <&uart8m0_xfer>; +}; + +&uart9 { + status = "okay"; + pinctrl-0 = <&uart9m1_xfer>; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usbdrd30 { + status = "okay"; +}; + +&usbdrd_dwc3 { + status = "okay"; + dr_mode = "otg"; + extcon = <&u2phy>; + maximum-speed = "high-speed"; + phys = <&u2phy_otg>; + phy-names = "usb2-phy"; + snps,dis_u2_susphy_quirk; + snps,usb2-lpm-disable; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3562j-electric.dtsi b/arch/arm64/boot/dts/rockchip/rk3562j-electric.dtsi new file mode 100644 index 000000000000..1f36d72bdd06 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3562j-electric.dtsi @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +#include "rk3562j.dtsi" + +&cpu0_opp_table { + /* + * Max CPU frequency is 1.8GHz for the overdrive mode, + * but it will reduce chip lifetime. + */ + /delete-node/ opp-408000000; + /delete-node/ opp-600000000; + /delete-node/ opp-816000000; + /delete-node/ opp-1008000000; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3562j.dtsi b/arch/arm64/boot/dts/rockchip/rk3562j.dtsi new file mode 100644 index 000000000000..b2ec94fccda0 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3562j.dtsi @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +#include "rk3562.dtsi" + +/ { + can0: can@ff600000 { + compatible = "rockchip,rk3562-can"; + reg = <0x0 0xff600000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_CAN0>, <&cru PCLK_CAN0>; + clock-names = "baudclk", "apb_pclk"; + resets = <&cru SRST_CAN0>, <&cru SRST_P_CAN0>; + reset-names = "can", "can-apb"; + status = "disabled"; + }; + + can1: can@ff610000 { + compatible = "rockchip,rk3562-can"; + reg = <0x0 0xff610000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_CAN1>, <&cru PCLK_CAN1>; + clock-names = "baudclk", "apb_pclk"; + resets = <&cru SRST_CAN1>, <&cru SRST_P_CAN1>; + reset-names = "can", "can-apb"; + status = "disabled"; + }; +}; + +&cpu0_opp_table { + /delete-node/ mbist-vmin; + /* + * Max CPU frequency is 1.8GHz for the overdrive mode, + * but it will reduce chip lifetime. + */ + /delete-node/ opp-1416000000; + /delete-node/ opp-1608000000; + /delete-node/ opp-1800000000; + /delete-node/ opp-2016000000; + opp-408000000 { + opp-microvolt = <850000 850000 1150000>; + }; + opp-600000000 { + opp-microvolt = <850000 850000 1150000>; + }; + opp-816000000 { + opp-microvolt = <850000 850000 1150000>; + }; + opp-1008000000 { + opp-microvolt = <850000 850000 1150000>; + }; + opp-1200000000 { + opp-microvolt-L4 = <850000 850000 1150000>; + }; +}; + +&gpu_opp_table { + /delete-node/ mbist-vmin; + /* + * Max GPU frequency is 900MHz for the overdrive mode, + * but it will reduce chip lifetime. + */ + /delete-node/ opp-800000000; + /delete-node/ opp-900000000; + opp-300000000 { + opp-microvolt = <850000 850000 1000000>; + }; + opp-400000000 { + opp-microvolt = <850000 850000 1000000>; + }; + opp-500000000 { + opp-microvolt = <850000 850000 1000000>; + }; + opp-600000000 { + opp-microvolt = <850000 850000 1000000>; + }; + opp-700000000 { + opp-microvolt-L3 = <850000 850000 1000000>; + opp-microvolt-L4 = <850000 850000 1000000>; + }; +}; + +&npu_opp_table { + /delete-node/ mbist-vmin; + /* + * Max NPU frequency is 900MHz for the overdrive mode, + * but it will reduce chip lifetime. + */ + /delete-node/ opp-800000000; + /delete-node/ opp-900000000; + /delete-node/ opp-1000000000; + opp-300000000 { + opp-microvolt = <850000 850000 1000000>; + }; + opp-400000000 { + opp-microvolt = <850000 850000 1000000>; + }; + opp-500000000 { + opp-microvolt = <850000 850000 1000000>; + }; + opp-600000000 { + opp-microvolt-L2 = <850000 850000 1000000>; + opp-microvolt-L3 = <850000 850000 1000000>; + opp-microvolt-L4 = <850000 850000 1000000>; + }; + opp-700000000 { + opp-microvolt-L4 = <850000 850000 1000000>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index 3c7db91c31fe..e209d2dcc362 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -125,12 +125,14 @@ opp-shared; mbist-vmin = <825000 900000 950000>; - nvmem-cells = <&cpu_leakage>, <&core_pvtm>, <&mbist_vmin>; - nvmem-cell-names = "leakage", "pvtm", "mbist-vmin"; + nvmem-cells = <&cpu_leakage>, <&core_pvtm>, <&mbist_vmin>, <&cpu_opp_info>; + nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info"; + rockchip,max-volt = <1150000>; rockchip,pvtm-voltage-sel = < 0 84000 0 - 84001 91000 1 - 91001 100000 2 + 84001 87000 1 + 87001 91000 2 + 91001 100000 3 >; rockchip,pvtm-freq = <408000>; rockchip,pvtm-volt = <900000>; @@ -145,7 +147,7 @@ rockchip,low-temp = <0>; rockchip,low-temp-adjust-volt = < /* MHz MHz uV */ - 0 1608 75000 + 0 1992 75000 >; opp-408000000 { @@ -170,38 +172,43 @@ opp-microvolt-L0 = <900000 900000 1150000>; opp-microvolt-L1 = <850000 850000 1150000>; opp-microvolt-L2 = <850000 850000 1150000>; + opp-microvolt-L3 = <850000 850000 1150000>; clock-latency-ns = <40000>; }; opp-1416000000 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <1000000 1000000 1150000>; - opp-microvolt-L0 = <1000000 1000000 1150000>; - opp-microvolt-L1 = <925000 925000 1150000>; - opp-microvolt-L2 = <925000 925000 1150000>; + opp-microvolt = <1025000 1025000 1150000>; + opp-microvolt-L0 = <1025000 1025000 1150000>; + opp-microvolt-L1 = <975000 975000 1150000>; + opp-microvolt-L2 = <950000 950000 1150000>; + opp-microvolt-L3 = <925000 925000 1150000>; clock-latency-ns = <40000>; }; opp-1608000000 { opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <1075000 1075000 1150000>; - opp-microvolt-L0 = <1075000 1075000 1150000>; - opp-microvolt-L1 = <1000000 1000000 1150000>; - opp-microvolt-L2 = <1000000 1000000 1150000>; + opp-microvolt = <1100000 1100000 1150000>; + opp-microvolt-L0 = <1100000 1100000 1150000>; + opp-microvolt-L1 = <1050000 1050000 1150000>; + opp-microvolt-L2 = <1025000 1025000 1150000>; + opp-microvolt-L3 = <1000000 1000000 1150000>; clock-latency-ns = <40000>; }; opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; - opp-microvolt = <1125000 1125000 1150000>; - opp-microvolt-L0 = <1125000 1125000 1150000>; - opp-microvolt-L1 = <1050000 1050000 1150000>; - opp-microvolt-L2 = <1050000 1050000 1150000>; + opp-microvolt = <1150000 1150000 1150000>; + opp-microvolt-L0 = <1150000 1150000 1150000>; + opp-microvolt-L1 = <1100000 1100000 1150000>; + opp-microvolt-L2 = <1075000 1075000 1150000>; + opp-microvolt-L3 = <1050000 1050000 1150000>; clock-latency-ns = <40000>; }; opp-1992000000 { opp-hz = /bits/ 64 <1992000000>; opp-microvolt = <1150000 1150000 1150000>; opp-microvolt-L0 = <1150000 1150000 1150000>; - opp-microvolt-L1 = <1100000 1100000 1150000>; - opp-microvolt-L2 = <1075000 1075000 1150000>; + opp-microvolt-L1 = <1150000 1150000 1150000>; + opp-microvolt-L2 = <1125000 1125000 1150000>; + opp-microvolt-L3 = <1100000 1100000 1150000>; clock-latency-ns = <40000>; }; }; @@ -292,7 +299,7 @@ reg = <0x14>; #clock-cells = <1>; - rockchip,clk-init = <1416000000>; + rockchip,clk-init = <1104000000>; }; }; @@ -1099,18 +1106,20 @@ compatible = "operating-points-v2"; mbist-vmin = <825000 900000 950000>; - nvmem-cells = <&npu_leakage>, <&core_pvtm>, <&mbist_vmin>; - nvmem-cell-names = "leakage", "pvtm", "mbist-vmin"; + nvmem-cells = <&npu_leakage>, <&core_pvtm>, <&mbist_vmin>, <&npu_opp_info>; + nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info"; + rockchip,max-volt = <1000000>; rockchip,temp-hysteresis = <5000>; rockchip,low-temp = <0>; rockchip,low-temp-adjust-volt = < /* MHz MHz uV */ - 0 700 50000 + 0 1000 50000 >; rockchip,pvtm-voltage-sel = < 0 84000 0 - 84001 91000 1 - 91001 100000 2 + 84001 87000 1 + 87001 91000 2 + 91001 100000 3 >; rockchip,pvtm-ch = <0 5>; @@ -1128,38 +1137,39 @@ }; opp-600000000 { opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <850000 850000 1000000>; + }; + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; opp-microvolt = <875000 875000 1000000>; opp-microvolt-L0 = <875000 875000 1000000>; opp-microvolt-L1 = <850000 850000 1000000>; opp-microvolt-L2 = <850000 850000 1000000>; - }; - opp-700000000 { - opp-hz = /bits/ 64 <700000000>; - opp-microvolt = <900000 900000 1000000>; - opp-microvolt-L0 = <900000 900000 1000000>; - opp-microvolt-L1 = <850000 850000 1000000>; - opp-microvolt-L2 = <850000 850000 1000000>; + opp-microvolt-L3 = <850000 850000 1000000>; }; opp-800000000 { opp-hz = /bits/ 64 <800000000>; opp-microvolt = <925000 925000 1000000>; opp-microvolt-L0 = <925000 925000 1000000>; - opp-microvolt-L1 = <875000 875000 1000000>; + opp-microvolt-L1 = <900000 900000 1000000>; opp-microvolt-L2 = <875000 875000 1000000>; + opp-microvolt-L3 = <875000 875000 1000000>; }; opp-900000000 { opp-hz = /bits/ 64 <900000000>; opp-microvolt = <975000 975000 1000000>; opp-microvolt-L0 = <975000 975000 1000000>; - opp-microvolt-L1 = <925000 925000 1000000>; - opp-microvolt-L2 = <900000 900000 1000000>; + opp-microvolt-L1 = <950000 950000 1000000>; + opp-microvolt-L2 = <925000 925000 1000000>; + opp-microvolt-L3 = <900000 900000 1000000>; }; opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <1000000 1000000 1000000>; opp-microvolt-L0 = <1000000 1000000 1000000>; - opp-microvolt-L1 = <950000 950000 1000000>; - opp-microvolt-L2 = <925000 925000 1000000>; + opp-microvolt-L1 = <975000 975000 1000000>; + opp-microvolt-L2 = <950000 950000 1000000>; + opp-microvolt-L3 = <925000 925000 1000000>; status = "disabled"; }; }; @@ -1252,47 +1262,58 @@ compatible = "operating-points-v2"; mbist-vmin = <825000 900000 950000>; - nvmem-cells = <&gpu_leakage>, <&core_pvtm>, <&mbist_vmin>; - nvmem-cell-names = "leakage", "pvtm", "mbist-vmin"; + nvmem-cells = <&gpu_leakage>, <&core_pvtm>, <&mbist_vmin>, <&gpu_opp_info>; + nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info"; + rockchip,max-volt = <1000000>; + rockchip,temp-hysteresis = <5000>; + rockchip,low-temp = <0>; + rockchip,low-temp-adjust-volt = < + /* MHz MHz uV */ + 0 800 50000 + >; rockchip,pvtm-voltage-sel = < 0 84000 0 - 84001 91000 1 - 91001 100000 2 + 84001 87000 1 + 87001 91000 2 + 91001 100000 3 >; rockchip,pvtm-ch = <0 5>; opp-200000000 { opp-hz = /bits/ 64 <200000000>; - opp-microvolt = <850000>; + opp-microvolt = <850000 850000 1000000>; }; opp-300000000 { opp-hz = /bits/ 64 <300000000>; - opp-microvolt = <850000>; + opp-microvolt = <850000 850000 1000000>; }; opp-400000000 { opp-hz = /bits/ 64 <400000000>; - opp-microvolt = <850000>; + opp-microvolt = <850000 850000 1000000>; }; opp-600000000 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <875000>; - opp-microvolt-L0 = <875000>; - opp-microvolt-L1 = <850000>; - opp-microvolt-L2 = <850000>; + opp-microvolt = <900000 900000 1000000>; + opp-microvolt-L0 = <900000 900000 1000000>; + opp-microvolt-L1 = <875000 875000 1000000>; + opp-microvolt-L2 = <850000 850000 1000000>; + opp-microvolt-L3 = <850000 850000 1000000>; }; opp-700000000 { opp-hz = /bits/ 64 <700000000>; - opp-microvolt = <950000>; - opp-microvolt-L0 = <950000>; - opp-microvolt-L1 = <900000>; - opp-microvolt-L2 = <850000>; + opp-microvolt = <950000 950000 1000000>; + opp-microvolt-L0 = <950000 950000 1000000>; + opp-microvolt-L1 = <925000 925000 1000000>; + opp-microvolt-L2 = <900000 900000 1000000>; + opp-microvolt-L3 = <875000 875000 1000000>; }; opp-800000000 { opp-hz = /bits/ 64 <800000000>; - opp-microvolt = <1000000>; - opp-microvolt-L0 = <1000000>; - opp-microvolt-L1 = <950000>; - opp-microvolt-L2 = <900000>; + opp-microvolt = <1000000 1000000 1000000>; + opp-microvolt-L0 = <1000000 1000000 1000000>; + opp-microvolt-L1 = <975000 975000 1000000>; + opp-microvolt-L2 = <950000 950000 1000000>; + opp-microvolt-L3 = <925000 925000 1000000>; }; }; @@ -2305,8 +2326,9 @@ compatible = "operating-points-v2"; mbist-vmin = <825000 900000 950000>; - nvmem-cells = <&log_leakage>, <&core_pvtm>, <&mbist_vmin>; - nvmem-cell-names = "leakage", "pvtm", "mbist-vmin"; + nvmem-cells = <&log_leakage>, <&core_pvtm>, <&mbist_vmin>, <&dmc_opp_info>; + nvmem-cell-names = "leakage", "pvtm", "mbist-vmin", "opp-info"; + rockchip,max-volt = <1000000>; rockchip,temp-hysteresis = <5000>; rockchip,low-temp = <0>; rockchip,low-temp-adjust-volt = < @@ -2325,9 +2347,9 @@ opp-1560000000 { opp-hz = /bits/ 64 <1560000000>; - opp-microvolt = <900000>; - opp-microvolt-L0 = <900000>; - opp-microvolt-L1 = <875000>; + opp-microvolt = <900000 900000 1000000>; + opp-microvolt-L0 = <900000 900000 1000000>; + opp-microvolt-L1 = <875000 875000 1000000>; }; }; @@ -2707,6 +2729,18 @@ tsadc_trim_base: tsadc-trim-base@32 { reg = <0x32 0x1>; }; + cpu_opp_info: cpu-opp-info@36 { + reg = <0x36 0x6>; + }; + gpu_opp_info: gpu-opp-info@3c { + reg = <0x3c 0x6>; + }; + npu_opp_info: npu-opp-info@42 { + reg = <0x42 0x6>; + }; + dmc_opp_info: dmc-opp-info@48 { + reg = <0x48 0x6>; + }; }; i2s0_8ch: i2s@fe400000 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb.dtsi index c9cdc0817251..deb40fdea728 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb.dtsi @@ -107,7 +107,7 @@ dp0_sound: dp0-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp0"; + rockchip,card-name= "rockchip-dp0"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx2>; rockchip,codec = <&dp0 1>; @@ -117,7 +117,7 @@ dp1_sound: dp1-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp1"; + rockchip,card-name= "rockchip-dp1"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx5>; rockchip,codec = <&dp1 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1.dts new file mode 100644 index 000000000000..4e48b928f0a4 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1.dts @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include "rk3588-evb1-lp4.dtsi" +#include "rk3588-evb1-imx415.dtsi" +#include "rk3588-android.dtsi" + +/ { + model = "Rockchip RK3588 EVB1 LP4 V10 Board + DSI DSC PANEL MV2100UZ1 DISPLAY Ext Board"; + compatible = "rockchip,rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1", "rockchip,rk3588"; +}; + +&backlight { + status = "okay"; + default-brightness-level = <20>; +}; + +&dsi0 { + status = "okay"; + rockchip,lane-rate = <1200000>; + + dsi0_panel: panel@0 { + status = "okay"; + compatible = "simple-panel-dsi"; + reg = <0>; + backlight = <&backlight>; + reset-delay-ms = <50>; + enable-delay-ms = <50>; + init-delay-ms = <20>; + prepare-delay-ms = <50>; + unprepare-delay-ms = <20>; + disable-delay-ms = <20>; + dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST)>; + + dsi,format = ; + dsi,lanes = <4>; + + compressed-data; + slice-width = <1140>; + slice-height = <2280>; + version-major = <1>; + version-minor = <1>; + + panel-init-sequence = [ + /* PPS Setting */ + 0A 00 58 11 00 00 89 30 80 08 E8 08 E8 08 E8 04 74 04 74 02 00 03 C9 00 20 F7 C5 00 0F 00 0F 00 0E 00 06 18 00 10 F0 03 0C 20 00 06 0B 0B 33 0E 1C 2A 38 46 54 62 69 70 77 79 7B 7D 7E 01 02 01 00 09 40 09 BE 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 2A F6 2B 34 2B 74 3B 74 6B F4 + 39 00 02 FF 20 + 39 00 02 E0 10 + 39 00 02 7A 07 + 39 00 02 7D 0C + 39 00 02 7E 0C + 39 00 02 FB 01 + + 39 00 02 FF E0 + 39 00 02 66 00 + 39 00 02 23 07 + 39 00 02 FB 01 + + /* CMD2 page 5 */ + 39 00 02 FF 25 + + /* OSC TRACE for MIPI H 4.748us */ + 39 00 02 2F 20 + 39 00 02 0D 07 + 39 00 02 0E 6B + 39 00 02 11 11 + 39 00 02 13 00 + 39 00 02 14 01 + 39 00 02 25 20 + 39 00 02 0F 09 + 39 00 02 10 A5 + 39 00 02 12 17 + 39 00 02 15 01 + 39 00 02 0C 01 + 39 00 02 09 10 + 39 00 02 38 03 + 39 00 02 0A 00 + 39 00 02 07 02 + + /* MIPI VFP */ + 39 00 02 BC FF + 39 00 02 BD FF + 39 00 02 BE FF + 39 00 02 BF FF + 39 00 02 C0 FF + 39 00 02 C1 FF + 39 00 02 C2 FF + 39 00 02 C3 FF + + 39 00 02 FB 01 + + 39 00 02 FF 10 + 39 00 05 2A 00 00 08 E7 + 39 00 05 2B 00 00 08 E7 + 39 00 02 03 01 + 39 00 02 BB 13 + 39 00 02 C0 03 + 39 00 11 C1 89 28 08 E8 F2 00 03 C9 F7 C5 00 0F 00 0E 00 06 + 39 00 03 C2 10 F0 + 39 00 02 35 00 + 39 00 03 44 00 00 + 39 00 02 51 FF + 39 00 02 53 24 + 39 00 02 FB 01 + + 15 64 01 11 + 15 14 01 29 + ]; + + panel-exit-sequence = [ + 05 00 01 28 + 05 00 01 10 + ]; + + disp_timings0: display-timings { + native-mode = <&dsi0_timing0>; + dsi0_timing0: timing0 { + clock-frequency = <506000000>; + hactive = <2280>; + vactive = <2280>; + hfront-porch = <52>; + hsync-len = <20>; + hback-porch = <52>; + vfront-porch = <44>; + vsync-len = <2>; + vback-porch = <14>; + 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>; + }; + }; + }; +}; + +&dp0 { + status = "disabled"; +}; + +&dp1 { + status = "disabled"; +}; + +&dp0_in_vp2 { + status = "disabled"; +}; + +&dp1_in_vp2 { + status = "disabled"; +}; + +&dsi0_in_vp2 { + status = "okay"; +}; + +&dsi0_in_vp3 { + status = "disabled"; +}; + +&dsi1_in_vp2 { + status = "disabled"; +}; + +&mipi_dcphy0 { + status = "okay"; +}; + +&route_dsi0 { + status = "okay"; + connect = <&vp2_out_dsi0>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4-v11-linux-ipc.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4-v11-linux-ipc.dts new file mode 100644 index 000000000000..74cf867cd913 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4-v11-linux-ipc.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include "rk3588-evb7-lp4.dtsi" +#include "rk3588-evb7-imx415.dtsi" +#include "rk3588-ipc.dtsi" + +/ { + model = "Rockchip RK3588 EVB7 LP4 V11 Board"; + compatible = "rockchip,rk3588-evb7-lp4-v11-linux-ipc", "rockchip,rk3588"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi index 69a328b2c8d7..59e61c648bb4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb7-lp4.dtsi @@ -515,22 +515,24 @@ poll_delay_ms = <100>; }; - mpu6500_acc: mpu_acc@68 { - compatible = "mpu6500_acc"; + icm42607_acc: icm_acc@68 { + status = "okay"; + compatible = "icm42607_acc"; reg = <0x68>; irq-gpio = <&gpio4 RK_PC2 IRQ_TYPE_EDGE_RISING>; irq_enable = <0>; poll_delay_ms = <30>; type = ; - layout = <5>; + layout = <0>; }; - mpu6500_gyro: mpu_gyro@68 { - compatible = "mpu6500_gyro"; + icm42607_gyro: icm_gyro@68 { + status = "okay"; + compatible = "icm42607_gyro"; reg = <0x68>; poll_delay_ms = <30>; type = ; - layout = <5>; + layout = <0>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-h0-imx415.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11-imx415.dtsi similarity index 98% rename from arch/arm64/boot/dts/rockchip/rk3588-h0-imx415.dtsi rename to arch/arm64/boot/dts/rockchip/rk3588-evb7-v11-imx415.dtsi index f5389891113d..d5772ebb9d49 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-h0-imx415.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11-imx415.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* - * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. * */ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11-linux.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11-linux.dts new file mode 100644 index 000000000000..f4051df93d9f --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11-linux.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include "rk3588-evb7-v11.dtsi" +#include "rk3588-evb7-v11-imx415.dtsi" +#include "rk3588-linux.dtsi" + +/ { + model = "Rockchip RK3588 EVB7 V11 Board"; + compatible = "rockchip,rk3588-evb7-v11", "rockchip,rk3588"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11.dts new file mode 100644 index 000000000000..24ef507c8b53 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include "rk3588-evb7-v11.dtsi" +#include "rk3588-evb7-v11-imx415.dtsi" +#include "rk3588-android.dtsi" + +/ { + model = "Rockchip RK3588 EVB7 V11 Board"; + compatible = "rockchip,rk3588-evb7-v11", "rockchip,rk3588"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-h0.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11.dtsi similarity index 97% rename from arch/arm64/boot/dts/rockchip/rk3588-h0.dtsi rename to arch/arm64/boot/dts/rockchip/rk3588-evb7-v11.dtsi index ecbc0b5718bc..5bef2102f9dd 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-h0.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb7-v11.dtsi @@ -526,22 +526,24 @@ poll_delay_ms = <100>; }; - mpu6500_acc: mpu_acc@68 { - compatible = "mpu6500_acc"; + icm42607_acc: icm_acc@68 { + status = "okay"; + compatible = "icm42607_acc"; reg = <0x68>; irq-gpio = <&gpio4 RK_PC2 IRQ_TYPE_EDGE_RISING>; irq_enable = <0>; poll_delay_ms = <30>; type = ; - layout = <5>; + layout = <0>; }; - mpu6500_gyro: mpu_gyro@68 { - compatible = "mpu6500_gyro"; + icm42607_gyro: icm_gyro@68 { + status = "okay"; + compatible = "icm42607_gyro"; reg = <0x68>; poll_delay_ms = <30>; type = ; - layout = <5>; + layout = <0>; }; }; @@ -561,9 +563,9 @@ &i2c6 { status = "okay"; - usbc0: fusb302@22 { - compatible = "fcs,fusb302"; - reg = <0x22>; + usbc0: husb311@4e { + compatible = "hynetek,husb311"; + reg = <0x4e>; interrupt-parent = <&gpio3>; interrupts = ; pinctrl-names = "default"; @@ -669,10 +671,6 @@ status = "okay"; }; -&leds { - status = "disabled"; -}; - &mdio1 { rgmii_phy: phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; @@ -750,6 +748,12 @@ }; }; + leds { + work_leds_gpio: work-leds-gpio { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + sdio-pwrseq { wifi_enable_h: wifi-enable-h { rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>; @@ -937,3 +941,9 @@ &usbhost_dwc3_0 { status = "disabled"; }; + +&work_led { + gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&work_leds_gpio>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-h0-v10-linux.dts b/arch/arm64/boot/dts/rockchip/rk3588-h0-v10-linux.dts deleted file mode 100644 index 047c51448985..000000000000 --- a/arch/arm64/boot/dts/rockchip/rk3588-h0-v10-linux.dts +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Copyright (c) 2022 Rockchip Electronics Co., Ltd. - * - */ - -/dts-v1/; - -#include "rk3588-h0.dtsi" -#include "rk3588-h0-imx415.dtsi" -#include "rk3588-linux.dtsi" - -/ { - model = "Rockchip RK3588 H0 V10 Board"; - compatible = "rockchip,rk3588-h0-v10", "rockchip,rk3588"; -}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-h0-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-h0-v10.dts deleted file mode 100644 index 8037e39cdef9..000000000000 --- a/arch/arm64/boot/dts/rockchip/rk3588-h0-v10.dts +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Copyright (c) 2022 Rockchip Electronics Co., Ltd. - * - */ - -/dts-v1/; - -#include "rk3588-h0.dtsi" -#include "rk3588-h0-imx415.dtsi" -#include "rk3588-android.dtsi" - -/ { - model = "Rockchip RK3588 H0 V10 Board"; - compatible = "rockchip,rk3588-h0-v10", "rockchip,rk3588"; -}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi index 12b815850b57..bfcde3f8e39a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi @@ -111,3 +111,8 @@ &rng { status = "okay"; }; + +/* Assign VOP_ACLK to 750MHZ for 8K */ +&vop { + assigned-clock-rates = <750000000>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nvr.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nvr.dtsi index d9f69e07dd70..0301d6f3118d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-nvr.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-nvr.dtsi @@ -31,7 +31,7 @@ dp0_sound: dp0-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp0"; + rockchip,card-name= "rockchip-dp0"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx2>; rockchip,codec = <&dp0 1>; @@ -41,7 +41,7 @@ dp1_sound: dp1-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp1"; + rockchip,card-name= "rockchip-dp1"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx5>; rockchip,codec = <&dp1 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-pcie-ep-demo.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-pcie-ep-demo.dtsi index 65ff203aab31..f44fd9e15c00 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-pcie-ep-demo.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-pcie-ep-demo.dtsi @@ -32,7 +32,7 @@ dp0_sound: dp0-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp0"; + rockchip,card-name= "rockchip-dp0"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx2>; rockchip,codec = <&dp0 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-toybrick.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-toybrick.dtsi index ae4131045a07..a76bedcfcdc1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-toybrick.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-toybrick.dtsi @@ -87,7 +87,7 @@ dp0_sound: dp0-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp0"; + rockchip,card-name= "rockchip-dp0"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx2>; rockchip,codec = <&dp0 1>; @@ -97,7 +97,7 @@ dp1_sound: dp1-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp1"; + rockchip,card-name= "rockchip-dp1"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx5>; rockchip,codec = <&dp1 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi index ee7041e8aa5b..4daa67699c94 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-maxim-max96712.dtsi @@ -61,7 +61,11 @@ power-domains = <&power RK3588_PD_VI>; rockchip,grf = <&sys_grf>; power-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>; + pocen-gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_HIGH>; //reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>; + lock-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>; + auto-init-deskew-mask = <0x03>; + frame-sync-period = <0>; rockchip,camera-module-index = <0>; rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "max96712"; @@ -143,11 +147,11 @@ &pinctrl { max96712 { max96712_errb: max96712-errb { - rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; + rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>; }; max96712_int: max96712-int { - rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>; + rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>; }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-mipi-nvp6188.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-mipi-nvp6188.dtsi index cf8494bfd9a1..39104b4f05fa 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-mipi-nvp6188.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-mipi-nvp6188.dtsi @@ -42,10 +42,10 @@ status = "okay"; - nvp6188: nvp6188@33 { + nvp6188: nvp6188@31 { compatible = "nvp6188"; status = "okay"; - reg = <0x33>; + reg = <0x31>; clocks = <&cru CLK_MIPI_CAMARAOUT_M2>; clock-names = "xvclk"; power-domains = <&power RK3588_PD_VI>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v10.dts index 9e497a20de8d..5f35db6bbc97 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v10.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* - * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. * */ @@ -16,4 +16,33 @@ / { model = "Rockchip RK3588 VEHICLE EVB V10 Board"; compatible = "rockchip,rk3588-vehicle-evb-v10", "rockchip,rk3588"; + + bt-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion = <1>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "rockchip,bt"; + simple-audio-card,cpu { + sound-dai = <&i2s2_2ch>; + }; + + simple-audio-card,codec { + sound-dai = <&bt_sco>; + }; + }; + + bt_sco: bt-sco { + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <0>; + status = "okay"; + }; +}; + +&i2s2_2ch{ + pinctrl-0 = <&i2s2m0_lrck + &i2s2m0_sclk + &i2s2m0_sdi + &i2s2m0_sdo>; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dts index 86dc62fd8236..30b3560f3485 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dts @@ -15,6 +15,34 @@ / { model = "Rockchip RK3588 VEHICLE EVB V20 Board"; compatible = "rockchip,rk3588-vehicle-evb-v20", "rockchip,rk3588"; + + bt-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion = <1>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "rockchip,bt"; + simple-audio-card,cpu { + sound-dai = <&i2s2_2ch>; + }; + + simple-audio-card,codec { + sound-dai = <&bt_sco>; + }; + }; + + bt_sco: bt-sco { + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <0>; + status = "okay"; + }; + + nvp6188_osc: oscillator { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <27000000>; + clock-output-names = "nvp6188-osc"; + }; }; &cif_sensor { @@ -23,7 +51,75 @@ }; }; -&nvp6188 { - pinctrl-0 = <&mipim1_camera3_clk>; - reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>; +&i2c7 { + status = "okay"; + /delete-node/ nvp6188@33; + nvp6188: nvp6188@31 { + compatible = "nvp6188"; + status = "okay"; + reg = <0x31>; + clocks = <&nvp6188_osc 0>; + clock-names = "xvclk"; + power-domains = <&power RK3588_PD_VI>; + rockchip,grf = <&sys_grf>; + /*power-gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>;*/ + reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "nvp6188"; + rockchip,camera-module-lens-name = "nvp6188"; + + port { + nvp6188_out: endpoint { + remote-endpoint = <&mipi_dphy0_in_nvp6188>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +&i2s2_2ch { + pinctrl-0 = <&i2s2m1_lrck + &i2s2m1_sclk + &i2s2m1_sdi + &i2s2m1_sdo>; + status = "okay"; +}; + +&rockchip_suspend { + rockchip,sleep-mode-config = < + (0 + | RKPM_SLP_ARMOFF_DDRPD + | RKPM_SLP_PMU_PMUALIVE_32K + | RKPM_SLP_PMU_DIS_OSC + | RKPM_SLP_32K_EXT + ) + >; + rockchip,wakeup-config = < + (0 + | RKPM_GPIO_WKUP_EN + ) + >; + status = "okay"; +}; + +&vdd_log_s0 { + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <800000>; + }; +}; + +&vcc_3v3_s0 { + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; +}; + +&vcc_1v8_s0 { + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi index f97f6bb94c01..e4e050ba5b42 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v20.dtsi @@ -61,7 +61,7 @@ * - SDIO_RESET_L_WL_REG_ON * - PDN (power down when low) */ - post-power-on-delay-ms = <200>; + post-power-on-delay-ms = <10>; reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; status = "okay"; }; @@ -117,6 +117,30 @@ WIFI,poweren_gpio = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>; status = "okay"; }; + + dummy_codec: dummy-codec { + status = "okay"; + compatible = "rockchip,dummy-codec"; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&rk3308_reset>; + }; + + car_rk3308_sound: car-rk3308-sound { + status = "okay"; + compatible = "simple-audio-card"; + simple-audio-card,name = "rockchip,car-rk3308-sound"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,bitclock-master = <&codec_master>; + simple-audio-card,frame-master = <&codec_master>; + simple-audio-card,cpu { + sound-dai = <&i2s0_8ch>; + }; + codec_master: simple-audio-card,codec { + sound-dai = <&dummy_codec>; + }; + }; }; &combphy0_ps { @@ -131,6 +155,26 @@ status = "okay"; }; +&gmac0 { + /* Use rgmii-rxid mode to disable rx delay inside Soc */ + phy-mode = "rgmii-rxid"; + clock_in_out = "output"; + snps,reset-gpio = <&gpio2 RK_PC5 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + /* Reset time is 20ms, 100ms for rtl8211f */ + snps,reset-delays-us = <0 20000 100000>; + pinctrl-names = "phydisb"; + pinctrl-0 = <&gmac0_miim + &gmac0_tx_bus2 + &gmac0_rx_bus2 + &gmac0_rgmii_clk + &gmac0_rgmii_bus + &phydisb>; + tx_delay = <0x43>; + //rx_delay = <0x3f>; + phy-handle = <&rgmii_phy>; + status = "okay"; +}; &i2c4 { status = "okay"; @@ -150,6 +194,26 @@ }; +&i2s0_8ch { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_lrck + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdi1 + &i2s0_sdo0 + &i2s0_sdo1 + &i2s0_sdo2 + &i2s0_sdo3>; +}; + +&mdio0 { + rgmii_phy: phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + }; +}; + &pcie2x1l0 { reset-gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>; rockchip,skip-scan-in-resume; @@ -164,6 +228,11 @@ }; &pinctrl { + gmac0 { + phydisb: phydisb { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_output_high>; + }; + }; hym8563 { hym8563_int: hym8563-int { @@ -207,6 +276,12 @@ rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>; }; }; + + rk3308 { + rk3308_reset: rk3308-reset { + rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; }; &pwm0 { @@ -241,7 +316,6 @@ non-removable; pinctrl-names = "default"; pinctrl-0 = <&sdiom1_pins>; - sd-uhs-sdr104; status = "okay"; }; @@ -304,5 +378,6 @@ &usbdrd_dwc3_1 { dr_mode = "host"; maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi index 166bcd049890..c63b5536cb3c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb.dtsi @@ -199,6 +199,30 @@ WIFI,poweren_gpio = <&gpio2 RK_PC5 GPIO_ACTIVE_HIGH>; status = "okay"; }; + + dummy_codec: dummy-codec { + status = "okay"; + compatible = "rockchip,dummy-codec"; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&rk3308_reset>; + }; + + car_rk3308_sound: car-rk3308-sound { + status = "okay"; + compatible = "simple-audio-card"; + simple-audio-card,name = "rockchip,car-rk3308-sound"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,bitclock-master = <&codec_master>; + simple-audio-card,frame-master = <&codec_master>; + simple-audio-card,cpu { + sound-dai = <&i2s0_8ch>; + }; + codec_master: simple-audio-card,codec { + sound-dai = <&dummy_codec>; + }; + }; }; &backlight { @@ -384,6 +408,19 @@ }; }; +&i2s0_8ch { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_lrck + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdi1 + &i2s0_sdo0 + &i2s0_sdo1 + &i2s0_sdo2 + &i2s0_sdo3>; +}; + &i2s5_8ch { status = "okay"; }; @@ -511,6 +548,12 @@ rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; }; }; + + rk3308 { + rk3308_reset: rk3308-reset { + rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; }; &pwm1 { @@ -624,5 +667,6 @@ &usbdrd_dwc3_1 { dr_mode = "host"; maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v20.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v20.dtsi index 476100b91c64..b458efd4ad9a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v20.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v20.dtsi @@ -5,6 +5,14 @@ */ / { + lt7911d { + compatible = "lontium,lt7911d-fb-notifier"; + reset-gpios = <&gpio0 RK_PD2 GPIO_ACTIVE_LOW>, + <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>, + <&gpio3 RK_PD4 GPIO_ACTIVE_LOW>, + <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>; + }; + dsi2lvds_backlight1: dsi2lvds_backlight1 { compatible = "pwm-backlight"; brightness-levels = < @@ -207,7 +215,7 @@ display-timings { native-mode = <&dsi2lvds0>; dsi2lvds0: timing0 { - clock-frequency = <87000000>; + clock-frequency = <88208000>; hactive = <1920>; vactive = <720>; hfront-porch = <32>; @@ -243,7 +251,7 @@ display-timings { native-mode = <&dsi2lvds1>; dsi2lvds1: timing0 { - clock-frequency = <87000000>; + clock-frequency = <88208000>; hactive = <1920>; vactive = <720>; hfront-porch = <32>; @@ -275,10 +283,6 @@ dp2lvds_panel0 { compatible = "simple-panel"; backlight = <&dp2lvds_backlight0>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -307,10 +311,6 @@ dp2lvds_panel1 { compatible = "simple-panel"; backlight = <&dp2lvds_backlight1>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -339,10 +339,6 @@ edp2lvds_panel0 { compatible = "simple-panel"; backlight = <&edp2lvds_backlight0>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -371,10 +367,6 @@ edp2lvds_panel1 { compatible = "simple-panel"; backlight = <&edp2lvds_backlight1>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -617,36 +609,6 @@ status = "okay"; }; -&gpio0 { - i2c5-serdes-reset { - gpio-hog; - gpios = <26 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - -&gpio4 { - i2c7-serdes-reset { - gpio-hog; - gpios = <7 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - -&gpio3 { - i2c4-serdes-reset { - gpio-hog; - gpios = <28 GPIO_ACTIVE_HIGH>; - output-high; - }; - - i2c8-serdes-reset { - gpio-hog; - gpios = <26 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - &hdmi0 { status = "disabled"; }; @@ -894,8 +856,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002d 0018 0030 0018 @@ -1068,8 +1030,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002e 0004 002d 0018 @@ -1472,8 +1434,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002d 0018 0030 0018 @@ -1648,8 +1610,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002d 0018 0030 0018 @@ -1954,3 +1916,28 @@ rockchip,dp-lane-mux = <0 1 2 3>; status = "okay"; }; + +&vop { + assigned-clocks = <&cru PLL_V0PLL>; + assigned-clock-rates = <1152000000>; +}; + +&vp0 { + assigned-clocks = <&cru DCLK_VOP0_SRC>; + assigned-clock-parents = <&cru PLL_V0PLL>; +}; + +&vp1 { + assigned-clocks = <&cru DCLK_VOP1_SRC>; + assigned-clock-parents = <&cru PLL_GPLL>; +}; + +&vp2 { + assigned-clocks = <&cru DCLK_VOP2_SRC>; + assigned-clock-parents = <&cru PLL_V0PLL>; +}; + +&vp3 { + assigned-clocks = <&cru DCLK_VOP3>; + assigned-clock-parents = <&cru PLL_V0PLL>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display.dtsi index 6379db10ee74..7ee1d48a6a42 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display.dtsi @@ -5,6 +5,14 @@ */ / { + lt7911d { + compatible = "lontium,lt7911d-fb-notifier"; + reset-gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>, + <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>, + <&gpio3 RK_PD4 GPIO_ACTIVE_LOW>, + <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>; + }; + dsi2lvds_backlight1: dsi2lvds_backlight1 { compatible = "pwm-backlight"; brightness-levels = < @@ -207,7 +215,7 @@ display-timings { native-mode = <&dsi2lvds0>; dsi2lvds0: timing0 { - clock-frequency = <87000000>; + clock-frequency = <88208000>; hactive = <1920>; vactive = <720>; hfront-porch = <32>; @@ -243,7 +251,7 @@ display-timings { native-mode = <&dsi2lvds1>; dsi2lvds1: timing0 { - clock-frequency = <87000000>; + clock-frequency = <88208000>; hactive = <1920>; vactive = <720>; hfront-porch = <32>; @@ -275,10 +283,6 @@ dp2lvds_panel0 { compatible = "simple-panel"; backlight = <&dp2lvds_backlight0>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -307,10 +311,6 @@ dp2lvds_panel1 { compatible = "simple-panel"; backlight = <&dp2lvds_backlight1>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -339,10 +339,6 @@ edp2lvds_panel0 { compatible = "simple-panel"; backlight = <&edp2lvds_backlight0>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -371,10 +367,6 @@ edp2lvds_panel1 { compatible = "simple-panel"; backlight = <&edp2lvds_backlight1>; - prepare-delay-ms = <120>; - enable-delay-ms = <120>; - unprepare-delay-ms = <120>; - disable-delay-ms = <120>; status = "okay"; panel-timing { @@ -617,34 +609,6 @@ status = "okay"; }; -&gpio1 { - i2c5-serdes-reset { - gpio-hog; - gpios = <6 GPIO_ACTIVE_HIGH>; - output-high; - }; - - i2c7-serdes-reset { - gpio-hog; - gpios = <2 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - -&gpio3 { - i2c3-serdes-reset { - gpio-hog; - gpios = <28 GPIO_ACTIVE_HIGH>; - output-high; - }; - - i2c8-serdes-reset { - gpio-hog; - gpios = <26 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - &hdmi0 { status = "disabled"; }; @@ -892,8 +856,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002d 0018 0030 0018 @@ -1066,8 +1030,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002e 0004 002d 0018 @@ -1470,8 +1434,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002d 0018 0030 0018 @@ -1646,8 +1610,8 @@ 0013 001a 0014 000a 0021 0008 - 0023 0003 - 0024 0003 + 0023 0009 + 0024 0009 002a 0018 002d 0018 0030 0018 @@ -1952,3 +1916,28 @@ rockchip,dp-lane-mux = <0 1 2 3>; status = "okay"; }; + +&vop { + assigned-clocks = <&cru PLL_V0PLL>; + assigned-clock-rates = <1152000000>; +}; + +&vp0 { + assigned-clocks = <&cru DCLK_VOP0_SRC>; + assigned-clock-parents = <&cru PLL_V0PLL>; +}; + +&vp1 { + assigned-clocks = <&cru DCLK_VOP1_SRC>; + assigned-clock-parents = <&cru PLL_GPLL>; +}; + +&vp2 { + assigned-clocks = <&cru DCLK_VOP2_SRC>; + assigned-clock-parents = <&cru PLL_V0PLL>; +}; + +&vp3 { + assigned-clocks = <&cru DCLK_VOP3>; + assigned-clock-parents = <&cru PLL_V0PLL>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle.dtsi index 383591104b0e..f4498cdd21c9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle.dtsi @@ -107,7 +107,7 @@ dp0_sound: dp0-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp0"; + rockchip,card-name= "rockchip-dp0"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx2>; rockchip,codec = <&dp0 1>; @@ -117,7 +117,7 @@ dp1_sound: dp1-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp1"; + rockchip,card-name= "rockchip-dp1"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx5>; rockchip,codec = <&dp1 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588.dtsi index c0aa2b183493..6011217fd644 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588.dtsi @@ -136,6 +136,8 @@ phy_type = "utmi_wide"; linux,sysdev_is_parent; snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; snps,dis-u2-freeclk-exists-quirk; snps,dis-del-phy-power-chg-quirk; snps,dis-tx-ipgap-linecheck-quirk; @@ -730,6 +732,13 @@ }; }; + gmac_uio0: uio@fe1b0000 { + compatible = "rockchip,uio-gmac"; + reg = <0x0 0xfe1b0000 0x0 0x10000>; + rockchip,ethernet = <&gmac0>; + status = "disabled"; + }; + gmac0: ethernet@fe1b0000 { compatible = "rockchip,rk3588-gmac", "snps,dwmac-4.20a"; reg = <0x0 0xfe1b0000 0x0 0x10000>; @@ -769,15 +778,13 @@ }; gmac0_mtl_rx_setup: rx-queues-config { - snps,rx-queues-to-use = <2>; + snps,rx-queues-to-use = <1>; queue0 {}; - queue1 {}; }; gmac0_mtl_tx_setup: tx-queues-config { - snps,tx-queues-to-use = <2>; + snps,tx-queues-to-use = <1>; queue0 {}; - queue1 {}; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb.dtsi index 6db4c5734836..586c6277449c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb.dtsi @@ -87,7 +87,7 @@ dp0_sound: dp0-sound { status = "disabled"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp0"; + rockchip,card-name= "rockchip-dp0"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx2>; rockchip,codec = <&dp0 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x-v10-linux.dts b/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x-v10-linux.dts index 121255ddfdbc..4d8157bcc7de 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x-v10-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x-v10-linux.dts @@ -7,6 +7,7 @@ /dts-v1/; #include "rk3588s-evb1-lp4x.dtsi" +#include "rk3588s-evb1-lp4x-v10-camera.dtsi" #include "rk3588-linux.dtsi" / { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi index b61a843ef28f..2a78a4eb05a1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-tablet.dtsi @@ -114,7 +114,7 @@ dp0_sound: dp0-sound { status = "okay"; compatible = "rockchip,hdmi"; - rockchip,card-name= "rockchip,dp0"; + rockchip,card-name= "rockchip-dp0"; rockchip,mclk-fs = <512>; rockchip,cpu = <&spdif_tx2>; rockchip,codec = <&dp0 1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index ed2c0ac73a3c..9318c32f8920 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -2372,7 +2372,8 @@ <&cru HCLK_PMU_CM0_ROOT>, <&cru ACLK_BUS_ROOT>, <&cru CLK_150M_SRC>, <&cru CLK_GPU>, <&cru CLK_SPDIF2_DP0>, - <&cru CLK_SPDIF5_DP1>; + <&cru CLK_SPDIF5_DP1>, <&cru CLK_HDMIRX_AUD>, + <&cru DCLK_DECOM>; assigned-clock-rates = <1100000000>, <786432000>, <850000000>, <1188000000>, @@ -2383,7 +2384,8 @@ <200000000>, <375000000>, <150000000>, <200000000>, <12000000>, - <12000000>; + <12000000>, <99000000>, + <20000000>; }; i2c0: i2c@fd880000 { @@ -2872,7 +2874,7 @@ 675000 3 495000 4 >; - low-volt-read-margin = <4>; + low-volt-mem-read-margin = <4>; intermediate-threshold-freq = <500000>; /* KHz*/ rockchip,init-freq = <1000000>; /* KHz */ @@ -3087,9 +3089,13 @@ interrupt-names = "irq_avsd"; clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; clock-names = "aclk_vcodec", "hclk_vcodec"; + rockchip,normal-rates = <594000000>, <0>; + assigned-clocks = <&cru ACLK_VPU>; + assigned-clock-rates = <594000000>; resets = <&cru SRST_A_VPU>, <&cru SRST_H_VPU>; reset-names = "shared_video_a", "shared_video_h"; rockchip,skip-pmu-idle-request; + rockchip,disable-auto-freq; iommus = <&vdpu_mmu>; power-domains = <&power RK3588_PD_VDPU>; rockchip,srv = <&mpp_srv>; @@ -3365,9 +3371,9 @@ interrupt-names = "irq_rkvenc0"; clocks = <&cru ACLK_RKVENC0>, <&cru HCLK_RKVENC0>, <&cru CLK_RKVENC0_CORE>; clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core"; - rockchip,normal-rates = <600000000>, <0>, <800000000>; + rockchip,normal-rates = <500000000>, <0>, <800000000>; assigned-clocks = <&cru ACLK_RKVENC0>, <&cru CLK_RKVENC0_CORE>; - assigned-clock-rates = <600000000>, <800000000>; + assigned-clock-rates = <500000000>, <800000000>; resets = <&cru SRST_A_RKVENC0>, <&cru SRST_H_RKVENC0>, <&cru SRST_RKVENC0_CORE>; reset-names = "video_a", "video_h", "video_core"; rockchip,skip-pmu-idle-request; @@ -3404,9 +3410,9 @@ interrupt-names = "irq_rkvenc1"; clocks = <&cru ACLK_RKVENC1>, <&cru HCLK_RKVENC1>, <&cru CLK_RKVENC1_CORE>; clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core"; - rockchip,normal-rates = <600000000>, <0>, <800000000>; + rockchip,normal-rates = <500000000>, <0>, <800000000>; assigned-clocks = <&cru ACLK_RKVENC1>, <&cru CLK_RKVENC1_CORE>; - assigned-clock-rates = <600000000>, <800000000>; + assigned-clock-rates = <500000000>, <800000000>; resets = <&cru SRST_A_RKVENC1>, <&cru SRST_H_RKVENC1>, <&cru SRST_RKVENC1_CORE>; reset-names = "video_a", "video_h", "video_core"; rockchip,skip-pmu-idle-request; @@ -4787,6 +4793,13 @@ }; }; + gmac_uio1: uio@fe1c0000 { + compatible = "rockchip,uio-gmac"; + reg = <0x0 0xfe1c0000 0x0 0x10000>; + rockchip,ethernet = <&gmac1>; + status = "disabled"; + }; + gmac1: ethernet@fe1c0000 { compatible = "rockchip,rk3588-gmac", "snps,dwmac-4.20a"; reg = <0x0 0xfe1c0000 0x0 0x10000>; @@ -4826,15 +4839,13 @@ }; gmac1_mtl_rx_setup: rx-queues-config { - snps,rx-queues-to-use = <2>; + snps,rx-queues-to-use = <1>; queue0 {}; - queue1 {}; }; gmac1_mtl_tx_setup: tx-queues-config { - snps,tx-queues-to-use = <2>; + snps,tx-queues-to-use = <1>; queue0 {}; - queue1 {}; }; }; diff --git a/arch/arm64/configs/rk3562_robot.config b/arch/arm64/configs/rk3562_robot.config new file mode 100644 index 000000000000..49a6781e1654 --- /dev/null +++ b/arch/arm64/configs/rk3562_robot.config @@ -0,0 +1,283 @@ +# CONFIG_ARM_SMMU_V3 is not set +# CONFIG_ATA is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# CONFIG_BATTERY_CW2017 is not set +# CONFIG_BATTERY_RK817 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +CONFIG_BT_HS=y +# CONFIG_BT_MRVL is not set +CONFIG_BT_RFCOMM_TTY=y +CONFIG_CFG80211_WEXT=y +# CONFIG_CGROUPS is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ25700 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_RK817 is not set +# CONFIG_COMMON_CLK_PWM is not set +CONFIG_COMPACTION=y +# CONFIG_CONNECTOR is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT is not set +# CONFIG_CPU_FREQ_TIMES is not set +# CONFIG_CPU_PX30 is not set +# CONFIG_CPU_RK1808 is not set +# CONFIG_CPU_RK3328 is not set +# CONFIG_CPU_RK3399 is not set +# CONFIG_CPU_RK3528 is not set +# CONFIG_CPU_RK3568 is not set +# CONFIG_CPU_RK3588 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_DEV_ROCKCHIP_V1 is not set +# CONFIG_CRYPTO_DEV_ROCKCHIP_V2 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_ZSTD is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_DMABUF_CACHE is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_DRM_DISPLAY_CONNECTOR is not set +# CONFIG_DRM_DP is not set +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_EDID is not set +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +# CONFIG_EFI is not set +# CONFIG_ETHERNET is not set +# CONFIG_FB is not set +# CONFIG_FTRACE is not set +# CONFIG_FUSE_FS is not set +# CONFIG_HID is not set +CONFIG_HZ=250 +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_I2C_HID is not set +# CONFIG_IEP is not set +# CONFIG_IKCONFIG is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_IPV6 is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_MULTICAST is not set +# CONFIG_ISO9660_FS is not set +CONFIG_JUMP_LABEL=y +CONFIG_LD_VERSION=238000000 +# CONFIG_LEDS_IS31FL32XX is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_MAILBOX is not set +# CONFIG_MALI400 is not set +# CONFIG_MALI_MIDGARD is not set +# CONFIG_MD is not set +# CONFIG_MDIO_DEVICE is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_TEST_SUPPORT is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MFD_RK806 is not set +# CONFIG_MFD_RK806_SPI is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MTD is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NR_CPUS=4 +# CONFIG_NTFS_FS is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_PCI is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHY_ROCKCHIP_DP is not set +# CONFIG_PHY_ROCKCHIP_EMMC is not set +# CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY is not set +# CONFIG_PHY_ROCKCHIP_INNO_HDMI is not set +# CONFIG_PHY_ROCKCHIP_INNO_USB3 is not set +# CONFIG_PHY_ROCKCHIP_NANENG_EDP is not set +# CONFIG_PHY_ROCKCHIP_PCIE is not set +# CONFIG_PHY_ROCKCHIP_SAMSUNG_DCPHY is not set +# CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX is not set +# CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX_HDMI is not set +# CONFIG_PHY_ROCKCHIP_SNPS_PCIE3 is not set +# CONFIG_PHY_ROCKCHIP_TYPEC is not set +# CONFIG_PHY_ROCKCHIP_USB is not set +# CONFIG_PHY_ROCKCHIP_USBDP is not set +# CONFIG_PM_DEBUG is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +CONFIG_PREEMPT=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PROFILING is not set +CONFIG_PSTORE_PMSG=y +# CONFIG_RCU_TRACE is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_ZSTD is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_LP8752 is not set +# CONFIG_REGULATOR_MP8865 is not set +# CONFIG_REGULATOR_RK860X is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_XZ3216 is not set +# CONFIG_ROCKCHIP_AMP is not set +# CONFIG_ROCKCHIP_ANALOGIX_DP is not set +# CONFIG_ROCKCHIP_CDN_DP is not set +# CONFIG_ROCKCHIP_DRM_TVE is not set +# CONFIG_ROCKCHIP_DW_DP is not set +# CONFIG_ROCKCHIP_DW_HDCP2 is not set +# CONFIG_ROCKCHIP_DW_HDMI is not set +# CONFIG_ROCKCHIP_DW_MIPI_DSI is not set +# CONFIG_ROCKCHIP_EFUSE is not set +# CONFIG_ROCKCHIP_INNO_HDMI is not set +# CONFIG_ROCKCHIP_LVDS is not set +# CONFIG_ROCKCHIP_MPP_AV1DEC is not set +# CONFIG_ROCKCHIP_MPP_IEP2 is not set +# CONFIG_ROCKCHIP_MPP_JPGDEC is not set +# CONFIG_ROCKCHIP_MPP_RKVDEC is not set +# CONFIG_ROCKCHIP_MPP_RKVENC is not set +# CONFIG_ROCKCHIP_MPP_VDPU1 is not set +# CONFIG_ROCKCHIP_MPP_VDPU2 is not set +# CONFIG_ROCKCHIP_MPP_VEPU1 is not set +# CONFIG_ROCKCHIP_MPP_VEPU2 is not set +CONFIG_ROCKCHIP_PERFORMANCE_LEVEL=2 +# CONFIG_ROCKCHIP_PLL_RK3399 is not set +# CONFIG_ROCKCHIP_PLL_RK3588 is not set +# CONFIG_ROCKCHIP_REMOTECTL is not set +# CONFIG_ROCKCHIP_RGB is not set +# CONFIG_RPMSG_VIRTIO is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RUNTIME_TESTING_MENU is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_SYSFS is not set +# CONFIG_SND_SOC_ES7202 is not set +# CONFIG_SND_SOC_ES7243E is not set +# CONFIG_SND_SOC_ES8311 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8323 is not set +# CONFIG_SND_SOC_ES8326 is not set +# CONFIG_SND_SOC_RK3308 is not set +# CONFIG_SND_SOC_RK3328 is not set +# CONFIG_SND_SOC_RK3528 is not set +# CONFIG_SND_SOC_ROCKCHIP_HDMI is not set +# CONFIG_SND_SOC_ROCKCHIP_MAX98090 is not set +# CONFIG_SND_SOC_ROCKCHIP_RT5645 is not set +# CONFIG_SND_SOC_ROCKCHIP_SPDIFRX is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5640 is not set +# CONFIG_SND_SOC_RT5651 is not set +# CONFIG_SND_SOC_TS3A227E is not set +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_SPI_ROCKCHIP_SFC is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SW_SYNC is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_TCG_TPM is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_TSL2583 is not set +# CONFIG_TYPEC_TCPM is not set +# CONFIG_UNICODE is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_CONFIGFS_ACM is not set +# CONFIG_USB_CONFIGFS_F_UVC is not set +# CONFIG_USB_CONFIGFS_MASS_STORAGE is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_VHOST_MENU is not set +CONFIG_VIDEO_GC2053=y +# CONFIG_VIDEO_IMX464 is not set +# CONFIG_VIDEO_LT6911UXC is not set +# CONFIG_VIDEO_LT7911D is not set +# CONFIG_VIDEO_OS04A10 is not set +# CONFIG_VIDEO_OV13850 is not set +# CONFIG_VIDEO_OV4689 is not set +# CONFIG_VIDEO_OV7251 is not set +# CONFIG_VIDEO_RK628_BT1120 is not set +# CONFIG_VIDEO_RK628_CSI is not set +# CONFIG_VIDEO_ROCKCHIP_HDMIRX is not set +# CONFIG_VIDEO_ROCKCHIP_ISPP is not set +# CONFIG_VIDEO_ROCKCHIP_ISP_VERSION_V1X is not set +# CONFIG_VIDEO_ROCKCHIP_ISP_VERSION_V21 is not set +# CONFIG_VIDEO_ROCKCHIP_ISP_VERSION_V30 is not set +CONFIG_VIDEO_SC031GS=y +# CONFIG_VIDEO_TC35874X is not set +# CONFIG_VIRTIO_MENU is not set +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_MICROCHIP is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_XFS_FS is not set +CONFIG_ARM64_LSE_ATOMICS=y +CONFIG_ARM64_USE_LSE_ATOMICS=y +CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1 +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1 +# CONFIG_BT_FEATURE_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_NO_IOPORT_MAP=y +CONFIG_PREEMPTION=y +CONFIG_PREEMPT_COUNT=y +CONFIG_PREEMPT_RCU=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +CONFIG_TASKS_RCU=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set diff --git a/arch/arm64/configs/rockchip_defconfig b/arch/arm64/configs/rockchip_defconfig index 1118fc2c8785..2369401bab1e 100644 --- a/arch/arm64/configs/rockchip_defconfig +++ b/arch/arm64/configs/rockchip_defconfig @@ -292,6 +292,7 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_NVME=y +CONFIG_LT7911D_FB_NOTIFIER=y CONFIG_SRAM=y CONFIG_UID_SYS_STATS=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index 37e69e7e8ae4..a9639edaca7e 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -310,6 +310,7 @@ CONFIG_VIDEO_ROCKCHIP_HDMIRX=y CONFIG_V4L_MEM2MEM_DRIVERS=y CONFIG_VIDEO_ROCKCHIP_RGA=y CONFIG_VIDEO_LT6911UXC=y +CONFIG_VIDEO_LT6911UXE=y CONFIG_VIDEO_LT7911D=y CONFIG_VIDEO_RK628_CSI=y CONFIG_VIDEO_RK628_BT1120=y @@ -320,9 +321,11 @@ CONFIG_VIDEO_IMX415=y CONFIG_VIDEO_IMX464=y CONFIG_VIDEO_OS04A10=y CONFIG_VIDEO_OV4689=y +CONFIG_VIDEO_OV50C40=y CONFIG_VIDEO_OV5695=y CONFIG_VIDEO_OV7251=y CONFIG_VIDEO_OV13850=y +CONFIG_VIDEO_OV13855=y # CONFIG_VGA_ARB is not set CONFIG_DRM=y CONFIG_DRM_IGNORE_IOTCL_PERMIT=y diff --git a/drivers/base/arm/Makefile b/drivers/base/arm/Makefile index cc4bde71d3e6..3e9544b591c2 100644 --- a/drivers/base/arm/Makefile +++ b/drivers/base/arm/Makefile @@ -96,6 +96,12 @@ ifeq ($(CONFIG_GCOV_KERNEL), y) EXTRA_CFLAGS += -DGCOV_PROFILE=1 endif +ifeq ($(CONFIG_MALI_KCOV),y) + KBUILD_CFLAGS += $(call cc-option, -fsanitize-coverage=trace-cmp) + EXTRA_CFLAGS += -DKCOV=1 + EXTRA_CFLAGS += -DKCOV_ENABLE_COMPARISONS=1 +endif + # The following were added to align with W=1 in scripts/Makefile.extrawarn # from the Linux source tree (v5.18.14) KBUILD_CFLAGS += -Wextra -Wunused -Wno-unused-parameter diff --git a/drivers/clk/rockchip/clk-out.c b/drivers/clk/rockchip/clk-out.c index 22dcd98fbbef..689832ed00d6 100644 --- a/drivers/clk/rockchip/clk-out.c +++ b/drivers/clk/rockchip/clk-out.c @@ -50,7 +50,7 @@ static int rockchip_clk_out_probe(struct platform_device *pdev) pm_runtime_enable(dev); - hw = clk_hw_register_gate(dev, clk_name, parent_name, CLK_SET_RATE_PARENT, + hw = clk_hw_register_gate(dev, clk_name, parent_name, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, reg, shift, clk_gate_flags, &clk_out_lock); if (IS_ERR(hw)) { ret = -EINVAL; diff --git a/drivers/clk/rockchip/clk-rk3308.c b/drivers/clk/rockchip/clk-rk3308.c index 14287533ec1e..6a8e38f11808 100644 --- a/drivers/clk/rockchip/clk-rk3308.c +++ b/drivers/clk/rockchip/clk-rk3308.c @@ -177,8 +177,8 @@ PNAME(mux_spdif_tx_src_p) = { "clk_spdif_tx_div", "clk_spdif_tx_div50" }; PNAME(mux_spdif_tx_p) = { "clk_spdif_tx_src", "clk_spdif_tx_frac", "mclk_i2s0_2ch_in" }; PNAME(mux_spdif_rx_src_p) = { "clk_spdif_rx_div", "clk_spdif_rx_div50" }; PNAME(mux_spdif_rx_p) = { "clk_spdif_rx_src", "clk_spdif_rx_frac" }; -PNAME(mux_uart_src_p) = { "xin24m", "usb480m", "dpll", "vpll0", "vpll1" }; -static u32 uart_src_mux_idx[] = { 4, 3, 0, 1, 2 }; +PNAME(mux_uart_src_p) = { "usb480m", "xin24m", "dpll", "vpll0", "vpll1" }; +static u32 uart_src_mux_idx[] = { 3, 4, 0, 1, 2 }; static struct rockchip_pll_clock rk3308_pll_clks[] __initdata = { [apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p, @@ -335,7 +335,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = { RK3308_CLKSEL_CON(10), 13, 3, MFLAGS, uart_src_mux_idx, 0, 5, DFLAGS, RK3308_CLKGATE_CON(1), 9, GFLAGS), COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_src", CLK_SET_RATE_PARENT, - RK3308_CLKSEL_CON(12), 0, + RK3308_CLKSEL_CON(12), CLK_FRAC_DIVIDER_NO_LIMIT, RK3308_CLKGATE_CON(1), 11, GFLAGS, &rk3308_uart0_fracmux), GATE(SCLK_UART0, "clk_uart0", "clk_uart0_mux", 0, @@ -345,7 +345,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = { RK3308_CLKSEL_CON(13), 13, 3, MFLAGS, uart_src_mux_idx, 0, 5, DFLAGS, RK3308_CLKGATE_CON(1), 13, GFLAGS), COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_src", CLK_SET_RATE_PARENT, - RK3308_CLKSEL_CON(15), 0, + RK3308_CLKSEL_CON(15), CLK_FRAC_DIVIDER_NO_LIMIT, RK3308_CLKGATE_CON(1), 15, GFLAGS, &rk3308_uart1_fracmux), GATE(SCLK_UART1, "clk_uart1", "clk_uart1_mux", 0, @@ -355,7 +355,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = { RK3308_CLKSEL_CON(16), 13, 3, MFLAGS, uart_src_mux_idx, 0, 5, DFLAGS, RK3308_CLKGATE_CON(2), 1, GFLAGS), COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_src", CLK_SET_RATE_PARENT, - RK3308_CLKSEL_CON(18), 0, + RK3308_CLKSEL_CON(18), CLK_FRAC_DIVIDER_NO_LIMIT, RK3308_CLKGATE_CON(2), 3, GFLAGS, &rk3308_uart2_fracmux), GATE(SCLK_UART2, "clk_uart2", "clk_uart2_mux", CLK_SET_RATE_PARENT, @@ -365,7 +365,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = { RK3308_CLKSEL_CON(19), 13, 3, MFLAGS, uart_src_mux_idx, 0, 5, DFLAGS, RK3308_CLKGATE_CON(2), 5, GFLAGS), COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_src", CLK_SET_RATE_PARENT, - RK3308_CLKSEL_CON(21), 0, + RK3308_CLKSEL_CON(21), CLK_FRAC_DIVIDER_NO_LIMIT, RK3308_CLKGATE_CON(2), 7, GFLAGS, &rk3308_uart3_fracmux), GATE(SCLK_UART3, "clk_uart3", "clk_uart3_mux", 0, @@ -375,7 +375,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = { RK3308_CLKSEL_CON(22), 13, 3, MFLAGS, uart_src_mux_idx, 0, 5, DFLAGS, RK3308_CLKGATE_CON(2), 9, GFLAGS), COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_src", CLK_SET_RATE_PARENT, - RK3308_CLKSEL_CON(24), 0, + RK3308_CLKSEL_CON(24), CLK_FRAC_DIVIDER_NO_LIMIT, RK3308_CLKGATE_CON(2), 11, GFLAGS, &rk3308_uart4_fracmux), GATE(SCLK_UART4, "clk_uart4", "clk_uart4_mux", 0, diff --git a/drivers/clk/rockchip/clk-rv1106.c b/drivers/clk/rockchip/clk-rv1106.c index 551c3396bc84..0833bf2adb8b 100644 --- a/drivers/clk/rockchip/clk-rv1106.c +++ b/drivers/clk/rockchip/clk-rv1106.c @@ -1118,7 +1118,7 @@ static void rockchip_rv1106_pvtpll_init(struct rockchip_clk_provider *ctx) /* set pvtpll ref clk mux */ writel_relaxed(CPU_PVTPLL_PATH_CORE, ctx->reg_base + CPU_CLK_PATH_BASE); - regmap_write(ctx->grf, CPU_PVTPLL_CON0_H, HIWORD_UPDATE(0x6, PVTPLL_LENGTH_SEL_MASK, + regmap_write(ctx->grf, CPU_PVTPLL_CON0_H, HIWORD_UPDATE(0x7, PVTPLL_LENGTH_SEL_MASK, PVTPLL_LENGTH_SEL_SHIFT)); regmap_write(ctx->grf, CPU_PVTPLL_CON0_L, HIWORD_UPDATE(0x1, PVTPLL_RING_SEL_MASK, PVTPLL_RING_SEL_SHIFT)); diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c index 9fceae9979e4..ce3e08a22b55 100644 --- a/drivers/cpufreq/rockchip-cpufreq.c +++ b/drivers/cpufreq/rockchip-cpufreq.c @@ -713,7 +713,7 @@ static int rockchip_cpufreq_add_monitor(struct cluster_info *cluster, if (!mdevp) return -ENOMEM; - mdevp->type = MONITOR_TPYE_CPU; + mdevp->type = MONITOR_TYPE_CPU; mdevp->low_temp_adjust = rockchip_monitor_cpu_low_temp_adjust; mdevp->high_temp_adjust = rockchip_monitor_cpu_high_temp_adjust; mdevp->update_volt = rockchip_monitor_check_rate_volt; diff --git a/drivers/crypto/rockchip/rk_crypto_ahash_utils.c b/drivers/crypto/rockchip/rk_crypto_ahash_utils.c index 4e6cc9ad405e..495c55485f14 100644 --- a/drivers/crypto/rockchip/rk_crypto_ahash_utils.c +++ b/drivers/crypto/rockchip/rk_crypto_ahash_utils.c @@ -286,7 +286,6 @@ int rk_ahash_start(struct rk_crypto_dev *rk_dev) struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct rk_crypto_algt *algt = rk_ahash_get_algt(tfm); struct scatterlist *src_sg; - unsigned long flags; unsigned int nbytes; int ret = 0; @@ -378,14 +377,12 @@ int rk_ahash_start(struct rk_crypto_dev *rk_dev) ctx->hash_tmp_len, ctx->lastc_len, nbytes); if (nbytes) { - spin_lock_irqsave(&rk_dev->lock, flags); if (ctx->calc_cnt == 0) alg_ctx->ops.hw_init(rk_dev, algt->algo, algt->type); /* flush all 64byte key buffer for hmac */ alg_ctx->ops.hw_write_key(ctx->rk_dev, ctx->authkey, sizeof(ctx->authkey)); ret = rk_ahash_set_data_start(rk_dev, rctx->flag); - spin_unlock_irqrestore(&rk_dev->lock, flags); } exit: return ret; diff --git a/drivers/crypto/rockchip/rk_crypto_core.c b/drivers/crypto/rockchip/rk_crypto_core.c index 768821fb637e..56a50d5c01de 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.c +++ b/drivers/crypto/rockchip/rk_crypto_core.c @@ -281,10 +281,12 @@ static void rk_crypto_irq_timer_handle(struct timer_list *t) static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) { struct rk_crypto_dev *rk_dev = platform_get_drvdata(dev_id); - struct rk_alg_ctx *alg_ctx = rk_alg_ctx_cast(rk_dev->async_req); + struct rk_alg_ctx *alg_ctx; spin_lock(&rk_dev->lock); + alg_ctx = rk_alg_ctx_cast(rk_dev->async_req); + rk_dev->stat.irq_cnt++; if (alg_ctx->ops.irq_handle) @@ -390,23 +392,22 @@ static void rk_crypto_queue_task_cb(unsigned long data) struct crypto_async_request *async_req, *backlog; unsigned long flags; + spin_lock_irqsave(&rk_dev->lock, flags); if (rk_dev->async_req) { dev_err(rk_dev->dev, "%s: Unexpected crypto paths.\n", __func__); - return; + goto exit; } rk_dev->err = 0; - spin_lock_irqsave(&rk_dev->lock, flags); + backlog = crypto_get_backlog(&rk_dev->queue); async_req = crypto_dequeue_request(&rk_dev->queue); if (!async_req) { rk_dev->busy = false; - spin_unlock_irqrestore(&rk_dev->lock, flags); - return; + goto exit; } rk_dev->stat.dequeue_cnt++; - spin_unlock_irqrestore(&rk_dev->lock, flags); if (backlog) { backlog->complete(backlog, -EINPROGRESS); @@ -417,15 +418,22 @@ static void rk_crypto_queue_task_cb(unsigned long data) rk_dev->err = rk_start_op(rk_dev); if (rk_dev->err) rk_complete_op(rk_dev, rk_dev->err); + +exit: + spin_unlock_irqrestore(&rk_dev->lock, flags); } 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; + unsigned long flags; + + spin_lock_irqsave(&rk_dev->lock, flags); if (!rk_dev->async_req) { dev_err(rk_dev->dev, "done task receive invalid async_req\n"); + spin_unlock_irqrestore(&rk_dev->lock, flags); return; } @@ -447,9 +455,12 @@ static void rk_crypto_done_task_cb(unsigned long data) if (rk_dev->err) goto exit; + spin_unlock_irqrestore(&rk_dev->lock, flags); + return; exit: rk_complete_op(rk_dev, rk_dev->err); + spin_unlock_irqrestore(&rk_dev->lock, flags); } static struct rk_crypto_algt *rk_crypto_find_algs(struct rk_crypto_dev *rk_dev, diff --git a/drivers/crypto/rockchip/rk_crypto_skcipher_utils.c b/drivers/crypto/rockchip/rk_crypto_skcipher_utils.c index 27b4164e3085..7d8d0aafa5f4 100644 --- a/drivers/crypto/rockchip/rk_crypto_skcipher_utils.c +++ b/drivers/crypto/rockchip/rk_crypto_skcipher_utils.c @@ -331,7 +331,6 @@ int rk_ablk_start(struct rk_crypto_dev *rk_dev) struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct rk_crypto_algt *algt = rk_cipher_get_algt(tfm); struct rk_alg_ctx *alg_ctx = rk_cipher_alg_ctx(rk_dev); - unsigned long flags; int err = 0; alg_ctx->left_bytes = req->cryptlen; @@ -345,10 +344,9 @@ int rk_ablk_start(struct rk_crypto_dev *rk_dev) CRYPTO_TRACE("total = %u", alg_ctx->total); - spin_lock_irqsave(&rk_dev->lock, flags); alg_ctx->ops.hw_init(rk_dev, algt->algo, algt->mode); err = rk_set_data_start(rk_dev); - spin_unlock_irqrestore(&rk_dev->lock, flags); + return err; } @@ -443,7 +441,6 @@ int rk_aead_start(struct rk_crypto_dev *rk_dev) struct rk_crypto_algt *algt = rk_aead_get_algt(tfm); struct rk_alg_ctx *alg_ctx = rk_cipher_alg_ctx(rk_dev); unsigned int total = 0, authsize; - unsigned long flags; int err = 0; total = req->cryptlen + req->assoclen; @@ -464,10 +461,9 @@ int rk_aead_start(struct rk_crypto_dev *rk_dev) CRYPTO_TRACE("is_enc = %d, authsize = %u, cryptlen = %u, total = %u, assoclen = %u", ctx->is_enc, authsize, req->cryptlen, alg_ctx->total, alg_ctx->assoclen); - spin_lock_irqsave(&rk_dev->lock, flags); alg_ctx->ops.hw_init(rk_dev, algt->algo, algt->mode); err = rk_set_data_start(rk_dev); - spin_unlock_irqrestore(&rk_dev->lock, flags); + return err; } diff --git a/drivers/crypto/rockchip/rk_crypto_v1_skcipher.c b/drivers/crypto/rockchip/rk_crypto_v1_skcipher.c index 6a8402a68815..dc7a57b80918 100644 --- a/drivers/crypto/rockchip/rk_crypto_v1_skcipher.c +++ b/drivers/crypto/rockchip/rk_crypto_v1_skcipher.c @@ -269,7 +269,6 @@ static int rk_ablk_start(struct rk_crypto_dev *rk_dev) struct skcipher_request *req = skcipher_request_cast(rk_dev->async_req); struct rk_alg_ctx *alg_ctx = rk_alg_ctx_cast(rk_dev); - unsigned long flags; int err = 0; alg_ctx->left_bytes = req->cryptlen; @@ -281,10 +280,9 @@ static int rk_ablk_start(struct rk_crypto_dev *rk_dev) alg_ctx->req_dst = req->dst; alg_ctx->dst_nents = sg_nents_for_len(req->dst, req->cryptlen); - spin_lock_irqsave(&rk_dev->lock, flags); rk_ablk_hw_init(rk_dev); err = rk_set_data_start(rk_dev); - spin_unlock_irqrestore(&rk_dev->lock, flags); + return err; } diff --git a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c index 6ee2a5d40a00..1311ea3d4eac 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c @@ -160,7 +160,7 @@ static int rk_rsa_calc(struct akcipher_request *req, bool encypt) goto exit; out = rk_bn_alloc(key_byte_size); - if (!in) + if (!out) goto exit; tmp_buf = kzalloc(key_byte_size, GFP_KERNEL); diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c index 4aa090e78b0a..e65e4890da7d 100644 --- a/drivers/devfreq/event/rockchip-dfi.c +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -52,6 +52,10 @@ #define RK3368_DFI_EN (0x30003 << 5) #define RK3368_DFI_DIS (0x30000 << 5) +#define RK3528_PMUGRF_OFFSET 0x70000 +#define RK3528_PMUGRF_OS_REG18 0x248 +#define RK3528_PMUGRF_OS_REG19 0x24c + #define MAX_DMC_NUM_CH 4 #define READ_DRAMTYPE_INFO(n) (((n) >> 13) & 0x7) #define READ_CH_INFO(n) (((n) >> 28) & 0x3) @@ -723,6 +727,41 @@ static __maybe_unused __init int rk3328_dfi_init(struct platform_device *pdev, return 0; } +static __maybe_unused __init int rk3528_dfi_init(struct platform_device *pdev, + struct rockchip_dfi *data, + struct devfreq_event_desc *desc) +{ + struct device_node *np = pdev->dev.of_node, *node; + struct resource *res; + u32 val_18, val_19; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->regs)) + return PTR_ERR(data->regs); + + node = of_parse_phandle(np, "rockchip,grf", 0); + if (node) { + data->regmap_grf = syscon_node_to_regmap(node); + if (IS_ERR(data->regmap_grf)) + return PTR_ERR(data->regmap_grf); + } + + regmap_read(data->regmap_grf, RK3528_PMUGRF_OFFSET + RK3528_PMUGRF_OS_REG18, &val_18); + regmap_read(data->regmap_grf, RK3528_PMUGRF_OFFSET + RK3528_PMUGRF_OS_REG19, &val_19); + if (READ_SYSREG_VERSION(val_19) >= 0x3) + data->dram_type = READ_DRAMTYPE_INFO_V3(val_18, val_19); + else + data->dram_type = READ_DRAMTYPE_INFO(val_18); + data->count_rate = 2; + data->ch_msk = 1; + data->clk = NULL; + + desc->ops = &rockchip_dfi_ops; + + return 0; +} + static const struct of_device_id rockchip_dfi_id_match[] = { #ifdef CONFIG_CPU_PX30 { .compatible = "rockchip,px30-dfi", .data = px30_dfi_init }, @@ -745,6 +784,9 @@ static const struct of_device_id rockchip_dfi_id_match[] = { #ifdef CONFIG_CPU_RK3399 { .compatible = "rockchip,rk3399-dfi", .data = rockchip_dfi_init }, #endif +#ifdef CONFIG_CPU_RK3528 + { .compatible = "rockchip,rk3528-dfi", .data = rk3528_dfi_init }, +#endif #ifdef CONFIG_CPU_RK3562 { .compatible = "rockchip,rk3562-dfi", .data = px30_dfi_init }, #endif diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c index 0df9b39f3700..01edb773ea32 100644 --- a/drivers/devfreq/rockchip_dmc.c +++ b/drivers/devfreq/rockchip_dmc.c @@ -180,7 +180,7 @@ static struct pm_qos_request pm_qos; static int rockchip_dmcfreq_opp_helper(struct dev_pm_set_opp_data *data); static struct monitor_dev_profile dmc_mdevp = { - .type = MONITOR_TPYE_DEV, + .type = MONITOR_TYPE_DEV, .low_temp_adjust = rockchip_monitor_dev_low_temp_adjust, .high_temp_adjust = rockchip_monitor_dev_high_temp_adjust, .update_volt = rockchip_monitor_check_rate_volt, @@ -594,12 +594,17 @@ static int rockchip_dmcfreq_get_dev_status(struct device *dev, if (!dmcfreq->info.auto_freq_en) return -EINVAL; + /* + * RK3588 platform may crash if the CPU and MCU access the DFI/DMC + * registers at same time. + */ + rockchip_monitor_volt_adjust_lock(dmcfreq->mdev_info); for (i = 0; i < dmcfreq->edev_count; i++) { ret = devfreq_event_get_event(dmcfreq->edev[i], &edata); if (ret < 0) { dev_err(dev, "failed to get event %s\n", dmcfreq->edev[i]->desc->name); - return ret; + goto out; } if (i == dmcfreq->dfi_id) { stat->busy_time = edata.load_count; @@ -609,7 +614,10 @@ static int rockchip_dmcfreq_get_dev_status(struct device *dev, } } - return 0; +out: + rockchip_monitor_volt_adjust_unlock(dmcfreq->mdev_info); + + return ret; } static int rockchip_dmcfreq_get_cur_freq(struct device *dev, @@ -1763,6 +1771,79 @@ static __maybe_unused int rk3399_dmc_init(struct platform_device *pdev, return 0; } +static __maybe_unused int rk3528_dmc_init(struct platform_device *pdev, + struct rockchip_dmcfreq *dmcfreq) +{ + struct arm_smccc_res res; + int ret; + int complt_irq; + u32 complt_hwirq; + struct irq_data *complt_irq_data; + + res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); + dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1); + if (res.a0 || res.a1 < 0x100) { + dev_err(&pdev->dev, "trusted firmware need update to V1.00 and above.\n"); + return -ENXIO; + } + + /* + * first 4KB is used for interface parameters + * after 4KB is dts parameters + * request share memory size 4KB * 2 + */ + res = sip_smc_request_share_mem(2, SHARE_PAGE_TYPE_DDR); + if (res.a0 != 0) { + dev_err(&pdev->dev, "no ATF memory for init\n"); + return -ENOMEM; + } + ddr_psci_param = (struct share_params *)res.a1; + /* Clear ddr_psci_param, size is 4KB * 2 */ + memset_io(ddr_psci_param, 0x0, 4096 * 2); + + wait_ctrl.dcf_en = 0; + + init_waitqueue_head(&wait_ctrl.wait_wq); + wait_ctrl.wait_en = 1; + wait_ctrl.wait_time_out_ms = 17 * 5; + + complt_irq = platform_get_irq_byname(pdev, "complete"); + if (complt_irq < 0) { + dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", complt_irq); + return complt_irq; + } + wait_ctrl.complt_irq = complt_irq; + + ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq, + 0, dev_name(&pdev->dev), &wait_ctrl); + if (ret < 0) { + dev_err(&pdev->dev, "cannot request complt_irq\n"); + return ret; + } + disable_irq(complt_irq); + + complt_irq_data = irq_get_irq_data(complt_irq); + complt_hwirq = irqd_to_hwirq(complt_irq_data); + ddr_psci_param->complt_hwirq = complt_hwirq; + + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_INIT); + if (res.a0) { + dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", res.a0); + return -ENOMEM; + } + + ret = rockchip_get_freq_info(dmcfreq); + if (ret < 0) { + dev_err(&pdev->dev, "cannot get frequency info\n"); + return ret; + } + dmcfreq->is_set_rate_direct = true; + + dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; + + return 0; +} + static __maybe_unused int rk3568_dmc_init(struct platform_device *pdev, struct rockchip_dmcfreq *dmcfreq) { @@ -2031,7 +2112,7 @@ static const struct of_device_id rockchip_dmcfreq_of_match[] = { { .compatible = "rockchip,rk3399-dmc", .data = rk3399_dmc_init }, #endif #if IS_ENABLED(CONFIG_CPU_RK3528) - { .compatible = "rockchip,rk3528-dmc", .data = NULL }, + { .compatible = "rockchip,rk3528-dmc", .data = rk3528_dmc_init }, #endif #if IS_ENABLED(CONFIG_CPU_RK3562) { .compatible = "rockchip,rk3562-dmc", .data = rk3568_dmc_init }, diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c index 1072dbd753d2..186011fe6463 100644 --- a/drivers/firmware/rockchip_sip.c +++ b/drivers/firmware/rockchip_sip.c @@ -471,16 +471,21 @@ static ulong cpu_logical_map_mpidr(u32 cpu) { #ifdef MODULE /* Empirically, local "cpu_logical_map()" for rockchip platforms */ - ulong mpidr = 0x00; + ulong mpidr = read_cpuid_mpidr(); - if (cpu < 4) - /* 0x00, 0x01, 0x02, 0x03 */ - mpidr = cpu; - else if (cpu < 8) - /* 0x100, 0x101, 0x102, 0x103 */ - mpidr = 0x100 | (cpu - 4); - else - pr_err("Unsupported map cpu: %d\n", cpu); + if (mpidr & MPIDR_MT_BITMASK) { + /* 0x100, 0x200, 0x300, 0x400 ... */ + mpidr = (cpu & 0xff) << 8; + } else { + if (cpu < 4) + /* 0x00, 0x01, 0x02, 0x03 */ + mpidr = cpu; + else if (cpu < 8) + /* 0x100, 0x101, 0x102, 0x103 */ + mpidr = 0x100 | (cpu - 4); + else + pr_err("Unsupported map cpu: %d\n", cpu); + } return mpidr; #else diff --git a/drivers/gpu/arm/bifrost/Kbuild b/drivers/gpu/arm/bifrost/Kbuild index 398e102a0af5..9cadda188fbc 100644 --- a/drivers/gpu/arm/bifrost/Kbuild +++ b/drivers/gpu/arm/bifrost/Kbuild @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2012-2022 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2012-2023 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,7 +69,7 @@ endif # # Driver version string which is returned to userspace via an ioctl -MALI_RELEASE_NAME ?= '"g17p0-01eac0"' +MALI_RELEASE_NAME ?= '"g18p0-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 e530e8c85b17..ca3da57cffd3 100644 --- a/drivers/gpu/arm/bifrost/Kconfig +++ b/drivers/gpu/arm/bifrost/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2012-2022 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2012-2023 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 @@ -112,21 +112,6 @@ config MALI_BIFROST_ENABLE_TRACE Enables tracing in kbase. Trace log available through the "mali_trace" debugfs file, when the CONFIG_DEBUG_FS is enabled -config MALI_FW_CORE_DUMP - bool "Enable support for FW core dump" - depends on MALI_BIFROST && MALI_CSF_SUPPORT - default n - help - Adds ability to request firmware core dump through the "fw_core_dump" - debugfs file - - 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_ARBITER_SUPPORT bool "Enable arbiter support for Mali" depends on MALI_BIFROST && !MALI_CSF_SUPPORT @@ -178,7 +163,19 @@ menuconfig MALI_BIFROST_EXPERT if MALI_BIFROST_EXPERT -config MALI_2MB_ALLOC +config LARGE_PAGE_ALLOC_OVERRIDE + bool "Override default setting of 2MB pages" + depends on MALI_BIFROST && MALI_BIFROST_EXPERT + default n + help + An override config for LARGE_PAGE_ALLOC config. + When LARGE_PAGE_ALLOC_OVERRIDE is Y, 2MB page allocation will be + enabled by LARGE_PAGE_ALLOC. When this is N, the feature will be + enabled when GPU HW satisfies requirements. + + If in doubt, say N + +config LARGE_PAGE_ALLOC bool "Attempt to allocate 2MB pages" depends on MALI_BIFROST && MALI_BIFROST_EXPERT default n @@ -187,6 +184,10 @@ config MALI_2MB_ALLOC allocate 2MB pages from the kernel. This reduces TLB pressure and helps to prevent memory fragmentation. + Note this config applies only when LARGE_PAGE_ALLOC_OVERRIDE config + is enabled and enabling this on a GPU HW that does not satisfy + requirements can cause serious problem. + If in doubt, say N config MALI_MEMORY_FULLY_BACKED @@ -222,14 +223,6 @@ config MALI_BIFROST_ERROR_INJECT help Enables insertion of errors to test module failure and recovery mechanisms. -config MALI_GEM5_BUILD - bool "Enable build of Mali kernel driver for GEM5" - depends on MALI_BIFROST && MALI_BIFROST_EXPERT - default n - help - This option is to do a Mali GEM5 build. - If unsure, say N. - comment "Debug options" depends on MALI_BIFROST && MALI_BIFROST_EXPERT diff --git a/drivers/gpu/arm/bifrost/Makefile b/drivers/gpu/arm/bifrost/Makefile index dfe96d8c37e7..39df298ff01c 100644 --- a/drivers/gpu/arm/bifrost/Makefile +++ b/drivers/gpu/arm/bifrost/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2010-2023 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 @@ -58,10 +58,7 @@ ifeq ($(CONFIG_MALI_BIFROST),m) endif ifeq ($(CONFIG_MALI_CSF_SUPPORT), y) - CONFIG_MALI_FW_CORE_DUMP ?= y CONFIG_MALI_CORESIGHT ?= n - else - CONFIG_MALI_FW_CORE_DUMP ?= n endif # @@ -101,7 +98,8 @@ ifeq ($(CONFIG_MALI_BIFROST),m) else # Prevent misuse when CONFIG_MALI_BIFROST_EXPERT=n CONFIG_MALI_CORESTACK = n - CONFIG_MALI_2MB_ALLOC = n + CONFIG_LARGE_PAGE_ALLOC_OVERRIDE = n + CONFIG_LARGE_PAGE_ALLOC = n CONFIG_MALI_PWRSOFT_765 = n CONFIG_MALI_MEMORY_FULLY_BACKED = n CONFIG_MALI_JOB_DUMP = n @@ -143,7 +141,6 @@ else CONFIG_MALI_KUTF_IRQ_TEST = n CONFIG_MALI_KUTF_CLK_RATE_TRACE = n CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST = n - CONFIG_MALI_FW_CORE_DUMP = n endif # All Mali CONFIG should be listed here @@ -155,14 +152,14 @@ CONFIGS := \ CONFIG_MALI_ARBITRATION \ CONFIG_MALI_PARTITION_MANAGER \ CONFIG_MALI_REAL_HW \ - CONFIG_MALI_GEM5_BUILD \ CONFIG_MALI_BIFROST_DEVFREQ \ CONFIG_MALI_BIFROST_DVFS \ CONFIG_MALI_DMA_BUF_MAP_ON_DEMAND \ CONFIG_MALI_DMA_BUF_LEGACY_COMPAT \ CONFIG_MALI_BIFROST_EXPERT \ CONFIG_MALI_CORESTACK \ - CONFIG_MALI_2MB_ALLOC \ + CONFIG_LARGE_PAGE_ALLOC_OVERRIDE \ + CONFIG_LARGE_PAGE_ALLOC \ CONFIG_MALI_PWRSOFT_765 \ CONFIG_MALI_MEMORY_FULLY_BACKED \ CONFIG_MALI_JOB_DUMP \ @@ -183,7 +180,6 @@ CONFIGS := \ CONFIG_MALI_KUTF_CLK_RATE_TRACE \ CONFIG_MALI_KUTF_MGM_INTEGRATION_TEST \ CONFIG_MALI_XEN \ - CONFIG_MALI_FW_CORE_DUMP \ CONFIG_MALI_CORESIGHT @@ -267,6 +263,12 @@ ifeq ($(CONFIG_GCOV_KERNEL),y) EXTRA_CFLAGS += -DGCOV_PROFILE=1 endif +ifeq ($(CONFIG_MALI_KCOV),y) + KBUILD_CFLAGS += $(call cc-option, -fsanitize-coverage=trace-cmp) + EXTRA_CFLAGS += -DKCOV=1 + EXTRA_CFLAGS += -DKCOV_ENABLE_COMPARISONS=1 +endif + all: $(MAKE) -C $(KDIR) M=$(CURDIR) $(MAKE_ARGS) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" modules 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 7fa134310f7d..02fb00da365c 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c @@ -46,7 +46,7 @@ static struct devfreq_simple_ondemand_data ondemand_data; static struct monitor_dev_profile mali_mdevp = { - .type = MONITOR_TPYE_DEV, + .type = MONITOR_TYPE_DEV, .low_temp_adjust = rockchip_monitor_dev_low_temp_adjust, .high_temp_adjust = rockchip_monitor_dev_high_temp_adjust, .update_volt = rockchip_monitor_check_rate_volt, @@ -304,7 +304,8 @@ kbase_devfreq_status(struct device *dev, struct devfreq_dev_status *stat) stat->private_data = NULL; #if MALI_USE_CSF && defined CONFIG_DEVFREQ_THERMAL - kbase_ipa_reset_data(kbdev); + if (!kbdev->dfc_power.dyn_power_coeff) + kbase_ipa_reset_data(kbdev); #endif return 0; 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 ab27e8bde40e..c7257117e98a 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 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 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 @@ -190,6 +190,27 @@ static u64 select_job_chain(struct kbase_jd_atom *katom) return jc; } +static inline bool kbasep_jm_wait_js_free(struct kbase_device *kbdev, unsigned int js, + struct kbase_context *kctx) +{ + const ktime_t wait_loop_start = ktime_get_raw(); + const s64 max_timeout = (s64)kbdev->js_data.js_free_wait_time_ms; + s64 diff = 0; + + /* wait for the JS_COMMAND_NEXT register to reach the given status value */ + do { + if (!kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT))) + return true; + + diff = ktime_to_ms(ktime_sub(ktime_get_raw(), wait_loop_start)); + } while (diff < max_timeout); + + dev_err(kbdev->dev, "Timeout in waiting for job slot %u to become free for ctx %d_%u", js, + kctx->tgid, kctx->id); + + return false; +} + int kbase_job_hw_submit(struct kbase_device *kbdev, struct kbase_jd_atom *katom, unsigned int js) { struct kbase_context *kctx; @@ -203,8 +224,7 @@ int kbase_job_hw_submit(struct kbase_device *kbdev, struct kbase_jd_atom *katom, kctx = katom->kctx; /* Command register must be available */ - if (WARN(!kbasep_jm_is_js_free(kbdev, js, kctx), - "Attempting to assign to occupied slot %d in kctx %pK\n", js, (void *)kctx)) + if (!kbasep_jm_wait_js_free(kbdev, js, kctx)) return -EPERM; dev_dbg(kctx->kbdev->dev, "Write JS_HEAD_NEXT 0x%llx for atom %pK\n", 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 e4cff1f1e59c..bfd55a6e2160 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-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2016, 2018-2023 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,14 +52,6 @@ static inline char *kbasep_make_job_slot_string(unsigned int js, char *js_string } #endif -#if !MALI_USE_CSF -static inline int kbasep_jm_is_js_free(struct kbase_device *kbdev, unsigned int js, - struct kbase_context *kctx) -{ - return !kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT)); -} -#endif - /** * kbase_job_hw_submit() - Submit a job to the GPU * @kbdev: Device pointer 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 388b37f36a9d..7db2b353b67a 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 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 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 @@ -1001,17 +1001,11 @@ void kbase_backend_slot_update(struct kbase_device *kbdev) other_slots_busy(kbdev, js)) break; -#ifdef CONFIG_MALI_GEM5_BUILD - if (!kbasep_jm_is_js_free(kbdev, js, - katom[idx]->kctx)) - break; -#endif /* Check if this job needs the cycle counter * enabled before submission */ if (katom[idx]->core_req & BASE_JD_REQ_PERMON) - kbase_pm_request_gpu_cycle_counter_l2_is_on( - kbdev); + kbase_pm_request_gpu_cycle_counter_l2_is_on(kbdev); if (!kbase_job_hw_submit(kbdev, katom[idx], js)) { katom[idx]->gpu_rb_state = KBASE_ATOM_GPU_RB_SUBMITTED; @@ -1025,9 +1019,12 @@ void kbase_backend_slot_update(struct kbase_device *kbdev) /* Inform platform at start/finish of atom */ kbasep_platform_event_atom_submit(katom[idx]); - } - else + } else { + if (katom[idx]->core_req & BASE_JD_REQ_PERMON) + kbase_pm_release_gpu_cycle_counter_nolock(kbdev); + break; + } /* ***TRANSITION TO HIGHER STATE*** */ fallthrough; 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 19c345341ea9..6db7031764ea 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 @@ -2024,8 +2024,6 @@ void midgard_model_read_reg(void *h, u32 addr, u32 *const value) *value = gpu_model_get_prfcnt_value(KBASE_IPA_CORE_TYPE_SHADER, counter_index, is_low_word); - } else if (addr == USER_REG(LATEST_FLUSH)) { - *value = 0; } #endif else if (addr == GPU_CONTROL_REG(GPU_FEATURES_LO)) { diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_error_generator.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_error_generator.c index 75b1e7e656c0..f310cc74cb24 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_error_generator.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_error_generator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2015, 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2015, 2018-2023 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 @@ -25,14 +25,17 @@ static struct kbase_error_atom *error_track_list; -unsigned int rand_seed; +#ifdef CONFIG_MALI_ERROR_INJECT_RANDOM + +/** Kernel 6.1.0 has dropped prandom_u32(), use get_random_u32() */ +#if (KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE) +#define prandom_u32 get_random_u32 +#endif /*following error probability are set quite high in order to stress the driver*/ -unsigned int error_probability = 50; /* to be set between 0 and 100 */ +static unsigned int error_probability = 50; /* to be set between 0 and 100 */ /* probability to have multiple error give that there is an error */ -unsigned int multiple_error_probability = 50; - -#ifdef CONFIG_MALI_ERROR_INJECT_RANDOM +static unsigned int multiple_error_probability = 50; /* all the error conditions supported by the model */ #define TOTAL_FAULTS 27 diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.c index b37680ddb29b..e90e4df2f494 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.c @@ -105,7 +105,7 @@ static void serve_mmu_irq(struct work_struct *work) kmem_cache_free(kbdev->irq_slab, data); } -void gpu_device_raise_irq(void *model, enum model_linux_irqs irq) +void gpu_device_raise_irq(void *model, u32 irq) { struct model_irq_data *data; struct kbase_device *kbdev = gpu_device_get_data(model); diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.h b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.h index a1c480eaf49d..8f09afe3d1cc 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.h +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_model_linux.h @@ -124,7 +124,7 @@ void midgard_model_read_reg(void *h, u32 addr, u32 *const value); * * This hook is global to the model Linux framework. */ -void gpu_device_raise_irq(void *model, enum model_linux_irqs irq); +void gpu_device_raise_irq(void *model, u32 irq); /** * gpu_device_set_data() - Private model set data function. 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 d86a388c64fb..5be8acd75d0a 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 @@ -2575,26 +2575,33 @@ void kbase_pm_disable_interrupts(struct kbase_device *kbdev) KBASE_EXPORT_TEST_API(kbase_pm_disable_interrupts); #if MALI_USE_CSF +/** + * update_user_reg_page_mapping - Update the mapping for USER Register page + * + * @kbdev: The kbase device structure for the device. + * + * This function must be called to unmap the dummy or real page from USER Register page + * mapping whenever GPU is powered up or down. The dummy or real page would get + * appropriately mapped in when Userspace reads the LATEST_FLUSH value. + */ static void update_user_reg_page_mapping(struct kbase_device *kbdev) { + struct kbase_context *kctx, *n; + lockdep_assert_held(&kbdev->pm.lock); mutex_lock(&kbdev->csf.reg_lock); - - /* Only if the mappings for USER page exist, update all PTEs associated to it */ - if (kbdev->csf.nr_user_page_mapped > 0) { - if (likely(kbdev->csf.mali_file_inode)) { - /* This would zap the pte corresponding to the mapping of User - * register page for all the Kbase contexts. - */ - unmap_mapping_range(kbdev->csf.mali_file_inode->i_mapping, - BASEP_MEM_CSF_USER_REG_PAGE_HANDLE, PAGE_SIZE, 1); - } else { - dev_err(kbdev->dev, - "Device file inode not exist even if USER page previously mapped"); - } + list_for_each_entry_safe(kctx, n, &kbdev->csf.user_reg.list, csf.user_reg.link) { + /* This would zap the PTE corresponding to the mapping of User + * Register page of the kbase context. The mapping will be reestablished + * when the context (user process) needs to access to the page. + */ + unmap_mapping_range(kbdev->csf.user_reg.filp->f_inode->i_mapping, + kctx->csf.user_reg.file_offset << PAGE_SHIFT, PAGE_SIZE, 1); + list_del_init(&kctx->csf.user_reg.link); + dev_dbg(kbdev->dev, "Updated USER Reg page mapping of ctx %d_%d", kctx->tgid, + kctx->id); } - mutex_unlock(&kbdev->csf.reg_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 6bee1fff324a..1b33461796e2 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_time.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_time.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2016, 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 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 @@ -22,6 +22,8 @@ #include #include #if MALI_USE_CSF +#include +#include #include #endif #include @@ -121,20 +123,29 @@ unsigned int kbase_get_timeout_ms(struct kbase_device *kbdev, /* Only for debug messages, safe default in case it's mis-maintained */ const char *selector_str = "(unknown)"; - if (WARN(!kbdev->lowest_gpu_freq_khz, - "Lowest frequency uninitialized! Using reference frequency for scaling")) { + if (!kbdev->lowest_gpu_freq_khz) { + dev_dbg(kbdev->dev, + "Lowest frequency uninitialized! Using reference frequency for scaling"); freq_khz = DEFAULT_REF_TIMEOUT_FREQ_KHZ; } else { freq_khz = kbdev->lowest_gpu_freq_khz; } switch (selector) { + case MMU_AS_INACTIVE_WAIT_TIMEOUT: + selector_str = "MMU_AS_INACTIVE_WAIT_TIMEOUT"; + nr_cycles = MMU_AS_INACTIVE_WAIT_TIMEOUT_CYCLES; + break; case KBASE_TIMEOUT_SELECTOR_COUNT: default: #if !MALI_USE_CSF WARN(1, "Invalid timeout selector used! Using default value"); nr_cycles = JM_DEFAULT_TIMEOUT_CYCLES; break; + case JM_DEFAULT_JS_FREE_TIMEOUT: + selector_str = "JM_DEFAULT_JS_FREE_TIMEOUT"; + nr_cycles = JM_DEFAULT_JS_FREE_TIMEOUT_CYCLES; + break; #else /* Use Firmware timeout if invalid selection */ WARN(1, @@ -204,3 +215,65 @@ u64 kbase_backend_get_cycle_cnt(struct kbase_device *kbdev) return lo | (((u64) hi1) << 32); } + +#if MALI_USE_CSF +u64 __maybe_unused kbase_backend_time_convert_gpu_to_cpu(struct kbase_device *kbdev, u64 gpu_ts) +{ + if (WARN_ON(!kbdev)) + return 0; + + return div64_u64(gpu_ts * kbdev->backend_time.multiplier, kbdev->backend_time.divisor) + + kbdev->backend_time.offset; +} + +/** + * get_cpu_gpu_time() - Get current CPU and GPU timestamps. + * + * @kbdev: Kbase device. + * @cpu_ts: Output CPU timestamp. + * @gpu_ts: Output GPU timestamp. + * @gpu_cycle: Output GPU cycle counts. + */ +static void get_cpu_gpu_time(struct kbase_device *kbdev, u64 *cpu_ts, u64 *gpu_ts, u64 *gpu_cycle) +{ + struct timespec64 ts; + + kbase_backend_get_gpu_time(kbdev, gpu_cycle, gpu_ts, &ts); + + if (cpu_ts) + *cpu_ts = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; +} +#endif + +int kbase_backend_time_init(struct kbase_device *kbdev) +{ +#if MALI_USE_CSF + u64 cpu_ts = 0; + u64 gpu_ts = 0; + u64 freq; + u64 common_factor; + + get_cpu_gpu_time(kbdev, &cpu_ts, &gpu_ts, NULL); + freq = arch_timer_get_cntfrq(); + + if (!freq) { + dev_warn(kbdev->dev, "arch_timer_get_rate() is zero!"); + return -EINVAL; + } + + common_factor = gcd(NSEC_PER_SEC, freq); + + kbdev->backend_time.multiplier = div64_u64(NSEC_PER_SEC, common_factor); + kbdev->backend_time.divisor = div64_u64(freq, common_factor); + + if (!kbdev->backend_time.divisor) { + dev_warn(kbdev->dev, "CPU to GPU divisor is zero!"); + return -EINVAL; + } + + kbdev->backend_time.offset = cpu_ts - div64_u64(gpu_ts * kbdev->backend_time.multiplier, + kbdev->backend_time.divisor); +#endif + + return 0; +} diff --git a/drivers/gpu/arm/bifrost/build.bp b/drivers/gpu/arm/bifrost/build.bp index 48c1fb44f494..0a61a12d902a 100644 --- a/drivers/gpu/arm/bifrost/build.bp +++ b/drivers/gpu/arm/bifrost/build.bp @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2017-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2017-2023 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 @@ -62,8 +62,11 @@ bob_defaults { mali_dma_buf_legacy_compat: { kbuild_options: ["CONFIG_MALI_DMA_BUF_LEGACY_COMPAT=y"], }, + large_page_alloc_override: { + kbuild_options: ["CONFIG_LARGE_PAGE_ALLOC_OVERRIDE=y"], + }, large_page_alloc: { - kbuild_options: ["CONFIG_MALI_2MB_ALLOC=y"], + kbuild_options: ["CONFIG_LARGE_PAGE_ALLOC=y"], }, mali_memory_fully_backed: { kbuild_options: ["CONFIG_MALI_MEMORY_FULLY_BACKED=y"], @@ -86,9 +89,6 @@ bob_defaults { mali_error_inject: { kbuild_options: ["CONFIG_MALI_BIFROST_ERROR_INJECT=y"], }, - mali_gem5_build: { - kbuild_options: ["CONFIG_MALI_GEM5_BUILD=y"], - }, mali_debug: { kbuild_options: [ "CONFIG_MALI_BIFROST_DEBUG=y", @@ -137,9 +137,6 @@ bob_defaults { platform_is_fpga: { kbuild_options: ["CONFIG_MALI_IS_FPGA=y"], }, - mali_fw_core_dump: { - kbuild_options: ["CONFIG_MALI_FW_CORE_DUMP=y"], - }, mali_coresight: { kbuild_options: ["CONFIG_MALI_CORESIGHT=y"], }, @@ -194,6 +191,15 @@ bob_kernel_module { "platform/*/*.c", "platform/*/*.h", "platform/*/Kbuild", + "platform/*/*/*.c", + "platform/*/*/*.h", + "platform/*/*/Kbuild", + "platform/*/*/*.c", + "platform/*/*/*.h", + "platform/*/*/Kbuild", + "platform/*/*/*/*.c", + "platform/*/*/*/*.h", + "platform/*/*/*/Kbuild", "thirdparty/*.c", "thirdparty/Kbuild", "debug/*.c", diff --git a/drivers/gpu/arm/bifrost/context/mali_kbase_context.c b/drivers/gpu/arm/bifrost/context/mali_kbase_context.c index 792f724f16e4..88be6c2e7587 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-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -22,6 +22,12 @@ /* * Base kernel context APIs */ +#include +#if KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE +#include +#else +#include +#endif #include #include @@ -129,12 +135,50 @@ int kbase_context_common_init(struct kbase_context *kctx) /* creating a context is considered a disjoint event */ kbase_disjoint_event(kctx->kbdev); - spin_lock_init(&kctx->mm_update_lock); kctx->process_mm = NULL; + kctx->task = NULL; atomic_set(&kctx->nonmapped_pages, 0); atomic_set(&kctx->permanent_mapped_pages, 0); - kctx->tgid = current->tgid; - kctx->pid = current->pid; + kctx->tgid = task_tgid_vnr(current); + kctx->pid = task_pid_vnr(current); + + /* Check if this is a Userspace created context */ + if (likely(kctx->filp)) { + struct pid *pid_struct; + + rcu_read_lock(); + pid_struct = find_get_pid(kctx->tgid); + if (likely(pid_struct)) { + struct task_struct *task = pid_task(pid_struct, PIDTYPE_PID); + + if (likely(task)) { + /* Take a reference on the task to avoid slow lookup + * later on from the page allocation loop. + */ + get_task_struct(task); + kctx->task = task; + } else { + dev_err(kctx->kbdev->dev, + "Failed to get task pointer for %s/%d", + current->comm, kctx->pid); + err = -ESRCH; + } + + put_pid(pid_struct); + } else { + dev_err(kctx->kbdev->dev, + "Failed to get pid pointer for %s/%d", + current->comm, kctx->pid); + err = -ESRCH; + } + rcu_read_unlock(); + + if (unlikely(err)) + return err; + + kbase_mem_mmgrab(); + kctx->process_mm = current->mm; + } atomic_set(&kctx->used_pages, 0); @@ -168,13 +212,16 @@ int kbase_context_common_init(struct kbase_context *kctx) kctx->id = atomic_add_return(1, &(kctx->kbdev->ctx_num)) - 1; mutex_lock(&kctx->kbdev->kctx_list_lock); - err = kbase_insert_kctx_to_process(kctx); - if (err) - dev_err(kctx->kbdev->dev, - "(err:%d) failed to insert kctx to kbase_process\n", err); - mutex_unlock(&kctx->kbdev->kctx_list_lock); + if (err) { + dev_err(kctx->kbdev->dev, + "(err:%d) failed to insert kctx to kbase_process", err); + if (likely(kctx->filp)) { + mmdrop(kctx->process_mm); + put_task_struct(kctx->task); + } + } return err; } @@ -260,6 +307,11 @@ void kbase_context_common_term(struct kbase_context *kctx) kbase_remove_kctx_from_process(kctx); mutex_unlock(&kctx->kbdev->kctx_list_lock); + if (likely(kctx->filp)) { + mmdrop(kctx->process_mm); + put_task_struct(kctx->task); + } + KBASE_KTRACE_ADD(kctx->kbdev, CORE_CTX_DESTROY, kctx, 0u); } diff --git a/drivers/gpu/arm/bifrost/context/mali_kbase_context.h b/drivers/gpu/arm/bifrost/context/mali_kbase_context.h index a0c51c90cd23..7c90e2708fa3 100644 --- a/drivers/gpu/arm/bifrost/context/mali_kbase_context.h +++ b/drivers/gpu/arm/bifrost/context/mali_kbase_context.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2011-2017, 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2023 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 @@ -92,6 +92,19 @@ static inline bool kbase_ctx_flag(struct kbase_context *kctx, return atomic_read(&kctx->flags) & flag; } +/** + * kbase_ctx_compat_mode - Indicate whether a kbase context needs to operate + * in compatibility mode for 32-bit userspace. + * @kctx: kbase context + * + * Return: True if needs to maintain compatibility, False otherwise. + */ +static inline bool kbase_ctx_compat_mode(struct kbase_context *kctx) +{ + return !IS_ENABLED(CONFIG_64BIT) || + (IS_ENABLED(CONFIG_64BIT) && kbase_ctx_flag(kctx, KCTX_COMPAT)); +} + /** * kbase_ctx_flag_clear - Clear @flag on @kctx * @kctx: Pointer to kbase context diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c index 5f4061b2ab62..7a939fc3382d 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.c @@ -39,7 +39,9 @@ #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) -#define POWER_DOWN_LATEST_FLUSH_VALUE ((u32)1) + +#define CS_RING_BUFFER_MAX_SIZE ((uint32_t)(1 << 31)) /* 2GiB */ +#define CS_RING_BUFFER_MIN_SIZE ((uint32_t)4096) #define PROTM_ALLOC_MAX_RETRIES ((u8)5) @@ -73,6 +75,38 @@ struct irq_idle_and_protm_track { s8 idle_slot; }; +/** + * kbasep_ctx_user_reg_page_mapping_term() - Terminate resources for USER Register Page. + * + * @kctx: Pointer to the kbase context + */ +static void kbasep_ctx_user_reg_page_mapping_term(struct kbase_context *kctx) +{ + struct kbase_device *kbdev = kctx->kbdev; + + if (unlikely(kctx->csf.user_reg.vma)) + dev_err(kbdev->dev, "VMA for USER Register page exist on termination of ctx %d_%d", + kctx->tgid, kctx->id); + if (WARN_ON_ONCE(!list_empty(&kctx->csf.user_reg.link))) + list_del_init(&kctx->csf.user_reg.link); +} + +/** + * kbasep_ctx_user_reg_page_mapping_init() - Initialize resources for USER Register Page. + * + * @kctx: Pointer to the kbase context + * + * @return: 0 on success. + */ +static int kbasep_ctx_user_reg_page_mapping_init(struct kbase_context *kctx) +{ + INIT_LIST_HEAD(&kctx->csf.user_reg.link); + kctx->csf.user_reg.vma = NULL; + kctx->csf.user_reg.file_offset = 0; + + return 0; +} + static void put_user_pages_mmap_handle(struct kbase_context *kctx, struct kbase_queue *queue) { @@ -267,7 +301,7 @@ int kbase_csf_alloc_command_stream_user_pages(struct kbase_context *kctx, struct ret = kbase_mem_pool_alloc_pages(&kctx->mem_pools.small[KBASE_MEM_GROUP_CSF_IO], KBASEP_NUM_CS_USER_IO_PAGES, - queue->phys, false); + queue->phys, false, kctx->task); if (ret != KBASEP_NUM_CS_USER_IO_PAGES) { /* Marking both the phys to zero for indicating there is no phys allocated */ queue->phys[0].tagged_addr = 0; @@ -293,11 +327,8 @@ int kbase_csf_alloc_command_stream_user_pages(struct kbase_context *kctx, struct queue->db_file_offset = kbdev->csf.db_file_offsets; kbdev->csf.db_file_offsets += BASEP_QUEUE_NR_MMAP_USER_PAGES; -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - WARN(atomic_read(&queue->refcount) != 1, "Incorrect refcounting for queue object\n"); -#else - WARN(refcount_read(&queue->refcount) != 1, "Incorrect refcounting for queue object\n"); -#endif + WARN(kbase_refcount_read(&queue->refcount) != 1, + "Incorrect refcounting for queue object\n"); /* This is the second reference taken on the queue object and * would be dropped only when the IO mapping is removed either * explicitly by userspace or implicitly by kernel on process exit. @@ -369,21 +400,13 @@ static struct kbase_queue *find_queue(struct kbase_context *kctx, u64 base_addr) static void get_queue(struct kbase_queue *queue) { -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - WARN_ON(!atomic_inc_not_zero(&queue->refcount)); -#else - WARN_ON(!refcount_inc_not_zero(&queue->refcount)); -#endif + WARN_ON(!kbase_refcount_inc_not_zero(&queue->refcount)); } static void release_queue(struct kbase_queue *queue) { lockdep_assert_held(&queue->kctx->csf.lock); -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - if (atomic_dec_and_test(&queue->refcount)) { -#else - if (refcount_dec_and_test(&queue->refcount)) { -#endif + if (kbase_refcount_dec_and_test(&queue->refcount)) { /* The queue can't still be on the per context list. */ WARN_ON(!list_empty(&queue->link)); WARN_ON(queue->group); @@ -399,7 +422,7 @@ static void release_queue(struct kbase_queue *queue) * would free up the GPU queue memory. */ kbase_gpu_vm_lock(queue->kctx); - kbase_va_region_no_user_free_put(queue->kctx, queue->queue_reg); + kbase_va_region_no_user_free_dec(queue->queue_reg); kbase_gpu_vm_unlock(queue->kctx); kfree(queue); @@ -505,17 +528,16 @@ static int csf_queue_register_internal(struct kbase_context *kctx, queue->kctx = kctx; queue->base_addr = queue_addr; - queue->queue_reg = kbase_va_region_no_user_free_get(kctx, region); + + queue->queue_reg = region; + kbase_va_region_no_user_free_inc(region); + queue->size = (queue_size << PAGE_SHIFT); queue->csi_index = KBASEP_IF_NR_INVALID; queue->enabled = false; queue->priority = reg->priority; -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - atomic_set(&queue->refcount, 1); -#else - refcount_set(&queue->refcount, 1); -#endif + kbase_refcount_set(&queue->refcount, 1); queue->group = NULL; queue->bind_state = KBASE_CSF_QUEUE_UNBOUND; @@ -572,6 +594,13 @@ out: int kbase_csf_queue_register(struct kbase_context *kctx, struct kbase_ioctl_cs_queue_register *reg) { + /* Validate the ring buffer configuration parameters */ + if (reg->buffer_size < CS_RING_BUFFER_MIN_SIZE || + reg->buffer_size > CS_RING_BUFFER_MAX_SIZE || + reg->buffer_size & (reg->buffer_size - 1) || !reg->buffer_gpu_addr || + reg->buffer_gpu_addr & ~PAGE_MASK) + return -EINVAL; + return csf_queue_register_internal(kctx, reg, NULL); } @@ -590,6 +619,13 @@ int kbase_csf_queue_register_ex(struct kbase_context *kctx, if (glb_version < kbase_csf_interface_version(1, 1, 0)) return -EINVAL; + /* Validate the ring buffer configuration parameters */ + if (reg->buffer_size < CS_RING_BUFFER_MIN_SIZE || + reg->buffer_size > CS_RING_BUFFER_MAX_SIZE || + reg->buffer_size & (reg->buffer_size - 1) || !reg->buffer_gpu_addr || + reg->buffer_gpu_addr & ~PAGE_MASK) + return -EINVAL; + /* Validate the cs_trace configuration parameters */ if (reg->ex_buffer_size && ((reg->ex_event_size > max_size) || @@ -909,6 +945,9 @@ static void unbind_stopped_queue(struct kbase_context *kctx, { lockdep_assert_held(&kctx->csf.lock); + if (WARN_ON(queue->csi_index < 0)) + return; + if (queue->bind_state != KBASE_CSF_QUEUE_UNBOUND) { unsigned long flags; @@ -922,6 +961,7 @@ static void unbind_stopped_queue(struct kbase_context *kctx, kbase_csf_scheduler_spin_unlock(kctx->kbdev, flags); put_user_pages_mmap_handle(kctx, queue); + WARN_ON_ONCE(queue->doorbell_nr != KBASEP_USER_DB_NR_INVALID); queue->bind_state = KBASE_CSF_QUEUE_UNBOUND; } } @@ -1099,7 +1139,7 @@ static int create_normal_suspend_buffer(struct kbase_context *const kctx, /* Get physical page for a normal suspend buffer */ err = kbase_mem_pool_alloc_pages(&kctx->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], nr_pages, - &s_buf->phy[0], false); + &s_buf->phy[0], false, kctx->task); if (err < 0) { kfree(s_buf->phy); @@ -1539,6 +1579,7 @@ void kbase_csf_queue_group_terminate(struct kbase_context *kctx, } KBASE_EXPORT_TEST_API(kbase_csf_queue_group_terminate); +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST int kbase_csf_queue_group_suspend(struct kbase_context *kctx, struct kbase_suspend_copy_buffer *sus_buf, u8 group_handle) @@ -1569,6 +1610,7 @@ int kbase_csf_queue_group_suspend(struct kbase_context *kctx, return err; } +#endif void kbase_csf_add_group_fatal_error( struct kbase_queue_group *const group, @@ -1637,8 +1679,6 @@ int kbase_csf_ctx_init(struct kbase_context *kctx) kbase_csf_event_init(kctx); - kctx->csf.user_reg_vma = NULL; - /* Mark all the cookies as 'free' */ bitmap_fill(kctx->csf.cookies, KBASE_CSF_NUM_USER_IO_PAGES_HANDLE); @@ -1658,7 +1698,14 @@ int kbase_csf_ctx_init(struct kbase_context *kctx) mutex_init(&kctx->csf.lock); INIT_WORK(&kctx->csf.pending_submission_work, pending_submission_worker); - } else + + err = kbasep_ctx_user_reg_page_mapping_init(kctx); + + if (unlikely(err)) + kbase_csf_tiler_heap_context_term(kctx); + } + + if (unlikely(err)) kbase_csf_kcpu_queue_context_term(kctx); } @@ -1816,17 +1863,14 @@ void kbase_csf_ctx_term(struct kbase_context *kctx) * only one reference left that was taken when queue was * registered. */ -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - WARN_ON(atomic_read(&queue->refcount) != 1); -#else - WARN_ON(refcount_read(&queue->refcount) != 1); -#endif + WARN_ON(kbase_refcount_read(&queue->refcount) != 1); list_del_init(&queue->link); release_queue(queue); } mutex_unlock(&kctx->csf.lock); + kbasep_ctx_user_reg_page_mapping_term(kctx); kbase_csf_tiler_heap_context_term(kctx); kbase_csf_kcpu_queue_context_term(kctx); kbase_csf_scheduler_context_term(kctx); @@ -2746,6 +2790,9 @@ static void process_csg_interrupts(struct kbase_device *const kbdev, int const c if ((req ^ ack) & CSG_REQ_IDLE_MASK) { struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; + KBASE_TLSTREAM_TL_KBASE_DEVICE_CSG_IDLE( + kbdev, kbdev->gpu_props.props.raw_props.gpu_id, csg_nr); + kbase_csf_firmware_csg_input_mask(ginfo, CSG_REQ, ack, CSG_REQ_IDLE_MASK); @@ -3159,12 +3206,12 @@ int kbase_csf_doorbell_mapping_init(struct kbase_device *kbdev) struct file *filp; int ret; - filp = shmem_file_setup("mali csf", MAX_LFS_FILESIZE, VM_NORESERVE); + filp = shmem_file_setup("mali csf db", MAX_LFS_FILESIZE, VM_NORESERVE); if (IS_ERR(filp)) return PTR_ERR(filp); ret = kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], 1, &phys, - false); + false, NULL); if (ret <= 0) { fput(filp); @@ -3180,29 +3227,34 @@ int kbase_csf_doorbell_mapping_init(struct kbase_device *kbdev) void kbase_csf_free_dummy_user_reg_page(struct kbase_device *kbdev) { - if (as_phys_addr_t(kbdev->csf.dummy_user_reg_page)) { - struct page *page = as_page(kbdev->csf.dummy_user_reg_page); + if (kbdev->csf.user_reg.filp) { + struct page *page = as_page(kbdev->csf.user_reg.dummy_page); - kbase_mem_pool_free( - &kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], page, - false); + kbase_mem_pool_free(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], page, false); + fput(kbdev->csf.user_reg.filp); } } int kbase_csf_setup_dummy_user_reg_page(struct kbase_device *kbdev) { struct tagged_addr phys; + struct file *filp; struct page *page; u32 *addr; - int ret; - kbdev->csf.dummy_user_reg_page = as_tagged(0); + kbdev->csf.user_reg.filp = NULL; - ret = kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], 1, &phys, - false); + filp = shmem_file_setup("mali csf user_reg", MAX_LFS_FILESIZE, VM_NORESERVE); + if (IS_ERR(filp)) { + dev_err(kbdev->dev, "failed to get an unlinked file for user_reg"); + return PTR_ERR(filp); + } - if (ret <= 0) - return ret; + if (kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], 1, &phys, + false, NULL) <= 0) { + fput(filp); + return -ENOMEM; + } page = as_page(phys); addr = kmap_atomic(page); @@ -3212,12 +3264,13 @@ int kbase_csf_setup_dummy_user_reg_page(struct kbase_device *kbdev) */ addr[LATEST_FLUSH / sizeof(u32)] = POWER_DOWN_LATEST_FLUSH_VALUE; - kbase_sync_single_for_device(kbdev, kbase_dma_addr(page), sizeof(u32), + kbase_sync_single_for_device(kbdev, kbase_dma_addr(page) + LATEST_FLUSH, sizeof(u32), DMA_BIDIRECTIONAL); kunmap_atomic(addr); - kbdev->csf.dummy_user_reg_page = phys; - + kbdev->csf.user_reg.filp = filp; + kbdev->csf.user_reg.dummy_page = phys; + kbdev->csf.user_reg.file_offset = 0; return 0; } diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h index 9fbc932b7905..dd947dcbab1c 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf.h @@ -274,6 +274,7 @@ void kbase_csf_queue_group_terminate(struct kbase_context *kctx, */ void kbase_csf_term_descheduled_queue_group(struct kbase_queue_group *group); +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST /** * kbase_csf_queue_group_suspend - Suspend a GPU command queue group * @@ -291,6 +292,7 @@ void kbase_csf_term_descheduled_queue_group(struct kbase_queue_group *group); */ int kbase_csf_queue_group_suspend(struct kbase_context *kctx, struct kbase_suspend_copy_buffer *sus_buf, u8 group_handle); +#endif /** * kbase_csf_add_group_fatal_error - Report a fatal group error to userspace 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 e4a69cb169c3..6fa0e27d657f 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_defs.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_defs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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,6 +30,7 @@ #include #include "mali_kbase_csf_firmware.h" +#include "mali_kbase_refcount_defs.h" #include "mali_kbase_csf_event.h" #include @@ -269,6 +270,8 @@ enum kbase_queue_group_priority { * @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. + * @MMU_AS_INACTIVE_WAIT_TIMEOUT: Maximum waiting time in ms for the completion + * of a MMU operation * @KBASE_TIMEOUT_SELECTOR_COUNT: Number of timeout selectors. Must be last in * the enum. */ @@ -280,6 +283,7 @@ enum kbase_timeout_selector { CSF_FIRMWARE_BOOT_TIMEOUT, CSF_FIRMWARE_PING_TIMEOUT, CSF_SCHED_PROTM_PROGRESS_TIMEOUT, + MMU_AS_INACTIVE_WAIT_TIMEOUT, /* Must be the last in the enum */ KBASE_TIMEOUT_SELECTOR_COUNT @@ -387,11 +391,7 @@ struct kbase_queue { int doorbell_nr; unsigned long db_file_offset; struct list_head link; -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - atomic_t refcount; -#else - refcount_t refcount; -#endif + kbase_refcount_t refcount; struct kbase_queue_group *group; struct kbase_va_region *queue_reg; struct work_struct oom_event_work; @@ -778,6 +778,23 @@ struct kbase_csf_event { spinlock_t lock; }; +/** + * struct kbase_csf_user_reg_context - Object containing members to manage the mapping + * of USER Register page for a context. + * + * @vma: Pointer to the VMA corresponding to the virtual mapping + * of the USER register page. + * @file_offset: File offset value that is assigned to userspace mapping + * of the USER Register page. It is in page units. + * @link: Links the context to the device list when mapping is pointing to + * either the dummy or the real Register page. + */ +struct kbase_csf_user_reg_context { + struct vm_area_struct *vma; + u32 file_offset; + struct list_head link; +}; + /** * struct kbase_csf_context - Object representing CSF for a GPU address space. * @@ -816,13 +833,11 @@ struct kbase_csf_event { * used by GPU command queues, and progress timeout events. * @link: Link to this csf context in the 'runnable_kctxs' list of * the scheduler instance - * @user_reg_vma: Pointer to the vma corresponding to the virtual mapping - * of the USER register page. Currently used only for sanity - * checking. * @sched: Object representing the scheduler's context * @pending_submission_work: Work item to process pending kicked GPU command queues. * @cpu_queue: CPU queue information. Only be available when DEBUG_FS * is enabled. + * @user_reg: Collective information to support mapping to USER Register page. */ struct kbase_csf_context { struct list_head event_pages_head; @@ -837,12 +852,12 @@ struct kbase_csf_context { struct kbase_csf_tiler_heap_context tiler_heaps; struct workqueue_struct *wq; struct list_head link; - struct vm_area_struct *user_reg_vma; struct kbase_csf_scheduler_context sched; struct work_struct pending_submission_work; #if IS_ENABLED(CONFIG_DEBUG_FS) struct kbase_csf_cpu_queue_context cpu_queue; #endif + struct kbase_csf_user_reg_context user_reg; }; /** @@ -1426,6 +1441,37 @@ struct kbase_csf_dump_on_fault { }; #endif /* CONFIG_DEBUG_FS*/ +/** + * struct kbase_csf_user_reg - Object containing members to manage the mapping + * of USER Register page for all contexts + * + * @dummy_page: Address of a dummy page that is mapped in place + * of the real USER Register page just before the GPU + * is powered down. The USER Register page is mapped + * in the address space of every process, that created + * a Base context, to enable the access to LATEST_FLUSH + * register from userspace. + * @filp: Pointer to a dummy file, that along with @file_offset, + * facilitates the use of unique file offset for the userspace mapping + * created for USER Register page. + * The userspace mapping is made to point to this file + * inside the mmap handler. + * @file_offset: Counter that is incremented every time Userspace creates a mapping of + * USER Register page, to provide a unique file offset range for + * @filp file, so that the CPU PTE of the Userspace mapping can be zapped + * through the kernel function unmap_mapping_range(). + * It is incremented in page units. + * @list: Linked list to maintain user processes(contexts) + * having the mapping to USER Register page. + * It's protected by &kbase_csf_device.reg_lock. + */ +struct kbase_csf_user_reg { + struct tagged_addr dummy_page; + struct file *filp; + u32 file_offset; + struct list_head list; +}; + /** * struct kbase_csf_device - Object representing CSF for an instance of GPU * platform device. @@ -1463,20 +1509,6 @@ struct kbase_csf_dump_on_fault { * of the real Hw doorbell page for the active GPU * command queues after they are stopped or after the * GPU is powered down. - * @dummy_user_reg_page: Address of the dummy page that is mapped in place - * of the real User register page just before the GPU - * is powered down. The User register page is mapped - * in the address space of every process, that created - * a Base context, to enable the access to LATEST_FLUSH - * register from userspace. - * @nr_user_page_mapped: The number of clients using the mapping of USER page. - * This is used to maintain backward compatibility. - * It's protected by @reg_lock. - * @mali_file_inode: Pointer to the inode corresponding to mali device - * file. This is needed in order to switch to the - * @dummy_user_reg_page on GPU power down. - * All instances of the mali device file will point to - * the same inode. It's protected by @reg_lock. * @reg_lock: Lock to serialize the MCU firmware related actions * that affect all contexts such as allocation of * regions from shared interface area, assignment of @@ -1531,7 +1563,7 @@ struct kbase_csf_dump_on_fault { * the @p mcu_core_pwroff_dur_count as an update * to the latter is asynchronous. * @gpu_idle_hysteresis_us: Sysfs attribute for the idle hysteresis time - * window in unit of microseconds. The firmware does not + * window in unit of microseconds. The firmware does not * use it directly. * @gpu_idle_dur_count: The counterpart of the hysteresis time window in * interface required format, ready to be used @@ -1545,6 +1577,8 @@ struct kbase_csf_dump_on_fault { * @fw_core_dump: Contain members required for handling the firmware * core dump. * @dof: Structure for dump on fault. + * @user_reg: Collective information to support the mapping to + * USER Register page for user processes. */ struct kbase_csf_device { struct kbase_mmu_table mcu_mmu; @@ -1558,9 +1592,6 @@ struct kbase_csf_device { struct file *db_filp; u32 db_file_offsets; struct tagged_addr dummy_db_page; - struct tagged_addr dummy_user_reg_page; - u32 nr_user_page_mapped; - struct inode *mali_file_inode; struct mutex reg_lock; wait_queue_head_t event_wait; bool interrupt_received; @@ -1597,6 +1628,7 @@ struct kbase_csf_device { */ struct kbase_debug_coresight_device coresight; #endif /* IS_ENABLED(CONFIG_MALI_CORESIGHT) */ + struct kbase_csf_user_reg user_reg; }; /** @@ -1613,6 +1645,10 @@ struct kbase_csf_device { * @bf_data: Data relating to Bus fault. * @gf_data: Data relating to GPU fault. * @current_setup: Stores the MMU configuration for this address space. + * @is_unresponsive: Flag to indicate MMU is not responding. + * Set if a MMU command isn't completed within + * &kbase_device:mmu_as_inactive_wait_time_ms. + * Clear by kbase_ctx_sched_restore_all_as() after GPU reset completes. */ struct kbase_as { int number; @@ -1624,6 +1660,7 @@ struct kbase_as { struct kbase_fault bf_data; struct kbase_fault gf_data; struct kbase_mmu_setup current_setup; + bool is_unresponsive; }; #endif /* _KBASE_CSF_DEFS_H_ */ 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 548657bc0a38..42bff1e91584 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_firmware.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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 @@ -201,8 +201,8 @@ static int setup_shared_iface_static_region(struct kbase_device *kbdev) if (!interface) return -EINVAL; - reg = kbase_alloc_free_region(&kbdev->csf.shared_reg_rbtree, 0, - interface->num_pages_aligned, KBASE_REG_ZONE_MCU_SHARED); + reg = kbase_alloc_free_region(kbdev, &kbdev->csf.shared_reg_rbtree, 0, + interface->num_pages_aligned, KBASE_REG_ZONE_MCU_SHARED); if (reg) { mutex_lock(&kbdev->csf.reg_lock); ret = kbase_add_va_region_rbtree(kbdev, reg, @@ -296,19 +296,41 @@ static void boot_csf_firmware(struct kbase_device *kbdev) wait_for_firmware_boot(kbdev); } -static void wait_ready(struct kbase_device *kbdev) +/** + * wait_ready() - Wait for previously issued MMU command to complete. + * + * @kbdev: Kbase device to wait for a MMU command to complete. + * + * Reset GPU if the wait for previously issued command times out. + * + * Return: 0 on success, error code otherwise. + */ +static int wait_ready(struct kbase_device *kbdev) { - u32 max_loops = KBASE_AS_INACTIVE_MAX_LOOPS; - u32 val; + const ktime_t wait_loop_start = ktime_get_raw(); + const u32 mmu_as_inactive_wait_time_ms = kbdev->mmu_as_inactive_wait_time_ms; + s64 diff; - val = kbase_reg_read(kbdev, MMU_AS_REG(MCU_AS_NR, AS_STATUS)); + do { + unsigned int i; - /* Wait for a while for the update command to take effect */ - while (--max_loops && (val & AS_STATUS_AS_ACTIVE)) - val = kbase_reg_read(kbdev, MMU_AS_REG(MCU_AS_NR, AS_STATUS)); + for (i = 0; i < 1000; i++) { + /* Wait for the MMU status to indicate there is no active command */ + if (!(kbase_reg_read(kbdev, MMU_AS_REG(MCU_AS_NR, AS_STATUS)) & + AS_STATUS_AS_ACTIVE)) + return 0; + } - if (max_loops == 0) - dev_err(kbdev->dev, "AS_ACTIVE bit stuck, might be caused by slow/unstable GPU clock or possible faulty FPGA connector\n"); + diff = ktime_to_ms(ktime_sub(ktime_get_raw(), wait_loop_start)); + } while (diff < mmu_as_inactive_wait_time_ms); + + dev_err(kbdev->dev, + "AS_ACTIVE bit stuck for MCU AS. Might be caused by unstable GPU clk/pwr or faulty system"); + + if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) + kbase_reset_gpu_locked(kbdev); + + return -ETIMEDOUT; } static void unload_mmu_tables(struct kbase_device *kbdev) @@ -323,7 +345,7 @@ static void unload_mmu_tables(struct kbase_device *kbdev) mutex_unlock(&kbdev->mmu_hw_mutex); } -static void load_mmu_tables(struct kbase_device *kbdev) +static int load_mmu_tables(struct kbase_device *kbdev) { unsigned long irq_flags; @@ -334,7 +356,7 @@ static void load_mmu_tables(struct kbase_device *kbdev) mutex_unlock(&kbdev->mmu_hw_mutex); /* Wait for a while for the update command to take effect */ - wait_ready(kbdev); + return wait_ready(kbdev); } /** @@ -695,7 +717,7 @@ static int parse_memory_setup_entry(struct kbase_device *kbdev, ret = kbase_mem_pool_alloc_pages( kbase_mem_pool_group_select(kbdev, KBASE_MEM_GROUP_CSF_FW, is_small_page), - num_pages_aligned, phys, false); + num_pages_aligned, phys, false, NULL); ignore_page_migration = false; } } @@ -2240,6 +2262,7 @@ int kbase_csf_firmware_early_init(struct kbase_device *kbdev) INIT_LIST_HEAD(&kbdev->csf.firmware_config); INIT_LIST_HEAD(&kbdev->csf.firmware_timeline_metadata); INIT_LIST_HEAD(&kbdev->csf.firmware_trace_buffers.list); + INIT_LIST_HEAD(&kbdev->csf.user_reg.list); INIT_WORK(&kbdev->csf.firmware_reload_work, kbase_csf_firmware_reload_worker); INIT_WORK(&kbdev->csf.fw_error_work, firmware_error_worker); @@ -2403,7 +2426,9 @@ int kbase_csf_firmware_load_init(struct kbase_device *kbdev) kbase_pm_wait_for_l2_powered(kbdev); /* Load the MMU tables into the selected address space */ - load_mmu_tables(kbdev); + ret = load_mmu_tables(kbdev); + if (ret != 0) + goto err_out; boot_csf_firmware(kbdev); @@ -2445,9 +2470,8 @@ int kbase_csf_firmware_load_init(struct kbase_device *kbdev) goto err_out; } -#ifdef CONFIG_MALI_FW_CORE_DUMP - kbase_csf_firmware_core_dump_init(kbdev); -#endif + if (kbdev->csf.fw_core_dump.available) + kbase_csf_firmware_core_dump_init(kbdev); /* Firmware loaded successfully, ret = 0 */ KBASE_KTRACE_ADD(kbdev, CSF_FIRMWARE_BOOT, NULL, @@ -3029,7 +3053,7 @@ int kbase_csf_firmware_mcu_shared_mapping_init( goto page_list_alloc_error; ret = kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], num_pages, - phys, false); + phys, false, NULL); if (ret <= 0) goto phys_mem_pool_alloc_error; @@ -3040,8 +3064,8 @@ int kbase_csf_firmware_mcu_shared_mapping_init( if (!cpu_addr) goto vmap_error; - va_reg = kbase_alloc_free_region(&kbdev->csf.shared_reg_rbtree, 0, - num_pages, KBASE_REG_ZONE_MCU_SHARED); + va_reg = kbase_alloc_free_region(kbdev, &kbdev->csf.shared_reg_rbtree, 0, num_pages, + KBASE_REG_ZONE_MCU_SHARED); if (!va_reg) goto va_region_alloc_error; 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 ab25ed4429e3..833947facce3 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 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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 @@ -1124,6 +1124,7 @@ int kbase_csf_firmware_early_init(struct kbase_device *kbdev) INIT_LIST_HEAD(&kbdev->csf.firmware_interfaces); INIT_LIST_HEAD(&kbdev->csf.firmware_config); INIT_LIST_HEAD(&kbdev->csf.firmware_trace_buffers.list); + INIT_LIST_HEAD(&kbdev->csf.user_reg.list); INIT_WORK(&kbdev->csf.firmware_reload_work, kbase_csf_firmware_reload_worker); INIT_WORK(&kbdev->csf.fw_error_work, firmware_error_worker); @@ -1569,7 +1570,7 @@ int kbase_csf_firmware_mcu_shared_mapping_init( goto page_list_alloc_error; ret = kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], num_pages, - phys, false); + phys, false, NULL); if (ret <= 0) goto phys_mem_pool_alloc_error; @@ -1580,8 +1581,8 @@ int kbase_csf_firmware_mcu_shared_mapping_init( if (!cpu_addr) goto vmap_error; - va_reg = kbase_alloc_free_region(&kbdev->csf.shared_reg_rbtree, 0, - num_pages, KBASE_REG_ZONE_MCU_SHARED); + va_reg = kbase_alloc_free_region(kbdev, &kbdev->csf.shared_reg_rbtree, 0, num_pages, + KBASE_REG_ZONE_MCU_SHARED); if (!va_reg) goto va_region_alloc_error; diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_heap_context_alloc.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_heap_context_alloc.c index 42d19e1b6ad7..7c14b8eb554c 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_heap_context_alloc.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_heap_context_alloc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -100,10 +100,10 @@ static void evict_heap_context(struct kbase_csf_heap_context_allocator *const ct lockdep_assert_held(&ctx_alloc->lock); - /* There is no need to take vm_lock here as the ctx_alloc region is no_user_free - * refcounted. The region and the backing page can't disappear whilst this - * function is executing. - * Flush type is passed as FLUSH_PT to CLN+INV L2 only. + /* There is no need to take vm_lock here as the ctx_alloc region is protected + * via a nonzero no_user_free_count. The region and the backing page can't + * disappear whilst this function is executing. Flush type is passed as FLUSH_PT + * to CLN+INV L2 only. */ kbase_mmu_flush_pa_range(kctx->kbdev, kctx, heap_context_pa, ctx_alloc->heap_context_size_aligned, @@ -181,14 +181,9 @@ void kbase_csf_heap_context_allocator_term( if (ctx_alloc->region) { kbase_gpu_vm_lock(kctx); - /* - * We can't enforce (nor check) the no_user_free refcount - * to be 0 here as other code regions can take such a reference. - * Anyway, this isn't an issue as the region will eventually - * be freed by the region tracker if its refcount didn't drop - * to 0. - */ - kbase_va_region_no_user_free_put(kctx, ctx_alloc->region); + WARN_ON(!kbase_va_region_is_no_user_free(ctx_alloc->region)); + + kbase_va_region_no_user_free_dec(ctx_alloc->region); kbase_mem_free_region(kctx, ctx_alloc->region); kbase_gpu_vm_unlock(kctx); } 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 f1727224b243..2b4d4a437213 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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 @@ -365,15 +365,16 @@ static int kbase_kcpu_jit_allocate_prepare( { struct kbase_context *const kctx = kcpu_queue->kctx; void __user *data = u64_to_user_ptr(alloc_info->info); - struct base_jit_alloc_info *info; + struct base_jit_alloc_info *info = NULL; u32 count = alloc_info->count; int ret = 0; u32 i; lockdep_assert_held(&kcpu_queue->lock); - if (!data || count > kcpu_queue->kctx->jit_max_allocations || - count > ARRAY_SIZE(kctx->jit_alloc)) { + if ((count == 0) || (count > ARRAY_SIZE(kctx->jit_alloc)) || + (count > kcpu_queue->kctx->jit_max_allocations) || (!data) || + !kbase_mem_allow_alloc(kctx)) { ret = -EINVAL; goto out; } @@ -610,6 +611,7 @@ out: return ret; } +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST static int kbase_csf_queue_group_suspend_prepare( struct kbase_kcpu_command_queue *kcpu_queue, struct base_kcpu_command_group_suspend_info *suspend_buf, @@ -681,8 +683,7 @@ static int kbase_csf_queue_group_suspend_prepare( (kbase_reg_current_backed_size(reg) < nr_pages) || !(reg->flags & KBASE_REG_CPU_WR) || (reg->gpu_alloc->type != KBASE_MEM_TYPE_NATIVE) || - (kbase_is_region_shrinkable(reg)) || - (kbase_va_region_is_no_user_free(kctx, reg))) { + (kbase_is_region_shrinkable(reg)) || (kbase_va_region_is_no_user_free(reg))) { ret = -EINVAL; goto out_clean_pages; } @@ -726,6 +727,7 @@ static int kbase_csf_queue_group_suspend_process(struct kbase_context *kctx, { return kbase_csf_queue_group_suspend(kctx, sus_buf, group_handle); } +#endif static enum kbase_csf_event_callback_action event_cqs_callback(void *param) { @@ -1037,9 +1039,12 @@ static int kbase_kcpu_cqs_wait_operation_process(struct kbase_device *kbdev, queue->kctx, cqs_wait_operation->objs[i].addr, &mapping); u64 val = 0; - /* GPUCORE-28172 RDT to review */ - if (!queue->command_started) + if (!queue->command_started) { queue->command_started = true; + KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_START( + kbdev, queue); + } + if (!evt) { dev_warn(kbdev->dev, @@ -1089,7 +1094,8 @@ static int kbase_kcpu_cqs_wait_operation_process(struct kbase_device *kbdev, queue->has_error = true; } - /* GPUCORE-28172 RDT to review */ + KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_END( + kbdev, queue, *(u32 *)evt); queue->command_started = false; } @@ -1232,8 +1238,6 @@ static void kbase_kcpu_cqs_set_operation_process( evt = (uintptr_t)kbase_phy_alloc_mapping_get( queue->kctx, cqs_set_operation->objs[i].addr, &mapping); - /* GPUCORE-28172 RDT to review */ - if (!evt) { dev_warn(kbdev->dev, "Sync memory %llx already freed", cqs_set_operation->objs[i].addr); @@ -1258,7 +1262,8 @@ static void kbase_kcpu_cqs_set_operation_process( break; } - /* GPUCORE-28172 RDT to review */ + KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET_OPERATION( + kbdev, queue, *(u32 *)evt ? 1 : 0); /* Always propagate errors */ *(u32 *)evt = queue->has_error; @@ -1622,11 +1627,7 @@ static int kbasep_kcpu_fence_signal_init(struct kbase_kcpu_command_queue *kcpu_q /* Set reference to KCPU metadata and increment refcount */ kcpu_fence->metadata = kcpu_queue->metadata; -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - WARN_ON(!atomic_inc_not_zero(&kcpu_fence->metadata->refcount)); -#else - WARN_ON(!refcount_inc_not_zero(&kcpu_fence->metadata->refcount)); -#endif + WARN_ON(!kbase_refcount_inc_not_zero(&kcpu_fence->metadata->refcount)); /* create a sync_file fd representing the fence */ *sync_file = sync_file_create(fence_out); @@ -2056,7 +2057,7 @@ static void kcpu_queue_process(struct kbase_kcpu_command_queue *queue, break; } - case BASE_KCPU_COMMAND_TYPE_JIT_FREE: + case BASE_KCPU_COMMAND_TYPE_JIT_FREE: { KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_JIT_FREE_START(kbdev, queue); status = kbase_kcpu_jit_free_process(queue, cmd); @@ -2066,6 +2067,8 @@ static void kcpu_queue_process(struct kbase_kcpu_command_queue *queue, KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_JIT_FREE_END( kbdev, queue); break; + } +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST case BASE_KCPU_COMMAND_TYPE_GROUP_SUSPEND: { struct kbase_suspend_copy_buffer *sus_buf = cmd->info.suspend_buf_copy.sus_buf; @@ -2082,24 +2085,25 @@ static void kcpu_queue_process(struct kbase_kcpu_command_queue *queue, KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_GROUP_SUSPEND_END( kbdev, queue, status); + } - if (!sus_buf->cpu_alloc) { - int i; + if (!sus_buf->cpu_alloc) { + int i; - for (i = 0; i < sus_buf->nr_pages; i++) - put_page(sus_buf->pages[i]); - } else { - kbase_mem_phy_alloc_kernel_unmapped( - sus_buf->cpu_alloc); - kbase_mem_phy_alloc_put( - sus_buf->cpu_alloc); - } + for (i = 0; i < sus_buf->nr_pages; i++) + put_page(sus_buf->pages[i]); + } else { + kbase_mem_phy_alloc_kernel_unmapped( + sus_buf->cpu_alloc); + kbase_mem_phy_alloc_put( + sus_buf->cpu_alloc); } kfree(sus_buf->pages); kfree(sus_buf); break; } +#endif default: dev_dbg(kbdev->dev, "Unrecognized command type"); @@ -2174,12 +2178,29 @@ static void KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_COMMAND( } case BASE_KCPU_COMMAND_TYPE_CQS_WAIT_OPERATION: { - /* GPUCORE-28172 RDT to review */ + const struct base_cqs_wait_operation_info *waits = + cmd->info.cqs_wait_operation.objs; + u32 inherit_err_flags = cmd->info.cqs_wait_operation.inherit_err_flags; + unsigned int i; + + for (i = 0; i < cmd->info.cqs_wait_operation.nr_objs; i++) { + KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT_OPERATION( + kbdev, queue, waits[i].addr, waits[i].val, + waits[i].operation, waits[i].data_type, + (inherit_err_flags & ((uint32_t)1 << i)) ? 1 : 0); + } break; } case BASE_KCPU_COMMAND_TYPE_CQS_SET_OPERATION: { - /* GPUCORE-28172 RDT to review */ + const struct base_cqs_set_operation_info *sets = cmd->info.cqs_set_operation.objs; + unsigned int i; + + for (i = 0; i < cmd->info.cqs_set_operation.nr_objs; i++) { + KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET_OPERATION( + kbdev, queue, sets[i].addr, sets[i].val, + sets[i].operation, sets[i].data_type); + } break; } case BASE_KCPU_COMMAND_TYPE_ERROR_BARRIER: @@ -2226,11 +2247,13 @@ static void KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_COMMAND( KBASE_TLSTREAM_TL_KBASE_ARRAY_END_KCPUQUEUE_ENQUEUE_JIT_FREE(kbdev, queue); break; } +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST case BASE_KCPU_COMMAND_TYPE_GROUP_SUSPEND: KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_GROUP_SUSPEND( kbdev, queue, cmd->info.suspend_buf_copy.sus_buf, cmd->info.suspend_buf_copy.group_handle); break; +#endif default: dev_dbg(kbdev->dev, "Unknown command type %u", cmd->type); break; @@ -2387,11 +2410,13 @@ int kbase_csf_kcpu_queue_enqueue(struct kbase_context *kctx, ret = kbase_kcpu_jit_free_prepare(queue, &command.info.jit_free, kcpu_cmd); break; +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST case BASE_KCPU_COMMAND_TYPE_GROUP_SUSPEND: ret = kbase_csf_queue_group_suspend_prepare(queue, &command.info.suspend_buf_copy, kcpu_cmd); break; +#endif default: dev_dbg(queue->kctx->kbdev->dev, "Unknown command type %u", command.type); @@ -2467,6 +2492,7 @@ int kbase_csf_kcpu_queue_new(struct kbase_context *kctx, { struct kbase_kcpu_command_queue *queue; int idx; + int n; int ret = 0; #if IS_ENABLED(CONFIG_SYNC_FILE) struct kbase_kcpu_dma_fence_meta *metadata; @@ -2519,6 +2545,7 @@ int kbase_csf_kcpu_queue_new(struct kbase_context *kctx, metadata = kzalloc(sizeof(*metadata), GFP_KERNEL); if (!metadata) { + destroy_workqueue(queue->wq); kfree(queue); ret = -ENOMEM; goto out; @@ -2526,14 +2553,17 @@ int kbase_csf_kcpu_queue_new(struct kbase_context *kctx, metadata->kbdev = kctx->kbdev; metadata->kctx_id = kctx->id; - snprintf(metadata->timeline_name, MAX_TIMELINE_NAME, "%d-%d_%d-%lld-kcpu", kctx->kbdev->id, - kctx->tgid, kctx->id, queue->fence_context); + n = snprintf(metadata->timeline_name, MAX_TIMELINE_NAME, "%d-%d_%d-%lld-kcpu", + kctx->kbdev->id, kctx->tgid, kctx->id, queue->fence_context); + if (WARN_ON(n >= MAX_TIMELINE_NAME)) { + destroy_workqueue(queue->wq); + kfree(queue); + kfree(metadata); + ret = -EINVAL; + goto out; + } -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - atomic_set(&metadata->refcount, 1); -#else - refcount_set(&metadata->refcount, 1); -#endif + kbase_refcount_set(&metadata->refcount, 1); queue->metadata = metadata; atomic_inc(&kctx->kbdev->live_fence_metadata); #endif /* CONFIG_SYNC_FILE */ 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 85db53867c06..5cad8b200c93 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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 @@ -186,6 +186,7 @@ struct kbase_suspend_copy_buffer { struct kbase_mem_phy_alloc *cpu_alloc; }; +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST /** * struct kbase_kcpu_command_group_suspend_info - structure which contains * suspend buffer data captured for a suspended queue group. @@ -198,6 +199,7 @@ struct kbase_kcpu_command_group_suspend_info { struct kbase_suspend_copy_buffer *sus_buf; u8 group_handle; }; +#endif /** @@ -232,7 +234,9 @@ struct kbase_kcpu_command { struct kbase_kcpu_command_import_info import; struct kbase_kcpu_command_jit_alloc_info jit_alloc; struct kbase_kcpu_command_jit_free_info jit_free; +#if IS_ENABLED(CONFIG_MALI_VECTOR_DUMP) || MALI_UNIT_TEST struct kbase_kcpu_command_group_suspend_info suspend_buf_copy; +#endif } info; }; diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_mcu_shared_reg.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_mcu_shared_reg.c index 77e19dba4262..4056a9d933d7 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_mcu_shared_reg.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_mcu_shared_reg.c @@ -613,7 +613,7 @@ static int shared_mcu_csg_reg_init(struct kbase_device *kbdev, int err, i; INIT_LIST_HEAD(&csg_reg->link); - reg = kbase_alloc_free_region(&kbdev->csf.shared_reg_rbtree, 0, nr_csg_reg_pages, + reg = kbase_alloc_free_region(kbdev, &kbdev->csf.shared_reg_rbtree, 0, nr_csg_reg_pages, KBASE_REG_ZONE_MCU_SHARED); if (!reg) { @@ -668,16 +668,17 @@ fail_userio_pages_map_fail: while (i-- > 0) { vpfn = CSG_REG_USERIO_VPFN(reg, i, nr_susp_pages); kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, vpfn, shared_regs->dummy_phys, - KBASEP_NUM_CS_USER_IO_PAGES, MCU_AS_NR, true); + KBASEP_NUM_CS_USER_IO_PAGES, KBASEP_NUM_CS_USER_IO_PAGES, + MCU_AS_NR, true); } vpfn = CSG_REG_PMOD_BUF_VPFN(reg, nr_susp_pages); kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, vpfn, shared_regs->dummy_phys, - nr_susp_pages, MCU_AS_NR, true); + nr_susp_pages, nr_susp_pages, MCU_AS_NR, true); fail_pmod_map_fail: vpfn = CSG_REG_SUSP_BUF_VPFN(reg, nr_susp_pages); kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, vpfn, shared_regs->dummy_phys, - nr_susp_pages, MCU_AS_NR, true); + nr_susp_pages, nr_susp_pages, MCU_AS_NR, true); fail_susp_map_fail: mutex_lock(&kbdev->csf.reg_lock); kbase_remove_va_region(kbdev, reg); @@ -701,15 +702,16 @@ static void shared_mcu_csg_reg_term(struct kbase_device *kbdev, for (i = 0; i < nr_csis; i++) { vpfn = CSG_REG_USERIO_VPFN(reg, i, nr_susp_pages); kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, vpfn, shared_regs->dummy_phys, - KBASEP_NUM_CS_USER_IO_PAGES, MCU_AS_NR, true); + KBASEP_NUM_CS_USER_IO_PAGES, KBASEP_NUM_CS_USER_IO_PAGES, + MCU_AS_NR, true); } vpfn = CSG_REG_PMOD_BUF_VPFN(reg, nr_susp_pages); kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, vpfn, shared_regs->dummy_phys, - nr_susp_pages, MCU_AS_NR, true); + nr_susp_pages, nr_susp_pages, MCU_AS_NR, true); vpfn = CSG_REG_SUSP_BUF_VPFN(reg, nr_susp_pages); kbase_mmu_teardown_pages(kbdev, &kbdev->csf.mcu_mmu, vpfn, shared_regs->dummy_phys, - nr_susp_pages, MCU_AS_NR, true); + nr_susp_pages, nr_susp_pages, MCU_AS_NR, true); mutex_lock(&kbdev->csf.reg_lock); kbase_remove_va_region(kbdev, reg); @@ -738,7 +740,7 @@ int kbase_csf_mcu_shared_regs_data_init(struct kbase_device *kbdev) return -ENOMEM; if (kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], 1, - &shared_regs->dummy_phys[0], false) <= 0) + &shared_regs->dummy_phys[0], false, NULL) <= 0) return -ENOMEM; shared_regs->dummy_phys_allocated = true; 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 82389e5bf2a3..b5bf7bbbc056 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_registers.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_registers.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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,10 +31,6 @@ * Begin register sets */ -/* DOORBELLS base address */ -#define DOORBELLS_BASE 0x0080000 -#define DOORBELLS_REG(r) (DOORBELLS_BASE + (r)) - /* CS_KERNEL_INPUT_BLOCK base address */ #define CS_KERNEL_INPUT_BLOCK_BASE 0x0000 #define CS_KERNEL_INPUT_BLOCK_REG(r) (CS_KERNEL_INPUT_BLOCK_BASE + (r)) @@ -71,10 +67,6 @@ #define GLB_OUTPUT_BLOCK_BASE 0x0000 #define GLB_OUTPUT_BLOCK_REG(r) (GLB_OUTPUT_BLOCK_BASE + (r)) -/* USER base address */ -#define USER_BASE 0x0010000 -#define USER_REG(r) (USER_BASE + (r)) - /* End register sets */ /* @@ -267,9 +259,6 @@ #define GLB_DEBUG_ARG_OUT0 0x0FE0 #endif /* CONFIG_MALI_CORESIGHT */ -/* USER register offsets */ -#define LATEST_FLUSH 0x0000 /* () Flush ID of latest clean-and-invalidate operation */ - /* End register offsets */ /* CS_KERNEL_INPUT_BLOCK register set definitions */ @@ -728,6 +717,27 @@ #define CS_FAULT_EXCEPTION_TYPE_ADDR_RANGE_FAULT 0x5A #define CS_FAULT_EXCEPTION_TYPE_IMPRECISE_FAULT 0x5B #define CS_FAULT_EXCEPTION_TYPE_RESOURCE_EVICTION_TIMEOUT 0x69 +#define CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L0 0xC0 +#define CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L1 0xC1 +#define CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L2 0xC2 +#define CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L3 0xC3 +#define CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L4 0xC4 +#define CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_0 0xC8 +#define CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_1 0xC9 +#define CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_2 0xCA +#define CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_3 0xCB +#define CS_FAULT_EXCEPTION_TYPE_ACCESS_FLAG_1 0xD9 +#define CS_FAULT_EXCEPTION_TYPE_ACCESS_FLAG_2 0xDA +#define CS_FAULT_EXCEPTION_TYPE_ACCESS_FLAG_3 0xDB +#define CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_IN 0xE0 +#define CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_0 0xE4 +#define CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_1 0xE5 +#define CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_2 0xE6 +#define CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_3 0xE7 +#define CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_0 0xE8 +#define CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_1 0xE9 +#define CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_2 0xEA +#define CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_3 0xEB /* End of CS_FAULT_EXCEPTION_TYPE values */ #define CS_FAULT_EXCEPTION_DATA_SHIFT 8 #define CS_FAULT_EXCEPTION_DATA_MASK (0xFFFFFF << CS_FAULT_EXCEPTION_DATA_SHIFT) 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 135d3b01a2ff..edaa6d17e304 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_scheduler.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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 @@ -1562,11 +1562,13 @@ static void program_cs(struct kbase_device *kbdev, WARN_ON(csi_index >= ginfo->stream_num)) return; - assign_user_doorbell_to_queue(kbdev, queue); - if (queue->doorbell_nr == KBASEP_USER_DB_NR_INVALID) - return; + if (queue->enabled) { + assign_user_doorbell_to_queue(kbdev, queue); + if (queue->doorbell_nr == KBASEP_USER_DB_NR_INVALID) + return; - WARN_ON(queue->doorbell_nr != queue->group->doorbell_nr); + WARN_ON(queue->doorbell_nr != queue->group->doorbell_nr); + } if (queue->enabled && queue_group_suspended_locked(group)) program_cs_extract_init(queue); @@ -1868,6 +1870,7 @@ static void halt_csg_slot(struct kbase_queue_group *group, bool suspend) unsigned long flags; struct kbase_csf_cmd_stream_group_info *ginfo = &global_iface->groups[slot]; + u32 halt_cmd = suspend ? CSG_REQ_STATE_SUSPEND : CSG_REQ_STATE_TERMINATE; @@ -1885,8 +1888,8 @@ static void halt_csg_slot(struct kbase_queue_group *group, bool suspend) csg_slot[slot].trigger_jiffies = jiffies; 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); + KBASE_TLSTREAM_TL_KBASE_DEVICE_HALTING_CSG( + kbdev, kbdev->gpu_props.props.raw_props.gpu_id, slot, suspend); } } @@ -3441,6 +3444,9 @@ static void program_suspending_csg_slots(struct kbase_device *kbdev) /* The on slot csg is now stopped */ clear_bit(i, slot_mask); + KBASE_TLSTREAM_TL_KBASE_DEVICE_SUSPEND_CSG( + kbdev, kbdev->gpu_props.props.raw_props.gpu_id, i); + if (likely(group)) { bool as_fault; /* Only do save/cleanup if the @@ -5076,6 +5082,9 @@ static int wait_csg_slots_suspend(struct kbase_device *kbdev, unsigned long *slo /* The on slot csg is now stopped */ clear_bit(i, slot_mask_local); + KBASE_TLSTREAM_TL_KBASE_DEVICE_SUSPEND_CSG( + kbdev, kbdev->gpu_props.props.raw_props.gpu_id, i); + group = scheduler->csg_slots[i].resident_group; if (likely(group)) { /* Only do save/cleanup if the @@ -5134,8 +5143,13 @@ static void evict_lru_or_blocked_csg(struct kbase_device *kbdev) if (all_addr_spaces_used) { for (i = 0; i != total_csg_slots; ++i) { - if (scheduler->csg_slots[i].resident_group != NULL) + if (scheduler->csg_slots[i].resident_group != NULL) { + if (WARN_ON(scheduler->csg_slots[i].resident_group->kctx->as_nr < + 0)) + continue; + as_usage[scheduler->csg_slots[i].resident_group->kctx->as_nr]++; + } } } @@ -5156,6 +5170,9 @@ static void evict_lru_or_blocked_csg(struct kbase_device *kbdev) (group->priority != BASE_QUEUE_GROUP_PRIORITY_REALTIME) && ((lru_idle_group == NULL) || (lru_idle_group->prepared_seq_num < group->prepared_seq_num))) { + if (WARN_ON(group->kctx->as_nr < 0)) + continue; + /* If all address spaces are used, we need to ensure the group does not * share the AS with other active CSGs. Or CSG would be freed without AS * and this optimization would not work. diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap.c index 14d80970ff70..8072a8bd2c32 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -228,11 +228,11 @@ static void remove_unlinked_chunk(struct kbase_context *kctx, kbase_vunmap(kctx, &chunk->map); /* KBASE_REG_DONT_NEED regions will be confused with ephemeral regions (inc freed JIT * regions), and so we must clear that flag too before freeing. - * For "no user free", we check that the refcount is 1 as it is a shrinkable region; + * For "no user free count", we check that the count is 1 as it is a shrinkable region; * no other code part within kbase can take a reference to it. */ - WARN_ON(chunk->region->no_user_free_refcnt > 1); - kbase_va_region_no_user_free_put(kctx, chunk->region); + WARN_ON(atomic_read(&chunk->region->no_user_free_count) > 1); + kbase_va_region_no_user_free_dec(chunk->region); #if !defined(CONFIG_MALI_VECTOR_DUMP) chunk->region->flags &= ~KBASE_REG_DONT_NEED; #endif @@ -315,8 +315,8 @@ static struct kbase_csf_tiler_heap_chunk *alloc_new_chunk(struct kbase_context * * It should be fine and not a security risk if we let the region leak till * region tracker termination in such a case. */ - if (unlikely(chunk->region->no_user_free_refcnt > 1)) { - dev_err(kctx->kbdev->dev, "Chunk region has no_user_free_refcnt > 1!\n"); + if (unlikely(atomic_read(&chunk->region->no_user_free_count) > 1)) { + dev_err(kctx->kbdev->dev, "Chunk region has no_user_free_count > 1!\n"); goto unroll_region; } @@ -371,7 +371,7 @@ unroll_region: /* KBASE_REG_DONT_NEED regions will be confused with ephemeral regions (inc freed JIT * regions), and so we must clear that flag too before freeing. */ - kbase_va_region_no_user_free_put(kctx, chunk->region); + kbase_va_region_no_user_free_dec(chunk->region); #if !defined(CONFIG_MALI_VECTOR_DUMP) chunk->region->flags &= ~KBASE_REG_DONT_NEED; #endif @@ -531,7 +531,7 @@ static void delete_heap(struct kbase_csf_tiler_heap *heap) if (heap->buf_desc_reg) { kbase_vunmap(kctx, &heap->buf_desc_map); kbase_gpu_vm_lock(kctx); - kbase_va_region_no_user_free_put(kctx, heap->buf_desc_reg); + kbase_va_region_no_user_free_dec(heap->buf_desc_reg); kbase_gpu_vm_unlock(kctx); } @@ -741,7 +741,8 @@ int kbase_csf_tiler_heap_init(struct kbase_context *const kctx, u32 const chunk_ */ heap->buf_desc_va = buf_desc_va; - heap->buf_desc_reg = kbase_va_region_no_user_free_get(kctx, buf_desc_reg); + heap->buf_desc_reg = buf_desc_reg; + kbase_va_region_no_user_free_inc(buf_desc_reg); vmap_ptr = kbase_vmap_reg(kctx, buf_desc_reg, buf_desc_va, TILER_BUF_DESC_SIZE, KBASE_REG_CPU_RD, &heap->buf_desc_map, @@ -834,7 +835,7 @@ heap_context_alloc_failed: buf_desc_vmap_failed: if (heap->buf_desc_reg) { kbase_gpu_vm_lock(kctx); - kbase_va_region_no_user_free_put(kctx, heap->buf_desc_reg); + kbase_va_region_no_user_free_dec(heap->buf_desc_reg); kbase_gpu_vm_unlock(kctx); } buf_desc_not_suitable: @@ -967,7 +968,12 @@ int kbase_csf_tiler_heap_alloc_new_chunk(struct kbase_context *kctx, err = validate_allocation_request(heap, nr_in_flight, pending_frag_count); if (unlikely(err)) { - dev_err(kctx->kbdev->dev, + /* The allocation request can be legitimate, but be invoked on a heap + * that has already reached the maximum pre-configured capacity. This + * is useful debug information, but should not be treated as an error, + * since the request will be re-sent at a later point. + */ + dev_dbg(kctx->kbdev->dev, "Not allocating new chunk for heap 0x%llX due to current heap state (err %d)", gpu_heap_va, err); mutex_unlock(&kctx->csf.tiler_heaps.lock); diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap_reclaim.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap_reclaim.c index 069e827d16ff..6357e3518d87 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap_reclaim.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tiler_heap_reclaim.c @@ -344,14 +344,6 @@ void kbase_csf_tiler_heap_reclaim_mgr_init(struct kbase_device *kbdev) reclaim->scan_objects = kbase_csf_tiler_heap_reclaim_scan_objects; reclaim->seeks = HEAP_SHRINKER_SEEKS; reclaim->batch = HEAP_SHRINKER_BATCH; - -#if !defined(CONFIG_MALI_VECTOR_DUMP) -#if KERNEL_VERSION(6, 0, 0) > LINUX_VERSION_CODE - register_shrinker(reclaim); -#else - register_shrinker(reclaim, "mali-csf-tiler-heap"); -#endif -#endif } void kbase_csf_tiler_heap_reclaim_mgr_term(struct kbase_device *kbdev) @@ -359,10 +351,6 @@ void kbase_csf_tiler_heap_reclaim_mgr_term(struct kbase_device *kbdev) struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler; u8 prio; -#if !defined(CONFIG_MALI_VECTOR_DUMP) - unregister_shrinker(&scheduler->reclaim_mgr.heap_reclaim); -#endif - for (prio = KBASE_QUEUE_GROUP_PRIORITY_REALTIME; prio < KBASE_QUEUE_GROUP_PRIORITY_COUNT; prio++) WARN_ON(!list_empty(&scheduler->reclaim_mgr.ctx_lists[prio])); diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.c index 71ec91e3de03..6859d65295c4 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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,9 +31,7 @@ #include "mali_kbase_pm.h" #include "mali_kbase_hwaccess_time.h" -#include #include -#include #if IS_ENABLED(CONFIG_DEBUG_FS) #include "tl/mali_kbase_timeline_priv.h" @@ -96,81 +94,6 @@ void kbase_csf_tl_reader_debugfs_init(struct kbase_device *kbdev) } #endif -/** - * get_cpu_gpu_time() - Get current CPU and GPU timestamps. - * - * @kbdev: Kbase device. - * @cpu_ts: Output CPU timestamp. - * @gpu_ts: Output GPU timestamp. - * @gpu_cycle: Output GPU cycle counts. - */ -static void get_cpu_gpu_time( - struct kbase_device *kbdev, - u64 *cpu_ts, - u64 *gpu_ts, - u64 *gpu_cycle) -{ - struct timespec64 ts; - - kbase_pm_context_active(kbdev); - kbase_backend_get_gpu_time(kbdev, gpu_cycle, gpu_ts, &ts); - kbase_pm_context_idle(kbdev); - - if (cpu_ts) - *cpu_ts = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; -} - - -/** - * kbase_ts_converter_init() - Initialize system timestamp converter. - * - * @self: System Timestamp Converter instance. - * @kbdev: Kbase device pointer - * - * Return: Zero on success, -1 otherwise. - */ -static int kbase_ts_converter_init( - struct kbase_ts_converter *self, - struct kbase_device *kbdev) -{ - u64 cpu_ts = 0; - u64 gpu_ts = 0; - u64 freq; - u64 common_factor; - - get_cpu_gpu_time(kbdev, &cpu_ts, &gpu_ts, NULL); - freq = arch_timer_get_cntfrq(); - - if (!freq) { - dev_warn(kbdev->dev, "arch_timer_get_rate() is zero!"); - return -1; - } - - common_factor = gcd(NSEC_PER_SEC, freq); - - self->multiplier = div64_u64(NSEC_PER_SEC, common_factor); - self->divisor = div64_u64(freq, common_factor); - self->offset = - cpu_ts - div64_u64(gpu_ts * self->multiplier, self->divisor); - - return 0; -} - -/** - * kbase_ts_converter_convert() - Convert GPU timestamp to CPU timestamp. - * - * @self: System Timestamp Converter instance. - * @gpu_ts: System timestamp value to converter. - * - * Return: The CPU timestamp. - */ -static u64 __maybe_unused -kbase_ts_converter_convert(const struct kbase_ts_converter *self, u64 gpu_ts) -{ - return div64_u64(gpu_ts * self->multiplier, self->divisor) + - self->offset; -} - /** * tl_reader_overflow_notify() - Emit stream overflow tracepoint. * @@ -321,8 +244,8 @@ int kbase_csf_tl_reader_flush_buffer(struct kbase_csf_tl_reader *self) { struct kbase_csffw_tl_message *msg = (struct kbase_csffw_tl_message *) csffw_data_it; - msg->timestamp = kbase_ts_converter_convert(&self->ts_converter, - msg->timestamp); + msg->timestamp = + kbase_backend_time_convert_gpu_to_cpu(kbdev, msg->timestamp); } /* Copy the message out to the tl_stream. */ @@ -396,9 +319,6 @@ static int tl_reader_init_late( return -1; } - if (kbase_ts_converter_init(&self->ts_converter, kbdev)) - return -1; - self->kbdev = kbdev; self->trace_buffer = tb; self->tl_header.data = hdr; diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.h b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.h index d554d5687484..12b285fd2929 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.h +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_tl_reader.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -39,37 +39,6 @@ struct firmware_trace_buffer; struct kbase_tlstream; struct kbase_device; -/** - * struct kbase_ts_converter - System timestamp to CPU timestamp converter state. - * - * @multiplier: Numerator of the converter's fraction. - * @divisor: Denominator of the converter's fraction. - * @offset: Converter's offset term. - * - * According to Generic timer spec, system timer: - * - Increments at a fixed frequency - * - Starts operating from zero - * - * Hence CPU time is a linear function of System Time. - * - * CPU_ts = alpha * SYS_ts + beta - * - * Where - * - alpha = 10^9/SYS_ts_freq - * - beta is calculated by two timer samples taken at the same time: - * beta = CPU_ts_s - SYS_ts_s * alpha - * - * Since alpha is a rational number, we minimizing possible - * rounding error by simplifying the ratio. Thus alpha is stored - * as a simple `multiplier / divisor` ratio. - * - */ -struct kbase_ts_converter { - u64 multiplier; - u64 divisor; - s64 offset; -}; - /** * struct kbase_csf_tl_reader - CSFFW timeline reader state. * @@ -106,7 +75,6 @@ struct kbase_csf_tl_reader { size_t size; size_t btc; } tl_header; - struct kbase_ts_converter ts_converter; bool got_first_event; bool is_active; 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 e123b3ac57ac..f7054f5b0090 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 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -123,6 +123,10 @@ static int kbase_backend_late_init(struct kbase_device *kbdev) if (err) goto fail_update_l2_features; + err = kbase_backend_time_init(kbdev); + if (err) + goto fail_update_l2_features; + init_waitqueue_head(&kbdev->hwaccess.backend.reset_wait); kbase_pm_context_idle(kbdev); @@ -285,8 +289,10 @@ static const struct kbase_device_init dev_init[] = { "Dummy model initialization failed" }, #else /* !IS_ENABLED(CONFIG_MALI_REAL_HW) */ { assign_irqs, NULL, "IRQ search failed" }, - { registers_map, registers_unmap, "Register map failed" }, #endif /* !IS_ENABLED(CONFIG_MALI_REAL_HW) */ +#if !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) + { registers_map, registers_unmap, "Register map failed" }, +#endif /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */ { power_control_init, power_control_term, "Power control initialization failed" }, { kbase_device_io_history_init, kbase_device_io_history_term, "Register access history initialization failed" }, @@ -359,7 +365,6 @@ static void kbase_device_term_partial(struct kbase_device *kbdev, void kbase_device_term(struct kbase_device *kbdev) { - kbdev->csf.mali_file_inode = NULL; kbase_device_term_partial(kbdev, ARRAY_SIZE(dev_init)); kbase_mem_halt(kbdev); } diff --git a/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_jm.c b/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_jm.c index 6f0ec7d933c4..2d3672383630 100644 --- a/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_jm.c +++ b/drivers/gpu/arm/bifrost/device/backend/mali_kbase_device_jm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -100,6 +100,10 @@ static int kbase_backend_late_init(struct kbase_device *kbdev) if (err) goto fail_update_l2_features; + err = kbase_backend_time_init(kbdev); + if (err) + goto fail_update_l2_features; + init_waitqueue_head(&kbdev->hwaccess.backend.reset_wait); /* Idle the GPU and/or cores, if the policy wants it to */ @@ -211,17 +215,19 @@ static void kbase_device_hwcnt_backend_jm_watchdog_term(struct kbase_device *kbd static const struct kbase_device_init dev_init[] = { #if !IS_ENABLED(CONFIG_MALI_REAL_HW) - { kbase_gpu_device_create, kbase_gpu_device_destroy, - "Dummy model initialization failed" }, + { kbase_gpu_device_create, kbase_gpu_device_destroy, "Dummy model initialization failed" }, #else /* !IS_ENABLED(CONFIG_MALI_REAL_HW) */ { assign_irqs, NULL, "IRQ search failed" }, - { registers_map, registers_unmap, "Register map failed" }, #endif /* !IS_ENABLED(CONFIG_MALI_REAL_HW) */ +#if !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) + { registers_map, registers_unmap, "Register map failed" }, +#endif /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */ { kbase_device_io_history_init, kbase_device_io_history_term, "Register access history initialization failed" }, { kbase_device_pm_init, kbase_device_pm_term, "Power management initialization failed" }, { kbase_device_early_init, kbase_device_early_term, "Early device initialization failed" }, { kbase_device_populate_max_freq, NULL, "Populating max frequency failed" }, + { kbase_pm_lowest_gpu_freq_init, NULL, "Lowest freq initialization failed" }, { kbase_device_misc_init, kbase_device_misc_term, "Miscellaneous device initialization failed" }, { kbase_device_pcm_dev_init, kbase_device_pcm_dev_term, @@ -237,7 +243,6 @@ static const struct kbase_device_init dev_init[] = { "Timeline stream initialization failed" }, { kbase_clk_rate_trace_manager_init, kbase_clk_rate_trace_manager_term, "Clock rate trace manager initialization failed" }, - { kbase_pm_lowest_gpu_freq_init, NULL, "Lowest freq initialization failed" }, { kbase_instr_backend_init, kbase_instr_backend_term, "Instrumentation backend initialization failed" }, { kbase_device_hwcnt_watchdog_if_init, kbase_device_hwcnt_watchdog_if_term, diff --git a/drivers/gpu/arm/bifrost/device/mali_kbase_device.c b/drivers/gpu/arm/bifrost/device/mali_kbase_device.c index 80ee62f64fd2..77093b9a20b9 100644 --- a/drivers/gpu/arm/bifrost/device/mali_kbase_device.c +++ b/drivers/gpu/arm/bifrost/device/mali_kbase_device.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 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 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -308,7 +309,8 @@ int kbase_device_misc_init(struct kbase_device * const kbdev) #endif /* MALI_USE_CSF */ kbdev->mmu_mode = kbase_mmu_mode_get_aarch64(); - + kbdev->mmu_as_inactive_wait_time_ms = + kbase_get_timeout_ms(kbdev, MMU_AS_INACTIVE_WAIT_TIMEOUT); mutex_init(&kbdev->kctx_list_lock); INIT_LIST_HEAD(&kbdev->kctx_list); 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 15bfd0375f0b..60ba9beab91c 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-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -105,6 +105,70 @@ const char *kbase_gpu_exception_name(u32 const exception_code) case GPU_FAULTSTATUS_EXCEPTION_TYPE_GPU_CACHEABILITY_FAULT: e = "GPU_CACHEABILITY_FAULT"; break; + /* MMU Fault */ + case CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L0: + e = "TRANSLATION_FAULT at level 0"; + break; + case CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L1: + e = "TRANSLATION_FAULT at level 1"; + break; + case CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L2: + e = "TRANSLATION_FAULT at level 2"; + break; + case CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L3: + e = "TRANSLATION_FAULT at level 3"; + break; + case CS_FAULT_EXCEPTION_TYPE_TRANSLATION_FAULT_L4: + e = "TRANSLATION_FAULT"; + break; + case CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_0: + e = "PERMISSION_FAULT at level 0"; + break; + case CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_1: + e = "PERMISSION_FAULT at level 1"; + break; + case CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_2: + e = "PERMISSION_FAULT at level 2"; + break; + case CS_FAULT_EXCEPTION_TYPE_PERMISSION_FAULT_3: + e = "PERMISSION_FAULT at level 3"; + break; + case CS_FAULT_EXCEPTION_TYPE_ACCESS_FLAG_1: + e = "ACCESS_FLAG at level 1"; + break; + case CS_FAULT_EXCEPTION_TYPE_ACCESS_FLAG_2: + e = "ACCESS_FLAG at level 2"; + break; + case CS_FAULT_EXCEPTION_TYPE_ACCESS_FLAG_3: + e = "ACCESS_FLAG at level 3"; + break; + case CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_IN: + e = "ADDRESS_SIZE_FAULT_IN"; + break; + case CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_0: + e = "ADDRESS_SIZE_FAULT_OUT_0 at level 0"; + break; + case CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_1: + e = "ADDRESS_SIZE_FAULT_OUT_1 at level 1"; + break; + case CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_2: + e = "ADDRESS_SIZE_FAULT_OUT_2 at level 2"; + break; + case CS_FAULT_EXCEPTION_TYPE_ADDRESS_SIZE_FAULT_OUT_3: + e = "ADDRESS_SIZE_FAULT_OUT_3 at level 3"; + break; + case CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_0: + e = "MEMORY_ATTRIBUTE_FAULT_0 at level 0"; + break; + case CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_1: + e = "MEMORY_ATTRIBUTE_FAULT_1 at level 1"; + break; + case CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_2: + e = "MEMORY_ATTRIBUTE_FAULT_2 at level 2"; + break; + case CS_FAULT_EXCEPTION_TYPE_MEMORY_ATTRIBUTE_FAULT_3: + e = "MEMORY_ATTRIBUTE_FAULT_3 at level 3"; + break; /* Any other exception code is unknown */ default: e = "UNKNOWN"; 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 380ec30d607f..f86f493c7f7e 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 @@ -108,7 +108,6 @@ #define JOB_IRQ_JS_STATE 0x010 /* status==active and _next == busy snapshot from last JOB_IRQ_CLEAR */ #define JOB_IRQ_THROTTLE 0x014 /* cycles to delay delivering an interrupt externally. The JOB_IRQ_STATUS is NOT affected by this, just the delivery of the interrupt. */ -#define JOB_SLOT0 0x800 /* Configuration registers for job slot 0 */ #define JOB_SLOT1 0x880 /* Configuration registers for job slot 1 */ #define JOB_SLOT2 0x900 /* Configuration registers for job slot 2 */ #define JOB_SLOT3 0x980 /* Configuration registers for job slot 3 */ @@ -125,8 +124,6 @@ #define JOB_SLOT14 0xF00 /* Configuration registers for job slot 14 */ #define JOB_SLOT15 0xF80 /* Configuration registers for job slot 15 */ -#define JOB_SLOT_REG(n, r) (JOB_CONTROL_REG(JOB_SLOT0 + ((n) << 7)) + (r)) - #define JS_XAFFINITY 0x1C /* (RO) Extended affinity mask for job slot n*/ #define JS_COMMAND 0x20 /* (WO) Command register for job slot n */ diff --git a/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_fault.h b/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_fault.h index 8b50a5d52e8b..6a937a5ed16d 100644 --- a/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_fault.h +++ b/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_fault.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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,9 +27,9 @@ * * @exception_code: exception code * - * This function is called from the interrupt handler when a GPU fault occurs. + * This function is called by error handlers when GPU reports an error. * - * Return: name associated with the exception code + * Return: Error string associated with the exception code */ const char *kbase_gpu_exception_name(u32 exception_code); 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 282f566c0746..6cef2bdd11e0 100644 --- a/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_regmap.h +++ b/drivers/gpu/arm/bifrost/gpu/mali_kbase_gpu_regmap.h @@ -51,9 +51,7 @@ #define MMU_FEATURES 0x014 /* (RO) MMU features */ #define AS_PRESENT 0x018 /* (RO) Address space slots present */ #define GPU_IRQ_RAWSTAT 0x020 /* (RW) */ -#define GPU_IRQ_CLEAR 0x024 /* (WO) */ #define GPU_IRQ_MASK 0x028 /* (RW) */ -#define GPU_IRQ_STATUS 0x02C /* (RO) */ #define GPU_COMMAND 0x030 /* (WO) */ #define GPU_STATUS 0x034 /* (RO) */ @@ -176,14 +174,9 @@ /* Job control registers */ #define JOB_IRQ_RAWSTAT 0x000 /* Raw interrupt status register */ -#define JOB_IRQ_STATUS 0x00C /* Interrupt status register */ /* MMU control registers */ -#define MMU_IRQ_CLEAR 0x004 /* (WO) Interrupt clear register */ -#define MMU_IRQ_MASK 0x008 /* (RW) Interrupt mask register */ -#define MMU_IRQ_STATUS 0x00C /* (RO) Interrupt status register */ - #define MMU_AS1 0x440 /* Configuration registers for address space 1 */ #define MMU_AS2 0x480 /* Configuration registers for address space 2 */ #define MMU_AS3 0x4C0 /* Configuration registers for address space 3 */ diff --git a/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf.c b/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf.c index 10d40bedc0f8..4a429a6cd1ae 100644 --- a/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf.c +++ b/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2021-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2021-2023 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 @@ -289,6 +289,8 @@ kbasep_hwcnt_backend_csf_cc_initial_sample(struct kbase_hwcnt_backend_csf *backe u64 cycle_counts[BASE_MAX_NR_CLOCKS_REGULATORS]; size_t clk; + memset(cycle_counts, 0, sizeof(cycle_counts)); + /* Read cycle count from CSF interface for both clock domains. */ backend_csf->info->csf_if->get_gpu_cycle_count(backend_csf->info->csf_if->ctx, cycle_counts, clk_enable_map); @@ -308,6 +310,8 @@ static void kbasep_hwcnt_backend_csf_cc_update(struct kbase_hwcnt_backend_csf *b u64 cycle_counts[BASE_MAX_NR_CLOCKS_REGULATORS]; size_t clk; + memset(cycle_counts, 0, sizeof(cycle_counts)); + backend_csf->info->csf_if->assert_lock_held(backend_csf->info->csf_if->ctx); backend_csf->info->csf_if->get_gpu_cycle_count(backend_csf->info->csf_if->ctx, cycle_counts, @@ -558,7 +562,7 @@ static void kbasep_hwcnt_backend_csf_accumulate_samples(struct kbase_hwcnt_backe u32 insert_index_to_stop) { u32 raw_idx; - unsigned long flags; + unsigned long flags = 0UL; u8 *cpu_dump_base = (u8 *)backend_csf->ring_buf_cpu_base; const size_t ring_buf_cnt = backend_csf->info->ring_buf_cnt; const size_t buf_dump_bytes = backend_csf->info->prfcnt_info.dump_bytes; @@ -639,7 +643,7 @@ static void kbasep_hwcnt_backend_watchdog_timer_cb(void *info) { struct kbase_hwcnt_backend_csf_info *csf_info = info; struct kbase_hwcnt_backend_csf *backend_csf; - unsigned long flags; + unsigned long flags = 0UL; csf_info->csf_if->lock(csf_info->csf_if->ctx, &flags); @@ -658,8 +662,8 @@ static void kbasep_hwcnt_backend_watchdog_timer_cb(void *info) /* 3. dump state indicates no other dumping is in progress. */ ((backend_csf->dump_state == KBASE_HWCNT_BACKEND_CSF_DUMP_IDLE) || (backend_csf->dump_state == KBASE_HWCNT_BACKEND_CSF_DUMP_COMPLETED))) { - u32 extract_index; - u32 insert_index; + u32 extract_index = 0U; + u32 insert_index = 0U; /* Read the raw extract and insert indexes from the CSF interface. */ csf_info->csf_if->get_indexes(csf_info->csf_if->ctx, &extract_index, &insert_index); @@ -700,11 +704,11 @@ static void kbasep_hwcnt_backend_watchdog_timer_cb(void *info) */ static void kbasep_hwcnt_backend_csf_dump_worker(struct work_struct *work) { - unsigned long flags; + unsigned long flags = 0ULL; struct kbase_hwcnt_backend_csf *backend_csf; u32 insert_index_to_acc; - u32 extract_index; - u32 insert_index; + u32 extract_index = 0U; + u32 insert_index = 0U; WARN_ON(!work); backend_csf = container_of(work, struct kbase_hwcnt_backend_csf, hwc_dump_work); @@ -776,10 +780,10 @@ static void kbasep_hwcnt_backend_csf_dump_worker(struct work_struct *work) */ static void kbasep_hwcnt_backend_csf_threshold_worker(struct work_struct *work) { - unsigned long flags; + unsigned long flags = 0ULL; struct kbase_hwcnt_backend_csf *backend_csf; - u32 extract_index; - u32 insert_index; + u32 extract_index = 0U; + u32 insert_index = 0U; WARN_ON(!work); @@ -920,7 +924,7 @@ static int kbasep_hwcnt_backend_csf_dump_enable(struct kbase_hwcnt_backend *back const struct kbase_hwcnt_enable_map *enable_map) { int errcode; - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf *backend_csf = (struct kbase_hwcnt_backend_csf *)backend; if (!backend_csf) @@ -954,7 +958,7 @@ static void kbasep_hwcnt_backend_csf_wait_enable_transition_complete( /* CSF backend implementation of kbase_hwcnt_backend_dump_disable_fn */ static void kbasep_hwcnt_backend_csf_dump_disable(struct kbase_hwcnt_backend *backend) { - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf *backend_csf = (struct kbase_hwcnt_backend_csf *)backend; bool do_disable = false; @@ -1050,7 +1054,7 @@ static void kbasep_hwcnt_backend_csf_dump_disable(struct kbase_hwcnt_backend *ba static int kbasep_hwcnt_backend_csf_dump_request(struct kbase_hwcnt_backend *backend, u64 *dump_time_ns) { - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf *backend_csf = (struct kbase_hwcnt_backend_csf *)backend; bool do_request = false; bool watchdog_dumping = false; @@ -1157,7 +1161,7 @@ static int kbasep_hwcnt_backend_csf_dump_request(struct kbase_hwcnt_backend *bac /* CSF backend implementation of kbase_hwcnt_backend_dump_wait_fn */ static int kbasep_hwcnt_backend_csf_dump_wait(struct kbase_hwcnt_backend *backend) { - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf *backend_csf = (struct kbase_hwcnt_backend_csf *)backend; int errcode; @@ -1365,7 +1369,7 @@ alloc_error: static int kbasep_hwcnt_backend_csf_init(const struct kbase_hwcnt_backend_info *info, struct kbase_hwcnt_backend **out_backend) { - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf *backend_csf = NULL; struct kbase_hwcnt_backend_csf_info *csf_info = (struct kbase_hwcnt_backend_csf_info *)info; int errcode; @@ -1407,7 +1411,7 @@ static int kbasep_hwcnt_backend_csf_init(const struct kbase_hwcnt_backend_info * /* CSF backend implementation of kbase_hwcnt_backend_term_fn */ static void kbasep_hwcnt_backend_csf_term(struct kbase_hwcnt_backend *backend) { - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf *backend_csf = (struct kbase_hwcnt_backend_csf *)backend; if (!backend) @@ -1619,7 +1623,7 @@ void kbase_hwcnt_backend_csf_protm_exited(struct kbase_hwcnt_backend_interface * void kbase_hwcnt_backend_csf_on_unrecoverable_error(struct kbase_hwcnt_backend_interface *iface) { - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf_info *csf_info; csf_info = (struct kbase_hwcnt_backend_csf_info *)iface->info; @@ -1639,7 +1643,7 @@ void kbase_hwcnt_backend_csf_on_unrecoverable_error(struct kbase_hwcnt_backend_i void kbase_hwcnt_backend_csf_on_before_reset(struct kbase_hwcnt_backend_interface *iface) { - unsigned long flags; + unsigned long flags = 0UL; struct kbase_hwcnt_backend_csf_info *csf_info; struct kbase_hwcnt_backend_csf *backend_csf; diff --git a/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf_if_fw.c b/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf_if_fw.c index f412531ab03a..b11f3a4e50e2 100644 --- a/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf_if_fw.c +++ b/drivers/gpu/arm/bifrost/hwcnt/backend/mali_kbase_hwcnt_backend_csf_if_fw.c @@ -329,7 +329,7 @@ static int kbasep_hwcnt_backend_csf_if_fw_ring_buf_alloc( /* Get physical page for the buffer */ ret = kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], num_pages, - phys, false); + phys, false, NULL); if (ret != num_pages) goto phys_mem_pool_alloc_error; @@ -482,7 +482,8 @@ kbasep_hwcnt_backend_csf_if_fw_ring_buf_free(struct kbase_hwcnt_backend_csf_if_c 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, true)); + fw_ring_buf->num_pages, fw_ring_buf->num_pages, + MCU_AS_NR, true)); vunmap(fw_ring_buf->cpu_dump_base); diff --git a/drivers/gpu/arm/bifrost/hwcnt/mali_kbase_hwcnt.c b/drivers/gpu/arm/bifrost/hwcnt/mali_kbase_hwcnt.c index e724572560d5..34deb5d9e3fc 100644 --- a/drivers/gpu/arm/bifrost/hwcnt/mali_kbase_hwcnt.c +++ b/drivers/gpu/arm/bifrost/hwcnt/mali_kbase_hwcnt.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2018, 2020-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 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 @@ -362,7 +362,7 @@ static int kbasep_hwcnt_accumulator_dump(struct kbase_hwcnt_context *hctx, u64 * bool cur_map_any_enabled; struct kbase_hwcnt_enable_map *cur_map; bool new_map_any_enabled = false; - u64 dump_time_ns; + u64 dump_time_ns = 0; struct kbase_hwcnt_accumulator *accum; WARN_ON(!hctx); diff --git a/drivers/gpu/arm/bifrost/ipa/backend/mali_kbase_ipa_counter_jm.c b/drivers/gpu/arm/bifrost/ipa/backend/mali_kbase_ipa_counter_jm.c index cc61f642399c..2092db042dec 100644 --- a/drivers/gpu/arm/bifrost/ipa/backend/mali_kbase_ipa_counter_jm.c +++ b/drivers/gpu/arm/bifrost/ipa/backend/mali_kbase_ipa_counter_jm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2016-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2016-2023 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 @@ -455,16 +455,14 @@ static const struct kbase_ipa_group ipa_groups_def_tbax[] = { }, }; - -#define IPA_POWER_MODEL_OPS(gpu, init_token) \ - const struct kbase_ipa_model_ops kbase_ ## gpu ## _ipa_model_ops = { \ - .name = "mali-" #gpu "-power-model", \ - .init = kbase_ ## init_token ## _power_model_init, \ - .term = kbase_ipa_vinstr_common_model_term, \ - .get_dynamic_coeff = kbase_ipa_vinstr_dynamic_coeff, \ - .reset_counter_data = kbase_ipa_vinstr_reset_data, \ - }; \ - KBASE_EXPORT_TEST_API(kbase_ ## gpu ## _ipa_model_ops) +#define IPA_POWER_MODEL_OPS(gpu, init_token) \ + static const struct kbase_ipa_model_ops kbase_##gpu##_ipa_model_ops = { \ + .name = "mali-" #gpu "-power-model", \ + .init = kbase_##init_token##_power_model_init, \ + .term = kbase_ipa_vinstr_common_model_term, \ + .get_dynamic_coeff = kbase_ipa_vinstr_dynamic_coeff, \ + .reset_counter_data = kbase_ipa_vinstr_reset_data, \ + } #define STANDARD_POWER_MODEL(gpu, reference_voltage) \ static int kbase_ ## gpu ## _power_model_init(\ 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 fe8995aefc37..debc3ad25fd7 100644 --- a/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_defs.h +++ b/drivers/gpu/arm/bifrost/jm/mali_kbase_jm_defs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -127,10 +127,17 @@ /** * enum kbase_timeout_selector - The choice of which timeout to get scaled * using the lowest GPU frequency. + * @MMU_AS_INACTIVE_WAIT_TIMEOUT: Maximum waiting time in ms for the completion + * of a MMU operation + * @JM_DEFAULT_JS_FREE_TIMEOUT: Maximum timeout to wait for JS_COMMAND_NEXT + * to be updated on HW side so a Job Slot is + * considered free. * @KBASE_TIMEOUT_SELECTOR_COUNT: Number of timeout selectors. Must be last in * the enum. */ enum kbase_timeout_selector { + MMU_AS_INACTIVE_WAIT_TIMEOUT, + JM_DEFAULT_JS_FREE_TIMEOUT, /* Must be the last in the enum */ KBASE_TIMEOUT_SELECTOR_COUNT @@ -852,6 +859,10 @@ struct jsctx_queue { * @pf_data: Data relating to Page fault. * @bf_data: Data relating to Bus fault. * @current_setup: Stores the MMU configuration for this address space. + * @is_unresponsive: Flag to indicate MMU is not responding. + * Set if a MMU command isn't completed within + * &kbase_device:mmu_as_inactive_wait_time_ms. + * Clear by kbase_ctx_sched_restore_all_as() after GPU reset completes. */ struct kbase_as { int number; @@ -861,6 +872,7 @@ struct kbase_as { struct kbase_fault pf_data; struct kbase_fault bf_data; struct kbase_mmu_setup current_setup; + bool is_unresponsive; }; #endif /* _KBASE_JM_DEFS_H_ */ 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 3d91efdf9d72..465cf7ec05bd 100644 --- a/drivers/gpu/arm/bifrost/jm/mali_kbase_js_defs.h +++ b/drivers/gpu/arm/bifrost/jm/mali_kbase_js_defs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2011-2018, 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2023 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 @@ -277,6 +277,7 @@ typedef u32 kbase_atom_ordering_flag_t; * @nr_contexts_runnable:Number of contexts that can either be pulled from or * arecurrently running * @soft_job_timeout_ms:Value for JS_SOFT_JOB_TIMEOUT + * @js_free_wait_time_ms: Maximum waiting time in ms for a Job Slot to be seen free. * @queue_mutex: Queue Lock, used to access the Policy's queue of contexts * independently of the Run Pool. * Of course, you don't need the Run Pool lock to access this. @@ -329,6 +330,8 @@ struct kbasep_js_device_data { u32 nr_contexts_pullable; atomic_t nr_contexts_runnable; atomic_t soft_job_timeout_ms; + u32 js_free_wait_time_ms; + struct mutex queue_mutex; /* * Run Pool mutex, for managing contexts within the runpool. diff --git a/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h b/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h index c6fea791b8c9..11aedef80109 100644 --- a/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h +++ b/drivers/gpu/arm/bifrost/mali_base_hwconfig_features.h @@ -40,6 +40,7 @@ enum base_hw_feature { BASE_HW_FEATURE_FLUSH_INV_SHADER_OTHER, BASE_HW_FEATURE_CORE_FEATURES, BASE_HW_FEATURE_PBHA_HWU, + BASE_HW_FEATURE_LARGE_PAGE_ALLOC, 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 2dc0402197de..0fbdec0bb0b6 100644 --- a/drivers/gpu/arm/bifrost/mali_base_hwconfig_issues.h +++ b/drivers/gpu/arm/bifrost/mali_base_hwconfig_issues.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2014-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 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 @@ -796,6 +796,19 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p2 BASE_HW_ISSUE_END }; +__attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p3[] = { + BASE_HW_ISSUE_TSIX_2033, + 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_TITANHW_2710, + BASE_HW_ISSUE_TITANHW_2679, + BASE_HW_ISSUE_GPU2022PRO_148, + BASE_HW_ISSUE_END +}; + __attribute__((unused)) static const enum base_hw_issue base_hw_issues_model_tTIx[] = { BASE_HW_ISSUE_TSIX_2033, BASE_HW_ISSUE_TTRX_1337, diff --git a/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h b/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h index 152ae2dfda8d..14493a77e1ea 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_config_defaults.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2013-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2013-2023 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 @@ -221,6 +221,16 @@ enum { */ #define JM_DEFAULT_RESET_TIMEOUT_MS (1) /* 1 ms */ +/* Default timeout in clock cycles to be used when checking if JS_COMMAND_NEXT + * is updated on HW side so a Job Slot is considered free. + * This timeout will only take effect on GPUs with low value for the minimum + * GPU clock frequency (<= 100MHz). + * + * Based on 1ms timeout at 100MHz. Will default to 0ms on GPUs with higher + * value for minimum GPU clock frequency. + */ +#define JM_DEFAULT_JS_FREE_TIMEOUT_CYCLES (100000) + #endif /* MALI_USE_CSF */ /* Default timeslice that a context is scheduled in for, in nanoseconds. @@ -257,5 +267,12 @@ enum { */ #define DEFAULT_IR_THRESHOLD (192) +/* Waiting time in clock cycles for the completion of a MMU operation. + * + * Ideally 1.6M GPU cycles required for the L2 cache (512KiB slice) flush. + * + * As a pessimistic value, 50M GPU cycles ( > 30 times bigger ) is chosen. + * It corresponds to 0.5s in GPU @ 100Mhz. + */ +#define MMU_AS_INACTIVE_WAIT_TIMEOUT_CYCLES ((u64)50 * 1024 * 1024) #endif /* _KBASE_CONFIG_DEFAULTS_H_ */ - diff --git a/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c b/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c index 7eb6b5a798ce..12d6cc8963a3 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 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 @@ -1573,7 +1573,6 @@ static int kbasep_ioctl_cs_cpu_queue_dump(struct kbase_context *kctx, cpu_queue_info->size); } -#define POWER_DOWN_LATEST_FLUSH_VALUE ((u32)1) static int kbase_ioctl_read_user_page(struct kbase_context *kctx, union kbase_ioctl_read_user_page *user_page) { @@ -2059,6 +2058,7 @@ static long kbase_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct kbase_ioctl_cs_cpu_queue_info, kctx); break; + /* This IOCTL will be kept for backward compatibility */ case KBASE_IOCTL_READ_USER_PAGE: KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_READ_USER_PAGE, kbase_ioctl_read_user_page, union kbase_ioctl_read_user_page, kctx); @@ -2225,7 +2225,10 @@ KBASE_EXPORT_TEST_API(kbase_event_wakeup); #if MALI_USE_CSF int kbase_event_pending(struct kbase_context *ctx) { - WARN_ON_ONCE(!ctx); + KBASE_DEBUG_ASSERT(ctx); + + if (unlikely(!ctx)) + return -EPERM; return (atomic_read(&ctx->event_count) != 0) || kbase_csf_event_error_pending(ctx) || @@ -2236,6 +2239,9 @@ int kbase_event_pending(struct kbase_context *ctx) { KBASE_DEBUG_ASSERT(ctx); + if (unlikely(!ctx)) + return -EPERM; + return (atomic_read(&ctx->event_count) != 0) || (atomic_read(&ctx->event_closed) != 0); } @@ -4284,7 +4290,7 @@ void kbase_protected_mode_term(struct kbase_device *kbdev) kfree(kbdev->protected_dev); } -#if !IS_ENABLED(CONFIG_MALI_REAL_HW) +#if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) static int kbase_common_reg_map(struct kbase_device *kbdev) { return 0; @@ -4292,7 +4298,7 @@ static int kbase_common_reg_map(struct kbase_device *kbdev) static void kbase_common_reg_unmap(struct kbase_device * const kbdev) { } -#else /* !IS_ENABLED(CONFIG_MALI_REAL_HW) */ +#else /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */ static int kbase_common_reg_map(struct kbase_device *kbdev) { int err = 0; @@ -4328,7 +4334,7 @@ static void kbase_common_reg_unmap(struct kbase_device * const kbdev) kbdev->reg_size = 0; } } -#endif /* !IS_ENABLED(CONFIG_MALI_REAL_HW) */ +#endif /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */ int registers_map(struct kbase_device * const kbdev) { diff --git a/drivers/gpu/arm/bifrost/mali_kbase_ctx_sched.c b/drivers/gpu/arm/bifrost/mali_kbase_ctx_sched.c index beb292862b21..dc6feb95a391 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_ctx_sched.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_ctx_sched.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2017-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2017-2023 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 @@ -242,6 +242,7 @@ void kbase_ctx_sched_restore_all_as(struct kbase_device *kbdev) for (i = 0; i != kbdev->nr_hw_address_spaces; ++i) { struct kbase_context *kctx; + kbdev->as[i].is_unresponsive = false; #if MALI_USE_CSF if ((i == MCU_AS_NR) && kbdev->csf.firmware_inited) { kbase_mmu_update(kbdev, &kbdev->csf.mcu_mmu, diff --git a/drivers/gpu/arm/bifrost/mali_kbase_debug_mem_allocs.c b/drivers/gpu/arm/bifrost/mali_kbase_debug_mem_allocs.c index 598d8f594644..418bb19086bb 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_debug_mem_allocs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_debug_mem_allocs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2022-2023 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 @@ -26,7 +26,7 @@ #include "mali_kbase_debug_mem_allocs.h" #include "mali_kbase.h" -#include +#include #include #include diff --git a/drivers/gpu/arm/bifrost/mali_kbase_debugfs_helper.c b/drivers/gpu/arm/bifrost/mali_kbase_debugfs_helper.c index 4c1aa281f38a..c846491e78fb 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_debugfs_helper.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_debugfs_helper.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -90,11 +90,10 @@ set_attr_from_string(char *const buf, void *const array, size_t const nelems, int kbase_debugfs_string_validator(char *const buf) { - size_t index; int err = 0; char *ptr = buf; - for (index = 0; *ptr; ++index) { + while (*ptr) { unsigned long test_number; size_t len; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_defs.h b/drivers/gpu/arm/bifrost/mali_kbase_defs.h index 80f76145e393..809e73000c4d 100755 --- a/drivers/gpu/arm/bifrost/mali_kbase_defs.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_defs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2023 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 @@ -245,12 +245,25 @@ struct kbase_fault { bool protected_mode; }; +/** Maximum number of memory pages that should be allocated for the array + * of pointers to free PGDs. + * + * This number has been pre-calculated to deal with the maximum allocation + * size expressed by the default value of KBASE_MEM_ALLOC_MAX_SIZE. + * This is supposed to be enough for almost the entirety of MMU operations. + * Any size greater than KBASE_MEM_ALLOC_MAX_SIZE requires being broken down + * into multiple iterations, each dealing with at most KBASE_MEM_ALLOC_MAX_SIZE + * bytes. + * + * Please update this value if KBASE_MEM_ALLOC_MAX_SIZE changes. + */ +#define MAX_PAGES_FOR_FREE_PGDS ((size_t)9) + +/* Maximum number of pointers to free PGDs */ +#define MAX_FREE_PGDS ((PAGE_SIZE / sizeof(struct page *)) * MAX_PAGES_FOR_FREE_PGDS) + /** * struct kbase_mmu_table - object representing a set of GPU page tables - * @mmu_teardown_pages: Array containing pointers to 3 separate pages, used - * to cache the entries of top (L0) & intermediate level - * page tables (L1 & L2) to avoid repeated calls to - * kmap_atomic() during the MMU teardown. * @mmu_lock: Lock to serialize the accesses made to multi level GPU * page tables * @pgd: Physical address of the page allocated for the top @@ -262,14 +275,40 @@ struct kbase_fault { * Valid range is 0..(MEMORY_GROUP_MANAGER_NR_GROUPS-1). * @kctx: If this set of MMU tables belongs to a context then * this is a back-reference to the context, otherwise - * it is NULL + * it is NULL. + * @scratch_mem: Scratch memory used for MMU operations, which are + * serialized by the @mmu_lock. */ struct kbase_mmu_table { - u64 *mmu_teardown_pages[MIDGARD_MMU_BOTTOMLEVEL]; struct mutex mmu_lock; phys_addr_t pgd; u8 group_id; struct kbase_context *kctx; + union { + /** + * @teardown_pages: Scratch memory used for backup copies of whole + * PGD pages when tearing down levels upon + * termination of the MMU table. + */ + struct { + /** + * @levels: Array of PGD pages, large enough to copy one PGD + * for each level of the MMU table. + */ + u64 levels[MIDGARD_MMU_BOTTOMLEVEL][PAGE_SIZE / sizeof(u64)]; + } teardown_pages; + /** + * @free_pgds: Scratch memory user for insertion, update and teardown + * operations to store a temporary list of PGDs to be freed + * at the end of the operation. + */ + struct { + /** @pgds: Array of pointers to PGDs to free. */ + struct page *pgds[MAX_FREE_PGDS]; + /** @head_index: Index of first free element in the PGDs array. */ + size_t head_index; + } free_pgds; + } scratch_mem; }; /** @@ -293,6 +332,8 @@ struct kbase_reg_zone { #include "jm/mali_kbase_jm_defs.h" #endif +#include "mali_kbase_hwaccess_time.h" + static inline int kbase_as_has_bus_fault(struct kbase_as *as, struct kbase_fault *fault) { @@ -762,6 +803,8 @@ struct kbase_mem_migrate { * GPU adrress spaces assigned to them. * @mmu_mask_change: Lock to serialize the access to MMU interrupt mask * register used in the handling of Bus & Page faults. + * @pagesize_2mb: Boolean to determine whether 2MiB page sizes are + * supported and used where possible. * @gpu_props: Object containing complete information about the * configuration/properties of GPU HW device in use. * @hw_issues_mask: List of SW workarounds for HW issues @@ -807,6 +850,7 @@ struct kbase_mem_migrate { * GPU reset. * @lowest_gpu_freq_khz: Lowest frequency in KHz that the GPU can run at. Used * to calculate suitable timeouts for wait operations. + * @backend_time: Kbase backend time related attributes. * @cache_clean_in_progress: Set when a cache clean has been started, and * cleared when it has finished. This prevents multiple * cache cleans being done simultaneously. @@ -1001,6 +1045,9 @@ struct kbase_mem_migrate { * KCPU queue. These structures may outlive kbase module * itself. Therefore, in such a case, a warning should be * be produced. + * @mmu_as_inactive_wait_time_ms: Maximum waiting time in ms for the completion of + * a MMU operation + * @va_region_slab: kmem_cache (slab) for allocated kbase_va_region structures. */ struct kbase_device { u32 hw_quirks_sc; @@ -1057,6 +1104,8 @@ struct kbase_device { spinlock_t mmu_mask_change; + bool pagesize_2mb; + struct kbase_gpu_props gpu_props; unsigned long hw_issues_mask[(BASE_HW_ISSUE_END + BITS_PER_LONG - 1) / BITS_PER_LONG]; @@ -1110,6 +1159,10 @@ struct kbase_device { u64 lowest_gpu_freq_khz; +#if MALI_USE_CSF + struct kbase_backend_time backend_time; +#endif + bool cache_clean_in_progress; u32 cache_clean_queued; wait_queue_head_t cache_clean_wait; @@ -1308,6 +1361,8 @@ struct kbase_device { #if MALI_USE_CSF && IS_ENABLED(CONFIG_SYNC_FILE) atomic_t live_fence_metadata; #endif + u32 mmu_as_inactive_wait_time_ms; + struct kmem_cache *va_region_slab; }; /** @@ -1661,11 +1716,13 @@ struct kbase_sub_alloc { * is scheduled in and an atom is pulled from the context's per * slot runnable tree in JM GPU or GPU command queue * group is programmed on CSG slot in CSF GPU. - * @mm_update_lock: lock used for handling of special tracking page. * @process_mm: Pointer to the memory descriptor of the process which * created the context. Used for accounting the physical * pages used for GPU allocations, done for the context, - * to the memory consumed by the process. + * to the memory consumed by the process. A reference is taken + * on this descriptor for the Userspace created contexts so that + * Kbase can safely access it to update the memory usage counters. + * The reference is dropped on context termination. * @gpu_va_end: End address of the GPU va space (in 4KB page units) * @running_total_tiler_heap_nr_chunks: Running total of number of chunks in all * tiler heaps of the kbase context. @@ -1787,6 +1844,10 @@ struct kbase_sub_alloc { * @limited_core_mask: The mask that is applied to the affinity in case of atoms * marked with BASE_JD_REQ_LIMITED_CORE_MASK. * @platform_data: Pointer to platform specific per-context data. + * @task: Pointer to the task structure of the main thread of the process + * that created the Kbase context. It would be set only for the + * contexts created by the Userspace and not for the contexts + * created internally by the Kbase. * * A kernel base context is an entity among which the GPU is scheduled. * Each context has its own GPU address space. @@ -1874,8 +1935,7 @@ struct kbase_context { atomic_t refcount; - spinlock_t mm_update_lock; - struct mm_struct __rcu *process_mm; + struct mm_struct *process_mm; u64 gpu_va_end; #if MALI_USE_CSF u32 running_total_tiler_heap_nr_chunks; @@ -1938,6 +1998,8 @@ struct kbase_context { #if !MALI_USE_CSF void *platform_data; #endif + + struct task_struct *task; }; #ifdef CONFIG_MALI_CINSTR_GWT @@ -2040,5 +2102,4 @@ static inline u64 kbase_get_lock_region_min_size_log2(struct kbase_gpu_props con #define KBASE_AS_INACTIVE_MAX_LOOPS 100000000 /* Maximum number of loops polling the GPU PRFCNT_ACTIVE bit before we assume the GPU has hung */ #define KBASE_PRFCNT_ACTIVE_MAX_LOOPS 100000000 - #endif /* _KBASE_DEFS_H_ */ diff --git a/drivers/gpu/arm/bifrost/mali_kbase_fence.h b/drivers/gpu/arm/bifrost/mali_kbase_fence.h index 25986f604c6c..f4507ac4309b 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_fence.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_fence.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2010-2018, 2020-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 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 @@ -32,6 +32,7 @@ #include #include "mali_kbase_fence_defs.h" #include "mali_kbase.h" +#include "mali_kbase_refcount_defs.h" #if MALI_USE_CSF /* Maximum number of characters in DMA fence timeline name. */ @@ -49,11 +50,7 @@ * @timeline_name: String of timeline name for associated fence object. */ struct kbase_kcpu_dma_fence_meta { -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - atomic_t refcount; -#else - refcount_t refcount; -#endif + kbase_refcount_t refcount; struct kbase_device *kbdev; int kctx_id; char timeline_name[MAX_TIMELINE_NAME]; @@ -225,11 +222,7 @@ static inline struct kbase_kcpu_dma_fence *kbase_kcpu_dma_fence_get(struct dma_f static inline void kbase_kcpu_dma_fence_meta_put(struct kbase_kcpu_dma_fence_meta *metadata) { -#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) - if (atomic_dec_and_test(&metadata->refcount)) { -#else - if (refcount_dec_and_test(&metadata->refcount)) { -#endif + if (kbase_refcount_dec_and_test(&metadata->refcount)) { atomic_dec(&metadata->kbdev->live_fence_metadata); kfree(metadata); } diff --git a/drivers/gpu/arm/bifrost/mali_kbase_gwt.c b/drivers/gpu/arm/bifrost/mali_kbase_gwt.c index 16cccee02184..0eba889e5b19 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_gwt.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_gwt.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 @@ -125,14 +125,17 @@ int kbase_gpu_gwt_stop(struct kbase_context *kctx) return 0; } - +#if (KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE) +static int list_cmp_function(void *priv, const struct list_head *a, const struct list_head *b) +#else static int list_cmp_function(void *priv, struct list_head *a, struct list_head *b) +#endif { - struct kbasep_gwt_list_element *elementA = container_of(a, - struct kbasep_gwt_list_element, link); - struct kbasep_gwt_list_element *elementB = container_of(b, - struct kbasep_gwt_list_element, link); + const struct kbasep_gwt_list_element *elementA = + container_of(a, struct kbasep_gwt_list_element, link); + const struct kbasep_gwt_list_element *elementB = + container_of(b, struct kbasep_gwt_list_element, link); CSTD_UNUSED(priv); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_hw.c b/drivers/gpu/arm/bifrost/mali_kbase_hw.c index c658fb79429b..b07327a55c0a 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_hw.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_hw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2012-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2012-2023 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 @@ -232,6 +232,7 @@ static const enum base_hw_issue *kbase_hw_get_issues_for_new_id( { GPU_ID2_VERSION_MAKE(1, 0, 0), base_hw_issues_tTUx_r1p0 }, { GPU_ID2_VERSION_MAKE(1, 1, 0), base_hw_issues_tTUx_r1p1 }, { GPU_ID2_VERSION_MAKE(1, 2, 0), base_hw_issues_tTUx_r1p2 }, + { GPU_ID2_VERSION_MAKE(1, 3, 0), base_hw_issues_tTUx_r1p3 }, { U32_MAX, NULL } } }, { GPU_ID2_PRODUCT_LTUX, @@ -239,6 +240,7 @@ static const enum base_hw_issue *kbase_hw_get_issues_for_new_id( { GPU_ID2_VERSION_MAKE(1, 0, 0), base_hw_issues_tTUx_r1p0 }, { GPU_ID2_VERSION_MAKE(1, 1, 0), base_hw_issues_tTUx_r1p1 }, { GPU_ID2_VERSION_MAKE(1, 2, 0), base_hw_issues_tTUx_r1p2 }, + { GPU_ID2_VERSION_MAKE(1, 3, 0), base_hw_issues_tTUx_r1p3 }, { U32_MAX, NULL } } }, { GPU_ID2_PRODUCT_TTIX, @@ -303,21 +305,20 @@ static const enum base_hw_issue *kbase_hw_get_issues_for_new_id( */ issues = fallback_issues; - dev_warn(kbdev->dev, - "GPU hardware issue table may need updating:\n" - "r%dp%d status %d is unknown; treating as r%dp%d status %d", - (gpu_id & GPU_ID2_VERSION_MAJOR) >> - GPU_ID2_VERSION_MAJOR_SHIFT, - (gpu_id & GPU_ID2_VERSION_MINOR) >> - GPU_ID2_VERSION_MINOR_SHIFT, - (gpu_id & GPU_ID2_VERSION_STATUS) >> - GPU_ID2_VERSION_STATUS_SHIFT, - (fallback_version & GPU_ID2_VERSION_MAJOR) >> - GPU_ID2_VERSION_MAJOR_SHIFT, - (fallback_version & GPU_ID2_VERSION_MINOR) >> - GPU_ID2_VERSION_MINOR_SHIFT, - (fallback_version & GPU_ID2_VERSION_STATUS) >> - GPU_ID2_VERSION_STATUS_SHIFT); + dev_notice(kbdev->dev, "r%dp%d status %d not found in HW issues table;\n", + (gpu_id & GPU_ID2_VERSION_MAJOR) >> GPU_ID2_VERSION_MAJOR_SHIFT, + (gpu_id & GPU_ID2_VERSION_MINOR) >> GPU_ID2_VERSION_MINOR_SHIFT, + (gpu_id & GPU_ID2_VERSION_STATUS) >> + GPU_ID2_VERSION_STATUS_SHIFT); + dev_notice(kbdev->dev, "falling back to closest match: r%dp%d status %d\n", + (fallback_version & GPU_ID2_VERSION_MAJOR) >> + GPU_ID2_VERSION_MAJOR_SHIFT, + (fallback_version & GPU_ID2_VERSION_MINOR) >> + GPU_ID2_VERSION_MINOR_SHIFT, + (fallback_version & GPU_ID2_VERSION_STATUS) >> + GPU_ID2_VERSION_STATUS_SHIFT); + dev_notice(kbdev->dev, + "Execution proceeding normally with fallback match\n"); gpu_id &= ~GPU_ID2_VERSION; gpu_id |= fallback_version; @@ -343,7 +344,7 @@ int kbase_hw_set_issues_mask(struct kbase_device *kbdev) issues = kbase_hw_get_issues_for_new_id(kbdev); if (issues == NULL) { dev_err(kbdev->dev, - "Unknown GPU ID %x", gpu_id); + "HW product - Unknown GPU ID %x", gpu_id); return -EINVAL; } @@ -407,7 +408,7 @@ int kbase_hw_set_issues_mask(struct kbase_device *kbdev) break; default: dev_err(kbdev->dev, - "Unknown GPU ID %x", gpu_id); + "HW issues - Unknown GPU ID %x", gpu_id); return -EINVAL; } } diff --git a/drivers/gpu/arm/bifrost/mali_kbase_hwaccess_time.h b/drivers/gpu/arm/bifrost/mali_kbase_hwaccess_time.h index 27e2cb7b9170..ac2a26d28d89 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_hwaccess_time.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_hwaccess_time.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2014, 2018-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014, 2018-2021, 2023 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 @@ -22,6 +22,49 @@ #ifndef _KBASE_BACKEND_TIME_H_ #define _KBASE_BACKEND_TIME_H_ +#if MALI_USE_CSF +/** + * struct kbase_backend_time - System timestamp attributes. + * + * @multiplier: Numerator of the converter's fraction. + * @divisor: Denominator of the converter's fraction. + * @offset: Converter's offset term. + * + * According to Generic timer spec, system timer: + * - Increments at a fixed frequency + * - Starts operating from zero + * + * Hence CPU time is a linear function of System Time. + * + * CPU_ts = alpha * SYS_ts + beta + * + * Where + * - alpha = 10^9/SYS_ts_freq + * - beta is calculated by two timer samples taken at the same time: + * beta = CPU_ts_s - SYS_ts_s * alpha + * + * Since alpha is a rational number, we minimizing possible + * rounding error by simplifying the ratio. Thus alpha is stored + * as a simple `multiplier / divisor` ratio. + * + */ +struct kbase_backend_time { + u64 multiplier; + u64 divisor; + s64 offset; +}; + +/** + * kbase_backend_time_convert_gpu_to_cpu() - Convert GPU timestamp to CPU timestamp. + * + * @kbdev: Kbase device pointer + * @gpu_ts: System timestamp value to converter. + * + * Return: The CPU timestamp. + */ +u64 __maybe_unused kbase_backend_time_convert_gpu_to_cpu(struct kbase_device *kbdev, u64 gpu_ts); +#endif + /** * kbase_backend_get_gpu_time() - Get current GPU time * @kbdev: Device pointer @@ -46,9 +89,6 @@ void kbase_backend_get_gpu_time_norequest(struct kbase_device *kbdev, u64 *cycle_counter, u64 *system_time, struct timespec64 *ts); - -#endif /* _KBASE_BACKEND_TIME_H_ */ - /** * kbase_get_timeout_ms - Choose a timeout value to get a timeout scaled * GPU frequency, using a choice from @@ -70,3 +110,17 @@ unsigned int kbase_get_timeout_ms(struct kbase_device *kbdev, * Return: Snapshot of the GPU cycle count register. */ u64 kbase_backend_get_cycle_cnt(struct kbase_device *kbdev); + +/** + * kbase_backend_time_init() - Initialize system timestamp converter. + * + * @kbdev: Kbase device pointer + * + * This function should only be called after GPU is powered-up and + * L2 cached power-up has been initiated. + * + * Return: Zero on success, error code otherwise. + */ +int kbase_backend_time_init(struct kbase_device *kbdev); + +#endif /* _KBASE_BACKEND_TIME_H_ */ diff --git a/drivers/gpu/arm/bifrost/mali_kbase_js.c b/drivers/gpu/arm/bifrost/mali_kbase_js.c index 78f2d7d47b3b..8ce09212a57e 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-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2023 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 "mali_kbase_jm.h" #include "mali_kbase_hwaccess_jm.h" +#include #include /* @@ -531,6 +532,7 @@ int kbasep_js_devdata_init(struct kbase_device * const kbdev) jsdd->gpu_reset_ticks_dumping = DEFAULT_JS_RESET_TICKS_DUMPING; jsdd->ctx_timeslice_ns = DEFAULT_JS_CTX_TIMESLICE_NS; atomic_set(&jsdd->soft_job_timeout_ms, DEFAULT_JS_SOFT_JOB_TIMEOUT); + jsdd->js_free_wait_time_ms = kbase_get_timeout_ms(kbdev, JM_DEFAULT_JS_FREE_TIMEOUT); dev_dbg(kbdev->dev, "JS Config Attribs: "); dev_dbg(kbdev->dev, "\tscheduling_period_ns:%u", @@ -555,6 +557,7 @@ int kbasep_js_devdata_init(struct kbase_device * const kbdev) jsdd->ctx_timeslice_ns); dev_dbg(kbdev->dev, "\tsoft_job_timeout:%i", atomic_read(&jsdd->soft_job_timeout_ms)); + dev_dbg(kbdev->dev, "\tjs_free_wait_time_ms:%u", jsdd->js_free_wait_time_ms); if (!(jsdd->soft_stop_ticks < jsdd->hard_stop_ticks_ss && jsdd->hard_stop_ticks_ss < jsdd->gpu_reset_ticks_ss && diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem.c b/drivers/gpu/arm/bifrost/mali_kbase_mem.c index b18b1e25267e..1c94e9c57b7f 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem.c @@ -44,6 +44,9 @@ #include #include +#define VA_REGION_SLAB_NAME_PREFIX "va-region-slab-" +#define VA_REGION_SLAB_NAME_SIZE (DEVNAME_SIZE + sizeof(VA_REGION_SLAB_NAME_PREFIX) + 1) + #if MALI_JIT_PRESSURE_LIMIT_BASE /* @@ -92,10 +95,8 @@ static size_t kbase_get_num_cpu_va_bits(struct kbase_context *kctx) #error "Unknown CPU VA width for this architecture" #endif -#if IS_ENABLED(CONFIG_64BIT) - if (kbase_ctx_flag(kctx, KCTX_COMPAT)) + if (kbase_ctx_compat_mode(kctx)) cpu_va_bits = 32; -#endif return cpu_va_bits; } @@ -130,18 +131,14 @@ static struct rb_root *kbase_gpu_va_to_rbtree(struct kbase_context *kctx, else { u64 same_va_end; -#if IS_ENABLED(CONFIG_64BIT) - if (kbase_ctx_flag(kctx, KCTX_COMPAT)) { -#endif /* CONFIG_64BIT */ + if (kbase_ctx_compat_mode(kctx)) { same_va_end = KBASE_REG_ZONE_CUSTOM_VA_BASE; -#if IS_ENABLED(CONFIG_64BIT) } else { struct kbase_reg_zone *same_va_zone = kbase_ctx_reg_zone_get(kctx, KBASE_REG_ZONE_SAME_VA); same_va_end = kbase_reg_zone_end_pfn(same_va_zone); } -#endif /* CONFIG_64BIT */ if (gpu_pfn >= same_va_end) rbtree = &kctx->reg_rbtree_custom; @@ -383,6 +380,7 @@ void kbase_remove_va_region(struct kbase_device *kbdev, struct rb_node *rbnext; struct kbase_va_region *next = NULL; struct rb_root *reg_rbtree = NULL; + struct kbase_va_region *orig_reg = reg; int merged_front = 0; int merged_back = 0; @@ -447,9 +445,8 @@ void kbase_remove_va_region(struct kbase_device *kbdev, */ struct kbase_va_region *free_reg; - free_reg = kbase_alloc_free_region(reg_rbtree, - reg->start_pfn, reg->nr_pages, - reg->flags & KBASE_REG_ZONE_MASK); + free_reg = kbase_alloc_free_region(kbdev, reg_rbtree, reg->start_pfn, reg->nr_pages, + reg->flags & KBASE_REG_ZONE_MASK); if (!free_reg) { /* In case of failure, we cannot allocate a replacement * free region, so we will be left with a 'gap' in the @@ -480,6 +477,12 @@ void kbase_remove_va_region(struct kbase_device *kbdev, rb_replace_node(&(reg->rblink), &(free_reg->rblink), reg_rbtree); } + /* This operation is always safe because the function never frees + * the region. If the region has been merged to both front and back, + * then it's the previous region that is supposed to be freed. + */ + orig_reg->start_pfn = 0; + out: return; } @@ -490,6 +493,7 @@ KBASE_EXPORT_TEST_API(kbase_remove_va_region); * kbase_insert_va_region_nolock - Insert a VA region to the list, * replacing the existing one. * + * @kbdev: The kbase device * @new_reg: The new region to insert * @at_reg: The region to replace * @start_pfn: The Page Frame Number to insert at @@ -497,8 +501,10 @@ KBASE_EXPORT_TEST_API(kbase_remove_va_region); * * Return: 0 on success, error code otherwise. */ -static int kbase_insert_va_region_nolock(struct kbase_va_region *new_reg, - struct kbase_va_region *at_reg, u64 start_pfn, size_t nr_pages) +static int kbase_insert_va_region_nolock(struct kbase_device *kbdev, + struct kbase_va_region *new_reg, + struct kbase_va_region *at_reg, u64 start_pfn, + size_t nr_pages) { struct rb_root *reg_rbtree = NULL; int err = 0; @@ -542,10 +548,9 @@ static int kbase_insert_va_region_nolock(struct kbase_va_region *new_reg, else { struct kbase_va_region *new_front_reg; - new_front_reg = kbase_alloc_free_region(reg_rbtree, - at_reg->start_pfn, - start_pfn - at_reg->start_pfn, - at_reg->flags & KBASE_REG_ZONE_MASK); + new_front_reg = kbase_alloc_free_region(kbdev, reg_rbtree, at_reg->start_pfn, + start_pfn - at_reg->start_pfn, + at_reg->flags & KBASE_REG_ZONE_MASK); if (new_front_reg) { at_reg->nr_pages -= nr_pages + new_front_reg->nr_pages; @@ -682,8 +687,7 @@ int kbase_add_va_region_rbtree(struct kbase_device *kbdev, goto exit; } - err = kbase_insert_va_region_nolock(reg, tmp, gpu_pfn, - nr_pages); + err = kbase_insert_va_region_nolock(kbdev, reg, tmp, gpu_pfn, nr_pages); if (err) { dev_warn(dev, "Failed to insert va region"); err = -ENOMEM; @@ -708,8 +712,7 @@ int kbase_add_va_region_rbtree(struct kbase_device *kbdev, nr_pages, align_offset, align_mask, &start_pfn); if (tmp) { - err = kbase_insert_va_region_nolock(reg, tmp, - start_pfn, nr_pages); + err = kbase_insert_va_region_nolock(kbdev, reg, tmp, start_pfn, nr_pages); if (unlikely(err)) { dev_warn(dev, "Failed to insert region: 0x%08llx start_pfn, %zu nr_pages", start_pfn, nr_pages); @@ -847,7 +850,7 @@ static void kbase_region_tracker_erase_rbtree(struct rb_root *rbtree) if (rbnode) { rb_erase(rbnode, rbtree); reg = rb_entry(rbnode, struct kbase_va_region, rblink); - WARN_ON(reg->va_refcnt != 1); + WARN_ON(kbase_refcount_read(®->va_refcnt) != 1); if (kbase_page_migration_enabled) kbase_gpu_munmap(kbase_reg_flags_to_kctx(reg), reg); /* Reset the start_pfn - as the rbtree is being @@ -933,9 +936,8 @@ int kbase_region_tracker_init(struct kbase_context *kctx) #endif /* all have SAME_VA */ - same_va_reg = - kbase_alloc_free_region(&kctx->reg_rbtree_same, same_va_base, - same_va_pages, KBASE_REG_ZONE_SAME_VA); + same_va_reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_same, same_va_base, + same_va_pages, KBASE_REG_ZONE_SAME_VA); if (!same_va_reg) { err = -ENOMEM; @@ -944,10 +946,7 @@ int kbase_region_tracker_init(struct kbase_context *kctx) kbase_ctx_reg_zone_init(kctx, KBASE_REG_ZONE_SAME_VA, same_va_base, same_va_pages); -#if IS_ENABLED(CONFIG_64BIT) - /* 32-bit clients have custom VA zones */ - if (kbase_ctx_flag(kctx, KCTX_COMPAT)) { -#endif + if (kbase_ctx_compat_mode(kctx)) { if (gpu_va_limit <= KBASE_REG_ZONE_CUSTOM_VA_BASE) { err = -EINVAL; goto fail_free_same_va; @@ -959,10 +958,9 @@ int kbase_region_tracker_init(struct kbase_context *kctx) if ((KBASE_REG_ZONE_CUSTOM_VA_BASE + KBASE_REG_ZONE_CUSTOM_VA_SIZE) >= gpu_va_limit) custom_va_size = gpu_va_limit - KBASE_REG_ZONE_CUSTOM_VA_BASE; - custom_va_reg = kbase_alloc_free_region( - &kctx->reg_rbtree_custom, - KBASE_REG_ZONE_CUSTOM_VA_BASE, - custom_va_size, KBASE_REG_ZONE_CUSTOM_VA); + custom_va_reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_custom, + KBASE_REG_ZONE_CUSTOM_VA_BASE, + custom_va_size, KBASE_REG_ZONE_CUSTOM_VA); if (!custom_va_reg) { err = -ENOMEM; @@ -971,11 +969,9 @@ int kbase_region_tracker_init(struct kbase_context *kctx) kbase_ctx_reg_zone_init(kctx, KBASE_REG_ZONE_CUSTOM_VA, KBASE_REG_ZONE_CUSTOM_VA_BASE, custom_va_size); -#if IS_ENABLED(CONFIG_64BIT) } else { custom_va_size = 0; } -#endif #if MALI_USE_CSF /* The position of EXEC_VA depends on whether the client is 32-bit or 64-bit. */ @@ -986,17 +982,15 @@ int kbase_region_tracker_init(struct kbase_context *kctx) */ fixed_va_end = KBASE_REG_ZONE_FIXED_VA_END_64; -#if IS_ENABLED(CONFIG_64BIT) - if (kbase_ctx_flag(kctx, KCTX_COMPAT)) { + if (kbase_ctx_compat_mode(kctx)) { exec_va_base = KBASE_REG_ZONE_EXEC_VA_BASE_32; fixed_va_end = KBASE_REG_ZONE_FIXED_VA_END_32; } -#endif kbase_ctx_reg_zone_init(kctx, KBASE_REG_ZONE_EXEC_VA, exec_va_base, KBASE_REG_ZONE_EXEC_VA_SIZE); - exec_va_reg = kbase_alloc_free_region(&kctx->reg_rbtree_exec, exec_va_base, + exec_va_reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_exec, exec_va_base, KBASE_REG_ZONE_EXEC_VA_SIZE, KBASE_REG_ZONE_EXEC_VA); if (!exec_va_reg) { @@ -1010,8 +1004,8 @@ int kbase_region_tracker_init(struct kbase_context *kctx) KBASE_REG_ZONE_EXEC_FIXED_VA_SIZE); exec_fixed_va_reg = - kbase_alloc_free_region(&kctx->reg_rbtree_exec_fixed, exec_fixed_va_base, - KBASE_REG_ZONE_EXEC_FIXED_VA_SIZE, + kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_exec_fixed, + exec_fixed_va_base, KBASE_REG_ZONE_EXEC_FIXED_VA_SIZE, KBASE_REG_ZONE_EXEC_FIXED_VA); if (!exec_fixed_va_reg) { @@ -1024,7 +1018,7 @@ int kbase_region_tracker_init(struct kbase_context *kctx) kbase_ctx_reg_zone_init(kctx, KBASE_REG_ZONE_FIXED_VA, fixed_va_base, fixed_va_pages); - fixed_va_reg = kbase_alloc_free_region(&kctx->reg_rbtree_fixed, fixed_va_base, + fixed_va_reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_fixed, fixed_va_base, fixed_va_pages, KBASE_REG_ZONE_FIXED_VA); kctx->gpu_va_end = fixed_va_end; @@ -1163,7 +1157,6 @@ static bool kbase_region_tracker_has_allocs(struct kbase_context *kctx) return false; } -#if IS_ENABLED(CONFIG_64BIT) static int kbase_region_tracker_init_jit_64(struct kbase_context *kctx, u64 jit_va_pages) { @@ -1212,9 +1205,8 @@ static int kbase_region_tracker_init_jit_64(struct kbase_context *kctx, * Create a custom VA zone at the end of the VA for allocations which * JIT can use so it doesn't have to allocate VA from the kernel. */ - custom_va_reg = - kbase_alloc_free_region(&kctx->reg_rbtree_custom, jit_va_start, - jit_va_pages, KBASE_REG_ZONE_CUSTOM_VA); + custom_va_reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_custom, jit_va_start, + jit_va_pages, KBASE_REG_ZONE_CUSTOM_VA); /* * The context will be destroyed if we fail here so no point @@ -1231,7 +1223,6 @@ static int kbase_region_tracker_init_jit_64(struct kbase_context *kctx, kbase_region_tracker_insert(custom_va_reg); return 0; } -#endif int kbase_region_tracker_init_jit(struct kbase_context *kctx, u64 jit_va_pages, int max_allocations, int trim_level, int group_id, @@ -1272,10 +1263,8 @@ int kbase_region_tracker_init_jit(struct kbase_context *kctx, u64 jit_va_pages, goto exit_unlock; } -#if IS_ENABLED(CONFIG_64BIT) - if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) + if (!kbase_ctx_compat_mode(kctx)) err = kbase_region_tracker_init_jit_64(kctx, jit_va_pages); -#endif /* * Nothing to do for 32-bit clients, JIT uses the existing * custom VA zone. @@ -1351,17 +1340,14 @@ int kbase_region_tracker_init_exec(struct kbase_context *kctx, u64 exec_va_pages goto exit_unlock; } -#if IS_ENABLED(CONFIG_64BIT) - if (kbase_ctx_flag(kctx, KCTX_COMPAT)) { -#endif + if (kbase_ctx_compat_mode(kctx)) { /* 32-bit client: take from CUSTOM_VA zone */ target_zone_bits = KBASE_REG_ZONE_CUSTOM_VA; -#if IS_ENABLED(CONFIG_64BIT) } else { /* 64-bit client: take from SAME_VA zone */ target_zone_bits = KBASE_REG_ZONE_SAME_VA; } -#endif + target_zone = kbase_ctx_reg_zone_get(kctx, target_zone_bits); target_zone_base_addr = target_zone->base_pfn << PAGE_SHIFT; @@ -1389,10 +1375,8 @@ int kbase_region_tracker_init_exec(struct kbase_context *kctx, u64 exec_va_pages /* Taken from the end of the target zone */ exec_va_start = kbase_reg_zone_end_pfn(target_zone) - exec_va_pages; - exec_va_reg = kbase_alloc_free_region(&kctx->reg_rbtree_exec, - exec_va_start, - exec_va_pages, - KBASE_REG_ZONE_EXEC_VA); + exec_va_reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_exec, exec_va_start, + exec_va_pages, KBASE_REG_ZONE_EXEC_VA); if (!exec_va_reg) { err = -ENOMEM; goto exit_unlock; @@ -1435,10 +1419,9 @@ int kbase_mcu_shared_interface_region_tracker_init(struct kbase_device *kbdev) kbdev->csf.shared_reg_rbtree = RB_ROOT; - shared_reg = kbase_alloc_free_region(&kbdev->csf.shared_reg_rbtree, - shared_reg_start_pfn, - shared_reg_size, - KBASE_REG_ZONE_MCU_SHARED); + shared_reg = + kbase_alloc_free_region(kbdev, &kbdev->csf.shared_reg_rbtree, shared_reg_start_pfn, + shared_reg_size, KBASE_REG_ZONE_MCU_SHARED); if (!shared_reg) return -ENOMEM; @@ -1447,10 +1430,30 @@ int kbase_mcu_shared_interface_region_tracker_init(struct kbase_device *kbdev) } #endif +static void kbasep_mem_page_size_init(struct kbase_device *kbdev) +{ +#if IS_ENABLED(CONFIG_LARGE_PAGE_ALLOC_OVERRIDE) +#if IS_ENABLED(CONFIG_LARGE_PAGE_ALLOC) + kbdev->pagesize_2mb = true; + if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_LARGE_PAGE_ALLOC) != 1) { + dev_warn( + kbdev->dev, + "2MB page is enabled by force while current GPU-HW doesn't meet the requirement to do so.\n"); + } +#else /* IS_ENABLED(CONFIG_LARGE_PAGE_ALLOC) */ + kbdev->pagesize_2mb = false; +#endif /* IS_ENABLED(CONFIG_LARGE_PAGE_ALLOC) */ +#else /* IS_ENABLED(CONFIG_LARGE_PAGE_ALLOC_OVERRIDE) */ + /* Set it to the default based on which GPU is present */ + kbdev->pagesize_2mb = kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_LARGE_PAGE_ALLOC); +#endif /* IS_ENABLED(CONFIG_LARGE_PAGE_ALLOC_OVERRIDE) */ +} + int kbase_mem_init(struct kbase_device *kbdev) { int err = 0; struct kbasep_mem_device *memdev; + char va_region_slab_name[VA_REGION_SLAB_NAME_SIZE]; #if IS_ENABLED(CONFIG_OF) struct device_node *mgm_node = NULL; #endif @@ -1459,6 +1462,19 @@ int kbase_mem_init(struct kbase_device *kbdev) memdev = &kbdev->memdev; + kbasep_mem_page_size_init(kbdev); + + scnprintf(va_region_slab_name, VA_REGION_SLAB_NAME_SIZE, VA_REGION_SLAB_NAME_PREFIX "%s", + kbdev->devname); + + /* Initialize slab cache for kbase_va_regions */ + kbdev->va_region_slab = + kmem_cache_create(va_region_slab_name, sizeof(struct kbase_va_region), 0, 0, NULL); + if (kbdev->va_region_slab == NULL) { + dev_err(kbdev->dev, "Failed to create va_region_slab\n"); + return -ENOMEM; + } + kbase_mem_migrate_init(kbdev); kbase_mem_pool_group_config_set_max_size(&kbdev->mem_pool_defaults, KBASE_MEM_POOL_MAX_SIZE_KCTX); @@ -1550,6 +1566,9 @@ void kbase_mem_term(struct kbase_device *kbdev) kbase_mem_migrate_term(kbdev); + kmem_cache_destroy(kbdev->va_region_slab); + kbdev->va_region_slab = NULL; + WARN_ON(kbdev->total_gpu_pages); WARN_ON(!RB_EMPTY_ROOT(&kbdev->process_root)); WARN_ON(!RB_EMPTY_ROOT(&kbdev->dma_buf_root)); @@ -1563,6 +1582,7 @@ KBASE_EXPORT_TEST_API(kbase_mem_term); /** * kbase_alloc_free_region - Allocate a free region object. * + * @kbdev: kbase device * @rbtree: Backlink to the red-black tree of memory regions. * @start_pfn: The Page Frame Number in GPU virtual address space. * @nr_pages: The size of the region in pages. @@ -1575,8 +1595,8 @@ KBASE_EXPORT_TEST_API(kbase_mem_term); * * Return: pointer to the allocated region object on success, NULL otherwise. */ -struct kbase_va_region *kbase_alloc_free_region(struct rb_root *rbtree, - u64 start_pfn, size_t nr_pages, int zone) +struct kbase_va_region *kbase_alloc_free_region(struct kbase_device *kbdev, struct rb_root *rbtree, + u64 start_pfn, size_t nr_pages, int zone) { struct kbase_va_region *new_reg; @@ -1588,13 +1608,13 @@ struct kbase_va_region *kbase_alloc_free_region(struct rb_root *rbtree, /* 64-bit address range is the max */ KBASE_DEBUG_ASSERT(start_pfn + nr_pages <= (U64_MAX / PAGE_SIZE)); - new_reg = kzalloc(sizeof(*new_reg), GFP_KERNEL); + new_reg = kmem_cache_zalloc(kbdev->va_region_slab, GFP_KERNEL); if (!new_reg) return NULL; - new_reg->va_refcnt = 1; - new_reg->no_user_free_refcnt = 0; + kbase_refcount_set(&new_reg->va_refcnt, 1); + atomic_set(&new_reg->no_user_free_count, 0); new_reg->cpu_alloc = NULL; /* no alloc bound yet */ new_reg->gpu_alloc = NULL; /* no alloc bound yet */ new_reg->rbtree = rbtree; @@ -1726,7 +1746,6 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, unsigned long gwt_mask = ~0; int group_id; struct kbase_mem_phy_alloc *alloc; - bool ignore_page_migration = false; #ifdef CONFIG_MALI_CINSTR_GWT if (kctx->gwt_enabled) @@ -1755,41 +1774,46 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, KBASE_DEBUG_ASSERT(alloc->imported.alias.aliased); for (i = 0; i < alloc->imported.alias.nents; i++) { if (alloc->imported.alias.aliased[i].alloc) { - err = kbase_mmu_insert_pages( + err = kbase_mmu_insert_aliased_pages( kctx->kbdev, &kctx->mmu, reg->start_pfn + (i * stride), alloc->imported.alias.aliased[i].alloc->pages + alloc->imported.alias.aliased[i].offset, alloc->imported.alias.aliased[i].length, reg->flags & gwt_mask, kctx->as_nr, group_id, mmu_sync_info, - NULL, ignore_page_migration); + NULL); if (err) - goto bad_insert; + goto bad_aliased_insert; /* Note: mapping count is tracked at alias * creation time */ } else { - err = kbase_mmu_insert_single_page( - kctx, reg->start_pfn + i * stride, - kctx->aliasing_sink_page, + err = kbase_mmu_insert_single_aliased_page( + kctx, reg->start_pfn + i * stride, kctx->aliasing_sink_page, alloc->imported.alias.aliased[i].length, - (reg->flags & mask & gwt_mask) | attr, - group_id, mmu_sync_info); + (reg->flags & mask & gwt_mask) | attr, group_id, + mmu_sync_info); if (err) - goto bad_insert; + goto bad_aliased_insert; } } } else { if (reg->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM || - reg->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_USER_BUF) - ignore_page_migration = true; + reg->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_USER_BUF) { + + err = kbase_mmu_insert_imported_pages( + kctx->kbdev, &kctx->mmu, reg->start_pfn, + kbase_get_gpu_phy_pages(reg), kbase_reg_current_backed_size(reg), + reg->flags & gwt_mask, kctx->as_nr, group_id, mmu_sync_info, reg); + } else { + err = kbase_mmu_insert_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + kbase_get_gpu_phy_pages(reg), + kbase_reg_current_backed_size(reg), + reg->flags & gwt_mask, kctx->as_nr, group_id, + mmu_sync_info, reg, true); + } - err = kbase_mmu_insert_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, - kbase_get_gpu_phy_pages(reg), - kbase_reg_current_backed_size(reg), - reg->flags & gwt_mask, kctx->as_nr, group_id, - mmu_sync_info, reg, ignore_page_migration); if (err) goto bad_insert; kbase_mem_phy_alloc_gpu_mapped(alloc); @@ -1799,9 +1823,9 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, !WARN_ON(reg->nr_pages < reg->gpu_alloc->nents) && reg->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM && reg->gpu_alloc->imported.umm.current_mapping_usage_count) { - /* For padded imported dma-buf memory, map the dummy aliasing - * page from the end of the dma-buf pages, to the end of the - * region using a read only mapping. + /* For padded imported dma-buf or user-buf memory, map the dummy + * aliasing page from the end of the imported pages, to the end of + * the region using a read only mapping. * * Only map when it's imported dma-buf memory that is currently * mapped. @@ -1809,22 +1833,32 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, * Assume reg->gpu_alloc->nents is the number of actual pages * in the dma-buf memory. */ - err = kbase_mmu_insert_single_page( - kctx, reg->start_pfn + reg->gpu_alloc->nents, - kctx->aliasing_sink_page, + err = kbase_mmu_insert_single_imported_page( + kctx, reg->start_pfn + reg->gpu_alloc->nents, kctx->aliasing_sink_page, reg->nr_pages - reg->gpu_alloc->nents, - (reg->flags | KBASE_REG_GPU_RD) & ~KBASE_REG_GPU_WR, - KBASE_MEM_GROUP_SINK, mmu_sync_info); + (reg->flags | KBASE_REG_GPU_RD) & ~KBASE_REG_GPU_WR, KBASE_MEM_GROUP_SINK, + mmu_sync_info); if (err) goto bad_insert; } return err; -bad_insert: - kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, - reg->nr_pages, kctx->as_nr, ignore_page_migration); +bad_aliased_insert: + while (i-- > 0) { + struct tagged_addr *phys_alloc = NULL; + u64 const stride = alloc->imported.alias.stride; + if (alloc->imported.alias.aliased[i].alloc != NULL) + phys_alloc = alloc->imported.alias.aliased[i].alloc->pages + + alloc->imported.alias.aliased[i].offset; + + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn + (i * stride), + phys_alloc, alloc->imported.alias.aliased[i].length, + alloc->imported.alias.aliased[i].length, kctx->as_nr, + false); + } +bad_insert: kbase_remove_va_region(kctx->kbdev, reg); return err; @@ -1870,26 +1904,49 @@ int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg) kctx->kbdev, &kctx->mmu, reg->start_pfn + (i * alloc->imported.alias.stride), phys_alloc, alloc->imported.alias.aliased[i].length, - kctx->as_nr, false); + alloc->imported.alias.aliased[i].length, kctx->as_nr, + false); if (WARN_ON_ONCE(err_loop)) err = err_loop; } } break; - case KBASE_MEM_TYPE_IMPORTED_UMM: - err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, - alloc->pages, reg->nr_pages, kctx->as_nr, true); + case KBASE_MEM_TYPE_IMPORTED_UMM: { + size_t nr_phys_pages = reg->nr_pages; + size_t nr_virt_pages = reg->nr_pages; + /* If the region has import padding and falls under the threshold for + * issuing a partial GPU cache flush, we want to reduce the number of + * physical pages that get flushed. + + * This is symmetric with case of mapping the memory, which first maps + * each imported physical page to a separate virtual page, and then + * maps the single aliasing sink page to each of the virtual padding + * pages. + */ + if (reg->flags & KBASE_REG_IMPORT_PAD) + nr_phys_pages = alloc->nents + 1; + + err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, nr_phys_pages, nr_virt_pages, + kctx->as_nr, true); + } break; - case KBASE_MEM_TYPE_IMPORTED_USER_BUF: - err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, - alloc->pages, kbase_reg_current_backed_size(reg), - kctx->as_nr, true); + case KBASE_MEM_TYPE_IMPORTED_USER_BUF: { + size_t nr_reg_pages = kbase_reg_current_backed_size(reg); + + err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, nr_reg_pages, nr_reg_pages, + kctx->as_nr, true); + } break; - default: - err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, - alloc->pages, kbase_reg_current_backed_size(reg), - kctx->as_nr, false); + default: { + size_t nr_reg_pages = kbase_reg_current_backed_size(reg); + + err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, nr_reg_pages, nr_reg_pages, + kctx->as_nr, false); + } break; } @@ -2214,7 +2271,7 @@ int kbase_mem_free_region(struct kbase_context *kctx, struct kbase_va_region *re __func__, (void *)reg, (void *)kctx); lockdep_assert_held(&kctx->reg_lock); - if (kbase_va_region_is_no_user_free(kctx, reg)) { + if (kbase_va_region_is_no_user_free(reg)) { dev_warn(kctx->kbdev->dev, "Attempt to free GPU memory whose freeing by user space is forbidden!\n"); return -EINVAL; } @@ -2435,7 +2492,7 @@ int kbase_update_region_flags(struct kbase_context *kctx, if (flags & BASEP_MEM_NO_USER_FREE) { kbase_gpu_vm_lock(kctx); - kbase_va_region_no_user_free_get(kctx, reg); + kbase_va_region_no_user_free_inc(reg); kbase_gpu_vm_unlock(kctx); } @@ -2489,15 +2546,14 @@ int kbase_alloc_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, tp = alloc->pages + alloc->nents; -#ifdef CONFIG_MALI_2MB_ALLOC /* Check if we have enough pages requested so we can allocate a large * page (512 * 4KB = 2MB ) */ - if (nr_left >= (SZ_2M / SZ_4K)) { + if (kbdev->pagesize_2mb && nr_left >= (SZ_2M / SZ_4K)) { int nr_lp = nr_left / (SZ_2M / SZ_4K); res = kbase_mem_pool_alloc_pages(&kctx->mem_pools.large[alloc->group_id], - nr_lp * (SZ_2M / SZ_4K), tp, true); + nr_lp * (SZ_2M / SZ_4K), tp, true, kctx->task); if (res > 0) { nr_left -= res; @@ -2551,7 +2607,7 @@ int kbase_alloc_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, err = kbase_mem_pool_grow( &kctx->mem_pools.large[alloc->group_id], - 1); + 1, kctx->task); if (err) break; } while (1); @@ -2592,12 +2648,11 @@ int kbase_alloc_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, } } } -no_new_partial: -#endif +no_new_partial: if (nr_left) { res = kbase_mem_pool_alloc_pages(&kctx->mem_pools.small[alloc->group_id], nr_left, - tp, false); + tp, false, kctx->task); if (res <= 0) goto alloc_failed; } @@ -2656,18 +2711,17 @@ struct tagged_addr *kbase_alloc_phy_pages_helper_locked( lockdep_assert_held(&pool->pool_lock); -#if !defined(CONFIG_MALI_2MB_ALLOC) - WARN_ON(pool->order); -#endif + kctx = alloc->imported.native.kctx; + kbdev = kctx->kbdev; + + if (!kbdev->pagesize_2mb) + WARN_ON(pool->order); if (alloc->reg) { if (nr_pages_requested > alloc->reg->nr_pages - alloc->nents) goto invalid_request; } - kctx = alloc->imported.native.kctx; - kbdev = kctx->kbdev; - lockdep_assert_held(&kctx->mem_partials_lock); if (nr_pages_requested == 0) @@ -2686,8 +2740,7 @@ struct tagged_addr *kbase_alloc_phy_pages_helper_locked( tp = alloc->pages + alloc->nents; new_pages = tp; -#ifdef CONFIG_MALI_2MB_ALLOC - if (pool->order) { + if (kbdev->pagesize_2mb && pool->order) { int nr_lp = nr_left / (SZ_2M / SZ_4K); res = kbase_mem_pool_alloc_pages_locked(pool, @@ -2771,15 +2824,12 @@ struct tagged_addr *kbase_alloc_phy_pages_helper_locked( if (nr_left) goto alloc_failed; } else { -#endif res = kbase_mem_pool_alloc_pages_locked(pool, nr_left, tp); if (res <= 0) goto alloc_failed; -#ifdef CONFIG_MALI_2MB_ALLOC } -#endif KBASE_TLSTREAM_AUX_PAGESALLOC( kbdev, @@ -2800,8 +2850,7 @@ alloc_failed: struct tagged_addr *start_free = alloc->pages + alloc->nents; -#ifdef CONFIG_MALI_2MB_ALLOC - if (pool->order) { + if (kbdev->pagesize_2mb && pool->order) { while (nr_pages_to_free) { if (is_huge_head(*start_free)) { kbase_mem_pool_free_pages_locked( @@ -2819,15 +2868,12 @@ alloc_failed: } } } else { -#endif kbase_mem_pool_free_pages_locked(pool, nr_pages_to_free, start_free, false, /* not dirty */ true); /* return to pool */ -#ifdef CONFIG_MALI_2MB_ALLOC } -#endif } kbase_process_page_usage_dec(kctx, nr_pages_requested); @@ -3816,8 +3862,8 @@ static void kbase_jit_destroy_worker(struct work_struct *work) * by implementing "free on putting the last reference", * but only for JIT regions. */ - WARN_ON(reg->no_user_free_refcnt > 1); - kbase_va_region_no_user_free_put(kctx, reg); + WARN_ON(atomic_read(®->no_user_free_count) > 1); + kbase_va_region_no_user_free_dec(reg); kbase_mem_free_region(kctx, reg); kbase_gpu_vm_unlock(kctx); } while (1); @@ -4078,18 +4124,14 @@ static int kbase_jit_grow(struct kbase_context *kctx, delta = info->commit_pages - reg->gpu_alloc->nents; pages_required = delta; -#ifdef CONFIG_MALI_2MB_ALLOC - if (pages_required >= (SZ_2M / SZ_4K)) { + if (kctx->kbdev->pagesize_2mb && pages_required >= (SZ_2M / SZ_4K)) { pool = &kctx->mem_pools.large[kctx->jit_group_id]; /* Round up to number of 2 MB pages required */ pages_required += ((SZ_2M / SZ_4K) - 1); pages_required /= (SZ_2M / SZ_4K); } else { -#endif pool = &kctx->mem_pools.small[kctx->jit_group_id]; -#ifdef CONFIG_MALI_2MB_ALLOC } -#endif if (reg->cpu_alloc != reg->gpu_alloc) pages_required *= 2; @@ -4110,7 +4152,7 @@ static int kbase_jit_grow(struct kbase_context *kctx, spin_unlock(&kctx->mem_partials_lock); kbase_gpu_vm_unlock(kctx); - ret = kbase_mem_pool_grow(pool, pool_delta); + ret = kbase_mem_pool_grow(pool, pool_delta, kctx->task); kbase_gpu_vm_lock(kctx); if (ret) @@ -4374,14 +4416,14 @@ struct kbase_va_region *kbase_jit_allocate(struct kbase_context *kctx, if (!jit_allow_allocate(kctx, info, ignore_pressure_limit)) return NULL; -#ifdef CONFIG_MALI_2MB_ALLOC - /* Preallocate memory for the sub-allocation structs */ - for (i = 0; i != ARRAY_SIZE(prealloc_sas); ++i) { - prealloc_sas[i] = kmalloc(sizeof(*prealloc_sas[i]), GFP_KERNEL); - if (!prealloc_sas[i]) - goto end; + if (kctx->kbdev->pagesize_2mb) { + /* Preallocate memory for the sub-allocation structs */ + for (i = 0; i != ARRAY_SIZE(prealloc_sas); ++i) { + prealloc_sas[i] = kmalloc(sizeof(*prealloc_sas[i]), GFP_KERNEL); + if (!prealloc_sas[i]) + goto end; + } } -#endif kbase_gpu_vm_lock(kctx); mutex_lock(&kctx->jit_evict_lock); @@ -4561,7 +4603,7 @@ struct kbase_va_region *kbase_jit_allocate(struct kbase_context *kctx, /* Similarly to tiler heap init, there is a short window of time * where the (either recycled or newly allocated, in our case) region has - * "no user free" refcount incremented but is still missing the DONT_NEED flag, and + * "no user free" count incremented but is still missing the DONT_NEED flag, and * doesn't yet have the ACTIVE_JIT_ALLOC flag either. Temporarily leaking the * allocation is the least bad option that doesn't lead to a security issue down the * line (it will eventually be cleaned up during context termination). @@ -4570,9 +4612,9 @@ struct kbase_va_region *kbase_jit_allocate(struct kbase_context *kctx, * flags. */ kbase_gpu_vm_lock(kctx); - if (unlikely(reg->no_user_free_refcnt > 1)) { + if (unlikely(atomic_read(®->no_user_free_count) > 1)) { kbase_gpu_vm_unlock(kctx); - dev_err(kctx->kbdev->dev, "JIT region has no_user_free_refcnt > 1!\n"); + dev_err(kctx->kbdev->dev, "JIT region has no_user_free_count > 1!\n"); mutex_lock(&kctx->jit_evict_lock); list_move(®->jit_node, &kctx->jit_pool_head); @@ -4728,8 +4770,8 @@ bool kbase_jit_evict(struct kbase_context *kctx) * by implementing "free on putting the last reference", * but only for JIT regions. */ - WARN_ON(reg->no_user_free_refcnt > 1); - kbase_va_region_no_user_free_put(kctx, reg); + WARN_ON(atomic_read(®->no_user_free_count) > 1); + kbase_va_region_no_user_free_dec(reg); kbase_mem_free_region(kctx, reg); } @@ -4757,8 +4799,8 @@ void kbase_jit_term(struct kbase_context *kctx) * by implementing "free on putting the last reference", * but only for JIT regions. */ - WARN_ON(walker->no_user_free_refcnt > 1); - kbase_va_region_no_user_free_put(kctx, walker); + WARN_ON(atomic_read(&walker->no_user_free_count) > 1); + kbase_va_region_no_user_free_dec(walker); kbase_mem_free_region(kctx, walker); mutex_lock(&kctx->jit_evict_lock); } @@ -4776,8 +4818,8 @@ void kbase_jit_term(struct kbase_context *kctx) * by implementing "free on putting the last reference", * but only for JIT regions. */ - WARN_ON(walker->no_user_free_refcnt > 1); - kbase_va_region_no_user_free_put(kctx, walker); + WARN_ON(atomic_read(&walker->no_user_free_count) > 1); + kbase_va_region_no_user_free_dec(walker); kbase_mem_free_region(kctx, walker); mutex_lock(&kctx->jit_evict_lock); } @@ -5023,9 +5065,13 @@ static int kbase_jd_user_buf_map(struct kbase_context *kctx, * region, otherwise the initial content of memory would be wrong. */ for (i = 0; i < pinned_pages; i++) { - dma_addr_t dma_addr = dma_map_page_attrs(dev, pages[i], 0, PAGE_SIZE, - DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); - + dma_addr_t dma_addr; +#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) + dma_addr = dma_map_page(dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL); +#else + dma_addr = dma_map_page_attrs(dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); +#endif err = dma_mapping_error(dev, dma_addr); if (err) goto unwind; @@ -5041,9 +5087,10 @@ static int kbase_jd_user_buf_map(struct kbase_context *kctx, gwt_mask = ~KBASE_REG_GPU_WR; #endif - err = kbase_mmu_insert_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, pa, - kbase_reg_current_backed_size(reg), reg->flags & gwt_mask, - kctx->as_nr, alloc->group_id, mmu_sync_info, NULL, true); + err = kbase_mmu_insert_imported_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, pa, + kbase_reg_current_backed_size(reg), + reg->flags & gwt_mask, kctx->as_nr, alloc->group_id, + mmu_sync_info, NULL); if (err == 0) return 0; @@ -5064,8 +5111,12 @@ unwind: dma_addr_t dma_addr = alloc->imported.user_buf.dma_addrs[i]; dma_sync_single_for_device(dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); +#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) + dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); +#else dma_unmap_page_attrs(dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); +#endif } /* The user buffer could already have been previously pinned before @@ -5182,9 +5233,13 @@ static void kbase_jd_user_buf_unmap(struct kbase_context *kctx, struct kbase_mem } /* Notice: use the original DMA address to unmap the whole memory page. */ +#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) + dma_unmap_page(kctx->kbdev->dev, alloc->imported.user_buf.dma_addrs[i], PAGE_SIZE, + DMA_BIDIRECTIONAL); +#else dma_unmap_page_attrs(kctx->kbdev->dev, alloc->imported.user_buf.dma_addrs[i], PAGE_SIZE, DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); - +#endif if (writeable) set_page_dirty_lock(pages[i]); #if !MALI_USE_CSF @@ -5308,6 +5363,7 @@ void kbase_unmap_external_resource(struct kbase_context *kctx, struct kbase_va_r kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, kbase_reg_current_backed_size(reg), + kbase_reg_current_backed_size(reg), kctx->as_nr, true); } diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem.h b/drivers/gpu/arm/bifrost/mali_kbase_mem.h index f0f5f92c793c..490ad3c9c2e2 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem.h @@ -38,6 +38,7 @@ /* Required for kbase_mem_evictable_unmake */ #include "mali_kbase_mem_linux.h" #include "mali_kbase_mem_migrate.h" +#include "mali_kbase_refcount_defs.h" static inline void kbase_process_page_usage_inc(struct kbase_context *kctx, int pages); @@ -419,8 +420,8 @@ static inline struct kbase_mem_phy_alloc *kbase_mem_phy_alloc_put(struct kbase_m * @jit_usage_id: The last just-in-time memory usage ID for this region. * @jit_bin_id: The just-in-time memory bin this region came from. * @va_refcnt: Number of users of this region. Protected by reg_lock. - * @no_user_free_refcnt: Number of users that want to prevent the region from - * being freed by userspace. + * @no_user_free_count: Number of contexts that want to prevent the region + * from being freed by userspace. * @heap_info_gpu_addr: Pointer to an object in GPU memory defining an end of * an allocated region * The object can be one of: @@ -681,8 +682,8 @@ struct kbase_va_region { size_t used_pages; #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */ - int va_refcnt; - int no_user_free_refcnt; + kbase_refcount_t va_refcnt; + atomic_t no_user_free_count; }; /** @@ -759,15 +760,12 @@ static inline void kbase_region_refcnt_free(struct kbase_device *kbdev, static inline struct kbase_va_region *kbase_va_region_alloc_get( struct kbase_context *kctx, struct kbase_va_region *region) { - lockdep_assert_held(&kctx->reg_lock); + WARN_ON(!kbase_refcount_read(®ion->va_refcnt)); + WARN_ON(kbase_refcount_read(®ion->va_refcnt) == INT_MAX); - WARN_ON(!region->va_refcnt); - WARN_ON(region->va_refcnt == INT_MAX); - - /* non-atomic as kctx->reg_lock is held */ dev_dbg(kctx->kbdev->dev, "va_refcnt %d before get %pK\n", - region->va_refcnt, (void *)region); - region->va_refcnt++; + kbase_refcount_read(®ion->va_refcnt), (void *)region); + kbase_refcount_inc(®ion->va_refcnt); return region; } @@ -775,17 +773,14 @@ static inline struct kbase_va_region *kbase_va_region_alloc_get( static inline struct kbase_va_region *kbase_va_region_alloc_put( struct kbase_context *kctx, struct kbase_va_region *region) { - lockdep_assert_held(&kctx->reg_lock); - - WARN_ON(region->va_refcnt <= 0); + WARN_ON(kbase_refcount_read(®ion->va_refcnt) <= 0); WARN_ON(region->flags & KBASE_REG_FREE); - /* non-atomic as kctx->reg_lock is held */ - region->va_refcnt--; - dev_dbg(kctx->kbdev->dev, "va_refcnt %d after put %pK\n", - region->va_refcnt, (void *)region); - if (!region->va_refcnt) + if (kbase_refcount_dec_and_test(®ion->va_refcnt)) kbase_region_refcnt_free(kctx->kbdev, region); + else + dev_dbg(kctx->kbdev->dev, "va_refcnt %d after put %pK\n", + kbase_refcount_read(®ion->va_refcnt), (void *)region); return NULL; } @@ -799,58 +794,44 @@ static inline struct kbase_va_region *kbase_va_region_alloc_put( * Hence, callers cannot rely on this check alone to determine if a region might be shrunk * by any part of kbase. Instead they should use kbase_is_region_shrinkable(). * - * @kctx: Pointer to kbase context. * @region: Pointer to region. * * Return: true if userspace cannot free the region, false if userspace can free the region. */ -static inline bool kbase_va_region_is_no_user_free(struct kbase_context *kctx, - struct kbase_va_region *region) +static inline bool kbase_va_region_is_no_user_free(struct kbase_va_region *region) { - lockdep_assert_held(&kctx->reg_lock); - return region->no_user_free_refcnt > 0; + return atomic_read(®ion->no_user_free_count) > 0; } /** - * kbase_va_region_no_user_free_get - Increment "no user free" refcount for a region. + * kbase_va_region_no_user_free_inc - Increment "no user free" count for a region. * Calling this function will prevent the region to be shrunk by parts of kbase that - * don't own the region (as long as the refcount stays above zero). Refer to + * don't own the region (as long as the count stays above zero). Refer to * kbase_va_region_is_no_user_free() for more information. * - * @kctx: Pointer to kbase context. * @region: Pointer to region (not shrinkable). * * Return: the pointer to the region passed as argument. */ -static inline struct kbase_va_region * -kbase_va_region_no_user_free_get(struct kbase_context *kctx, struct kbase_va_region *region) +static inline void kbase_va_region_no_user_free_inc(struct kbase_va_region *region) { - lockdep_assert_held(&kctx->reg_lock); - WARN_ON(kbase_is_region_shrinkable(region)); - WARN_ON(region->no_user_free_refcnt == INT_MAX); + WARN_ON(atomic_read(®ion->no_user_free_count) == INT_MAX); /* non-atomic as kctx->reg_lock is held */ - region->no_user_free_refcnt++; - - return region; + atomic_inc(®ion->no_user_free_count); } /** - * kbase_va_region_no_user_free_put - Decrement "no user free" refcount for a region. + * kbase_va_region_no_user_free_dec - Decrement "no user free" count for a region. * - * @kctx: Pointer to kbase context. * @region: Pointer to region (not shrinkable). */ -static inline void kbase_va_region_no_user_free_put(struct kbase_context *kctx, - struct kbase_va_region *region) +static inline void kbase_va_region_no_user_free_dec(struct kbase_va_region *region) { - lockdep_assert_held(&kctx->reg_lock); + WARN_ON(!kbase_va_region_is_no_user_free(region)); - WARN_ON(!kbase_va_region_is_no_user_free(kctx, region)); - - /* non-atomic as kctx->reg_lock is held */ - region->no_user_free_refcnt--; + atomic_dec(®ion->no_user_free_count); } /* Common functions */ @@ -1148,6 +1129,9 @@ void kbase_mem_pool_free_locked(struct kbase_mem_pool *pool, struct page *p, * @pages: Pointer to array where the physical address of the allocated * pages will be stored. * @partial_allowed: If fewer pages allocated is allowed + * @page_owner: Pointer to the task that created the Kbase context for which + * the pages are being allocated. It can be NULL if the pages + * won't be associated with any Kbase context. * * Like kbase_mem_pool_alloc() but optimized for allocating many pages. * @@ -1164,7 +1148,8 @@ void kbase_mem_pool_free_locked(struct kbase_mem_pool *pool, struct page *p, * this lock, it should use kbase_mem_pool_alloc_pages_locked() instead. */ int kbase_mem_pool_alloc_pages(struct kbase_mem_pool *pool, size_t nr_4k_pages, - struct tagged_addr *pages, bool partial_allowed); + struct tagged_addr *pages, bool partial_allowed, + struct task_struct *page_owner); /** * kbase_mem_pool_alloc_pages_locked - Allocate pages from memory pool @@ -1276,13 +1261,17 @@ void kbase_mem_pool_set_max_size(struct kbase_mem_pool *pool, size_t max_size); * kbase_mem_pool_grow - Grow the pool * @pool: Memory pool to grow * @nr_to_grow: Number of pages to add to the pool + * @page_owner: Pointer to the task that created the Kbase context for which + * the memory pool is being grown. It can be NULL if the pages + * to be allocated won't be associated with any Kbase context. * * Adds @nr_to_grow pages to the pool. Note that this may cause the pool to * become larger than the maximum size specified. * * Return: 0 on success, -ENOMEM if unable to allocate sufficent pages */ -int kbase_mem_pool_grow(struct kbase_mem_pool *pool, size_t nr_to_grow); +int kbase_mem_pool_grow(struct kbase_mem_pool *pool, size_t nr_to_grow, + struct task_struct *page_owner); /** * kbase_mem_pool_trim - Grow or shrink the pool to a new size @@ -1398,8 +1387,8 @@ struct kbase_va_region *kbase_region_tracker_find_region_base_address( struct kbase_va_region *kbase_find_region_base_address(struct rb_root *rbtree, u64 gpu_addr); -struct kbase_va_region *kbase_alloc_free_region(struct rb_root *rbtree, - u64 start_pfn, size_t nr_pages, int zone); +struct kbase_va_region *kbase_alloc_free_region(struct kbase_device *kbdev, struct rb_root *rbtree, + u64 start_pfn, size_t nr_pages, int zone); void kbase_free_alloced_region(struct kbase_va_region *reg); int kbase_add_va_region(struct kbase_context *kctx, struct kbase_va_region *reg, u64 addr, size_t nr_pages, size_t align); @@ -1410,6 +1399,32 @@ int kbase_add_va_region_rbtree(struct kbase_device *kbdev, bool kbase_check_alloc_flags(unsigned long flags); bool kbase_check_import_flags(unsigned long flags); +static inline bool kbase_import_size_is_valid(struct kbase_device *kbdev, u64 va_pages) +{ + if (va_pages > KBASE_MEM_ALLOC_MAX_SIZE) { + dev_dbg( + kbdev->dev, + "Import attempted with va_pages==%lld larger than KBASE_MEM_ALLOC_MAX_SIZE!", + (unsigned long long)va_pages); + return false; + } + + return true; +} + +static inline bool kbase_alias_size_is_valid(struct kbase_device *kbdev, u64 va_pages) +{ + if (va_pages > KBASE_MEM_ALLOC_MAX_SIZE) { + dev_dbg( + kbdev->dev, + "Alias attempted with va_pages==%lld larger than KBASE_MEM_ALLOC_MAX_SIZE!", + (unsigned long long)va_pages); + return false; + } + + return true; +} + /** * kbase_check_alloc_sizes - check user space sizes parameters for an * allocation @@ -1737,7 +1752,7 @@ int kbase_alloc_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, * * @prealloc_sa: Information about the partial allocation if the amount of memory requested * is not a multiple of 2MB. One instance of struct kbase_sub_alloc must be - * allocated by the caller iff CONFIG_MALI_2MB_ALLOC is enabled. + * allocated by the caller if kbdev->pagesize_2mb is enabled. * * Allocates @nr_pages_requested and updates the alloc object. This function does not allocate new * pages from the kernel, and therefore will never trigger the OoM killer. Therefore, it can be @@ -1765,7 +1780,7 @@ int kbase_alloc_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, * This ensures that the pool can be grown to the required size and that the allocation can * complete without another thread using the newly grown pages. * - * If CONFIG_MALI_2MB_ALLOC is defined and the allocation is >= 2MB, then @pool must be one of the + * If kbdev->pagesize_2mb is enabled and the allocation is >= 2MB, then @pool must be one of the * pools from alloc->imported.native.kctx->mem_pools.large[]. Otherwise it must be one of the * mempools from alloc->imported.native.kctx->mem_pools.small[]. * @@ -2494,8 +2509,7 @@ kbase_ctx_reg_zone_get(struct kbase_context *kctx, unsigned long zone_bits) * kbase_mem_allow_alloc - Check if allocation of GPU memory is allowed * @kctx: Pointer to kbase context * - * Don't allow the allocation of GPU memory until user space has set up the - * tracking page (which sets kctx->process_mm) or if the ioctl has been issued + * Don't allow the allocation of GPU memory if the ioctl has been issued * from the forked child process using the mali device file fd inherited from * the parent process. * @@ -2503,13 +2517,23 @@ kbase_ctx_reg_zone_get(struct kbase_context *kctx, unsigned long zone_bits) */ static inline bool kbase_mem_allow_alloc(struct kbase_context *kctx) { - bool allow_alloc = true; + return (kctx->process_mm == current->mm); +} - rcu_read_lock(); - allow_alloc = (rcu_dereference(kctx->process_mm) == current->mm); - rcu_read_unlock(); - - return allow_alloc; +/** + * kbase_mem_mmgrab - Wrapper function to take reference on mm_struct of current process + */ +static inline void kbase_mem_mmgrab(void) +{ + /* This merely takes a reference on the memory descriptor structure + * i.e. mm_struct of current process and not on its address space and + * so won't block the freeing of address space on process exit. + */ +#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE + atomic_inc(¤t->mm->mm_count); +#else + mmgrab(current->mm); +#endif } /** diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c b/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c index 998849fa4cc2..f1251a4ed575 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem_linux.c @@ -37,7 +37,7 @@ #include #include #include - +#include #include #include #include @@ -385,8 +385,7 @@ struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, u64 va_pages zone = KBASE_REG_ZONE_CUSTOM_VA; } - reg = kbase_alloc_free_region(rbtree, PFN_DOWN(*gpu_va), - va_pages, zone); + reg = kbase_alloc_free_region(kctx->kbdev, rbtree, PFN_DOWN(*gpu_va), va_pages, zone); if (!reg) { dev_err(dev, "Failed to allocate free region"); @@ -481,22 +480,22 @@ struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, u64 va_pages } else /* we control the VA */ { size_t align = 1; -#ifdef CONFIG_MALI_2MB_ALLOC - /* If there's enough (> 33 bits) of GPU VA space, align to 2MB - * boundaries. The similar condition is used for mapping from - * the SAME_VA zone inside kbase_context_get_unmapped_area(). - */ - if (kctx->kbdev->gpu_props.mmu.va_bits > 33) { - if (va_pages >= (SZ_2M / SZ_4K)) - align = (SZ_2M / SZ_4K); - } - if (*gpu_va) - align = 1; + if (kctx->kbdev->pagesize_2mb) { + /* If there's enough (> 33 bits) of GPU VA space, align to 2MB + * boundaries. The similar condition is used for mapping from + * the SAME_VA zone inside kbase_context_get_unmapped_area(). + */ + if (kctx->kbdev->gpu_props.mmu.va_bits > 33) { + if (va_pages >= (SZ_2M / SZ_4K)) + align = (SZ_2M / SZ_4K); + } + if (*gpu_va) + align = 1; #if !MALI_USE_CSF - if (reg->flags & KBASE_REG_TILER_ALIGN_TOP) - align = 1; + if (reg->flags & KBASE_REG_TILER_ALIGN_TOP) + align = 1; #endif /* !MALI_USE_CSF */ -#endif /* CONFIG_MALI_2MB_ALLOC */ + } if (kbase_gpu_mmap(kctx, reg, *gpu_va, va_pages, align, mmu_sync_info) != 0) { dev_warn(dev, "Failed to map memory on GPU"); @@ -999,7 +998,7 @@ int kbase_mem_flags_change(struct kbase_context *kctx, u64 gpu_addr, unsigned in * & GPU queue ringbuffer and none of them needs to be explicitly marked * as evictable by Userspace. */ - if (kbase_va_region_is_no_user_free(kctx, reg)) + if (kbase_va_region_is_no_user_free(reg)) goto out_unlock; /* Is the region being transitioning between not needed and needed? */ @@ -1322,10 +1321,11 @@ int kbase_mem_umm_map(struct kbase_context *kctx, gwt_mask = ~KBASE_REG_GPU_WR; #endif - err = kbase_mmu_insert_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, - kbase_get_gpu_phy_pages(reg), - kbase_reg_current_backed_size(reg), reg->flags & gwt_mask, - kctx->as_nr, alloc->group_id, mmu_sync_info, NULL, true); + err = kbase_mmu_insert_imported_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + kbase_get_gpu_phy_pages(reg), + kbase_reg_current_backed_size(reg), + reg->flags & gwt_mask, kctx->as_nr, alloc->group_id, + mmu_sync_info, NULL); if (err) goto bad_insert; @@ -1338,11 +1338,11 @@ int kbase_mem_umm_map(struct kbase_context *kctx, * Assume alloc->nents is the number of actual pages in the * dma-buf memory. */ - err = kbase_mmu_insert_single_page( - kctx, reg->start_pfn + alloc->nents, - kctx->aliasing_sink_page, reg->nr_pages - alloc->nents, - (reg->flags | KBASE_REG_GPU_RD) & ~KBASE_REG_GPU_WR, - KBASE_MEM_GROUP_SINK, mmu_sync_info); + err = kbase_mmu_insert_single_imported_page( + kctx, reg->start_pfn + alloc->nents, kctx->aliasing_sink_page, + reg->nr_pages - alloc->nents, + (reg->flags | KBASE_REG_GPU_RD) & ~KBASE_REG_GPU_WR, KBASE_MEM_GROUP_SINK, + mmu_sync_info); if (err) goto bad_pad_insert; } @@ -1351,7 +1351,7 @@ int kbase_mem_umm_map(struct kbase_context *kctx, bad_pad_insert: kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, - alloc->nents, kctx->as_nr, true); + alloc->nents, alloc->nents, kctx->as_nr, true); bad_insert: kbase_mem_umm_unmap_attachment(kctx, alloc); bad_map_attachment: @@ -1380,7 +1380,8 @@ void kbase_mem_umm_unmap(struct kbase_context *kctx, int err; err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, - alloc->pages, reg->nr_pages, kctx->as_nr, true); + alloc->pages, reg->nr_pages, reg->nr_pages, + kctx->as_nr, true); WARN_ON(err); } @@ -1452,6 +1453,9 @@ static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, return NULL; } + if (!kbase_import_size_is_valid(kctx->kbdev, *va_pages)) + return NULL; + /* ignore SAME_VA */ *flags &= ~BASE_MEM_SAME_VA; @@ -1472,23 +1476,21 @@ static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, if (*flags & BASE_MEM_IMPORT_SYNC_ON_MAP_UNMAP) need_sync = true; -#if IS_ENABLED(CONFIG_64BIT) - if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { + if (!kbase_ctx_compat_mode(kctx)) { /* * 64-bit tasks require us to reserve VA on the CPU that we use * on the GPU. */ shared_zone = true; } -#endif if (shared_zone) { *flags |= BASE_MEM_NEED_MMAP; - reg = kbase_alloc_free_region(&kctx->reg_rbtree_same, - 0, *va_pages, KBASE_REG_ZONE_SAME_VA); + reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_same, 0, *va_pages, + KBASE_REG_ZONE_SAME_VA); } else { - reg = kbase_alloc_free_region(&kctx->reg_rbtree_custom, - 0, *va_pages, KBASE_REG_ZONE_CUSTOM_VA); + reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_custom, 0, *va_pages, + KBASE_REG_ZONE_CUSTOM_VA); } if (!reg) { @@ -1621,21 +1623,22 @@ static struct kbase_va_region *kbase_mem_from_user_buffer( /* 64-bit address range is the max */ goto bad_size; + if (!kbase_import_size_is_valid(kctx->kbdev, *va_pages)) + goto bad_size; + /* SAME_VA generally not supported with imported memory (no known use cases) */ *flags &= ~BASE_MEM_SAME_VA; if (*flags & BASE_MEM_IMPORT_SHARED) shared_zone = true; -#if IS_ENABLED(CONFIG_64BIT) - if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { + if (!kbase_ctx_compat_mode(kctx)) { /* * 64-bit tasks require us to reserve VA on the CPU that we use * on the GPU. */ shared_zone = true; } -#endif if (shared_zone) { *flags |= BASE_MEM_NEED_MMAP; @@ -1644,7 +1647,7 @@ static struct kbase_va_region *kbase_mem_from_user_buffer( } else rbtree = &kctx->reg_rbtree_custom; - reg = kbase_alloc_free_region(rbtree, 0, *va_pages, zone); + reg = kbase_alloc_free_region(kctx->kbdev, rbtree, 0, *va_pages, zone); if (!reg) goto no_region; @@ -1670,11 +1673,7 @@ static struct kbase_va_region *kbase_mem_from_user_buffer( user_buf->address = address; user_buf->nr_pages = *va_pages; user_buf->mm = current->mm; -#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE - atomic_inc(¤t->mm->mm_count); -#else - mmgrab(current->mm); -#endif + kbase_mem_mmgrab(); if (reg->gpu_alloc->properties & KBASE_MEM_PHY_ALLOC_LARGE) user_buf->pages = vmalloc(*va_pages * sizeof(struct page *)); else @@ -1749,10 +1748,13 @@ static struct kbase_va_region *kbase_mem_from_user_buffer( * region, otherwise the initial content of memory would be wrong. */ for (i = 0; i < faulted_pages; i++) { - dma_addr_t dma_addr = - dma_map_page_attrs(dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL, - DMA_ATTR_SKIP_CPU_SYNC); - + dma_addr_t dma_addr; +#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) + dma_addr = dma_map_page(dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL); +#else + dma_addr = dma_map_page_attrs(dev, pages[i], 0, PAGE_SIZE, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); +#endif if (dma_mapping_error(dev, dma_addr)) goto unwind_dma_map; @@ -1779,8 +1781,12 @@ unwind_dma_map: dma_addr_t dma_addr = user_buf->dma_addrs[i]; dma_sync_single_for_device(dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); +#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) + dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); +#else dma_unmap_page_attrs(dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); +#endif } fault_mismatch: if (pages) { @@ -1856,22 +1862,19 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, /* calculate the number of pages this alias will cover */ *num_pages = nents * stride; -#if IS_ENABLED(CONFIG_64BIT) - if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { + if (!kbase_alias_size_is_valid(kctx->kbdev, *num_pages)) + goto bad_size; + + if (!kbase_ctx_compat_mode(kctx)) { /* 64-bit tasks must MMAP anyway, but not expose this address to * clients */ *flags |= BASE_MEM_NEED_MMAP; - reg = kbase_alloc_free_region(&kctx->reg_rbtree_same, 0, - *num_pages, - KBASE_REG_ZONE_SAME_VA); + reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_same, 0, *num_pages, + KBASE_REG_ZONE_SAME_VA); } else { -#else - if (1) { -#endif - reg = kbase_alloc_free_region(&kctx->reg_rbtree_custom, - 0, *num_pages, - KBASE_REG_ZONE_CUSTOM_VA); + reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_custom, 0, *num_pages, + KBASE_REG_ZONE_CUSTOM_VA); } if (!reg) @@ -1922,7 +1925,7 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, goto bad_handle; /* Not found/already free */ if (kbase_is_region_shrinkable(aliasing_reg)) goto bad_handle; /* Ephemeral region */ - if (kbase_va_region_is_no_user_free(kctx, aliasing_reg)) + if (kbase_va_region_is_no_user_free(aliasing_reg)) goto bad_handle; /* JIT regions can't be * aliased. NO_USER_FREE flag * covers the entire lifetime @@ -1977,8 +1980,7 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, } } -#if IS_ENABLED(CONFIG_64BIT) - if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { + if (!kbase_ctx_compat_mode(kctx)) { /* Bind to a cookie */ if (bitmap_empty(kctx->cookies, BITS_PER_LONG)) { dev_err(kctx->kbdev->dev, "No cookies available for allocation!"); @@ -1993,10 +1995,8 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, /* relocate to correct base */ gpu_va += PFN_DOWN(BASE_MEM_COOKIE_BASE); gpu_va <<= PAGE_SHIFT; - } else /* we control the VA */ { -#else - if (1) { -#endif + } else { + /* we control the VA */ if (kbase_gpu_mmap(kctx, reg, 0, *num_pages, 1, mmu_sync_info) != 0) { dev_warn(kctx->kbdev->dev, "Failed to map memory on GPU"); @@ -2013,9 +2013,7 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, return gpu_va; -#if IS_ENABLED(CONFIG_64BIT) no_cookie: -#endif no_mmap: bad_handle: /* Marking the source allocs as not being mapped on the GPU and putting @@ -2230,7 +2228,7 @@ int kbase_mem_shrink_gpu_mapping(struct kbase_context *const kctx, int ret = 0; ret = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn + new_pages, - alloc->pages + new_pages, delta, kctx->as_nr, false); + alloc->pages + new_pages, delta, delta, kctx->as_nr, false); return ret; } @@ -2298,7 +2296,7 @@ int kbase_mem_commit(struct kbase_context *kctx, u64 gpu_addr, u64 new_pages) if (kbase_is_region_shrinkable(reg)) goto out_unlock; - if (kbase_va_region_is_no_user_free(kctx, reg)) + if (kbase_va_region_is_no_user_free(reg)) goto out_unlock; #ifdef CONFIG_MALI_MEMORY_FULLY_BACKED @@ -2401,18 +2399,19 @@ int kbase_mem_shrink(struct kbase_context *const kctx, kbase_free_phy_pages_helper(reg->cpu_alloc, delta); if (reg->cpu_alloc != reg->gpu_alloc) kbase_free_phy_pages_helper(reg->gpu_alloc, delta); -#ifdef CONFIG_MALI_2MB_ALLOC - if (kbase_reg_current_backed_size(reg) > new_pages) { - old_pages = new_pages; - new_pages = kbase_reg_current_backed_size(reg); - /* Update GPU mapping. */ - err = kbase_mem_grow_gpu_mapping(kctx, reg, - new_pages, old_pages, CALLER_MMU_ASYNC); + if (kctx->kbdev->pagesize_2mb) { + if (kbase_reg_current_backed_size(reg) > new_pages) { + old_pages = new_pages; + new_pages = kbase_reg_current_backed_size(reg); + + /* Update GPU mapping. */ + err = kbase_mem_grow_gpu_mapping(kctx, reg, new_pages, old_pages, + CALLER_MMU_ASYNC); + } + } else { + WARN_ON(kbase_reg_current_backed_size(reg) != new_pages); } -#else - WARN_ON(kbase_reg_current_backed_size(reg) != new_pages); -#endif } return err; @@ -2710,8 +2709,8 @@ static int kbase_mmu_dump_mmap(struct kbase_context *kctx, goto out; } - new_reg = kbase_alloc_free_region(&kctx->reg_rbtree_same, 0, nr_pages, - KBASE_REG_ZONE_SAME_VA); + new_reg = kbase_alloc_free_region(kctx->kbdev, &kctx->reg_rbtree_same, 0, nr_pages, + KBASE_REG_ZONE_SAME_VA); if (!new_reg) { err = -ENOMEM; WARN_ON(1); @@ -3381,79 +3380,29 @@ static void kbasep_add_mm_counter(struct mm_struct *mm, int member, long value) void kbasep_os_process_page_usage_update(struct kbase_context *kctx, int pages) { - struct mm_struct *mm; + struct mm_struct *mm = kctx->process_mm; - rcu_read_lock(); - mm = rcu_dereference(kctx->process_mm); - if (mm) { - atomic_add(pages, &kctx->nonmapped_pages); -#ifdef SPLIT_RSS_COUNTING - kbasep_add_mm_counter(mm, MM_FILEPAGES, pages); -#else - spin_lock(&mm->page_table_lock); - kbasep_add_mm_counter(mm, MM_FILEPAGES, pages); - spin_unlock(&mm->page_table_lock); -#endif - } - rcu_read_unlock(); -} - -static void kbasep_os_process_page_usage_drain(struct kbase_context *kctx) -{ - int pages; - struct mm_struct *mm; - - spin_lock(&kctx->mm_update_lock); - mm = rcu_dereference_protected(kctx->process_mm, lockdep_is_held(&kctx->mm_update_lock)); - if (!mm) { - spin_unlock(&kctx->mm_update_lock); + if (unlikely(!mm)) return; - } - rcu_assign_pointer(kctx->process_mm, NULL); - spin_unlock(&kctx->mm_update_lock); - synchronize_rcu(); - - pages = atomic_xchg(&kctx->nonmapped_pages, 0); + atomic_add(pages, &kctx->nonmapped_pages); #ifdef SPLIT_RSS_COUNTING - kbasep_add_mm_counter(mm, MM_FILEPAGES, -pages); + kbasep_add_mm_counter(mm, MM_FILEPAGES, pages); #else spin_lock(&mm->page_table_lock); - kbasep_add_mm_counter(mm, MM_FILEPAGES, -pages); + kbasep_add_mm_counter(mm, MM_FILEPAGES, pages); spin_unlock(&mm->page_table_lock); #endif } -static void kbase_special_vm_close(struct vm_area_struct *vma) -{ - struct kbase_context *kctx; - - kctx = vma->vm_private_data; - kbasep_os_process_page_usage_drain(kctx); -} - -static const struct vm_operations_struct kbase_vm_special_ops = { - .close = kbase_special_vm_close, -}; - static int kbase_tracking_page_setup(struct kbase_context *kctx, struct vm_area_struct *vma) { - /* check that this is the only tracking page */ - spin_lock(&kctx->mm_update_lock); - if (rcu_dereference_protected(kctx->process_mm, lockdep_is_held(&kctx->mm_update_lock))) { - spin_unlock(&kctx->mm_update_lock); - return -EFAULT; - } - - rcu_assign_pointer(kctx->process_mm, current->mm); - - spin_unlock(&kctx->mm_update_lock); + if (vma_pages(vma) != 1) + return -EINVAL; /* no real access */ vma->vm_flags &= ~(VM_READ | VM_MAYREAD | VM_WRITE | VM_MAYWRITE | VM_EXEC | VM_MAYEXEC); vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP | VM_IO; - vma->vm_ops = &kbase_vm_special_ops; - vma->vm_private_data = kctx; return 0; } @@ -3726,23 +3675,27 @@ static void kbase_csf_user_reg_vm_open(struct vm_area_struct *vma) static void kbase_csf_user_reg_vm_close(struct vm_area_struct *vma) { struct kbase_context *kctx = vma->vm_private_data; + struct kbase_device *kbdev; - if (!kctx) { + if (unlikely(!kctx)) { pr_debug("Close function called for the unexpected mapping"); return; } - if (unlikely(!kctx->csf.user_reg_vma)) - dev_warn(kctx->kbdev->dev, "user_reg_vma pointer unexpectedly NULL"); + kbdev = kctx->kbdev; - kctx->csf.user_reg_vma = NULL; + if (unlikely(!kctx->csf.user_reg.vma)) + dev_warn(kbdev->dev, "user_reg VMA pointer unexpectedly NULL for ctx %d_%d", + kctx->tgid, kctx->id); - mutex_lock(&kctx->kbdev->csf.reg_lock); - if (unlikely(kctx->kbdev->csf.nr_user_page_mapped == 0)) - dev_warn(kctx->kbdev->dev, "Unexpected value for the USER page mapping counter"); - else - kctx->kbdev->csf.nr_user_page_mapped--; - mutex_unlock(&kctx->kbdev->csf.reg_lock); + mutex_lock(&kbdev->csf.reg_lock); + list_del_init(&kctx->csf.user_reg.link); + mutex_unlock(&kbdev->csf.reg_lock); + + kctx->csf.user_reg.vma = NULL; + + /* Now as the VMA is closed, drop the reference on mali device file */ + fput(kctx->filp); } /** @@ -3787,10 +3740,11 @@ static vm_fault_t kbase_csf_user_reg_vm_fault(struct vm_fault *vmf) unsigned long flags; /* Few sanity checks up front */ - if (!kctx || (nr_pages != 1) || (vma != kctx->csf.user_reg_vma) || - (vma->vm_pgoff != PFN_DOWN(BASEP_MEM_CSF_USER_REG_PAGE_HANDLE))) { - pr_warn("Unexpected CPU page fault on USER page mapping for process %s tgid %d pid %d\n", - current->comm, current->tgid, current->pid); + + if (!kctx || (nr_pages != 1) || (vma != kctx->csf.user_reg.vma) || + (vma->vm_pgoff != kctx->csf.user_reg.file_offset)) { + pr_err("Unexpected CPU page fault on USER page mapping for process %s tgid %d pid %d\n", + current->comm, current->tgid, current->pid); return VM_FAULT_SIGBUS; } @@ -3799,22 +3753,22 @@ static vm_fault_t kbase_csf_user_reg_vm_fault(struct vm_fault *vmf) pfn = PFN_DOWN(kbdev->reg_start + USER_BASE); mutex_lock(&kbdev->csf.reg_lock); + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); - /* Don't map in the actual register page if GPU is powered down. - * Always map in the dummy page in no mali builds. + /* Dummy page will be mapped during GPU off. + * + * In no mail builds, always map in the dummy page. */ -#if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) - pfn = PFN_DOWN(as_phys_addr_t(kbdev->csf.dummy_user_reg_page)); -#else - if (!kbdev->pm.backend.gpu_powered) - pfn = PFN_DOWN(as_phys_addr_t(kbdev->csf.dummy_user_reg_page)); -#endif + if (IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) || !kbdev->pm.backend.gpu_powered) + pfn = PFN_DOWN(as_phys_addr_t(kbdev->csf.user_reg.dummy_page)); spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + list_move_tail(&kctx->csf.user_reg.link, &kbdev->csf.user_reg.list); ret = mgm_dev->ops.mgm_vmf_insert_pfn_prot(mgm_dev, KBASE_MEM_GROUP_CSF_FW, vma, vma->vm_start, pfn, vma->vm_page_prot); + mutex_unlock(&kbdev->csf.reg_lock); return ret; @@ -3827,20 +3781,6 @@ static const struct vm_operations_struct kbase_csf_user_reg_vm_ops = { .fault = kbase_csf_user_reg_vm_fault }; -/** - * kbase_csf_cpu_mmap_user_reg_page - Memory map method for USER page. - * - * @kctx: Pointer of the kernel context. - * @vma: Pointer to the struct containing the information about - * the userspace mapping of USER page. - * - * Return: 0 on success, error code otherwise. - * - * Note: - * New Base will request Kbase to read the LATEST_FLUSH of USER page on its behalf. - * But this function needs to be kept for backward-compatibility as old Base (<=1.12) - * will try to mmap USER page for direct access when it creates a base context. - */ static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, struct vm_area_struct *vma) { @@ -3848,7 +3788,7 @@ static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, struct kbase_device *kbdev = kctx->kbdev; /* Few sanity checks */ - if (kctx->csf.user_reg_vma) + if (kctx->csf.user_reg.vma) return -EBUSY; if (nr_pages != 1) @@ -3867,19 +3807,21 @@ static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, */ vma->vm_flags |= VM_PFNMAP; - kctx->csf.user_reg_vma = vma; + kctx->csf.user_reg.vma = vma; mutex_lock(&kbdev->csf.reg_lock); - kbdev->csf.nr_user_page_mapped++; - - if (!kbdev->csf.mali_file_inode) - kbdev->csf.mali_file_inode = kctx->filp->f_inode; - - if (unlikely(kbdev->csf.mali_file_inode != kctx->filp->f_inode)) - dev_warn(kbdev->dev, "Device file inode pointer not same for all contexts"); - + kctx->csf.user_reg.file_offset = kbdev->csf.user_reg.file_offset++; mutex_unlock(&kbdev->csf.reg_lock); + /* Make VMA point to the special internal file, but don't drop the + * reference on mali device file (that would be done later when the + * VMA is closed). + */ + vma->vm_file = kctx->kbdev->csf.user_reg.filp; + get_file(vma->vm_file); + + /* Also adjust the vm_pgoff */ + vma->vm_pgoff = kctx->csf.user_reg.file_offset; vma->vm_ops = &kbase_csf_user_reg_vm_ops; vma->vm_private_data = kctx; diff --git a/drivers/gpu/arm/bifrost/mali_kbase_mem_pool.c b/drivers/gpu/arm/bifrost/mali_kbase_mem_pool.c index 75569cc51c52..fa8f34d86c24 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_mem_pool.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_mem_pool.c @@ -28,6 +28,11 @@ #include #include #include +#if KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE +#include +#else +#include +#endif #define pool_dbg(pool, format, ...) \ dev_dbg(pool->kbdev->dev, "%s-pool [%zu/%zu]: " format, \ @@ -39,6 +44,47 @@ #define NOT_DIRTY false #define NOT_RECLAIMED false +/** + * can_alloc_page() - Check if the current thread can allocate a physical page + * + * @pool: Pointer to the memory pool. + * @page_owner: Pointer to the task/process that created the Kbase context + * for which a page needs to be allocated. It can be NULL if + * the page won't be associated with Kbase context. + * @alloc_from_kthread: Flag indicating that the current thread is a kernel thread. + * + * This function checks if the current thread is a kernel thread and can make a + * request to kernel to allocate a physical page. If the kernel thread is allocating + * a page for the Kbase context and the process that created the context is exiting + * or is being killed, then there is no point in doing a page allocation. + * + * The check done by the function is particularly helpful when the system is running + * low on memory. When a page is allocated from the context of a kernel thread, OoM + * killer doesn't consider the kernel thread for killing and kernel keeps retrying + * to allocate the page as long as the OoM killer is able to kill processes. + * The check allows kernel thread to quickly exit the page allocation loop once OoM + * killer has initiated the killing of @page_owner, thereby unblocking the context + * termination for @page_owner and freeing of GPU memory allocated by it. This helps + * in preventing the kernel panic and also limits the number of innocent processes + * that get killed. + * + * Return: true if the page can be allocated otherwise false. + */ +static inline bool can_alloc_page(struct kbase_mem_pool *pool, struct task_struct *page_owner, + const bool alloc_from_kthread) +{ + if (likely(!alloc_from_kthread || !page_owner)) + return true; + + if ((page_owner->flags & PF_EXITING) || fatal_signal_pending(page_owner)) { + dev_info(pool->kbdev->dev, "%s : Process %s/%d exiting", + __func__, page_owner->comm, task_pid_nr(page_owner)); + return false; + } + + return true; +} + static size_t kbase_mem_pool_capacity(struct kbase_mem_pool *pool) { ssize_t max_size = kbase_mem_pool_max_size(pool); @@ -342,10 +388,12 @@ static size_t kbase_mem_pool_shrink(struct kbase_mem_pool *pool, return nr_freed; } -int kbase_mem_pool_grow(struct kbase_mem_pool *pool, size_t nr_to_grow) +int kbase_mem_pool_grow(struct kbase_mem_pool *pool, size_t nr_to_grow, + struct task_struct *page_owner) { struct page *p; size_t i; + const bool alloc_from_kthread = !!(current->flags & PF_KTHREAD); kbase_mem_pool_lock(pool); @@ -360,6 +408,9 @@ int kbase_mem_pool_grow(struct kbase_mem_pool *pool, size_t nr_to_grow) } kbase_mem_pool_unlock(pool); + if (unlikely(!can_alloc_page(pool, page_owner, alloc_from_kthread))) + return -ENOMEM; + p = kbase_mem_alloc_page(pool); if (!p) { kbase_mem_pool_lock(pool); @@ -392,7 +443,7 @@ void kbase_mem_pool_trim(struct kbase_mem_pool *pool, size_t new_size) if (new_size < cur_size) kbase_mem_pool_shrink(pool, cur_size - new_size); else if (new_size > cur_size) - err = kbase_mem_pool_grow(pool, new_size - cur_size); + err = kbase_mem_pool_grow(pool, new_size - cur_size, NULL); if (err) { size_t grown_size = kbase_mem_pool_size(pool); @@ -656,13 +707,15 @@ void kbase_mem_pool_free_locked(struct kbase_mem_pool *pool, struct page *p, } int kbase_mem_pool_alloc_pages(struct kbase_mem_pool *pool, size_t nr_4k_pages, - struct tagged_addr *pages, bool partial_allowed) + struct tagged_addr *pages, bool partial_allowed, + struct task_struct *page_owner) { struct page *p; size_t nr_from_pool; size_t i = 0; int err = -ENOMEM; size_t nr_pages_internal; + const bool alloc_from_kthread = !!(current->flags & PF_KTHREAD); nr_pages_internal = nr_4k_pages / (1u << (pool->order)); @@ -697,7 +750,7 @@ int kbase_mem_pool_alloc_pages(struct kbase_mem_pool *pool, size_t nr_4k_pages, if (i != nr_4k_pages && pool->next_pool) { /* Allocate via next pool */ err = kbase_mem_pool_alloc_pages(pool->next_pool, nr_4k_pages - i, pages + i, - partial_allowed); + partial_allowed, page_owner); if (err < 0) goto err_rollback; @@ -706,6 +759,9 @@ int kbase_mem_pool_alloc_pages(struct kbase_mem_pool *pool, size_t nr_4k_pages, } else { /* Get any remaining pages from kernel */ while (i != nr_4k_pages) { + if (unlikely(!can_alloc_page(pool, page_owner, alloc_from_kthread))) + goto err_rollback; + p = kbase_mem_alloc_page(pool); if (!p) { if (partial_allowed) diff --git a/drivers/gpu/arm/bifrost/mali_kbase_refcount_defs.h b/drivers/gpu/arm/bifrost/mali_kbase_refcount_defs.h new file mode 100644 index 000000000000..c517a2d2ab83 --- /dev/null +++ b/drivers/gpu/arm/bifrost/mali_kbase_refcount_defs.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * + * (C) COPYRIGHT 2023 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 _KBASE_REFCOUNT_DEFS_H_ +#define _KBASE_REFCOUNT_DEFS_H_ + +/* + * The Refcount API is available from 4.11 onwards + * This file hides the compatibility issues with this for the rest the driver + */ + +#include +#include + +#if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) + +#define kbase_refcount_t atomic_t +#define kbase_refcount_read(x) atomic_read(x) +#define kbase_refcount_set(x, v) atomic_set(x, v) +#define kbase_refcount_dec_and_test(x) atomic_dec_and_test(x) +#define kbase_refcount_dec(x) atomic_dec(x) +#define kbase_refcount_inc_not_zero(x) atomic_inc_not_zero(x) +#define kbase_refcount_inc(x) atomic_inc(x) + +#else + +#include + +#define kbase_refcount_t refcount_t +#define kbase_refcount_read(x) refcount_read(x) +#define kbase_refcount_set(x, v) refcount_set(x, v) +#define kbase_refcount_dec_and_test(x) refcount_dec_and_test(x) +#define kbase_refcount_dec(x) refcount_dec(x) +#define kbase_refcount_inc_not_zero(x) refcount_inc_not_zero(x) +#define kbase_refcount_inc(x) refcount_inc(x) + +#endif /* (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) */ + +#endif /* _KBASE_REFCOUNT_DEFS_H_ */ diff --git a/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c b/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c index 212a61f68372..a9312a0c433e 100644 --- a/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c +++ b/drivers/gpu/arm/bifrost/mali_kbase_softjobs.c @@ -943,6 +943,13 @@ static int kbase_jit_allocate_prepare(struct kbase_jd_atom *katom) int ret; u32 i; + if (!kbase_mem_allow_alloc(kctx)) { + dev_dbg(kbdev->dev, "Invalid attempt to allocate JIT memory by %s/%d for ctx %d_%d", + current->comm, current->pid, kctx->tgid, kctx->id); + ret = -EINVAL; + goto fail; + } + /* For backwards compatibility, and to prevent reading more than 1 jit * info struct on jit version 1 */ 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 4a0926531af2..4cac7876f5f7 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-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -150,17 +150,18 @@ void kbase_gpu_report_bus_fault_and_kill(struct kbase_context *kctx, "true" : "false"; int as_no = as->number; unsigned long flags; + const uintptr_t fault_addr = fault->addr; /* terminal fault, print info about the fault */ dev_err(kbdev->dev, - "GPU bus fault in AS%d at PA 0x%016llX\n" + "GPU bus fault in AS%d at PA %pK\n" "PA_VALID: %s\n" "raw fault status: 0x%X\n" "exception type 0x%X: %s\n" "access type 0x%X: %s\n" "source id 0x%X\n" "pid: %d\n", - as_no, fault->addr, + as_no, (void *)fault_addr, addr_valid, status, exception_type, kbase_gpu_exception_name(exception_type), @@ -557,6 +558,7 @@ int kbase_mmu_as_init(struct kbase_device *kbdev, unsigned int i) kbdev->as[i].bf_data.addr = 0ULL; kbdev->as[i].pf_data.addr = 0ULL; kbdev->as[i].gf_data.addr = 0ULL; + kbdev->as[i].is_unresponsive = false; kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", WQ_UNBOUND, 1, i); if (!kbdev->as[i].pf_wq) 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 83605c3dc56f..d716ce0068fd 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-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -63,15 +63,16 @@ void kbase_gpu_report_bus_fault_and_kill(struct kbase_context *kctx, u32 const exception_data = (status >> 8) & 0xFFFFFF; int const as_no = as->number; unsigned long flags; + const uintptr_t fault_addr = fault->addr; /* terminal fault, print info about the fault */ dev_err(kbdev->dev, - "GPU bus fault in AS%d at PA 0x%016llX\n" + "GPU bus fault in AS%d at PA %pK\n" "raw fault status: 0x%X\n" "exception type 0x%X: %s\n" "exception data 0x%X\n" "pid: %d\n", - as_no, fault->addr, + as_no, (void *)fault_addr, status, exception_type, kbase_gpu_exception_name(exception_type), exception_data, @@ -428,6 +429,7 @@ int kbase_mmu_as_init(struct kbase_device *kbdev, unsigned int i) kbdev->as[i].number = i; kbdev->as[i].bf_data.addr = 0ULL; kbdev->as[i].pf_data.addr = 0ULL; + kbdev->as[i].is_unresponsive = false; kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%u", 0, 1, i); if (!kbdev->as[i].pf_wq) diff --git a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c index 3131d57ef330..d6d3fcdee6e7 100644 --- a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c +++ b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 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 @@ -144,35 +144,21 @@ static void mmu_flush_pa_range(struct kbase_device *kbdev, phys_addr_t phys, siz enum kbase_mmu_op_type op) { u32 flush_op; - int ret; - - if (WARN_ON(kbdev == NULL)) - return; lockdep_assert_held(&kbdev->hwaccess_lock); /* Translate operation to command */ - if (op == KBASE_MMU_OP_FLUSH_PT) { + if (op == KBASE_MMU_OP_FLUSH_PT) flush_op = GPU_COMMAND_FLUSH_PA_RANGE_CLN_INV_L2; - } else if (op == KBASE_MMU_OP_FLUSH_MEM) { + else if (op == KBASE_MMU_OP_FLUSH_MEM) flush_op = GPU_COMMAND_FLUSH_PA_RANGE_CLN_INV_L2_LSC; - } else { + else { dev_warn(kbdev->dev, "Invalid flush request (op = %d)", op); return; } - ret = kbase_gpu_cache_flush_pa_range_and_busy_wait(kbdev, phys, nr_bytes, flush_op); - - if (ret) { - /* Flush failed to complete, assume the GPU has hung and - * perform a reset to recover - */ - dev_err(kbdev->dev, - "Flush for physical address range 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); - } + if (kbase_gpu_cache_flush_pa_range_and_busy_wait(kbdev, phys, nr_bytes, flush_op)) + dev_err(kbdev->dev, "Flush for physical address range did not complete"); } #endif @@ -190,21 +176,15 @@ static void mmu_flush_pa_range(struct kbase_device *kbdev, phys_addr_t phys, siz static void mmu_invalidate(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; 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_unlock(kbdev, &kbdev->as[as_nr], op_param); - } - - 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); + if (kbase_mmu_hw_do_unlock(kbdev, &kbdev->as[as_nr], op_param)) + dev_err(kbdev->dev, + "Invalidate after GPU page table update did not complete"); } spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); @@ -215,25 +195,14 @@ static void mmu_invalidate(struct kbase_device *kbdev, struct kbase_context *kct 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 = 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) - err = kbase_mmu_hw_do_flush_locked(kbdev, as, 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"); - - if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) - kbase_reset_gpu_locked(kbdev); - } + if (kbdev->pm.backend.gpu_powered && (kbase_mmu_hw_do_flush_locked(kbdev, as, op_param))) + dev_err(kbdev->dev, "Flush for GPU page table update did not complete"); spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); mutex_unlock(&kbdev->mmu_hw_mutex); @@ -308,7 +277,6 @@ static void mmu_flush_invalidate(struct kbase_device *kbdev, struct kbase_contex 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 */ @@ -317,19 +285,8 @@ static void mmu_flush_invalidate_on_gpu_ctrl(struct kbase_device *kbdev, struct 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"); - - if (kbase_prepare_to_reset_gpu(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) - kbase_reset_gpu(kbdev); + if (kbase_mmu_hw_do_flush_on_gpu_ctrl(kbdev, &kbdev->as[as_nr], op_param)) + dev_err(kbdev->dev, "Flush for GPU page table update did not complete"); } spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); @@ -405,13 +362,11 @@ static int kbase_mmu_update_pages_no_flush(struct kbase_device *kbdev, struct kb * @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. - * @free_pgds_list: Linked list of the page directory pages to free. */ 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, - enum kbase_mmu_op_type flush_op, u64 *dirty_pgds, - struct list_head *free_pgds_list); + enum kbase_mmu_op_type flush_op, u64 *dirty_pgds); static void kbase_mmu_account_freed_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *mmut) { @@ -485,14 +440,17 @@ static void kbase_mmu_free_pgd(struct kbase_device *kbdev, struct kbase_mmu_tabl phys_addr_t pgd) { struct page *p; + bool page_is_isolated = false; lockdep_assert_held(&mmut->mmu_lock); p = pfn_to_page(PFN_DOWN(pgd)); + page_is_isolated = kbase_mmu_handle_isolated_pgd_page(kbdev, mmut, p); - kbase_mem_pool_free(&kbdev->mem_pools.small[mmut->group_id], p, true); - - kbase_mmu_account_freed_pgd(kbdev, mmut); + if (likely(!page_is_isolated)) { + kbase_mem_pool_free(&kbdev->mem_pools.small[mmut->group_id], p, true); + kbase_mmu_account_freed_pgd(kbdev, mmut); + } } /** @@ -500,41 +458,42 @@ static void kbase_mmu_free_pgd(struct kbase_device *kbdev, struct kbase_mmu_tabl * * @kbdev: Device pointer. * @mmut: GPU MMU page table. - * @free_pgds_list: Linked list of the page directory pages to free. * * This function will call kbase_mmu_free_pgd() on each page directory page - * present in the @free_pgds_list. + * present in the list of free PGDs inside @mmut. * * The function is supposed to be called after the GPU cache and MMU TLB has * been invalidated post the teardown loop. + * + * The mmu_lock shall be held prior to calling the function. */ -static void kbase_mmu_free_pgds_list(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, - struct list_head *free_pgds_list) +static void kbase_mmu_free_pgds_list(struct kbase_device *kbdev, struct kbase_mmu_table *mmut) { - struct page *page, *next_page; - - mutex_lock(&mmut->mmu_lock); - - list_for_each_entry_safe(page, next_page, free_pgds_list, lru) { - list_del_init(&page->lru); - kbase_mmu_free_pgd(kbdev, mmut, page_to_phys(page)); - } - - mutex_unlock(&mmut->mmu_lock); -} - -static void kbase_mmu_add_to_free_pgds_list(struct kbase_device *kbdev, - struct kbase_mmu_table *mmut, - struct page *p, struct list_head *free_pgds_list) -{ - bool page_is_isolated = false; + size_t i; lockdep_assert_held(&mmut->mmu_lock); - page_is_isolated = kbase_mmu_handle_isolated_pgd_page(kbdev, mmut, p); + for (i = 0; i < mmut->scratch_mem.free_pgds.head_index; i++) + kbase_mmu_free_pgd(kbdev, mmut, page_to_phys(mmut->scratch_mem.free_pgds.pgds[i])); - if (likely(!page_is_isolated)) - list_add(&p->lru, free_pgds_list); + mmut->scratch_mem.free_pgds.head_index = 0; +} + +static void kbase_mmu_add_to_free_pgds_list(struct kbase_mmu_table *mmut, struct page *p) +{ + lockdep_assert_held(&mmut->mmu_lock); + + if (WARN_ON_ONCE(mmut->scratch_mem.free_pgds.head_index > (MAX_FREE_PGDS - 1))) + return; + + mmut->scratch_mem.free_pgds.pgds[mmut->scratch_mem.free_pgds.head_index++] = p; +} + +static inline void kbase_mmu_reset_free_pgds_list(struct kbase_mmu_table *mmut) +{ + lockdep_assert_held(&mmut->mmu_lock); + + mmut->scratch_mem.free_pgds.head_index = 0; } /** @@ -627,6 +586,7 @@ static void kbase_gpu_mmu_handle_write_faulting_as(struct kbase_device *kbdev, */ const enum kbase_caller_mmu_sync_info mmu_sync_info = CALLER_MMU_SYNC; struct kbase_mmu_hw_op_param op_param; + int ret = 0; mutex_lock(&kbdev->mmu_hw_mutex); @@ -645,16 +605,20 @@ static void kbase_gpu_mmu_handle_write_faulting_as(struct kbase_device *kbdev, spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags); op_param.flush_skip_levels = pgd_level_to_skip_flush(dirty_pgds); - kbase_mmu_hw_do_flush_on_gpu_ctrl(kbdev, faulting_as, &op_param); + ret = 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_flush(kbdev, faulting_as, &op_param); + ret = kbase_mmu_hw_do_flush(kbdev, faulting_as, &op_param); mmu_hw_operation_end(kbdev); } mutex_unlock(&kbdev->mmu_hw_mutex); + if (ret) + dev_err(kbdev->dev, + "Flush for GPU page fault due to write access did not complete"); + kbase_mmu_hw_enable_fault(kbdev, faulting_as, KBASE_MMU_FAULT_TYPE_PAGE); } @@ -869,17 +833,13 @@ static bool page_fault_try_alloc(struct kbase_context *kctx, return false; } -#ifdef CONFIG_MALI_2MB_ALLOC - if (new_pages >= (SZ_2M / SZ_4K)) { + if (kctx->kbdev->pagesize_2mb && new_pages >= (SZ_2M / SZ_4K)) { root_pool = &kctx->mem_pools.large[region->gpu_alloc->group_id]; *grow_2mb_pool = true; } else { -#endif root_pool = &kctx->mem_pools.small[region->gpu_alloc->group_id]; *grow_2mb_pool = false; -#ifdef CONFIG_MALI_2MB_ALLOC } -#endif if (region->gpu_alloc != region->cpu_alloc) new_pages *= 2; @@ -1128,22 +1088,22 @@ void kbase_mmu_page_fault_worker(struct work_struct *data) } page_fault_retry: -#ifdef CONFIG_MALI_2MB_ALLOC - /* Preallocate (or re-allocate) memory for the sub-allocation structs if necessary */ - for (i = 0; i != ARRAY_SIZE(prealloc_sas); ++i) { - if (!prealloc_sas[i]) { - prealloc_sas[i] = kmalloc(sizeof(*prealloc_sas[i]), GFP_KERNEL); - + if (kbdev->pagesize_2mb) { + /* Preallocate (or re-allocate) memory for the sub-allocation structs if necessary */ + for (i = 0; i != ARRAY_SIZE(prealloc_sas); ++i) { if (!prealloc_sas[i]) { - kbase_mmu_report_fault_and_kill( - kctx, faulting_as, - "Failed pre-allocating memory for sub-allocations' metadata", - fault); - goto fault_done; + prealloc_sas[i] = kmalloc(sizeof(*prealloc_sas[i]), GFP_KERNEL); + + if (!prealloc_sas[i]) { + kbase_mmu_report_fault_and_kill( + kctx, faulting_as, + "Failed pre-allocating memory for sub-allocations' metadata", + fault); + goto fault_done; + } } } } -#endif /* CONFIG_MALI_2MB_ALLOC */ /* so we have a translation fault, * let's see if it is for growable memory @@ -1457,8 +1417,7 @@ page_fault_retry: * Otherwise fail the allocation. */ if (pages_to_grow > 0) { -#ifdef CONFIG_MALI_2MB_ALLOC - if (grow_2mb_pool) { + if (kbdev->pagesize_2mb && grow_2mb_pool) { /* Round page requirement up to nearest 2 MB */ struct kbase_mem_pool *const lp_mem_pool = &kctx->mem_pools.large[ @@ -1469,18 +1428,15 @@ page_fault_retry: >> lp_mem_pool->order; ret = kbase_mem_pool_grow(lp_mem_pool, - pages_to_grow); + pages_to_grow, kctx->task); } else { -#endif struct kbase_mem_pool *const mem_pool = &kctx->mem_pools.small[ region->gpu_alloc->group_id]; ret = kbase_mem_pool_grow(mem_pool, - pages_to_grow); -#ifdef CONFIG_MALI_2MB_ALLOC + pages_to_grow, kctx->task); } -#endif } if (ret < 0) { /* failed to extend, handle as a normal PF */ @@ -1570,15 +1526,24 @@ alloc_free: return KBASE_MMU_INVALID_PGD_ADDRESS; } -/* Given PGD PFN for level N, return PGD PFN for level N+1, allocating the - * new table from the pool if needed and possible +/** + * mmu_get_next_pgd() - Given PGD PFN for level N, return PGD PFN for level N+1 + * + * @kbdev: Device pointer. + * @mmut: GPU MMU page table. + * @pgd: Physical addresse of level N page directory. + * @vpfn: The virtual page frame number. + * @level: The level of MMU page table (N). + * + * Return: + * * 0 - OK + * * -EFAULT - level N+1 PGD does not exist + * * -EINVAL - kmap() failed for level N PGD PFN */ 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) + phys_addr_t *pgd, u64 vpfn, int level) { u64 *page; - u64 pgd_vpfn = vpfn; phys_addr_t target_pgd; struct page *p; @@ -1594,67 +1559,15 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, struct kbase_mmu_table * p = pfn_to_page(PFN_DOWN(*pgd)); page = kmap(p); if (page == NULL) { - dev_warn(kbdev->dev, "%s: kmap failure", __func__); + dev_err(kbdev->dev, "%s: kmap failure", __func__); return -EINVAL; } if (!kbdev->mmu_mode->pte_is_valid(page[vpfn], level)) { - unsigned int current_valid_entries; - u64 managed_pte; - - target_pgd = kbase_mmu_alloc_pgd(kbdev, mmut); - if (target_pgd == KBASE_MMU_INVALID_PGD_ADDRESS) { - dev_dbg(kbdev->dev, "%s: kbase_mmu_alloc_pgd failure", __func__); - kunmap(p); - return -ENOMEM; - } - - 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); - - /* Rely on the caller to update the address space flags. */ - if (newly_created_pgd && !*newly_created_pgd) { - *newly_created_pgd = true; - if (dirty_pgds) - *dirty_pgds |= 1ULL << level; - } - - /* A new valid entry is added to an existing PGD. Perform the - * invalidate operation for GPU cache as it could be having a - * cacheline that contains the entry (in an invalid form). - * Even if the parent PGD was newly created, invalidation of - * GPU cache is still needed. For explanation, please refer - * the comment in kbase_mmu_insert_pages_no_flush(). - */ - kbase_mmu_sync_pgd(kbdev, mmut->kctx, - *pgd + (vpfn * sizeof(u64)), - kbase_dma_addr(p) + (vpfn * sizeof(u64)), - sizeof(u64), KBASE_MMU_OP_FLUSH_PT); - - /* Update the new target_pgd page to its stable state */ - if (kbase_page_migration_enabled) { - struct kbase_page_metadata *page_md = - kbase_page_private(phys_to_page(target_pgd)); - - spin_lock(&page_md->migrate_lock); - - WARN_ON_ONCE(PAGE_STATUS_GET(page_md->status) != ALLOCATE_IN_PROGRESS || - IS_PAGE_ISOLATED(page_md->status)); - - if (mmut->kctx) { - page_md->status = PAGE_STATUS_SET(page_md->status, PT_MAPPED); - page_md->data.pt_mapped.mmut = mmut; - page_md->data.pt_mapped.pgd_vpfn_level = - PGD_VPFN_LEVEL_SET(pgd_vpfn, level); - } else { - page_md->status = PAGE_STATUS_SET(page_md->status, NOT_MOVABLE); - } - - spin_unlock(&page_md->migrate_lock); - } + dev_dbg(kbdev->dev, "%s: invalid PTE at level %d vpfn 0x%llx", __func__, level, + vpfn); + kunmap(p); + return -EFAULT; } else { target_pgd = kbdev->mmu_mode->pte_to_phy_addr( kbdev->mgm_dev->ops.mgm_pte_to_original_pte( @@ -1667,12 +1580,69 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, struct kbase_mmu_table * return 0; } +/** + * mmu_get_lowest_valid_pgd() - Find a valid PGD at or closest to in_level + * + * @kbdev: Device pointer. + * @mmut: GPU MMU page table. + * @vpfn: The virtual page frame number. + * @in_level: The level of MMU page table (N). + * @out_level: Set to the level of the lowest valid PGD found on success. + * Invalid on error. + * @out_pgd: Set to the lowest valid PGD found on success. + * Invalid on error. + * + * Does a page table walk starting from top level (L0) to in_level to find a valid PGD at or + * closest to in_level + * + * Terminology: + * Level-0 = Top-level = highest + * Level-3 = Bottom-level = lowest + * + * Return: + * * 0 - OK + * * -EINVAL - kmap() failed during page table walk. + */ +static int mmu_get_lowest_valid_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + u64 vpfn, int in_level, int *out_level, phys_addr_t *out_pgd) +{ + phys_addr_t pgd; + int l; + int err = 0; + + lockdep_assert_held(&mmut->mmu_lock); + pgd = mmut->pgd; + + for (l = MIDGARD_MMU_TOPLEVEL; l < in_level; l++) { + err = mmu_get_next_pgd(kbdev, mmut, &pgd, vpfn, l); + + /* Handle failure condition */ + if (err) { + dev_dbg(kbdev->dev, + "%s: mmu_get_next_pgd() failed to find a valid pgd at level %d", + __func__, l + 1); + break; + } + } + + *out_pgd = pgd; + *out_level = l; + + /* -EFAULT indicates that pgd param was valid but the next pgd entry at vpfn was invalid. + * This implies that we have found the lowest valid pgd. Reset the error code. + */ + if (err == -EFAULT) + err = 0; + + return err; +} + /* - * Returns the PGD for the specified level of translation + * On success, sets out_pgd to the PGD for the specified level of translation + * Returns -EFAULT if a valid PGD is not found */ 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) + int level, phys_addr_t *out_pgd) { phys_addr_t pgd; int l; @@ -1681,12 +1651,12 @@ static int mmu_get_pgd_at_level(struct kbase_device *kbdev, struct kbase_mmu_tab pgd = mmut->pgd; for (l = MIDGARD_MMU_TOPLEVEL; l < level; l++) { - int err = - mmu_get_next_pgd(kbdev, mmut, &pgd, vpfn, l, newly_created_pgd, dirty_pgds); + int err = mmu_get_next_pgd(kbdev, mmut, &pgd, vpfn, l); /* Handle failure condition */ if (err) { - dev_dbg(kbdev->dev, "%s: mmu_get_next_pgd failure at level %d", __func__, - l); + dev_err(kbdev->dev, + "%s: mmu_get_next_pgd() failed to find a valid pgd at level %d", + __func__, l + 1); return err; } } @@ -1696,17 +1666,9 @@ static int mmu_get_pgd_at_level(struct kbase_device *kbdev, struct kbase_mmu_tab return 0; } -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, - 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, u64 *dirty_pgds, - struct list_head *free_pgds_list, struct tagged_addr *phys, bool ignore_page_migration) { u64 vpfn = from_vpfn; @@ -1719,6 +1681,7 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev, lockdep_assert_held(&mmut->mmu_lock); mmu_mode = kbdev->mmu_mode; + kbase_mmu_reset_free_pgds_list(mmut); while (vpfn < to_vpfn) { unsigned int idx = vpfn & 0x1FF; @@ -1779,11 +1742,10 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev, if (!num_of_valid_entries) { kunmap(p); - kbase_mmu_add_to_free_pgds_list(kbdev, mmut, p, free_pgds_list); + kbase_mmu_add_to_free_pgds_list(mmut, p); kbase_mmu_update_and_free_parent_pgds(kbdev, mmut, pgds, vpfn, level, - KBASE_MMU_OP_NONE, dirty_pgds, - free_pgds_list); + KBASE_MMU_OP_NONE, dirty_pgds); vpfn += count; continue; } @@ -1863,34 +1825,209 @@ static void mmu_flush_invalidate_insert_pages(struct kbase_device *kbdev, mmu_flush_invalidate(kbdev, mmut->kctx, as_nr, &op_param); } -/* - * Map the single page 'phys' 'nr' of times, starting at GPU PFN 'vpfn' +/** + * update_parent_pgds() - Updates the page table from bottom level towards + * the top level to insert a new ATE + * + * @kbdev: Device pointer. + * @mmut: GPU MMU page table. + * @cur_level: The level of MMU page table where the ATE needs to be added. + * The bottom PGD level. + * @insert_level: The level of MMU page table where the chain of newly allocated + * PGDs needs to be linked-in/inserted. + * The top-most PDG level to be updated. + * @insert_vpfn: The virtual page frame number for the ATE. + * @pgds_to_insert: Ptr to an array (size MIDGARD_MMU_BOTTOMLEVEL+1) that contains + * the physical addresses of newly allocated PGDs from index + * insert_level+1 to cur_level, and an existing PGD at index + * insert_level. + * + * The newly allocated PGDs are linked from the bottom level up and inserted into the PGD + * at insert_level which already exists in the MMU Page Tables.Migration status is also + * updated for all the newly allocated PGD pages. + * + * Return: + * * 0 - OK + * * -EFAULT - level N+1 PGD does not exist + * * -EINVAL - kmap() failed for level N PGD PFN */ -int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, - struct tagged_addr phys, size_t nr, - unsigned long flags, int const group_id, - enum kbase_caller_mmu_sync_info mmu_sync_info) +static int update_parent_pgds(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + int cur_level, int insert_level, u64 insert_vpfn, + phys_addr_t *pgds_to_insert) +{ + int pgd_index; + int err = 0; + + /* Add a PTE for the new PGD page at pgd_index into the parent PGD at (pgd_index-1) + * Loop runs from the bottom-most to the top-most level so that all entries in the chain + * are valid when they are inserted into the MMU Page table via the insert_level PGD. + */ + for (pgd_index = cur_level; pgd_index > insert_level; pgd_index--) { + int parent_index = pgd_index - 1; + phys_addr_t parent_pgd = pgds_to_insert[parent_index]; + unsigned int current_valid_entries; + u64 pte; + phys_addr_t target_pgd = pgds_to_insert[pgd_index]; + u64 parent_vpfn = (insert_vpfn >> ((3 - parent_index) * 9)) & 0x1FF; + struct page *parent_page = pfn_to_page(PFN_DOWN(parent_pgd)); + u64 *parent_page_va; + + if (WARN_ON_ONCE(target_pgd == KBASE_MMU_INVALID_PGD_ADDRESS)) { + err = -EFAULT; + goto failure_recovery; + } + + parent_page_va = kmap(parent_page); + if (unlikely(parent_page_va == NULL)) { + dev_err(kbdev->dev, "%s: kmap failure", __func__); + err = -EINVAL; + goto failure_recovery; + } + + current_valid_entries = kbdev->mmu_mode->get_num_valid_entries(parent_page_va); + + kbdev->mmu_mode->entry_set_pte(&pte, target_pgd); + parent_page_va[parent_vpfn] = kbdev->mgm_dev->ops.mgm_update_gpu_pte( + kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, parent_index, pte); + kbdev->mmu_mode->set_num_valid_entries(parent_page_va, current_valid_entries + 1); + kunmap(parent_page); + + if (parent_index != insert_level) { + /* Newly allocated PGDs */ + kbase_mmu_sync_pgd_cpu( + kbdev, kbase_dma_addr(parent_page) + (parent_vpfn * sizeof(u64)), + sizeof(u64)); + } else { + /* A new valid entry is added to an existing PGD. Perform the + * invalidate operation for GPU cache as it could be having a + * cacheline that contains the entry (in an invalid form). + */ + kbase_mmu_sync_pgd( + kbdev, mmut->kctx, parent_pgd + (parent_vpfn * sizeof(u64)), + kbase_dma_addr(parent_page) + (parent_vpfn * sizeof(u64)), + sizeof(u64), KBASE_MMU_OP_FLUSH_PT); + } + + /* Update the new target_pgd page to its stable state */ + if (kbase_page_migration_enabled) { + struct kbase_page_metadata *page_md = + kbase_page_private(phys_to_page(target_pgd)); + + spin_lock(&page_md->migrate_lock); + + WARN_ON_ONCE(PAGE_STATUS_GET(page_md->status) != ALLOCATE_IN_PROGRESS || + IS_PAGE_ISOLATED(page_md->status)); + + if (mmut->kctx) { + page_md->status = PAGE_STATUS_SET(page_md->status, PT_MAPPED); + page_md->data.pt_mapped.mmut = mmut; + page_md->data.pt_mapped.pgd_vpfn_level = + PGD_VPFN_LEVEL_SET(insert_vpfn, parent_index); + } else { + page_md->status = PAGE_STATUS_SET(page_md->status, NOT_MOVABLE); + } + + spin_unlock(&page_md->migrate_lock); + } + } + + return 0; + +failure_recovery: + /* Cleanup PTEs from PGDs. The Parent PGD in the loop above is just "PGD" here */ + for (; pgd_index < cur_level; pgd_index++) { + phys_addr_t pgd = pgds_to_insert[pgd_index]; + struct page *pgd_page = pfn_to_page(PFN_DOWN(pgd)); + u64 *pgd_page_va = kmap(pgd_page); + u64 vpfn = (insert_vpfn >> ((3 - pgd_index) * 9)) & 0x1FF; + + kbdev->mmu_mode->entries_invalidate(&pgd_page_va[vpfn], 1); + kunmap(pgd_page); + } + + return err; +} + +/** + * mmu_insert_alloc_pgds() - allocate memory for PGDs from level_low to + * level_high (inclusive) + * + * @kbdev: Device pointer. + * @mmut: GPU MMU page table. + * @level_low: The lower bound for the levels for which the PGD allocs are required + * @level_high: The higher bound for the levels for which the PGD allocs are required + * @new_pgds: Ptr to an array (size MIDGARD_MMU_BOTTOMLEVEL+1) to write the + * newly allocated PGD addresses to. + * + * Numerically, level_low < level_high, not to be confused with top level and + * bottom level concepts for MMU PGDs. They are only used as low and high bounds + * in an incrementing for-loop. + * + * Return: + * * 0 - OK + * * -ENOMEM - allocation failed for a PGD. + */ +static int mmu_insert_alloc_pgds(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + phys_addr_t *new_pgds, int level_low, int level_high) +{ + int err = 0; + int i; + + lockdep_assert_held(&mmut->mmu_lock); + + for (i = level_low; i <= level_high; i++) { + do { + new_pgds[i] = kbase_mmu_alloc_pgd(kbdev, mmut); + if (new_pgds[i] != KBASE_MMU_INVALID_PGD_ADDRESS) + break; + + mutex_unlock(&mmut->mmu_lock); + err = kbase_mem_pool_grow(&kbdev->mem_pools.small[mmut->group_id], + level_high, NULL); + mutex_lock(&mmut->mmu_lock); + if (err) { + dev_err(kbdev->dev, "%s: kbase_mem_pool_grow() returned error %d", + __func__, err); + + /* Free all PGDs allocated in previous successful iterations + * from (i-1) to level_low + */ + for (i = (i - 1); i >= level_low; i--) { + if (new_pgds[i] != KBASE_MMU_INVALID_PGD_ADDRESS) + kbase_mmu_free_pgd(kbdev, mmut, new_pgds[i]); + } + + return err; + } + } while (1); + } + + return 0; +} + +int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 start_vpfn, + struct tagged_addr phys, size_t nr, unsigned long flags, + int const group_id, enum kbase_caller_mmu_sync_info mmu_sync_info, + bool ignore_page_migration) { phys_addr_t pgd; u64 *pgd_page; - /* In case the insert_single_page only partially completes - * we need to be able to recover - */ - bool recover_required = false; - u64 start_vpfn = vpfn; - size_t recover_count = 0; + u64 insert_vpfn = start_vpfn; size_t remain = nr; int err; struct kbase_device *kbdev; - enum kbase_mmu_op_type flush_op; u64 dirty_pgds = 0; - LIST_HEAD(free_pgds_list); + unsigned int i; + phys_addr_t new_pgds[MIDGARD_MMU_BOTTOMLEVEL + 1]; + enum kbase_mmu_op_type flush_op; + struct kbase_mmu_table *mmut = &kctx->mmu; + int l, cur_level, insert_level; if (WARN_ON(kctx == NULL)) return -EINVAL; /* 64-bit address range is the max */ - KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE)); + KBASE_DEBUG_ASSERT(start_vpfn <= (U64_MAX / PAGE_SIZE)); kbdev = kctx->kbdev; @@ -1901,7 +2038,7 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, /* If page migration is enabled, pages involved in multiple GPU mappings * are always treated as not movable. */ - if (kbase_page_migration_enabled) { + if (kbase_page_migration_enabled && !ignore_page_migration) { struct page *phys_page = as_page(phys); struct kbase_page_metadata *page_md = kbase_page_private(phys_page); @@ -1912,12 +2049,11 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, } } - mutex_lock(&kctx->mmu.mmu_lock); + mutex_lock(&mmut->mmu_lock); while (remain) { - unsigned int i; - unsigned int index = vpfn & 0x1FF; - unsigned int count = KBASE_MMU_PAGE_ENTRIES - index; + unsigned int vindex = insert_vpfn & 0x1FF; + unsigned int count = KBASE_MMU_PAGE_ENTRIES - vindex; struct page *p; register unsigned int num_of_valid_entries; bool newly_created_pgd = false; @@ -1925,64 +2061,61 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, if (count > remain) count = remain; + cur_level = MIDGARD_MMU_BOTTOMLEVEL; + insert_level = cur_level; + /* - * Repeatedly calling mmu_get_bottom_pgd() is clearly + * Repeatedly calling mmu_get_lowest_valid_pgd() is clearly * suboptimal. We don't have to re-parse the whole tree * each time (just cache the l0-l2 sequence). * On the other hand, it's only a gain when we map more than * 256 pages at once (on average). Do we really care? */ - do { - 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 - * the page walk to succeed - */ - mutex_unlock(&kctx->mmu.mmu_lock); - err = kbase_mem_pool_grow( - &kbdev->mem_pools.small[ - kctx->mmu.group_id], - MIDGARD_MMU_BOTTOMLEVEL); - mutex_lock(&kctx->mmu.mmu_lock); - } while (!err); + /* insert_level < cur_level if there's no valid PGD for cur_level and insert_vpn */ + err = mmu_get_lowest_valid_pgd(kbdev, mmut, insert_vpfn, cur_level, &insert_level, + &pgd); + if (err) { - dev_warn(kbdev->dev, "%s: mmu_get_bottom_pgd failure", __func__); - if (recover_required) { - /* Invalidate the pages we have partially - * completed - */ - mmu_insert_pages_failure_recovery(kbdev, &kctx->mmu, start_vpfn, - start_vpfn + recover_count, - &dirty_pgds, &free_pgds_list, - NULL, true); - } + dev_err(kbdev->dev, "%s: mmu_get_lowest_valid_pgd() returned error %d", + __func__, err); goto fail_unlock; } + /* No valid pgd at cur_level */ + if (insert_level != cur_level) { + /* Allocate new pgds for all missing levels from the required level + * down to the lowest valid pgd at insert_level + */ + err = mmu_insert_alloc_pgds(kbdev, mmut, new_pgds, (insert_level + 1), + cur_level); + if (err) + goto fail_unlock; + + newly_created_pgd = true; + + new_pgds[insert_level] = pgd; + + /* If we didn't find an existing valid pgd at cur_level, + * we've now allocated one. The ATE in the next step should + * be inserted in this newly allocated pgd. + */ + pgd = new_pgds[cur_level]; + } + p = pfn_to_page(PFN_DOWN(pgd)); pgd_page = kmap(p); if (!pgd_page) { - dev_warn(kbdev->dev, "%s: kmap failure", __func__); - if (recover_required) { - /* Invalidate the pages we have partially - * completed - */ - mmu_insert_pages_failure_recovery(kbdev, &kctx->mmu, start_vpfn, - start_vpfn + recover_count, - &dirty_pgds, &free_pgds_list, - NULL, true); - } + dev_err(kbdev->dev, "%s: kmap failure", __func__); err = -ENOMEM; - goto fail_unlock; + + goto fail_unlock_free_pgds; } num_of_valid_entries = kbdev->mmu_mode->get_num_valid_entries(pgd_page); for (i = 0; i < count; i++) { - unsigned int ofs = index + i; + unsigned int ofs = vindex + i; /* Fail if the current page is a valid ATE entry */ KBASE_DEBUG_ASSERT(0 == (pgd_page[ofs] & 1UL)); @@ -1994,50 +2127,87 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, kbdev->mmu_mode->set_num_valid_entries( pgd_page, num_of_valid_entries + count); - vpfn += count; - remain -= count; - - if (count > 0 && !newly_created_pgd) - dirty_pgds |= 1ULL << MIDGARD_MMU_BOTTOMLEVEL; + dirty_pgds |= 1ULL << (newly_created_pgd ? insert_level : 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 + * If bottom level PGD is newly created then no GPU 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), + kbase_mmu_sync_pgd(kbdev, kctx, pgd + (vindex * sizeof(u64)), + kbase_dma_addr(p) + (vindex * sizeof(u64)), count * sizeof(u64), flush_op); - kunmap(p); - /* We have started modifying the page table. - * If further pages need inserting and fail we need to undo what - * has already taken place - */ - recover_required = true; - recover_count += count; - } - mutex_unlock(&kctx->mmu.mmu_lock); + if (newly_created_pgd) { + err = update_parent_pgds(kbdev, mmut, cur_level, insert_level, insert_vpfn, + new_pgds); + if (err) { + dev_err(kbdev->dev, "%s: update_parent_pgds() failed (%d)", + __func__, err); - mmu_flush_invalidate_insert_pages(kbdev, &kctx->mmu, start_vpfn, nr, dirty_pgds, - mmu_sync_info, false); + kbdev->mmu_mode->entries_invalidate(&pgd_page[vindex], count); + + kunmap(p); + goto fail_unlock_free_pgds; + } + } + + insert_vpfn += count; + remain -= count; + kunmap(p); + } + + mutex_unlock(&mmut->mmu_lock); + + mmu_flush_invalidate_insert_pages(kbdev, mmut, start_vpfn, nr, dirty_pgds, mmu_sync_info, + false); return 0; -fail_unlock: - mutex_unlock(&kctx->mmu.mmu_lock); +fail_unlock_free_pgds: + /* Free the pgds allocated by us from insert_level+1 to bottom level */ + for (l = cur_level; l > insert_level; l--) + kbase_mmu_free_pgd(kbdev, mmut, new_pgds[l]); - mmu_flush_invalidate_insert_pages(kbdev, &kctx->mmu, start_vpfn, nr, dirty_pgds, - mmu_sync_info, true); - kbase_mmu_free_pgds_list(kbdev, &kctx->mmu, &free_pgds_list); +fail_unlock: + if (insert_vpfn != start_vpfn) { + /* Invalidate the pages we have partially completed */ + mmu_insert_pages_failure_recovery(kbdev, mmut, start_vpfn, insert_vpfn, &dirty_pgds, + NULL, true); + } + + mmu_flush_invalidate_insert_pages(kbdev, mmut, start_vpfn, nr, dirty_pgds, mmu_sync_info, + true); + kbase_mmu_free_pgds_list(kbdev, mmut); + mutex_unlock(&mmut->mmu_lock); return err; } +int kbase_mmu_insert_single_imported_page(struct kbase_context *kctx, u64 vpfn, + struct tagged_addr phys, size_t nr, unsigned long flags, + int const group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info) +{ + /* The aliasing sink page has metadata and shall be moved to NOT_MOVABLE. */ + return kbase_mmu_insert_single_page(kctx, vpfn, phys, nr, flags, group_id, mmu_sync_info, + false); +} + +int kbase_mmu_insert_single_aliased_page(struct kbase_context *kctx, u64 vpfn, + struct tagged_addr phys, size_t nr, unsigned long flags, + int const group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info) +{ + /* The aliasing sink page has metadata and shall be moved to NOT_MOVABLE. */ + return kbase_mmu_insert_single_page(kctx, vpfn, phys, nr, flags, group_id, mmu_sync_info, + false); +} + static void kbase_mmu_progress_migration_on_insert(struct tagged_addr phys, struct kbase_va_region *reg, struct kbase_mmu_table *mmut, const u64 vpfn) @@ -2139,7 +2309,9 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu size_t remain = nr; int err; struct kbase_mmu_mode const *mmu_mode; - LIST_HEAD(free_pgds_list); + unsigned int i; + phys_addr_t new_pgds[MIDGARD_MMU_BOTTOMLEVEL + 1]; + int l, cur_level, insert_level; /* Note that 0 is a valid start_vpfn */ /* 64-bit address range is the max */ @@ -2154,13 +2326,12 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu mutex_lock(&mmut->mmu_lock); while (remain) { - unsigned int i; unsigned int vindex = insert_vpfn & 0x1FF; unsigned int count = KBASE_MMU_PAGE_ENTRIES - vindex; struct page *p; - int cur_level; register unsigned int num_of_valid_entries; bool newly_created_pgd = false; + enum kbase_mmu_op_type flush_op; if (count > remain) count = remain; @@ -2170,57 +2341,53 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu else cur_level = MIDGARD_MMU_BOTTOMLEVEL; + insert_level = cur_level; + /* - * Repeatedly calling mmu_get_pgd_at_level() is clearly + * Repeatedly calling mmu_get_lowest_valid_pgd() is clearly * suboptimal. We don't have to re-parse the whole tree * each time (just cache the l0-l2 sequence). * On the other hand, it's only a gain when we map more than * 256 pages at once (on average). Do we really care? */ - do { - 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 - * the page walk to succeed - */ - mutex_unlock(&mmut->mmu_lock); - err = kbase_mem_pool_grow( - &kbdev->mem_pools.small[mmut->group_id], - cur_level); - mutex_lock(&mmut->mmu_lock); - } while (!err); + /* insert_level < cur_level if there's no valid PGD for cur_level and insert_vpn */ + err = mmu_get_lowest_valid_pgd(kbdev, mmut, insert_vpfn, cur_level, &insert_level, + &pgd); if (err) { - dev_warn(kbdev->dev, "%s: mmu_get_pgd_at_level failure", __func__); - if (insert_vpfn != start_vpfn) { - /* Invalidate the pages we have partially - * completed - */ - mmu_insert_pages_failure_recovery(kbdev, mmut, start_vpfn, - insert_vpfn, dirty_pgds, - &free_pgds_list, phys, - ignore_page_migration); - } + dev_err(kbdev->dev, "%s: mmu_get_lowest_valid_pgd() returned error %d", + __func__, err); goto fail_unlock; } + /* No valid pgd at cur_level */ + if (insert_level != cur_level) { + /* Allocate new pgds for all missing levels from the required level + * down to the lowest valid pgd at insert_level + */ + err = mmu_insert_alloc_pgds(kbdev, mmut, new_pgds, (insert_level + 1), + cur_level); + if (err) + goto fail_unlock; + + newly_created_pgd = true; + + new_pgds[insert_level] = pgd; + + /* If we didn't find an existing valid pgd at cur_level, + * we've now allocated one. The ATE in the next step should + * be inserted in this newly allocated pgd. + */ + pgd = new_pgds[cur_level]; + } + p = pfn_to_page(PFN_DOWN(pgd)); pgd_page = kmap(p); if (!pgd_page) { - dev_warn(kbdev->dev, "%s: kmap failure", __func__); - if (insert_vpfn != start_vpfn) { - /* Invalidate the pages we have partially - * completed - */ - mmu_insert_pages_failure_recovery(kbdev, mmut, start_vpfn, - insert_vpfn, dirty_pgds, - &free_pgds_list, phys, - ignore_page_migration); - } + dev_err(kbdev->dev, "%s: kmap failure", __func__); err = -ENOMEM; - goto fail_unlock; + + goto fail_unlock_free_pgds; } num_of_valid_entries = @@ -2262,34 +2429,39 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu mmu_mode->set_num_valid_entries(pgd_page, num_of_valid_entries); - if (dirty_pgds && !newly_created_pgd) - *dirty_pgds |= 1ULL << cur_level; + if (dirty_pgds) + *dirty_pgds |= 1ULL << (newly_created_pgd ? insert_level : cur_level); + + /* 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 GPU 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, mmut->kctx, pgd + (vindex * sizeof(u64)), + kbase_dma_addr(p) + (vindex * sizeof(u64)), count * sizeof(u64), + flush_op); + + if (newly_created_pgd) { + err = update_parent_pgds(kbdev, mmut, cur_level, insert_level, insert_vpfn, + new_pgds); + if (err) { + dev_err(kbdev->dev, "%s: update_parent_pgds() failed (%d)", + __func__, err); + + kbdev->mmu_mode->entries_invalidate(&pgd_page[vindex], count); + + kunmap(p); + goto fail_unlock_free_pgds; + } + } phys += count; insert_vpfn += count; remain -= count; - - /* Even if mmu_get_pgd_at_level() allocated a new bottom level - * table page, the invalidation of L2 cache is still needed for - * for the valid entries written in that page. This is because a - * race can happen as soon as the entry of parent level table is - * updated to point to the page of bottom level table. - * GPU can try to access within the the same virtual range that - * is being mapped, before the valid entries of bottom level table - * page are flushed to the memory from the CPU's cache. And if that - * happens then the invalid entries from memory could get fetched - * into the L2 cache and so those entries won't be affected by the - * MMU TLB invalidation done by sending the UNLOCK command. - * If the memory is growable then this could result in unexpected - * page faults happening repeatedly, until the invalid entry is - * evicted from the L2 cache, as Driver would consider the page - * faults for mapped memory as duplicate and won't take any action - * effectively. - */ - kbase_mmu_sync_pgd(kbdev, mmut->kctx, pgd + (vindex * sizeof(u64)), - kbase_dma_addr(p) + (vindex * sizeof(u64)), count * sizeof(u64), - KBASE_MMU_OP_FLUSH_PT); - kunmap(p); } @@ -2297,12 +2469,22 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu return 0; +fail_unlock_free_pgds: + /* Free the pgds allocated by us from insert_level+1 to bottom level */ + for (l = cur_level; l > insert_level; l--) + kbase_mmu_free_pgd(kbdev, mmut, new_pgds[l]); + fail_unlock: - mutex_unlock(&mmut->mmu_lock); + if (insert_vpfn != start_vpfn) { + /* Invalidate the pages we have partially completed */ + mmu_insert_pages_failure_recovery(kbdev, mmut, start_vpfn, insert_vpfn, dirty_pgds, + phys, ignore_page_migration); + } mmu_flush_invalidate_insert_pages(kbdev, mmut, start_vpfn, nr, dirty_pgds ? *dirty_pgds : 0xF, CALLER_MMU_ASYNC, true); - kbase_mmu_free_pgds_list(kbdev, mmut, &free_pgds_list); + kbase_mmu_free_pgds_list(kbdev, mmut); + mutex_unlock(&mmut->mmu_lock); return err; } @@ -2318,7 +2500,6 @@ int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *m { int err; u64 dirty_pgds = 0; - LIST_HEAD(free_pgds_list); /* Early out if there is nothing to do */ if (nr == 0) @@ -2336,58 +2517,56 @@ int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *m KBASE_EXPORT_TEST_API(kbase_mmu_insert_pages); -/** - * 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. - * @nr: The number of pages to flush. - * - * As per kbase_mmu_flush_invalidate but doesn't retain the kctx or do any - * other locking. - */ -static void kbase_mmu_flush_noretain(struct kbase_context *kctx, u64 vpfn, size_t nr) +int kbase_mmu_insert_imported_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + u64 vpfn, struct tagged_addr *phys, size_t nr, + unsigned long flags, int as_nr, int const group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info, + struct kbase_va_region *reg) { - struct kbase_device *kbdev = kctx->kbdev; 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); + u64 dirty_pgds = 0; /* Early out if there is nothing to do */ if (nr == 0) - return; + return 0; - /* flush L2 and unlock the VA (resumes the MMU) */ - 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)) { - /* 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_flush_locked(kbdev, &kbdev->as[kctx->as_nr], - &op_param); - } + /* Imported allocations don't have metadata and therefore always ignore the + * page migration logic. + */ + err = kbase_mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id, + &dirty_pgds, reg, true); + if (err) + return err; - 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"); + mmu_flush_invalidate_insert_pages(kbdev, mmut, vpfn, nr, dirty_pgds, mmu_sync_info, false); - if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_NONE)) - kbase_reset_gpu_locked(kbdev); - } + return 0; +} + +int kbase_mmu_insert_aliased_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + u64 vpfn, struct tagged_addr *phys, size_t nr, + unsigned long flags, int as_nr, int const group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info, + struct kbase_va_region *reg) +{ + int err; + u64 dirty_pgds = 0; + + /* Early out if there is nothing to do */ + if (nr == 0) + return 0; + + /* Memory aliases are always built on top of existing allocations, + * therefore the state of physical pages shall be updated. + */ + err = kbase_mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id, + &dirty_pgds, reg, false); + if (err) + return err; + + mmu_flush_invalidate_insert_pages(kbdev, mmut, vpfn, nr, dirty_pgds, mmu_sync_info, false); + + return 0; } void kbase_mmu_update(struct kbase_device *kbdev, @@ -2412,6 +2591,14 @@ void kbase_mmu_disable_as(struct kbase_device *kbdev, int as_nr) void kbase_mmu_disable(struct kbase_context *kctx) { + /* 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_device *kbdev = kctx->kbdev; + struct kbase_mmu_hw_op_param op_param = { 0 }; + int lock_err, flush_err; + /* ASSERT that the context has a valid as_nr, which is only the case * when it's scheduled in. * @@ -2422,16 +2609,49 @@ void kbase_mmu_disable(struct kbase_context *kctx) lockdep_assert_held(&kctx->kbdev->hwaccess_lock); lockdep_assert_held(&kctx->kbdev->mmu_hw_mutex); - /* - * The address space is being disabled, drain all knowledge of it out - * from the caches as pages and page tables might be freed after this. - * - * The job scheduler code will already be holding the locks and context - * so just do the flush. - */ - kbase_mmu_flush_noretain(kctx, 0, ~0); + op_param.vpfn = 0; + op_param.nr = ~0; + op_param.op = KBASE_MMU_OP_FLUSH_MEM; + op_param.kctx_id = kctx->id; + op_param.mmu_sync_info = mmu_sync_info; + +#if MALI_USE_CSF + /* 0xF value used to prevent skipping of any levels when flushing */ + if (mmu_flush_cache_on_gpu_ctrl(kbdev)) + op_param.flush_skip_levels = pgd_level_to_skip_flush(0xF); +#endif + + /* lock MMU to prevent existing jobs on GPU from executing while the AS is + * not yet disabled + */ + lock_err = kbase_mmu_hw_do_lock(kbdev, &kbdev->as[kctx->as_nr], &op_param); + if (lock_err) + dev_err(kbdev->dev, "Failed to lock AS %d for ctx %d_%d", kctx->as_nr, kctx->tgid, + kctx->id); + + /* Issue the flush command only when L2 cache is in stable power on state. + * Any other state for L2 cache implies that shader cores are powered off, + * which in turn implies there is no execution happening on the GPU. + */ + if (kbdev->pm.backend.l2_state == KBASE_L2_ON) { + flush_err = kbase_gpu_cache_flush_and_busy_wait(kbdev, + GPU_COMMAND_CACHE_CLN_INV_L2_LSC); + if (flush_err) + dev_err(kbdev->dev, + "Failed to flush GPU cache when disabling AS %d for ctx %d_%d", + kctx->as_nr, kctx->tgid, kctx->id); + } + kbdev->mmu_mode->disable_as(kbdev, kctx->as_nr); + + if (!lock_err) { + /* unlock the MMU to allow it to resume */ + lock_err = + kbase_mmu_hw_do_unlock_no_addr(kbdev, &kbdev->as[kctx->as_nr], &op_param); + if (lock_err) + dev_err(kbdev->dev, "Failed to unlock AS %d for ctx %d_%d", kctx->as_nr, + kctx->tgid, kctx->id); + } - kctx->kbdev->mmu_mode->disable_as(kctx->kbdev, kctx->as_nr); #if !MALI_USE_CSF /* * JM GPUs has some L1 read only caches that need to be invalidated @@ -2439,7 +2659,7 @@ void kbase_mmu_disable(struct kbase_context *kctx) * the slot_rb tracking field so such invalidation is performed when * a new katom is executed on the affected slots. */ - kbase_backend_slot_kctx_purge_locked(kctx->kbdev, kctx); + kbase_backend_slot_kctx_purge_locked(kbdev, kctx); #endif } KBASE_EXPORT_TEST_API(kbase_mmu_disable); @@ -2447,8 +2667,7 @@ 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, - enum kbase_mmu_op_type flush_op, u64 *dirty_pgds, - struct list_head *free_pgds_list) + enum kbase_mmu_op_type flush_op, u64 *dirty_pgds) { int current_level; @@ -2480,7 +2699,7 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, current_pgd + (index * sizeof(u64)), sizeof(u64), flush_op); - kbase_mmu_add_to_free_pgds_list(kbdev, mmut, p, free_pgds_list); + kbase_mmu_add_to_free_pgds_list(mmut, p); } else { current_valid_entries--; @@ -2500,13 +2719,14 @@ 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. + * @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. + * @phys_page_nr: Number 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 @@ -2514,10 +2734,14 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev, * 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. + * + * When performing a partial GPU cache flush, the number of physical + * pages does not have to be identical to the number of virtual pages on the MMU, + * to support a single physical address flush for an aliased page. */ static void mmu_flush_invalidate_teardown_pages(struct kbase_device *kbdev, struct kbase_context *kctx, int as_nr, - struct tagged_addr *phys, + struct tagged_addr *phys, size_t phys_page_nr, struct kbase_mmu_hw_op_param *op_param) { if (!mmu_flush_cache_on_gpu_ctrl(kbdev)) { @@ -2536,7 +2760,7 @@ static void mmu_flush_invalidate_teardown_pages(struct kbase_device *kbdev, mmu_invalidate(kbdev, kctx, as_nr, op_param); - for (i = 0; !flush_done && i < op_param->nr; i++) { + for (i = 0; !flush_done && i < phys_page_nr; i++) { spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags); if (kbdev->pm.backend.gpu_powered && (!kctx || kctx->as_nr >= 0)) mmu_flush_pa_range(kbdev, as_phys_addr_t(phys[i]), PAGE_SIZE, @@ -2549,76 +2773,15 @@ static void mmu_flush_invalidate_teardown_pages(struct kbase_device *kbdev, #endif } -/** - * 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 used for GPU cache maintenance - * and page migration support. - * @nr: Number of pages to unmap. - * @as_nr: Address space number, for GPU cache maintenance operations - * that happen outside a specific kbase context. - * @ignore_page_migration: Whether page migration metadata should be ignored. - * - * We actually discard the ATE and free the page table pages if no valid entries - * exist in PGD. - * - * IMPORTANT: This uses kbasep_js_runpool_release_ctx() when the context is - * currently scheduled into the runpool, and so potentially uses a lot of locks. - * 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, - struct tagged_addr *phys, size_t nr, int as_nr, - bool ignore_page_migration) +static int kbase_mmu_teardown_pgd_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + u64 vpfn, size_t nr, u64 *dirty_pgds, + struct list_head *free_pgds_list, + enum kbase_mmu_op_type flush_op) { - const size_t requested_nr = nr; - u64 start_vpfn = vpfn; - 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; - int err = -EFAULT; - u64 dirty_pgds = 0; - LIST_HEAD(free_pgds_list); + struct kbase_mmu_mode const *mmu_mode = kbdev->mmu_mode; - /* 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; - - if (nr == 0) { - /* early out if nothing to do */ - 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; + lockdep_assert_held(&mmut->mmu_lock); + kbase_mmu_reset_free_pgds_list(mmut); while (nr) { unsigned int index = vpfn & 0x1FF; @@ -2703,7 +2866,7 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table } if (pcount > 0) - dirty_pgds |= 1ULL << level; + *dirty_pgds |= 1ULL << level; num_of_valid_entries = mmu_mode->get_num_valid_entries(page); if (WARN_ON_ONCE(num_of_valid_entries < pcount)) @@ -2725,11 +2888,10 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table pgd + (index * sizeof(u64)), pcount * sizeof(u64), flush_op); - kbase_mmu_add_to_free_pgds_list(kbdev, mmut, p, &free_pgds_list); + kbase_mmu_add_to_free_pgds_list(mmut, p); kbase_mmu_update_and_free_parent_pgds(kbdev, mmut, pgds, vpfn, level, - flush_op, &dirty_pgds, - &free_pgds_list); + flush_op, dirty_pgds); vpfn += count; nr -= count; @@ -2746,19 +2908,77 @@ next: vpfn += count; nr -= count; } - err = 0; out: + return 0; +} + +int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn, + struct tagged_addr *phys, size_t nr_phys_pages, size_t nr_virt_pages, + int as_nr, bool ignore_page_migration) +{ + u64 start_vpfn = vpfn; + enum kbase_mmu_op_type flush_op = KBASE_MMU_OP_NONE; + struct kbase_mmu_hw_op_param op_param; + int err = -EFAULT; + u64 dirty_pgds = 0; + LIST_HEAD(free_pgds_list); + + /* 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; + + /* This function performs two operations: MMU maintenance and flushing + * the caches. To ensure internal consistency between the caches and the + * MMU, it does not make sense to be able to flush only the physical pages + * from the cache and keep the PTE, nor does it make sense to use this + * function to remove a PTE and keep the physical pages in the cache. + * + * However, we have legitimate cases where we can try to tear down a mapping + * with zero virtual and zero physical pages, so we must have the following + * behaviour: + * - if both physical and virtual page counts are zero, return early + * - if either physical and virtual page counts are zero, return early + * - if there are fewer physical pages than virtual pages, return -EINVAL + */ + if (unlikely(nr_virt_pages == 0 || nr_phys_pages == 0)) + return 0; + + if (unlikely(nr_virt_pages < nr_phys_pages)) + return -EINVAL; + + /* 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_phys_pages <= KBASE_PA_RANGE_THRESHOLD_NR_PAGES) + flush_op = KBASE_MMU_OP_FLUSH_PT; + + mutex_lock(&mmut->mmu_lock); + + err = kbase_mmu_teardown_pgd_pages(kbdev, mmut, vpfn, nr_virt_pages, &dirty_pgds, + &free_pgds_list, flush_op); + /* 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, + .nr = nr_virt_pages, .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); + mmu_flush_invalidate_teardown_pages(kbdev, mmut->kctx, as_nr, phys, nr_phys_pages, + &op_param); /* If page migration is enabled: the status of all physical pages involved * shall be updated, unless they are not movable. Their status shall be @@ -2766,15 +2986,14 @@ out: * requests to migrate the pages, if they have been isolated. */ if (kbase_page_migration_enabled && phys && !ignore_page_migration) - kbase_mmu_progress_migration_on_teardown(kbdev, phys, requested_nr); + kbase_mmu_progress_migration_on_teardown(kbdev, phys, nr_phys_pages); + + kbase_mmu_free_pgds_list(kbdev, mmut); mutex_unlock(&mmut->mmu_lock); - kbase_mmu_free_pgds_list(kbdev, mmut, &free_pgds_list); - return err; } - KBASE_EXPORT_TEST_API(kbase_mmu_teardown_pages); /** @@ -2834,7 +3053,7 @@ static int kbase_mmu_update_pages_no_flush(struct kbase_device *kbdev, struct kb if (is_huge(*phys) && (index == index_in_large_page(*phys))) cur_level = MIDGARD_MMU_LEVEL(2); - err = mmu_get_pgd_at_level(kbdev, mmut, vpfn, cur_level, &pgd, NULL, dirty_pgds); + err = mmu_get_pgd_at_level(kbdev, mmut, vpfn, cur_level, &pgd); if (WARN_ON(err)) goto fail_unlock; @@ -3119,9 +3338,9 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p } } - ret = mmu_get_pgd_at_level(kbdev, mmut, vpfn, level, &pgd, NULL, NULL); + ret = mmu_get_pgd_at_level(kbdev, mmut, vpfn, level, &pgd); if (ret) { - dev_warn(kbdev->dev, "%s: failed to find PGD for old page.", __func__); + dev_err(kbdev->dev, "%s: failed to find PGD for old page.", __func__); goto get_pgd_at_level_error; } @@ -3167,10 +3386,8 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p if (ret < 0) { mutex_unlock(&kbdev->mmu_hw_mutex); mutex_unlock(&kbdev->pm.lock); - dev_err(kbdev->dev, - "%s: failed to lock MMU region or flush GPU cache. Issuing GPU soft-reset to recover.", - __func__); - goto gpu_reset; + dev_err(kbdev->dev, "%s: failed to lock MMU region or flush GPU cache", __func__); + goto undo_mappings; } /* Copy memory content. @@ -3270,7 +3487,7 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p /* Checking the final migration transaction error state */ if (ret < 0) { dev_err(kbdev->dev, "%s: failed to unlock MMU region.", __func__); - goto gpu_reset; + goto undo_mappings; } /* Undertaking metadata transfer, while we are holding the mmu_lock */ @@ -3305,19 +3522,13 @@ new_page_map_error: old_page_map_error: return ret; -gpu_reset: - /* Unlock the MMU table before resetting the GPU and undo - * mappings. - */ +undo_mappings: + /* Unlock the MMU table and undo mappings. */ mutex_unlock(&mmut->mmu_lock); kunmap(phys_to_page(pgd)); kunmap(as_page(new_phys)); kunmap(as_page(old_phys)); - /* Reset the GPU because of an unrecoverable error in locking or flushing. */ - if (kbase_prepare_to_reset_gpu(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) - kbase_reset_gpu(kbdev); - return ret; } @@ -3329,7 +3540,6 @@ static void mmu_teardown_level(struct kbase_device *kbdev, struct kbase_mmu_tabl struct memory_group_manager_device *mgm_dev = kbdev->mgm_dev; struct kbase_mmu_mode const *mmu_mode = kbdev->mmu_mode; u64 *pgd_page_buffer = NULL; - bool page_is_isolated = false; struct page *p = phys_to_page(pgd); lockdep_assert_held(&mmut->mmu_lock); @@ -3342,7 +3552,7 @@ static void mmu_teardown_level(struct kbase_device *kbdev, struct kbase_mmu_tabl /* Copy the page to our preallocated buffer so that we can minimize * kmap_atomic usage */ - pgd_page_buffer = mmut->mmu_teardown_pages[level]; + pgd_page_buffer = mmut->scratch_mem.teardown_pages.levels[level]; memcpy(pgd_page_buffer, pgd_page, PAGE_SIZE); } @@ -3370,41 +3580,27 @@ static void mmu_teardown_level(struct kbase_device *kbdev, struct kbase_mmu_tabl } } - /* Top level PGD page is excluded from migration process. */ - if (level != MIDGARD_MMU_TOPLEVEL) - page_is_isolated = kbase_mmu_handle_isolated_pgd_page(kbdev, mmut, p); - - if (likely(!page_is_isolated)) - kbase_mmu_free_pgd(kbdev, mmut, pgd); + kbase_mmu_free_pgd(kbdev, mmut, pgd); } int kbase_mmu_init(struct kbase_device *const kbdev, struct kbase_mmu_table *const mmut, struct kbase_context *const kctx, int const group_id) { - int level; - if (WARN_ON(group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS) || WARN_ON(group_id < 0)) return -EINVAL; + compiletime_assert(KBASE_MEM_ALLOC_MAX_SIZE <= (((8ull << 30) >> PAGE_SHIFT)), + "List of free PGDs may not be large enough."); + compiletime_assert(MAX_PAGES_FOR_FREE_PGDS >= MIDGARD_MMU_BOTTOMLEVEL, + "Array of MMU levels is not large enough."); + mmut->group_id = group_id; mutex_init(&mmut->mmu_lock); mmut->kctx = kctx; mmut->pgd = KBASE_MMU_INVALID_PGD_ADDRESS; - /* Preallocate MMU depth of 3 pages for mmu_teardown_level to use */ - for (level = MIDGARD_MMU_TOPLEVEL; - level < MIDGARD_MMU_BOTTOMLEVEL; level++) { - mmut->mmu_teardown_pages[level] = - kmalloc(PAGE_SIZE, GFP_KERNEL); - - if (!mmut->mmu_teardown_pages[level]) { - kbase_mmu_term(kbdev, mmut); - return -ENOMEM; - } - } - /* We allocate pages into the kbdev memory pool, then * kbase_mmu_alloc_pgd will allocate out of that pool. This is done to * avoid allocations from the kernel happening with the lock held. @@ -3414,7 +3610,7 @@ int kbase_mmu_init(struct kbase_device *const kbdev, err = kbase_mem_pool_grow( &kbdev->mem_pools.small[mmut->group_id], - MIDGARD_MMU_BOTTOMLEVEL); + MIDGARD_MMU_BOTTOMLEVEL, kctx ? kctx->task : NULL); if (err) { kbase_mmu_term(kbdev, mmut); return -ENOMEM; @@ -3430,8 +3626,6 @@ int kbase_mmu_init(struct kbase_device *const kbdev, void kbase_mmu_term(struct kbase_device *kbdev, struct kbase_mmu_table *mmut) { - int level; - WARN((mmut->kctx) && (mmut->kctx->as_nr != KBASEP_AS_NR_INVALID), "kctx-%d_%d must first be scheduled out to flush GPU caches+tlbs before tearing down MMU tables", mmut->kctx->tgid, mmut->kctx->id); @@ -3445,13 +3639,6 @@ void kbase_mmu_term(struct kbase_device *kbdev, struct kbase_mmu_table *mmut) KBASE_TLSTREAM_AUX_PAGESALLOC(kbdev, mmut->kctx->id, 0); } - for (level = MIDGARD_MMU_TOPLEVEL; - level < MIDGARD_MMU_BOTTOMLEVEL; level++) { - if (!mmut->mmu_teardown_pages[level]) - break; - kfree(mmut->mmu_teardown_pages[level]); - } - mutex_destroy(&mmut->mmu_lock); } diff --git a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h index 247a67c50da8..699b1f340482 100644 --- a/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h +++ b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu.h @@ -152,21 +152,71 @@ 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, + u64 vpfn, struct tagged_addr *phys, size_t nr, unsigned long flags, int group_id, u64 *dirty_pgds, struct kbase_va_region *reg, bool ignore_page_migration); int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn, struct tagged_addr *phys, size_t nr, unsigned long flags, int as_nr, int group_id, enum kbase_caller_mmu_sync_info mmu_sync_info, struct kbase_va_region *reg, bool ignore_page_migration); -int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, - struct tagged_addr phys, size_t nr, - unsigned long flags, int group_id, - enum kbase_caller_mmu_sync_info mmu_sync_info); +int kbase_mmu_insert_imported_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + u64 vpfn, struct tagged_addr *phys, size_t nr, + unsigned long flags, int as_nr, int group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info, + struct kbase_va_region *reg); +int kbase_mmu_insert_aliased_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, + u64 vpfn, struct tagged_addr *phys, size_t nr, + unsigned long flags, int as_nr, int group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info, + struct kbase_va_region *reg); +int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, struct tagged_addr phys, + size_t nr, unsigned long flags, int group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info, + bool ignore_page_migration); +int kbase_mmu_insert_single_imported_page(struct kbase_context *kctx, u64 vpfn, + struct tagged_addr phys, size_t nr, unsigned long flags, + int group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info); +int kbase_mmu_insert_single_aliased_page(struct kbase_context *kctx, u64 vpfn, + struct tagged_addr phys, size_t nr, unsigned long flags, + int group_id, + enum kbase_caller_mmu_sync_info mmu_sync_info); +/** + * 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 used for GPU cache maintenance + * and page migration support. + * @nr_phys_pages: Number of physical pages to flush. + * @nr_virt_pages: Number of virtual pages whose PTEs should be destroyed. + * @as_nr: Address space number, for GPU cache maintenance operations + * that happen outside a specific kbase context. + * @ignore_page_migration: Whether page migration metadata should be ignored. + * + * We actually discard the ATE and free the page table pages if no valid entries + * exist in PGD. + * + * IMPORTANT: This uses kbasep_js_runpool_release_ctx() when the context is + * currently scheduled into the runpool, and so potentially uses a lot of locks. + * 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, - struct tagged_addr *phys, size_t nr, int as_nr, - bool ignore_page_migration); + struct tagged_addr *phys, size_t nr_phys_pages, size_t nr_virt_pages, + int as_nr, bool ignore_page_migration); + 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_direct.c b/drivers/gpu/arm/bifrost/mmu/mali_kbase_mmu_hw_direct.c index 858d4bf6edcd..3f6da35d80f2 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 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 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 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -156,37 +157,60 @@ static int lock_region(struct kbase_gpu_props const *gpu_props, u64 *lockaddr, return 0; } -static int wait_ready(struct kbase_device *kbdev, - unsigned int as_nr) +/** + * wait_ready() - Wait for previously issued MMU command to complete. + * + * @kbdev: Kbase device to wait for a MMU command to complete. + * @as_nr: Address space to wait for a MMU command to complete. + * + * Reset GPU if the wait for previously issued command fails. + * + * Return: 0 on successful completion. negative error on failure. + */ +static int wait_ready(struct kbase_device *kbdev, unsigned int as_nr) { - u32 max_loops = KBASE_AS_INACTIVE_MAX_LOOPS; + const ktime_t wait_loop_start = ktime_get_raw(); + const u32 mmu_as_inactive_wait_time_ms = kbdev->mmu_as_inactive_wait_time_ms; + s64 diff; - /* Wait for the MMU status to indicate there is no active command. */ - while (--max_loops && - kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS)) & - AS_STATUS_AS_ACTIVE) { - ; - } + if (unlikely(kbdev->as[as_nr].is_unresponsive)) + return -EBUSY; - if (WARN_ON_ONCE(max_loops == 0)) { - dev_err(kbdev->dev, - "AS_ACTIVE bit stuck for as %u, might be caused by slow/unstable GPU clock or possible faulty FPGA connector", - as_nr); - return -1; - } + do { + unsigned int i; - return 0; + for (i = 0; i < 1000; i++) { + /* Wait for the MMU status to indicate there is no active command */ + if (!(kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS)) & + AS_STATUS_AS_ACTIVE)) + return 0; + } + + diff = ktime_to_ms(ktime_sub(ktime_get_raw(), wait_loop_start)); + } while (diff < mmu_as_inactive_wait_time_ms); + + dev_err(kbdev->dev, + "AS_ACTIVE bit stuck for as %u. Might be caused by unstable GPU clk/pwr or faulty system", + as_nr); + kbdev->as[as_nr].is_unresponsive = true; + if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) + kbase_reset_gpu_locked(kbdev); + + return -ETIMEDOUT; } static int write_cmd(struct kbase_device *kbdev, int as_nr, u32 cmd) { - int status; - /* write AS_COMMAND when MMU is ready to accept another command */ - status = wait_ready(kbdev, as_nr); - if (status == 0) + const int status = wait_ready(kbdev, as_nr); + + if (likely(status == 0)) kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_COMMAND), cmd); - else { + else if (status == -EBUSY) { + dev_dbg(kbdev->dev, + "Skipped the wait for AS_ACTIVE bit for as %u, before sending MMU command %u", + as_nr, cmd); + } else { dev_err(kbdev->dev, "Wait for AS_ACTIVE bit failed for as %u, before sending MMU command %u", as_nr, cmd); @@ -259,17 +283,21 @@ static int apply_hw_issue_GPU2019_3901_wa(struct kbase_device *kbdev, u32 *mmu_c /* Wait for the LOCK MMU command to complete, issued by the caller */ ret = wait_ready(kbdev, as_nr); - if (ret) + if (unlikely(ret)) return ret; ret = kbase_gpu_cache_flush_and_busy_wait(kbdev, GPU_COMMAND_CACHE_CLN_INV_LSC); - if (ret) + if (unlikely(ret)) return ret; ret = wait_cores_power_trans_complete(kbdev); - if (ret) + if (unlikely(ret)) { + if (kbase_prepare_to_reset_gpu_locked(kbdev, + RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) + kbase_reset_gpu_locked(kbdev); return ret; + } /* As LSC is guaranteed to have been flushed we can use FLUSH_PT * MMU command to only flush the L2. @@ -397,12 +425,21 @@ static int mmu_hw_do_lock_no_wait(struct kbase_device *kbdev, struct kbase_as *a ret = mmu_hw_set_lock_addr(kbdev, as->number, lock_addr, op_param); - if (!ret) - write_cmd(kbdev, as->number, AS_COMMAND_LOCK); + if (likely(!ret)) + ret = write_cmd(kbdev, as->number, AS_COMMAND_LOCK); return ret; } +/** + * mmu_hw_do_lock - Issue LOCK command to the MMU and wait for its completion. + * + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @op_param: Pointer to a struct containing information about the MMU operation. + * + * Return: 0 if issuing the LOCK command was successful, otherwise an error code. + */ static int mmu_hw_do_lock(struct kbase_device *kbdev, struct kbase_as *as, const struct kbase_mmu_hw_op_param *op_param) { @@ -443,10 +480,10 @@ int kbase_mmu_hw_do_unlock_no_addr(struct kbase_device *kbdev, struct kbase_as * ret = write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK); /* Wait for UNLOCK command to complete */ - if (!ret) + if (likely(!ret)) ret = wait_ready(kbdev, as->number); - if (!ret) { + if (likely(!ret)) { 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)) @@ -478,6 +515,16 @@ int kbase_mmu_hw_do_unlock(struct kbase_device *kbdev, struct kbase_as *as, return ret; } +/** + * mmu_hw_do_flush - Flush MMU and wait for its completion. + * + * @kbdev: Kbase device to issue the MMU operation on. + * @as: Address space to issue the MMU operation on. + * @op_param: Pointer to a struct containing information about the MMU operation. + * @hwaccess_locked: Flag to indicate if the lock has been held. + * + * Return: 0 if flushing MMU was successful, otherwise an error code. + */ 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) { @@ -508,12 +555,9 @@ static int mmu_hw_do_flush(struct kbase_device *kbdev, struct kbase_as *as, 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) { + /* WA for the BASE_HW_ISSUE_GPU2019_3901. */ + if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_GPU2019_3901) && + mmu_cmd == AS_COMMAND_FLUSH_MEM) { if (!hwaccess_locked) { unsigned long flags = 0; @@ -529,12 +573,13 @@ static int mmu_hw_do_flush(struct kbase_device *kbdev, struct kbase_as *as, } #endif - write_cmd(kbdev, as->number, mmu_cmd); + ret = write_cmd(kbdev, as->number, mmu_cmd); /* Wait for the command to complete */ - ret = wait_ready(kbdev, as->number); + if (likely(!ret)) + ret = wait_ready(kbdev, as->number); - if (!ret) + if (likely(!ret)) mmu_command_instr(kbdev, op_param->kctx_id, mmu_cmd, lock_addr, op_param->mmu_sync_info); diff --git a/drivers/gpu/arm/bifrost/tests/build.bp b/drivers/gpu/arm/bifrost/tests/build.bp index 7abae237f9c3..5581ba934cd3 100644 --- a/drivers/gpu/arm/bifrost/tests/build.bp +++ b/drivers/gpu/arm/bifrost/tests/build.bp @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2021-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2021-2023 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,3 +38,9 @@ bob_defaults { kbuild_options: ["CONFIG_UNIT_TEST_KERNEL_MODULES=y"], }, } + +bob_defaults { + name: "kernel_unit_tests", + add_to_alias: ["unit_tests"], + srcs: [".*_unit_test/"], +} diff --git a/drivers/gpu/arm/bifrost/thirdparty/mali_kbase_mmap.c b/drivers/gpu/arm/bifrost/thirdparty/mali_kbase_mmap.c index 34d2223d67cb..1e636b9a7759 100644 --- a/drivers/gpu/arm/bifrost/thirdparty/mali_kbase_mmap.c +++ b/drivers/gpu/arm/bifrost/thirdparty/mali_kbase_mmap.c @@ -10,6 +10,7 @@ */ #include "linux/mman.h" +#include #include /* mali_kbase_mmap.c @@ -90,7 +91,6 @@ static bool align_and_check(unsigned long *gap_end, unsigned long gap_start, if ((*gap_end < info->low_limit) || (*gap_end < gap_start)) return false; - return true; } @@ -132,6 +132,7 @@ static bool align_and_check(unsigned long *gap_end, unsigned long gap_start, static unsigned long kbase_unmapped_area_topdown(struct vm_unmapped_area_info *info, bool is_shader_code, bool is_same_4gb_page) { +#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE) struct mm_struct *mm = current->mm; struct vm_area_struct *vma; unsigned long length, low_limit, high_limit, gap_start, gap_end; @@ -225,7 +226,37 @@ check_current: } } } +#else + unsigned long length, high_limit, gap_start, gap_end; + MA_STATE(mas, ¤t->mm->mm_mt, 0, 0); + /* Adjust search length to account for worst case alignment overhead */ + length = info->length + info->align_mask; + if (length < info->length) + return -ENOMEM; + + /* + * Adjust search limits by the desired length. + * See implementation comment at top of unmapped_area(). + */ + gap_end = info->high_limit; + if (gap_end < length) + return -ENOMEM; + high_limit = gap_end - length; + + if (info->low_limit > high_limit) + return -ENOMEM; + + while (true) { + if (mas_empty_area_rev(&mas, info->low_limit, info->high_limit - 1, length)) + return -ENOMEM; + gap_end = mas.last + 1; + gap_start = mas.min; + + if (align_and_check(&gap_end, gap_start, info, is_shader_code, is_same_4gb_page)) + return gap_end; + } +#endif return -ENOMEM; } @@ -242,8 +273,13 @@ unsigned long kbase_context_get_unmapped_area(struct kbase_context *const kctx, struct vm_unmapped_area_info info; unsigned long align_offset = 0; unsigned long align_mask = 0; +#if (KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE) + unsigned long high_limit = arch_get_mmap_base(addr, mm->mmap_base); + unsigned long low_limit = max_t(unsigned long, PAGE_SIZE, kbase_mmap_min_addr); +#else unsigned long high_limit = mm->mmap_base; unsigned long low_limit = PAGE_SIZE; +#endif int cpu_va_bits = BITS_PER_LONG; int gpu_pc_bits = kctx->kbdev->gpu_props.props.core_props.log2_program_counter_size; @@ -270,6 +306,13 @@ unsigned long kbase_context_get_unmapped_area(struct kbase_context *const kctx, struct kbase_reg_zone *zone = kbase_ctx_reg_zone_get_nolock(kctx, KBASE_REG_ZONE_SAME_VA); u64 same_va_end_addr = kbase_reg_zone_end_pfn(zone) << PAGE_SHIFT; +#if (KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE) + const unsigned long mmap_end = arch_get_mmap_end(addr, len, flags); + + /* requested length too big for entire address space */ + if (len > mmap_end - kbase_mmap_min_addr) + return -ENOMEM; +#endif /* err on fixed address */ if ((flags & MAP_FIXED) || addr) @@ -282,7 +325,7 @@ unsigned long kbase_context_get_unmapped_area(struct kbase_context *const kctx, if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { high_limit = - min_t(unsigned long, mm->mmap_base, same_va_end_addr); + min_t(unsigned long, high_limit, same_va_end_addr); /* If there's enough (> 33 bits) of GPU VA space, align * to 2MB boundaries. @@ -359,9 +402,15 @@ unsigned long kbase_context_get_unmapped_area(struct kbase_context *const kctx, if (IS_ERR_VALUE(ret) && high_limit == mm->mmap_base && high_limit < same_va_end_addr) { +#if (KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE) + /* Retry above TASK_UNMAPPED_BASE */ + info.low_limit = TASK_UNMAPPED_BASE; + info.high_limit = min_t(u64, mmap_end, same_va_end_addr); +#else /* Retry above mmap_base */ info.low_limit = mm->mmap_base; info.high_limit = min_t(u64, TASK_SIZE, same_va_end_addr); +#endif ret = kbase_unmapped_area_topdown(&info, is_shader_code, is_same_4gb_page); diff --git a/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline.c b/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline.c index 334248867c7c..9ed59633c41b 100644 --- a/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline.c +++ b/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2015-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2015-2023 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 @@ -24,8 +24,6 @@ #include "mali_kbase_tracepoints.h" #include -#include - #include #include #include 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 359d06371aff..ae570064e7d0 100644 --- a/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline_io.c +++ b/drivers/gpu/arm/bifrost/tl/mali_kbase_timeline_io.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 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 @@ -35,6 +35,47 @@ #include #endif +static int kbase_unprivileged_global_profiling; + +/** + * kbase_unprivileged_global_profiling_set - set permissions for unprivileged processes + * + * @val: String containing value to set. Only strings representing positive + * integers are accepted as valid; any non-positive integer (including 0) + * is rejected. + * @kp: Module parameter associated with this method. + * + * This method can only be used to enable permissions for unprivileged processes, + * if they are disabled: for this reason, the only values which are accepted are + * strings representing positive integers. Since it's impossible to disable + * permissions once they're set, any integer which is non-positive is rejected, + * including 0. + * + * Return: 0 if success, otherwise error code. + */ +static int kbase_unprivileged_global_profiling_set(const char *val, const struct kernel_param *kp) +{ + int new_val; + int ret = kstrtoint(val, 0, &new_val); + + if (ret == 0) { + if (new_val < 1) + return -EINVAL; + + kbase_unprivileged_global_profiling = 1; + } + + return ret; +} + +static const struct kernel_param_ops kbase_global_unprivileged_profiling_ops = { + .get = param_get_int, + .set = kbase_unprivileged_global_profiling_set, +}; + +module_param_cb(kbase_unprivileged_global_profiling, &kbase_global_unprivileged_profiling_ops, + &kbase_unprivileged_global_profiling, 0600); + /* 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); @@ -43,6 +84,15 @@ 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); +static bool timeline_is_permitted(void) +{ +#if KERNEL_VERSION(5, 8, 0) <= LINUX_VERSION_CODE + return kbase_unprivileged_global_profiling || perfmon_capable(); +#else + return kbase_unprivileged_global_profiling || capable(CAP_SYS_ADMIN); +#endif +} + /** * kbasep_timeline_io_packet_pending - check timeline streams for pending * packets @@ -328,6 +378,9 @@ int kbase_timeline_io_acquire(struct kbase_device *kbdev, u32 flags) }; int err; + if (!timeline_is_permitted()) + return -EPERM; + if (WARN_ON(!kbdev) || (flags & ~BASE_TLSTREAM_FLAGS_MASK)) return -EINVAL; @@ -371,7 +424,7 @@ void kbase_timeline_io_debugfs_init(struct kbase_device *const kbdev) if (WARN_ON(!kbdev) || WARN_ON(IS_ERR_OR_NULL(kbdev->mali_debugfs_directory))) return; - file = debugfs_create_file("tlstream", 0444, kbdev->mali_debugfs_directory, kbdev, + file = debugfs_create_file("tlstream", 0400, kbdev->mali_debugfs_directory, kbdev, &kbasep_tlstream_debugfs_fops); if (IS_ERR_OR_NULL(file)) diff --git a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c index e8a74e9dafa6..f62c75583566 100644 --- a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c +++ b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 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,7 +87,9 @@ enum tl_msg_id_obj { KBASE_TL_KBASE_GPUCMDQUEUE_KICK, KBASE_TL_KBASE_DEVICE_PROGRAM_CSG, KBASE_TL_KBASE_DEVICE_DEPROGRAM_CSG, - KBASE_TL_KBASE_DEVICE_HALT_CSG, + KBASE_TL_KBASE_DEVICE_HALTING_CSG, + KBASE_TL_KBASE_DEVICE_SUSPEND_CSG, + KBASE_TL_KBASE_DEVICE_CSG_IDLE, KBASE_TL_KBASE_NEW_CTX, KBASE_TL_KBASE_DEL_CTX, KBASE_TL_KBASE_CTX_ASSIGN_AS, @@ -98,6 +100,8 @@ enum tl_msg_id_obj { KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_FENCE_WAIT, KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT, KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET, + KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT_OPERATION, + KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET_OPERATION, KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_MAP_IMPORT, KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_UNMAP_IMPORT, KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_UNMAP_IMPORT_FORCE, @@ -116,6 +120,9 @@ enum tl_msg_id_obj { KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_START, KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_END, KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET, + KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_START, + KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_END, + KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET_OPERATION, KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_MAP_IMPORT_START, KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_MAP_IMPORT_END, KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_UNMAP_IMPORT_START, @@ -360,13 +367,21 @@ enum tl_msg_id_obj { TRACEPOINT_DESC(KBASE_TL_KBASE_DEVICE_PROGRAM_CSG, \ "CSG is programmed to a slot", \ "@IIIII", \ - "kbase_device_id,kernel_ctx_id,gpu_cmdq_grp_handle,kbase_device_csg_slot_index,kbase_device_csg_slot_resumed") \ + "kbase_device_id,kernel_ctx_id,gpu_cmdq_grp_handle,kbase_device_csg_slot_index,kbase_device_csg_slot_resuming") \ TRACEPOINT_DESC(KBASE_TL_KBASE_DEVICE_DEPROGRAM_CSG, \ "CSG is deprogrammed from a slot", \ "@II", \ "kbase_device_id,kbase_device_csg_slot_index") \ - TRACEPOINT_DESC(KBASE_TL_KBASE_DEVICE_HALT_CSG, \ - "CSG is halted", \ + TRACEPOINT_DESC(KBASE_TL_KBASE_DEVICE_HALTING_CSG, \ + "CSG is halting", \ + "@III", \ + "kbase_device_id,kbase_device_csg_slot_index,kbase_device_csg_slot_suspending") \ + TRACEPOINT_DESC(KBASE_TL_KBASE_DEVICE_SUSPEND_CSG, \ + "CSG is suspended", \ + "@II", \ + "kbase_device_id,kbase_device_csg_slot_index") \ + TRACEPOINT_DESC(KBASE_TL_KBASE_DEVICE_CSG_IDLE, \ + "KBase device is notified that CSG is idle.", \ "@II", \ "kbase_device_id,kbase_device_csg_slot_index") \ TRACEPOINT_DESC(KBASE_TL_KBASE_NEW_CTX, \ @@ -404,11 +419,19 @@ enum tl_msg_id_obj { TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT, \ "KCPU Queue enqueues Wait on Cross Queue Sync Object", \ "@pLII", \ - "kcpu_queue,cqs_obj_gpu_addr,cqs_obj_compare_value,cqs_obj_inherit_error") \ + "kcpu_queue,cqs_obj_gpu_addr,compare_value,inherit_error") \ TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET, \ "KCPU Queue enqueues Set on Cross Queue Sync Object", \ "@pL", \ "kcpu_queue,cqs_obj_gpu_addr") \ + TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT_OPERATION, \ + "KCPU Queue enqueues Wait Operation on Cross Queue Sync Object", \ + "@pLLIII", \ + "kcpu_queue,cqs_obj_gpu_addr,compare_value,condition,data_type,inherit_error") \ + TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET_OPERATION, \ + "KCPU Queue enqueues Set Operation on Cross Queue Sync Object", \ + "@pLLII", \ + "kcpu_queue,cqs_obj_gpu_addr,value,operation,data_type") \ TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_MAP_IMPORT, \ "KCPU Queue enqueues Map Import", \ "@pL", \ @@ -481,6 +504,18 @@ enum tl_msg_id_obj { "KCPU Queue executes a Set on Cross Queue Sync Object", \ "@pI", \ "kcpu_queue,execute_error") \ + TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_START, \ + "KCPU Queue starts a Wait Operation on Cross Queue Sync Object", \ + "@p", \ + "kcpu_queue") \ + TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_END, \ + "KCPU Queue ends a Wait Operation on Cross Queue Sync Object", \ + "@pI", \ + "kcpu_queue,execute_error") \ + TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET_OPERATION, \ + "KCPU Queue executes a Set Operation on Cross Queue Sync Object", \ + "@pI", \ + "kcpu_queue,execute_error") \ TRACEPOINT_DESC(KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_MAP_IMPORT_START, \ "KCPU Queue starts a Map Import", \ "@p", \ @@ -2130,7 +2165,7 @@ void __kbase_tlstream_tl_kbase_device_program_csg( u32 kernel_ctx_id, u32 gpu_cmdq_grp_handle, u32 kbase_device_csg_slot_index, - u32 kbase_device_csg_slot_resumed + u32 kbase_device_csg_slot_resuming ) { const u32 msg_id = KBASE_TL_KBASE_DEVICE_PROGRAM_CSG; @@ -2139,7 +2174,7 @@ void __kbase_tlstream_tl_kbase_device_program_csg( + sizeof(kernel_ctx_id) + sizeof(gpu_cmdq_grp_handle) + sizeof(kbase_device_csg_slot_index) - + sizeof(kbase_device_csg_slot_resumed) + + sizeof(kbase_device_csg_slot_resuming) ; char *buffer; unsigned long acq_flags; @@ -2158,7 +2193,7 @@ void __kbase_tlstream_tl_kbase_device_program_csg( pos = kbasep_serialize_bytes(buffer, pos, &kbase_device_csg_slot_index, sizeof(kbase_device_csg_slot_index)); pos = kbasep_serialize_bytes(buffer, - pos, &kbase_device_csg_slot_resumed, sizeof(kbase_device_csg_slot_resumed)); + pos, &kbase_device_csg_slot_resuming, sizeof(kbase_device_csg_slot_resuming)); kbase_tlstream_msgbuf_release(stream, acq_flags); } @@ -2190,13 +2225,71 @@ void __kbase_tlstream_tl_kbase_device_deprogram_csg( kbase_tlstream_msgbuf_release(stream, acq_flags); } -void __kbase_tlstream_tl_kbase_device_halt_csg( +void __kbase_tlstream_tl_kbase_device_halting_csg( + struct kbase_tlstream *stream, + u32 kbase_device_id, + u32 kbase_device_csg_slot_index, + u32 kbase_device_csg_slot_suspending +) +{ + const u32 msg_id = KBASE_TL_KBASE_DEVICE_HALTING_CSG; + const size_t msg_size = sizeof(msg_id) + sizeof(u64) + + sizeof(kbase_device_id) + + sizeof(kbase_device_csg_slot_index) + + sizeof(kbase_device_csg_slot_suspending) + ; + char *buffer; + unsigned long acq_flags; + size_t pos = 0; + + buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags); + + pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id)); + pos = kbasep_serialize_timestamp(buffer, pos); + pos = kbasep_serialize_bytes(buffer, + pos, &kbase_device_id, sizeof(kbase_device_id)); + pos = kbasep_serialize_bytes(buffer, + pos, &kbase_device_csg_slot_index, sizeof(kbase_device_csg_slot_index)); + pos = kbasep_serialize_bytes(buffer, + pos, &kbase_device_csg_slot_suspending, sizeof(kbase_device_csg_slot_suspending)); + + kbase_tlstream_msgbuf_release(stream, acq_flags); +} + +void __kbase_tlstream_tl_kbase_device_suspend_csg( struct kbase_tlstream *stream, u32 kbase_device_id, u32 kbase_device_csg_slot_index ) { - const u32 msg_id = KBASE_TL_KBASE_DEVICE_HALT_CSG; + const u32 msg_id = KBASE_TL_KBASE_DEVICE_SUSPEND_CSG; + const size_t msg_size = sizeof(msg_id) + sizeof(u64) + + sizeof(kbase_device_id) + + sizeof(kbase_device_csg_slot_index) + ; + char *buffer; + unsigned long acq_flags; + size_t pos = 0; + + buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags); + + pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id)); + pos = kbasep_serialize_timestamp(buffer, pos); + pos = kbasep_serialize_bytes(buffer, + pos, &kbase_device_id, sizeof(kbase_device_id)); + pos = kbasep_serialize_bytes(buffer, + pos, &kbase_device_csg_slot_index, sizeof(kbase_device_csg_slot_index)); + + kbase_tlstream_msgbuf_release(stream, acq_flags); +} + +void __kbase_tlstream_tl_kbase_device_csg_idle( + struct kbase_tlstream *stream, + u32 kbase_device_id, + u32 kbase_device_csg_slot_index +) +{ + const u32 msg_id = KBASE_TL_KBASE_DEVICE_CSG_IDLE; const size_t msg_size = sizeof(msg_id) + sizeof(u64) + sizeof(kbase_device_id) + sizeof(kbase_device_csg_slot_index) @@ -2433,16 +2526,16 @@ void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_wait( struct kbase_tlstream *stream, const void *kcpu_queue, u64 cqs_obj_gpu_addr, - u32 cqs_obj_compare_value, - u32 cqs_obj_inherit_error + u32 compare_value, + u32 inherit_error ) { const u32 msg_id = KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT; const size_t msg_size = sizeof(msg_id) + sizeof(u64) + sizeof(kcpu_queue) + sizeof(cqs_obj_gpu_addr) - + sizeof(cqs_obj_compare_value) - + sizeof(cqs_obj_inherit_error) + + sizeof(compare_value) + + sizeof(inherit_error) ; char *buffer; unsigned long acq_flags; @@ -2457,9 +2550,9 @@ void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_wait( pos = kbasep_serialize_bytes(buffer, pos, &cqs_obj_gpu_addr, sizeof(cqs_obj_gpu_addr)); pos = kbasep_serialize_bytes(buffer, - pos, &cqs_obj_compare_value, sizeof(cqs_obj_compare_value)); + pos, &compare_value, sizeof(compare_value)); pos = kbasep_serialize_bytes(buffer, - pos, &cqs_obj_inherit_error, sizeof(cqs_obj_inherit_error)); + pos, &inherit_error, sizeof(inherit_error)); kbase_tlstream_msgbuf_release(stream, acq_flags); } @@ -2491,6 +2584,88 @@ void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_set( kbase_tlstream_msgbuf_release(stream, acq_flags); } +void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_wait_operation( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u64 cqs_obj_gpu_addr, + u64 compare_value, + u32 condition, + u32 data_type, + u32 inherit_error +) +{ + const u32 msg_id = KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT_OPERATION; + const size_t msg_size = sizeof(msg_id) + sizeof(u64) + + sizeof(kcpu_queue) + + sizeof(cqs_obj_gpu_addr) + + sizeof(compare_value) + + sizeof(condition) + + sizeof(data_type) + + sizeof(inherit_error) + ; + char *buffer; + unsigned long acq_flags; + size_t pos = 0; + + buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags); + + pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id)); + pos = kbasep_serialize_timestamp(buffer, pos); + pos = kbasep_serialize_bytes(buffer, + pos, &kcpu_queue, sizeof(kcpu_queue)); + pos = kbasep_serialize_bytes(buffer, + pos, &cqs_obj_gpu_addr, sizeof(cqs_obj_gpu_addr)); + pos = kbasep_serialize_bytes(buffer, + pos, &compare_value, sizeof(compare_value)); + pos = kbasep_serialize_bytes(buffer, + pos, &condition, sizeof(condition)); + pos = kbasep_serialize_bytes(buffer, + pos, &data_type, sizeof(data_type)); + pos = kbasep_serialize_bytes(buffer, + pos, &inherit_error, sizeof(inherit_error)); + + kbase_tlstream_msgbuf_release(stream, acq_flags); +} + +void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_set_operation( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u64 cqs_obj_gpu_addr, + u64 value, + u32 operation, + u32 data_type +) +{ + const u32 msg_id = KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET_OPERATION; + const size_t msg_size = sizeof(msg_id) + sizeof(u64) + + sizeof(kcpu_queue) + + sizeof(cqs_obj_gpu_addr) + + sizeof(value) + + sizeof(operation) + + sizeof(data_type) + ; + char *buffer; + unsigned long acq_flags; + size_t pos = 0; + + buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags); + + pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id)); + pos = kbasep_serialize_timestamp(buffer, pos); + pos = kbasep_serialize_bytes(buffer, + pos, &kcpu_queue, sizeof(kcpu_queue)); + pos = kbasep_serialize_bytes(buffer, + pos, &cqs_obj_gpu_addr, sizeof(cqs_obj_gpu_addr)); + pos = kbasep_serialize_bytes(buffer, + pos, &value, sizeof(value)); + pos = kbasep_serialize_bytes(buffer, + pos, &operation, sizeof(operation)); + pos = kbasep_serialize_bytes(buffer, + pos, &data_type, sizeof(data_type)); + + kbase_tlstream_msgbuf_release(stream, acq_flags); +} + void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_map_import( struct kbase_tlstream *stream, const void *kcpu_queue, @@ -2981,6 +3156,83 @@ void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_set( kbase_tlstream_msgbuf_release(stream, acq_flags); } +void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_wait_operation_start( + struct kbase_tlstream *stream, + const void *kcpu_queue +) +{ + const u32 msg_id = KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_START; + const size_t msg_size = sizeof(msg_id) + sizeof(u64) + + sizeof(kcpu_queue) + ; + char *buffer; + unsigned long acq_flags; + size_t pos = 0; + + buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags); + + pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id)); + pos = kbasep_serialize_timestamp(buffer, pos); + pos = kbasep_serialize_bytes(buffer, + pos, &kcpu_queue, sizeof(kcpu_queue)); + + kbase_tlstream_msgbuf_release(stream, acq_flags); +} + +void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_wait_operation_end( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u32 execute_error +) +{ + const u32 msg_id = KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_END; + const size_t msg_size = sizeof(msg_id) + sizeof(u64) + + sizeof(kcpu_queue) + + sizeof(execute_error) + ; + char *buffer; + unsigned long acq_flags; + size_t pos = 0; + + buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags); + + pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id)); + pos = kbasep_serialize_timestamp(buffer, pos); + pos = kbasep_serialize_bytes(buffer, + pos, &kcpu_queue, sizeof(kcpu_queue)); + pos = kbasep_serialize_bytes(buffer, + pos, &execute_error, sizeof(execute_error)); + + kbase_tlstream_msgbuf_release(stream, acq_flags); +} + +void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_set_operation( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u32 execute_error +) +{ + const u32 msg_id = KBASE_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET_OPERATION; + const size_t msg_size = sizeof(msg_id) + sizeof(u64) + + sizeof(kcpu_queue) + + sizeof(execute_error) + ; + char *buffer; + unsigned long acq_flags; + size_t pos = 0; + + buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags); + + pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id)); + pos = kbasep_serialize_timestamp(buffer, pos); + pos = kbasep_serialize_bytes(buffer, + pos, &kcpu_queue, sizeof(kcpu_queue)); + pos = kbasep_serialize_bytes(buffer, + pos, &execute_error, sizeof(execute_error)); + + kbase_tlstream_msgbuf_release(stream, acq_flags); +} + void __kbase_tlstream_tl_kbase_kcpuqueue_execute_map_import_start( struct kbase_tlstream *stream, const void *kcpu_queue diff --git a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h index c690a75fe22c..06e4ca4a6bc2 100644 --- a/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h +++ b/drivers/gpu/arm/bifrost/tl/mali_kbase_tracepoints.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 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 @@ -408,7 +408,7 @@ void __kbase_tlstream_tl_kbase_device_program_csg( u32 kernel_ctx_id, u32 gpu_cmdq_grp_handle, u32 kbase_device_csg_slot_index, - u32 kbase_device_csg_slot_resumed + u32 kbase_device_csg_slot_resuming ); void __kbase_tlstream_tl_kbase_device_deprogram_csg( @@ -417,7 +417,20 @@ void __kbase_tlstream_tl_kbase_device_deprogram_csg( u32 kbase_device_csg_slot_index ); -void __kbase_tlstream_tl_kbase_device_halt_csg( +void __kbase_tlstream_tl_kbase_device_halting_csg( + struct kbase_tlstream *stream, + u32 kbase_device_id, + u32 kbase_device_csg_slot_index, + u32 kbase_device_csg_slot_suspending +); + +void __kbase_tlstream_tl_kbase_device_suspend_csg( + struct kbase_tlstream *stream, + u32 kbase_device_id, + u32 kbase_device_csg_slot_index +); + +void __kbase_tlstream_tl_kbase_device_csg_idle( struct kbase_tlstream *stream, u32 kbase_device_id, u32 kbase_device_csg_slot_index @@ -474,8 +487,8 @@ void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_wait( struct kbase_tlstream *stream, const void *kcpu_queue, u64 cqs_obj_gpu_addr, - u32 cqs_obj_compare_value, - u32 cqs_obj_inherit_error + u32 compare_value, + u32 inherit_error ); void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_set( @@ -484,6 +497,25 @@ void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_set( u64 cqs_obj_gpu_addr ); +void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_wait_operation( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u64 cqs_obj_gpu_addr, + u64 compare_value, + u32 condition, + u32 data_type, + u32 inherit_error +); + +void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_set_operation( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u64 cqs_obj_gpu_addr, + u64 value, + u32 operation, + u32 data_type +); + void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_map_import( struct kbase_tlstream *stream, const void *kcpu_queue, @@ -593,6 +625,23 @@ void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_set( u32 execute_error ); +void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_wait_operation_start( + struct kbase_tlstream *stream, + const void *kcpu_queue +); + +void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_wait_operation_end( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u32 execute_error +); + +void __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_set_operation( + struct kbase_tlstream *stream, + const void *kcpu_queue, + u32 execute_error +); + void __kbase_tlstream_tl_kbase_kcpuqueue_execute_map_import_start( struct kbase_tlstream *stream, const void *kcpu_queue @@ -2026,7 +2075,7 @@ struct kbase_tlstream; * @kernel_ctx_id: Unique ID for the KBase Context * @gpu_cmdq_grp_handle: GPU Command Queue Group handle which will match userspace * @kbase_device_csg_slot_index: The index of the slot in the scheduler being programmed - * @kbase_device_csg_slot_resumed: Whether the csg is being resumed + * @kbase_device_csg_slot_resuming: Whether the csg is being resumed */ #if MALI_USE_CSF #define KBASE_TLSTREAM_TL_KBASE_DEVICE_PROGRAM_CSG( \ @@ -2035,7 +2084,7 @@ struct kbase_tlstream; kernel_ctx_id, \ gpu_cmdq_grp_handle, \ kbase_device_csg_slot_index, \ - kbase_device_csg_slot_resumed \ + kbase_device_csg_slot_resuming \ ) \ do { \ int enabled = atomic_read(&kbdev->timeline_flags); \ @@ -2046,7 +2095,7 @@ struct kbase_tlstream; kernel_ctx_id, \ gpu_cmdq_grp_handle, \ kbase_device_csg_slot_index, \ - kbase_device_csg_slot_resumed \ + kbase_device_csg_slot_resuming \ ); \ } while (0) #else @@ -2056,7 +2105,7 @@ struct kbase_tlstream; kernel_ctx_id, \ gpu_cmdq_grp_handle, \ kbase_device_csg_slot_index, \ - kbase_device_csg_slot_resumed \ + kbase_device_csg_slot_resuming \ ) \ do { } while (0) #endif /* MALI_USE_CSF */ @@ -2066,7 +2115,7 @@ struct kbase_tlstream; * * @kbdev: Kbase device * @kbase_device_id: The ID of the physical hardware - * @kbase_device_csg_slot_index: The index of the slot in the scheduler being programmed + * @kbase_device_csg_slot_index: The index of the slot in the scheduler whose CSG is being deprogrammed */ #if MALI_USE_CSF #define KBASE_TLSTREAM_TL_KBASE_DEVICE_DEPROGRAM_CSG( \ @@ -2093,14 +2142,49 @@ struct kbase_tlstream; #endif /* MALI_USE_CSF */ /** - * KBASE_TLSTREAM_TL_KBASE_DEVICE_HALT_CSG - CSG is halted + * KBASE_TLSTREAM_TL_KBASE_DEVICE_HALTING_CSG - CSG is halting * * @kbdev: Kbase device * @kbase_device_id: The ID of the physical hardware - * @kbase_device_csg_slot_index: The index of the slot in the scheduler being programmed + * @kbase_device_csg_slot_index: The index of the slot in the scheduler whose CSG is being halted + * @kbase_device_csg_slot_suspending: Whether the csg is being suspended */ #if MALI_USE_CSF -#define KBASE_TLSTREAM_TL_KBASE_DEVICE_HALT_CSG( \ +#define KBASE_TLSTREAM_TL_KBASE_DEVICE_HALTING_CSG( \ + kbdev, \ + kbase_device_id, \ + kbase_device_csg_slot_index, \ + kbase_device_csg_slot_suspending \ + ) \ + do { \ + int enabled = atomic_read(&kbdev->timeline_flags); \ + if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ + __kbase_tlstream_tl_kbase_device_halting_csg( \ + __TL_DISPATCH_STREAM(kbdev, obj), \ + kbase_device_id, \ + kbase_device_csg_slot_index, \ + kbase_device_csg_slot_suspending \ + ); \ + } while (0) +#else +#define KBASE_TLSTREAM_TL_KBASE_DEVICE_HALTING_CSG( \ + kbdev, \ + kbase_device_id, \ + kbase_device_csg_slot_index, \ + kbase_device_csg_slot_suspending \ + ) \ + do { } while (0) +#endif /* MALI_USE_CSF */ + +/** + * KBASE_TLSTREAM_TL_KBASE_DEVICE_SUSPEND_CSG - CSG is suspended + * + * @kbdev: Kbase device + * @kbase_device_id: The ID of the physical hardware + * @kbase_device_csg_slot_index: The index of the slot in the scheduler whose CSG is being suspended + */ +#if MALI_USE_CSF +#define KBASE_TLSTREAM_TL_KBASE_DEVICE_SUSPEND_CSG( \ kbdev, \ kbase_device_id, \ kbase_device_csg_slot_index \ @@ -2108,14 +2192,45 @@ struct kbase_tlstream; do { \ int enabled = atomic_read(&kbdev->timeline_flags); \ if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ - __kbase_tlstream_tl_kbase_device_halt_csg( \ + __kbase_tlstream_tl_kbase_device_suspend_csg( \ __TL_DISPATCH_STREAM(kbdev, obj), \ kbase_device_id, \ kbase_device_csg_slot_index \ ); \ } while (0) #else -#define KBASE_TLSTREAM_TL_KBASE_DEVICE_HALT_CSG( \ +#define KBASE_TLSTREAM_TL_KBASE_DEVICE_SUSPEND_CSG( \ + kbdev, \ + kbase_device_id, \ + kbase_device_csg_slot_index \ + ) \ + do { } while (0) +#endif /* MALI_USE_CSF */ + +/** + * KBASE_TLSTREAM_TL_KBASE_DEVICE_CSG_IDLE - KBase device is notified that CSG is idle. + * + * @kbdev: Kbase device + * @kbase_device_id: The ID of the physical hardware + * @kbase_device_csg_slot_index: The index of the slot in the scheduler whose CSG for which we are receiving an idle notification + */ +#if MALI_USE_CSF +#define KBASE_TLSTREAM_TL_KBASE_DEVICE_CSG_IDLE( \ + kbdev, \ + kbase_device_id, \ + kbase_device_csg_slot_index \ + ) \ + do { \ + int enabled = atomic_read(&kbdev->timeline_flags); \ + if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ + __kbase_tlstream_tl_kbase_device_csg_idle( \ + __TL_DISPATCH_STREAM(kbdev, obj), \ + kbase_device_id, \ + kbase_device_csg_slot_index \ + ); \ + } while (0) +#else +#define KBASE_TLSTREAM_TL_KBASE_DEVICE_CSG_IDLE( \ kbdev, \ kbase_device_id, \ kbase_device_csg_slot_index \ @@ -2373,16 +2488,16 @@ struct kbase_tlstream; * @kbdev: Kbase device * @kcpu_queue: KCPU queue * @cqs_obj_gpu_addr: CQS Object GPU pointer - * @cqs_obj_compare_value: Semaphore value that should be exceeded for the WAIT to pass - * @cqs_obj_inherit_error: Flag which indicates if the CQS object error state should be inherited by the queue + * @compare_value: Semaphore value that should be exceeded for the WAIT to pass + * @inherit_error: Flag which indicates if the CQS object error state should be inherited by the queue */ #if MALI_USE_CSF #define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT( \ kbdev, \ kcpu_queue, \ cqs_obj_gpu_addr, \ - cqs_obj_compare_value, \ - cqs_obj_inherit_error \ + compare_value, \ + inherit_error \ ) \ do { \ int enabled = atomic_read(&kbdev->timeline_flags); \ @@ -2391,8 +2506,8 @@ struct kbase_tlstream; __TL_DISPATCH_STREAM(kbdev, obj), \ kcpu_queue, \ cqs_obj_gpu_addr, \ - cqs_obj_compare_value, \ - cqs_obj_inherit_error \ + compare_value, \ + inherit_error \ ); \ } while (0) #else @@ -2400,8 +2515,8 @@ struct kbase_tlstream; kbdev, \ kcpu_queue, \ cqs_obj_gpu_addr, \ - cqs_obj_compare_value, \ - cqs_obj_inherit_error \ + compare_value, \ + inherit_error \ ) \ do { } while (0) #endif /* MALI_USE_CSF */ @@ -2437,6 +2552,96 @@ struct kbase_tlstream; do { } while (0) #endif /* MALI_USE_CSF */ +/** + * KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT_OPERATION - KCPU Queue enqueues Wait Operation on Cross Queue Sync Object + * + * @kbdev: Kbase device + * @kcpu_queue: KCPU queue + * @cqs_obj_gpu_addr: CQS Object GPU pointer + * @compare_value: Value that should be compared to semaphore value for the WAIT to pass + * @condition: Condition for unblocking WAITs on Timeline Cross Queue Sync Object (e.g. greater than, less or equal) + * @data_type: Data type of a CQS Object's value + * @inherit_error: Flag which indicates if the CQS object error state should be inherited by the queue + */ +#if MALI_USE_CSF +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT_OPERATION( \ + kbdev, \ + kcpu_queue, \ + cqs_obj_gpu_addr, \ + compare_value, \ + condition, \ + data_type, \ + inherit_error \ + ) \ + do { \ + int enabled = atomic_read(&kbdev->timeline_flags); \ + if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ + __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_wait_operation( \ + __TL_DISPATCH_STREAM(kbdev, obj), \ + kcpu_queue, \ + cqs_obj_gpu_addr, \ + compare_value, \ + condition, \ + data_type, \ + inherit_error \ + ); \ + } while (0) +#else +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_WAIT_OPERATION( \ + kbdev, \ + kcpu_queue, \ + cqs_obj_gpu_addr, \ + compare_value, \ + condition, \ + data_type, \ + inherit_error \ + ) \ + do { } while (0) +#endif /* MALI_USE_CSF */ + +/** + * KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET_OPERATION - KCPU Queue enqueues Set Operation on Cross Queue Sync Object + * + * @kbdev: Kbase device + * @kcpu_queue: KCPU queue + * @cqs_obj_gpu_addr: CQS Object GPU pointer + * @value: Value that will be set or added to semaphore + * @operation: Operation type performed on semaphore value (SET or ADD) + * @data_type: Data type of a CQS Object's value + */ +#if MALI_USE_CSF +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET_OPERATION( \ + kbdev, \ + kcpu_queue, \ + cqs_obj_gpu_addr, \ + value, \ + operation, \ + data_type \ + ) \ + do { \ + int enabled = atomic_read(&kbdev->timeline_flags); \ + if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ + __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_cqs_set_operation( \ + __TL_DISPATCH_STREAM(kbdev, obj), \ + kcpu_queue, \ + cqs_obj_gpu_addr, \ + value, \ + operation, \ + data_type \ + ); \ + } while (0) +#else +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_CQS_SET_OPERATION( \ + kbdev, \ + kcpu_queue, \ + cqs_obj_gpu_addr, \ + value, \ + operation, \ + data_type \ + ) \ + do { } while (0) +#endif /* MALI_USE_CSF */ + /** * KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_ENQUEUE_MAP_IMPORT - KCPU Queue enqueues Map Import * @@ -2999,6 +3204,95 @@ struct kbase_tlstream; do { } while (0) #endif /* MALI_USE_CSF */ +/** + * KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_START - KCPU Queue starts a Wait Operation on Cross Queue Sync Object + * + * @kbdev: Kbase device + * @kcpu_queue: KCPU queue + */ +#if MALI_USE_CSF +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_START( \ + kbdev, \ + kcpu_queue \ + ) \ + do { \ + int enabled = atomic_read(&kbdev->timeline_flags); \ + if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ + __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_wait_operation_start( \ + __TL_DISPATCH_STREAM(kbdev, obj), \ + kcpu_queue \ + ); \ + } while (0) +#else +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_START( \ + kbdev, \ + kcpu_queue \ + ) \ + do { } while (0) +#endif /* MALI_USE_CSF */ + +/** + * KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_END - KCPU Queue ends a Wait Operation on Cross Queue Sync Object + * + * @kbdev: Kbase device + * @kcpu_queue: KCPU queue + * @execute_error: Non-zero error code if KCPU Queue item completed with error, else zero + */ +#if MALI_USE_CSF +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_END( \ + kbdev, \ + kcpu_queue, \ + execute_error \ + ) \ + do { \ + int enabled = atomic_read(&kbdev->timeline_flags); \ + if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ + __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_wait_operation_end( \ + __TL_DISPATCH_STREAM(kbdev, obj), \ + kcpu_queue, \ + execute_error \ + ); \ + } while (0) +#else +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_WAIT_OPERATION_END( \ + kbdev, \ + kcpu_queue, \ + execute_error \ + ) \ + do { } while (0) +#endif /* MALI_USE_CSF */ + +/** + * KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET_OPERATION - KCPU Queue executes a Set Operation on Cross Queue Sync Object + * + * @kbdev: Kbase device + * @kcpu_queue: KCPU queue + * @execute_error: Non-zero error code if KCPU Queue item completed with error, else zero + */ +#if MALI_USE_CSF +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET_OPERATION( \ + kbdev, \ + kcpu_queue, \ + execute_error \ + ) \ + do { \ + int enabled = atomic_read(&kbdev->timeline_flags); \ + if (enabled & BASE_TLSTREAM_ENABLE_CSF_TRACEPOINTS) \ + __kbase_tlstream_tl_kbase_kcpuqueue_execute_cqs_set_operation( \ + __TL_DISPATCH_STREAM(kbdev, obj), \ + kcpu_queue, \ + execute_error \ + ); \ + } while (0) +#else +#define KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_CQS_SET_OPERATION( \ + kbdev, \ + kcpu_queue, \ + execute_error \ + ) \ + do { } while (0) +#endif /* MALI_USE_CSF */ + /** * KBASE_TLSTREAM_TL_KBASE_KCPUQUEUE_EXECUTE_MAP_IMPORT_START - KCPU Queue starts a Map Import * diff --git a/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c b/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c index 6023495e571a..7438cb4951e2 100644 --- a/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c +++ b/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c @@ -41,7 +41,7 @@ #include static struct monitor_dev_profile mali_mdevp = { - .type = MONITOR_TPYE_DEV, + .type = MONITOR_TYPE_DEV, .low_temp_adjust = rockchip_monitor_dev_low_temp_adjust, .high_temp_adjust = rockchip_monitor_dev_high_temp_adjust, }; diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c index ab14bc2e2ae4..4e8e56e9baf2 100644 --- a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c +++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c @@ -51,7 +51,7 @@ static struct devfreq_simple_ondemand_data ondemand_data; static struct monitor_dev_profile mali_mdevp = { - .type = MONITOR_TPYE_DEV, + .type = MONITOR_TYPE_DEV, .low_temp_adjust = rockchip_monitor_dev_low_temp_adjust, .high_temp_adjust = rockchip_monitor_dev_high_temp_adjust, }; @@ -241,16 +241,24 @@ static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev, static void kbase_devfreq_term_freq_table(struct kbase_device *kbdev) { - struct devfreq_dev_profile *dp = kbdev->devfreq->profile; + struct devfreq_dev_profile *dp = &kbdev->devfreq_profile; kfree(dp->freq_table); + dp->freq_table = NULL; +} + +static void kbase_devfreq_term_core_mask_table(struct kbase_device *kbdev) +{ + kfree(kbdev->opp_table); + kbdev->opp_table = NULL; } static void kbase_devfreq_exit(struct device *dev) { struct kbase_device *kbdev = dev_get_drvdata(dev); - kbase_devfreq_term_freq_table(kbdev); + if (kbdev) + kbase_devfreq_term_freq_table(kbdev); } static int kbase_devfreq_init_core_mask_table(struct kbase_device *kbdev) @@ -358,7 +366,7 @@ int kbase_devfreq_init(struct kbase_device *kbdev) err = kbase_devfreq_init_core_mask_table(kbdev); if (err) - return err; + goto init_core_mask_table_failed; of_property_read_u32(np, "upthreshold", &ondemand_data.upthreshold); @@ -368,8 +376,10 @@ int kbase_devfreq_init(struct kbase_device *kbdev) kbdev->devfreq = devfreq_add_device(kbdev->dev, dp, "simple_ondemand", &ondemand_data); if (IS_ERR(kbdev->devfreq)) { - kbase_devfreq_term_freq_table(kbdev); - return PTR_ERR(kbdev->devfreq); + err = PTR_ERR(kbdev->devfreq); + kbdev->devfreq = NULL; + dev_err(kbdev->dev, "Fail to add devfreq device(%d)", err); + goto devfreq_add_dev_failed; } /* devfreq_add_device only copies a few of kbdev->dev's fields, so @@ -429,6 +439,12 @@ opp_notifier_failed: else kbdev->devfreq = NULL; +devfreq_add_dev_failed: + kbase_devfreq_term_core_mask_table(kbdev); + +init_core_mask_table_failed: + kbase_devfreq_term_freq_table(kbdev); + return err; } @@ -454,5 +470,5 @@ void kbase_devfreq_term(struct kbase_device *kbdev) else kbdev->devfreq = NULL; - kfree(kbdev->opp_table); + kbase_devfreq_term_core_mask_table(kbdev); } diff --git a/drivers/gpu/drm/bridge/maxim-max96745.c b/drivers/gpu/drm/bridge/maxim-max96745.c index 9755f129f519..00bd4dc5886d 100644 --- a/drivers/gpu/drm/bridge/maxim-max96745.c +++ b/drivers/gpu/drm/bridge/maxim-max96745.c @@ -88,6 +88,23 @@ static void max96745_bridge_enable(struct drm_bridge *bridge) { struct max96745_bridge *ser = to_max96745_bridge(bridge); struct max96745 *max96745 = ser->parent; + struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode; + u8 cxtp, tx_rate; + u32 reg; + + regmap_read(ser->regmap, 0x0011, ®); + cxtp = FIELD_GET(CXTP_A, reg); + regmap_read(ser->regmap, 0x0028, ®); + tx_rate = FIELD_GET(TX_RATE, reg); + if (!cxtp && mode->clock > 95000 && tx_rate == 1) { + regmap_update_bits(ser->regmap, 0x0028, TX_RATE, + FIELD_PREP(TX_RATE, 2)); + regmap_update_bits(ser->regmap, 0x0029, RESET_ONESHOT, + FIELD_PREP(RESET_ONESHOT, 1)); + if (regmap_read_poll_timeout(ser->regmap, 0x002a, reg, + reg & LINK_LOCKED, 10000, 200000)) + dev_err(ser->dev, "%s: GMSL link not locked\n", __func__); + } if (ser->panel) drm_panel_enable(ser->panel); @@ -109,9 +126,30 @@ static void max96745_bridge_disable(struct drm_bridge *bridge) static void max96745_bridge_post_disable(struct drm_bridge *bridge) { struct max96745_bridge *ser = to_max96745_bridge(bridge); + u8 cxtp, tx_rate, link_locked; + u32 reg; + + regmap_read(ser->regmap, 0x002a, ®); + link_locked = FIELD_GET(LINK_LOCKED, reg); if (ser->panel) drm_panel_unprepare(ser->panel); + + regmap_read(ser->regmap, 0x0011, ®); + cxtp = FIELD_GET(CXTP_A, reg); + regmap_read(ser->regmap, 0x0028, ®); + tx_rate = FIELD_GET(TX_RATE, reg); + if (!cxtp && tx_rate == 2) { + regmap_update_bits(ser->regmap, 0x0028, TX_RATE, + FIELD_PREP(TX_RATE, 1)); + regmap_update_bits(ser->regmap, 0x0029, RESET_ONESHOT, + FIELD_PREP(RESET_ONESHOT, 1)); + if (link_locked) { + if (regmap_read_poll_timeout(ser->regmap, 0x002a, reg, + reg & LINK_LOCKED, 10000, 200000)) + dev_err(ser->dev, "%s: GMSL link not locked\n", __func__); + } + } } static enum drm_connector_status diff --git a/drivers/gpu/drm/bridge/rohm-bu18tl82.c b/drivers/gpu/drm/bridge/rohm-bu18tl82.c index 5bc289929592..ed7622b0945c 100644 --- a/drivers/gpu/drm/bridge/rohm-bu18tl82.c +++ b/drivers/gpu/drm/bridge/rohm-bu18tl82.c @@ -39,7 +39,6 @@ struct bu18tl82 { struct device_node *dsi_node; struct serdes_init_seq *serdes_init_seq; bool sel_mipi; - struct regulator *supply; struct gpio_desc *reset_gpio; struct gpio_desc *enable_gpio; }; @@ -202,12 +201,6 @@ static void bu18tl82_bridge_detach(struct drm_bridge *bridge) static void bu18tl82_bridge_enable(struct drm_bridge *bridge) { - struct bu18tl82 *bu18tl82 = bridge_to_bu18tl82(bridge); - struct serdes_init_seq *init_seq = bu18tl82->serdes_init_seq; - int count = init_seq->reg_seq_cnt; - - regmap_multi_reg_write(bu18tl82->regmap, init_seq->reg_sequence, count); - mdelay(1000); } static void bu18tl82_bridge_disable(struct drm_bridge *bridge) @@ -217,26 +210,26 @@ static void bu18tl82_bridge_disable(struct drm_bridge *bridge) static void bu18tl82_bridge_pre_enable(struct drm_bridge *bridge) { struct bu18tl82 *bu18tl82 = bridge_to_bu18tl82(bridge); + struct serdes_init_seq *init_seq = bu18tl82->serdes_init_seq; int ret; - if (bu18tl82->supply) { - ret = regulator_enable(bu18tl82->supply); - if (ret < 0) - return; - - msleep(120); - } - if (bu18tl82->enable_gpio) { gpiod_direction_output(bu18tl82->enable_gpio, 1); - msleep(120); + msleep(20); } if (bu18tl82->reset_gpio) { - gpiod_direction_output(bu18tl82->reset_gpio, 1); - msleep(120); gpiod_direction_output(bu18tl82->reset_gpio, 0); + msleep(30); } + + ret = regmap_multi_reg_write(bu18tl82->regmap, init_seq->reg_sequence, + init_seq->reg_seq_cnt); + if (ret) { + dev_err(bu18tl82->dev, "failed to set register setting: %d\n", ret); + return; + } + msleep(160); } static void bu18tl82_bridge_post_disable(struct drm_bridge *bridge) @@ -248,9 +241,6 @@ static void bu18tl82_bridge_post_disable(struct drm_bridge *bridge) if (bu18tl82->enable_gpio) gpiod_direction_output(bu18tl82->enable_gpio, 0); - - if (bu18tl82->supply) - regulator_disable(bu18tl82->supply); } static const struct drm_bridge_funcs bu18tl82_bridge_funcs = { @@ -277,11 +267,6 @@ static int bu18tl82_i2c_probe(struct i2c_client *client, bu18tl82->dev = dev; i2c_set_clientdata(client, bu18tl82); - bu18tl82->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(bu18tl82->supply)) - return dev_err_probe(dev, PTR_ERR(bu18tl82->supply), - "failed to get power regulator\n"); - bu18tl82->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); if (IS_ERR(bu18tl82->reset_gpio)) return dev_err_probe(dev, PTR_ERR(bu18tl82->reset_gpio), diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 19d09adc0fbe..7ea4a5468986 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -269,6 +269,9 @@ struct dw_hdmi_qp { u8 phy_mask; /* desired phy int mask settings */ u8 mc_clkdis; /* clock disable register */ + bool update; + bool hdr2sdr; + u32 scdc_intr; u32 flt_intr; u32 earc_intr; @@ -289,6 +292,7 @@ struct dw_hdmi_qp { struct regmap *regm; bool initialized; /* hdmi is enabled before bind */ + bool logo_plug_out; /* hdmi is plug out when kernel logo */ struct completion flt_cmp; struct completion earc_cmp; @@ -1182,6 +1186,8 @@ int dw_hdmi_qp_set_earc(struct dw_hdmi_qp *hdmi) if (ret) return ret; + hdmi->disabled = false; + reinit_completion(&hdmi->earc_cmp); hdmi_modb(hdmi, EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ | @@ -1362,6 +1368,8 @@ static void hdmi_config_AVI(struct dw_hdmi_qp *hdmi, buff[4] |= ((frame.colorspace & 0x7) << 5); buff[7] = hdmi->vic; hdmi_infoframe_set_checksum(buff, 17); + } else if (is_hdmi2_sink(connector)) { + buff[7] = hdmi->vic; } /* @@ -1429,6 +1437,10 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi_qp *hdmi, err = 9; } else { + if (is_hdmi2_sink(connector)) { + hdmi_modb(hdmi, 0, PKTSCHED_VSI_TX_EN, PKTSCHED_PKT_EN); + return; + } err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, connector, mode); if (err < 0) @@ -1627,6 +1639,11 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi_qp *hdmi, hdmi_modb(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1); + /* + * avi and hdr infoframe cannot be sent at the same time + * for compatibility with Huawei TV + */ + mdelay(50); hdmi_modb(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); DRM_DEBUG("%s eotf %d end\n", __func__, @@ -1778,7 +1795,7 @@ static int hdmi_set_op_mode(struct dw_hdmi_qp *hdmi, const struct drm_connector *connector) { int frl_rate; - int i, ret; + int i, ret = 0; if (hdmi->frl_switch) return 0; @@ -1787,9 +1804,18 @@ static int hdmi_set_op_mode(struct dw_hdmi_qp *hdmi, dev_info(hdmi->dev, "dw hdmi qp use tmds mode\n"); hdmi_modb(hdmi, 0, OPMODE_FRL, LINK_CONFIG0); hdmi_modb(hdmi, 0, OPMODE_FRL_4LANES, LINK_CONFIG0); - return hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); + if (!hdmi->update) { + ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); + if (!ret) + hdmi->disabled = false; + } + + return ret; } + if (hdmi->update) + return 0; + if (link_cfg->frl_lanes == 4) hdmi_modb(hdmi, OPMODE_FRL_4LANES, OPMODE_FRL_4LANES, LINK_CONFIG0); @@ -1803,6 +1829,8 @@ static int hdmi_set_op_mode(struct dw_hdmi_qp *hdmi, ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); if (ret) return ret; + hdmi->disabled = false; + msleep(50); ret = hdmi_start_flt(hdmi, frl_rate); @@ -1882,6 +1910,7 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; } + /* Get input format from plat data or fallback to RGB888 */ if (hdmi->plat_data->get_input_bus_format) hdmi->hdmi_data.enc_in_bus_format = @@ -1899,6 +1928,9 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, else hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; + if (hdmi->plat_data->set_prev_bus_format) + hdmi->plat_data->set_prev_bus_format(data, hdmi->hdmi_data.enc_out_bus_format); + /* Get input encoding from plat data or fallback to none */ if (hdmi->plat_data->get_enc_in_encoding) hdmi->hdmi_data.enc_in_encoding = @@ -1923,7 +1955,7 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, hdmi->phy.ops->set_mode(hdmi, hdmi->phy.data, HDMI_MODE_FRL_MASK, link_cfg->frl_mode); - if (hdmi->plat_data->link_clk_set && !hdmi->frl_switch) + if (!hdmi->update && !hdmi->frl_switch && hdmi->plat_data->link_clk_set) hdmi->plat_data->link_clk_set(data, true); /* @@ -1969,7 +2001,8 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, hdmi_modb(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); hdmi_modb(hdmi, KEEPOUT_REKEY_ALWAYS, KEEPOUT_REKEY_CFG, FRAME_COMPOSER_CONFIG9); - if (!link_cfg->frl_mode && dw_hdmi_support_scdc(hdmi, &connector->display_info)) { + if (!link_cfg->frl_mode && dw_hdmi_support_scdc(hdmi, &connector->display_info) && + !hdmi->update) { if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK) { drm_scdc_readb(hdmi->ddc, SCDC_SINK_VERSION, &bytes); drm_scdc_writeb(hdmi->ddc, SCDC_SOURCE_VERSION, @@ -1991,10 +2024,6 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, hdmi_config_CVTEM(hdmi); hdmi_config_drm_infoframe(hdmi, connector); ret = hdmi_set_op_mode(hdmi, link_cfg, connector); - msleep(50); - /* clear avmute */ - hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0); - hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); if (ret) { dev_err(hdmi->dev, "%s hdmi set operation mode failed\n", __func__); hdmi->frl_switch = false; @@ -2349,19 +2378,70 @@ static bool dw_hdmi_color_changed(struct drm_connector *connector, return ret; } -static bool hdr_metadata_equal(const struct drm_connector_state *old_state, +static bool hdr_metadata_equal(struct dw_hdmi_qp *hdmi, const struct drm_connector_state *old_state, const struct drm_connector_state *new_state) { struct drm_property_blob *old_blob = old_state->hdr_output_metadata; struct drm_property_blob *new_blob = new_state->hdr_output_metadata; + int i, ret; + u8 *data; - if (!old_blob || !new_blob) - return old_blob == new_blob; + hdmi->hdr2sdr = false; + + if (!old_blob && !new_blob) + return true; + + if (!old_blob) { + data = (u8 *)new_blob->data; + + for (i = 0; i < new_blob->length; i++) + if (data[i]) + return false; + + return true; + } + + if (!new_blob) { + data = (u8 *)old_blob->data; + + for (i = 0; i < old_blob->length; i++) + if (data[i]) + return false; + + return true; + } if (old_blob->length != new_blob->length) return false; - return !memcmp(old_blob->data, new_blob->data, old_blob->length); + ret = !memcmp(old_blob->data, new_blob->data, old_blob->length); + + if (!ret && new_blob) { + data = (u8 *)new_blob->data; + + for (i = 0; i < new_blob->length; i++) + if (data[i]) + break; + + if (i == new_blob->length) + hdmi->hdr2sdr = true; + } + + return ret; +} + +static bool check_hdr_color_change(struct drm_connector_state *old_state, + struct drm_connector_state *new_state, + struct dw_hdmi_qp *hdmi) +{ + void *data = hdmi->plat_data->phy_data; + + if (!hdr_metadata_equal(hdmi, old_state, new_state)) { + hdmi->plat_data->check_hdr_color_change(new_state, data); + return true; + } + + return false; } static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, @@ -2406,6 +2486,7 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, */ if (!vmode->mpixelclock) { struct dw_hdmi_qp *secondary = NULL; + u8 val; if (hdmi->plat_data->left) secondary = hdmi->plat_data->left; @@ -2456,22 +2537,74 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, hdmi->curr_conn = connector; extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, true); } + + drm_scdc_readb(hdmi->ddc, SCDC_TMDS_CONFIG, &val); + /* if plug out before hdmi bind, reset hdmi */ + if (vmode->mtmdsclock >= 340000000 && vmode->mpixelclock <= 600000000 && + !(val & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40)) + hdmi->logo_plug_out = true; } - if (!hdr_metadata_equal(old_state, new_state) || + if (check_hdr_color_change(old_state, new_state, hdmi) || hdmi->logo_plug_out || dw_hdmi_color_changed(connector, state)) { + u32 mtmdsclk; + crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - crtc_state->mode_changed = true; - if (mode.clock > 600000) - hdmi->frl_switch = true; + if (hdmi->plat_data->update_color_format) + hdmi->plat_data->update_color_format(new_state, data); + if (hdmi->plat_data->get_enc_in_encoding) + hdmi->hdmi_data.enc_in_encoding = + hdmi->plat_data->get_enc_in_encoding(data); + if (hdmi->plat_data->get_enc_out_encoding) + hdmi->hdmi_data.enc_out_encoding = + hdmi->plat_data->get_enc_out_encoding(data); + if (hdmi->plat_data->get_input_bus_format) + hdmi->hdmi_data.enc_in_bus_format = + hdmi->plat_data->get_input_bus_format(data); + if (hdmi->plat_data->get_output_bus_format) + hdmi->hdmi_data.enc_out_bus_format = + hdmi->plat_data->get_output_bus_format(data); + + mtmdsclk = hdmi_get_tmdsclock(hdmi, mode.clock); + if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) + mtmdsclk /= 2; + + if (hdmi->hdmi_data.video_mode.mpixelclock == (mode.clock * 1000) && + hdmi->hdmi_data.video_mode.mtmdsclock == (mtmdsclk * 1000) && + mode.clock <= 600000 && !hdmi->disabled && !hdmi->logo_plug_out) { + hdmi->update = true; + hdmi_writel(hdmi, 1, PKTSCHED_PKT_CONTROL0); + hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); + mdelay(50); + } else if (!hdmi->disabled) { + if (mode.clock > 600000) + hdmi->frl_switch = true; + hdmi->update = false; + crtc_state->mode_changed = true; + hdmi->logo_plug_out = false; + } } return 0; } +static void dw_hdmi_connector_atomic_commit(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct dw_hdmi_qp *hdmi = + container_of(connector, struct dw_hdmi_qp, connector); + + if (hdmi->update) { + dw_hdmi_qp_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); + msleep(50); + hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0); + hdmi->update = false; + } +} + void dw_hdmi_qp_set_output_type(struct dw_hdmi_qp *hdmi, u64 val) { hdmi->force_output = val; @@ -2538,6 +2671,7 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = .get_modes = dw_hdmi_connector_get_modes, .best_encoder = dw_hdmi_connector_best_encoder, .atomic_check = dw_hdmi_connector_atomic_check, + .atomic_commit = dw_hdmi_connector_atomic_commit, }; static int dw_hdmi_qp_bridge_attach(struct drm_bridge *bridge, @@ -2645,17 +2779,18 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, if (hdmi->phy.ops->disable && !hdmi->frl_switch) { hdmi_writel(hdmi, 0, FLT_CONFIG0); + hdmi_writel(hdmi, 0, SCRAMB_CONFIG0); /* set sink frl mode disable */ if (hdmi->curr_conn && dw_hdmi_support_scdc(hdmi, &hdmi->curr_conn->display_info)) drm_scdc_writeb(hdmi->ddc, 0x31, 0); hdmi->phy.ops->disable(hdmi, hdmi->phy.data); + hdmi->disabled = true; if (hdmi->plat_data->link_clk_set) hdmi->plat_data->link_clk_set(data, false); } hdmi->curr_conn = NULL; - hdmi->disabled = true; mutex_unlock(&hdmi->mutex); if (hdmi->panel) @@ -2680,7 +2815,8 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, hdmi->curr_conn = connector; dw_hdmi_qp_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); - hdmi->disabled = false; + hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0); + hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); mutex_unlock(&hdmi->mutex); if (!hdmi->dclk_en) { @@ -3280,7 +3416,9 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi_writel(hdmi, 0, MAINUNIT_0_INT_MASK_N); hdmi_writel(hdmi, 0, MAINUNIT_1_INT_MASK_N); hdmi_writel(hdmi, 428571429, TIMER_BASE_CONFIG0); - if ((hdmi_readl(hdmi, CMU_STATUS) & DISPLAY_CLK_MONITOR) == DISPLAY_CLK_LOCKED) { + hdmi->logo_plug_out = false; + if (hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data) == connector_status_connected && + hdmi_readl(hdmi, I2CM_INTERFACE_CONTROL0)) { hdmi->initialized = true; hdmi->disabled = false; } @@ -3365,6 +3503,28 @@ __dw_hdmi_probe(struct platform_device *pdev, goto err_aud; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto err_aud; + } + + hdmi->avp_irq = irq; + ret = devm_request_threaded_irq(dev, hdmi->avp_irq, + dw_hdmi_qp_avp_hardirq, + dw_hdmi_qp_avp_irq, IRQF_SHARED, + dev_name(dev), hdmi); + if (ret) + goto err_aud; + + irq = platform_get_irq(pdev, 1); + if (irq < 0) { + ret = irq; + goto err_aud; + } + + cec.irq = irq; + if (of_property_read_bool(np, "cec-enable")) { hdmi->cec_enable = true; cec.hdmi = hdmi; @@ -3376,28 +3536,6 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi->cec = platform_device_register_full(&pdevinfo); } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err_cec; - } - - hdmi->avp_irq = irq; - ret = devm_request_threaded_irq(dev, hdmi->avp_irq, - dw_hdmi_qp_avp_hardirq, - dw_hdmi_qp_avp_irq, IRQF_SHARED, - dev_name(dev), hdmi); - if (ret) - goto err_cec; - - irq = platform_get_irq(pdev, 1); - if (irq < 0) { - ret = irq; - goto err_cec; - } - - cec.irq = irq; - irq = platform_get_irq(pdev, 2); if (irq < 0) { ret = irq; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 4d9d27f1f9ee..1d137af13e73 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -994,16 +994,13 @@ static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi) if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); - if (dsi->slave) - dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO); } else { dsi_write(dsi, DSI_EDPI_CMD_SIZE, dsi->mode.hdisplay); dw_mipi_dsi_set_mode(dsi, 0); - if (dsi->slave) { - dsi_write(dsi->slave, DSI_EDPI_CMD_SIZE, dsi->mode.hdisplay); - dw_mipi_dsi_set_mode(dsi->slave, 0); - } } + + if (dsi->slave) + dw_mipi_dsi_enable(dsi->slave); } static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4108c7265d53..33768ddfaacb 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -296,14 +296,12 @@ update_connector_routing(struct drm_atomic_state *state, if (old_connector_state->crtc != new_connector_state->crtc) { if (old_connector_state->crtc) { crtc_state = drm_atomic_get_new_crtc_state(state, old_connector_state->crtc); - if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) - crtc_state->connectors_changed = true; + crtc_state->connectors_changed = true; } if (new_connector_state->crtc) { crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc); - if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) - crtc_state->connectors_changed = true; + crtc_state->connectors_changed = true; } } @@ -388,8 +386,7 @@ update_connector_routing(struct drm_atomic_state *state, set_best_encoder(state, new_connector_state, new_encoder); - if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) - crtc_state->connectors_changed = true; + crtc_state->connectors_changed = true; DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n", connector->base.id, diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 258b01e2f1b7..4a57b259e6c1 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1915,6 +1915,76 @@ int drm_add_override_edid_modes(struct drm_connector *connector) } EXPORT_SYMBOL(drm_add_override_edid_modes); +#ifdef CONFIG_NO_GKI +/* + * References: + * - CTA-861-H section 7.3.3 CTA Extension Version 3 + */ +static int cea_db_collection_size(const u8 *cta) +{ + u8 d = cta[2]; + + if (d < 4 || d > 127) + return 0; + + return d - 4; +} + +#define CTA_EXT_DB_HF_EEODB 0x78 +#define CTA_DB_EXTENDED_TAG 7 + +static int cea_db_tag(const u8 *db); +static int cea_db_payload_len(const u8 *db); +static int cea_db_extended_tag(const u8 *db); + +static bool cea_db_is_extended_tag(const void *db, int tag) +{ + return cea_db_tag(db) == CTA_DB_EXTENDED_TAG && + cea_db_payload_len(db) >= 1 && + cea_db_extended_tag(db) == tag; +} + +static bool cea_db_is_hdmi_forum_eeodb(const void *db) +{ + return cea_db_is_extended_tag(db, CTA_EXT_DB_HF_EEODB) && + cea_db_payload_len(db) >= 2; +} + +static int edid_hfeeodb_extension_block_count(const struct edid *edid) +{ + const u8 *cta; + + /* No extensions according to base block, no HF-EEODB. */ + if (!edid->extensions) + return 0; + + /* HF-EEODB is always in the first EDID extension block only */ + cta = (u8 *)edid + EDID_LENGTH * 1; + if (cta[0] != CEA_EXT || cta[1] < 3) + return 0; + + /* Need to have the data block collection, and at least 3 bytes. */ + if (cea_db_collection_size(cta) < 3) + return 0; + + /* + * Sinks that include the HF-EEODB in their E-EDID shall include one and + * only one instance of the HF-EEODB in the E-EDID, occupying bytes 4 + * through 6 of Block 1 of the E-EDID. + */ + if (!cea_db_is_hdmi_forum_eeodb(&cta[4])) + return 0; + + return cta[4 + 2]; +} + +static int edid_hfeeodb_block_count(const struct edid *edid) +{ + int eeodb = edid_hfeeodb_extension_block_count(edid); + + return eeodb ? eeodb + 1 : 0; +} + /** * drm_do_get_edid - get EDID data using a custom EDID block read function * @connector: connector we're probing @@ -1935,6 +2005,120 @@ EXPORT_SYMBOL(drm_add_override_edid_modes); * * Return: Pointer to valid EDID or NULL if we couldn't find any. */ +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *data, u8 *buf, unsigned int block, + size_t len), + void *data) +{ + int i, j = 0, valid_extensions = 0, num_blocks, invalid_blocks = 0; + u8 *edid, *new; + struct edid *override; + + override = drm_get_override_edid(connector); + if (override) + return override; + + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!edid) + return NULL; + + /* base block fetch */ + for (i = 0; i < 4; i++) { + if (get_edid_block(data, edid, 0, EDID_LENGTH)) + goto out; + if (drm_edid_block_valid(edid, 0, false, + &connector->edid_corrupt)) + break; + if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) { + connector->null_edid_counter++; + goto out; + } + } + if (i == 4) + goto out; + + /* if there's no extensions, we're done */ + valid_extensions = edid[0x7e]; + if (valid_extensions == 0) + return (struct edid *)edid; + + new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); + if (!new) + goto out; + edid = new; + + num_blocks = edid[0x7e] + 1; + + for (j = 1; j < num_blocks; j++) { + u8 *block = edid + j * EDID_LENGTH; + + for (i = 0; i < 4; i++) { + if (get_edid_block(data, block, j, EDID_LENGTH)) + goto out; + if (drm_edid_block_valid(block, j, false, NULL)) + break; + } + + if (i == 4) + invalid_blocks++; + + if (j == 1) { + /* + * If the first EDID extension is a CTA extension, and + * the first Data Block is HF-EEODB, override the + * extension block count. + * + * Note: HF-EEODB could specify a smaller extension + * count too, but we can't risk allocating a smaller + * amount. + */ + int eeodb = edid_hfeeodb_block_count((const struct edid *)edid); + + if (eeodb > num_blocks) { + num_blocks = eeodb; + new = krealloc(edid, num_blocks * EDID_LENGTH, GFP_KERNEL); + if (!new) + goto out; + edid = new; + } + } + } + + if (invalid_blocks) { + u8 *base; + + connector_bad_edid(connector, edid, edid[0x7e] + 1); + + new = kmalloc_array(valid_extensions + 1, EDID_LENGTH, + GFP_KERNEL); + if (!new) + goto out; + + base = new; + for (i = 0; i <= edid[0x7e]; i++) { + u8 *block = edid + i * EDID_LENGTH; + + if (!drm_edid_block_valid(block, i, false, NULL)) + continue; + + memcpy(base, block, EDID_LENGTH); + base += EDID_LENGTH; + } + + new[EDID_LENGTH - 1] += new[0x7e] - valid_extensions; + new[0x7e] = valid_extensions; + + kfree(edid); + edid = new; + } + + return (struct edid *)edid; + +out: + kfree(edid); + return NULL; +} +#else struct edid *drm_do_get_edid(struct drm_connector *connector, int (*get_edid_block)(void *data, u8 *buf, unsigned int block, size_t len), @@ -2026,6 +2210,7 @@ out: kfree(edid); return NULL; } +#endif EXPORT_SYMBOL_GPL(drm_do_get_edid); /** @@ -3245,6 +3430,39 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, /* * Search EDID for CEA extension block. */ +#ifdef CONFIG_NO_GKI +static u8 *drm_find_edid_extension(const struct edid *edid, + int ext_id, int *ext_index) +{ + u8 *edid_ext = NULL; + int i; + int len; + + /* No EDID or EDID extensions */ + if (edid == NULL || edid->extensions == 0) + return NULL; + + if (edid_hfeeodb_extension_block_count(edid)) + len = edid_hfeeodb_extension_block_count(edid); + else + len = edid->extensions; + + /* Find CEA extension */ + for (i = *ext_index; i < len; i++) { + edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); + + if (edid_ext[0] == ext_id) + break; + } + + if (i >= len) + return NULL; + + *ext_index = i + 1; + + return edid_ext; +} +#else static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id, int *ext_index) { @@ -3269,7 +3487,7 @@ static u8 *drm_find_edid_extension(const struct edid *edid, return edid_ext; } - +#endif static u8 *drm_find_displayid_extension(const struct edid *edid, int *length, int *idx, @@ -4266,32 +4484,6 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, } #ifdef CONFIG_NO_GKI -static int drm_find_all_edid_extension(const struct edid *edid, - int ext_id, int *ext_list) -{ - u8 *edid_ext = NULL; - int i, count = 0; - - /* No EDID or EDID extensions */ - if (edid == NULL || edid->extensions == 0) - return -EINVAL; - - /* too many EDID extensions */ - if (edid->extensions > 32) - return -EINVAL; - - /* Find CEA extension */ - for (i = 0; i < edid->extensions; i++) { - edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); - if (edid_ext[0] == ext_id) { - *ext_list = i; - ext_list++; - count++; - } - } - - return count; -} static int add_cea_modes(struct drm_connector *connector, struct edid *edid) @@ -4301,11 +4493,15 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid) u8 dbl, hdmi_len, video_len = 0; int i, count = 0, modes = 0; int ext_index = 0; - int ext_list[32]; - count = drm_find_all_edid_extension(edid, CEA_EXT, ext_list); + if (edid_hfeeodb_extension_block_count(edid)) + count = edid_hfeeodb_extension_block_count(edid); + else + count = edid->extensions; + for (i = 0; i < count; i++) { - ext_index = ext_list[i]; + ext_index = i; + cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); if (cea && cea_revision(cea) >= 3) { int i, start, end; diff --git a/drivers/gpu/drm/panel/panel-maxim-max96752f.c b/drivers/gpu/drm/panel/panel-maxim-max96752f.c index 7212f1ccd437..34d78d2fe655 100644 --- a/drivers/gpu/drm/panel/panel-maxim-max96752f.c +++ b/drivers/gpu/drm/panel/panel-maxim-max96752f.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include