// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * WardenOS 86-Panel board DT for the self-built Linux 6.18 forward-port. * * Includes the full vendor rv1106.dtsi (SoC nodes + pinctrl + gpio + dmac), then * enables only what our wall-HMI needs — no camera/ISP/CSI. Grows one driver * batch at a time toward full parity with the 5.10 kernel (DRIVER-PARITY.md). */ /dts-v1/; #include #include "rv1106.dtsi" / { model = "WardenOS 86-Panel (RV1106)"; compatible = "rockchip,rv1106-warden", "rockchip,rv1106"; chosen { stdout-path = "serial2:115200n8"; bootargs = "earlycon=uart8250,mmio32,0xff4c0000 console=ttyS2,115200n8 earlyprintk rootwait"; }; memory@0 { device_type = "memory"; reg = <0x00000000 0x10000000>; /* 256 MiB */ }; /* --- M5: AIC8800DC wifi/BT power sequencing --- */ sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; pinctrl-names = "default"; reset-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>; }; /* SARADC voltage reference (1.8V) — the driver reads this for scale; without it saradc probes -22 (regulator_get_voltage on the dummy). */ vcc_1v8: vcc-1v8 { compatible = "regulator-fixed"; regulator-name = "vcc_1v8"; regulator-always-on; regulator-boot-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; }; /* --- console --- */ &uart2 { status = "okay"; }; /* --- eMMC rootfs (M3) --- */ &emmc { bus-width = <8>; cap-mmc-highspeed; mmc-hs200-1_8v; non-removable; status = "okay"; }; /* --- M5: AIC8800DC wifi/BT SDIO (on &sdmmc, mmc@ffaa0000 — NOT &sdio) --- */ &sdmmc { max-frequency = <50000000>; bus-width = <4>; cap-sd-highspeed; cap-sdio-irq; keep-power-in-suspend; non-removable; rockchip,default-sample-phase = <90>; supports-sdio; mmc-pwrseq = <&sdio_pwrseq>; pinctrl-names = "default"; pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_bus4 &sdmmc0_det>; status = "okay"; }; /* --- batch 1: mainline peripherals (wire DT + config) --- */ &uart1 { status = "okay"; }; &uart4 { status = "okay"; }; /* --- GT911 capacitive touch on i2c3 (86-Panel HMI) --- * The stock rootfs ships a goodix.ko built for the 5.10 kernel; it cannot load * on our 6.18 (`struct module` size mismatch) so touch was dead on _b. Build * CONFIG_TOUCHSCREEN_GOODIX=y instead (in the config fragment) and describe the * GT911 here, matching the vendor 86-panel wiring: addr 0x14, IRQ GPIO0_A0 * (edge-falling), reset GPIO3_D0 (active-low). reset-gpios + irq-gpios let the * mainline goodix driver run the GT911 power-on/address-select sequence. */ &i2c3 { status = "okay"; clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&i2c3m2_xfer &tp_rst &tp_irq>; touchscreen@14 { compatible = "goodix,gt911"; reg = <0x14>; interrupt-parent = <&gpio0>; interrupts = ; irq-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio3 RK_PD0 GPIO_ACTIVE_HIGH>; }; }; &pinctrl { touch { tp_rst: tp-rst { rockchip,pins = <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; }; tp_irq: tp-irq { rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; }; }; }; &saradc { vref-supply = <&vcc_1v8>; status = "okay"; }; &wdt { status = "okay"; }; /* --- M4: display (VOP + RGB → 720x720 panel + PWM backlight) --- */ &display_subsystem { status = "okay"; }; &vop { status = "okay"; /* mainline rockchip_drm_vop requests named "ahb" + "dclk" resets that the * vendor node omits; without them vop_bind fails "failed to get ahb reset". */ resets = <&cru SRST_H_VOP>, <&cru SRST_D_VOP>; reset-names = "ahb", "dclk"; /* * The 18-bit parallel RGB output (lcd_clk + lcd_d0..d17 + den/hsync/vsync, * 22 pins) must be muxed to the VOP's LCDC function or NO pixel data reaches * the panel -> backlit-black even with a fully healthy DRM pipeline. The * vendor board carried this mux as pinctrl-0 = <&lcd_pins> ON THE &rgb node; * we deleted &rgb (dangling-endpoint graph cycle), which silently dropped it. * Re-attach it here: the driver core auto-applies the "default" pinctrl state * when the VOP probes, exactly like the pwm1 backlight pin. Same root cause * as the dark backlight -- an unmuxed output pin group. */ pinctrl-names = "default"; pinctrl-0 = <&lcd_pins>; }; /* mainline wires vop_out straight to the panel (no separate rgb node) */ &vop_out_rgb { remote-endpoint = <&panel_in_vop>; }; &pwm1 { status = "okay"; /* mainline pwm-rockchip does NOT pinctrl_select_state("active") the way * the vendor 5.10 driver did; it relies on the pinctrl core auto-applying * the "default" state at probe. With "active" the pin never gets muxed to * PWM, so the backlight stays dark. Use "default". */ pinctrl-names = "default"; pinctrl-0 = <&pwm1m2_pins>; }; /* * NOTE on the RGB panel init MCU (WCH CH32V003, U6, net RGB_RES = GPIO0_A1): * the panel controller is configured by that MCU's SPI init sequence, released * once by U-Boot board_init() (stock boot). The WardenOS *userspace* (identical * rootfs on _a and _b) also drives GPIO0_A1 as part of the panel bring-up, and * on stock 5.10 (_a) the panel comes up fine that way. A kernel gpio-hog here * FIGHTS that userspace management (two owners on the same line) and left the * panel black on _b, so it is deliberately NOT hogged — matching _a, where only * userspace touches the line. */ / { backlight: backlight { compatible = "pwm-backlight"; pwms = <&pwm1 0 100000 50000>; brightness-levels = <0 32 64 96 128 160 192 224 255>; default-brightness-level = <8>; status = "okay"; }; panel: panel { compatible = "panel-dpi"; backlight = <&backlight>; /* the 86-Panel is an 18-bit parallel RGB (RGB666) panel; without a * bus-format the RGB output width is unset and the screen stays * black. Read by our panel-dpi patch (upstream ignores it). */ bus-format = ; /* * Deliberately NO reset-gpios / reset-delay-ms on this node. * RGB_RES (GPIO0_A1) resets the CH32V003 init MCU, which is * released exactly once, early, by U-Boot board_init() (shared * across A/B slots) so the MCU SPI-inits the NV3052 panel * controller before Linux. Handing reset-gpios to panel-simple * makes drm_panel_prepare() REBOOT the MCU while the VOP is * scanning out -- Luckfox deleted these two properties upstream * for exactly this reason (commit e2b0ffa22), and the flare-edge * 5.10 board DTS documents them as "the fix", not a regression. * Verified black-screen root cause was the VOP dclk polarity, not * this line (see rockchip_drm_vop.c rgb_dclk_pol). backlight stays * (U-Boot rockchip_panel.c reads its handle from this node). */ width-mm = <85>; height-mm = <85>; panel-timing { clock-frequency = <30000000>; hactive = <720>; vactive = <720>; hback-porch = <44>; hfront-porch = <46>; vback-porch = <18>; vfront-porch = <16>; hsync-len = <2>; vsync-len = <2>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <0>; }; port { panel_in_vop: endpoint { remote-endpoint = <&vop_out_rgb>; }; }; }; }; /* The vendor rgb bridge node has no 6.18 driver and its dangling endpoint * (rgb_in_vop -> vop_out_rgb) leaves a stray graph link that fw_devlink reads * as a vop<->panel dependency cycle, so the VOP probes before the panel and the * RGB connector is never created. DELETE it outright (disabling still left the * endpoint in the graph) so vop_out_rgb <-> panel_in_vop is the only link. */ /delete-node/ &rgb; /* --- sweep: USB OTG (eth0 gadget / host) via the ported inno-usb2 phy --- */ &u2phy { status = "okay"; }; &u2phy_otg { status = "okay"; }; &usbdrd { status = "okay"; }; &usbdrd_dwc3 { status = "okay"; dr_mode = "otg"; /* NO extcon, deliberately (tried 2026-09-01, reverted same day): our * bench/router panels self-source VBUS on this port (D1 mod), so the * phy's bvalid is always high and extcon pins the role to peripheral -- * the plugged USB NIC then never enumerates and debugfs "mode" writes * are overridden. Without extcon, otg defaults to host and the role is * switched at runtime per device role (router=host, client=gadget) via * /sys/kernel/debug/usb/ffb00000.usb/mode -- S26usbhost's 6.18 path. */ }; /* --- sweep: RTC + thermal (tsadc) + I2S audio DAI --- */ &rtc { status = "okay"; }; &tsadc { status = "okay"; }; &i2s0_8ch { status = "okay"; }; &rga2 { status = "okay"; }; /* --- batch A: hardware RNG (trngv1, same IP as rk3588) --- */ &rng { compatible = "rockchip,rv1106-rng"; status = "okay"; }; /* --- batch A: OTP / nvmem (chip id, MAC, PHY bandgap for GMAC) --- */ &otp { status = "okay"; }; /* --- GMAC: wired 10/100 ethernet via the on-die RMII FEPHY --- */ &gmac { status = "okay"; }; /* --- audio: i2s0_8ch (DAI) -> acodec (analog codec) -> speaker/headphone, * tied together by a simple-audio-card. Matches the vendor 86-Panel wiring * in rv1106-luckfox-pico-86panel-ipc.dtsi. The digital speaker modulator * (dsm) driver is ported and builds, but is left disabled here: the panel * uses the acodec path only, and the vendor board itself ships dsm * disabled. --- */ &acodec { #sound-dai-cells = <0>; status = "okay"; }; &dsm { status = "disabled"; }; / { acodec_sound: acodec-sound { compatible = "simple-audio-card"; simple-audio-card,name = "rv1106-acodec"; simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <256>; simple-audio-card,cpu { sound-dai = <&i2s0_8ch>; }; simple-audio-card,codec { sound-dai = <&acodec>; }; }; }; /* --- HPMCU mailbox (A7 <-> RISC-V SCR1). Controller binds via the rk3368 * fallback compatible with zero driver patch; @ff5c0000 is the HPMCU-connected * instance (SRST_CORE_MCU on the Linux side, MBOX_BASE 0xFF5C0000 on the MCU * side). M-MBOX-1 proves the controller; M-MBOX-2 adds the SCR1 echo + round-trip. */ &mailbox { status = "okay"; }; /* --- NPU (rknpu, ff660000). Kernel driver ported from the vendor 5.10 BSP * (GPL source port -- see warden-sdk/kernel/rv1106-enablement/npu/PORT-PLAN.md * and PORT-PROGRESS.md). compatible/reg/interrupts/clocks/resets are already * fully specified in rv1106.dtsi's rv1106_rknpu_config-matching npu node -- * this is only the status flip, same pattern as every other block enabled * in this file. No iommus= property (this board's NPU runs non-iommu, * matching the 5.10 boot-log finding), no power-domains (single-rail). */ &npu { /* the rknpu driver requests its IRQ by name ("npu_irq"); the base dtsi * node declares the interrupt but no interrupt-names, so probe fails * "IRQ npu_irq not found" without this. */ interrupt-names = "npu_irq"; status = "okay"; };