Device Tree Overlays
The device-tree configuration baked into the system image: config.txt snippets, the GPIO pin reservation table, and the validation steps that confirm a freshly-flashed SD has its peripherals wired up correctly. Read this if you are adding a new SPI / I2C / GPIO peripheral or if a peripheral is silently failing to enumerate.
system-image-build.md— thestage-kn86-firmwarestage where these overlays are installed.boot-and-systemd.md— the systemd units that wait on these overlays’ device nodes.coprocessor-firmware.md— the Pico-side counterpart to the UART overlay below.../hardware/build-specification.md— the physical wiring these overlays correspond to.../../adr/ADR-0017-realtime-io-coprocessor.md,../../adr/ADR-0018-custom-mechanical-keyboard-build.md,../../adr/ADR-0015-cipher-line-auxiliary-display.md.
What’s in /boot/config.txt
Section titled “What’s in /boot/config.txt”The KN-86 image ships with a config.txt derived from pi-gen’s Pi OS Lite default plus the project-specific overlays below. The full file lives in tools/sd-provision/pi-gen-stages/stage-kn86-firmware/files/boot/config.txt. The relevant additions:
# --- KN-86 device-tree overlays ---
# Primary display: HDMI to Elecrow 7" IPS @ 1024x600hdmi_force_hotplug=1hdmi_group=2hdmi_mode=87hdmi_cvt=1024 600 60 6 0 0 0disable_overscan=1
# UART0 to Pi Pico 2 coprocessor (ADR-0017)# GPIO14 = TXD0 -> Pico RX (GPIO1)# GPIO15 = RXD0 <- Pico TX (GPIO0)enable_uart=1dtoverlay=disable-bt # release UART0 from BT module to /dev/serial0init_uart_baud=1000000
# GPIO22 = Pico BOOTSEL control, GPIO23 = Pico RESET control (ADR-0017 §6)# Driven by the coprocessor daemon during firmware-update flow; reserved here.gpio=22=op,dhgpio=23=op,dh
# Audio — BENCH PHASE (GWP-698): Waveshare WM8960 Audio HAT, Pi-driven# I2S (GPIO18-21) + I2C1 codec config (GPIO2/3, addr 0x1a). Canonical# topology moves the whole chain to the Pico 2 (ADR-0017/ADR-0054), at# which point both lines go away. See "Pi-side audio" below.dtparam=i2c_arm=ondtoverlay=wm8960-soundcard
# SPI0 is FREE (post-ADR-0017). Pre-ADR-0017 the OLED was on Pi SPI0; the# OLED is now driven from the Pico's SPI bus. SPI0 is disabled here so any# kernel SPI driver doesn't claim the pins.dtparam=spi=off
# Hardware watchdog enable (GWP-352). The closed-lid Pelican kiosk has no# accessible reset button; the BCM2837 watchdog is the only hang-recovery# path. systemd consumes this via /etc/systemd/system.conf.d/10-kn86-watchdog.conf# (RuntimeWatchdogSec=15, RebootWatchdogSec=120). See# docs/device/os/boot-and-systemd.md "Hardware watchdog".dtparam=watchdog=on
# USB peripheral mode for the updater image (ADR-0011)# Used only by the kexec'd updater rootfs, not by the normal nOSh boot.# config.txt loads dwc2 with peripheral mode; cmdline.txt in the updater# bootfs slot carries `modules-load=dwc2,g_mass_storage`.dtoverlay=dwc2,dr_mode=peripheralconfig.txt lives on p1 (the common boot region per ../../adr/ADR-0011-device-firmware-update-system.md). Each bootfs slot (p2, p3) carries its own cmdline.txt. Slot-shared firmware-level config goes in config.txt; slot-specific kernel command-line lives in the per-slot cmdline.txt.
Overlay-by-overlay notes
Section titled “Overlay-by-overlay notes”UART0 to the Pico 2 (ADR-0017)
Section titled “UART0 to the Pico 2 (ADR-0017)”enable_uart=1dtoverlay=disable-btinit_uart_baud=1000000dtoverlay=disable-bt re-routes the BCM43438 Bluetooth module off UART0 onto the lower-quality mini-uart (UART1). UART0 (PL011) is the full-feature UART with hardware flow control and stable timing — exactly what the 1 Mbps Pi↔Pico link requires. Bluetooth is unused on the KN-86, so this trade is free.
After boot, /dev/serial0 is a symlink to /dev/ttyAMA0. The coprocessor daemon (boot-and-systemd.md) opens /dev/serial0 at 1,000,000 baud, 8N1, and runs the §5.3 bootstrap from coprocessor-protocol.md.
USB hub topology (ADR-0018)
Section titled “USB hub topology (ADR-0018)”The Pi Zero 2 W’s OTG port fans out through an internal USB 2.0 hub IC (TUSB2036, FE1.1s, or equivalent — exact part TBD per ADR-0018 KBD-03) to two downstream devices: the QMK-compatible keyboard controller, and the USB-to-SD card reader bridge IC for cartridges (ADR-0019). This is not a device-tree-overlay matter on the Pi side — USB hubs and USB-MSC bridges are class-compliant and surface through the kernel’s standard USB stack with no DTB hint required. The only Pi-side config.txt interaction is dtoverlay=dwc2,dr_mode=peripheral for the updater image’s USB-MSC mode (above); the host-mode that the normal boot uses is the default and does not need an explicit overlay.
Keyboard enumeration appears as /dev/input/event* once the udev pipeline settles. Cartridge insertion appears as a /dev/sd* block device subscribed by the udev rule shipped in stage-kn86-runtime (boot-and-systemd.md, ../../software/runtime/cartridge-lifecycle.md).
Stable USB device names (GWP-355): the udev rule
/etc/udev/rules.d/90-kn86-usb.rules (also shipped in stage-kn86-runtime)
maps the keyboard and the cart-MSC bridge to /dev/kn86-keyboard and
/dev/kn86-cart respectively, so nOSh and the cartridge-mount path unit
do not depend on hub-port enumeration order. The keyboard rule matches
on idVendor=239a (Adafruit) — the QMK firmware’s idProduct is TBD
pending the descriptor pin per ADR-0024
F2. The cart-bridge rule matches on the USB-MSC interface class
(08:06:50) instead of VID/PID, which is durable across the candidate
bridge IC families in ADR-0019
§Open Questions §1. Both VID/PID matches will be tightened in the same
PR that pins the bring-up choices.
Pi-side audio: bench-phase WM8960 HAT overlay (GWP-698, amends GWP-358)
Section titled “Pi-side audio: bench-phase WM8960 HAT overlay (GWP-698, amends GWP-358)”Bench phase (current): the Waveshare WM8960 Audio HAT sits on the Pi’s
40-pin header, and the Pi drives it directly — dtoverlay=wm8960-soundcard
(the in-tree simple-audio-card overlay; no vendor DKMS module) plus
dtparam=i2c_arm=on for the codec’s register config (I2C1, addr 0x1a).
This validates the ADR-0054 codec in HAT form ahead of the Pico wiring.
Three things have to agree or the card sits in deferred probe
(asoc-simple-card: parse error, observed on deckline 2026-07-08):
- The overlay + I2C lines in
config.txt(this doc’s listing above). snd_soc_bcm2835_i2snot blacklisted — GWP-698 amends the GWP-358 blacklist (/etc/modprobe.d/kn86-blacklist.conf) to allow the Pi I2S DAI to autoload;snd_bcm2835(legacy PWM/HDMI ALSA) stays blocked.- ALSA default routing by card name in
/etc/asound.conf(hw:wm8960soundcard) —vc4-hdmienumerates first and owns card 0, so anything defaulting by index plays out the HDMI panel instead.
The audio-wm8960 converge role delivers 3 and the codec mixer state
(DAC → output-mixer routing, which powers up disconnected, i.e. silent).
Canonical topology (end state): audio is owned end-to-end by the Pico
2 coprocessor (YM2149 PSG → I2S → WM8960 codec, ADR-0017/ADR-0054); the
Pi never produces a sample. When the chain moves to the Pico, the overlay
lines, /etc/asound.conf, and the audio-wm8960 role are removed
together and the snd_soc_bcm2835_i2s blacklist returns.
SSD1322 OLED — Pi side has no overlay (ADR-0015 + ADR-0017)
Section titled “SSD1322 OLED — Pi side has no overlay (ADR-0015 + ADR-0017)”Pre-ADR-0017, the SSD1322 CIPHER-LINE OLED was driven from Pi SPI0 with a dtoverlay=spi0-2cs plus a custom SSD1322 driver. That entire path is obsolete. The OLED is now driven from the Pico 2’s SPI bus, commanded by the Pi over UART using OLED frame types from coprocessor-protocol.md §4.
Concretely on the Pi:
dtparam=spi=offis set inconfig.txtso Linux does not claim SPI0/SPI1.- No SSD1322 driver is shipped in the kernel module set; the OLED never appears as a Linux character device.
- The Pico-side SPI pin assignment to the SSD1322 is finalised at the Pico firmware F2 bring-up (
coprocessor-firmware.md) and is not visible to Linux at all.
If a future hardware revision moves the OLED back to the Pi, the original Pi-side overlay would re-enter — but that is not in scope under ADR-0017 + ADR-0019.
GPIO pin reservation table
Section titled “GPIO pin reservation table”The Pi Zero 2 W has 26 usable GPIO pins on the 40-pin header. The KN-86 v1 claims a small subset; the rest are explicitly unclaimed to leave headroom for future peripherals.
| Pin (BCM) | Header | Claimed by | Function |
|---|---|---|---|
| GPIO 14 | pin 8 | UART0 (this doc) | TXD0 → Pico GPIO1 (RX) |
| GPIO 15 | pin 10 | UART0 (this doc) | RXD0 ← Pico GPIO0 (TX) |
| GPIO 22 | pin 15 | Coprocessor daemon (ADR-0017 §6) | Pico BOOTSEL control. TBD pending bring-up — see ADR-0017 KU#9 if a conflict surfaces. |
| GPIO 23 | pin 16 | Coprocessor daemon (ADR-0017 §6) | Pico RESET control. TBD pending bring-up — see ADR-0017 KU#9. |
| GPIO 2 / 3 | pin 3 / 5 | WM8960 HAT I2C1 (GWP-698, bench phase) | Codec register config, addr 0x1a. Frees back up when audio moves to the Pico per ADR-0054; the battery fuel gauge candidate can share the bus meanwhile (I2C is multi-drop). |
| GPIO 7–11 | pin 24/26/19/21/23 | (free — reserved SPI0) | Available; not claimed because OLED moved to Pico per ADR-0017. |
| GPIO 18–21 | pin 12 / 35 / 38 / 40 | WM8960 HAT I2S (GWP-698, bench phase) | BCLK / LRCLK / ADC / DAC. Frees back up when audio moves to the Pico per ADR-0017/ADR-0054. |
| All others | — | (free) | No project claim. |
Conflict-avoidance rule: any new peripheral that wants a GPIO must update this table in the same PR that lands the overlay change, and must not collide with an existing claim. canonical-spec.md Spec Hygiene Rule 3 applies — the table is the source of truth, not a hint.
Validation
Section titled “Validation”After flashing a fresh SD and first-boot, run these from an SSH session in dev mode (or from the bench-rig serial console — see ../hardware/build-specification.md §5):
# 1. Confirm UART0 is live and routed to /dev/serial0:ls -l /dev/serial0# expected: lrwxrwxrwx /dev/serial0 -> ttyAMA0
# 2. Confirm the BT module is OFF UART0:dmesg | grep -i bluetooth# expected: nothing on the PL011, "Bluetooth: disabled" or "no UART"
# 3. Confirm GPIO claims match the table above:raspi-gpio get# Spot-check rows for GPIO 14, 15, 22, 23 — should show the assignments above.# GPIO 7-11 and 18/19/21 should be inputs (free).
# 4. Confirm SPI is OFF:ls /dev/spidev* 2>/dev/null && echo "SPI is ON (BAD)" || echo "SPI is OFF (good)"
# 5. Confirm the USB hub + downstream devices enumerated:lsusb -t# Expected tree: Pi root hub -> internal hub IC -> {keyboard controller, SD card reader bridge}# (Cartridge bridge appears even with no SD inserted; the SD card itself appears under it on insertion.)
# 6. Confirm the keyboard:ls /dev/input/by-id/ | grep -i kn86# expected: a /dev/input/by-id/usb-KN86_*-event-kbd symlinkIf any of these fail, the most likely cause is a stale config.txt — verify the file on p1 matches stage-kn86-firmware/files/boot/config.txt from the source tree. If the file is correct and the validation still fails, the overlay snippet may be syntactically valid but blocked by a Pi firmware version mismatch (see system-image-build.md “Base Debian release pinning”) — capture /boot/config.txt, dmesg | head -100, and vcgencmd version, and escalate.