[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