This technote explains how to choose the correct MTD routine for your flash filesystem. Before you begin, you should first review the descriptions of all available MTD callouts for a flash driver. See “Building your flash filesystem driver” in Customizing the Flash Filesystem chapter of the Building Embedded Systems guide.
The MTD callouts are as follows:
Callout | Description |
---|---|
ident() | Identify the flash chip(s) |
reset() | Return flash to read state after an error |
read() | Read data from flash (if NULL, an internal memcpy() is used) |
write() | Write data to flash |
erase() | Erase a flash block (aka “unit”) |
sync() | Poll for erase completion |
suspend() | Suspend an erase for a read/write operation (if supported) |
resume() | Resume a suspended erase after a read/write operation (if supported) |
islock() | Determine whether a block/unit is write protected |
lock() | Write-protect a block |
unlock() | Disable write protection |
unlockall() | Invoke a single command to unlock the whole chip (if supported) |
Although we refer to the callouts in this technote using the general notation above,
the source code for the MTD libraries contains different API versions. The
exact callouts available for the two versions of the library (MTDv1 and MTDv2) are:
|
Ideally, there should be a table that describes every combination of board and flash in existence, and tells you which callout to use. Since this is unrealistic, this technote focuses mainly on describing a general method for choosing the right combination of MTD callouts. You will need to:
As a first step, you should determine whether your board has an unusual flash configuration. In a standard flash configuration, the flash should be located at a contiguous physical memory address that can be directly mapped, read, and written to by software. Usually, the chips are allowed to be interleaved for performance/bus-width reasons.
Here are some examples of nonstandard flash configurations:
If your board has any such unusual configuration, don't hesitate to consult your QNX Software Systems representative.
You can find the complete source to the MTD driver library under bsp_root/libs/src/hardware/flash/mtd-flash.
The callouts are grouped by manufacturer (e.g. intel/iCFI_write.c). Each of these files contains enough comments to detail the type of flash they work with. These comment-blocks provide the most up-to-date information on selecting the right MTD callout. Don't be afraid to look at these files.
Since the MTD source code is organized by manufacturer, your next step is to determine the manufacturer. Look at the board itself or read the flash's datasheet. Flash components made by different manufacturers are usually not compatible with each other.
To date, we support flash from these manufacturers: Intel and FASL LLC (Spansion/AMD/Fujitsu). |
There are also groups for SRAM and ROM — in this case there is only one choice for each callout, we don't discuss them here.
In most cases, setting the callout pointer to NULL is sufficient. This causes the MTD to use memcpy() to read directly from flash. You need to write a custom read callout if your board has special read restrictions.
Here is an example:
#include <sys/f3s_mtd.h> int32_t f3s_mtd_read(f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset, int32_t size, uint8_t *buffer) { uint8_t *memory; /* Set proper page on socket */ memory = (uint8_t *)access->service->page(&access->socket, F3S_POWER_ALL, offset, NULL); if (memory == NULL) { fprintf(stderr, "%s: %d page() returns NULL\n", __func__, __LINE__); return (-1); } /* Replace this memcpy with your special handling code */ memcpy(buffer, memory, size); return (size); }
There are currently two main choices available for ident() callouts: one for CFI and another for non-CFI. Most modern flash chips support the common flash interface (CFI) specification, a common method of identifying a flash chip and its capabilities. If your flash chip supports CFI, then you should always use the CFI-specific ident() callout. The alternative is to use a hard-coded table of recognized flash IDs. These non-CFI-specific ident() callouts usually require some customization and should be used as a last resort.
Flash can be written to either a word (8 or 16 bits) or a buffer (several words at a time). All chips support single-word writes, so it is always a conservative choice. More sophisticated chips such as Intel StrataFlash and AMD MirrorBit support buffered writes, which are significantly faster.
When consulting AMD's datasheets, don't confuse their “Unlock Bypass” write mode with their buffered write mode. The unlock bypass mode eliminates only the extra handshake between each word write. Real buffered write modes collect several words into an internal buffer and programs them in parallel.
Choosing an erase() callout is very straightforward; there is usually one to choose from.
For MTDv1, there are usually two main types of f3s_sync() callouts: one for boot-block flash and one for regular flash. The boot-block flash have two different sizes for erase blocks. The boot-block f3s_sync() callout needs to know the size of the block it wants to erase. The regular f3s_sync() callout doesn't need this extra logic. If you are not sure, pick the f3s_sync() for boot-block flash — it is slightly slower, but works for any kind of flash.
If you need to use a f3s_v2sync() callout, there's usually only one to choose from.
The f3s_v2sync() callout doesn't need to know the erase block size. The size is determined by the filesystem via a different API.
Flash chips either support suspend() and resume() callouts or they don't. This is evident from the datasheet. Like the erase() callout, there is usually only one choice.
Locking is new to the MTD version 2 library (MTDv2). Support for locking is evident from the datasheet. For chips that do support block-level write protection, there are two different implementations: persistent and volatile.