Mercurial > nand-ecoscentric
view packages/io/nand/current/doc/nand.sgml @ 3403:8c8767bb9a62 default tip
devs/nand/micron_mt29: Remove defunct references (in comments) to mt29f2g08_oob_ecc.
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Sun, 18 Jan 2015 17:59:01 +1300 |
| parents | 707de7f35fc7 |
| children |
line wrap: on
line source
<!-- {{{ Banner --> <!-- =============================================================== --> <!-- --> <!-- nand.sgml --> <!-- --> <!-- Documentation for the eCos NAND flash access library. --> <!-- --> <!-- =============================================================== --> <!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> <!-- =============================================================== --> <!-- Copyright (C) 2009 eCosCentric Ltd. --> <!-- This material may be distributed only subject to the terms --> <!-- and conditions set forth in the Open Publication License, v1.0 --> <!-- or later (the latest version is presently available at --> <!-- http://www.opencontent.org/openpub/) --> <!-- Distribution of the work or derivative of the work in any --> <!-- standard (paper) book form is prohibited unless prior --> <!-- permission obtained from the copyright holder --> <!-- =============================================================== --> <!-- ####ECOSDOCCOPYRIGHTEND#### --> <!-- =============================================================== --> <!-- #####DESCRIPTIONBEGIN#### --> <!-- --> <!-- Author(s): wry --> <!-- Date: 2009/04/17 --> <!-- --> <!-- ####DESCRIPTIONEND#### --> <!-- =============================================================== --> <!-- }}} --> <part id="io-nand-overview"> <title>The eCos NAND Flash Library</title> <titleabbrev id="io-nand-short">eCos NAND Flash Library</titleabbrev> <chapter id="nand-overview-c"> <title>NAND Library Overview</title> <sect1 id="nand-overview1"><title>Description</title> <para>This is a library which allows NAND flash devices to be accessed by the eCos kernel and applications. It is analogous to the eCos FLASH library, but for NAND devices. It exists as a separate library because of the fundamental differences between the two types of flash memory.</para> <para>This library provides the following functionality: <itemizedlist> <listitem><para>Interrogation to confirm that the expected device is present</para></listitem> <listitem><para>Reading from and writing to flash pages</para></listitem> <listitem><para>Erasing flash blocks</para></listitem> <listitem><para>The ability to divide a single device into multiple partitions, like those of a hard drive</para></listitem> <listitem><para>Creation and maintenance of a Bad Block Table</para></listitem> <listitem><para>Use of an Error Correcting Code to detect and correct single-bit errors, and to detect multiple-bit errors</para></listitem> <listitem><para>Packing of the ECC and application out-of-band data into the spare area on the device</para></listitem> </itemizedlist> <note><para>The spare area, ECC and bad block table have been deliberately created with the intention of compatibility with current versions of the Linux MTD layer. For example, this would allow a single NAND device to be accessed by RedBoot to load a Linux kernel, which could then go on to use another partition as its root filesystem.</para></note> </para> <tip><para>This library is also used as glue to allow appropriate filesystems to use NAND devices. This allows more useful higher-level access by applications and RedBoot via the File I/O and POSIX interfaces. In other words, your application may not need to invoke this library directly, though of course you may still have to write a driver for your chip and/or board. </para></tip> <sect2 id="nand-lib-structure"><title>Structure of the library</title> <para>This library has two principal interfaces: one for <emphasis>applications</emphasis> to call into it, and another to call out to the chip-specific <emphasis>drivers</emphasis>. (The chip drivers themselves then require support from the relevant platform HAL to allow them to access the physical chip in an appropriate manner for the board - such as the memory-mapped I/O range to use.)</para> <para>The following diagram illustrates the calls from two applications all the way to an underlying NAND device. Application 1 uses the NAND library directly, whereas application 2 is using a filesystem and the eCos File I/O layer.</para> <mediaobject> <imageobject> <imagedata fileref="nandlib-layout.png" align=center scalefit=1 depth=600> </imageobject> <textobject> <phrase>Library layout diagram</phrase> </textobject> </mediaobject> </sect2> <sect2 id="nand-lib-devsupport"><title>Device support</title> <para>Before this library can be used on a given board, an appropriate device driver must be created. Each driver is for a particular NAND part or family of parts; the HAL for each board then instantiates the relevant driver(s) appropriately with board-specific glue such as the memory-mapped I/O range to use. Full details on creating a driver are presented in <xref linkend="nand-devs-writing">.</para> <para>There is also a <xref linkend="devs-nand-synth"> for testing purposes, which is present on the <emphasis>synth</emphasis> target. </para> </sect2> </sect1> <SECT1 id="nand-danger"> <TITLE>Danger, Will Robinson! Danger!</TITLE> <PARA>Unlike nearly every other aspect of embedded system programming, getting it wrong with FLASH devices can render your target system useless. Most targets have a boot loader in the FLASH. Without this boot loader the target will obviously not boot. So before starting to play with this library its worth investigating a few things. How do you recover your target if you delete the boot loader? Do you have the necessary JTAG cable? Or is specialist hardware needed? Is it even possible to recover the target boards or must it be thrown into the rubbish bin? How does killing the board affect your project schedule? </PARA> </SECT1> <sect1 id="nand-nor-diff"><title>Differences between NAND and NOR flash</title> <para>Most flash devices supported by the eCos Flash library are categorised as NOR flash. These are fundamentally different from NAND flash devices, both in terms of the storage cells deep within the chip, and how they are addressed and used by applications.</para> <informaltable frame=topbot pgwide=1> <tgroup cols=3> <colspec colname=what> <colspec colname=nor> <colspec colname=nand> <thead> <row> <entry> Attribute </entry> <entry> NOR </entry> <entry> NAND </entry> </row> </thead> <tbody> <row> <entry>Addressing of data</entry> <entry>By byte address within the device. Usually expressed as memory-mapped addresses.</entry> <entry>By row (page) number. Pages are a power of two; commonly 512 or 2048 bytes. Optimised for reading and writing a page at a time. Sometimes supports column (byte) addressing, but this library does not expose such functionality.</entry> </row> <row> <entry>Are direct reads and writes possible? <footnote><para>In other words, can the application read flash directly as if it was RAM, or does it have to invoke the driver to copy data in and out?</para></footnote></entry> <entry>Usually</entry> <entry>Not in general, though a few special-case exceptions exist such as OneNAND devices.</entry> </row> <row> <entry>Erase block size</entry> <entry>May vary across the chip</entry> <entry>A fixed number of pages, typically 64</entry> </row> <row> <entry>Out-of-band data </entry> <entry>Not supported </entry> <entry>A small number of bytes per page - typically 16 "spare" per 512 "data" bytes - are usable by the application. They are read, written and erased at the same time as the "real" page data. </entry> </row> <row> <entry>May factory-bad regions <footnote><para>Regions which were found during manufacture to be bad and marked in some way - usually by placing a special code in the Out Of Band area.</para></footnote> exist on the chip?</entry> <entry>No </entry> <entry>Typically up to 20 eraseblocks are marked as factory-bad in their OOB area. The OS is expected to scan these to create a Bad Block Table. <footnote><para>Once a BBT exists it can then be used to keep track of any blocks which fail through wear during the lifetime of the device.</para></footnote></entry> </row> <row> <entry>May data be rewritten without being erased first?</entry> <entry>Usually (but only by resetting 1-bits to 0) </entry> <entry>Usually, on SLC NAND chips; not on MLC chips.</entry> </row> <row> <entry>Error detection and correction</entry> <entry>Not present</entry> <entry>Usually automatic. Typically this involves an Error Correcting Code, automatically calculated and stored in the OOB area, then checked on read. </entry> </row> </tbody> </tgroup> </informaltable> <para> Since a NAND chip can in general only be read indirectly, its contents must be copied to RAM before they can be executed. This means that the caveats in the eCos FLASH library about disabling interrupts whilst programming do not apply here, except in special cases such as OneNAND devices.</para> </sect1> <sect1 id="nand-deployment-notes"><title>Preparing for deployment</title> <para> It is generally not recommended to hard-code physical on-NAND locations in case of factory bad blocks or block failures in the field. <footnote><para>Usually the first block is guaranteed to be defect free for a certain number of erase cycles. This tends to be necessary if bootstrapping the CPU off NAND, and is an obvious exception to this rule.</para></footnote> Instead it is preferable to set up <emphasis>partitions</emphasis> on the chip with a generous safety margin and to store data in a location-independent way. This is commonly achieved by placing logical tags in the spare area of each page, or using a log-structured filesystem such as YAFFS. Such strategies remove the dependence on physical addressing, at the cost of increased complexity.</para> <para>The upshot of this is that you cannot reliably create a simple binary image to bulk-program in the factory. A more complicated programming operation is required to take account of your chip partitions, logical addressing strategy and any bad blocks which may be encountered during write. </para> </sect1> </chapter> <chapter id="nand-using"> <title>Using the NAND library</title> <para>The eCos NAND library exposes two principal APIs: one for applications to use and the other to communicate with device drivers.</para> <sect1 id="nand-app-config"><title>Configuring the NAND library</title> <para>The following configuration options are provided. They affect the library globally, i.e. across all drivers.</para> <variablelist> <varlistentry><term><constant>CYGPKG_IO_NAND_CFLAGS_ADD</constant></term> <term><constant>CYGPKG_IO_NAND_CFLAGS_REMOVE</constant></term> <listitem><para> Allows specific build options to be added to or removed from the CFLAGS list when building this library.</para></listitem></varlistentry> <varlistentry><term><constant>CYGSEM_IO_NAND_DEBUG</constant></term> <listitem><para> This is the master switch for all debug reporting from the library.</para></listitem></varlistentry> <varlistentry><term><constant>CYGSEM_IO_NAND_DEBUG_FN_DEFAULT</constant></term> <listitem><para> This is the default function that the library will use when sending debugging output. It must behave like <function>printf</function>. The default - <function>cyg_nand_defaultprintf</function> - is a wrapper to <function>diag_printf</function>.</para> <note><para>Individual drivers may override this setting in their <function>devinit</function> routines by overwriting the pointer in the device struct.</para></note></listitem></varlistentry> <varlistentry><term><constant>CYGSEM_IO_NAND_DEBUG_LEVEL</constant></term> <listitem><para> Specifies the verbosity of the NAND library and device drivers. Ranges from 0 (off) to 9 (incredibly verbose); the default setting is 1. (Higher values are only likely to be of use during driver development, if ever.) When enabled, messages are printed using the per-device printf-like function (see above).</para> <note><para>Should a serious problem be encountered it will always be reported the printf-like function, regardless of this setting. Such messages may be suppressed altogether by turning off <constant>CYGSEM_IO_NAND_DEBUG</constant>.</para></note></listitem></varlistentry> <varlistentry><term><constant>CYGSEM_IO_NAND_READONLY</constant></term> <listitem><para>Globally disables all code which writes to NAND devices. This may be useful during driver development.</para></listitem></varlistentry> <varlistentry><term><constant>CYGNUM_NAND_MAX_PARTITIONS</constant></term> <listitem><para>Sets a compile-time limit on the number of partitions any NAND device may have. The default is 4, which should be enough for most purposes; unnecessarily setting this higher wastes RAM.</para></listitem></varlistentry> <varlistentry><term><constant>CYGSEM_IO_NAND_USE_BBT</constant></term> <listitem><para>Globally enables and disables the use of Bad Block Table. <warning><para>This setting should not be disabled lightly! It is strongly recommended that you leave this setting enabled unless you have a very good reason to not use it. It is provided really as a convenience for allowing developers to recover their NAND from a confused state. </para></warning> </para></listitem></varlistentry> </variablelist> </sect1> <sect1 id="nand-using-app-api"><title>The NAND Application API</title> <para>All of the functions described here are declared in the header file <filename><cyg/nand/nand.h></filename>, which should be included by all users of the NAND library.</para> <note><para> Most of the functions in the library are declared as returning <type>int</type>. <emphasis>Unless otherwise stated, all functions return 0 for success, or a negative eCos error code if something went wrong.</emphasis></para></note> <sect2 id="nand-app-lookup"><title>Device initialisation and lookup</title> <para>NAND devices are identified to the library by name. In many cases there will be only one, commonly named <emphasis>onboard</emphasis>, but this flexibility allows for easy expansion later without cross-device confusion.</para> <note><para>The naming of NAND devices is set up by the code that instantiates their drivers. Normally this is done by the platform HAL port.</para></note> <programlisting> __externC int cyg_nand_lookup(const char *devname, cyg_nand_device **dev_o);</programlisting> <para>On success, *dev_o will be set up to point to a <type>cyg_nand_device</type> struct. On failure, it will not; a return code of <constant>-ENOENT</constant> signifies that the requested device name was not found.</para> <para> Applications will hardly, if ever, need to access the <type>cyg_nand_device</type> structs directly. The following members and convenience macros are most likely to be of relevance: <programlisting> struct _cyg_nand_device_t { ... cyg_nand_printf pf; // Diagnostic printf-like function for this device to use. May be changed at runtime. ... size_t page_bits; // log2 of no of regular bytes per page size_t spare_per_page; // OOB area size in bytes size_t block_page_bits; // log2 of no of pages per eraseblock size_t blockcount_bits; // log2 of number of blocks size_t chipsize_log; // log2 of total chip size in BYTES. ... }; #define CYG_NAND_BYTES_PER_PAGE(dev) (1<<(dev)->page_bits) #define CYG_NAND_SPARE_PER_PAGE(dev) ((dev)->spare_per_page) #define CYG_NAND_PAGES_PER_BLOCK(dev) (1<<(dev)->block_page_bits) #define CYG_NAND_BLOCKCOUNT(dev) (1<<(dev)->blockcount_bits) #define CYG_NAND_PAGECOUNT(dev) (NAND_BLOCKCOUNT(dev) * NAND_PAGES_PER_BLOCK(dev)) #define CYG_NAND_CHIPSIZE(dev) (1<<(dev)->chipsize_log) #define CYG_NAND_APPSPARE_PER_PAGE(dev) ((dev)->oob->app_size) #define CYG_NAND_BYTES_PER_BLOCK(dev) (1<<( (dev)->block_page_bits + (dev)->page_bits )) </programlisting> </para> </sect2> <sect2 id="nand-app-addressing"><title>NAND device addressing</title> <para>NAND devices are arranged as a series of <emphasis>pages</emphasis> and <emphasis>eraseblocks</emphasis>. The eCos NAND library numbers pages and eraseblocks sequentially, both starting at 0 and continuing until the end of the chip. For example, eraseblock 0 might contain pages 0 through 63; eraseblock 1, pages 64 through 127; and so on.</para> <caution><para>This numbering scheme is independent of the device's addressing scheme. Take care, particularly when erasing blocks; some devices and some applications effectively express the location to erase as a page number (or, in NAND-speak, as the <emphasis>row address</emphasis> to erase from).</para></caution> <warning><para>Most NAND chip manufacturers document restrictions on the order in which pages may be written to their device. Typically, individual pages within an eraseblock must be written in sequential order starting from the first, and random-order writes are prohibited or unspecified. The eCos NAND library does not attempt to police such restrictions; if at all unsure, check the spec sheet for the part. You have been warned! </para></warning> <para>NAND devices are widely considered to be arranged as one or more <emphasis>partitions</emphasis>, and the eCos NAND library supports this. However, there is no universal scheme for partition sizes to be supplied to the driver, unlike hard drives which encode a partition table into their first sector. Partition arrangements are often implicitly hardcoded, such as by byte address within the device, though they could be encoded in a "partition table", user-set, or even variable under software control by some esoteric rules. Therefore, every device driver is responsible for configuring its partition information as appropriate for the device, and this might for example appear as CDL options.</para> <tip><para>Be sure to read the notes associated with the device driver to understand how partitions are set up; if no notes are provided, look in its <function>devinit</function> code.</para></tip> <sect3 id="nand-app-partitions"><title>NAND device partitions</title> <para>After a NAND device has been initialised, its device struct contains a list of partitions. These are numbered from 0 and may go up to <constant>CYGNUM_NAND_MAX_PARTITIONS</constant>-1. Before an application can use the NAND device, it must obtain a partition context (pointer) with the following call: <programlisting>__externC cyg_nand_partition* cyg_nand_get_partition(cyg_nand_device *dev, unsigned partno);</programlisting> </para> <note><para>This call returns a pointer to the partition struct, not an error code. If the given partition number is inactive or invalid, it returns NULL.</para></note> </sect3> <sect3 id="nand-app-addressing-spare"><title>About the spare area</title> <para>Every page on the NAND array has a small number of "spare" bytes associated with it. These are used by the NAND library to store the page's ECC; whatever is left over may be used by the application for whatever purposes may suit it.</para> <para>Every page has <function>CYG_NAND_APPSPARE_PER_PAGE(dev)</function> bytes of spare area available to the application. (This amount is implicit from the driver configuration and cannot change during the lifetime of a device.) </para> <note><para>Application spare bytes are not subject to the ECC. When reading the spare area data, you must be prepared to cope with the consequences of the (unlikely) event of a bit drop-out or other failure.</para></note> </sect3> </sect2> <sect2 id="nand-app-manipulating"><title>Manipulating the NAND array</title> <para>Now, finally, given a <type>cyg_nand_partition*</type>, your application can make use of the NAND array with the following functions:</para> <sect3 id="nand-app-read"><title>Reading data</title> <programlisting> __externC int cyg_nand_read_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, void * dest, size_t size, void * spare, size_t spare_size); </programlisting> <blockquote> <para>Reads a single page and its spare area. The data read from the chip will be automatically ECC-checked and repaired if necessary. Parameters are as follows:</para> <glosslist> <glossentry><glossterm><parameter>ctx</parameter></glossterm><glossdef><para>The partition that data is to be read from.</para></glossdef></glossentry> <glossentry><glossterm><parameter>page</parameter></glossterm><glossdef><para> The page to be read, <emphasis>numbered from the start of the partition. </emphasis>. As a double-check, the library will refuse the operation with <constant>-ENOENT</constant> if this address is not within partition <parameter>ctx</parameter>. <note><para>This was changed in application interface v2; earlier page and block addresses were device-relative.</para></note> </para></glossdef></glossentry> <glossentry><glossterm><parameter>dest</parameter></glossterm><glossdef><para> Where to put the data. May be NULL, in which case the page data is not read.</para></glossdef></glossentry> <glossentry><glossterm><parameter>size</parameter></glossterm><glossdef><para> The maximum amount of data to read. (In any event, no more than a single page will be read, but if your application knows it doesn't need the whole page, you can place a cap here.) </para></glossdef></glossentry> <glossentry><glossterm><parameter>spare</parameter></glossterm><glossdef><para> Where to store the application data read from the spare area. This may be NULL if spare data is not required.</para></glossdef></glossentry> <glossentry><glossterm><parameter>spare_size</parameter></glossterm><glossdef><para> The maximum number of bytes to read from the spare area. This will not be more than <function>CYG_NAND_APPSPARE_PER_PAGE(dev)</function> bytes.</para></glossdef></glossentry> </glosslist> <para>An error response of <constant>-EIO</constant> means that a multiple-bit I/O error has occurred in the page data, which the ECC could not repair. The library stores the data read from the device in <parameter>*dest</parameter> and <parameter>*spare</parameter> on a best-effort basis; it should not be relied upon. The application should take steps to salvage what it can and erase the block as soon as possible.</para> </blockquote> </sect3> <sect3 id="nand-app-writing"><title>Writing data</title> <programlisting> __externC int cyg_nand_write_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, const void * src, size_t size, const void * spare, size_t spare_size); </programlisting> <blockquote> <para>Writes a single page and its spare area. The ECC will be computed and stored automatically. Parameters are as follows:</para> <glosslist> <glossentry><glossterm><parameter>ctx</parameter></glossterm><glossdef><para>The partition that data is to be written to.</para></glossdef></glossentry> <glossentry><glossterm><parameter>page</parameter></glossterm><glossdef><para> The page to be written, <emphasis>numbered from the start of the partition</emphasis>. As a double-check, the library will refuse the operation with <constant>-ENOENT</constant> if this address is not within partition <parameter>ctx</parameter>. </para></glossdef></glossentry> <glossentry><glossterm><parameter>src</parameter></glossterm><glossdef><para> Where to read the data from. May be NULL, in which case the page data is not written.</para></glossdef></glossentry> <glossentry><glossterm><parameter>size</parameter></glossterm><glossdef><para> The amount of data to write. (In any event, no more than a single page will be written.)</para></glossdef></glossentry> <glossentry><glossterm><parameter>spare</parameter></glossterm><glossdef><para> Where to read the data to go into the spare area; it will automatically be packed around the ECC as necessary. Again, this may be NULL if spare data is not required.</para></glossdef></glossentry> <glossentry><glossterm><parameter>spare_size</parameter></glossterm><glossdef><para> The number of bytes to write to the spare area. This should not be larger than <function>CYG_NAND_APPSPARE_PER_PAGE(dev)</function>; if it is, only that many bytes will be stored.</para></glossdef></glossentry> </glosslist> <para> An error response of <constant>-EIO</constant> means that the page write failed. The application should copy out any data it wishes to keep from the rest of the eraseblock, then call <function>cyg_nand_bbt_markbad()</function> to put the block beyond use.</para> </blockquote></sect3> <sect3 id="nand-app-erasing"><title>Erasing blocks</title> <programlisting> __externC int cyg_nand_erase_block(cyg_nand_partition *ctx, cyg_nand_block_addr blk); </programlisting> <blockquote><glosslist> <glossentry><glossterm><parameter>ctx</parameter></glossterm><glossdef><para>The partition that data is to be erased from.</para></glossdef></glossentry> <glossentry><glossterm><parameter>blk</parameter></glossterm><glossdef><para> The block to be erased, <emphasis>numbered from the start of the partition</emphasis>. As a double-check, the library will refuse the operation with <constant>-ENOENT</constant> if this address is not within partition <parameter>ctx</parameter>. </para></glossdef></glossentry> </glosslist> <para>An error response of <constant>-EIO</constant> means that the block erase failed. In this case, the library automatically marks the block as bad, and the application need take no further action.</para> </blockquote> </sect3> <sect3 id="nand-app-manip-commonerrs"><title>Common error returns</title> <para> The following common error returns may be encountered when manipulating the NAND array using the above functions:</para> <glosslist> <glossentry><glossterm><constant>-EIO</constant></glossterm><glossdef><para> The operation could not be completed due to an I/O error. This may require the application to take further action; check the details provided above for the call you have just made.</para></glossdef></glossentry> <glossentry><glossterm><constant>-ENOENT</constant></glossterm><glossdef><para> The page or block address was not valid for the given partition.</para></glossdef></glossentry> <glossentry><glossterm><constant>-EINVAL</constant></glossterm><glossdef><para> The page (block) address was (within) a block that is marked bad.</para></glossdef></glossentry> </glosslist> </sect3> </sect2> <sect2 id="nand-app-ancillary"><title>Ancillary NAND functions</title> <para>The following functions are provided to allow applications to interact with the Bad Block Table:</para> <programlisting> typedef enum { CYG_NAND_BBT_OK=0, CYG_NAND_BBT_WORNBAD=1, CYG_NAND_BBT_RESERVED=2, CYG_NAND_BBT_FACTORY_BAD=3 } cyg_nand_bbt_status_t; __externC int cyg_nand_bbt_query(cyg_nand_partition *ctx, cyg_nand_block_addr blk); __externC int cyg_nand_bbt_markbad(cyg_nand_partition *ctx, cyg_nand_block_addr blk); </programlisting> <para>To determine the status of an eraseblock, use <function>cyg_nand_bbt_query</function>; this returns an enum from <type>cyg_nand_bbt_status_t</type> or a negative eCos error code. All blocks which return a non-0 enum value are considered inaccessible by applications.</para> <para>Occasionally, it is necessary for applications to mark a block as bad. This most commonly happens when a write operation fails (see <xref linkend="nand-app-writing"> above). To do this, call <function>cyg_nand_bbt_markbad</function>; the return is 0 for success, or a negative eCos error code. <emphasis>As with other calls, blocks are numbered from 0 at the start of the partition, and internally translated for the device as appropriate.</emphasis></para> <para>Both of these calls may foreseeably return <constant>-ENOENT</constant> if the given block address was not valid, or <constant>-EIO</constant> if something awful happened with the on-chip bad block table. </para> </sect2> </sect1> </chapter> <chapter id="nand-devs-writing"> <title>Writing NAND device drivers</title> <sect1 id="nand-devs-planning"><title>Planning a port</title> <para> Before you start, you will need to have sight of appropriate spec sheets for both the NAND chip and the board into which it is connected, and you need to know how the chip is to be partitioned.</para> <sect2 id="nand-devs-structure"><title>Driver structure and layout</title> <para> A typical NAND device driver falls into two parts:</para> <itemizedlist> <listitem><para>high-level operations specific to the NAND chip (page reads and writes); and </para></listitem> <listitem><para>board-specific plumbing (sending commands and data to the chip; reading data back from the chip). </para></listitem> </itemizedlist> <para> This distinction is important in the interests of code reuse; the same part may appear on different boards, or indeed multiple times, but connected differently. It need not be maintained if there are good reasons not to.</para> <para> The <emphasis>NAND library device interface</emphasis> consists of a C struct, <type>cyg_nand_device</type>, comprising a number of data fields and function pointers. Each NAND chip to be made available to the library requires exactly one instance of this struct.</para> <tip><para>The <type>cyg_nand_device</type> structure includes a <structfield>void* priv</structfield> member which is treated as opaque. The driver may use this member as it sees fit; it is intended to provide an easy means to identify the NAND array, MMIO addresses or function pointers to use and so on. Typically this is used by the chip driver for its own purposes, and includes a further opaque member for the use of the HAL port. </para></tip> <para>The function pointers in the struct form the driver's high-level functions; they make use of the low-level functions to talk to the chip. We present the high-level functions first, although there is no intrinsic reason to prefer either ordering during driver development.</para> <para> The high-level chip-specific functions are traditionally laid out as an <emphasis>inline file</emphasis> in an appropriate package in <filename class=directory>devs/nand/<replaceable>CHIP</replaceable></filename>. The board-specific functions should normally appear in the platform HAL and #include the inline. </para></sect2> <sect2 id="nand-devs-partitions"><title>Chip partitions</title> <para>Before embarking on the port, you should determine how the NAND array will be partitioned. This is necessarily a board-specific question, and your layout must accommodate any other software users of the array. You will need to know either the fixed layout - converted to eraseblock addresses - or how to determine the layout at initialisation time.</para> <tip><para>It may be worthwhile to set up partitioning by way of some parameters in your platform's CDL, with sensible defaults, instead of outright hard-coding the partition layout.</para></tip> </sect2> <sect2 id="nand-devs-locking"><title>Locking against concurrent access</title> <para> The eCos NAND library provides per-device locking, to guard against concurrent access during high-level operations. This support is fully automatic; drivers need take no action to make use of it.</para> <para> This strategy may not be sufficient on all target boards: sometimes, accessing a NAND chip requires mediation by CPLD or other device, which must be shared with other NAND chips or even other peripherals. <emphasis>If this applies, it is the responsibility of the driver and platform port to provide further locking as appropriate!</emphasis></para> <tip><para>When using mutexes in a driver, one should use the <emphasis>driver API</emphasis> as defined in <filename><cyg/hal/drv_api.h></filename> instead of the full kernel API. This has the useful property that mutex operations are very cheaply implemented when the eCos kernel is not present, such as when operating in RedBoot. </para></tip> </sect2> <sect2 id="nand-devs-cdl"> <title>Required CDL declarations</title> <para> An individual NAND chip driver must declare the largest page size it supports by means of CDL. This is done with a statement like the following in its cdl_package stanza:</para> <programlisting> requires ( CYGNUM_NAND_PAGEBUFFER >= 2048 ) </programlisting> <note><para> This requirement is due to the internal workings of the eCos NAND library: a buffer is required for certain operations which manipulate up to a NAND page worth of data, internally to the library. This is declared once as a global buffer for safety under low-memory conditions; a page may be too big to use temporary storage on the C stack, and the NAND library deliberately avoids the use of <function>malloc</function>.</para> </note> <para> By convention, a driver package would declare <constant>CYGPKG_IO_NAND</constant> as its <constant>parent</constant> and use <filename>cyg/devs/nand</filename> as its <constant>include_dir</constant>, but there is no intrinsic reason why this should be so.</para> </sect2> </sect1> <sect1 id="nand-devs-highlevel"> <title>High-level (chip) functions</title> <para> The high-level functions provided by the chip driver are typically created as an <emphasis>inline file</emphasis> providing a fully-populated <type>cyg_nand_dev_fns_v1</type> struct, instantiated by the <type>CYG_NAND_FUNS</type> macro. The high-level driver should not directly read or write to the hardware itself, but instead call into functions in the low-level driver.</para> <para> The form the low-level functions should take is not prescribed; typically functions will be required to write commands to the device, to read and write data, and to query any status line which may be present. The high-level driver should normally provide a header file containing prototypes for the functions it requires from the low-level driver. (The low-level source file would provide the low-level functions required, include the high-level include, then instantiate the combined driver using the <type>CYG_NAND_DEVICE</type> macro.)</para> <para> This source code layout is not intended as a prescription. It would for example be entirely in order to store pointers to the low-level functions in a struct and set <structfield>priv</structfield> to point to that struct, which could be useful in some cases.</para> <note><para>The device driver must not call <function>malloc</function> or otherwise allocate memory; all data should be in the stack or set as globals. This is because the driver may be required to run within a minimal eCos configuration.</para></note> <para> These functions should all return 0 on success, or a negative eCos error code. In the event of an error, do <emphasis>not</emphasis> call back into the NAND library; use the <type>NAND_CHATTER</type> macro to report, in case a human is watching, and return an error code. The library will take care of ensuring the correct response to the application and updating the BBT as necessary.</para> <sect2 id="nand-devs-devinit"> <title>Device initialisation</title> <programlisting> static int my_devinit (cyg_nand_device *dev); </programlisting> <para> The <function>devinit</function> function is the most complex, and logically one to write first. It is responsible for:</para> <itemizedlist> <listitem><para>initialising the device, typically by sending a reset command; </para></listitem> <listitem><para>interrogating the device to confirm its presence and properties; </para></listitem> <listitem><para>setting up the partition table list (see "Planning a port" above); </para></listitem> <listitem><para>setting up mutexes as necessary (see "Locking against concurrent access" above); </para></listitem> <listitem><para>populating the other members of the <type>cyg_nand_device</type> struct (see below). </para></listitem> </itemizedlist> <para> Interrogating the device is normally performed by sending a <emphasis>Read ID</emphasis> command and examining the result, which typically encodes some or all of the chip parameters.</para> <para> Given the similarity between many NAND parts, it may be possible to write a generic driver to cover all of one or more manufacturer's parts, or indeed for all ONFI-compliant parts. At the time of writing, this has not yet been attempted.</para> <variablelist><title>The <function>devinit</function> function must set up the following struct members:</title> <varlistentry><term><structfield>page_bits</structfield></term><listitem><para>The size of the regular (non-spare) part of a page, expressed as the logarithm in base 2 of the number of bytes. For example, if pages are 2048 bytes long, <structfield>page_bits</structfield> would be 11. Obviously, the size of a page must be an exact power of two. </para></listitem></varlistentry> <varlistentry><term><structfield>spare_per_page</structfield></term><listitem><para>The number of bytes of spare area available in each page.</para></listitem></varlistentry> <varlistentry><term><structfield>block_page_bits</structfield></term><listitem><para>The base-2 log of the number of pages per eraseblock.</para></listitem></varlistentry> <varlistentry><term><structfield>blockcount_bits</structfield></term><listitem><para>The total number of erase blocks in the device, expressed as a base-2 log. </para></listitem></varlistentry> <varlistentry><term><structfield>chipsize_log</structfield></term><listitem><para>The total size of the chip, not counting the spare areas. This is required so that the library can double-check that the given parameters make sense by comparing with the preceding fields. Again, this field is itself a base-2 logarithm.</para></listitem></varlistentry> <varlistentry><term><structfield>bbt.data</structfield></term><listitem><para>Space for the in-memory Bad Block Table for this device. </para></listitem></varlistentry> <varlistentry><term><structfield>bbt.datasize</structfield></term><listitem><para>This is the size of <structfield>bbt.data</structfield>, in bytes. At present, this should be two bits times the number of blocks in the device; in other words, <varname>1<<(blockcount_bits-2)</varname> bytes. </para></listitem></varlistentry> </variablelist> <para>The <type>cyg_nand_device</type> struct has two further members <structfield>ecc</structfield> and <structfield>oob</structfield> which must be set up to point to the ECC and OOB descriptors to use for the device. This is normally done by the <type>CYG_NAND_DEVICE</type> low-level instantiation macro, so will be better described in that section, but at this level you should be aware that it is also safe to set up the descriptor block during <function>devinit</function>. for example if multiple semantics might be you had included logic to detect what semantics to use.</para> <para> The Bad Block Table itself is implemented in a way which intends to be compatible with the Linux MTD layer. A full parameter struct is not currently provided, though one may be in future.</para> </sect2> <sect2 id="nand-devs-readwrite"> <title>Reading, writing and erasing data</title> <para>The read and write operations are divided into three phases, with the following flow:</para> <itemizedlist> <listitem><para>Begin. This is called once; the driver should lock any platform-level mutex and send the command and address.</para></listitem> <listitem><para>Stride. This is called one or more times to read the page data from the device. <note><para>The reason for this is if the platform provides a NAND controller with hardware ECC: it is often necessary to read out the ECC registers every so often.</para></note></para></listitem> <listitem><para>Finish. This is called once; it should read or write the spare area, (on programming) send a "program confirm" command and check its status, and unlock any platform-level mutex.</para></listitem> </itemizedlist> <para>Erasing is a single-shot call which should lock any platform-specific mutex, send the command, check its status and unlock the mutex.</para> <programlisting> static int my_read_begin(cyg_nand_device *dev, cyg_nand_page_addr page); static int my_read_stride(cyg_nand_device *dev, void * dest, size_t size); static int my_read_finish(cyg_nand_device *dev, void * spare, size_t spare_size); static int my_write_begin(cyg_nand_device *dev, cyg_nand_page_addr page); static int my_write_stride(cyg_nand_device *dev, const void * src, size_t size); static int my_write_finish(cyg_nand_device *dev, const void * spare, size_t spare_size); static int my_erase_block(cyg_nand_device *dev, cyg_nand_block_addr blk); </programlisting> </sect2> <sect2 id="nand-devs-isfactorybad"> <title>Searching for factory-bad blocks</title> <programlisting> static int my_is_factory_bad(cyg_nand_device *dev, cyg_nand_block_addr blk); </programlisting> <para> The very first time a NAND chip is used, the library has to scan it to check for factory-bad eraseblocks and build up the Bad Block Table. This function is called repeatedly to do so, one block at a time; it should return 1 if the block is marked bad, or 0 if the block appears to be OK.</para> <para>Typically this function will invoke <function>read_page</function>; blocks are usually marked factory-bad by the presence of a particular signature in the out-of-band area of the first or second page of that block.</para> <warning><para> It is extremely important that you get this function right; after an eraseblock has been written to, it is no longer possible to reliably determine whether the block was factory-bad. It is never safe to assume that the factory-bad signature for a chip is the same as that of a similarly-sized chip or another by the same manufacturer; <emphasis>always</emphasis> check the correct spec sheet for the actual part or part-family in use! </para></warning> <tip><para> Because this function is critical and a subtle error could cripple your application some time later in the field when it runs across undetected factory-bad blocks, you might find it handy to have a double-check before proceeding. If you enable CYGSEM_IO_NAND_READONLY in your eCos configuration during early development, you can safely fire up a test application (which calls <function>cyg_nand_lookup</function>) whilst watching the chatter output: the scan will be performed, but no BBT will be written. You can then compare the number of bad blocks reported against the manufacturer's specification of the maximum. Double-check that your <function>is_factory_bad</function> function is correct before enabling read-write mode! </para></tip> </sect2> <sect2 id="nand-devs-declaring-fun-set"> <title>Declaring the function set</title> <programlisting> CYG_NAND_FUNS_V2(mydev_funs, my_devinit, my_read_begin, my_read_stride, my_read_finish, my_write_begin, my_write_stride, my_write_finish, my_erase_block, my_is_factory_bad); </programlisting> <para> This macro ties the above functions together into a struct whose name is given as its first argument. The name of the resulting struct must be quoted when the driver is formally instantiated, which is normally done by the low-level functions.</para> <note><para>Earlier versions of this library used a slightly different device interface, keyed off the macro CYG_NAND_FUNS. This interface has been retired.</para></note> </sect2> </sect1> <sect1 id="nand-devs-lowlevel"> <title>Low-level (board) functions</title> <para> The set and prototypes of the functions required here will necessarily depend on the board and to a lesser extent on the NAND part itself. The following functionality is typically required:</para> <itemizedlist> <listitem><para>Very low-level hardware initialisation - for example, GPIO pin direction and interrupt config - if this has not already been done by the platform HAL</para></listitem> <listitem><para>Set up the chip partition table (see below) </para></listitem> <listitem><para>Runtime hardware config as required, such as commanding an FPGA or CPLD to route lines to the NAND part </para></listitem> <listitem><para>Write a command (byte) </para></listitem> <listitem><para>Write an address (handful of bytes) </para></listitem> <listitem><para>Write data, usually at the chip's full bus width (typically 8 or 16 bits) </para></listitem> <listitem><para>Read data at full bus width </para></listitem> <listitem><para>Read data at 8-bit width (if the chip has a 16 bit data bus, some commands - commonly ReadID - may return 8-bit data) </para></listitem> <listitem><para>Poll any status lines required or - if supported - set them up as interrupts to allow sleeping-wait </para></listitem> </itemizedlist> <sect2 id="nand-devs-accessing"> <title>Talking to the chip</title> <para> It is impossible to prescribe how to achieve this, as it depends entirely on how the NAND part is wired up on the board.</para> <para> The ideal situation is that the NAND part is wired in via the CPU's memory controller and that the controller is set up to do most of the hard work for you. In that case, reading and writing the device is as simple as accessing the correct memory-mapped I/O address; usually different address ranges connect to the device's command, address and data registers respectively.</para> <tip><para>The HAL provides a number of macros in <filename><cyg/hal/hal_io.h></filename> to read and write memory-mapped I/O. </para></tip> <note><para>On platforms with an MMU, MMIO may be rerouted to different addresses to those on the board spec sheet. Check the MMU setup in the platform HAL.</para></note> <para> On some platforms, you may have to invoke an FPGA or CPLD to be able to talk to the NAND chip. This might typically take the form of a handful of MMIO accesses, but should hopefully be fairly straightforward once you've figured out how the components interrelate.</para> <para> The worst case is where you have no support from any sort of controller hardware and have to bit-bang GPIO lines to talk to the chip. This is a much more involved process; you have to take great care to get the timings right with carefully tuned delays. The result is usually quite CPU intensive, and could be clock speed sensitive too; you should check for and take account of any CDL settings in the architecture and variant HAL which allow the CPU clock frequency to be changed.</para> <tip><para> If your low-level functions take a <type>cyg_nand_device</type> pointer as an argument, you can use its <structfield>priv</structfield> member to hold or point to some relevant data like the MMIO addresses to use, which is preferable to hard-coding them. Indeed, if you wish your board port to support more than one chip, you should use the <structfield>priv</structfield> member to distinguish between them. </para></tip> </sect2> <sect2 id="nand-devs-partition"> <title>Setting up the chip partition table</title> <para> It is the responsibility of the high-level <function>devinit</function> function to set up the device's partition table. (It may be appropriate for it to invoke a low-level function to do this.)</para> <para>The partition definition is an array of <type>cyg_nand_partition</type> entries in the <type>cyg_nand_device</type>.</para> <programlisting> struct _cyg_nand_partition_t { cyg_nand_device *dev; cyg_nand_block_addr first; cyg_nand_block_addr last; }; typedef struct _cyg_nand_partition_t cyg_nand_partition; struct _cyg_nand_device_t { ... cyg_nand_partition partition[CYGNUM_NAND_MAX_PARTITIONS]; ... }; </programlisting> <para> Application-visible partition numbers are simply indexes into this array.</para> <itemizedlist> <listitem><para>On a live partition, <structfield>dev</structfield> must point back to the <type>cyg_nand_device</type> containing it. If <constant>NULL</constant>, the partition is inactive.</para></listitem> <listitem><para><structfield>first</structfield> is the number of the first block of the partition.</para></listitem> <listitem><para><structfield>last</structfield> is the number of the last block of the partition (<emphasis>not</emphasis> the number of blocks, unless the partition starts at block 0).</para></listitem> </itemizedlist> </sect2> <sect2 id="nand-devs-lowlevel-putting-it-together"> <title>Putting it all together...</title> <para> Finally, with everything else in place, we turn to the CYG_NAND_DEVICE macro to instantiate it.</para> <programlisting> CYG_NAND_DEVICE(my_nand, "onboard", &mydev_funs, &my_priv_struct, &linux_mtd_ecc, &nand_mtd_oob_64); </programlisting> <para>In order, the arguments to this macro are:</para> <itemizedlist> <listitem><para>The name to give the resultant cyg_nand_device struct;</para></listitem> <listitem><para>the device identifier string, application-visible to be used in <function>cyg_nand_lookup()</function> ;</para></listitem> <listitem><para>a pointer to the device high-level function set to use, normally set up by the CYG_NAND_FUNS macro;</para></listitem> <listitem><para>the <structfield>priv</structfield> member to include in the struct;</para></listitem> <listitem><para>a pointer to the ECC semantics block to use. <filename>linux_mtd_ecc</filename> provides software ECC compatible with the Linux MTD layer, but it is strongly recommended to use onboard hardware ecc support if this is present as it gives a huge speed boost. See <xref linkend="nand-ecc"> for more details. </para></listitem> <listitem><para>a pointer to the OOB-area layout descriptor to use (see <filename>nand_oob.h</filename> : nand_mtd_oob_16 and nand_mtd_oob_64 are Linux-compatible layouts for devices with 16 and 64 bytes of spare area per page respectively).</para></listitem> </itemizedlist> <para>The macro invokes the appropriate linker magic to pull all the compiled NAND device structs into one section so the NAND library can find them.</para> </sect2> </sect1> <sect1 id="nand-ecc"><title>ECC implementation</title> <para> The use of ECC is strongly recommended with NAND flash parts owing to their tendency to occasionally bit-flip. This is usually done with a variant of a Hamming code which calculates column and line parity. The computed ECC is stored in the spare area of the page to which it relates. </para> <para> The NAND library automatically computes and stores the ECC of data as it is written to the chip. On read, the code is calculated for the data actually read; this is compared with the stored code and the data repaired if necessary. </para> <para> The NAND library comes with a software ECC implementation named <filename>linux_mtd_ecc</filename>. This is compatible with the ECC used in the Linux MTD layer, hence its name. It calculates a 3-byte ECC on a 256-byte data block. This algorithm is adequate for most circumstances, but it is strongly recommended to use any hardware ECC support which may be available because of the performance gains it yields. (In testing, we observed that up to two thirds of the time taken by every page read and program call was used in computing ECC in software.) </para> <sect2 id="nand-ecc-interface"><title>The ECC interface</title> <para> This library draws a semantic distinction between <emphasis>hardware</emphasis> and <emphasis>software</emphasis> ECC implementations. </para> <itemizedlist> <listitem><para> A software ECC implementation will typically not require an initialisation step. The calculation function will always be called with a pointer to the data bytes to compute. </para></listitem> <listitem><para> A hardware implementation is assumed to read and act upon the data <emphasis>as it goes past</emphasis>. Therefore, it will not be passed a pointer to the data when its <filename>calculate</filename> step is invoked. </para></listitem> </itemizedlist> <para> An ECC is defined by the following parameters: <itemizedlist> <listitem><para>The size of data block it handles, in bytes. </para></listitem> <listitem><para>The size of ECC it calculates on those blocks, in bytes. </para></listitem> <listitem><para>Whether the algorithm is hardware or software. </para></listitem> </itemizedlist> </para> <para>An ECC algorithm must provide the following functions: </para> <programlisting> /* Initialises an ECC computation. May be NULL if not required. */ void my_ecc_init(struct _cyg_nand_device_t *dev); /* Returns the ECC for the given data block. * If IS_HARDWARE: * - dat and nbytes are ignored * If ! IS_HARDWARE: * - dat and nbytes are required * - if nbytes is less than the chunk size, the remainder are * assumed to be 0xff. */ void my_ecc_calc(struct _cyg_nand_device_t *dev, const CYG_BYTE *dat, size_t nbytes, CYG_BYTE *ecc); /* Repairs the ECC for the given data block, if needed. * Call this if your read-from-chip ECC doesn't match what you computed * over the data block. Both *dat and *ecc_read may be corrected. * * `nbytes' is the number of bytes we're interested in; if a correction * is indicated outside of that range, it will be ignored. * * Returns: * 0 for no errors * 1 for a corrected single bit error in the data * 2 for a corrected single bit error in the ECC * -1 for an uncorrectable error (more than one bit) */ int my_ecc_repair(struct _cyg_nand_device_t *dev, CYG_BYTE *dat, size_t nbytes, CYG_BYTE *ecc_read, const CYG_BYTE *ecc_calc); </programlisting> <para>In some cases - particularly where hardware assistance is in use - it is necessary to specify different functions for calculating the ECC depending on whether the operation at hand is a page read or a page write. In that case, two <emphasis>init</emphasis> and <emphasis>calc</emphasis> functions may be supplied, each taking the same prototype. </para> <para>The algorithm parameters and functions are then tied together with one of the following macros: </para> <programlisting> CYG_NAND_ECC_ALG_SW(my_ecc, _datasize, _eccsize, my_ecc_init, my_ecc_calc, my_ecc_repair); CYG_NAND_ECC_ALG_HW(my_ecc, _datasize, _eccsize, my_ecc_init, my_ecc_calc, my_ecc_repair); CYG_NAND_ECC_ALG_HW2(my_ecc, _datasize, _eccsize, my_ecc_init, my_ecc_calc_read, my_ecc_calc_write, my_ecc_repair); CYG_NAND_ECC_ALG_HW3(my_ecc, _datasize, _eccsize, my_ecc_init_read, my_ecc_init_write, my_ecc_calc_read, my_ecc_calc_write, my_ecc_repair); </programlisting> <tip><para> It's OK to use software ECC while getting things going, but if you do then switch to a hardware implementation, you probably need to erase your entire NAND chip including its Bad Block Table. The <filename>nanderase</filename> utility may come in handy for this.) </para></tip> <warning><para>You must be sure that your ECC repair algorithm is correct. This can be quite tricky to test. However, it is often possible to hoodwink the controller into computing ECCs for you even if the data is not going to affect the data stored on the NAND chip, for example if you send it data but haven't told it to program a page. A variant of the <filename>sweccwalk</filename> test may come in handy for this purpose. </para></warning> <para> An example implementation, including an ECC calculation and repair test named <filename>eccwalk</filename>, may be found in the STM3210E evaluation board platform HAL, <filename>packages/hal/cortexm/stm32/stm3210e_eval</filename>. The chip NAND controller has on-board ECC calculation, but does not undertake to repair data; a repair function was written specially. </para> </sect2> </sect1> </chapter> <chapter id="nand-tests-utils"> <title>Tests and utilities</title> <sect1 id="nand-tests"><title>Unit and functional tests</title> <para> The NAND library includes a number of tests. The most useful to driver writers are <filename>readwrite</filename>, <filename>rwbenchmark</filename> and <filename>sweccwalk</filename>; the others are only likely to be of interest to library maintainers.</para> <glosslist> <glossentry><glossterm>readwrite</glossterm><glossdef><para>Performs a read-write-erase cycle on the first NAND device it finds, checking that its operations have had the expected effect on the device contents. This is a potentially destructive test; do not run it on a device containing data you care about! </para></glossdef></glossentry> <glossentry><glossterm>rwbenchmark</glossterm><glossdef><para> A more involved version of <filename>readwrite</filename>, this is a timing test which performs multiple reads, writes and erases and applies statistical techniques to the results in the same way that <filename>tm_basic</filename> instruments the speed of various eCos kernel functions. <emphasis> This is a potentially destructive test; do not run it on a device containing data you care about!</emphasis> </para></glossdef></glossentry> <glossentry><glossterm>sweccwalk</glossterm><glossdef><para> Repeatedly makes single-bit changes to a data buffer and checks that the software ECC implementation correctly repairs them. <tip><para> This test can be adapted to test out hardware ECC implementations. The test outputs the raw ECC codes as it goes, which is useful in confirming that the bits in the computed ECC are what you think they are. </para></tip> </para></glossdef></glossentry> <glossentry><glossterm>nandunit</glossterm><glossdef><para>Some unit tests which do not require any NAND device: ECC known answer vectors, and OOB area packing/unpacking correctness. </para></glossdef></glossentry> <glossentry><glossterm>readlimits</glossterm><glossdef><para>Attempts to read a block outside of a partition, confirming that it doesn't work.</para></glossdef></glossentry> </glosslist> <para>There are some further tests of the library which require the <link linkend="devs-nand-synth-tests">synthetic NAND device</link>. </para> </sect1> <sect1 id="nand-utils"> <title>Ancillary NAND utilities</title> <para> The following utilities are included with the NAND library. They are standalone eCos applications; for convenience, you can set <constant>CYGBLD_IO_NAND_BUILD_UTILS</constant> in your eCos configuration and they will be built and placed into <filename>install/tests/io/nand/current/utils</filename>. </para> <glosslist> <glossentry><glossterm>erasenand.c</glossterm><glossdef><para> Loops over all the blocks of a partition, erasing all the blocks which are not marked as bad. The device and partition to erase are set by #define. <note><para>This will not normally erase the Bad Block Table. This is because the BBT reports its own blocks as "Reserved" when queried via <function>cyg_nand_bbt_query</function>, which makes them inaccessible to applications. However, if <constant>CYGSEM_IO_NAND_USE_BBT</constant> is turned off, then any BBT present will not be detected and hence will be erased. </para></note> </para></glossdef></glossentry> <glossentry><glossterm>erase_bbt_dangerous.c</glossterm><glossdef><para> Erases the NAND blocks comprising the primary and mirror bad-block tables of a device. The device to erase is set by #define. (The tables are detected by the library in the usual way. If none are present, the library will scan the device for factory-bad blocks to create such a table, then this code will immediately erase it.) <warning><para>It is particularly dangerous to run this utility on a production device, as it is generally not possible to later reconstruct the list of factory-bad blocks. It is intended only as an aid to driver authors. </para></warning> </para></glossdef></glossentry> </glosslist> </sect1> </chapter> </part>
