본문 바로가기

Job Notes/File System

NAND Flash (NAND vs. NOR)

NAND FLASH

NAND vs. NOR

Beside the different silicon cell design, the most important difference between NAND and NOR Flash is the bus interface. NOR Flash is connected to a address / data bus direct like other memory devices as SRAM etc. NAND Flash uses a multiplexed I/O Interface with some additional control pins. NAND flash is a sequential access device appropriate for mass storage applications, while NOR flash is a random access device appropriate for code storage application.NOR Flash can be used for code storage and code execution. Code stored on NAND Flash can't be executed frome there. It must be loaded into RAM memory and executed from there.

NOR NAND
Interface Bus I/O
Cell Size Large Small
Cell Cost High Low
Read Time Fast Slow
Program Time single Byte Fast Slow
Program Time multi Byte Slow Fast
Erase Time Slow Fast
Power consumption High Low, but requires additional RAM
Can execute code Yes No, but newer chips can execute a small loader out of the first page
Bit twiddling nearly unrestricted 1-3 times, also known as "partial page program restriction"
Bad blocks at ship time No Allowed

Some facts about write speed.
NAND is typically faster than NOR for large writes. A typical NOR write is 10uS per word, which results in 1280uS per 512 bytes on a 32-bit bus. A typical NAND write is 50nS per byte + 10uS page seek + 200uS program which results in 236uS per 512 bytes on a 8 bit bus.

As NAND Flash is cheaper than NOR Flash and has a very slim interface it was selected as the optimum solution for large nonvolatile storage applications such as solid state file storage, digital audio/voice recorder, digital still camera and portable applications requiring non-volatility.


NAND Types

There are various types of NAND Flash available. Bare NAND chips, SmartMediaCards, DiskOnChip.

SmartMediaCards are bare NAND chips covered by thin plastic. They are very common in digital cameras and MP3 players. The card itself contains nothing smart at all. It gets smart by software.

DiskOnChip is NAND Flash with additional glue logic as a drop in replacement for NOR Flash chips. The glue logic provides direct memory access to a small address window, which contains a boot loader stub, which loads the real boot code from the NAND device. The logic contains also control registers for the static NAND chip control lines and a hardware ECC generator.


NAND technical view

The memory is arranged as a array of pages. A page consists of 256 / 512 Byte data and 8 / 16 Byte spare (out of band) area. The spare area is used to store ECC (error correction code), bad block information and filesystem dependend data. n pages build one block. The read / write access to data is on a per page basis. Erase is done on a per block basis. The commands to read / write / erase the chip is given by writing to the chip with the Command Latch Enable pin high. Address is given by writing with the Address Latch Enable pin high.

There are only a few lines neccecary to access up to 256 MB of Flashmemory.

Pin(s) Function
I/O 0-7 Data Inputs/Outputs
/CE Chip Enable
CLE Command Latch Enable
ALE Address Latch Enable
/RE Read Enable
/WE Write Enable
/WP Write Protect
/SE Spare area Enable
R/B Ready / Busy Output

As it is neccecary to use the spare area, the /SE (Spare area Enable) pin should be tied to GND. /CE, CLE and ALE should be GPIO pins or latched signals. It's possible to use address lines for ALE and CLE, but you have to take care about the timing restrictions of the chip !

/RE and /WE can be tied to the corresponding lines of the CPU. Make sure, that they are logicaly combined with the corresponding chipselect. You can also use two different chipselects for /RE and /WE, but be aware of data hold time constraints of your NAND chip. Data hold time after rising edge of /WE is different to data hold timeafter rising edge of chipselect lines!

I/O 0-7 are connected to the databus D0-D7. The /WP pin can be used for write protection or connected to VCC to enable writes unconditionally. As NAND flash uses a command driven programming and erasing, an accidential write or erase is not likely to happen. The Ready / Busy output is not neccecary for operation, but it can be tied to a GPIO or an interrupt line.


Filesystems supporting NAND

One major problem for using NAND Flash is, that you cannot write as often as you want to a page. The consecutive writes to a page, before erasing it again, are restricted to 1-3 writes, depending on the manufacturers specifications. This applies similar to the spare area. This makes it neccecary for the filesystem to handle a writebuffer, which contains data, that is less than a page

At the moment there are only a few filesystems, which support NAND

  • JFFS2 and YAFFS for bare NAND Flash and SmartMediaCards
  • NTFL for DiskOnChip devices
  • TRUEFFS from M-Systems for DiskOnChip devices
  • SmartMedia DOS-FAT as defined by the SSFDC Forum

JFFS2 and NTFL are Open Source, while TRUEFFS is a proprietary solution. SmartMedia DOS-Fat is a specification from SSFDC forum. It is somewhat open under a non disclosure agreement with Toshiba, who owns all rights on this specifications. NTFL is designed for the usage of DiskOnChip devices. JFFS2 supports raw NAND chips and SmartMediaCards at the moment. A JFFS2 support for DiskOnChip devices, based on the NAND code, is planned. There are some other Open Source projects for NAND filesystem support, but there's no other working solution than JFFS2 and YAFFS at the moment of this writing. YAFFS is available from YAFFS-Homepage. YAFFS is faster than JFFS2 and consumes less RAM, JFFS2 provides on the fly file compression and decompression, which is very helpfull for small FLASHs.

There is currently no support for the wide spread SmartMedia DOS-FAT filesystem, mainly because it's not a reliable filesystem for industrial usage. It's ok for multimedia applications. The hardware support layer is designed to support an implementation of SmartMedia DOS-FAT, but nobody has made an attempt to implement it really. There are a couple of SmartMedia Card adaptors for USB, PCMCIA, FireWire ... with Linux drivers available, which support the SmartMedia DOS-FAT.

JFFS2 and YAFFS include bad block management, wear leveling, error correction and provide reliable filesystems for industrial use on top of NAND Flash.


Multiple filesystems on different partitions

You can mount different filesystems on different partitions of the same chip.

Technical information for filesystem implementation

OOB usage

As the OOB usage of the filesystems differs, the OOB usage can be selected on runtime from the filesystem driver. The parameter is given to the functions mtd->read_ecc and mtd->write_ecc. This parameter specifies the location of the ECC-data inside the oob area. The parameter is a structure named nand_oobinfo.
struct nand_oobconfig {
int useecc;
int eccpos[6];
}
With this structure the usage of ecc and the position of ecc-data in the oob area are given. If useecc is 0, then eccpos will be ignored, else eccpos array gives an index for the ecc data inside out of band area.

All non ecc functions like mtd->read and mtd->write use an internal structure, which can be set by an ioctl.
ioctl (fd, MEMSETOOBSEL, oobsel);, where oobsel is a pointer to a user supplied structure of type oobconfig. The contents of this structure must match the criteria of the filesystem, which will be used. See an example in utils/nandwrite.c.

Read back OOB data together with main area

If the fs driver needs to read the oobdata together with the raw data, then the fs-driver has to supply a big enough buffer.
size = 12 bytes * number of pages to read (256B pagesize) or 24 bytes* number of pages to read (512B pagesize)
The buffer contains 8/16 byte oobdata and 4/8 byte returncode from correct_ecc
oobbuf [0-15] oob-data 1st read page
oobbuf [16-19] return code from correct_ecc byte 0-255
oobbuf [20-23] return code from correct_ecc byte 256-511
oobbuf [24-39] oob-data 2nd read page
oobbuf [40-31] return code from correct_ecc byte 0-255
.....
The returnvalue of read_ecc is -EIO, if any correct_ecc returned -1. But retlen is equal to the requested length, so fs-driver can decide what to do.

Write OOB data together with main area

Oob data can be given from filesystem to program them in one go together with the raw data. ECC codes are filled in at the place selected by oobsel. This supports multipage programming.
oobbuf[0-15] 1st page to write
oobbuf[16-31] 2nd page to write
.....
ECC is filled in at the appropriate place selected by the above mentioned constants.


JFFS2 specific information

JFFS2 Out of Band usage

Nand chips with 256 byte pagesize and 8 byte OOB size

Offset Content Comment
0x00 ECC byte 0 Error correction code byte 0
0x01 ECC byte 1 Error correction code byte 1
0x02 ECC byte 2 Error correction code byte 2
0x03 reserved reserved
0x04 reserved reserved, was ECC valid marker, which is now obsolete
0x05 Bad block marker If any bit in this byte is zero, then this block is bad. This applies only to the first page in a block. In the remaining pages this byte is reserved
0x06 Clean marker byte 0 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x85. In the remaining pages this byte is reserved
0x07 Clean marker byte 1 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x19. In the remaining pages this byte is reserved

Nand chips with 512 byte pagesize and 16 byte OOB size

Offset Content Comment
0x00 ECC byte 0 Error correction code byte 0 of the lower 256 Byte data in this page
0x01 ECC byte 1 Error correction code byte 1 of the lower 256 Bytes of data in this page
0x02 ECC byte 2 Error correction code byte 2 of the lower 256 Bytes of data in this page
0x03 ECC byte 3 Error correction code byte 0 of the upper 256 Bytes of data in this page
0x04 reserved reserved, was ECC valid marker, which is now obsolete
0x05 Bad block marker If any bit in this byte is zero, then this block is bad. This applies only to the first page in a block. In the remaining pages this byte is reserved
0x06 ECC byte 4 Error correction code byte 1 of the upper 256 Bytes of data in this page
0x07 ECC byte 5 Error correction code byte 2 of the upper 256 Bytes of data in this page
0x08 Clean marker byte 0 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x85. In the remaining pages this byte is reserved
0x08 Clean marker byte 1 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x19. In the remaining pages this byte is reserved
0x08 Clean marker byte 2 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x03. In the remaining pages this byte is reserved
0x08 Clean marker byte 3 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x20. In the remaining pages this byte is reserved
0x08 Clean marker byte 4 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x08. In the remaining pages this byte is reserved
0x08 Clean marker byte 5 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x00. In the remaining pages this byte is reserved
0x08 Clean marker byte 6 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x00. In the remaining pages this byte is reserved
0x08 Clean marker byte 7 This byte indicates that a block was erased under JFFS2 control. If the page was succesfully erased this byte in the first page of a block is programmed to 0x00. In the remaining pages this byte is reserved

HOWTO implement NAND support

Where can you get the code ?

The latest changes to JFFS2 and the underlying NAND code are not in the kernel code at the moment. The latest code is available from CVS and daily snapshots

There are four layers of software

  1. JFFS2: filesystem driver
  2. MTD: Memory Technology Devices driver
  3. NAND: generic NAND driver
  4. Hardware specific driver

the MTD driver just provides a mount point for JFFS2. The generic NAND driver provides all functions, which are neccecary to identify, read, write and erase NAND Flash. The hardware dependend functions are provided by the hardware driver. They provide mainly the hardware access informations and functions for the generic NAND driver. For YAFFS applies the same.

Hardware driver

To implement it on your hardware, you will have to write a new hardware driver. Copy one of the existing hardware drivers and modify it to fit your hardware. These basic functions have to be modified:

  1. Hardware specific control function
  2. Device ready function
  3. Init function
To provide enough flexibilty for all kind of devices, there can be supplied additional functions optionally.
  1. Hardware specific command function
  2. Hardware specific wait function
  3. Hardware ECC functions

Hardware specific control function

This function sets and resets the control pins CLE, ALE and CE of the NAND device depending on the function argument. The argument constants are defined in nand.h and explained in the example function below.

void yourboard_hwcontrol(int cmd)
{
switch(cmd){
case NAND_CTL_SETCLE: Hardware specific code to set CLE line to 1; break;
case NAND_CTL_CLRCLE: Hardware specific code to set CLE line to 0; break;
case NAND_CTL_SETALE: Hardware specific code to set ALE line to 1; break;
case NAND_CTL_CLRALE: Hardware specific code to set ALE line to 0; break;
case NAND_CTL_SETNCE: Hardware specific code to set CE line to 0; break;
case NAND_CTL_CLRNCE: Hardware specific code to set CE line to 1; break;
}
}

Device ready function

If your hardware interface has the ready busy pin of the NAND chip connected to a GPIO or other accesible I/O pin, this function is used to read back the state of the pin. The function has no arguments and should return 0, if the device is busy (R/B pin is low) and 1, if the device is ready (R/B pin is high). If your hardware interface does not give access to the ready busy pin, you can delete this function and set the function pointer this->dev_ready during init to NULL.

int yourboard_device_ready(void)
{
return The state of the ready/busy pin of the chip;
}

Init function

This function is called, when the driver is initialized either on kernel boot or when you load your driver as a module. The function remaps the I/O area, through which your NAND chip can be accessed, allocates all neccecary memory chunks for the device structure and data cache. The structure of the device has to be zeroed out first and then filled with the neccecary information about your device. See example code for the most important members of the device structure you have to set.

int __init yourboard_init (void)
{
SNIP
/* Allocate memory for MTD device structure and private data */
yourboard_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),GFP_KERNEL);
SNIP
/* map physical adress */
yourboard_fio_base=(unsigned long)ioremap(yourboard_fio_pbase,SZ_1K);
SNIP
/* Set address of NAND IO lines */
this->IO_ADDR_R = yourboard_fio_base; The address to read from the chip
this->IO_ADDR_W = yourboard_fio_base; The address to write to the chip
this->hwcontrol = yourboard_hwcontrol;Your function for accessing the controllines
this->dev_ready = yourboard_device_ready; Your function for accessing the ready/busy line or NULL, if you don't have one
this->chip_delay = 20;The delay time (us), after writing a command to the chip, according to datasheet (tR)
this->eccmode = NAND_ECC_XXX; Set the correct ECC generator mode for your board. This defaults to NAND_ECC_SOFT. Notes about hardware ECC can be found below.
SNIP
}

Hardware specific command function

Some new CPU's like Samsungs ARM based S3SC2410 provide a hardware based NAND interface. For them and ugly designed hardware interfaces it may be neccecary to have a customized command write function. You can supply such a function by setting
this->cmdfunc = yourboard_cmdfunc;
This must be done in yourboard_init before calling nand_scan.

The function is defined as
void yourboard_cmdfunc (struct mtd_info *mtd, unsigned command, int column, int page_addr);

Hardware specific wait function

If you have connected the ready/busy pin to an interrupt line, you could supply a own interrupt driven waitfunction for erase and program wait for ready. In this case set

this->waitfunc = yourboard_waitfunction;
This must be done in yourboard_init before calling nand_scan.

The function is defined as
int yourboard_waitfunction (struct mtd_info *mtd, struct nand_chip *this, int state);
Please take care of the functionality, which is in standard nand driver wait function (nand_wait).

Hardware based ECC

If your hardware supplies a hardware based ECC generator, then fill out the following. If not, skip this topic.

this->eccmode = NAND_ECC_HW3_256;
or
this->eccmode = NAND_ECC_HW3_512;
or
this->eccmode = NAND_ECC_HW6_512;

NAND_ECC_HW3_256 is a hardware based ECC generator, which generates 3 byte ECC code for 256 byte of data. Such a generator can be found on DOC devices and on passive SmartMedia adaptors.
NAND_ECC_HW3_512 is a hardware based ECC generator, which generates 3 byte ECC code for 512 byte of data. Such a generator can be found e.g. on Samsungs ARM based S3SC2410 CPU.
NAND_ECC_HW6_512 is a hardware based ECC generator, which generates 6 byte ECC code for 512 byte of data.

You have also to provide following functions:

Enable hardware ECC generator

void yourboard_enable_hwecc (int mode);

Your function to enable (reset) the hardware ECC generator. This function is called from the generic nand driver before reading or writing data from/to the chip. The function is called with NAND_ECC_READ or NAND_ECC_WRITE as argument.
Set the function pointer in init to
this->enable_hwecc = yourboard_enable_hwecc;

Enable hardware ECC generator

void yourboard_readecc(const u_char *dat, u_char *ecc_code);

Your function to read back the ECC bytes from your hardware ECC generator. Fill the data into the ecc_code array, which is given as argument. Ignore the first argument of this function, which is neccecary for software ecc only. Set the function pointer in init to
this->calculate_ecc = yourboard_readecc; 

Error detection and data correction function

int xxxx_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc);

A function which implements error detection and data correction corresponding to your hardware ECC algorithm. This function should be incorporated into nand_ecc.c with an appropriate function name, to make it public available for similar hardware drivers. Maybe the function you need is already there. If you implement a new one, please contact NAND driver maintainer to include it in the public source tree. Please consult current implementations in nand_ecc.c to provide a compatible solution. Set the function pointer in init to
this->correct_data = xxxx_correct_data;

All the function pointers must be set in yourboard_init before calling nand_scan.

Supported chips

Most NAND chips actually available from 2 to 128MB should be supported by the current code. If you have a chip, which is not supported, you can easily add it by extending the chiplist in drivers/mtd/nand/nand.c. The chip name does not longer contain cryptic part numbers, as the device ID is just an information about size, erase block size, pagesize and operating voltage. Add an entry, which contains following information:
{ name, id, chipshift, erasesize, page256 }

ref comment
name string: "NAND 'size' 'voltage'"
id chip device code. This code is read during nand_scan. Check datasheet for the code of your chip
chipshift chip size indicator. Chip size = (1 << chipshift)
erasesize the erasesize of your chip in bytes. Consult datasheet for proper
page256 set this to 1, if your chip has pagelength 256 byte, else set it to 0.

Please contact NAND driver maintainer to include it in the public source tree.

Manufacturer codes are scanned during nand_scan too. If the code is one of the known codes in the manufacturer ID table, the name of the manufacturer is printed out, else "Unknown" is printed. This happens when your hardware driver is loaded and calls nand_scan. Add codes, which are new and contact NAND driver maintainer to include it

Config settings

The following config switches have to be set. JFFS2 on NAND does not work, if one of these settings is missing.

CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_YOURBOARD=y
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_NAND=y

Make sure that fs/Config.in contains the following lines:
dep_tristate 'Journalling Flash File System v2 (JFFS2) support' CONFIG_JFFS2_FS $CONFIG_MTD
if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
bool 'JFFS2 support for NAND chips' CONFIG_JFFS2_FS_NAND
fi


FAQ

Can I boot from NAND Flash?

Not from a bare NAND chip. You need a glue logic around, which gives you memory access to the chip on bootup, like the DiskOnChip devices do. This will be a quite complex CPLD. An alternative is to use a small e.g. 1MB NOR Flash, which contains the boot code and maybe a compressed kernel image. Then you can use JFFS2 on NAND as your root filesystem

Some newer chips make the first page available for reading after power up. This could be helpful for starting a small 256/512 byte bootcode. At the time of this writing there is no tested implementation of this.

Samsungs S3C2410 ARM based SOC-CPU provides a mechanism to boot from NAND flash.

Is there support for 16/32bit wide NAND Flash ?

No. The generic NAND driver supports 8 bit wide NAND Flash only. 16 or 32 bit NAND Flash can be built by using 2 or 4 chips and connect them to D0-7, D8-D15, D16-D23 and D24-D31 on the data bus. You can tie all corresponding control signals together. But you have to build a new nand16 or nand32 driver, which can be derived from the existing nand.c. Be aware, that the writebuffer size is 2 or 4 times as big as on 8 bit NAND. This mean's, if you flush the buffer to ensure, that your data are on disk, you may waste much more memory space than on 8 bit NAND. Another point is bad block handling. When a block on 1 chip is bad, the corresponding blocks on the other chips are lost too, as you present them as one big block to the filesystem driver. The JFFS2 code, which handles the writebuffer and the out of band (spare) area of NAND doesn't support 16 / 32 bit neither.

How is ensured, that data is written to flash ?

As we have to handle a writebuffer for writing only full pages to the chips, there could be a loss of data, when the writebuffer is not flushed before power down. There are some mechanisms to ensure, that the writebuffer is flushed. You can force the flush of the writebuffer by using fsync() or sync() in your application. JFFS2 has a timed flush of the write buffer, which forces the flush of the buffer to flash, if there are no writes to the filesystem for more than 2 seconds. When you unmount the filesystem the buffer is flushed too.

Can I use mtdutils erase / eraseall

Yes, the latest nand driver code forces the protection of bad block information. It's safe to erase a NAND flash with erase(all) /dev/mtdX. It's recommended to use eraseall with -j or --jffs2 option set. This will write the cleanmarker to the out of band area. So you can mount the filesystem and no further formatting is needed. This formatting is also neccecary before you copy a fs-image to the chip.

Can I copy a JFFS2 Image to NAND via /dev/mtdX ?

Yes, as long as your chip does not contain bad blocks. Make sure, that the erasesize you set to mkfs.jffs2 is the same as the erasesize of your chip. Data will only be written with ECC, if your default settings for oob-layout selection are set for JFFS2. For bad block aware copying, use nandwrite from mtd-utils.
nandwrite -j /dev/mtdX image

Can I use seek/read/write on /dev/mtdX ?

Yes, as long as your program is aware of bad blocks. Make sure to set the desired ECC layout by ioctl (MEMSETOOBSEL). A example for bad block handling and usage of ioctl (MEMOOBSEL) can be found in util/nandwrite.c

Must my bootloader be aware of NAND FLASH ?

Yes, if you use your bootloader to erase the FLASH chip and copy a filesystem image to it. For erase make sure, that you don't erase factory-marked bad blocks. They are marked in the 6th byte (offset 0x5) in the out of band area of the first page of a block. The block is bad, if any bit in this byte is zero. If you erase such a block, the bad block information is erased too and lost. Further use of this block will lead to erroneous results

After the erase it's recommended to programm the JFFS2 erased marker into the out of band area of the first page in each erased block. Do not program it into the data area of the page !

For 256 byte pagesize devices program the following data into the out of band area:

Offset 0x06 0x07
Data 0x85 0x19

For 512 byte pagesize devices program the following data into the out of band area:

Offset 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f
Data 0x85 0x19 0x03 0x20 0x08 0x00 0x00 0x00

If you copy a filesystem image to the chip, it's recommended to write it with ECC. You can use the ECC code in the nand driver to do this. If you have a bad block on your chip, just skip this block and copy the data to the next block. JFFS2 is able to handle this gap.


References:

Open Source

JFFS2 and NTFL are located on this website.
YAFFS is located at YAFFS-Homepage.

Hardware

Toshiba

Samsung

SSFDC Forum

M-Systems


Maintainers

JFFS2 is maintained by David Woodhouse

The generic NAND driver is maintained by Thomas Gleixner

Please don't contact them direct. Ask your questions on the mtd-mailing-list.

Any suggestions, improvements, bug-reports and bug-fixes are welcome


Thomas Gleixner
$Id: nand.html,v 1.17 2003/04/14 06:58:04 gleixner Exp $