// SPDX-License-Identifier: GPL-2.0 OR MIT // LILYGO T-Display-K230. // // Derived from canaan/k230-canmv-v3-lcd.dts, which is the reference this // board is a variant of -- U-Boot on our hardware prints // "Model: kendryte k230 canmv v3.0". Every divergence from that reference // is marked DIVERGENCE below and listed in // docs/evidence/dts-divergence.md. // // UNVERIFIED: this has never been booted. /dts-v1/; #include "k230.dtsi" #include "display-rm69a10-568x1232.dtsi" / { model = "LILYGO T-Display-K230"; compatible = "lilygo,t-display-k230", "canaan,canmv-k230", "canaan,kendryte-k230"; aliases { serial3 = &uart3; // DIVERGENCE (naming only): on this board mmc0 carries the // RTL8189FTV over SDIO and mmc1 carries the TF card. The // reference names them the same way; recorded because // docs/findings.md originally had them swapped. mmc0 = &mmc_sd0; mmc1 = &mmc_sd1; i2c0 = &i2c4; i2c1 = &i2c3; }; chosen { // Linux console. Note U-Boot's own console is ttyS1 per the // SDK environment; the two legitimately differ. stdout-path = "serial0:115200n8"; }; ddr: memory@0 { device_type = "memory"; reg = <0x0 0x0 0x0 0x40000000>; }; // DIVERGENCE: stage 1 scans this XRGB buffer until Linux owns the panel. // The values come from nix/boot-splash.nix through device-tree.nix's // preprocessor definitions, shared with U-Boot's Kconfig fragment. reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; splash_framebuffer: framebuffer@K230_SPLASH_FRAMEBUFFER_UNIT_ADDRESS { reg = <0x0 K230_SPLASH_FRAMEBUFFER_ADDRESS 0x0 K230_SPLASH_FRAMEBUFFER_SIZE>; no-map; }; }; // PMU INT0 power key. The kernel input driver reports edges; userspace // decides short press vs. hold. Physical-key proof is still pending. soc { pmu_pwrkey: pmu-pwrkey@91000000 { compatible = "canaan,k230-pmu-pwrkey"; reg = <0x0 0x91000000 0x0 0xc00>, <0x0 0x91103000 0x0 0x1000>; reg-names = "pmu", "pwr"; interrupts = <175 IRQ_TYPE_LEVEL_HIGH>; wakeup-source; }; }; sound { status = "okay"; compatible = "canaan,k230-audio-inno"; canaan,model = "K230_I2S_INNO"; canaan,k230-i2s-controller = <&i2s>; canaan,k230-audio-codec = <&inno_codec>; // Deliberately absent: canaan,external-i2s-output-default. Leaving // it unset keeps this board booting through the Inno codec // (headphone/line-out) exactly as before; the external route below // is opt-in at runtime via the "External I2S Output Switch" ALSA // control (nix/patches/canaan-audio-external-i2s-switch.patch). }; }; // MAX98357A external I2S amplifier -- the-handheld-plays-through-its-speaker. // // LILYGO's own BSP (Xinyuan-LilyGO/T-Display-K230, // k230_bsp/docs/HARDWARE_PINMAP.md) places this part on the OPTIONAL // "nRF52840 BLE / Audio / Sensor" add-on board, not the main T-Display-K230 // board and not the nRF9151 keyboard base -- confirmed by that same file's // three-way board grouping and by CHANGELOG.MD listing it alongside the // nRF52840/nRF9151/LoRa presets under "Included Hardware Support". Whether // THIS board has that add-on attached is UNVERIFIED; nothing in this repo // has recorded one before this change. // // BCLK GPIO32 I2S bit clock, shared with the Inno codec's I2S output // LRCK GPIO33 I2S word-select, shared with the Inno codec's I2S output // DOUT GPIO35 I2S data, shared with the Inno codec's I2S output // SDMODE GPIO34 plain GPIO, high enables the amp, low shuts it down // // Grounding for all four: k230_bsp/docs/HARDWARE_PINMAP.md's "nRF52840 BLE / // Audio / Sensor Base Board" table, and // k230_bsp/overlay/buildroot-overlay/linux/0058-riscv-dts-rm69a10-add-audio-fan-sensor-pins.patch // (commit 6b5d4c3a, same repo). GPIO34 is a plain GPIO, not behind the // XL9555 expander -- that expander is documented in the same file under the // SEPARATE nRF9151 keyboard base, for its own LEDs and keyboard matrix only. // // UNVERIFIED: whether GPIO32/33/35 are actually muxed to their I2S // alternate function on THIS board. This SoC's FPIOA pin mux is set by // U-Boot, not by the Linux device tree -- there is no pinctrl driver // anywhere in the pinned kernel tree (see docs/dts-evidence.md, "There is // no pinctrl in the Linux device tree"), and LILYGO's own pinctrl-based // patch (0058, above) targets a pinctrl-k230 driver that patch series does // not otherwise add here and that this pinned tree does not carry. Setting // the ALSA route to "external" only tells the SAI peripheral to stop // feeding the Inno codec and drive these pads directly; it says nothing // about whether U-Boot already muxed them for I2S rather than plain GPIO. // See docs/evidence/max98357a-speaker.md. // // GPIO34 needs no device-tree node to be usable: it is a plain, // unclaimed line on the existing always-on gpio1_ports controller // (k230.dtsi:415-421), driven directly by libgpiod from userspace -- // exactly how LILYGO's own launcher does it (ui_hardware.c:1655-1731, // AMP_SHUTDOWN_GPIO 34). A "maxim,max98357a" ALSA codec DT node was // deliberately NOT added: that driver claims its sdmode-gpios exclusively // via devm_gpiod_get, which would conflict with a userspace helper toggling // the same line, and nothing here ever wires such a node into a dai-link // for its DAPM power sequencing to have anything to switch. Naming the pin // below is documentation only; it claims nothing. &gpio1_ports { gpio-line-names = "MAX98357A_I2S_BCLK", "MAX98357A_I2S_LRCK", "MAX98357A_SDMODE", "MAX98357A_I2S_DOUT"; }; &uart0 { status = "okay"; }; &uart3 { status = "okay"; }; // The TF card. &mmc_sd1 { status = "okay"; no-1-8-v; cap-sd-highspeed; mshc_ctrl_r = <0x00>; }; // The RTL8189FTV, over SDIO. &mmc_sd0 { status = "okay"; no-1-8-v; rx_delay_line = <0x0d>; tx_delay_line = <0xc0>; }; &usb0 { status = "okay"; }; &usb1 { status = "okay"; }; &i2c3 { status = "okay"; // DIVERGENCE: the reference fits an edt,edt-ft5306 at 0x38. This // board has a Goodix GT9895 at 0x5d -- a Berlin-generation part, // which the pinned 6.6 tree does not support. The driver arrives as // a backport in this change; without it this node simply does not // probe and the panel still works. // // The GPIOs are the same as the reference's touch controller: // RST on 24, INT on 23. Confirmed against the schematic. // // Two compatibles, most-specific first, which is how a fallback is // meant to be written. The part really is a GT9895, and that string // is what a driver gaining real GT9895 support would match on. But // the backported goodix_berlin matches ONLY "goodix,gt9916" -- // nix/patches/goodix-berlin/goodix_berlin_i2c.c:57 -- so with the // specific string alone nothing binds and the experiment task 4.1 // asks for cannot even run. The fallback lets the Berlin driver // attach while the device tree keeps telling the truth about the // silicon. // // It is close enough: the backport binds, reads the firmware version // and the IC-info blob without error, and derives touch_data_addr // from the part at runtime. See docs/evidence/gt9895-port.md. touchscreen@5d { compatible = "goodix,gt9895", "goodix,gt9916"; reg = <0x5d>; reset-gpios = <&gpio0_ports 24 GPIO_ACTIVE_LOW>; interrupt-parent = <&gpio0_ports>; // LEVEL_LOW, not EDGE_FALLING. // // EDGE_FALLING was inherited from the reference board's // edt-ft5306 (k230-canmv-v3-lcd.dts:66), a different part, // and it is why touch bound but reported nothing: four // interrupts on IRQ 87 since boot and then silence, with a // live controller answering i2c. A Goodix Berlin part holds // INT asserted low until the host clears the status byte at // touch_data_addr; goodix_berlin_irq() returns early WITHOUT // clearing whenever it reads status == 0 // (nix/patches/goodix-berlin/goodix_berlin_core.c:566), so // one such early return leaves the line low forever and an // edge detector never sees another falling edge. A level // detector re-asserts immediately and the handler clears it. // // caveman99/k230-linux runs this same backported driver on // this same 6.6.36 tree on this same board with // IRQ_TYPE_LEVEL_LOW and reports working multitouch; its // /proc/interrupts line reads "gpio-k230 23 Level // goodix-berlin" where ours reads "Edge". gpio-k230 supports // both (drivers/gpio/gpio-k230.c:333). interrupts = <23 IRQ_TYPE_LEVEL_LOW>; // The digitizer grid, not the panel. goodix_berlin declares // ABS_MT_POSITION_X/Y max = SZ_64K-1 and then lets // touchscreen_parse_properties() override it // (goodix_berlin_core.c:621-627); with nothing to read, every // touch lands in the top-left 1% of any client that scales by // the declared range. // // 1024 x 2400 has two independent sources: LILYGO's own // RT-Smart driver, which divides raw coordinates by exactly // these constants // (repo/canmv_k230/src/rtsmart/rtsmart/kernel/bsp/maix3/drivers/extdrv/touch/gt9895.c:44-45), // and caveman99's Linux port. The panel is 568x1232, so the // sensor grid is roughly 1.8x the pixel grid in both axes -- // same orientation, hence no swapped-x-y or inverted-* here. /* The controller reports X 0..1079: a finger at the * long edge hit raw 1079 on the second board * (docs/evidence/panel-landscape/touch-range.md), and * LILYGO's own tree gives panel-max-x 1060. 1024 lost * the last 5% of the glass past the panel edge. */ touchscreen-size-x = <1080>; touchscreen-size-y = <2400>; }; }; &i2c4 { status = "okay"; }; &mipi0 { // set to csi2 id = <2>; reg = <0x0 0x9000a800 0x0 0x800>; interrupts = <121 IRQ_TYPE_LEVEL_HIGH>; resets = <&sysctl_reset K230_RESET_CSI2_REG_OFFSET K230_RESET_CSI2_TYPE K230_RESET_CSI2_DONE_BIT K230_RESET_CSI2_ASSERT_BIT>, <&sysctl_reset K230_RESET_M2_REG_OFFSET K230_RESET_M2_TYPE K230_RESET_M2_DONE_BIT K230_RESET_M2_ASSERT_BIT>; }; // Reset and backlight for the panel. `lcd` is the label on the panel node // in display-rm69a10-568x1232.dtsi; the panel dtsi deliberately carries no // GPIOs of its own, matching how the reference splits panel from board. // // GPIO22 reset is ACTIVE_HIGH and GPIO25 is the backlight -- both taken // from k230-canmv-v3-lcd.dts, and both were unestablished before that. &lcd { dsi_reset-gpios = <&gpio0_ports 22 GPIO_ACTIVE_HIGH>; backlight_gpio-gpios = <&gpio0_ports 25 GPIO_ACTIVE_HIGH>; };