NOR flash, covered in the previous lecture, is simple to reason about: map it, read it like RAM, execute from it. NAND flash is where embedded storage gets genuinely tricky – it can’t be memory-mapped, it can flip bits during normal reads, and every page carries a small hidden area that bootloaders, kernel drivers, and filesystems must all agree on. This lecture, part of our free linux device drivers course, breaks that down piece by piece with original examples verified against current kernel APIs.
What You Will Learn
Prerequisites
Before this lecture
NAND Cell Density: SLC, MLC, and TLC
A NAND cell stores charge, and the amount of charge determines what value it represents. The simplest design, Single Level Cell (SLC), stores exactly one bit per cell – the cell is either charged or not. Manufacturers later found ways to store two bits per cell as Multi-Level Cell (MLC), and three bits per cell as Tri-Level Cell (TLC), by distinguishing finer voltage levels within the same physical cell.
Packing more bits into the same cell increases capacity and lowers cost per gigabyte, but it comes at a real price: distinguishing four or eight voltage levels instead of two makes the cell far more sensitive to wear and to the neighboring cells’ charge, so both endurance and read reliability drop sharply as bit density increases.
| Cell type | Bits per cell | Typical erase endurance | Error correction needed |
|---|---|---|---|
| SLC | 1 | Up to about 100K cycles | Simple Hamming code, single-bit correction |
| MLC | 2 | Roughly 3K-10K cycles | BCH, multi-bit correction |
| TLC | 3 | As low as about 1K cycles | Stronger BCH or LDPC, multi-bit correction |
Pages, Erase Blocks, and Why NAND Can’t Be Mapped
Where NOR is erased in blocks but read and written a word at a time, NAND is erased in blocks and read and written a page at a time – there is no byte-level access at all. Erase blocks commonly range from around 16 KiB to 512 KiB, and each block is divided into pages, typically 2 KiB or 4 KiB each. Because a NAND chip cannot be addressed byte-by-byte, it cannot be mapped into the CPU’s address space the way NOR can – there is no execute-in-place option for raw NAND. Any code or data stored on it has to be read a full page at a time into RAM before the CPU can use it.
Bit Flips and Error Correction
NAND cells are packed tightly enough that reading, writing, or even just leaving data sitting for a long time can occasionally flip a bit – this is expected, normal behavior, not a defect. Every serious NAND driver corrects for it using an Error Correction Code (ECC) computed when a page is written and checked when it’s read back.
- Hamming code – cheap to compute in software, corrects a single bit error per page. Sufficient for SLC, where bit flips are rare.
- BCH (Bose-Chaudhuri-Hocquenghem) – corrects multiple bit errors per page (commonly up to 8 or more), needed for MLC and TLC where flips are far more frequent. Usually requires hardware ECC engine support in the SoC.
The Out-of-Band (OOB) Area
Every NAND page carries a small extra region beyond its main data area, called the out-of-band (OOB) or spare area. This is where the ECC bytes for that page are stored, along with a factory bad-block marker and, in many designs, filesystem metadata. A page with a 2 KiB data area typically carries 64 bytes of OOB; a 4 KiB page typically carries around 128 bytes – the OOB size scales with the page size because larger pages need proportionally more ECC bytes, especially on MLC/TLC parts with stronger ECC.
Main data area: holds the actual page content (for example 2 KiB).
OOB / spare area: holds ECC bytes, the bad-block marker byte, and optional filesystem metadata (for example 64 bytes).
An erase block is simply a fixed run of consecutive pages like this one, all erased together.
Because there’s little standardization of exactly how the OOB bytes are laid out, it’s entirely possible for a bootloader to write OOB data in a format the kernel’s NAND driver doesn’t expect – and vice versa. Keeping the bootloader, kernel MTD driver, and any image-creation tools in agreement about OOB layout is a real, common source of “why won’t this device boot after a firmware update” bugs.
Bad Block Management
NAND manufacturing isn’t perfect. During production, the factory tests every block and marks any that fail by writing a specific flag byte into the OOB area of the first page in that block – it’s normal, not a sign of a defective chip, for a couple of percent of blocks on a brand-new part to already be marked bad this way. The Linux NAND driver reads these markers at startup and builds a bad block table so nothing ever tries to use those blocks.
Blocks can also go bad later, in the field, typically by failing an erase or program operation. A correct driver detects that failure and marks the block bad at that point too, so future writes avoid it – this is why NAND filesystems like UBIFS always reserve some spare capacity beyond the advertised device size.
Reading NAND Geometry: An Original Kernel Module
Rather than writing a full raw NAND controller driver, the fastest way to get hands-on with NAND geometry is a small module that walks the MTD device list and logs each device’s key numbers – exactly the values a real driver would use to compute page and OOB offsets.
// ep_nand_geometry.c - original demo, logs NAND/MTD geometry via current mtd_info API
#include <linux/module.h>
#include <linux/mtd/mtd.h>
static int __init ep_nand_geometry_init(void)
{
struct mtd_info *mtd;
int i;
for (i = 0; i < 32; i++) {
mtd = get_mtd_device(NULL, i);
if (IS_ERR(mtd))
continue;
pr_info("ep_nand_geometry: mtd%d name=%s type=%d\n", i, mtd->name, mtd->type);
pr_info("ep_nand_geometry: size=%llu erasesize=%u writesize=%u oobsize=%u\n",
mtd->size, mtd->erasesize, mtd->writesize, mtd->oobsize);
put_mtd_device(mtd);
}
return 0;
}
static void __exit ep_nand_geometry_exit(void)
{
pr_info("ep_nand_geometry: unloaded\n");
}
module_init(ep_nand_geometry_init);
module_exit(ep_nand_geometry_exit);
MODULE_LICENSE("GPL");
To try this without real NAND hardware, load the kernel’s built-in nandsim module first to create a simulated NAND device, then load ours on top:
$ sudo modprobe nandsim first_id_byte=0x2c second_id_byte=0xda \
third_id_byte=0x90 fourth_id_byte=0x95
$ sudo insmod ep_nand_geometry.ko
$ dmesg | tail -6
[ 2011.442310] nandsim: NAND_ADDRESS_CYCLES value 5
[ 2011.443981] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
[ 2011.445102] nand: Hynix NAND 1GiB 3,3V 8-bit
[ 2011.448877] ep_nand_geometry: mtd0 name=NAND simulator, 32MB type=4
[ 2011.448921] ep_nand_geometry: size=1073741824 erasesize=131072 writesize=2048 oobsize=64
[ 2011.449010] ep_nand_geometry: unloaded
$ sudo mtdinfo /dev/mtd0
mtd0
Name: NAND simulator, 32MB
Type: nand
Eraseblock size: 131072 bytes, 128.0 KiB
Amount of eraseblocks: 8192
Minimum input/output unit size: 2048 bytes
Sub-page size: 512 bytes
OOB size: 64 bytes
Notice writesize (the page size) and oobsize line up exactly with what mtdinfo reports – that’s the same geometry a real driver would use to compute how many ECC bytes it needs per page.
Common Mistakes and Troubleshooting
Best Practices
Summary and Key Takeaways
NAND flash trades NOR’s byte-level simplicity for much higher density and lower cost, at the price of page-based access, unavoidable bit flips that require ECC, and a hidden per-page OOB area that stores that ECC plus bad-block markers. SLC is the most robust and simplest to correct; MLC and TLC pack in more capacity but need stronger error correction and tolerate far fewer erase cycles. Getting the OOB layout and bad block handling right across the bootloader and kernel is what separates a storage design that survives years in the field from one that bricks itself on the first bad update.
Conclusion
Between this lecture and the previous one, you now have the full physical-layer picture: NOR for execute-in-place robustness, NAND for dense, cost-effective bulk storage, and the MTD subsystem tying both into one uniform kernel API. From here, the natural next step in a storage strategy is choosing the right filesystem on top of that MTD device – which is exactly where this course’s storage chapter continues.
Frequently Asked Questions
What is the difference between SLC, MLC, and TLC NAND?
They differ in how many bits each memory cell stores: one for SLC, two for MLC, three for TLC. More bits per cell means higher capacity and lower cost, but lower erase endurance and a greater need for strong error correction.
Why can’t NAND flash be memory-mapped like NOR flash?
NAND can only be read and written a full page at a time through a controller, not addressed byte-by-byte, so it cannot be wired into the CPU’s address space for direct execution.
What is the out-of-band (OOB) area on a NAND page?
It’s a small extra region attached to every page that stores the page’s ECC bytes, a bad-block marker, and sometimes filesystem metadata – separate from the page’s main data area.
Why does NAND flash need error correction but NOR flash mostly doesn’t?
NAND’s tightly packed cells are prone to occasional bit flips during normal read and write operations. NOR’s less dense, more robust cell design makes this far less of a concern.
What’s the difference between a factory bad block and a bad block found in the field?
A factory bad block is marked during manufacturing testing before the chip ships. A field bad block is detected later by the driver, typically after a failed erase or program operation on a block that was previously good.
Do I need real NAND hardware to test a NAND driver?
No – the kernel’s built-in nandsim module creates a simulated NAND device with configurable geometry, which is enough to develop and test driver logic before moving to real hardware.
Is this part of a free course?
Yes, this lecture is part of EmbeddedPathashala’s free linux kernel development course and free linux device drivers course, both freely available.
Continue the Free Embedded Linux Course
Next: Choosing a Flash Filesystem Back to Course Index
2 Comments