free linux development course
free linux device drivers course
free linux kernel development course
u-boot nand flash
Plenty of embedded boards have no SD card slot at all — the kernel lives permanently in raw NAND flash soldered
onto the board. Getting an image there safely means more than a simple copy, because NAND has quirks that ordinary
storage doesn’t: it must be erased in blocks before it can be rewritten, and it can develop bad blocks over its
lifetime. This lecture in our free embedded Linux course covers U-Boot’s nand command
family and how to use it correctly.
What You Will Learn
- Why NAND flash requires erase-before-write
- Erasing, writing, and reading NAND regions from U-Boot
- Where ECC fits into the write/read path
- Planning a NAND partition layout for boot images
- Recovering from a bad or interrupted NAND write
Prerequisites
This lecture assumes you already have a wrapped, verified kernel image sitting in RAM — either loaded via
fatload or tftp as covered in the previous lecture in this free linux kernel
development course.
Why NAND Is Different
Unlike an SD card, which presents a clean block-device abstraction to whoever’s using it, raw NAND flash exposes
its physical quirks directly to the software talking to it. Two properties matter most for boot images:
- Erase granularity — NAND can only be erased in large blocks (commonly 128KB-256KB), even though it can be programmed in much smaller pages. You cannot overwrite existing data directly; the containing block must be erased first.
- Bit errors and bad blocks — NAND cells wear out and occasionally flip bits even on healthy blocks, so error-correcting code (ECC) is applied on every write and checked on every read, and blocks that fail permanently get marked bad and skipped.
Enabling ECC
Before writing anything meaningful, make sure hardware or software ECC is active — writing without it risks
silent corruption that only surfaces later as a boot failure:
U-Boot# nandecc hw
Most modern SoCs implement ECC in a hardware NAND controller, so hw is typically correct; older or
simpler controllers may require U-Boot’s software ECC implementation instead.
Erasing a Region
Erase takes an offset and a size, both interpreted in the NAND’s own address space, not the RAM address space:
U-Boot# nand erase 0x280000 0x600000
NAND erase: device 0 offset 0x280000, size 0x600000
Erasing at 0x860000 -- 100% complete.
OK
The size must be a multiple of the NAND’s erase block size, and both offset and size are typically given in hex.
It’s common practice to erase a region somewhat larger than the current image, leaving headroom for the image to
grow across future builds without needing a layout change.
Writing the Image
With the target region freshly erased, write the image already sitting in RAM out to NAND:
U-Boot# nand write ${ep_kernel_addr} 0x280000 0x600000
NAND write: device 0 offset 0x280000, size 0x600000
6291456 bytes written: OK
Note that the write size here is the full erased region, not just the actual image size — U-Boot pads the
remainder, which is one reason the earlier erase size should comfortably exceed the image’s actual byte count.
Reading It Back
To boot from this image later (or just to verify the write immediately), read it from NAND back into RAM:
U-Boot# nand read ${ep_kernel_addr} 0x280000 0x600000
NAND read: device 0 offset 0x280000, size 0x600000
6291456 bytes read: OK
U-Boot# iminfo ${ep_kernel_addr}
Running iminfo right after a NAND write-then-read cycle is the fastest way to confirm the image
survived the round trip intact, using the same header checksum mechanism covered in the mkimage lecture.
|
| nand erase 0x280000 0x600000
v
+——————————–+
| NAND flash region (erased) |
+——————————–+
|
| nand write <ram_addr> 0x280000 0x600000
v
+——————————–+
| NAND flash region (programmed) |
| [ECC computed per page] |
+——————————–+
|
| nand read <ram_addr> 0x280000 0x600000
v
RAM (verified via iminfo)
Planning a NAND Layout
A board’s NAND is normally divided into fixed regions at design time — one for U-Boot itself, one for its
environment (often duplicated, as covered in the environment variables lecture), one for the kernel image, and one
for the root filesystem. These offsets get baked into both the board’s U-Boot configuration and its Linux MTD
partition table, so the two must always agree:
| Region | Typical Purpose |
|---|---|
| 0x000000 – 0x100000 | U-Boot (SPL + proper) |
| 0x100000 – 0x180000 | Environment (primary + redundant copy) |
| 0x280000 – 0x880000 | Kernel / FIT image |
| 0x880000 onward | Root filesystem (UBIFS, JFFS2, or similar) |
These offsets are illustrative — always confirm the actual layout from your board’s device tree or U-Boot config
rather than assuming.
Common Mistakes and Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| “NAND write: attempt to write to bad block” warnings | A block in the target range is factory-marked bad | Expected behavior — U-Boot skips it automatically; don’t disable bad-block handling |
| iminfo checksum fails after read-back | ECC not enabled, or write interrupted by power loss | Confirm nandecc hw was set before writing; retry the full erase/write cycle |
| Erase fails partway through | Erase size not block-aligned | Round the erase size up to a multiple of the NAND erase block size |
| Board unbootable after a bad flash | Old image partially overwritten, new image incomplete | Recover via network/JTAG boot if available; always keep a known-good fallback path during bring-up |
Best Practices
- Never power-cycle a board mid-erase or mid-write — NAND operations are not safely interruptible.
- Leave headroom in your erase size for image growth across builds.
- Keep U-Boot itself and the environment in a separate, rarely-touched region from the kernel/rootfs you iterate on.
- Always verify with
iminfoimmediately after writing, while the board is still up and easy to recover.
Performance Considerations
NAND erase is significantly slower than write, which is itself slower than read — a full chip erase can take
tens of seconds, so erasing only the region you actually need (rather than the whole device) matters for iteration
speed during development.
Summary and Key Takeaways
- NAND requires erase-before-write, and erases operate on whole blocks, not arbitrary byte ranges.
nandecc hw,nand erase,nand write, andnand readform the core workflow.- Bad block handling is automatic but should never be disabled.
- NAND layout must stay consistent between U-Boot’s configuration and Linux’s MTD partition table.
Conclusion
With a kernel image safely written to NAND and verified, everything is finally in place to actually start Linux.
The last lecture in this chapter of our free linux device drivers course covers the command that
does exactly that — bootm.
FAQ
Can I write directly to NAND without erasing first?
No, NAND cells can only transition from erased to programmed, not back, so any region must be erased before it
can hold new data.
What happens if a block is marked bad?
U-Boot’s NAND driver automatically skips bad blocks during erase, write, and read operations — this is expected
and does not indicate a failed operation.
Is software ECC as reliable as hardware ECC?
Software ECC works but is slower and typically corrects fewer bit errors per page than a dedicated hardware
controller, so hardware ECC is preferred whenever the SoC supports it.
Why does nand write report a size equal to the erased region, not the image size?
U-Boot writes the full requested byte range, padding beyond the actual image, which is why choosing an
appropriately sized (not oversized) erase region matters.
What’s the safest way to recover from a bad NAND flash mid-development?
Keep a network or JTAG-based recovery boot path available so you can re-flash without depending on the
partially-written NAND contents.
Continue the Free Embedded Linux Bootloader Course
