7.1 MTD-Supported Devices

As we saw earlier in Section 3.4.1, the MTD subsystem is rich and elaborate. To use it on your target, you will need a properly configured kernel and the MTD tools available from the project's web site. We will discuss both of the issues below.

As with other kernel subsystems, the development of the MTD subsystem and the MTD tools is independent of the mainline kernel. Hence, the latest kernel often does not include the latest code in the MTD CVS repository. You can, nevertheless, retrieve the latest code and use it instead of the MTD code already included in the kernel you have selected.

Because the MTD code in the kernel releases is not in sync with the MTD development, however, you can sometimes encounter problems. I was unable, for instance, to get vanilla Linux 2.4.18 to boot from a DiskOnChip (DOC) 2000, because there is a bug in the default MTD code in that kernel. To fix the problem, I had to manually modify the MTD code according to instructions found in the MTD mailing list archive. For this reason, you will find the MTD mailing list and its archive helpful.

In the following sections, we will start by discussing the usage basics of the MTD subsystem. This will cover issues such as configuring the kernel, installing the required utilities, and creating appropriate entries in /dev. The discussion will then focus on the use of the MTD subsystem with the two solid state storage devices most commonly used in embedded Linux systems: native CFI-compliant flash and DOC devices.

7.1.1 MTD Usage Basics

Having already covered the detailed architecture of the MTD subsystem, we can now concentrate on the actual practical use of its components. First, we will discuss the /dev entries required for MTD abstractions. Second, we will discuss the basic MTD kernel configuration options. Third, we will discuss the tools available to manipulate MTD storage devices in Linux. Finally, we will describe how to install these tools both on the host and on the target.

7.1.1.1 MTD /dev entries

There are five types of MTD /dev entries and seven corresponding MTD user modules.[1] In practice, many MTD user modules share the same /dev entries and each /dev entry can serve as an interface to many MTD user modules. Table 7-1 describes each type of MTD /dev entry and the corresponding MTD user modules, and Table 7-2 provides the minor number ranges and describes the naming scheme used for each device type.

[1] See Section 3.4.1 for the definition of MTD "user modules."

Table 7-1. MTD /dev entries, corresponding MTD user modules, and relevant device major numbers

/dev entry

Accessible MTD user module

Device type

Major number

mtdN

char device

char

90

mtdrN

char device

char

90

mtdblockN

block device, read-only block device, JFFS, and JFFS2

block

31

nftlLN

NFTL

block

93

ftlLN

FTL

block

44

Table 7-2. MTD /dev entries, minor numbers, and naming schemes

/dev entry

Minor number range

Naming scheme

mtdN

0 to 32 per increments of 2

N = minor / 2

mtdrN

1 to 33 per increments of 2

N = (minor - 1) / 2

mtdblockN

0 to 16 per increments of 1

N = minor

nftlLN

0 to 255 per sets of 16

L = set;[2] N = minor - (set - 1) x 16; N is not appended to entry name if its value is zero.

ftlLN

0 to 255 per sets of 16

Same as NFTL.

[2] As with other partitionable block device entries in /dev, device sets are identified by letters. The first set is "a," the second set is "b," the third set is "c," and so on.

The use of each type of MTD /dev entry is as follows:

mtdN

Each entry is a separate MTD device or partition. Remember that each MTD partition acts as a separate MTD device.

mtdrN

Each entry is the read-only equivalent of the matching /dev/mtdN entry.

mtdblockN

Each entry is the block device equivalent of the matching /dev/mtdN entry.

nftlLN

Each set is a separate NFTL device, and each entry in a set is a partition on that device. The first entry in a set is the entire device. /dev/nftlb, for instance, is the second NFTL device in its entirety, while /dev/nftlb3 is the third partition on the second NFTL device.

ftlLN

Same as NFTL.

As we'll see later, you don't need to create all these entries manually on your host. You will, however, need to create some of these entries manually on your target's root filesystem to use the corresponding MTD user module. Also, note that the naming scheme described above differs slightly from the one described in the devices.txt file mentioned earlier. The naming scheme presented here is the one used in practice.

7.1.1.2 Configuring the kernel

As I mentioned in Chapter 5, the configuration of the MTD subsystem is part of the main menu of the kernel configuration options. Whether you are configuring the kernel using the curses-based terminal configuration menu or through the Tk-based X Window configuration menu, you will need to enter the "Memory Technology Devices (MTD)" submenu to configure the MTD subsystem for your kernel.

The MTD submenu contains a list of configuration options that you can choose to build as part of the kernel, build as separate modules, or disable completely. Here are the main options you can configure in the MTD submenu:

Memory Technology Device (MTD) support, CONFIG_MTD

Enable this option if you want to include core MTD subsystem support. If you disable this option, this kernel will not have any MTD support. When this option is set to be built as a module, the resulting functionality is found in the module called mtdcore.o.

MTD partitioning support, CONFIG_MTD_PARTITIONS

Enable this option if you want to be able to divide your MTD devices into separate partitions. If you compile this as a module, the module's filename is mtdpart.o. Note that MTD partitioning does not apply to DOC devices. These devices are partitioned using conventional disk partitioning tools.

Direct char device access to MTD devices, CONFIG_MTD_CHAR

This is the configuration option for the char device MTD user module that is visible as /dev/mtdN and /dev/mtdrN. If you configure this as a module, the module's filename is mtdchar.o.

Caching block device access to MTD devices, CONFIG_MTD_BLOCK

This is the configuration option for the read-write block device MTD user module that is visible as /dev/mtdblockN. If you configure this as a module, the module's filename is mtdblock.o.

Read-only block device access to MTD devices, CONFIG_MTD_BLOCK_RO

This is the configuration option for the read-only block device MTD user module that is visible using the same /dev entries as the read-write block device. If you configure the read-only block device user module as a module, the module's filename is mtdblock_ro.o.

FTL (Flash Translation Layer) support, CONFIG_FTL

Set this option if you would like to include the FTL user module in your kernel. When configured as a module, the module's filename is ftl.o. The FTL user module is accessible through the /dev/ftlLN device entries.

NFTL (NAND Flash Translation Layer) support, CONFIG_NFTL

Set this option if you would like to include the NFTL user module in your kernel. When configured as a module, the module's filename is nftl.o. The NFTL user module is accessible through the /dev/nftlLN device entries.

Write support for NFTL (BETA), CONFIG_NFTL_RW

You must enable this option if you want to be able to write to your NFTL-formatted devices. This will only influence the way the NFTL user module is built and is not a separate user module in itself.

Notice that only one of the two block device MTD user modules can be built in the kernel, although both can be configured as modules (mtdblock.o and mtdblock_ro.o). In other words, if you set the read-write block device user module to be built into the kernel?not as a module?you will not be able to configure the read-only block device user module, either built-in or as a module. As we saw earlier, both block device MTD user modules use the same /dev entry, and cannot therefore be active simultaneously.

The preceding list is primarily made up of the user modules I described earlier. The remaining MTD user modules, JFFS and JFFS2, are not configured as part of the MTD subsystem configuration. Rather, they are configured within the "File systems" submenu. Nevertheless, you will need to enable MTD support to enable support for either JFFS or JFFS2.

The MTD submenu also contains four submenus to configure support for the actual MTD hardware device drivers. Here are the submenus found in the MTD submenu and their descriptions:

RAM/ROM/Flash chip drivers

Contains configuration options for CFI-Compliant flash, JEDEC-compliant flash, old non-CFI flash, RAM, ROM, and absent chips.

Mapping drivers for chip access

Contains configuration options for mapping drivers. Includes one generic mapping driver that can be configured by providing the physical start address of the device and its size in hexadecimal notation, and its bus width in octets. This submenu also contains one entry for each board for which there is an existing mapping driver included in the kernel.

Self-contained MTD device drivers

Contains configuration options for uncached system RAM, virtual memory test driver, block device emulation driver, and DOC devices.

NAND Flash Device Drivers

Contains configuration options for non-DOC NAND flash devices.

Before configuring your kernel's MTD subsystem, make sure you have read the MTD subsystem discussion in Chapter 3, since many of the options described here were amply covered in my earlier discussion.

When configuring the kernel for your host, you will find it useful to configure all the MTD subsystem options as modules, since you will be able to test different device setup combinations. For your target, however, you will need to compile all the options required to support your solid state storage device as part of your kernel rather than as modules. Otherwise, your target will not be able to mount its root filesystem from its solid state storage device. If you forget to configure your target's kernel so that it can mount its root filesystem from the MTD device, your kernel will panic during startup and complain about its inability to mount its root filesystem with a message similar to the following:

Kernel panic: VFS: unable to mount root fs on ...
7.1.1.3 The MTD utilities

Because the MTD subsystem's functionality is different from that of other kernel subsystems, a special set of utilities is required to interact with it. We will see in the next sections how to obtain and install these utilities. For now, let's take a look at the available tools and their purposes.

The MTD utilities are powerful tools. Make sure you understand exactly the operations being performed by a tool before using it. Also, make sure you understand the particularities of the device on which you are using the tools. DOC devices, for example, require careful manipulation. You can easily damage your DOC device if you do not use the MTD tools appropriately.

Within the MTD tool set, there are different categories of tools, each serving a different MTD subsystem component. Here are the different tool categories and the tools they contain:

Generic tools

These are the tools that can be used with all types of MTD devices:

einfo device

Provides information regarding a device's erase regions.

erase device start_address number_of_blocks

Erases a certain number of blocks from a device starting at a given address.

eraseall [options] device

Erases the entire device.

unlock device

Unlocks[3] all the sectors of a device.

[3] Some devices can be protected from accidental writes using write "locks." Once a device, or some portion of it, is locked, it cannot be written to until it is unlocked.

lock device offset number_of_blocks

Locks a certain number of blocks on a device.

fcp [options] filename flash_device

Copies a file to a flash_device.

doc_loadbios device firmware_file

Writes a bootloader to the device's boot region. Though this command is usually used with DOC devices only, it is not DOC specific.

mtd_debug operation [operation_parameters]

Provides useful MTD debugging operations.

Filesystem creation tools

These tools create the filesystems that are later used by the corresponding MTD user modules:

mkfs.jffs2 [options] -r directory -o output_file

Builds a JFFS2 filesystem image from a directory.

mkfs.jffs [options] -d directory -o output_file

Builds a JFFS filesystem image from a directory.

jffs2reader image [options] path

Lists the content of a path in the JFFS2 filesystem image.

NFTL tools

These tools interact with NFTL partitions:

nftl_format device [start_address [size]]

Formats a device for use with the NFTL user module.

nftldump device [output_file]

Dumps the content of an NFTL partition to a file.

FTL tools

These tools interact with FTL partitions:

ftl_format [options] device

Formats an FTL device.

ftl_check [options] device

Checks and provides information regarding an FTL device.

NAND chip tools

These tools are provided for manipulating NAND chips:

nandwrite device input_file start_address

Writes the content of a file to a NAND chip.

nandtest device

Tests NAND chips, including those in DOC devices.

nanddump device output_file [offset] [number_of_bytes]

Dumps the content of a NAND chip to a file.

Most of these tools are used on /dev/mtdN devices, which are the char device interfaces to the various MTD devices. I will describe the typical uses of the most important MTD tools over the next few chapters, covering the actual MTD hardware in this chapter, preparation of the root filesystem in Chapter 8, and the boot setup in Chapter 9.

7.1.1.4 Installing the MTD utilities for the host

The MTD utilities are maintained as part of the MTD development CVS. You can retrieve the latest tool versions using CVS. You can also download a CVS snapshot from ftp://ftp.uk.linux.org/pub/people/dwmw2/mtd/cvs/. For my DAQ module, I am using the snapshot dated 2002-07-31.

Download the snapshot of your choice to your ${PRJROOT}/build-tools directory and extract it. You can then move to this directory and prepare to compile the tools:

$ cd ${PRJROOT}/build-tools/mtd/util
$ automake --foreign; autoconf
$ ./configure --with-kernel=/usr/src/linux

When issuing the configure command, you must provide the path to the kernel that will be used to compile the tools. Since you are building the tools for your host, you need to provide the path to your host's kernel sources. By default, these should be located at /usr/src/linux.

As in other build scenarios, configure builds the Makefile required to compile the tools. You can now compile the tools:

$ make clean
$ make

Make sure you issue the make clean command, as there are files in the utilities source code that need to be deleted to allow symbolic links with the same names to be created to files in the kernel sources.

If the build process fails while compiling compr.c because of an undefined KERN_WARNING symbol, you will need to edit the Makefile.am file and replace the following lines:

compr.o: compr.c
        $(COMPILE) $(CFLAGS) $(INCLUDES) -Dprintk=printf \
        -DKERN_NOTICE= -c -o $@ $<

with:

compr.o: compr.c
        $(COMPILE) $(CFLAGS) $(INCLUDES) -Dprintk=printf \
        -DKERN_WARNING= -DKERN_NOTICE= -c -o $@ $<

Once you have completed the modification, you will need to restart the build from the start, as already described, after having issued a make distclean command.

With the utilities built, you can now install them in your tools directory:

$ make prefix=${PREFIX} install

This will install the utilities in ${PREFIX}/sbin. You will need to add this directory to your path, if it's not already part of it. See my earlier explanation in Chapter 4 about installing uClibc's utilities for a complete description on how to add a new directory to your development path.

Now that the utilities have been installed, you need to create the MTD device entries in your host's /dev directory. The MAKEDEV script found in the util directory takes care of the device creation. Have a look inside this file if you are interested in the devices being created. MAKEDEV mainly creates the /dev entries I covered earlier in Section 7.1.1.1. Because MAKEDEV uses the mknod command, you will need to run it as root:

# ./MAKEDEV

Although you may later want to update your MTD tool set, you should not need to use MAKEDEV again. If your MTD devices are accessible on the host because you are using the removable storage setup or the standalone setup we discussed in Chapter 2, you are ready to manipulate your MTD devices immediately. If you are using the linked setup or want to use the MTD utilities on your target in a removable storage setup, read the next section for instructions on how to build the MTD utilities for your target.

7.1.1.5 Installing the MTD utilities for the target

To install the MTD utilities for your target, you need to first download and install zlib. Earlier, when you installed the MTD utilities on your host, you didn't need to install zlib, because zlib is part of most mainstream distributions. Zlib is available at http://www.gzip.org/zlib/. For my DAQ module, I used zlib 1.1.4.

Download zlib and extract it in your ${PRJROOT}/build-tools directory. You can then move to the library's directory to prepare its compilation:

$ cd ${PRJROOT}/build-tools/zlib-1.1.4
$ CC=i386-linux-gcc LDSHARED="i386-linux-ld -shared" \
> ./configure --shared

By default, the zlib build process generates a static library. To build zlib as a shared library, you must set the LDSHARED variable and provide the - -shared option when invoking configure. With the Makefile created, you can compile and install the library:

$ make
$ make prefix=${TARGET_PREFIX} install

As with the other target libraries we installed earlier, we install zlib in ${TARGET_PREFIX}/lib. Once the library is installed, you can install it on your target's root filesystem:

$ cd ${TARGET_PREFIX}/lib
$ cp -d libz.so* ${PRJROOT}/rootfs/lib

You are now ready to build the MTD utilities. Download the MTD snapshot into your ${PRJROOT}/sysapps and extract it. Now move into the utilities directory and build the tools:

$ cd ${PRJROOT}/sysapps/mtd/util
$ automake --foreign; autoconf
$ CC=i386-linux-gcc ./configure \
> --with-kernel=${PRJROOT}/kernel/linux-2.4.18
$ make clean
$ make

In this case, the kernel path points to your target's kernel. As in the previous section, if the build process fails while compiling compr.c because of an undefined KERN_WARNING symbol, you will need to edit the Makefile.am file, make the appropriate changes, and restart the build from the beginning after issuing make distclean.

With the utilities built, you can now install them in your target's root filesystem:

$ make prefix=${PRJROOT}/rootfs install

This will install the utilities in ${PRJROOT}/rootfs/sbin. We will not run the MAKEDEV script here, because it is not well adapted to creating device entries other than on the root filesystem of the system on which it runs. If you want to use the script as is, you would have to copy it to your target's root filesystem and then run it once you have the target running. This, however, would waste filesystem resources on the target, since the script creates entries for all the MTD devices you can possibly have in a system. We will see in the following sections how to create just the devices needed on the target's root filesystem.

How NOR and NAND Flash Work

Flash devices, including NOR flash devices such as CFI flash chips and NAND flash devices such as the DOC, are not like disk storage devices. They cannot be written to and read from arbitrarily. To understand how to operate flash chips properly, we must first look at how they operate internally. Flash devices are generally divided into erase blocks. Initially, an empty block will have all its bits set to 1. Writing to this block amounts to clearing bits to 0. Once all the bits in a block are cleared (set to 0), the only possible way to erase this block is to set all of its bits to 1 simultaneously. With NOR flash devices, bits can be set to 0 individually in an erase block until the entire block is full of 0s. NAND flash devices, on the other hand, have their erase blocks divided further into pages, of 512 bytes typically, which can only be written to a certain number of times?typically less than 10 times?before their content becomes undefined. Pages can then only be reused once the blocks they are part of are erased in their entirety.

7.1.2 Native CFI Flash

Most recent small-to-medium-sized non-x86 embedded Linux systems are equipped with some form of CFI flash. Setting up CFI flash to be used with Linux is relatively easy. In this section, we will discuss the set up and manipulation of CFI devices in Linux. We will not discuss the use of filesystems on such devices, however, since these will be covered in the next chapter. The order to the subsections below tries to follow the actual steps involved in using CFI flash devices with Linux as much as possible. You can, nevertheless, use these instructions selectively according to your current manipulation.

7.1.2.1 Kernel configuration

You will need to enable kernel support for the following options to use your CFI flash device:

  • Memory Technology Device (MTD) support

  • MTD partitioning support, if you would like to partition your flash device

  • Direct char device access to MTD devices

  • Caching block device access to MTD devices

  • In the "RAM/ROM/Flash chip drivers" submenu, Detect flash chips by Common Flash Interface (CFI) probe

  • In the "Mapping drivers for chip access" submenu, the CFI flash device mapping driver for your particular board

You may also choose to enable other options, but these are the bare minimum. Also, remember to set the options to "y" instead of "m" if you intend to have the kernel mount its root filesystem from the CFI device.

7.1.2.2 Partitioning

Unlike disk or DOC devices, CFI flash cannot generally be partitioned using tools such as fdisk or pdisk, because partition information is not usually stored on CFI flash devices. Instead, the device's partitions are hardcoded in the mapping driver and are registered with the MTD subsystem during the driver's initialization. The actual device does not contain any partition information whatsoever. You will, therefore, have to edit the mapping driver's C source code to modify the partitions.

Take TQM8xxL PPC boards, for instance, which are good candidates for my control module. Such boards can contain up to two 4 MB flash banks. Each 32 bit-wide memory addressable flash bank is made of two 16 bit-wide flash chips. To define the partitions on these boards, the boards' mapping driver contains the following structure initializations:

static struct mtd_partition tqm8xxl_partitions[  ] = {
    {
        name:   "ppcboot",                        /* PPCBoot Firmware */
        offset: 0x00000000,
        size:   0x00040000,                       /* 256 KB */
    },
    {
        name:   "kernel",                         /* default kernel image */
        offset: 0x00040000,
        size:   0x000C0000,
    },
    {
        name:   "user",
        offset: 0x00100000,
        size:   0x00100000,
    },
    {
        name:   "initrd",
        offset: 0x00200000,
        size:   0x00200000,
    }
};

static struct mtd_partition tqm8xxl_fs_partitions[  ] = {
    {
        name:   "cramfs",
        offset: 0x00000000,
        size:   0x00200000,
    },
    {
        name:   "jffs2",
        offset: 0x00200000,
        size:   0x00200000,
    }
};

In this case, tqm8xxl_partitions defines four partitions for the first 4 MB flash bank, and tqm8xxl_fs_partitions defines two partitions for the second 4 MB flash bank. Three attributes are defined for each partition: name, offset, and size.

A partition's name is an arbitrary string meant only to facilitate human usability. This name is not used by either the MTD subsystem or the MTD utilities to enforce any sort of structure on said partition. The offset is used to provide the MTD subsystem with the start address of the partition, while the size is self-explanatory. Notice that each partition on a device starts where the previous one ended; no padding is necessary. Table 7-3 presents the actual physical memory address ranges for these partitions on a TQM860L board where the two 4 MB banks are mapped consecutively starting at address 0x40000000.

Table 7-3. Flash device partition physical memory mapping for TQM860L board

Device

Start address

End address

Partition name

0

0x40000000

0x40040000

ppcboot

0

0x40040000

0x40100000

kernel

0

0x40100000

0x40200000

user

0

0x40200000

0x40400000

initrd

1

0x40400000

0x40600000

cramfs

1

0x40600000

0x40800000

jffs2

During the registration of this device's mapping, the kernel displays the following message:

TQM flash bank 0: Using static image partition definition
Creating 4 MTD partitions on "TQM8xxL Bank 0":
0x00000000-0x00040000 : "ppcboot"
0x00040000-0x00100000 : "kernel"
0x00100000-0x00200000 : "user"
0x00200000-0x00400000 : "initrd"
TQM flash bank 1: Using static file system partition definition
Creating 2 MTD partitions on "TQM8xxL Bank 1":
0x00000000-0x00200000 : "cramfs"
0x00200000-0x00400000 : "jffs2"

You can also see the partitions by looking at /proc/mtd. Here is its content for my control module:

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00020000 "ppcboot"
mtd1: 000c0000 00020000 "kernel"
mtd2: 00100000 00020000 "user"
mtd3: 00200000 00020000 "initrd"
mtd4: 00200000 00020000 "cramfs"
mtd5: 00200000 00020000 "jffs2"

Notice that the partitions are on erase size boundaries. Because flash chips are erased by block, not by byte, the size of the erase blocks must be taken in account when creating partitions. In this case, erase blocks are 128 KB in size, and all partitions are aligned on 128 KB (0x20000) boundaries.

Another Way to Provide MTD Partition Information

For some time now, the MTD subsystem has been able to accept partition information as part of the kernel boot options for the ARM architecture. This capability is used by the iPAQ Familiar distribution to provide the iPAQ's kernel with the partition information for the device's CFI flash chips.

Lately, a generalized form of this capability for all the architectures has been integrated into the main MTD source code CVS repository. Though these changes had not yet made their way into the main kernel tree at the time of this writing, they will eventually be integrated and, therefore, enable the passing of the partition information at the kernel boot options on all architectures supported by Linux.

Here is an example boot option line used to provide the kernel with the same partition information provided in the previous section for the TQM8xxL board (the line appears wrapped on the page, but must be written as a single line):

mtdparts=0:256k(ppcboot)ro,768k(kernel),1m(user),-(initrd);1:2m(cramfs),-
    (jffs2)

7.1.2.3 Required /dev entries

You need to create /dev entries for the char device and block device MTD user modules to access your CFI flash device. Create as many entries for each type of user module as you have partitions on your device. For example, the following commands create root filesystem entries for the six partitions of my TQM860L board:

$ cd ${PRJROOT}/rootfs/dev
$ su -m
Password:
# for i in $(seq 0 5)
> do
> mknod mtd$i c 90 $(expr $i + $i)
> mknod mtdblock$i b 31 $i
> done
# exit

Here are the resulting entries:

$ ls -al mtd*
crw-rw-r--    1 root     root      90,   0 Aug 23 17:19 mtd0
crw-rw-r--    1 root     root      90,   2 Aug 23 17:20 mtd1
crw-rw-r--    1 root     root      90,   4 Aug 23 17:20 mtd2
crw-rw-r--    1 root     root      90,   6 Aug 23 17:20 mtd3
crw-rw-r--    1 root     root      90,   8 Aug 23 17:20 mtd4
crw-rw-r--    1 root     root      90,  10 Aug 23 17:20 mtd5  
brw-rw-r--    1 root     root      31,   0 Aug 23 17:17 mtdblock0
brw-rw-r--    1 root     root      31,   1 Aug 23 17:17 mtdblock1
brw-rw-r--    1 root     root      31,   2 Aug 23 17:17 mtdblock2
brw-rw-r--    1 root     root      31,   3 Aug 23 17:17 mtdblock3
brw-rw-r--    1 root     root      31,   4 Aug 23 17:17 mtdblock4
brw-rw-r--    1 root     root      31,   5 Aug 23 17:17 mtdblock5
7.1.2.4 Erasing

Before you can write to a CFI flash device, you need to erase its content. This can be done using one of the two erase commands available as part of the MTD utilities, erase and eraseall.

Before updating the initial RAM disk on my control module, for example, I need to erase the "initrd" partition:

# eraseall /dev/mtd3
Erased 2048 Kibyte @ 0 -- 100% complete.
7.1.2.5 Writing and reading

Whereas flash filesystems such as JFFS2 take advantage of the capability of continuing to set bits to 0 in an erase block to allow transparent read and write access, you cannot usually use user-level tools to write to an MTD device more than once. If you want to update the content of an MTD device or partition using its raw char /dev entry, for example, you must usually erase this device or partition before you can write new data to it.

Writing to a raw flash device can be done using traditional filesystem commands such as cat and dd. After erasing the "initrd" partition on my control module, for example, I use the following command to write a new initial RAM disk image to the designated partition:

# cat /tmp/initrd.bin > /dev/mtd3

In this case, my target's root filesystem is mounted via NFS, and I am running the MTD commands on my target. I could have also used the dd command instead of cat. Nevertheless, the end result is the same in this case.

Reading from a CFI MTD partition is no different from reading from any other device. The following command on my control module, for instance, will copy the binary image of the bootloader partition to a file:

# dd if=/dev/mtd0 of=/tmp/ppcboot.img

Since the bootloader image itself may not fill the entire partition, the ppcboot.img file may contain some extra unrelated data in addition to the bootloader image.

7.1.3 DiskOnChip

DOC devices are quite popular in x86-based embedded Linux systems, and the MTD subsystem goes a long way in providing support for them. I use it, for example, in my DAQ module. It remains that the DOC is a peculiar beast that requires an attentive master. The reasons for such a statement will become evident shortly.

7.1.3.1 Preliminary manipulations

Unlike most other devices found in embedded Linux systems, you will need to equip yourself with, at the very least, a bootable DOS diskette loaded with M-Systems' DOS DOC tools to make proper use of any DOC device. There are two basic reasons for this:

  • Like all NAND flash devices, DOC devices can contain a certain number of manufacturing defects that result in bad blocks. Before a DOC device is shipped from the factory, a Bad Block Table (BBT) is written on it. Although this table is not write-protected, it is essential to the operation of all software that reads and writes to a DOC. As such, M-Systems' DOC software is capable of reading this table and storing it to a file. Linux, however, does not currently have any utility to retrieve this table.

  • The NFTL driver included in most 2.4.x kernels (up to 2.4.19 at least) is unable to deal with some versions of the M-Systems' DOC firmware. Versions 5.0 and later are the most likely to cause problems. Hence, you may need to replace your DOC's current firmware with an older version, using M-Systems' tools, for Linux to operate with your device properly. Currently, the firmware provided with Version 4.2 of M-Systems' TrueFFS tools works fine with all kernels.

In addition, there are two ways to install a bootloader on the DOC and format it for NFTL. The first, which is most recommended by the MTD maintainer, is to use M-Systems' dformat DOS utility. The second, which gives you the greatest degree of control over your DOC device from within Linux, is to use the doc_loadbios and nftl_format MTD utilities. We will discuss both methods in the following sections.

M-Systems' DOS DOC tools and related documentation are available from the company's web site at http://www.m-sys.com/. If you plan to use the Linux method to install a bootloader on the DOC and format it, you need both Version 4.2 and Version 5.0 or later of M-Systems' tools. If you plan to use the DOS method, you only need Version 5.0 or later of the M-Systems tools. At the time of this writing, the latest version is 5.1.2. The example below is based on a 32 MB DOC 2000 device. The output of the various tools will depend on the actual device you are using, but should closely resemble the output presented here.

Start by preparing a DOS diskette with the latest tools. Once you have prepared the DOS diskette, boot the system containing your DOC device with that diskette. Now, use the tools as follows:[4]

[4] See M-Systems' manuals for a full explanation of the tools' semantics and usage.

  1. Using Version 5.0 or later of the DOC tools, make a copy of the BBT:

    A:\>dformat /win:d000 /noformat /log:docbbt.txt
    DFORMAT Version 5.1.0.25 for DOS
    Copyright (C) M-Systems, 1992-2002
    
    DiskOnChip 2000 found in 0xd0000.
    32M media, 16K unit
    
    OK

    The dformat command is usually used to format the DOC for use with DOS. In this case, we instruct dformat not to format the device by using the /noformat option. In addition, we instruct it to record the BBT of the device starting at segment 0xD000[5] to the docbbt.txt file. Once dformat finishes retrieving the BBT, store a copy of docbbt.txt in a safe repository, since you may have to restore it if you erase the entire DOC device in Linux. Have a look at M-Systems' dformat documentation for information on how to restore a lost BBT.

    [5] "Real-mode" addresses on the PC are represented using a segment and offset couple in the following way: segment:offset. It's usually shorter to provide just the segment whenever the offset is null. In this case, for example, segment 0xD000 starts at address 0xD0000, as is displayed by dformat in its output.

    Note that your DOC device may be free of bad blocks. In that case, the docbbt.txt will be empty and you will not need to worry about restoring the BBT if you erase the device completely.

    If you are using the DOS method to install a bootloader and format the DOC, you are done with the preliminary manipulations and should proceed immediately to the next section, Section 7.1.3.2.

  2. Using Version 5.0 or later of the DOC tools, check the firmware version:

    A:\>dinfo /exb
    
                               D I N F O - utility
                      Version 5.1.1.1.0, Last Update: 17 Jun 2002
                       Copyright (C) M-Systems, 1992 - 2001
                     ---------------------------------------- 
     GENERAL INFO.
    --------------
    --------------
            Physical Address:  0xD0000
            DiskOnChip Type :  DiskOnChip 2000
            Flash Type      :  Toshiba TC58128
            FormatType      :  NFTL
            TrueFFS version :  5.1
            Driver Version  :  DOS
            Sectors         :  4
            Heads           :  16
            Cylinders       :  1001
            Boot Area Size  :  49152 Bytes
            Logical Sectors :  64064
            Phy. UnitSize   :  16384 Bytes
            Physical Size   :  33554432 (32 MB)
            Unit Size       :  16384 Bytes
            Media Size      :  33554432 Bytes (32 MB)
            Chip Size       :  16777216 Bytes (16 MB)
            No Of Chips     :  2
            Interleaving    :  1
     
     EXB INFO.
    -----------
    -----------
    
            Version      :  4.2
            Copyright    :  SPL_DiskOnChip (c) M-Systems
            RunTime ID   :  0xC3
            Exb Flags    :  No Flags Found

    The dinfo command displays a lot of information. You can identify the version of the firmware by looking at the Version line in the EXB INFO section. In this case, the firmware version is 4.2. Do not be confused by the TrueFFS version line in the GENERAL INFO section. This is not the firmware version.

  3. If your firmware is Version 5.0 or later, update the firmware version using Version 4.2 of the DOC tools:

    A:\>dformat /win:d000 /s:doc42.exb
    DFORMAT Version 3.3.9 for DiskOnChip 2000 (V4.2)
    Copyright (C) M-Systems, 1992-2000
     
    Driver not loaded - using direct access
    WARNING: All data on DiskOnChip 2000(R) will be destroyed. Continue ? (Y/N)y
    
    Medium physical size is 32768 KBytes
    Boot-image size is 48 KBytes
     
    Finished 32768 KBytes
    Writing Boot-Image
    Format complete. Formatted size is 32032 KBytes.
    Please reboot to let DiskOnChip 2000(R) install itself.

    Once you have formatted the chip with Version 4.2 of the firmware, I recommend that you power-cycle your system. Shut the system off and then put it back on. A simple reboot may work to get the firmware installed properly, but a full power-cycle is necessary on some systems.

You are now ready to use your DOC device with Linux.

7.1.3.2 Kernel configuration

At the time of this writing, if you are using the DOS method to install a bootloader and format the DOC, you need to patch your kernel with the latest MTD code from the MTD CVS repository to proceed. See the MTD project's web site (http://www.linux-mtd.infradead.org/) for information on how to retrieve the code from the CVS repository.

You will need to enable kernel support for the following options to use your DOC device:

  • Memory Technology Device (MTD) support

  • MTD partitioning support, if you would like to partition your flash device

  • Direct char device access to MTD devices

  • NFTL (NAND Flash Translation Layer) support

  • Write support for NFTL (BETA)

  • In the "Self-contained MTD device drivers" submenu, M-Systems Disk-On-Chip 2000 and Millennium

As with CFI flash, you may choose to select other options. If you compile the options just listed as modules, the DOC support will be separated in three files, docecc.o, doc2000.o, and docprobe.o. Issuing a modprobe docprobe command should load all three modules automatically. Whether it is part of the kernel or loaded as a module, the DOC probe driver will analyze potential memory addresses for DOC devices. For each memory address it analyzes, the probe driver outputs a message regarding its findings. Here is an example of output from the probe driver on my DAQ module:

Possible DiskOnChip with unknown ChipID FF found at 0xc8000
...
Possible DiskOnChip with unknown ChipID FF found at 0xce000
DiskOnChip 2000 found at address 0xD0000
Flash chip found: Manufacturer ID: 98, Chip ID: 73 (Toshiba TH58V128DC)
2 flash chips found. Total DiskOnChip size: 32 MiB
Possible DiskOnChip with unknown ChipID FF found at 0xd2000
Possible DiskOnChip with unknown ChipID FF found at 0xd4000
...

M-Systems' DOC Driver

M-Systems provides a DOC driver for Linux as part of their Linux tools packages. This driver, however, is not under the GPL and you can use it only as a loadable kernel module. Distributing a kernel with this driver built in is a violation of the GPL. Hence, if you want to boot from a DOC with a kernel that uses M-Systems' driver, you need to use an init RAM disk to load the binary driver. Also, postings on the MTD mailing list suggest that the driver uses a lot of system resources and can sometimes cause data loss on the serial port. For these reasons, I recommend that you avoid using M-Systems' Linux DOC driver. Instead, use the GPL MTD drivers, as I describe here.

7.1.3.3 Required /dev entries

You need to create /dev entries for the char device and the NFTL MTD user modules in order to access your DOC device. Create as many char device entries and sets of NFTL entries as you have DOC devices in your system. For each NFTL set, create as many entries as you will create partitions on your device. For my DAQ module, for instance, I have one DOC device with only one main partition. I use the following commands to create the relevant entries:

$ cd ${PRJROOT}/rootfs/dev
$ su -m
Password:
# mknod mtd0 c 90 0
# mknod nftla b 93 0
# mknod nftla1 b 93 1
# exit

Here are the resulting entries:

$ ls -al mtd* nftl*
crw-rw-r--    1 root     root      90,   0 Aug 29 12:48 mtd0
brw-rw-r--    1 root     root      93,   0 Aug 29 12:48 nftla
brw-rw-r--    1 root     root      93,   1 Aug 29 12:48 nftla1
7.1.3.4 Erasing

Erasing a DOC device is done in very much the same way as other MTD devices, using the erase and eraseall commands. Before using any such command on a DOC device, make sure you have a copy of the BBT, because an erase of the device will wipe out the BBT it contains.

To erase the entire DOC device in my DAQ modules, for instance, I use the following command on my DAQ module:

# eraseall /dev/mtd0
Erased 32768 Kibyte @ 0 -- 100% complete.

Typically, you will need to erase a DOC device only if you want to erase the bootloader and the current format on the device. If you installed a Linux bootloader, for example, and would like to revert back to M-Systems' SPL, you will need to use the eraseall command before you can install M-Systems' SPL with M-Systems' tools. Whenever you erase the entire device, however, you need to use M-Systems' tools to restore the BBT.

7.1.3.5 Installing bootloader image

If your target does not boot from its DOC device, you can skip this step. Otherwise, you need to build the bootloader, as I describe in Chapter 9, before going any further. First, nonetheless, let's see how a system boots from the DOC.

During system startup on x86 systems, the BIOS scans the memory for BIOS extensions. When such an extension is found, it is executed by the BIOS. DOC devices contain a ROM program called the Initial Program Loader (IPL) that takes advantage of this characteristic to install another program called the Secondary Program Loader (SPL) that acts as a bootloader during system startup. By default, the SPL is provided by M-Systems' own firmware. To boot Linux from a DOC device, however, the SPL must be replaced with a bootloader able to recognize the format used by Linux on a DOC. We will discuss the various DOC-capable Linux bootloaders in Chapter 9. For now, let us take a look at how we can install our own SPL on a DOC.

Here is the command I use to install the GRUB bootloader image, grub_firmware, on the DOC in Linux:

# doc_loadbios /dev/mtd0 grub_firmware
Performing Flash Erase of length 16384 at offset 0
Performing Flash Erase of length 16384 at offset 16384
Performing Flash Erase of length 16384 at offset 32768
Performing Flash Erase of length 16384 at offset 49152
Performing Flash Erase of length 16384 at offset 65536
Performing Flash Erase of length 16384 at offset 81920
Writing the firmware of length 92752 at 0... Done.

Here is the command I use to install the GRUB bootloader image on the DOC in DOS:

A:\>dformat /win:d000 /bdkf0:grub_firmware
DFORMAT Version 5.1.0.25 for DOS
Copyright (C) M-Systems, 1992-2002
WARNING: All data on DiskOnChip will be destroyed. Continue ? (Y/N)y

DiskOnChip 2000 found in 0xd0000.
32M media, 16K unit

Formatting               2042
Writing file to BDK 0    92752
OK
Please reboot to let DiskOnChip install itself.

As with updating the firmware version earlier, you need to power-cycle your system after using doc_loadbios or dformat for the firmware to be installed properly. That said, do not use doc_loadbios or dformat before reading the explanations pertaining to its use with a bootloader in Chapter 9.

7.1.3.6 NFTL formatting

Currently, the only way to use DOC devices in Linux is to format them for NFTL. Once we format a DOC device for NFTL, we can use conventional block device tools and filesystems in conjunction with the device.

If you would like to boot from the DOC, read the sections in Chapter 9 regarding x86 bootloaders before carrying out any further operations on your DOC.

If you used the dformat utility earlier to install GRUB on the DOC, your DOC is already formatted for NFTL. If you used doc_loadbios in Linux, you must use the nftl_format command to format the device for NFTL.

The following MTD command formats the entire DOC device for NFTL:

# nftl_format /dev/mtd0
$Id: ch07.xml,v 1.3 2003/05/01 21:52:06 madd Exp madd $
Phase 1. Checking and erasing Erase Zones from 0x00000000 to 0x02000000
        Checking Zone #2047 @ 0x1ffc000
Phase 2.a Writing NFTL Media Header and Bad Unit Table
Phase 2.b Writing Spare NFTL Media Header and Spare Bad Unit Table
Phase 3. Writing Unit Control Information to each Erase Unit

This command takes some time to go through the various zones on the DOC. Should nftl_format encounter bad blocks on the DOC, it outputs the following message:

Skipping bad zone (factory marked) #BLOCK_NUM @ 0xADDRESS

The BLOCK_NUM and ADDR values output by nftl_format should match the values found in the docbbt.txt file generated earlier.

For the nftl_format command to operate properly, it needs to have total control and exclusive access over the raw DOC device it is formatting. Total control is guaranteed by the fact that the commands provided earlier use the /dev/mtdX device entries. Because these entries are handled by the char device MTD user module, there is no conversion layer between the operations conducted on these devices and the actual hardware. Hence, any operation carried out by