diff --git a/Makefile b/Makefile
index c8ac179..de7e630 100644
--- a/Makefile
+++ b/Makefile
@@ -124,8 +124,7 @@ patches-overlay:
else \
echo "Overlay Go $$GO_VER — skipping Go toolchain patch (CVEs fixed upstream)"; \
fi && \
- git am "$(PATCHES_DIRECTORY)/talos-rpi5/sbc-raspberrypi5/0002-"*.patch && \
- git am "$(PATCHES_DIRECTORY)/talos-rpi5/sbc-raspberrypi5/0003-"*.patch
+ git am "$(PATCHES_DIRECTORY)/talos-rpi5/sbc-raspberrypi5/0002-"*.patch
patches: patches-pkgs patches-talos patches-overlay
diff --git a/README.md b/README.md
index 0b6a891..40875a7 100644
--- a/README.md
+++ b/README.md
@@ -61,13 +61,49 @@ In-place upgrades are fully supported. The image includes patches to force GRUB
- Fallback to classic bind mounts on kernels without `open_tree` support (Linux <6.15)
- Overclock: 2.6GHz (`arm_freq=2600`, `over_voltage_delta=50000`, `arm_boost=1`)
- PCIe Gen 3 enabled for NVMe (~800 MB/s, via `dtparam=pciex1_gen=3` in `config.txt`)
+- Serial console on GPIO UART0 (`dtoverlay=uart0-pi5`, 115200 baud, even parity)
- Extensions: `iscsi-tools`, `util-linux-tools`
## Known issues
-### ~~No serial console output after boot~~ (Fixed)
+### Serial console (read-only)
-The overlay was using `console=ttyAMA0` (GPIO 14/15 UART) but the RPi5/CM5 debug UART is `ttyAMA10`. Fixed by switching to `console=ttyAMA10,115200` and adding `earlycon=pl011,0x107d001000,115200n8` for early boot output. Also added `[pi5] enable_uart=0` to `config.txt` to match upstream and avoid U-Boot compatibility issues.
+The serial console outputs kernel logs, boot messages, and panic traces over GPIO UART0 (`ttyAMA0`) at 115200 baud with **even parity**. Talos Linux has no interactive shell — the console is **read-only** and cannot accept input.
+
+On Pi5/CM5, GPIO 14/15 are not mapped to UART by default (unlike Pi4). The `dtoverlay=uart0-pi5` device tree overlay is required and is applied via `configTxtAppend` (after `disable-bt` and `disable-wifi` — ordering matters).
+
+#### Wiring (Compute Blade)
+
+Connect a **3.3V** USB-to-UART adapter to the front UART header (3-pin: GND, RX, TX). Only two wires are needed for read-only monitoring:
+
+```
+ USB-UART Adapter Compute Blade (Front UART)
+ ┌──────────────┐ ┌──────────────┐
+ │ GND ├──────────┤ GND │
+ │ RX ├──────────┤ TX │
+ │ TX │ │ RX │
+ └──────────────┘ └──────────────┘
+ 3.3V logic 3.3V GPIO
+```
+
+- **Adapter RX** connects to **Blade TX** (adapter receives data from the blade)
+- **GND** to **GND** (common ground reference)
+- Adapter TX is not needed for read-only monitoring (Talos has no shell to send input to)
+
+> **Warning:** CM5 GPIO is **3.3V only**. A 5V logic adapter will crash or damage the board.
+
+Tested with: [USB to TTL Serial Cable (FT232RNL)](https://www.pishop.ca/product/usb-to-ttl-serial-cable-for-raspberry-pi-5-debugging-ft232rnl-chip/) set to 3.3V mode.
+
+#### Reading the console
+
+```bash
+# macOS — use screen with even parity
+screen /dev/cu.usbserial-XXXXXXXX 115200,,cse
+
+# Linux — configure with stty, then read with cat
+stty -F /dev/ttyUSB0 115200 cs8 parenb -parodd
+cat /dev/ttyUSB0
+```
*Upstream: talos-builder#4*
@@ -88,8 +124,7 @@ Talos ignores the `machine.install.disk` config field on SBC platforms. You **mu
| `0004` (talos) | Runtime | Fallback to classic bind mounts on kernels without `open_tree` (Linux <6.15) |
| `0005` (talos) | GRUB | Handle missing BOOT partition for SBC EFI-only disk layouts |
| `0001` (overlay) | Toolchain | Bump Go to 1.24.13 (CVE fix) |
-| `0002` (overlay) | Console | Fix serial console for RPi5/CM5 debug UART (`ttyAMA10`) |
-| `0003` (overlay) | Upgrade | Detect EFI mount path for SBC layouts (no BOOT partition) |
+| `0002` (overlay) | Upgrade | Detect EFI mount path for SBC layouts (no BOOT partition) |
## Roadmap
@@ -100,7 +135,7 @@ This project targets production-ready Talos clusters on RPi5/CM5 hardware.
| Tested | **4K page size** | Aligned with upstream Talos kernel config. Reduces memory overhead and improves workload compatibility (Longhorn, jemalloc, F2FS, etc.). |
| Tested | **Reliable in-place upgrades** | Force GRUB bootloader with `--no-nvram` on arm64, handle SBC EFI-only disk layout. Verified end-to-end with `talosctl upgrade`. |
| Tested | **Kernel <6.15 compatibility** | Unconditional `open_tree` capability check — falls back to classic bind mounts on RPi downstream kernel 6.12.x. |
-| Untested | **Serial console fix** | Use correct debug UART (`ttyAMA10`) with `earlycon` for early boot output. |
+| Tested | **Serial console** | GPIO UART0 (`ttyAMA0`) via `dtoverlay=uart0-pi5`. Read-only output at 115200 baud, even parity. Verified on Compute Blade with FT232RNL adapter. |
| Tested | **NVMe boot support** | `dd` image to NVMe + set EEPROM `BOOT_ORDER=0xf416` and `PCIE_PROBE=1`. Verified on 1TB Kingston NVMe on Compute Blade. |
## NVMe boot
@@ -213,10 +248,11 @@ PCIE_PROBE=1 # always required
All node types share the same overclock config (baked into the image via `config.txt.append`):
```ini
+dtparam=pciex1_gen=3
+dtoverlay=uart0-pi5
arm_freq=2600
over_voltage_delta=50000
arm_boost=1
-dtparam=pciex1_gen=3
```
Verified stable at 44.6°C max under full CPU + memory + disk stress across 10 nodes with Compute Blade heatsinks.
diff --git a/config/config.txt.append b/config/config.txt.append
index 16507e6..d583850 100644
--- a/config/config.txt.append
+++ b/config/config.txt.append
@@ -1,5 +1,8 @@
# Enable PCIe Gen 3 for NVMe (~800 MB/s vs ~400 MB/s Gen 2)
dtparam=pciex1_gen=3
+# Enable GPIO UART0 (ttyAMA0) on Pi5/CM5 for serial console
+# Must load AFTER disable-bt and disable-wifi overlays in config.txt
+dtoverlay=uart0-pi5
# CM5 Overclock — 2.6GHz stable on Compute Blade with heatsink
arm_freq=2600
over_voltage_delta=50000
diff --git a/patches/talos-rpi5/sbc-raspberrypi5/0003-Fix-SBC-overlay-upgrade-detect-EFI-mount-path-for-SB.patch b/patches/talos-rpi5/sbc-raspberrypi5/0002-Fix-SBC-overlay-upgrade-detect-EFI-mount-path-for-SB.patch
similarity index 73%
rename from patches/talos-rpi5/sbc-raspberrypi5/0003-Fix-SBC-overlay-upgrade-detect-EFI-mount-path-for-SB.patch
rename to patches/talos-rpi5/sbc-raspberrypi5/0002-Fix-SBC-overlay-upgrade-detect-EFI-mount-path-for-SB.patch
index d340637..ca56022 100644
--- a/patches/talos-rpi5/sbc-raspberrypi5/0003-Fix-SBC-overlay-upgrade-detect-EFI-mount-path-for-SB.patch
+++ b/patches/talos-rpi5/sbc-raspberrypi5/0002-Fix-SBC-overlay-upgrade-detect-EFI-mount-path-for-SB.patch
@@ -1,6 +1,6 @@
-From 85585f84af18e1cba6080e95490b275e69d0309e Mon Sep 17 00:00:00 2001
+From 5cdfe8ddb717e8de4e9d1c9e3000614ad8a1b5bb Mon Sep 17 00:00:00 2001
From: Mathias Beaulieu-Duncan
-Date: Mon, 16 Feb 2026 19:07:45 -0500
+Date: Wed, 25 Feb 2026 12:41:51 -0500
Subject: [PATCH] Fix SBC overlay upgrade: detect EFI mount path for SBC
layouts
MIME-Version: 1.0
@@ -17,14 +17,29 @@ Detect the SBC layout by checking if config.txt already exists at
/boot/ (indicating EFI is mounted there), and write files to the
correct location.
---
- installers/rpi5/src/main.go | 18 +++++++++++++-----
- 1 file changed, 13 insertions(+), 5 deletions(-)
+ installers/rpi5/src/config.txt | 3 ++-
+ installers/rpi5/src/main.go | 18 +++++++++++++-----
+ 2 files changed, 15 insertions(+), 6 deletions(-)
+diff --git a/installers/rpi5/src/config.txt b/installers/rpi5/src/config.txt
+index 1445d0e..e38291b 100644
+--- a/installers/rpi5/src/config.txt
++++ b/installers/rpi5/src/config.txt
+@@ -11,7 +11,8 @@ kernel=u-boot.bin
+ arm_64bit=1
+ # Run as fast as firmware / board allows.
+ arm_boost=1
+-# Enable the primary/console UART.
++# Enable UART0 on GPIO 14/15 (Pi5/CM5 requires explicit dt overlay).
++dtoverlay=uart0-pi5
+ enable_uart=1
+ # Disable Bluetooth.
+ dtoverlay=disable-bt
diff --git a/installers/rpi5/src/main.go b/installers/rpi5/src/main.go
-index fed3819..4bf8c38 100644
+index 38cd824..155a86b 100644
--- a/installers/rpi5/src/main.go
+++ b/installers/rpi5/src/main.go
-@@ -42,13 +42,21 @@ func (i *RpiInstaller) GetOptions(extra rpiOptions) (overlay.Options, error) {
+@@ -41,13 +41,21 @@ func (i *RpiInstaller) GetOptions(extra rpiOptions) (overlay.Options, error) {
}
func (i *RpiInstaller) Install(options overlay.InstallOptions[rpiOptions]) error {
@@ -50,7 +65,7 @@ index fed3819..4bf8c38 100644
return err
}
-@@ -58,5 +66,5 @@ func (i *RpiInstaller) Install(options overlay.InstallOptions[rpiOptions]) error
+@@ -57,5 +65,5 @@ func (i *RpiInstaller) Install(options overlay.InstallOptions[rpiOptions]) error
configTxt = append(configTxt, []byte("\n"+options.ExtraOptions.ConfigTxtAppend)...)
diff --git a/patches/talos-rpi5/sbc-raspberrypi5/0002-Fix-serial-console-for-RPi5-CM5-debug-UART.patch b/patches/talos-rpi5/sbc-raspberrypi5/0002-Fix-serial-console-for-RPi5-CM5-debug-UART.patch
deleted file mode 100644
index 6d877d3..0000000
--- a/patches/talos-rpi5/sbc-raspberrypi5/0002-Fix-serial-console-for-RPi5-CM5-debug-UART.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 7c1f75d724e54df5382d7900a0fdfac50f870043 Mon Sep 17 00:00:00 2001
-From: Mathias Beaulieu-Duncan
-Date: Fri, 13 Feb 2026 19:43:02 -0500
-Subject: [PATCH] Fix serial console for RPi5/CM5 debug UART
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The overlay was using console=ttyAMA0 (GPIO 14/15 UART) but the RPi5
-debug UART — the JST connector between HDMI ports on Pi5, or test pads
-TP35/TP36 on CM5 — is ttyAMA10.
-
-Changes:
-- main.go: Use console=ttyAMA10,115200 (Pi5 debug UART, not GPIO UART0)
-- main.go: Add earlycon=pl011,0x107d001000,115200n8 for early boot output
- before the full PL011 driver initializes
-- config.txt: Add [pi5] enable_uart=0 to match upstream and avoid U-Boot
- compatibility issues (the debug UART is always active regardless)
-
-The earlycon parameter uses the BCM2712 debug UART MMIO base address
-(0x107d001000) to provide kernel output immediately after ExitBootServices,
-bridging the gap between U-Boot handoff and full driver init.
----
- installers/rpi5/src/config.txt | 7 ++++++-
- installers/rpi5/src/main.go | 3 ++-
- 2 files changed, 8 insertions(+), 2 deletions(-)
-
-diff --git a/installers/rpi5/src/config.txt b/installers/rpi5/src/config.txt
-index 1445d0e..7af461e 100644
---- a/installers/rpi5/src/config.txt
-+++ b/installers/rpi5/src/config.txt
-@@ -11,8 +11,13 @@ kernel=u-boot.bin
- arm_64bit=1
- # Run as fast as firmware / board allows.
- arm_boost=1
--# Enable the primary/console UART.
-+# Enable the primary/console UART (globally).
- enable_uart=1
-+# Disable UART on Pi5 to avoid U-Boot compatibility issue.
-+# The debug UART (ttyAMA10) is always active regardless of this setting.
-+[pi5]
-+enable_uart=0
-+[all]
- # Disable Bluetooth.
- dtoverlay=disable-bt
- # Disable Wireless Lan.
-diff --git a/installers/rpi5/src/main.go b/installers/rpi5/src/main.go
-index 38cd824..fed3819 100644
---- a/installers/rpi5/src/main.go
-+++ b/installers/rpi5/src/main.go
-@@ -32,8 +32,9 @@ func (i *RpiInstaller) GetOptions(extra rpiOptions) (overlay.Options, error) {
- return overlay.Options{
- Name: "rpi5",
- KernelArgs: []string{
-+ "earlycon=pl011,0x107d001000,115200n8",
- "console=tty0",
-- "console=ttyAMA0,115200",
-+ "console=ttyAMA10,115200",
- "sysctl.kernel.kexec_load_disabled=1",
- "talos.dashboard.disabled=1",
- },
---
-2.50.1 (Apple Git-155)
-