Almost the whole week went into one bug. This is the honest account of it: the fix I was sure about that didn't work, disproving my own theory, and the actual root cause hiding one layer deeper — a single voltage-switch on the SD bus. It ends at a login prompt on real hardware.
Week 5 ended mid-fight. The board booted my AGL kernel off the SD card, then drowned in I/O error, dev mmcblk0, sector 0 and never mounted the root filesystem. My leading theory was a firmware/OS generation mismatch — the board's firmware was JetPack 7, my kernel was JetPack 6 — and the plan was a full USB-recovery flash to pull the firmware back down to the matching generation. This week I did exactly that. It did not fix it. What followed was the real debugging.
What I did: got the board into Force Recovery Mode (it enumerated as 0955 NVIDIA Corp. APX), and ran the meta-tegra flash bundle, which ships its own matching firmware. It rewrote the board's firmware and OS together as one coherent JetPack-6 system.
Flashing completed
Coldbooting the device
I checked the version off the boot log afterwards, and it was genuinely downgraded:
| Piece | Before | After flash |
|---|---|---|
| Board firmware | 39.2.0 (JetPack 7.2) | 36.5.0 (JetPack 6.2) |
| AGL kernel | 5.15-l4t-r36.5 | 5.15-l4t-r36.5 |
Firmware and kernel were now the same generation. By my theory, the SD errors should have been gone.
The board booted, loaded the kernel, and hit the exact same flood:
blk_update_request: I/O error, dev mmcblk0, sector 0 (READ)
mmcblk0: unable to read partition table
Being honest about it The generation mismatch was not the root cause. I'd built a clean, plausible story around one version number and it was wrong. Aligning the firmware changed nothing — which was actually useful: it eliminated the single biggest variable and forced me to look one layer deeper, at the kernel's own conversation with the card.
With the tidy explanation gone, I went back to first principles and knocked out every suspect I could:
That last point was the whole key. The firmware reads the card. The kernel cannot. Same card, same slot, same board, seconds apart — the only thing that changes between them is how each one drives the SD bus.
An SD card can run its data lines at two signaling voltages: a slow, universally-safe 3.3 V, or a fast 1.8 V UHS high-speed mode (SDR50/DDR50/SDR104). The bootloader is conservative — it stays at 3.3 V, so it always works. The Linux kernel is ambitious — it boots, sees a UHS-capable card, and immediately tries to renegotiate the bus up from 3.3 V to 1.8 V for speed.
Why it corrupts every read On this carrier board + card combination, that 3.3 V→1.8 V handshake fails at the electrical level. The controller believes it switched; the card (or the signal integrity on those lines) doesn't follow it cleanly. From that moment every read comes back garbage — including sector 0, the partition table — so the kernel can never mount root. The bootloader worked for exactly one reason: it never attempts the switch.
So the fix isn't firmware, or power, or the card. It's telling the kernel to be as conservative as the bootloader: never leave 3.3 V.
The SD/MMC controller is a node in the board's device tree — mmc@3400000. I patched it to forbid the 1.8 V switch and hold the power rail steady, and stripped out the UHS high-speed modes so the kernel never even tries them:
mmc@3400000 {
status = "okay";
no-1-8-v; /* never switch to 1.8V UHS */
nvidia,vmmc-always-on; /* keep the card's power rail steady */
/* removed: sd-uhs-sdr25 / sdr50 / ddr50 / sdr104 */
};
Deploying it without a full reflash: normally the kernel's device tree comes from a flashed partition, so testing a change would mean rebuilding and reflashing every time. Instead I used an FDT override — I compiled the patched device tree, dropped it on the card's boot partition, and added one line to extlinux.conf pointing the bootloader at it:
LINUX /boot/Image
INITRD /boot/initrd
FDT /boot/kernel_tegra234-...-nv-super-fixed.dtb
Now the bootloader hands the kernel my device tree instead of the flashed one — a full test-fix loop in seconds instead of a rebuild.
Reinserted the card, powered on, watched the serial console. No error flood. The kernel mounted root and dropped straight to:
Automotive Grade Linux 21.0.1 jetson-orin-nano-devkit ttyTCU0
jetson-orin-nano-devkit login:
Logged in as root and confirmed the whole stack end to end:
$ cat /etc/os-release
ID=agl
VERSION="21.0.1 (unagi)"
$ uname -r
5.15.185-l4t-r36.5-1033.33+g9c6d5c8154da
$ df -h /
/dev/mmcblk0p1 ... / (read-write)
AGL 21 "Unagi" now boots to a working root shell on a real Jetson Orin Nano. Genuine hand-built Yocto image, matching firmware, root filesystem mounted read-write off the SD card, GPU (nvgpu) up. After almost a week on one bug, the board is finally a usable Linux machine.
There was no single guide for this — I want to be clear about that, because it's the part I'm most proud of. The mechanism (a failed 3.3 V→1.8 V switch) I reasoned out from the symptom: bootloader reads, kernel doesn't, only the bus signaling differs. nvidia,vmmc-always-on came from a matching NVIDIA developer-forum thread on Orin SD instability. no-1-8-v is a standard property from the upstream Linux MMC device-tree binding, not anything Jetson-specific. Assembling those three facts into the fix was the work.
And to a question my mentor asked — it's not specific to the Orin Nano "Super." The change targets the SDMMC controller node, which is identical across the whole Orin Nano / NX devkit family; only the device tree filename carries the "super" tag. It's a known Orin-family SD signal-integrity quirk, reported on plain Orin Nano boards too.
Status: the target board is fully up — AGL boots to userspace on real silicon. That closes out the entire hardware bring-up arc that started back in Week 3 with a Raspberry Pi that wouldn't boot.
Two loose ends, then the real goal:
Next — the payoff: add meta-ros to the Jetson image so the board can run ROS2 and subscribe to the live CARLA LiDAR stream over the network, on real hardware. That's the transport leg from the project's ideal diagram — workstation → real target over a LAN — running on real silicon instead of an emulated VM for the first time. Everything the QEMU pipeline already proved now gets to run on the board itself.
Bare-metal debugging is a different discipline from writing code. The lesson that'll stick from this week isn't the device tree property — it's watching a clean, confident theory die on contact with the hardware, and having to trust the evidence over the story I'd already told myself.