evidence · 24.8 KiB

mainline-kernel-inventory.md

Committed at docs/research/mainline-kernel-inventory.md. This is what grounds the requirements that cite it.

Open raw source

Mainline kernel inventory: what upstream Linux can drive on this board

Researched 2026-09-29 for openspec/changes/the-board-runs-a-mainline-kernel. Answers, per hardware function this board uses today (docs/research/board-capability-inventory.md), one additional question that document does not: can mainline Linux drive this at all, and if not, what is the exact blocking upstream state?

How to read this document

Same grounding tiers as .skills/k230-spec-change/SKILL.md and board-capability-inventory.md. Two additional evidence tools used specifically here, both checked directly on 2026-09-29 and cited by exact command:

Target version

kernel.org, 2026-09-25: latest stable is 7.2.8; latest longterm is 6.1.188. Neither carries any Canaan K230 support — checked directly: git show v7.2:arch/riscv/boot/dts/canaan/ lists only k210.dtsi, k210_generic.dts, canaan_kd233.dts and the four sipeed_maix_*.dts files; no k230.dtsi.

Basic K230 support (ARCH_CANAAN’s PINCTRL_K230, RESET_K230, COMMON_CLK_K230, and arch/riscv/boot/dts/canaan/k230.dtsi + k230-canmv.dts + k230-evb.dts) merged for the v7.3 merge window (“[GIT PULL] RISC-V devicetrees for v7.3”, July 2026; “too late for the 7.2 window” per the clock-driver pull thread). v7.3-rc1 released 2026-09-01; the current tip as of this research is v7.3-rc5 (72d3fcf802c45d00b300f25b848a93c3a2bd7c7e), with no stable v7.3 release yet. This change pins that commit — see nix/kernel-mainline-src.nix for exactly why (the newest tag that actually has K230 support, not an unreleased moving master).

What mainline’s k230.dtsi actually contains today

Fetched directly, raw.githubusercontent.com/torvalds/linux/master/arch/riscv/boot/dts/canaan/k230.dtsi: cpus (2× thead,c908 @ 1.6/0.8 GHz is NOT modeled — mainline’s dtsi describes only ONE cpu@0; see “Second C908 core” row), plic (canaan,k230-plic+thead,c900-plic), clint (ditto pattern), a reset controller (canaan,k230-rst), a pinctrl node (canaan,k230-pinctrl, no consumer groups defined anywhere upstream), a clock controller (canaan,k230-clk), and uart0–uart4 (snps,dw-apb-uart, all status = "disabled" by default). Nothing else. No mmc/sdhci, usb, i2c, spi, pwm, rtc, adc, watchdog, gpio, crypto, or thermal node exists in this file. k230-canmv.dts and k230-evb.dts each enable uart0 and add a board memory node; k230-canmv.dts additionally wires pinmux groups for uart2/uart3/uart4, PWM, I2S, I2C0/1/3/4, and an mmc1 SD slot pin group — but with no matching controller node in k230.dtsi for most of those buses yet, those pinmux groups currently mux pins for hardware nothing in this tree can drive.

Inventory

FunctionVendor driver (this project, nix/kernel.nix)Mainline statusPorting strategy
Serial console (UART0)snps,dw-apb-uart, mainline 8250 code alreadyPresent. k230.dtsi’s uart0 node is byte-identical in shape to the vendor tree’s; docs/research/board-capability-inventory.md already confirms our board’s console is UART0, and neither tree’s device tree programs UART0’s pinmux (both rely on U-Boot’s FPIOA table) — see nix/dts/k230-tdisplay-mainline.dts’s header for the full citation chain.Use upstream as-is. No patch needed; only a board .dts enabling it (nix/dts/k230-tdisplay-mainline.dts, this change).
SoC platform (PLIC/CLINT/reset/clock/pinctrl)Vendor tree’s own copies of the same IP blocksPresent, merged for v7.3: PINCTRL_K230 (drivers/pinctrl/canaan/pinctrl-k230-iomux.c), RESET_K230 (drivers/reset/reset-k230.c), COMMON_CLK_K230. All gate on ARCH_CANAAN.Use upstream as-is. nix/kernel-mainline.nix turns on all three.
Second C908 coreN/A — system/second-core-readiness, not attemptedNot modeled at all. Mainline’s k230.dtsi cpus node has exactly one cpu@0; there is no cpu@1 upstream to even describe the second hart, independent of whether Linux SMP release would be safe (see that capability’s own gating).Blocked upstream, not just on us — a future upstream patch would need to add the second hart’s CPU node before this project’s own SMP-safety gating even becomes relevant.
RM69A10 AMOLED panel (DSI)drivers/gpu/drm/panel/panel-canaan-universal.c, patchedUpstream driver still missing; local opt-in candidate host-builds. The pinned upstream source has no drivers/gpu/drm/panel/panel-canaan-universal.c and no drivers/gpu/drm/canaan/ directory (canaan_drv.c/canaan_vo.c/canaan_dsi.c/canaan_phy.c all absent). No K230 DSI/VO/DRM patch series was found in this research’s mailing-list searches. docs/research/linux-on-t-display-k230.md (2026-09-21) found three working Linux-on-this-panel projects, all forks of the vendor Xuantie tree. A separate local candidate in nix/kernel-mainline-drm.nix and nix/patches/mainline/drm/ has a successful complete kernel, matching DTB, and Image+DTB boot-files build; see docs/evidence/mainline-display-nix-build.md. No board boot, panel illumination, or touch behavior is proven.Candidate remains hardware-unverified. The pinned mainline source has no display power-domain provider; the opt-in DTS leaves that phandle out. The built profile does not change console-only or vendor defaults.
GT9895 touchnix/patches/goodix-berlin/ (v6.12 backport onto the vendor 6.6 tree)Present, unusually — already upstream on its own merits. gh api .../drivers/input/touchscreen/goodix_berlin_core.c → 200 (our own backport patch header already says this: “goodix_berlin, backported from v6.12”). But unusable without an I2C DT node, and no I2C controller node exists in mainline’s k230.dtsi at all yet.Driver needs no porting; the I2C bus DT plumbing does. Blocked on an upstream (or our own forward-ported) I2C controller node, not on touch itself.
GC2093 cameraMissing-driver (vendor tree too)Missing-driver, same as vendor. No CSI/ISP driver of any kind for this SoC anywhere; not investigated further here since the vendor-tree gap is already the binding constraint.Out of scope for both trees today.
HDMI (Lontium LT9611)CONFIG_DRM_LONTIUM_LT9611=y already, vendor treeBridge driver itself is generic upstream code (not Canaan-specific), but it is DSI-fed, so it inherits the same “no mainline DSI host” blocker as the panel row above.Blocked on the same DSI/VO gap as the panel.
Wi-Fi (RTL8189FTV, SDIO)8189fs.ko, vendor firmware blobPORTED (2026-10-06): mmc_sd0 SDIO enabled with owned clocks; the out-of-tree driver builds for 7.3 with nix/patches/mainline/rtl8189fs-mainline-v7.3-rc5.patch (API drift plus cfg80211_ops port) against CFG80211=m; on the board the SDIO card enumerates, 8189fs loads and wlan0 comes up. See docs/research/mainline-wifi-port.md.Association: task 6.2.
SD card / SDIO (SDHCI)Vendor board mmc_sd0/mmc_sd1 nodes, generic dw_mmc-adjacent pathPORTED (2026-09-29, milestone 1). Not the in-review v5 upstream series (still unmerged at v7.3-rc5) — the coordinator explicitly allowed either path, and the vendor’s own drivers/mmc/host/sdhci-of-kendryte.c (already a real, self-contained, sdhci-pltfm.c-layered driver matching our exact DT compatible string) was the lower-risk choice: one file, no new DT binding shape to invent. Forward-ported to nix/patches/mainline/sdhci-of-kendryte.c; needed one real API fix, sdhci_pltfm_free() (removed upstream entirely after this file’s 6.6-era origin — confirmed against mainline’s own sdhci-of-dwcmshc.c, whose probe/.remove call no equivalent). nix build .#kernelMainline confirms CONFIG_MMC_SDHCI_OF_DWCMSHC_KENDRYTE=y; &mmc_sd1 (the physical TF/SD card) is status = "okay" in nix/dts/k230-tdisplay-mainline.dts with real &sysclk/&rst phandles (UNVERIFIED clock-gate/reset-ID choice — see design.md). &mmc_sd0 (Wi-Fi SDIO) stays disabled; no Wi-Fi driver forward-ported in this pass.Ported; board-unverified.
USB (DWC2 ×2, host/gadget)CONFIG_USB_DWC2=y, vendor treePORTED (2026-09-29, milestone 1), via the vendor’s own dwc2_set_k230_params()/ctl-reg mechanism — deliberately NOT the separately-accepted phy-k230-usb.c/canaan,k230-usb-phy generic-PHY-framework driver already present upstream (design.md decision 7: the two are non-interoperating ways of driving the same HiSysConfig registers, and only the vendor’s mechanism has ever run on this board). Three small hunks ported into drivers/usb/dwc2/{params.c,core.h,core.c} via nix/kernel-mainline.nix’s postPatch (a usb_ctl field on struct dwc2_core_params, its HiSysConfig-register init in dwc2_phy_init(), and the "canaan,k230-otg" of_match_table entry that lets platform.c’s driver actually bind). No API migration needed here — confirmed by a clean build on the first attempt. usb0/usb1 are status = "okay" in the board DTS.Ported; board-unverified.
I2C (5×, snps,designware-i2c)fully mainline generic driver already, vendor treeDriver is fully mainline (drivers/i2c/busses/i2c-designware-platform.c is generic upstream code, unrelated to this SoC), but no I2C controller DT node exists in k230.dtsi at all. Not attempted in milestone 1 (scoped to boot-critical SD/GPIO/USB only).DT node porting needed, driver itself needs none. Blocks touch, and every I2C-bus sensor/PMIC row in board-capability-inventory.md.
SPI (3×, canaan,k230-spi)spi-dw-mmio.c + vendor init hook, vendor treeGeneric spi-dw-mmio.c is mainline, but no SPI controller node in k230.dtsi, and the vendor’s small dw_spi_canaan_k230_init() hook has no upstream equivalent found.DT node + a small init-hook port needed; not attempted here.
RTCdrivers/rtc/rtc-k230.c, patched (mday mask fix)PORTED (2026-09-29, after milestone 1). gh api .../drivers/rtc/rtc-k230.c → 404 upstream; forward-ported whole file to nix/patches/mainline/rtc-k230.c, carrying our own already-board-proven mday-mask fix forward (0xf → 0x1f) rather than reintroducing the bug freshly. One trivial fix needed: .remove_new (a transitional platform_driver field from the file’s 6.6-era origin) doesn’t exist at v7.3-rc5 — renamed to .remove (the function’s signature already matched). Built cleanly on the first attempt otherwise. rtc@91000c00 added to nix/dts/k230-tdisplay-mainline.dts (status = "okay", no clocks/resets — the driver calls neither devm_clk_get() nor devm_reset_control_get()).Ported; board-unverified.
Thermal sensordrivers/thermal/canaan_thermal.c, patched (bounded read loop)PORTED (2026-10-06, the-mainline-shell-reaches-parity): nix/patches/mainline/canaan_thermal.c, claims the temperature-sensor clock. On the board the mainline zone reads 7218 against the vendor kernel’s 7223 (same driver scale).Rise under load: task 7.2.
Power key (PMU INT0)drivers/input/misc/k230-pmu-pwrkey.c, vendored from LILYGOPORTED (2026-10-06): nix/patches/mainline/k230-pmu-pwrkey.c with a PMU DT node claiming the PMU APB gate; K230 PMU Power Key input registers on the board.Physical press: task 4.2.
Audio (I2S / MAX98357A route)sound/soc/canaan/canaan_k230_inno.c, patched (external I2S switch)PORTED (2026-10-06): SAI mux, Inno codec, machine driver and the vendor dwc_canaan I2S forward-ported (mainline’s generic dwc-i2s froze the SoC on playback); vendor k230_peridma forward-ported as the DMA provider, holding the shared-memory APB/AXI-slave/SRAM gates; the PCM registers before the DAI. Playback completes on the board with ordinary clock cleanup. See docs/research/mainline-audio-port.md.Audible tone: task 5.2.
Crypto (AES/hash/RSA/RNG/OTP)drivers/crypto/canaan/*, vendor tree, unpatchedNON-GOAL (recorded 2026-10-06): no shipped unit, package or tool uses the K230 crypto engine, hwrng or OTP; the kernel’s software crypto serves the system. Revisit if a consumer appears.—
GPIOdrivers/gpio/gpio-k230.c, vendor tree, unpatchedPORTED (2026-09-29, milestone 1). gh api .../drivers/gpio/gpio-k230.c → 404 upstream; forward-ported to nix/patches/mainline/gpio-k230.c. Needed a real, substantial API migration, found by a failed build (error: 'struct gpio_chip' has no member named 'bgpio_lock'): bgpio_init()/.read_reg/.write_reg/.bgpio_lock were replaced upstream by struct gpio_generic_chip (include/linux/gpio/generic.h) sometime after this file’s 6.6-era origin. Fixed against mainline’s own already-migrated gpio-dwapb.c (this file’s own stated template, “based on gpio-dwapb.c”) as the reference pattern — the port struct’s embedded struct gpio_chip gc became struct gpio_generic_chip chip, direct gc->bgpio_lock/.read_reg/.write_reg became to_gpio_generic_chip(gc)->lock/.read_reg/.write_reg, and bgpio_init() became gpio_generic_chip_init() against the same four MMIO addresses. gpio0/gpio1 are status = "okay" in nix/dts/k230-tdisplay-mainline.dts, still gating panel reset/touch reset-IRQ/Wi-Fi-enable functionally on their own controller/bus support landing first (unaffected by this row).Ported; board-unverified.
ADC / PWMk230-adc.c / (PWM controller, unnamed vendor file)NON-GOAL (recorded 2026-10-06): no shipped unit reads an IIO ADC channel or drives a PWM (the panel backlight is DSI DCS, not PWM). Revisit if battery sensing or a PWM peripheral is added.—
NPU/KPUClosed nncase runtime; thin kernel shim onlyNot investigated for mainline — the blocking constraint is the closed userspace runtime either way (docs/blob-inventory.md B1/B2), so mainline kernel-shim status does not change the conclusion.Out of scope.

Our eleven vendor-kernel patches, and which of them mainline needs

Every patch lives in nix/kernel.nix’s applyPatches/postPatch. Checked against the table above:

  1. riscv-vector-toolchain-probe.patch (Kconfig TOOLCHAIN_HAS_V missing the m extension in its -march probe string) — already fixed upstream. Fetched directly, raw.githubusercontent.com/torvalds/linux/master/arch/riscv/Kconfig: current mainline already reads -march=rv64imv/-march=rv32imv, exactly this patch’s fix. Does not need porting; nothing to apply it to.
  2. canaan-dsi-implement-dcs-read.patch — targets panel-canaan-universal.c. Cannot port: file does not exist upstream (missing-driver row above).
  3. canaan-panel-read-back-id-and-power-mode.patch — same file. Cannot port, same reason.
  4. canaan-audio-external-i2s-switch.patch — targets sound/soc/canaan/canaan_k230_inno.c. Cannot port: no such file or directory upstream.
  5. k230-rtc-mday-mask.patch — targets drivers/rtc/rtc-k230.c. Update, 2026-09-29: no longer “cannot port” — drivers/rtc/rtc-k230.c itself was forward-ported whole onto the mainline pin (see the RTC row above), carrying this exact fix forward directly in the copied file rather than as a separate patch against it (there being no separate upstream file this patch could apply to in the usual sense — the whole file is ours to place). Superseded, not stale: the original “cannot port” finding was correct at the time it was written (nothing existed to port a patch against); porting the driver itself is what changed.
  6. k230-pmu-pwrkey.c (a whole vendored driver, not a patch against an existing file) — cannot be ported as a patch since there is no upstream PMU infrastructure to patch; porting it would mean submitting the whole driver + DT binding, out of scope here.
  7. goodix-berlin backport — moot: mainline at this pin already has the real v6.12+ driver natively; forward-porting our backport would be backporting mainline onto itself. Nothing to do except add the I2C DT plumbing this row is actually blocked on.
  8. The panel-canaan-universal.c/canaan_drv.c/canaan_vo.c/ canaan_dsi.c/canaan_phy.c postPatch hunks (bounded PHY wait, DSI message transport, stage-1 splash handoff, PM-runtime pin, DT-settable hsfreqrange, DSI backlight, DPMS restore) — cannot port, any of them: none of these files exist upstream. This is the same conclusion as the panel row above, restated patch by patch so no partial-port is silently skipped.
  9. canaan_thermal.c’s bounded-read-loop fix — cannot port: file does not exist upstream.
  10. fbdev bpp sed (drm_fbdev_generic_setup(drm_dev, 32) → 16) — targets canaan_drv.c. Cannot port, same reason.

Net result at the time this section was first written: zero of our eleven vendor-kernel patches port to mainline as patches, because ten of them target a file that plainly does not exist upstream, and the eleventh (the toolchain probe) turns out to already be fixed upstream by a different, independent change. This was not a failure of porting effort; it was the direct, mechanical consequence of mainline having no display/audio/RTC/ power-key/thermal driver for this SoC at all yet.

Updated, 2026-09-29, after milestone 1: one of the ten — the RTC mday-mask fix — has since been ported, not as a patch against an upstream file (none existed), but by forward-porting drivers/rtc/rtc-k230.c itself onto the mainline pin and carrying the fix forward in the copied file (see the RTC row above and item 5’s updated entry). The other nine (display, audio, power-key, thermal) are unaffected — no upstream driver exists for any of them to patch or forward-port a fix against yet. This is exactly the pattern milestone 1’s GPIO/SD-MMC/USB forward-ports also followed: porting the whole driver, not just a patch, is what “porting” means once nothing upstream exists to patch.

Phased plan

Ordered so each milestone is provable before the next is attempted, per .skills/k230-spec-change/SKILL.md’s QEMU-vs-hardware distinction — every milestone below whose evidence is board console output is hardware-only; none of it is provable under QEMU, because QEMU’s k230 machine in this project models the vendor board, not a generic mainline-booted K230, and no upstream QEMU K230 machine model was confirmed working in this research (a QEMU-side “add SDHCI support for K230” series was found, implying machine support is itself still incomplete upstream).

  1. Cross-builds exist (DONE, this change): .#kernelMainline compiles, .#deviceTreeMainline compiles and round-trips, .#kernelMainlineBootFiles collects both under clear names. Host-only, proven by nix build.
  2. Reaches the serial console (hardware-gated, not performed): U-Boot loads this Image + DTB; the CH342 console shows the OpenSBI banner and Linux’s own early boot log over UART0, whether or not it then panics for lack of a root filesystem. This is the first milestone that needs the board, and is explicitly NOT performed by this change.
  3. Boot-critical GPIO/SD-MMC/USB forward-ported, and a matching full NixOS system variant (DONE, this change’s milestone-1 continuation): drivers/gpio/gpio-k230.c and drivers/mmc/host/sdhci-of-kendryte.c forward-ported from the vendor tree (one real API migration each found and fixed, see the GPIO and SD card/SDIO rows above); drivers/usb/ dwc2/{params.c,core.h,core.c} hunks ported cleanly (no migration needed). nixosConfigurations.k230-mainline-console is configured to boot this kernel; .#kernelMainlineConsoleBootFiles bakes its real bootargs and wraps its initrd. This remains host-proven (nix build); an actual SD-backed boot to a login prompt remains milestone 4’s hardware gate.
  4. Reaches an interactive shell over SD (hardware-gated, not performed): the milestone-3 candidate’s own pass condition — does k230-mainline-console’s boot files actually reach a login prompt over the physical card’s NIXOS_SD-labeled root partition. Genuinely open: whether &mmc_sd1 probes at all with this change’s best-effort clock/reset IDs, whether by-label root resolution works the same way under mainline as it does under the vendor kernel, and whether this system’s own closure/profile is even staged on that card (this change does not stage it). See tasks.md’s “Remaining evidence gate”.
  5. Wi-Fi (SDIO) + wider USB (network): &mmc_sd0 stays disabled and no RTL8189FTV driver was forward-ported in this pass (out-of-tree, and not expected to compile against this kernel unmodified — see design.md decision 9); a USB-Ethernet dongle or a forward-ported Wi-Fi driver would follow milestone 4, not before it.
  6. I2C/SPI DT plumbing: unblocks touch (driver already present, per the inventory row) and any future PMIC/sensor work, independent of display. Not attempted in milestone 1 (scoped to boot-critical SD/GPIO/USB only).
  7. RTC — PORTED (2026-09-29, first item of what was originally milestone 7): drivers/rtc/rtc-k230.c forward-ported whole, one trivial .remove_new→.remove fix, rtc@91000c00 added to the board DTS. Built cleanly on the first attempt — no API migration needed, unlike GPIO/ SD-MMC. Board-unverified, same as every row in this document.
  8. Display, audio, power key, thermal, crypto, ADC, PWM: each missing upstream drivers, with no in-progress public series found. The local DRM candidate is tracked separately from upstream mainline. Display was initially scoped without a port, then resumed in task group 5b of the OpenSpec change. The historical scratch trial copied the vendor’s canaan_drv.c/canaan_vo.c/canaan_dsi.c/canaan_phy.c/ canaan_plane.c plus panel-canaan-universal.c (about 3,900 lines, before project-specific patches) and exposed structural DRM API changes: drm_panel_init() had been replaced by devm_drm_panel_alloc(), along with Kconfig dependency and removed-symbol adjustments. That trial was discarded, then the coordinator authorized a separate opt-in derivation. The resumed source adapts the panel allocation, fbdev/client setup, atomic helper signatures, and platform remove callbacks. The prepared-header API check is an external-module build; it emits expected modpost warnings and is not an in-tree link proof (docs/evidence/mainline-display-api-compile.md). The first full kernel attempt reached the vmlinux link and exposed missing DRM_DISPLAY_HELPER/DRM_BRIDGE_CONNECTOR Kconfig selections; after adding them, the corrected object/config check and full Nix derivations succeeded (docs/evidence/mainline-display-nix-build.md). The separate opt-in DRM display/touch DT source and Image+DTB bundle now exist; host DTS, complete kernel/DTB/boot-files builds, and the Kconfig correction are recorded in docs/evidence/mainline-display-dtb.md and docs/evidence/mainline-display-nix-build.md. Physical probe remains open. The candidate omits the vendor display power domain because the pinned mainline tree has no provider for it. The other six (audio, power key, thermal, crypto, ADC, PWM) are individually much closer in size/shape to RTC (single small self-contained files) and are plausible next candidates for the same methodology. Not scheduled further in this pass; continue the RTC-style pattern for the smaller remaining drivers.

Sources