[PATCH v2 2/2] arm64: dts: rockchip: add ALIENTEK QuarkPi-CA2

BG9OXA bg9oxa at 163.com
Sun Sep 27 06:51:32 PDT 2026


Add a device tree for the ALIENTEK QuarkPi-CA2, an RK3588S based
single board computer.

Tested on hardware: UART console, eMMC, microSD, gigabit Ethernet,
HDMI video and audio, ES8388 analog audio, the USB 2.0 host ports
and the USB 3.0 (Type-A) host port.

Signed-off-by: BG9OXA <bg9oxa at 163.com>
---
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-quarkpi-ca2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-quarkpi-ca2.dts
new file mode 100644
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -236,6 +236,7 @@
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5b.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5-pro.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-cm5-base.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-quarkpi-ca2.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-radxa-cm5-io.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-roc-pc.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-rock-5a.dtb
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-quarkpi-ca2.dts
@@ -0,0 +1,1608 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/media/video-interfaces.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/thermal/thermal.h>
+#include "rk3588s.dtsi"
+/ {
+	model = "Alientek QuarkPI-CA2";
+	compatible = "alientek,quarkpi-ca2", "rockchip,rk3588s";
+
+	/* Crash log retention (pstore/ramoops).  The shared rk3588-ramoops.dtsi
+	 * used by the vendor BSP is not part of mainline, so the node is inlined
+	 * here.  The reserved region layout follows the vendor BSP device tree.
+	 */
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		ramoops: ramoops at 118000 {
+			compatible = "ramoops";
+			reg = <0 0x118000 0 0xd8000>;
+			console-size = <0x80000>;
+			ftrace-size = <0x00000>;
+			pmsg-size = <0x30000>;
+			record-size = <0x14000>;
+		};
+	};
+
+	aliases {
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		ethernet0 = &gmac1;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	adc_keys: adc-keys {
+		compatible = "adc-keys";
+		io-channels = <&saradc 1>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <100>;
+
+		button-vol-up {
+			label = "volume up";
+			linux,code = <KEY_VOLUMEUP>;
+			press-threshold-microvolt = <17000>;
+		};
+
+		button-vol-down {
+			label = "volume down";
+			linux,code = <KEY_VOLUMEDOWN>;
+			press-threshold-microvolt = <417000>;
+		};
+	};
+
+	leds: leds {
+		compatible = "gpio-leds";
+
+		work_led: led-0 {
+			/* Mainline deprecated 'label' (dtbs_check reports an
+			 * "Unevaluated properties" error); use 'function' instead.
+			 */
+			function = LED_FUNCTION_HEARTBEAT;
+			gpios = <&gpio1 RK_PD7 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+			pinctrl-names = "default";
+			pinctrl-0 = <&work_led_pin>;
+		};
+	};
+
+	fan: pwm-fan {
+		compatible = "pwm-fan";
+		#cooling-cells = <2>;
+		pwms = <&pwm7 0 50000 0>;
+		cooling-levels = <0 50 100 150 200 255>;
+	};
+
+	vcc12v_dcin: vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		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 = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb: vcc5v0-usb {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_3v3_sd_s0: vcc-3v3-sd-s0-regulator {
+		compatible = "regulator-fixed";
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sd_s0_pwr>;
+		regulator-name = "vcc_3v3_sd_s0";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc_3v3_s3>;
+	};
+};
+
+&spi2 {
+	status = "okay";
+	assigned-clocks = <&cru CLK_SPI2>;
+	assigned-clock-rates = <200000000>;
+	num-cs = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+
+	pmic at 0 {
+		compatible = "rockchip,rk806";
+		reg = <0x0>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+			    <&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		spi-max-frequency = <1000000>;
+		system-power-controller;
+
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: dvs1-null-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_null: dvs2-null-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_null: dvs3-null-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-name = "vdd_gpu_s0";
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 {
+				regulator-name = "vdd_cpu_lit_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-name = "vdd_log_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 {
+				regulator-name = "vdd_vdenc_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-name = "vdd_ddr_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-name = "vdd2_ddr_s3";
+				regulator-always-on;
+				regulator-boot-on;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-name = "vcc_2v0_pldo_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-ramp-delay = <12500>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-name = "vcc_3v3_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-name = "vddq_ddr_s0";
+				regulator-always-on;
+				regulator-boot-on;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-name = "vcc_1v8_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-name = "avcc_1v8_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-name = "vcc_1v8_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-name = "avdd_1v2_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-name = "vcc_3v3_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-name = "vccio_sd_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-ramp-delay = <12500>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-name = "pldo6_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-name = "vdd_0v75_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-name = "vdd_ddr_pll_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-name = "avdd_0v75_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-name = "vdd_0v85_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-name = "vdd_0v75_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0m2_xfer>;
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		reg = <0x43>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2m0_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: vdd_npu_mem_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+		};
+
+		/*
+		* Type-C PD controller HUSB311, ported from the vendor 6.1 dtb
+		* (vendor node: i2c2 at 0x4e, status = "okay").
+		*
+		* WARNING: both compatibles are required. The of_match table of
+		* mainline tcpci_rt1711h.c has no "hynetek,husb311" entry, so the
+		* device is matched through the "richtek,rt1711h" fallback.
+		* See Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml
+		* ("hynetek,husb311" must be followed by "richtek,rt1711h");
+		* mainline rk3588-hlink-h88k-v31.dts uses the same chip.
+		*
+		* Interrupt: vendor pinctrl usbc0-int = <0x01 0x04 0x00> =>
+		*            gpio1 PA4; vendor interrupts = <0x04 0x08> =>
+		*            pin 4 + IRQ_TYPE_LEVEL_LOW.
+		* VBUS: vbus-supply = <&vbus5v0_typec>, switched by gpio1 PD5.
+		*
+		* Data path (orientation switch / DP altmode mux) is wired up: see
+		* the DP section at the end of this file -- usbdp_phy0 carries
+		* orientation-switch / mode-switch and the SBU1/SBU2 DC switches
+		* (gpio4-6/7, vendor values); the connector side adds port at 2 (SBU).
+		* DP output works at 1920x1080 and does not affect HDMI (vp0).
+		*/
+		husb311: husb311 at 4e {
+		status = "okay";
+		compatible = "hynetek,husb311", "richtek,rt1711h";
+		reg = <0x4e>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <RK_PA4 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usbc0_int>;
+		vbus-supply = <&vbus5v0_typec>;
+
+		/* Vendor connector PD parameters (values taken as-is) */
+		usb_con: connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			power-role = "dual";
+			data-role = "dual";
+			try-power-role = "sink";
+			source-pdos = <0x401912c>;
+			sink-pdos = <0x4019064>;
+			op-sink-microwatt = <1000000>;
+
+			/* DP alt mode: the connector SBU pairs have to be linked to
+			 *   usbdp_phy0's dp_out for the DP link to be complete.
+			 *   Only port at 2 (SBU) is added; HS/SS stay untouched so the
+			 *   USB3 host keeps working. */
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0xffffffff>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					usbc0_hs: endpoint {
+						remote-endpoint = <&usb_host0_hs_ep>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+					usbc0_ss: endpoint {
+						remote-endpoint = <&usb_host0_ss_ep>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+					usbc0_sbu: endpoint {
+						remote-endpoint = <&usbdp_phy0_dp_out>;
+					};
+				};
+			};
+		};
+		};
+		};
+
+		&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+	mem-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+	mem-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+	mem-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+	mem-supply = <&vdd_cpu_big1_s0>;
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&rknn_core_0 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_mem_s0>;
+	status = "okay";
+};
+
+&rknn_core_1 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_mem_s0>;
+	status = "okay";
+};
+
+&rknn_core_2 {
+	npu-supply = <&vdd_npu_s0>;
+	sram-supply = <&vdd_npu_mem_s0>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	no-sdio;
+	no-sd;
+	non-removable;
+	max-frequency = <200000000>;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	max-frequency = <150000000>;
+	no-sdio;
+	no-mmc;
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_sd_s0>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc_bus4 &sdmmc_clk &sdmmc_cmd &sdmmc_det>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&gmac1 {
+	/* Use rgmii-rxid mode to disable rx delay inside Soc */
+	phy-mode = "rgmii-rxid";
+	clock_in_out = "input";
+
+	snps,reset-gpio = <&gpio0 RK_PD5 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 = <&gmac1_miim
+		     &gmac1_tx_bus2
+		     &gmac1_rx_bus2
+		     &gmac1_rgmii_clk
+		     &gmac1_rgmii_bus
+		     &gmac1_clkinout>;
+
+	tx_delay = <0x2f>;
+	rx_delay = <0x00>;
+
+	phy-handle = <&rgmii_phy1>;
+	status = "okay";
+};
+
+&mdio1 {
+	rgmii_phy1: ethernet-phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+
+		/*
+		 * gmac1 runs with clock_in_out = "input": the MAC gets its 125M
+		 * clock from the PHY CLKOUT pin (routed through gmac1_clkinout).
+		 * The mainline motorcomm driver disables clock output by default
+		 * (clk-out-frequency-hz defaults to 0), so it has to be enabled
+		 * explicitly, otherwise the MAC gets no clock: MDIO works and the
+		 * link comes up, but the first open() times out on DMA/VLAN_TAG
+		 * and the TX watchdog fires.
+		 */
+		motorcomm,clk-out-frequency-hz = <125000000>;
+		/* Keep the PLL/clock output enabled while the link is down so
+		 * the MAC can be initialised.
+		 */
+		motorcomm,keep-pll-enabled;
+	};
+};
+
+/* USB2.0 HOST0 (PHY2) */
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+/* USB2.0 HOST1 (PHY3) */
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb>;
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&pwm7 {
+	pinctrl-0 = <&pwm7m0_pins>;
+	status = "okay";
+};
+
+&saradc {
+	status = "okay";
+	vref-supply = <&vcc_1v8_s0>;
+};
+
+&tsadc {
+	status = "okay";
+};
+
+&pinctrl {
+	sdmmc {
+		sd_s0_pwr: sd-s0-pwr {
+			rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		pcie2x1l2_perstn: pcie2x1l2-perstn {
+			/* The vendor dtsi only provides reset-gpios, not the mux,
+			 * so select the GPIO function explicitly here.
+			 */
+			rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	usb-typec {
+		typec5v_pwren: typec5v-pwren {
+			/* Vendor value <0x01 0x1d 0x00>: bank1 pin 0x1d = 29,
+			 * i.e. PD5. Note: PC5 is i2s0_lrck; driving it would
+			 * collide with the I2S LRCLK, so vbus5v0-typec fails
+			 * to probe and xhci gets no VBUS.
+			 */
+			rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
+			};
+
+			usbc0_int: usbc0-int {
+			/* Vendor value <0x01 0x04 0x00>: bank1 pin 4 => PA4
+			 * (HUSB311 interrupt pin).
+			 */
+			rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
+			};
+			};
+
+			leds {
+		work_led_pin: work-led-pin {
+			rockchip,pins = <1 RK_PD7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+};
+
+/*
+ * Fan thermal control
+ *
+ * The vendor BSP uses the private rockchip,temp-trips property to do fan
+ * control inside the driver (mainline pwm-fan does not support it). Use
+ * the standard mainline approach instead: attach the fan to the package
+ * thermal zone trips + cooling maps. The thresholds follow the vendor dtsi
+ * (50/55/60/65/70 degrees C) and the steps match cooling-levels
+ * <0 50 100 150 200 255> (duty 0/50/100/150/200/255).
+ *
+ * WARNING: polling-delay defaults to 0 (no polling) in the SoC dtsi and
+ *    the board file has to enable it, otherwise temperature changes never
+ *    change the fan step: the fan runs at a fixed speed and cur_state
+ *    stays at max.
+ */
+&package_thermal {
+	polling-delay = <1000>;
+
+	trips {
+		fan_trip0: fan-trip0 {
+			temperature = <50000>;
+			hysteresis = <2000>;
+			type = "active";
+		};
+
+		fan_trip1: fan-trip1 {
+			temperature = <55000>;
+			hysteresis = <2000>;
+			type = "active";
+		};
+
+		fan_trip2: fan-trip2 {
+			temperature = <60000>;
+			hysteresis = <2000>;
+			type = "active";
+		};
+
+		fan_trip3: fan-trip3 {
+			temperature = <65000>;
+			hysteresis = <2000>;
+			type = "active";
+		};
+
+		fan_trip4: fan-trip4 {
+			temperature = <70000>;
+			hysteresis = <2000>;
+			type = "active";
+		};
+	};
+
+	cooling-maps {
+		map0 {
+			trip = <&fan_trip0>;
+			cooling-device = <&fan THERMAL_NO_LIMIT 1>;
+		};
+
+		map1 {
+			trip = <&fan_trip1>;
+			cooling-device = <&fan 1 2>;
+		};
+
+		map2 {
+			trip = <&fan_trip2>;
+			cooling-device = <&fan 2 3>;
+		};
+
+		map3 {
+			trip = <&fan_trip3>;
+			cooling-device = <&fan 3 4>;
+		};
+
+		map4 {
+			trip = <&fan_trip4>;
+			cooling-device = <&fan 4 THERMAL_NO_LIMIT>;
+		};
+	};
+};
+
+/*
+ * HDMI0 output (VOP VP0 -> hdmi0 -> hdptxphy0)
+ *
+ * The pin map comes from the vendor BSP dtb, all mux 5:
+ *   CEC = gpio4 PC1    HPD = gpio1 PA5
+ *   SCL = gpio4 PB7    SDA = gpio4 PC0
+ * It matches the mainline hdmim0_tx0_* pinctrl groups bit for bit, so they
+ * are referenced directly and no custom group is needed.
+ *
+ * Enable pin: the vendor dtsi sets
+ * enable-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; the mainline dw-hdmi-qp
+ * driver only knows frl-enable-gpios and calls gpiod_set_value(..., 0) once
+ * (de-assert), so with GPIO_ACTIVE_LOW the pin is driven high, which
+ * matches the vendor ACTIVE_HIGH enable semantics. Mainline rk3588s boards
+ * with the same pin (indiedroid-nova, coolpi-4b) are written the same way.
+ */
+&hdmi0 {
+	frl-enable-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_LOW>;
+	pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd
+		     &hdmim0_tx0_scl &hdmim0_tx0_sda>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+/*
+ * HDMI0 audio
+ *
+ * Mainline rk3588-base.dtsi already provides the hdmi0_sound card
+ * (disabled by default); it only has to be enabled together with
+ * i2s5_8ch, so no simple-audio-card has to be added here.
+ *
+ * Cross-check against the vendor 6.1 dtb:
+ *   vendor hdmi0-sound: cpu   = i2s at fddf0000   = mainline i2s5_8ch
+ *                       codec = hdmi at fde80000  = mainline hdmi0
+ *                       mclk-fs = 0x80 = 128   = mainline 128
+ * Other boards of the same SoC (RK3588S) do the same:
+ *   rk3588s-orangepi-5.dtsi:127/214, rk3588s-nanopi-r6.dtsi:258/346
+ *   only set the status of both nodes to okay.
+ */
+&i2s5_8ch {
+	status = "okay";
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+/*
+ * PCIe 2.0 x1 -- M.2 socket (over combphy0_ps)
+ *
+ * WARNING: sata0 and pcie2x1l2 share combphy0_ps, so sata0 must stay
+ *    disabled (the vendor dtsi does the same), otherwise both fight over
+ *    the same PHY.
+ * Reset pin gpio3 RK_PB2 (vendor dtb value); the 3.3V rail is always on
+ * and comes from vcc_3v3_s3.
+ */
+&sata0 {
+	status = "disabled";
+};
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2x1l2_perstn>;
+	reset-gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_3v3_s3>;
+	status = "okay";
+};
+
+/*
+ * USB3 -- Type-C port (over usbdp_phy0 + u2phy0)
+ *
+ * Mainline has no HUSB311 (TCPC) driver, so Type-C plug orientation and
+ * role switching (CC detection) are unavailable; fix the port to host
+ * mode as rock-5c does and do not use OTG/DP altmode.
+ * VBUS is controlled by vbus5v0_typec (GPIO = gpio1 PD5, vendor dtb value).
+ */
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	phy-supply = <&vbus5v0_typec>;
+	status = "okay";
+};
+
+/*
+ * USB3.0 Type-A host port (the blue, upper connector).
+ * The SuperSpeed lanes are wired to usb_host2_xhci through combphy2_psu.
+ * The vendor BSP enables both; without them the port's SS lanes have no
+ * driver and the connector only ever links at 480M (USB2).
+ * combphy2_psu is free here: this board uses pcie2x1l2 (combphy0_ps) for M.2.
+ */
+&combphy2_psu {
+	status = "okay";
+};
+
+&usb_host2_xhci {
+	status = "okay";
+};
+
+&usb_host0_xhci {
+	dr_mode = "host";
+	status = "okay";
+
+	/* USB-C connector HS/SS port graph. The binding requires port at 0 and
+	 * the SS port should be port at 1.
+	 */
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_host0_hs_ep: endpoint {
+				remote-endpoint = <&usbc0_hs>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_host0_ss_ep: endpoint {
+				remote-endpoint = <&usbc0_ss>;
+			};
+		};
+	};
+};
+
+/ {
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	/*
+	 * Type-C port VBUS 5V -- the vendor dtb has gpio = <&gpio1 0x1d 0>,
+	 * i.e. gpio1 PD5 (enable-active-high; ACTIVE_HIGH is equivalent).
+	 * Note: PC5 is i2s0_lrck (the audio LRCLK), so driving the regulator
+	 *    from it takes the audio pin over and leaves the real PD5
+	 *    undriven, which means VBUS is never switched on (self-powered
+	 *    devices still work, so such a mistake is easy to miss).
+	 */
+	vbus5v0_typec: vbus5v0-typec {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus5v0_typec";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>;
+		vin-supply = <&vcc5v0_sys>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&typec5v_pwren>;
+	};
+};
+
+/*
+ * ===== ES8388 audio (ported from the vendor BSP) =====
+ *
+ * Pins: the vendor BSP i2s0 group matches the mainline
+ *   rk3588-base-pinctrl group 1:1
+ *   mclk=PC2 m1   sclk=PC3 m1   lrck=PC5 m1   sdo0=PC7 m1   sdi0=PD4 m2
+ * i2c1(fea90000): the vendor uses i2c1m4 = PD2/PD3 mux9
+ * Headphone detect PC4, amplifier enable PC6 (vendor hp-det-gpio /
+ * hp-con-gpio, both mux0 = GPIO)
+ *
+ * WARNING: the vendor uses the private rockchip,multicodecs-card, which
+ * mainline does not have, so use a standard simple-audio-card instead.
+ * WARNING: the vendor ADC headphone detect and play-pause key are not
+ * supported by mainline and are omitted.
+ * WARNING: the driver is built in: CONFIG_SND_SOC_ES8328_I2C=y (the
+ * es8328 driver binds everest,es8388).
+ */
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m4_xfer>;
+	status = "okay";
+
+	es8388: audio-codec at 11 {
+		/* everest,es8323 must be listed first.
+		 *   Reasons (driver source plus the module present on the board):
+		 *   - Mainline es8328.c is the simplified driver (888 lines),
+		 *     es8323.c is the complete one (791 lines, with set_dai_fmt /
+		 *     set_dai_sysclk / pcm_hw_params and the coeff_div table).
+		 *   - compatible lists are matched in order: with
+		 *     'everest,es8388' first, es8328 claims the device, so es8323
+		 *     has to come first for the complete driver to bind.
+		 *   - The driver is built as a module (module alias
+		 *     of:N*T*Ceverest,es8323), so it binds once the node exists.
+		 *   - The upstream board with the same codec,
+		 *     rk3588-youyeetoo-yy3588.dts, also lists only
+		 *     es8323.
+		 *   - The vendor 6.1 BSP dtb uses the same pair,
+		 *     "everest,es8388","everest,es8323".
+		 */
+		compatible = "everest,es8323", "everest,es8388";
+		reg = <0x11>;
+		/* The codec clock phandle must use the _TO_IO variant (the
+		 *   segment that reaches the pin). Using the internal segment
+		 *   without the suffix leaves i2s0_8ch_mclkout_to_io
+		 *   deviceless/disabled, so MCLK never reaches the codec pin even
+		 *   though registers, DAPM and volume all look correct, and there
+		 *   is no sound at all. The mainline board with the same codec,
+		 *   rk3588-youyeetoo-yy3588.dts, does it the same way:
+		 *   assigned-clocks uses the internal segment for the rate, clocks
+		 *   uses the _TO_IO segment to drive the pin.
+		 */
+		clocks = <&cru I2S0_8CH_MCLKOUT_TO_IO>;
+		/* clock-names is mandatory. The complete driver gets the clock by
+		 *   name (es8323.c:618):
+		 *       es8323->mclk = devm_clk_get_optional(component->dev, "mclk");
+		 *   Without clock-names it gets NULL, so later in hw_params
+		 *       coeff = get_coeff(es8323->sysclk, rate)
+		 *   cannot derive the right MCLK/LRCK divider from the
+		 *   coefficient table, the codec is clocked wrongly and stays
+		 *   silent. The vendor 6.1 BSP dtb codec node also carries
+		 *   clock-names = "mclk"; both sides have to match.
+		 */
+		clock-names = "mclk";
+		assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
+		assigned-clock-rates = <12288000>;
+		AVDD-supply = <&vcc_3v3_s0>;
+		DVDD-supply = <&vcc_1v8_s0>;
+		HPVDD-supply = <&vcc_3v3_s0>;
+		PVDD-supply = <&vcc_3v3_s0>;
+		#sound-dai-cells = <0>;
+	};
+
+	/*
+	 * Camera (CAM3 connector, D-PHY0 path)
+	 *
+	 * Why CAM3: in mainline 6.18 rk3588-base.dtsi both CSI hosts are bound
+	 * to the D-PHYs:
+	 *     csi2 at fdd30000  phys = <&csi_dphy0>
+	 *     csi4 at fdd50000  phys = <&csi_dphy1>
+	 * while both DC-PHYs are bound to DSI only:
+	 *     dsi0 at fde20000  phys = <&mipidcphy0 PHY_TYPE_DPHY>
+	 *     dsi1 at fde30000  phys = <&mipidcphy1 PHY_TYPE_DPHY>
+	 *   => mainline has no DC-PHY to CSI path (no precedent in the tree,
+	 *      and no board connects a sensor to a DC-PHY)
+	 *   => the DC-PHY based CAM1/CAM2 connectors are unusable on 6.18; of
+	 *      the three connectors on this board only CAM3 uses D-PHY0.
+	 *
+	 * Wiring (from the vendor 6.1 dtb; GPIO numbers are linear, so
+	 * pin8 = PB0):
+	 *   CAM3 = i2c1(fea90000), reset = gpio1 PB4(ACTIVE_LOW),
+	 *          power = gpio1 PB5(ACTIVE_HIGH),
+	 *          MCLK pinctrl = mipim0_camera3_clk, DPHY = csi2_dphy0
+	 * Aligned with the vendor overlay for the same sensor:
+	 *   rk3588-rock-5b-plus-radxa-cam4k-cam0.dtso
+	 *   (IMX415 + csi_dphy0 + csi2 + vicap) -- its MCLK is also
+	 *   CLK_MIPI_CAMARAOUT_M3, matching this connector.
+	 */
+	imx415: camera-sensor at 1a {
+		compatible = "sony,imx415";
+		reg = <0x1a>;
+		clocks = <&cru CLK_MIPI_CAMARAOUT_M3>;
+		assigned-clocks = <&cru CLK_MIPI_CAMARAOUT_M3>;
+		assigned-clock-rates = <37125000>;
+		avdd-supply = <&cam_pwr>;
+		dvdd-supply = <&cam_pwr>;
+		ovdd-supply = <&cam_pwr>;
+		reset-gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&mipim0_camera3_clk>;
+
+		port {
+			imx415_out: endpoint {
+				data-lanes = <1 2 3 4>;
+				link-frequencies = /bits/ 64 <445500000>;
+				remote-endpoint = <&csi2_input>;
+			};
+		};
+	};
+};
+
+&i2s0_8ch {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s0_lrck &i2s0_mclk &i2s0_sclk &i2s0_sdi0 &i2s0_sdo0>;
+	status = "okay";
+};
+
+&pinctrl {
+	headphone {
+		hp_det: hp-det {
+			rockchip,pins = <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		hp_con: hp-con {
+			rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+/ {
+	analog_sound: analog-sound {
+		compatible = "simple-audio-card";
+		pinctrl-names = "default";
+		pinctrl-0 = <&hp_det &hp_con>;
+		simple-audio-card,name = "QuarkPi-CA2 ES8388";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,bitclock-master = <&sound_cpu>;
+		simple-audio-card,frame-master = <&sound_cpu>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,aux-devs = <&hp_amp>;
+		/* Vendor <0x13d 0x14 0x00>: flags = 0 => ACTIVE_HIGH (the on-board
+		 * detect circuit is active high). With ACTIVE_LOW a plugged
+		 * headset reads as unplugged, pin-switches stay open and there is
+		 * no output at all; gpio-20 reads high, so an active high level
+		 * means "plugged".
+		 */
+		simple-audio-card,hp-det-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>;
+		/*
+		 * The card level controls must be declared here first, otherwise
+		 *    the names used in routing do not exist (as in roc-pc: the
+		 *    first entry is the widget type, Headphone/Microphone, and the
+		 *    second one is the control name)
+		 */
+		simple-audio-card,pin-switches = "Headphones";
+		simple-audio-card,widgets =
+			"Headphone", "Headphones",
+			"Microphone", "Headset Mic",
+			"Microphone", "Main Mic";
+		simple-audio-card,routing =
+			/* The vendor BSP routing has two direct entries,
+			 *   "Headphone","LOUT1" and "Headphone","ROUT1"; they are
+			 *   added here so the jack still gets a signal from
+			 *   LOUT1/ROUT1 even if the amplifier or the switch fails.
+			 */
+			"Headphones", "LOUT1",
+			"Headphones", "ROUT1",
+			/* Vendor "Headphone Power" path (DAPM must power it) */
+			"Headphones", "Headphone Power OUTL",
+			"Headphones", "Headphone Power OUTR",
+			"Headphone Power INL", "LOUT1",
+			"Headphone Power INR", "ROUT1",
+			/* Fallback: wire LOUT2/ROUT2 as well. The vendor
+			 * reference board routes the speaker to that output
+			 * pair; this board has no speaker, so these two
+			 * entries recover the jack if it is actually wired
+			 * to route 2. */
+			"Headphone Power INL", "LOUT2",
+			"Headphone Power INR", "ROUT2",
+			"LINPUT1", "Headset Mic",
+			"LINPUT2", "Main Mic",
+			"RINPUT1", "Headset Mic",
+			"RINPUT2", "Main Mic";
+
+		sound_cpu: simple-audio-card,cpu {
+			sound-dai = <&i2s0_8ch>;
+		};
+
+		sound_codec: simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+	};
+
+	/* Headphone amplifier enable (vendor hp-con-gpio = gpio1 PC6) */
+	hp_amp: audio-amplifier-hp {
+		compatible = "simple-audio-amplifier";
+		/* Same name as the vendor BSP "Headphone Power" control: the
+		 *   amplifier is only powered when it appears in the DAPM routing;
+		 *   listing it in aux-devs alone is not enough (with aux-devs
+		 *   only, the amp INL/OUTL never got powered and the jack had no
+		 *   signal).
+		 */
+		sound-name-prefix = "Headphone Power";
+		/* hp-con selects the headphone path (plugging in a headset
+		 *   switches to it and stops the speaker). The vendor dtb flags = 0
+		 *   can mean the opposite in the private multicodecs driver, since
+		 *   it is not a standard enable-gpios.
+		 */
+		/* hp-con selects the headphone/speaker path (plugging in a
+		 *   headset switches to it and stops the speaker). The vendor BSP
+		 *   has hp-con-gpio = <&gpio1 22 0> with flags = 0, i.e.
+		 *   ACTIVE_HIGH. With ACTIVE_LOW, DAPM asserting the pin pulls it
+		 *   low, which the vendor hardware reads as "off", so audio is
+		 *   routed to the amplifier/speaker side and the jack stays silent
+		 *   (/sys/kernel/debug/gpio shows gpio-22 = out lo ACTIVE LOW
+		 *   while playing).
+		 */
+		enable-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/*
+ * Camera module power: fixed regulator controlled by gpio1 PB5 (the
+ * module carries its own LDO, so all three supplies share this 3.3V rail)
+ *
+ * WARNING: it has to live under the root node and must not be put inside
+ *    an i2c bus -- i2c child nodes all require a reg property, otherwise
+ *    dtc reports "missing or empty reg property".
+ *    The vendor overlay rk3588-rock-5b-plus-radxa-cam4k-cam0.dtso puts
+ *    the regulator under &{/} as well.
+ */
+&{/} {
+	cam_pwr: regulator-cam-pwren {
+		compatible = "regulator-fixed";
+		regulator-name = "cam_pwr";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		vin-supply = <&vcc_3v3_s3>;
+	};
+};
+
+/*
+ * Camera pipeline: sensor -> csi_dphy0 (D-PHY0) -> csi2 (host) -> vicap
+ *
+ * Every node and port already exists in mainline rk3588-base.dtsi, so
+ * they only have to be enabled and two endpoints added:
+ *   csi2 port at 0 = csi2_in (sensor input), port at 1 = csi2_out -> vicap_mipi2_input
+ * The structure matches the vendor overlay
+ * rk3588-rock-5b-plus-radxa-cam4k-cam0.dtso exactly.
+ *
+ * Kernel side needs no changes:
+ *   PHY_ROCKCHIP_INNO_CSIDPHY=y (built in, supports
+ *   rockchip,rk3588-csi-dphy), VIDEO_ROCKCHIP_CIF=m,
+ *   VIDEO_DW_MIPI_CSI2RX=m, VIDEO_IMX415=m
+ */
+&csi_dphy0 {
+	status = "okay";
+};
+
+&csi2 {
+	status = "okay";
+};
+
+&csi2_in {
+	csi2_input: endpoint {
+		bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
+		data-lanes = <1 2 3 4>;
+		link-frequencies = /bits/ 64 <445500000>;
+		remote-endpoint = <&imx415_out>;
+	};
+};
+
+&vicap {
+	status = "okay";
+};
+
+&vicap_mmu {
+	status = "okay";
+};
+
+/* ==========================================================================
+ * Multiplexed function pins of the 40-pin header (J11, marked RPI40pin
+ * compatible in the schematic)
+ *
+ * These controllers are disabled by default in rk3588-base.dtsi and were
+ * never enabled on this board, so those header pins could only be used as
+ * GPIOs. The schematic net names carry the mux suffix (_M1/_M2/_M3), so
+ * the matching mainline mux group can be selected directly. Group names
+ * and pins were checked one by one against rk3588-base-pinctrl.dtsi:
+ *    I2C3_M1 : gpio3-15(SCL) / gpio3-16(SDA)           => header pin5 / pin3
+ *    I2C5_M2 : gpio4-6(SCL)  / gpio4-7(SDA)            => header pin28/ pin27
+ *    UART5_M1: gpio3-20(TX)  / gpio3-21(RX)            => header pin8 / pin10
+ *    SPI0_M3 : gpio3-27(CLK)/gpio3-25(MISO)/gpio3-26(MOSI)
+ *              gpio3-28(CS0)/gpio3-29(CS1)             => header pin23/21/19/24/26
+ * WARNING: when referencing a group name, make sure the file is
+ *    rk3588-*-pinctrl.dtsi -- a wildcard grep also matches same-named
+ *    groups in rk3528/rk3576, whose pins are completely different.
+ * ========================================================================== */
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3m1_xfer>;
+	status = "okay";
+};
+
+/* WARNING: do not enable &i2c5 here (the i2c5m2_xfer group is gpio4-6/7):
+ *   1) in the vendor 6.1 tree i2c at fead0000 (i2c5) is status = "disabled"
+ *      and was never enabled;
+ *   2) gpio4-6 / gpio4-7 are the usbdp_phy0 sbu1-dc-gpios /
+ *      sbu2-dc-gpios (the SBU DC switch controls used by DP alt mode) in
+ *      the same vendor tree, so the two uses conflict physically;
+ *   3) in the J11 header pin table the net names of pin27/pin28 are
+ *      SDA0/SCL0 (I2C0), not i2c5m2 either.
+ *   => header pins of a multiplexed function must not be inferred from the
+ *      schematic labels; use measured values instead.
+ */
+
+&uart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart5m1_xfer>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0m3_pins>, <&spi0m3_cs0>, <&spi0m3_cs1>;
+	num-cs = <2>;
+	status = "okay";
+
+};
+
+/* ==========================================================================
+ * RGA3 2D acceleration -- rk3588-base.dtsi:1265/1287 already have
+ * rga at fdb60000 / rga at fdb70000 (compatible = "rockchip,rk3588-rga3") and
+ * the kernel config has CONFIG_VIDEO_ROCKCHIP_RGA=m, so only status has to
+ * be enabled here.
+ * ========================================================================== */
+&rga3_core0 {
+	status = "okay";
+};
+
+&rga3_core1 {
+	status = "okay";
+};
+
+/* ==========================================================================
+ * IR receiver
+ *
+ * Hardware path: the on-board IR receiver output drives net PWM_IR into
+ * SoC GPIO0_D4 (= gpio0-28); the vendor BSP uses it as PWM3_M0 (the
+ *    mainline pin group is even called `pwm3_ir_m0`).
+ *
+ * Why the GPIO route: mainline drivers/media/rc/ has pwm-ir-tx (transmit)
+ *    only and no PWM IR receive driver, and `rockchip,remotectl-pwm` is
+ *    vendor private, so use the mainline gpio-ir-recv instead: treat the
+ *    pin as a plain GPIO input, let the driver sample the pulse widths and
+ *    have rc-core decode NEC in software.
+ *
+ * Kernel side needs no changes: CONFIG_IR_GPIO_CIR=m,
+ * CONFIG_IR_NEC_DECODER=m, CONFIG_RC_CORE=y and CONFIG_RC_MAP=y are
+ * all set.
+ *   Note: the Kconfig symbol is IR_GPIO_CIR.
+ * The driver has its own of_device_id (compatible = "gpio-ir-receiver"), so
+ *   udev loads it automatically once this node exists; `modprobe
+ *   gpio-ir-recv` can be used by hand if needed.
+ * The remote key map is loaded from userspace: /etc/rc_keymaps +
+ *   ir-keytable (vendor map: usercode 0xFF00, 20 keys), so
+ *   linux,rc-map-name is not set here.
+ * ========================================================================== */
+&pinctrl {
+	/* WARNING: this must use the two-level "function node -> group node"
+	 *   structure. rockchip_pinctrl_parse_dt() calls parse_functions() for
+	 *   every child of pinctrl, and that walks the children of the child
+	 *   node as groups (see pinctrl-rockchip.c:4440). Writing groups "flat"
+	 *   below &pinctrl gives of_get_child_count() = 0, the groups are never
+	 *   registered and the kernel reports "unable to find group for node
+	 *   xxx" when a device requests them.
+	 *   The leds / usb-typec / sdmmc / headphone groups in this file all
+	 *   use this two-level form. */
+	ir {
+		ir_receiver_pin: ir-receiver-pin {
+			/* gpio0-28 = GPIO0_D4, GPIO function (0) with pull-up
+			 * (receiver outputs are usually open drain)
+			 */
+			rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
+
+/* MIPI DSI0 / DSI1 (2 ports): deliberately not enabled
+ * Enabling &dsi0/&dsi1/&mipidcphy0/&mipidcphy1 all at once, straight from
+ *   the vendor tree, makes HDMI stop working: the four nodes do come up
+ *   (rockchip,rk3588-mipi-dsi2 / mipi-dcphy), but the HDMI connectors in
+ *   /sys/class/drm/ drop from 1 to 0 and the sound cards from 2 to 1, with
+ *   dmesg reporting "platform hdmi0-sound: deferred probe pending:
+ *   asoc-simple-card: parse error": the RK3588S VOP2 video port (VP) is
+ *   taken over by DSI and HDMI0 loses its output.
+ * => do not enable DSI on a board without a display: it cannot be verified
+ *    and it breaks the working HDMI. Add the DSI nodes together with
+ *    panel/bridge nodes only once a display is available, and accept that
+ *    HDMI has to give way or the VP assignment has to change.
+ */
+
+&{/} {
+	ir_receiver: ir-receiver {
+		compatible = "gpio-ir-receiver";
+		/* The polarity must be ACTIVE_LOW: the IR receiver idles
+		 *   high and pulls low on a carrier, while rc-core wants
+		 *   the active level to be the pulse. The three mainline
+		 *   gpio-ir-receiver examples (rk3568-rock-3b /
+		 *   rk3328-roc-pc / rk3566-box-demo) all use
+		 *   GPIO_ACTIVE_LOW. */
+		gpios = <&gpio0 RK_PD4 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ir_receiver_pin>;
+	};
+};
+
+/* ==========================================================================
+ * DP output (DP alt mode on Type-C0)
+ *
+ * Evidence, all from the vendor 6.1 tree plus a mainline board of the same
+ * SoC:
+ *   1) vendor tree dp at fde50000 = status "okay", phys = <the dp-port of
+ *      &usbdp_phy0>;
+ *   2) vendor tree usbdp_phy0: dp-port = okay, sbu1-dc-gpios = gpio4-6,
+ *      sbu2-dc-gpios = gpio4-7;
+ *   3) DP uses video port vp1 (vendor tree vp1_out_dp0 =
+ *      /vop/ports/port at 1/endpoint at 0, and the mainline reference board
+ *      rk3588s-indiedroid-nova also uses vp1 -> dp0), which does not clash
+ *      with the vp0 used by HDMI0;
+ *   4) the mainline kernel config is complete: ROCKCHIP_DW_DP=y /
+ *      PHY_ROCKCHIP_USBDP=y / TYPEC=y / TYPEC_TCPCI=y.
+ *
+ * ========================================================================== */
+
+&dp0 {
+	status = "okay";
+};
+
+&dp0_in {
+	dp0_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_dp0>;
+	};
+};
+
+&dp0_out {
+	dp0_out_con: endpoint {
+		remote-endpoint = <&usbdp_phy0_dp_in>;
+	};
+};
+
+&vp1 {
+	vp1_out_dp0: endpoint at a {
+		reg = <ROCKCHIP_VOP2_EP_DP0>;
+		remote-endpoint = <&dp0_in_vp1>;
+	};
+};
+
+&usbdp_phy0 {
+	orientation-switch;
+	mode-switch;
+	/* Vendor tree values: SBU1/SBU2 DC switch controls = GPIO4_A6 / GPIO4_A7 */
+	sbu1-dc-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>;
+	sbu2-dc-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>;
+	rockchip,dp-lane-mux = <2 3>;
+	status = "okay";
+
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		usbdp_phy0_dp_in: endpoint at 2 {
+			reg = <2>;
+			remote-endpoint = <&dp0_out_con>;
+		};
+
+		usbdp_phy0_dp_out: endpoint at 3 {
+			reg = <3>;
+			remote-endpoint = <&usbc0_sbu>;
+		};
+	};
+};




More information about the Linux-rockchip mailing list