changeset 1739:1773ef378c6f

Add new AM29xxxxx V2 flash driver
author bartv
date Sat, 20 Nov 2004 18:09:53 +0000
parents 0801d20c7256
children 699be933fd5e
files packages/ChangeLog packages/devs/flash/amd/am29xxxxxv2/current/ChangeLog packages/devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl packages/devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml packages/devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c packages/ecos.db
diffstat 8 files changed, 1909 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/packages/ChangeLog
+++ b/packages/ChangeLog
@@ -1,3 +1,7 @@
+2004-11-20  Bart Veer  <bartv@ecoscentric.com>
+
+	* ecos.db: Add new AM29xxxxxx driver which supports the V2 API
+
 2004-08-06  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* ecos.db: Added the new strata driver which uses the V2 API.
new file mode 100644
--- /dev/null
+++ b/packages/devs/flash/amd/am29xxxxxv2/current/ChangeLog
@@ -0,0 +1,35 @@
+2004-11-05  Bart Veer  <bartv@ecoscentric.com>
+
+	* New AM29xxxxx flash driver created
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl
@@ -0,0 +1,141 @@
+# ====================================================================
+#
+#      flash_am29xxxxx_v2.cdl
+#
+#      Device driver for AMD am29xxxxx flash chips and compatibles
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2004 eCosCentric Ltd
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      bartv
+# Contributors:   
+# Date:           2004-11-05
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_FLASH_AMD_AM29XXXXX_V2 {
+    display	"AMD am29xxxxx flash memory support"
+    parent	CYGPKG_IO_FLASH
+    active_if	CYGPKG_IO_FLASH
+    implements	CYGHWR_IO_FLASH_DEVICE
+    implements	CYGHWR_IO_FLASH_DEVICE_V2
+    include_dir	cyg/io
+    compile	am29xxxxx.c
+
+    description "
+        Flash memory support for AMD AM29xxxxx devices and compatibles.
+        This driver implements the V2 flash driver API"
+
+    cdl_option CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_REGIONS {
+	display		"Number of different erase regions"
+	flavor		data
+	default_value	4
+	legal_values	1 to 64
+	description "
+            Flash devices vary widely in the way the various flash blocks are
+            laid out. In uniform devices all flash blocks are the same size,
+            for example 64 blocks of 64K each. Other devices have a boot block,
+            where one of the big blocks is subdivided into a number of smaller
+            ones. For example there could be a 16K block, followed by two 8K blocks,
+            then a 32K block, and finally 63 64K blocks. Each sequence of blocks
+            of a given size is known as an erase region, so a uniform device has
+            a single erase region and the above boot block device has four
+            erase regions. The driver needs to know the maximum number of erase
+            regions that may be present, especially if CFI is used to determine
+            the block details at run-time. Typically this option is controlled
+            by a requires property in the platform HAL, so users do not need
+            to edit it."
+    }
+
+    cdl_option CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_TIMEOUT {
+	display		"Maximum number of iterations during a block erase"
+	flavor		data
+	default_value	100000000
+	description "
+            The driver needs to poll the flash device during a block erase
+            to detect when the operation has completed. This option controls
+            the maximum number of iterations of the polling loop, before the
+            driver will give up. The timeout should never actually trigger,
+            as long as the hardware is functioning correctly. If a timeout
+            does occur the flash device may be left in an inconsistent state.
+            If very slow flash devices are used then the platform HAL may
+            require a larger timeout."
+    }
+    
+    cdl_option CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_TIMEOUT {
+	display		"Maximum number of iterations during a write"
+	flavor		data
+	default_value	10000000
+	description "
+            The driver needs to poll the flash device when writing data
+            to detect when the operation has completed. This option controls
+            the maximum number of iterations of the polling loop, before the
+            driver will give up. The timeout should never actually trigger,
+            as long as the hardware is functioning correctly. If a timeout
+            does occur the flash device may be left in an inconsistent state.
+            If very slow flash devices are used then the platform HAL may
+            require a larger timeout."
+    }
+    
+    cdl_component CYGPKG_DEVS_FLASH_AMD_AM29XXXXX_V2_OPTIONS {
+        display "AMD AM29xxxxx driver build options"
+        flavor  none
+        description   "
+	    Package specific build options including control over
+	    compiler flags used only in building the AMD am29xxxxx
+            flash driver, and details of which tests are built."
+
+        cdl_option CYGPKG_DEVS_FLASH_AMD_AM29XXXXX_V2_CFLAGS_ADD {
+            display "Additional compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the AMD am29xxxxx flash driver. These flags
+                are used in addition to the set of global flags."
+        }
+
+        cdl_option CYGPKG_DEVS_FLASH_AMD_AM29XXXXX_V2_CFLAGS_REMOVE {
+            display "Suppressed compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the AMD am29xxxxx flash driver. These flags
+                are removed from the set of global flags if present."
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/packages/devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml
@@ -0,0 +1,723 @@
+<!-- DOCTYPE part  PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->
+
+<!-- {{{ Banner                         -->
+
+<!-- =============================================================== -->
+<!--                                                                 -->
+<!--     am29xxxxx.sgml                                              -->
+<!--                                                                 -->
+<!--     Documentation for the am29xxxxx flash device driver.        -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- ####ECOSPRODOCCOPYRIGHTBEGIN####                                -->
+<!--                                                                 -->
+<!-- This file is part of eCosPro(tm)                                -->
+<!-- Copyright (C) 2004 eCosCentric Limited                          -->
+<!-- Distribution of the work or derivative of the work in any       -->
+<!-- form is prohibited unless prior permission obtained from the    -->
+<!-- copyright holder                                                -->
+<!--                                                                 -->
+<!-- ####ECOSPRODOCCOPYRIGHTEND####                                  -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN####                                       -->
+<!--                                                                 -->
+<!-- Author(s):   bartv                                              -->
+<!-- Date:        2004/11/05                                         -->
+<!--                                                                 -->
+<!-- ####DESCRIPTIONEND####                                          -->
+<!-- =============================================================== -->
+
+<!-- }}} -->
+
+<part id="devs-flash-am29xxxxx"><title>AMD AM29xxxxx Flash Device Driver</title>
+
+<refentry id="am29xxxxx">
+  <refmeta>
+    <refentrytitle>Overview</refentrytitle>
+  </refmeta>
+  <refnamediv>
+    <refname>Overview</refname>
+    <refpurpose>eCos Support for AMD AM29xxxxx Flash Devices and Compatibles</refpurpose>
+  </refnamediv>
+
+  <refsect1 id="am29xxxxx-description"><title>Description</title>
+    <para>
+The <varname>CYGPKG_DEVS_FLASH_AMD_AM29XXXXX_V2</varname> AMD
+AM29xxxxx V2 flash driver package implements support for the AM29xxxxx
+family of flash devices and compatibles. The driver is not normally
+accessed directly. Instead application code will use the API provided
+by the generic flash driver package
+<varname>CYGPKG_IO_FLASH</varname>, for example by calling functions
+like <function>cyg_flash_program</function>.
+    </para>
+    <para>
+The driver imposes one restriction on application code which
+developers should be aware of: when programming the flash the
+destination addresses must be aligned to a bus boundary. For example
+if the target hardware has a single flash device attached to a 16-bit
+bus then program operations must involve a multiple of 16-bit values
+aligned to a 16-bit boundary. Note that it is the bus width that
+matters, not the device width. If the target hardware has two 16-bit
+devices attached to a 32-bit bus then program operations must still be
+aligned to a 32-bit boundary, even though in theory a 16-bit boundary
+would suffice. In practice this is rarely an issue, and requiring the
+larger boundary greatly simplifies the code and improves performance.
+    </para>
+    <note><para>
+Many eCos targets with AM29xxxxx or compatible flash devices will
+still use the older driver package
+<varname>CYGPKG_DEVS_FLASH_AMD_AM29XXXXX</varname>. Only newer ports
+and some older ports that have been converted will use the V2 driver.
+This documentation only applies to the V2 driver.
+    </para></note>
+  </refsect1>
+
+  <refsect1 id="am29xxxxx-config"><title>Configuration Options</title>
+    <para>
+The AM29xxxxx flash driver package will be loaded automatically when
+configuring eCos for a target with suitable hardware. However the
+driver will be inactive unless the generic flash package
+<varname>CYGPKG_IO_FLASH</varname> is loaded. It may be necessary to
+add this generic package to the configuration explicitly before the
+driver functionality becomes available. There should never be any need
+to load or unload the AM29xxxx driver package.
+    </para>
+    <para>
+The AM29xxxxx flash driver package contains a small number of
+configuration options, relating mostly to hardware characteristics. It
+is very rare that application developers need to change any of these.
+For example the option
+<varname>CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_REGIONS</varname>
+may need a non-default value if the flash devices used on the target
+have an unusual boot block layout. If so the platform HAL will impose
+a requires constraint on this option and the configuration system will
+resolve the constraint. The only time it might be necessary to change
+the value manually is if the actual board being used is a variant of
+the one supported by the platform HAL and uses a different flash chip.
+    </para>
+  </refsect1>
+</refentry>
+
+<refentry id="am29xxxxx-instance">
+  <refmeta>
+    <refentrytitle>Instantiating an AM29xxxxx Device</refentrytitle>
+  </refmeta>
+  <refnamediv>
+    <refname>Instantiating</refname>
+    <refpurpose>including the driver in an eCos target</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>
+#include &lt;cyg/io/am29xxxxx_dev.h&gt;
+      </funcsynopsisinfo>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_init_nop</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_init_check_devid_XX</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_init_cfi_XX</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_erase_XX</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+        <paramdef>const cyg_flashaddr_t <parameter>addr</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_program_XX</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+        <paramdef>const cyg_flashaddr_t <parameter>addr</parameter></paramdef>
+        <paramdef>const void* <parameter>data</parameter></paramdef>
+        <paramdef>const size_t <parameter>len</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_query_nop</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+        <paramdef>void* <parameter>data</parameter></paramdef>
+        <paramdef>const size_t <parameter>len</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_hwr_map_error_nop</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+        <paramdef>int <parameter>err</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_lock_nop</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+        <paramdef>const cyg_flashaddr_t <parameter>addr</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_unlock_nop</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+        <paramdef>const cyg_flashaddr_t <parameter>addr</parameter></paramdef>
+      </funcprototype>
+      <funcprototype>
+        <funcdef>int <function>cyg_am29xxxxx_read_devid_XX</function></funcdef>
+        <paramdef>struct cyg_flash_dev* <parameter>device</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1 id="am29xxxxx-instance-description"><title>Description</title>
+    <para>
+The AM29xxxxx family contains some hundreds of different flash
+devices, all supporting the same basic set of operations, with various
+common or uncommon extensions. The devices vary in capacity,
+performance, boot block layout, and width. There are also
+platform-specific issues such as how many devices are actually present
+on the board and where they are mapped in the address space. The
+AM29xxxxx driver package cannot know all this information. Instead it
+is the responsibility of another package, usually the platform HAL, to
+instantiate some flash device structures. Two pieces of information
+are especially important: the bus configuration and the boot block
+layout.
+    </para>
+    <para>
+Flash devices are typically 8-bits, 16-bits, or 32-bits wide (64-bit
+devices are not yet in common use). Most 16-bit devices will also
+support 8-bit accesses, but not all. Similarly 32-bit devices can be
+accessed 16-bits at a time or 8-bits at a time. A board will have one
+or more of these devices on the bus. For example there may be a single
+16-bit device on a 16-bit bus, or two 16-bit devices on a 32-bit bus.
+The processor's bus logic determines which combinations are possible,
+and usually there will be a trade off between cost and performance.
+For example two 16-bit devices in parallel can provide twice the
+memory bandwidth of a single device. The driver supports the following
+combinations:
+    </para>
+    <variablelist>
+      <varlistentry>
+        <term>8</term>
+        <listitem><para>
+A single 8-bit flash device on an 8-bit bus.
+        </para></listitem>
+       </varlistentry>
+      <varlistentry>
+        <term>16</term>
+        <listitem><para>
+A single 16-bit flash device on a 16-bit bus.
+        </para></listitem>
+       </varlistentry>
+      <varlistentry>
+        <term>32</term>
+        <listitem><para>
+A single 32-bit flash device on an 32-bit bus.
+        </para></listitem>
+       </varlistentry>
+      <varlistentry>
+        <term>88</term>
+        <listitem><para>
+Two parallel 8-bit devices on an 16-bit bus.
+        </para></listitem>
+       </varlistentry>
+      <varlistentry>
+        <term>8888</term>
+        <listitem><para>
+Four parallel 8-bit devices on a 32-bit bus.
+        </para></listitem>
+       </varlistentry>
+      <varlistentry>
+        <term>1616</term>
+        <listitem><para>
+Two parallel 16-bit devices on a 32-bit bus, with one device providing
+the bottom two bytes of each 32-bit datum and the other device
+providing the upper two bytes.
+        </para></listitem>
+       </varlistentry>
+      <varlistentry>
+        <term>16as8</term>
+        <listitem><para>
+A single 16-bit flash device connected to an 8-bit bus.
+        </para></listitem>
+       </varlistentry>
+    </variablelist>
+    <para>
+These configuration all require slightly different code to manipulate
+the hardware. The AM29xxxxx driver package provides separate functions
+for each configuration, for example
+<function>cyg_am29xxxxx_erase_16</function> and
+<function>cyg_am29xxxxx_program_1616</function>. 
+    </para>
+    <caution><para>
+At the time of writing not all the configurations have been tested.
+    </para></caution>
+    <para>
+The second piece of information is the boot block layout. Flash
+devices are subdivided into blocks (also known as sectors, both terms
+are in common use). Some operations such as erase work on a whole
+block at a time, and for most applications a block is the smallest
+unit that gets updated. A typical block size is 64K. It is inefficient
+to use an entire 64K block for small bits of configuration data and
+similar information, so many flash devices also support a number of
+smaller boot blocks. A typical 2MB flash device could have a single
+16K block, followed by two 8K blocks, then a 32K block, and finally 31
+full-size 64K blocks. The boot blocks may appear at the bottom or the
+top of the device. So-called uniform devices do not have boot blocks,
+just full-size ones. The driver needs to know the boot block layout.
+With modern devices it can work this out at run-time, but often it is
+better to provide the information statically.
+    </para>
+  </refsect1>
+
+  <refsect1 id="am29xxxxx-instance-example"><title>Example</title>
+    <para>
+Flash support is usually specific to each platform. Even if two
+platforms happen to use the same flash device there are likely to be
+differences such as the location in the address map. Hence there is
+little possibility of re-using the platform-specific code, and this
+code is generally placed in the platform HAL rather than in a separate
+package. Typically this involves a separate file and a corresponding
+compile property in the platform HAL's CDL:
+    </para>
+    <programlisting width=72>
+cdl_package CYGPKG_HAL_M68K_ALAIA {
+    &hellip;
+    compile -library=libextras.a alaia_flash.c
+    &hellip;
+}
+    </programlisting>
+    <para>
+The contents of this file will not be accessed directly, only
+indirectly via the generic flash API, so normally it would be removed
+by link-time garbage collection. To avoid this the object file has to
+go into <filename>libextras.a</filename>.
+    </para>
+    <para>
+The actual file <filename>alaia_flash.c</filename> will look something like:
+    </para>
+    <programlisting>
+#include &lt;pkgconf/system.h&gt;
+#ifdef CYGPKG_DEVS_FLASH_AMD_AM29XXXXX_V2
+
+#include &lt;cyg/io/flash.h&gt;
+#include &lt;cyg/io/flash_priv.h&gt;
+#include &lt;cyg/io/am29xxxxx_dev.h&gt;
+
+static const CYG_FLASH_FUNS(hal_alaia_flash_amd_funs,
+    &amp;cyg_am29xxxxx_init_check_devid_16,
+    &amp;cyg_am29xxxxx_query_nop,
+    &amp;cyg_am29xxxxx_erase_16,
+    &amp;cyg_am29xxxxx_program_16,
+    (int (*)(struct cyg_flash_dev*, const cyg_flashaddr_t, void*, const size_t))0,
+    &amp;cyg_am29xxxxx_hwr_map_error_nop,
+    &amp;cyg_am29xxxxx_lock_nop,
+    &amp;cyg_am29xxxxx_unlock_nop);
+
+static const cyg_am29xxxxx_dev hal_alaia_flash_priv = {
+    .devid      = 0x45,
+    .block_info = {
+        { 0x00004000, 1 },
+        { 0x00002000, 2 },
+        { 0x00008000, 1 },
+        { 0x00010000, 63 }
+    }
+};
+
+struct cyg_flash_dev hal_alaia_flash CYG_HAL_TABLE_ENTRY(cyg_flashdev) = {
+    .funs               = &amp;hal_alaia_flash_amd_funs,
+    .start              = 0xFFE00000,
+    .end                = 0xFFFFFFFF,
+    .num_block_infos    = 4,
+    .block_info         = hal_alaia_flash_priv.block_info,
+    .priv               = &amp;hal_alaia_flash_priv
+};
+#endif
+    </programlisting>
+    <para>
+The bulk of the file is protected by an ifdef for the AM29xxxxx flash
+driver. That driver will only be active if the generic flash support
+is enabled. Without that support there will be no way of accessing
+the device so there is no point in instantiating the device. The rest
+of the file is split into three definitions. The first supplies the
+functions which will be used to perform the actual flash accesses,
+using a macro provided by the generic flash code in <filename
+class="headerfile">cyg/io/flash_priv.h</filename>. The
+relevant ones have an <literal>_16</literal> suffix, indicating that
+on this board there is a single 16-bit flash device on a 16-bit
+bus. The second definition provides information specific to AM29xxxxx
+flash devices. The third provides the
+<structname>cyg_flash_dev</structname> structure needed by the generic
+flash code, which contains pointers to the previous two.
+    </para>
+  </refsect1>
+
+  <refsect1 id="am29xxxxx-instance-functions"><title>Functions</title>
+    <para>
+All eCos flash device drivers must implement a standard interface,
+defined by the generic flash code <varname>CYGPKG_IO_FLASH</varname>.
+This interface includes a table of 8 function pointers for various
+operations: initialization, query, erase, program, read, error code
+handling, locking and unlocking. The query operation is optional and
+the AM29xxxxx driver only provides a dummy implementation
+<function>cyg_am29xxxxx_query_nop</function>. AM29xxxxx flash devices
+are always directly accessible so there is no need for a separate read
+function. Standard flash error codes are used so only a dummy
+<function>cyg_am29xxxxx_hwr_map_error_nop</function> function is
+needed. The remaining functions are more complicated.
+    </para>
+    <para>
+Usually the table can be declared <literal>const</literal>. In a ROM
+startup application this avoids both ROM and RAM copies of the table,
+saving a small amount of memory. <literal>const</literal> should not
+be used if the table may be modified by a platform-specific
+initialization routine.
+    </para>
+
+    <refsect2 id="am29xxxxx-instance-functions-init"><title>Initialization</title>
+      <para>
+There is a choice of three main initialization functions. The simplest
+is <function>cyg_am29xxxxx_init_nop</function>, which does nothing. It
+can be used if the <structname>cyg_am29xxxxx_dev</structname> and
+<structname>cyg_flash_dev</structname> structures are fully
+initialized statically and the flash will just work without special
+effort. This is useful if it is guaranteed that the board will always
+be manufactured using the same flash chip, since the nop function
+involves the smallest code size and run-time overheads.
+      </para>
+      <para>
+The next step up is
+<function>cyg_am29xxxxx_init_check_devid_XX</function>, where
+<literal>XX</literal> will be replaced by the suffix appropriate for the
+bus configuration. It is still necessary to provide all the device
+information statically, including the <structfield>devid</structfield>
+field in the <structname>cyg_am29xxxxx_dev</structname> structure.
+However this initialization function will attempt to query the flash
+device and check that the provided device id matches the actual
+hardware. If there is a mismatch the device will be marked
+uninitialized and subsequent attempts to manipulate the flash will
+fail.
+      </para>
+      <para>
+If the board may end up being manufactured with any of a number of
+different flash chips then the driver can perform run-time
+initialization, using a <function>cyg_am29xxxxx_init_cfi_XX</function>
+function. This queries the flash device as per the Common Flash Memory
+Interface Specification, supported by all current devices (although
+not necessarily by older devices). The
+<structfield>block_info</structfield> field in the
+<structname>cyg_am29xxxxx_dev</structname> structure and the
+<structfield>end</structfield> and
+<structfield>num_block_infos</structfield> fields in the
+<structname>cyg_flash_dev</structname> structure will be filled in.
+It is still necessary to supply the <structfield>start</structfield>
+field statically since otherwise the driver will not know how to
+access the flash device. The main disadvantage of using CFI is that it
+will increase the code size.
+      </para>
+      <para>
+A final option is to use a platform-specific initialization function.
+This may be useful if the board may be manufactured with one of a
+small number of different flash devices and the platform HAL needs to
+adapt to this. The AM29xxxxx driver provides a utility function to
+read the device id, <function>cyg_am29xxxxx_read_devid_XX</function>:
+      </para>
+      <programlisting width=72>
+static int
+alaia_flash_init(struct cyg_flash_dev* dev)
+{
+    int devid = cyg_am29xxxxx_read_devid_1616(dev);
+    switch(devid) {
+        case 0x0042 :
+          &hellip;
+        case 0x0084 :
+          &hellip;
+        default:
+          return CYG_FLASH_ERR_DRV_WRONG_PART;
+    }
+}
+      </programlisting>
+      <para>
+There are many other possible uses for a platform-specific
+initialization function. For example initial prototype boards might
+have only supported 8-bit access to a 16-bit flash device rather than
+16-bit access, but this was fixed in the next revision. The
+platform-specific initialization function could figure out which model
+board it is running on and replace the default
+<literal>16as8</literal> functions with <literal>16</literal> ones.
+      </para>
+    </refsect2>
+
+    <refsect2 id="am29xxxxx-instance-functions-erase-program"><title>Erase and Program</title>
+      <para>
+The AM29xxxxx driver provides erase and program functions appropriate
+for the various bus configurations. On most targets these can be used
+directly. On some targets it may be necessary to do some extra work
+before and after the erase and program operations. For example if the
+hardware has an MMU then the part of the address map containing the
+flash may have been set to read-only, in an attempt to catch spurious
+memory accesses. Erasing or programming the flash requires
+write-access, so the MMU settings have to be changed temporarily. For
+another example some flash device may require a higher voltage to be
+applied during an erase or program operation. or a higher voltage may
+be desirable to make the operation proceed faster. A typical
+platform-specific erase function would look like this:
+      </para>
+      <programlisting width=72>
+static int
+alaia_flash_erase(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    int result;
+    &hellip;  // Set up the hardware for an erase
+    result = cyg_am29xxxxx_erase_32(dev, addr);
+    &hellip;  // Revert the hardware change
+    return result;
+}
+      </programlisting>
+      <para>
+There are two configurations which affect the erase and program
+functions, and which a platform HAL may wish to change:
+<varname>CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_TIMEOUT</varname>
+and
+<varname>CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_TIMEOUT</varname>.
+The erase and program operations both involve polling for completion,
+and these timeout impose an upper bound on the polling loop. Normally
+these operations should never take anywhere close to the timeout
+period, and hence a timeout probably indicates a catastrophic failure
+that should really be handled by a watchdog reset. A reset is
+particularly appropriate because there will be no clean way of
+aborting the flash operation. The main reason for the timeouts is
+to help with debugging when porting to new hardware. If there is a
+valid reason why a particular platform needs different timeouts then
+the platform HAL's CDL can require appropriate values for these
+options.
+      </para>
+    </refsect2>
+
+    <refsect2 id="am29xxxxx-instance-functions-locking"><title>Locking</title>
+      <para>
+There is no single way of implementing the block lock and unlock
+operations on AM29xxxxx devices. If these operations are supported at
+all then usually they involve manipulating the voltages on certain
+pins. This cannot be handled by generic driver code since it requires
+knowing exactly how these pins can be manipulated via the processor's
+GPIO pins. Therefore the AM29xxxxx driver does not provide functional
+lock and unlock functions, only dummy functions
+<function>cyg_am29xxxxx_lock_nop</function> and
+<function>cyg_am29xxxxx_unlock_nop</function>. If there is a way of
+implementing the locking then this can be handled by platform-specific
+functions.
+      </para>
+      <programlisting width=72>
+static int
+alaia_lock(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    &hellip;
+}
+
+static int
+alaia_unlock(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    &hellip;
+}
+      </programlisting>
+    </refsect2>
+
+    <refsect2 id="am29xxxxx-instance-functions-other"><title>Other</title>
+      <para>
+The driver provides a set of functions
+<function>cyg_am29xxxxx_read_devid_XX</function>, one per supported
+bus configuration. These functions take a single argument, a pointer
+to the <structname>cyg_flash_dev</structname> structure, and return
+the chip's device id. For older devices this id is a single byte. For
+more recent devices the id is a 3-byte value, 0x7E followed by a
+further two bytes that actually identify the device.
+<function>cyg_am29xxxxx_read_devid_XX</function> is usually called
+only from inside a platform-specific driver initialization routine,
+allowing the platform HAL to adapt to the actual device present on the
+board.
+      </para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1 id="am29xxxxx-instance-devpriv"><title>Device-Specific Structure</title>
+    <para>
+The <structname>cyg_am29xxxxx_dev</structname> structure provides
+information specific to AM29xxxxx flash devices, as opposed to the
+more generic flash information which goes into the
+<structname>cyg_flash_dev</structname> structure. There are only two
+fields: <structfield>devid</structfield> and
+<structfield>block_info</structfield>.
+    </para>
+    <para>
+<structfield>devid</structfield> is only needed if the driver's
+initialization function is set to
+<function>cyg_am29xxxxx_init_check_devid_XX</function>. That function
+will extract the actual device info from the flash chip and compare it
+with the <structfield>devid</structfield> field. If there is a
+mismatch then subsequent operations on the device will fail.
+    </para>
+    <para>
+The <structfield>block_info</structfield> field consists of one or
+more pairs of the block size in bytes and the number of blocks of that
+size. The order must match the actual hardware device since the flash
+code will use the table to determine the start and end locations of
+each block. The table can be initialized in one of three ways:
+    </para>
+    <orderedlist>
+      <listitem><para>
+If the driver initialization function is set to
+<function>cyg_am29xxxxx_init_nop</function> or
+<function>cyg_am29xxxxx_init_check_devid_XX</function> then the block
+information should be provided statically. This is appropriate if the
+board will also be manufactured using the same flash chip.
+      </para></listitem>
+      <listitem><para>
+If <function>cyg_am29xxxxx_init_cfi_XX</function> is used then this
+will fill in the block info table. Hence there is no need for static
+initialization.
+      </para></listitem>
+      <listitem><para>
+If a platform-specific initialization function is used then either
+this should fill in the block info table, or the info should be
+provided statically.
+      </para></listitem>
+    </orderedlist>
+    <para>
+The size of the <structfield>block_info</structfield> table is
+determined by the configuration option
+<varname>CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_REGIONS</varname>.
+This has a default value of 4, which should suffice for nearly all
+AM29xxxxx flash devices. If more entries are needed then the platform
+HAL's CDL script should require a larger value.
+    </para>
+    <para>
+If the <structname>cyg_am29xxxxx_dev</structname> structure is
+statically initialized then it can be <literal>const</literal>. This
+saves a small amount of memory in ROM startup applications. If the
+structure may be updated at run-time, either by
+<function>cyg_am29xxxxx_init_cfi_XX</function> or by a
+platform-specific initialization routine, then it cannot be
+<literal>const</literal>.
+    </para>
+  </refsect1>
+
+  <refsect1 id="am29xxxxx-instance-flash"><title>Flash Structure</title>
+    <para>
+Internally the flash code works in terms of
+<structname>cyg_flash_dev</structname> structures, and the platform
+HAL should define one of these. The structure should be placed in the
+<literal>cyg_flashdev</literal> table. The following fields need to be
+provided:
+    </para>
+    <variablelist>
+      <varlistentry>
+        <term><structfield>funs</structfield></term>
+        <listitem><para>
+This should point at the table of functions.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><structfield>start</structfield></term>
+        <listitem><para>
+The base address of the flash in the address map. On
+some board the flash may be mapped into memory several times, for
+example it may appear in both cached and uncached parts of the address
+space. The <structfield>start</structfield> field should correspond to
+the cached address.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><structfield>end</structfield></term>
+        <listitem><para>
+The address of the last byte in the flash. It can
+either be statically initialized, or
+<function>cyg_am29xxxxx_init_cfi_XX</function> will calculate
+its value at run-time.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><structfield>num_block_infos</structfield></term>
+        <listitem><para>
+This should be the number of entries in the
+<structfield>block_info</structfield> table. It can either be
+statically initialized or it will be filled in by
+<function>cyg_am29xxxxx_init_cfi_XX</function>.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><structfield>block_info</structfield></term>
+        <listitem><para>
+The table with the block information is held in the
+<structname>cyg_am29xxxxx_dev</structname> structure, so this field
+should just point into that structure.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><structfield>priv</structfield></term>
+        <listitem><para>
+This field is reserved for use by the device driver. For the AM29xxxxx
+driver it should point at the appropriate
+<structname>cyg_am29xxxxx</structname> structure. 
+        </para></listitem>
+      </varlistentry>
+    </variablelist>
+    <para>
+The <structname>cyg_flash_dev</structname> structure contains a number
+of other fields which are manipulated only by the generic flash code.
+Some of these fields will be updated at run-time so the structure
+cannot be declared <literal>const</literal>.
+    </para>
+  </refsect1>
+
+  <refsect1 id="am29xxxxx-instance-serial"><title>Multiple Devices</title>
+    <para>
+A board may have several flash devices in parallel, for example two
+16-bit devices on a 32-bit bus. It may also have several such banks
+to increase the total amount of flash. If each device provides 2MB,
+there could be one bank of 2 parallel flash devices at 0xFF800000 and
+another bank at 0xFFC00000, giving a total of 8MB. This setup can be
+described in several ways. One approach is to define two
+<structname>cyg_flash_dev</structname> structures. The table of
+function pointers can usually be shared, as can the
+<structname>cyg_am29xxxxx_dev</structname> structure. Another approach
+is to define a single <structname>cyg_flash_dev</structname>
+structure but with a larger <structfield>block_info</structfield>
+table, covering the blocks in both banks of devices. The second
+approach makes more efficient use of memory.
+    </para>
+    <para>
+Many variations are possible, for example a small slow flash device
+may be used for initial bootstrap and holding the configuration data,
+while there is also a much larger and faster device to hold a file
+system. Such variations are usually best described by separate
+<structname>cyg_flash_dev</structname> structures.
+    </para>
+  </refsect1>
+
+  <refsect1 id="am29xxxxx-instance-platform"><title>Platform-Specific Macros</title>
+    <para>
+The AM29xxxxx driver source code includes the header files
+<filename class="headerfile">cyg/hal/hal_arch.h</filename> and
+<filename class="headerfile">cyg/hal/hal_io.h</filename>, and hence
+indirectly the corresponding platform header files (if defined).
+Optionally these headers can define macros which are used inside the
+driver, thus giving the HAL limited control over how the driver works.
+    </para>
+    <para>
+<function>HAL_AM29XXXXX_P2V</function> provides control over the
+addresses used to manipulate the flash. For example the flash device
+may be mirrored in the address space: if the top bit of the address is
+clear then the memory access will go via the cache; if the top bit is
+set then the access will bypass the cache. Ordinary read accesses
+should go via the cache so the <structfield>start</structfield> field
+in the <structname>cyg_flash_dev</structname> structure should have
+the top bit clear. <function>HAL_AM29XXXXX_P2V</function> can then or
+in the top bit, ensuring that the cache does not get in the way of
+flash updates.
+    </para>
+    <programlisting width=72>
+#define HAL_AM29XXXXX_P2V(_addr_)                      \
+    ({ CYG_ADDRWORD new_addr = (CYG_ADDRWORD)(_addr_); \
+       new_addr |= 0x80000000;                         \
+       new_addr; })
+    </programlisting>
+  </refsect1>
+
+</refentry>
+
+</part>
new file mode 100644
--- /dev/null
+++ b/packages/devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h
@@ -0,0 +1,115 @@
+#ifndef CYGONCE_DEVS_FLASH_AM29xxxxx_dev_V2_H
+# define CYGONCE_DEVS_FLASH_AM29xxxxx_dev_V2_H
+//==========================================================================
+//
+//      am29xxxxx_dev.h
+//
+//      Flash driver for the AMD family - driver details
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 eCosCentric Ltd
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    bartv
+// Contributors:
+// Date:         2004-11-05
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/devs_flash_amd_am29xxxxx_v2.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/io/flash.h>
+#include <cyg/io/flash_priv.h>
+
+externC int     cyg_am29xxxxx_init_nop(struct cyg_flash_dev*);
+externC size_t  cyg_am29xxxxx_query_nop(struct cyg_flash_dev*, void*, const size_t);
+externC int     cyg_am29xxxxx_hwr_map_error_nop(struct cyg_flash_dev*, int);
+externC int     cyg_am29xxxxx_lock_nop(struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int     cyg_am29xxxxx_unlock_nop(struct cyg_flash_dev*, const cyg_flashaddr_t);
+
+externC int cyg_am29xxxxx_read_devid_8(     struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_read_devid_16(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_read_devid_32(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_read_devid_88(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_read_devid_8888(  struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_read_devid_1616(  struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_read_devid_16as8( struct cyg_flash_dev*);
+
+externC int cyg_am29xxxxx_init_check_devid_8(     struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_check_devid_16(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_check_devid_32(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_check_devid_88(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_check_devid_8888(  struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_check_devid_1616(  struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_check_devid_16as8( struct cyg_flash_dev*);
+
+externC int cyg_am29xxxxx_init_cfi_8(     struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_cfi_16(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_cfi_32(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_cfi_88(    struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_cfi_8888(  struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_cfi_1616(  struct cyg_flash_dev*);
+externC int cyg_am29xxxxx_init_cfi_16as8( struct cyg_flash_dev*);
+
+externC int cyg_am29xxxxx_erase_8(     struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_16(    struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_32(    struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_88(    struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_8888(  struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_1616(  struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_16as8( struct cyg_flash_dev*, const cyg_flashaddr_t);
+
+externC int cyg_am29xxxxx_program_8(     struct cyg_flash_dev*, const cyg_flashaddr_t, const void*, const size_t);
+externC int cyg_am29xxxxx_program_16(    struct cyg_flash_dev*, const cyg_flashaddr_t, const void*, const size_t);
+externC int cyg_am29xxxxx_program_32(    struct cyg_flash_dev*, const cyg_flashaddr_t, const void*, const size_t);
+externC int cyg_am29xxxxx_program_88(    struct cyg_flash_dev*, const cyg_flashaddr_t, const void*, const size_t);
+externC int cyg_am29xxxxx_program_8888(  struct cyg_flash_dev*, const cyg_flashaddr_t, const void*, const size_t);
+externC int cyg_am29xxxxx_program_1616(  struct cyg_flash_dev*, const cyg_flashaddr_t, const void*, const size_t);
+externC int cyg_am29xxxxx_program_16as8( struct cyg_flash_dev*, const cyg_flashaddr_t, const void*, const size_t);
+
+// FIXME: add program_buffered() support as per e.g. the AM29LV128
+// FIXME: add software lock/unlock support as per e.g. the AM29BDS640
+
+// The driver-specific data, pointed at by the priv field in a
+// a cyg_flash_dev structure.
+typedef struct cyg_am29xxxxx_dev {
+    // The device id, mainly for use by the init_check_devid() routines
+    cyg_uint32          devid;
+    // Space for the block_info fields needed for the cyg_flash_dev.
+    // These can be statically initialized, or dynamically via
+    // init_cfi().
+    cyg_block_info_t    block_info[CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_REGIONS];
+} cyg_am29xxxxx_dev;
+
+#endif  // CYGONCE_DEVS_FLASH_AM29xxxxx_dev_V2_H
new file mode 100644
--- /dev/null
+++ b/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c
@@ -0,0 +1,384 @@
+//==========================================================================
+//
+//      am29xxxxx.c
+//
+//      Flash driver for the AMD family
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 eCosCentric Ltd
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    bartv
+// Contributors:
+// Date:         2004-11-05
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/devs_flash_amd_am29xxxxx_v2.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/io/flash.h>
+#include <cyg/io/flash_priv.h>
+#include <cyg/io/am29xxxxx_dev.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_io.h>
+
+// This driver supports multiple banks of AMD am29xxxxx flash devices
+// or compatibles. These are NOR-flash devices, requiring explicit
+// erase operations with an erase value of 0xff.
+//
+// The devices may be 8-bit, 16-bit, or 32-bit (64-bit devices are not
+// yet supported). Most but not all 16-bit devices can also be
+// accessed as 8-bit, in which case the chip may be hooked up to an
+// 8-bit bus. A bank of flash may involve just a single chip, or there
+// may be several chips in parallel. Typical combinations are 88 to
+// get 16-bit, 8888 for 32-bit, and 1616 for 32-bit. It is assumed
+// that all chips within a bank are the same device. There may also be
+// several banks of flash, and different banks may use different
+// devices.
+//
+// This driver instantiates support for the various bus
+// configurations: 8, 16, 16AS8, 32, 88, 8888, and 1616. On any given
+// platform only one or two of these combinations will be of interest,
+// but the remainder will be eliminated via linker garbage collection.
+// To avoid excessive duplication an auxiliary file contains the
+// actual implementations. Compiler optimization should eliminate any
+// unnecessary code.
+
+// A flash driver is supposed to provide the following functions:
+//  int     (*init)(...)
+//  size_t  (*query)(...)
+//  int     (*erase)(...)
+//  int     (*program)(...)
+//  int     (*hwr_map_error)(...)
+//  int     (*block_lock)(...)
+//  int     (*block_unlock)(...)
+//
+// The devices do not need any special initialization. However a given
+// board may be manufactured with any one of several devices, which
+// complicates things. The main complication is that there may be
+// different bootsector layouts. The primary job of the init function
+// is to check the device id, possibly fill in the bootsector info,
+// or even to use the CFI support to get the bootsector info from the
+// device itself. There may be other complications, e.g. minor variations
+// of a given board design. These can be handled by h/w specific init
+// functions in the platform HAL.
+//
+// The query function need not do anything useful, it is
+// driver-defined.
+//
+// No read function need be supplied because the flash memory is
+// always directly accessible to the cpu.
+//
+// The hwr_map_error is a no-op.
+//
+// Erase, program, and the locking functions need real
+// implementations.
+
+// ----------------------------------------------------------------------------
+// The protocol understood by AMD flash chips and compatibles.
+// The AM29_PARALLEL() macro is used in bus configurations with multiple
+// devices in parallel, to issue commands to all the devices in a single
+// write. In theory some of the operations, e.g. READ_DEVID, only need
+// to access a single chip but then you get into complications for the
+// SETUP commands.
+#define AM29_COMMAND_SETUP1         AM29_PARALLEL(0x00AA)
+#define AM29_COMMAND_SETUP2         AM29_PARALLEL(0x0055)
+#define AM29_COMMAND_RESET          AM29_PARALLEL(0x00F0)
+#define AM29_COMMAND_AUTOSELECT     AM29_PARALLEL(0x0090)
+#define AM29_COMMAND_ERASE          AM29_PARALLEL(0x0080)
+#define AM29_COMMAND_ERASE_SECTOR   AM29_PARALLEL(0x0030)
+#define AM29_COMMAND_CFI            AM29_PARALLEL(0x0098)
+#define AM29_COMMAND_PROGRAM        AM29_PARALLEL(0x00A0)
+
+// CFI offsets of interest. This assumes that the standard query table
+// has not been replaced by the extended query table, although the
+// CFI standard allows that behaviour.
+#define AM29_OFFSET_CFI_Q                       AM29_OFFSET_CFI_DATA(0x0010)
+#define AM29_OFFSET_CFI_SIZE                    AM29_OFFSET_CFI_DATA(0x0027)
+#define AM29_OFFSET_CFI_BLOCK_REGIONS           AM29_OFFSET_CFI_DATA(0x002C)
+#define AM29_OFFSET_CFI_BLOCK_COUNT_LSB(_i_)    AM29_OFFSET_CFI_DATA(0x002D + (4 * _i_))
+#define AM29_OFFSET_CFI_BLOCK_COUNT_MSB(_i_)    AM29_OFFSET_CFI_DATA(0x002E + (4 * _i_))
+#define AM29_OFFSET_CFI_BLOCK_SIZE_LSB(_i_)     AM29_OFFSET_CFI_DATA(0x002F + (4 * _i_))
+#define AM29_OFFSET_CFI_BLOCK_SIZE_MSB(_i_)     AM29_OFFSET_CFI_DATA(0x0030 + (4 * _i_))
+
+#define AM29_STATUS_DQ7             AM29_PARALLEL(0x0080)
+#define AM29_STATUS_DQ6             AM29_PARALLEL(0x0040)
+#define AM29_STATUS_DQ5             AM29_PARALLEL(0x0020)
+#define AM29_STATUS_DQ4             AM29_PARALLEL(0x0010)
+#define AM29_STATUS_DQ3             AM29_PARALLEL(0x0008)
+#define AM29_STATUS_DQ2             AM29_PARALLEL(0x0004)
+#define AM29_STATUS_DQ1             AM29_PARALLEL(0x0002)
+#define AM29_STATUS_DQ0             AM29_PARALLEL(0x0001)
+
+// The addresses used for programming the flash may be different from
+// the ones used to read the flash. For example the former may be in
+// uncached memory while the latter are in cached memory. The platform
+// HAL can provide a macro HAL_AM29XXXXX_P2V() to convert an address
+// relative to the base in the flash dev structure to the address that
+// should actually be manipulated.
+# ifdef HAL_AM29XXXXX_P2V
+#  define AM29_P2V(_addr_)  (volatile AM29_TYPE*)HAL_AM29XXXXX_P2V(_addr_)
+# else
+#  define AM29_P2V(_addr_)  (volatile AM29_TYPE*)(_addr_)
+# endif
+
+// When programming the flash the source data may not be aligned
+// correctly (although usually it will be). Hence it is necessary to
+// construct the 16-bit or 32-bit numbers to be written to the flash
+// from individual bytes, allowing for endianness.
+#define AM29_NEXT_DATUM_8(_ptr_) (*_ptr_++)
+#if CYG_BYTEORDER == CYG_LSBFIRST
+# define AM29_NEXT_DATUM_16(_ptr_)                  \
+    ({                                              \
+        cyg_uint16 _result_;                        \
+        _result_  = (_ptr_[1] << 8) | _ptr_[0];     \
+        _ptr_    += 2;                              \
+        _result_; })
+
+# define AM29_NEXT_DATUM_32(_ptr_)                                                      \
+    ({                                                                                  \
+        cyg_uint16 _result_;                                                            \
+        _result_  = (_ptr_[3] << 24) | (_ptr_[2] << 16) | (_ptr_[1] << 8) | _ptr_[0];   \
+        _ptr_    += 4;                                                                  \
+        _result_; })
+#else
+# define AM29_NEXT_DATUM_16(_ptr_)                  \
+    ({                                              \
+        cyg_uint16 _result_;                        \
+        _result_  = (_ptr_[0] << 8) | _ptr_[1];     \
+        _ptr_    += 2;                              \
+        _result_; })
+
+# define AM29_NEXT_DATUM_32(_ptr_)                                                      \
+    ({                                                                                  \
+        cyg_uint16 _result_;                                                            \
+        _result_  = (_ptr_[0] << 24) | (_ptr_[1] << 16) | (_ptr_[2] << 8) | _ptr_[3];   \
+        _ptr_    += 4;                                                                  \
+        _result_; })
+
+#endif
+
+// ----------------------------------------------------------------------------
+// Generic code.
+
+// A dummy initialization routine, for platforms where everything is
+// done statically and there is no need to check device ids or anything similar.
+int
+cyg_am29xxxxx_init_nop(struct cyg_flash_dev* dev)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    return CYG_FLASH_ERR_OK;
+}
+
+// A dummy query routine. The implementation of this is specific to
+// each device driver, and I choose to do as little as possible.
+size_t
+cyg_am29xxxxx_query_nop(struct cyg_flash_dev* dev, void* data, const size_t len)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    CYG_UNUSED_PARAM(void*, data);
+    CYG_UNUSED_PARAM(size_t, len);
+    return 0;
+}
+
+// A dummy hwr_map_error routine.
+int
+cyg_am29xxxxx_hwr_map_error_nop(struct cyg_flash_dev* dev, int err)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    return err;
+}
+
+// Dummy lock/unlock routines
+int
+cyg_am29xxxxx_lock_nop(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    CYG_UNUSED_PARAM(cyg_flashaddr_t, addr);
+    return CYG_FLASH_ERR_DRV_WRONG_PART;
+}
+
+int
+cyg_am29xxxxx_unlock_nop(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    CYG_UNUSED_PARAM(cyg_flashaddr_t, addr);
+    return CYG_FLASH_ERR_DRV_WRONG_PART;
+}
+
+// On some architectures there are problems calling the .2ram
+// functions from the main ones. Specifically the compiler may issue a
+// short call, even though the flash and ram are too far apart. The
+// solution is to indirect via a function pointer, but the simplistic
+// approach is vulnerable to compiler optimization. Hence the function
+// pointer is passed through an anonymizer. Even this may fail in
+// future if the compiler starts doing global optimization.
+static void*
+am29_anonymizer(void* fn)
+{
+    return fn;
+}
+
+// Get info about the current block, i.e. base and size.
+static void
+am29_get_block_info(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr, cyg_flashaddr_t* block_start, size_t* block_size)
+{
+    cyg_uint32      i;
+    size_t          offset  = addr - dev->start;
+    cyg_flashaddr_t result;
+
+    result  = dev->start;
+    
+    for (i = 0; i < dev->num_block_infos; i++) {
+        if (offset < (dev->block_info[i].blocks * dev->block_info[i].block_size)) {
+            offset         -= (offset % dev->block_info[i].block_size);
+            *block_start    = result + offset;
+            *block_size     = dev->block_info[i].block_size;
+            return;
+        }
+        result  += (dev->block_info[i].blocks * dev->block_info[i].block_size);
+        offset  -= (dev->block_info[i].blocks * dev->block_info[i].block_size);
+    }
+    CYG_FAIL("Address out of range of selected flash device");
+}
+
+// ----------------------------------------------------------------------------
+// Instantiate all of the h/w functions appropriate for the various
+// configurations.
+//   The suffix is used to construct the function names.
+//   Types for the width of the bus, controlling the granularity of access.
+//   devcount specifies the number of devices in parallel, and is used for looping
+//   The NEXT_DATUM() macro allows for misaligned source data.
+//   The PARALLEL macro, if defined, is used for sending commands and reading
+//   status bits from all devices in the bank in one operation.
+
+// A single 8-bit device on an 8-bit bus.
+#define AM29_SUFFIX             8
+#define AM29_TYPE               cyg_uint8
+#define AM29_DEVCOUNT           1
+#define AM29_NEXT_DATUM(_ptr_)  AM29_NEXT_DATUM_8(_ptr_)
+
+#include "am29xxxxx_aux.c"
+
+#undef AM29_SUFFIX
+#undef AM29_TYPE
+#undef AM29_DEVCOUNT
+#undef AM29_NEXT_DATUM
+
+// A single 16-bit device.
+#define AM29_SUFFIX             16
+#define AM29_TYPE               cyg_uint16
+#define AM29_DEVCOUNT           1
+#define AM29_NEXT_DATUM(_ptr_)  AM29_NEXT_DATUM_16(_ptr_)
+
+#include "am29xxxxx_aux.c"
+
+#undef AM29_SUFFIX
+#undef AM29_TYPE
+#undef AM29_DEVCOUNT
+#undef AM29_NEXT_DATUM
+
+// A single 32-bit device.
+#define AM29_SUFFIX             32
+#define AM29_TYPE               cyg_uint32
+#define AM29_DEVCOUNT           1
+#define AM29_NEXT_DATUM(_ptr_)  AM29_NEXT_DATUM_32(_ptr_)
+
+#include "am29xxxxx_aux.c"
+
+#undef AM29_SUFFIX
+#undef AM29_TYPE
+#undef AM29_DEVCOUNT
+#undef AM29_NEXT_DATUM
+
+// Two 8-bit devices, giving a 16-bit bus. 
+#define AM29_SUFFIX             88
+#define AM29_TYPE               cyg_uint16
+#define AM29_DEVCOUNT           2
+#define AM29_NEXT_DATUM(_ptr_)  AM29_NEXT_DATUM_16(_ptr_)
+#define AM29_PARALLEL(_cmd_)     ((_cmd_ << 8) | _cmd_)
+
+#include "am29xxxxx_aux.c"
+
+#undef AM29_SUFFIX
+#undef AM29_TYPE
+#undef AM29_DEVCOUNT
+#undef AM29_NEXT_DATUM
+
+// Four 8-bit devices, giving a 32-bit bus. 
+#define AM29_SUFFIX             8888
+#define AM29_TYPE               cyg_uint32
+#define AM29_DEVCOUNT           4
+#define AM29_NEXT_DATUM(_ptr_)  AM29_NEXT_DATUM_32(_ptr_)
+#define AM29_PARALLEL(_cmd_)    ((_cmd_ << 24) | (_cmd_ << 16) | (_cmd_ << 8) | _cmd_)
+
+#include "am29xxxxx_aux.c"
+
+#undef AM29_SUFFIX
+#undef AM29_TYPE
+#undef AM29_DEVCOUNT
+#undef AM29_NEXT_DATUM
+
+// Two 16-bit devices, giving a 32-bit bus.
+#define AM29_SUFFIX             1616
+#define AM29_TYPE               cyg_uint32
+#define AM29_DEVCOUNT           2
+#define AM29_NEXT_DATUM(_ptr_)  AM29_NEXT_DATUM_32(_ptr_)
+#define AM29_PARALLEL(_cmd_)    ((_cmd_ << 16) | _cmd_)
+
+#include "am29xxxxx_aux.c"
+
+#undef AM29_SUFFIX
+#undef AM29_TYPE
+#undef AM29_DEVCOUNT
+#undef AM29_NEXT_DATUM
+
+// 16AS8. A 16-bit device hooked up so that only byte accesses are
+// allowed. This requires unusual offsets
+#define AM29_SUFFIX                 16as8
+#define AM29_TYPE                   cyg_uint8
+#define AM29_DEVCOUNT               1
+#define AM29_NEXT_DATUM(_ptr_)      AM29_NEXT_DATUM_8(_ptr_)
+#define AM29_OFFSET_COMMAND         0x0AAA
+#define AM29_OFFSET_COMMAND2        0x0555
+#define AM29_OFFSET_DEVID           0x0002
+#define AM29_OFFSET_DEVID2          0x001C
+#define AM29_OFFSET_DEVID3          0x001E
+#define AM29_OFFSET_CFI             0x00AA
+#define AM29_OFFSET_CFI_DATA(_idx_) (2 * _idx_)
+
+#include "am29xxxxx_aux.c"
new file mode 100644
--- /dev/null
+++ b/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c
@@ -0,0 +1,497 @@
+//==========================================================================
+//
+//      am29xxxxx_aux.c
+//
+//      Flash driver for the AMD family - implementation. 
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 eCosCentric Ltd
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    bartv
+// Contributors:
+// Date:         2004-11-05
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// This file is #include'd multiple times from the main am29xxxxx.c file,
+// It serves to instantiate the various hardware operations in ways
+// appropriate for all the bus configurations.
+
+// The following macros are used to construct suitable function names
+// for the current bus configuration. AM29_SUFFIX is #define'd before
+// each #include of am29xxxxx_aux.c
+
+#ifndef AM29_STR
+# define AM29_STR1(_a_) # _a_
+# define AM29_STR(_a_) AM29_STR1(_a_)
+# define AM29_CONCAT3_AUX(_a_, _b_, _c_) _a_##_b_##_c_
+# define AM29_CONCAT3(_a_, _b_, _c_) AM29_CONCAT3_AUX(_a_, _b_, _c_)
+#endif
+
+#define AM29_FNNAME(_base_) AM29_CONCAT3(_base_, _,  AM29_SUFFIX)
+
+// Similarly construct a forward declaration, placing the function in
+// the .2ram section. Each function must still be in a separate section
+// for linker garbage collection.
+
+# define AM29_RAMFNDECL(_base_, _args_) \
+  AM29_FNNAME(_base_) _args_ __attribute__((section (".2ram." AM29_STR(_base_) "_" AM29_STR(AM29_SUFFIX))))
+
+// Calculate the various offsets, based on the device count.
+// The main code may override these settings for specific
+// configurations, e.g. 16as8
+#ifndef AM29_OFFSET_COMMAND
+# define AM29_OFFSET_COMMAND    0x0555
+#endif
+#ifndef AM29_OFFSET_COMMAND2
+# define AM29_OFFSET_COMMAND2   0x02AA
+#endif
+#ifndef AM29_OFFSET_DEVID
+# define AM29_OFFSET_DEVID      0x0001
+#endif
+#ifndef AM29_OFFSET_DEVID2
+# define AM29_OFFSET_DEVID2     0x000E
+#endif
+#ifndef AM29_OFFSET_DEVID3
+# define AM29_OFFSET_DEVID3     0x000F
+#endif
+#ifndef AM29_OFFSET_CFI
+# define AM29_OFFSET_CFI        0x0055
+#endif
+#ifndef AM29_OFFSET_CFI_DATA
+# define AM29_OFFSET_CFI_DATA(_idx_) _idx_
+#endif
+
+// For parallel operation commands are issued in parallel and status
+// bits are checked in parallel.
+#ifndef AM29_PARALLEL
+# define AM29_PARALLEL(_cmd_)    (_cmd_)
+#endif
+
+// ----------------------------------------------------------------------------
+// When performing the various low-level operations like erase the flash
+// chip can no longer support ordinary data reads. Obviously this is a
+// problem if the current code is executing out of flash. The solution is
+// to store the key functions in RAM rather than flash, via a special
+// linker section .2ram which usually gets placed in the same area as
+// .data.
+//
+// In a ROM startup application anything in .2ram will consume space
+// in both the flash and RAM. Hence it is desirable to keep the .2ram
+// functions as small as possible, responsible only for the actual
+// hardware manipulation.
+//
+// All these .2ram functions should be invoked with interrupts
+// disabled. Depending on the hardware it may also be necessary to
+// have the data cache disabled. The .2ram functions must be
+// self-contained, even macro invocations like HAL_DELAY_US() are
+// banned because on some platforms those could be implemented as
+// function calls.
+
+// gcc requires forward declarations with the attributes, then the actual
+// definitions.
+static int  AM29_RAMFNDECL(am29_hw_query, (volatile AM29_TYPE*));
+static int  AM29_RAMFNDECL(am29_hw_cfi, (struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*));
+static void AM29_RAMFNDECL(am29_hw_erase, (volatile AM29_TYPE*));
+static void AM29_RAMFNDECL(am29_hw_program, (volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32 count));
+
+// Read the device id. This involves a straightforward command
+// sequence, followed by a reset to get back into array mode.
+// All chips are accessed in parallel, but only the response
+// from the least significant is used.
+static int
+AM29_FNNAME(am29_hw_query)(volatile AM29_TYPE* addr)
+{
+    int devid;
+    
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_SETUP1;
+    addr[AM29_OFFSET_COMMAND2]  = AM29_COMMAND_SETUP2;
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_AUTOSELECT;
+    devid                       = addr[AM29_OFFSET_DEVID] & 0x00FF;
+
+    // The original AMD chips only used a single-byte device id, but
+    // all codes have now been used up. Newer devices use a 3-byte
+    // devid. The above devid read will have returned 0x007E. The
+    // test allows for boards with a mixture of old and new chips.
+    // The amount of code involved is too small to warrant a config
+    // option.
+    if (0x007E == devid) {
+        devid <<= 16;
+        devid  |= ((addr[AM29_OFFSET_DEVID2] & 0x00FF) << 8);
+        devid  |=  (addr[AM29_OFFSET_DEVID3] & 0x00FF);
+    }
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
+    return devid;
+}
+
+// Perform a CFI query. This involves placing the device(s) into CFI
+// mode, checking that this has really happened, and then reading the
+// size and block info. The address corresponds to the start of the
+// flash.
+static int
+AM29_FNNAME(am29_hw_cfi)(struct cyg_flash_dev* dev, cyg_am29xxxxx_dev* am29_dev, volatile AM29_TYPE* addr)
+{
+    int     dev_size;
+    int     i;
+    int     erase_regions;
+
+    // Just a single write is needed to put the device into CFI mode
+    addr[AM29_OFFSET_CFI]   = AM29_COMMAND_CFI;
+    // Now check that we really are in CFI mode. There should be a 'Q'
+    // at a specific address. This test is not 100% reliable, but should
+    // be good enough.
+    if ('Q' != (addr[AM29_OFFSET_CFI_Q] & 0x00FF)) {
+        addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
+        return CYG_FLASH_ERR_PROTOCOL;
+    }
+    // Device sizes are always a power of 2, and the shift is encoded
+    // in a single byte
+    dev_size = 0x01 << (addr[AM29_OFFSET_CFI_SIZE] & 0x00FF);
+    dev->end = dev->start + dev_size - 1;
+
+    // The number of erase regions is also encoded in a single byte.
+    // Usually this is no more than 4. A value of 0 indicates that
+    // only chip erase is supported, but the driver does not cope
+    // with that.
+    erase_regions   = addr[AM29_OFFSET_CFI_BLOCK_REGIONS] & 0x00FF;
+    if (erase_regions > CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_REGIONS) {
+        addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
+        return CYG_FLASH_ERR_PROTOCOL;
+    }
+    dev->num_block_infos    = erase_regions;
+
+    for (i = 0; i < erase_regions; i++) {
+        cyg_uint32 count, size;
+        cyg_uint32 count_lsb   = addr[AM29_OFFSET_CFI_BLOCK_COUNT_LSB(i)] & 0x00FF;
+        cyg_uint32 count_msb   = addr[AM29_OFFSET_CFI_BLOCK_COUNT_MSB(i)] & 0x00FF;
+        cyg_uint32 size_lsb    = addr[AM29_OFFSET_CFI_BLOCK_SIZE_LSB(i)] & 0x00FF;
+        cyg_uint32 size_msb    = addr[AM29_OFFSET_CFI_BLOCK_SIZE_MSB(i)] & 0x00FF;
+
+        count = ((count_msb << 8) | count_lsb) + 1;
+        size  = (size_msb << 16) | (size_lsb << 8);
+        am29_dev->block_info[i].block_size  = (size_t) size * AM29_DEVCOUNT;
+        am29_dev->block_info[i].blocks      = count;
+    }
+
+    // Get out of CFI mode
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
+
+    return CYG_FLASH_ERR_OK;
+}
+
+// Erase a single sector. There is no API support for chip-erase. The
+// generic code operates one sector at a time, invoking the driver for
+// each sector, so there is no opportunity inside the driver for
+// erasing multiple sectors in a single call. The address argument
+// points at the start of the sector.
+static void
+AM29_FNNAME(am29_hw_erase)(volatile AM29_TYPE* addr)
+{
+    int     retries = CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_TIMEOUT;
+
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_SETUP1;
+    addr[AM29_OFFSET_COMMAND2]  = AM29_COMMAND_SETUP2;
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_ERASE;
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_SETUP1;
+    addr[AM29_OFFSET_COMMAND2]  = AM29_COMMAND_SETUP2;
+    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_ERASE_SECTOR;
+    // There is now a 50us window in which we could send additional
+    // ERASE_SECTOR commands, but the driver API does not allow this
+
+    // All chips are now erasing in parallel. Loop until all have
+    // completed. This can be detected in a number of ways. The DQ7
+    // bit will be 0 until the erase is complete, but there is a
+    // problem if something went wrong (e.g. the sector is locked),
+    // the erase has not actually started, and the relevant bit was 0
+    // already. More useful is DQ6. This will toggle during the 50us
+    // window and while the erase is in progress, then stop toggling.
+    // If the erase does not actually start then the bit won't toggle
+    // at all so the operation completes rather quickly.
+    //
+    // If at any time DQ5 is set (indicating a timeout inside the
+    // chip) then a reset command must be issued and the erase is
+    // aborted. It is not clear this can actually happen during an
+    // erase, but just in case.
+    do {
+        AM29_TYPE   datum1, datum2;
+        datum1  = addr[AM29_OFFSET_COMMAND];
+        datum2  = addr[AM29_OFFSET_COMMAND];
+        if ((datum1 & AM29_STATUS_DQ6) == (datum2 & AM29_STATUS_DQ6)) {
+            // The bits have stopped toggling, so finished.
+            break;
+        }
+        if (0 != ((datum1 | datum2) & AM29_STATUS_DQ5)) {
+            addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
+            break;
+        }
+    } while (retries-- > 0);
+
+    // The calling code will verify that the erase was successful,
+    // and generate an error code.
+}
+
+// Write data to flash. At most one block will be processed at a time,
+// but the write may be for a subset of the write. The destination
+// address will be aligned in a way suitable for the bus. The source
+// address need not be aligned. The count is in AM29_TYPE's, i.e.
+// as per the bus alignment, not in bytes.
+static void
+AM29_FNNAME(am29_hw_program)(volatile AM29_TYPE* block_start, volatile AM29_TYPE* addr, const cyg_uint8* buf, cyg_uint32 count)
+{
+    int     retries;
+    int     i;
+    
+    for (i = 0; i < count; i++) {
+        AM29_TYPE   datum;
+        AM29_TYPE   current, masked_datum;
+        
+        // We can only clear bits, not set them, so any bits that were
+        // already clear need to be preserved.
+        current = addr[i];
+        datum   = AM29_NEXT_DATUM(buf) & current;
+        if (datum == current) {
+            // No change, so just move on.
+            continue;
+        }
+        
+        block_start[AM29_OFFSET_COMMAND]    = AM29_COMMAND_SETUP1;
+        block_start[AM29_OFFSET_COMMAND2]   = AM29_COMMAND_SETUP2;
+        block_start[AM29_OFFSET_COMMAND]    = AM29_COMMAND_PROGRAM;
+        addr[i] = datum;
+
+        // The data is now being written. While the write is in progress
+        // DQ7 will have an inverted value from what was written, so we
+        // can poll, comparing just this bit. Again, if DQ5 is set then
+        // an error has occurred.
+        masked_datum = datum & AM29_STATUS_DQ7;
+        retries = CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_TIMEOUT;
+        do {
+            current = addr[i];
+            if ((current & AM29_STATUS_DQ7) == masked_datum) {
+                break;
+            }
+            if (0 != (current & AM29_STATUS_DQ5)) {
+                current = addr[i];
+                if (current == datum) {
+                    // Race condition, but the operation did succeed.
+                    break;
+                } else {
+                    // A timeout has occurred inside the hardware and
+                    // the system is in a strange state. Reset but don't
+                    // try to write any more of the data.
+                    block_start[AM29_OFFSET_COMMAND]    = AM29_COMMAND_RESET;
+                    return;
+                }
+            }
+        } while (retries-- > 0);
+
+        if (0 == retries) {
+            // Failed to write this word, no point in trying to write the rest.
+            return;
+        }
+    }
+}
+
+// FIXME: implement a separate program routine for buffered writes. 
+
+// ----------------------------------------------------------------------------
+// Exported code, mostly for placing in a cyg_flash_dev_funs structure.
+
+// Just read the device id, either for sanity checking that the system
+// has been configured for the right device, or for filling in the
+// block info by a platform-specific init routine if the platform may
+// be manufactured with one of several different chips.
+int
+AM29_FNNAME(cyg_am29xxxxx_read_devid) (struct cyg_flash_dev* dev)
+{
+    int                 (*query_fn)(volatile AM29_TYPE*);
+    int                 devid;
+    volatile AM29_TYPE* addr;
+
+    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+    
+    addr     = AM29_P2V(dev->start);
+    query_fn = (int (*)(volatile AM29_TYPE*)) am29_anonymizer( & AM29_FNNAME(am29_hw_query) );
+    devid    = (*query_fn)(addr);
+    return devid;
+}
+
+// Validate that the device statically configured is the one on the
+// board.
+int
+AM29_FNNAME(cyg_am29xxxxx_init_check_devid)(struct cyg_flash_dev* dev)
+{
+    cyg_am29xxxxx_dev*  am29_dev;
+    int                 devid;
+
+    am29_dev = (cyg_am29xxxxx_dev*) dev->priv;
+    devid    = AM29_FNNAME(cyg_am29xxxxx_read_devid)(dev);
+    if (devid != am29_dev->devid) {
+        return CYG_FLASH_ERR_DRV_WRONG_PART;
+    }
+    // Successfully queried the device, and the id's match. That
+    // should be a good enough indication that the flash is working.
+    return CYG_FLASH_ERR_OK;
+}
+
+// Initialize via a CFI query, instead of statically specifying the
+// boot block layout.
+int
+AM29_FNNAME(cyg_am29xxxxx_init_cfi)(struct cyg_flash_dev* dev)
+{
+    int                 (*cfi_fn)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*);
+    volatile AM29_TYPE* addr;
+    cyg_am29xxxxx_dev*  am29_dev;
+    int                 result;
+    
+    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+    am29_dev    = (cyg_am29xxxxx_dev*) dev->priv;
+    addr        = AM29_P2V(dev->start);
+    cfi_fn      = (int (*)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*))
+        am29_anonymizer( & AM29_FNNAME(am29_hw_cfi));
+
+    result      = (*cfi_fn)(dev, am29_dev, addr);
+
+    // Now calculate the device size, and hence the end field.
+    if (CYG_FLASH_ERR_OK == result) {
+        int i;
+        int size    = 0;
+        for (i = 0; i < dev->num_block_infos; i++) {
+            size += (dev->block_info[i].block_size * dev->block_info[i].blocks);
+        }
+        dev->end = dev->start + size - 1;
+    }
+    return result;
+}
+
+// Erase a single block. The calling code will have supplied a pointer
+// aligned to a block boundary.
+int
+AM29_FNNAME(cyg_am29xxxxx_erase)(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    void                (*erase_fn)(volatile AM29_TYPE*);
+    volatile AM29_TYPE* block;
+    cyg_flashaddr_t     block_start;
+    size_t              block_size;
+    int                 i;
+
+    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+    CYG_ASSERT((addr >= dev->start) && (addr <= dev->end), "flash address out of device range");
+
+    am29_get_block_info(dev, addr, &block_start, &block_size);
+    CYG_ASSERT(addr == block_start, "erase address should be the start of a flash block");
+    
+    block       = AM29_P2V(addr);
+    erase_fn    = (void (*)(volatile AM29_TYPE*)) am29_anonymizer( & AM29_FNNAME(am29_hw_erase) );
+    (*erase_fn)(block);
+
+    // The erase may have failed for a number of reasons, e.g. because
+    // of a locked sector. The best thing to do here is to check that the
+    // erase has succeeded.
+    block = (AM29_TYPE*) addr;
+    for (i = 0; i < (block_size / sizeof(AM29_TYPE)); i++) {
+        if (block[i] != (AM29_TYPE)~0) {
+            // There is no easy way of detecting the specific error,
+            // e.g. locked flash block, timeout, ... So return a
+            // useless catch-all error.
+            return CYG_FLASH_ERR_ERASE;
+        }
+    }
+    return CYG_FLASH_ERR_OK;
+}
+
+// Write some data to the flash. The destination must be aligned
+// appropriately for the bus width (not the device width).
+int
+AM29_FNNAME(cyg_am29xxxxx_program)(struct cyg_flash_dev* dev, const cyg_flashaddr_t dest, const void* src, const size_t len)
+{
+    void                (*program_fn)(volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32);
+    volatile AM29_TYPE* block;
+    volatile AM29_TYPE* addr; 
+    cyg_flashaddr_t     block_start;
+    size_t              block_size;
+    const cyg_uint8*    data;
+    int                 i;
+
+    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+    CYG_ASSERT((dest >= dev->start) && (addr <= dev->end), "flash address out of device range");
+
+    // Only support writes that are aligned to the bus boundary. This
+    // may be more restrictive than what the hardware is capable of.
+    // However it ensures that the hw_program routine can write as
+    // much data as possible each iteration, and hence significantly
+    // improves performance. The length had better be a multiple of
+    // the bus width as well
+    if ((0 != ((CYG_ADDRWORD)dest & (sizeof(AM29_TYPE) - 1))) ||
+        (0 != (len & (sizeof(AM29_TYPE) - 1)))) {
+        return CYG_FLASH_ERR_INVALID;
+    }
+
+    am29_get_block_info(dev, dest, &block_start, &block_size);
+    CYG_ASSERT(((dest - block_start) + len) <= block_size, "write cannot cross block boundary");
+    
+    block       = AM29_P2V(block_start);
+    addr        = AM29_P2V(dest);
+    data        = (const cyg_uint8*) src;
+
+    program_fn  = (void (*)(volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32))
+        am29_anonymizer( & AM29_FNNAME(am29_hw_program) );
+    (*program_fn)(block, addr, (const cyg_uint8*)src, len / sizeof(AM29_TYPE));
+    
+    // Too many things can go wrong when manipulating the h/w, so
+    // verify the operation by actually checking the data.
+    addr = (volatile AM29_TYPE*) dest;
+    for (i = 0; i < (len / sizeof(AM29_TYPE)); i++) {
+        AM29_TYPE   datum   = AM29_NEXT_DATUM(data);
+        AM29_TYPE   current = addr[i];
+        if ((datum & current) != current) {
+            return CYG_FLASH_ERR_PROGRAM;
+        }
+    }
+    return CYG_FLASH_ERR_OK;
+}
+
+// ----------------------------------------------------------------------------
+// Clean up the various #define's so this file can be #include'd again
+#undef AM29_FNNAME
+#undef AM29_RAMFNDECL
+#undef AM29_OFFSET_COMMAND
+#undef AM29_OFFSET_COMMAND2
+#undef AM29_OFFSET_DEVID
+#undef AM29_OFFSET_DEVID2
+#undef AM29_OFFSET_DEVID3
+#undef AM29_OFFSET_CFI
+#undef AM29_OFFSET_CFI_DATA
+#undef AM29_PARALLEL
--- a/packages/ecos.db
+++ b/packages/ecos.db
@@ -181,6 +181,16 @@ package CYGPKG_DEVS_FLASH_AMD_AM29XXXXX 
            flash memory devices."
 }
 
+package CYGPKG_DEVS_FLASH_AMD_AM29XXXXX_V2 {
+	alias 		{ "Support for AMD AM29xxxxx flash memory" flash_amd_am29xxxxx_v2 }
+	directory	devs/flash/amd/am29xxxxxv2
+	script		flash_am29xxxxx_v2.cdl
+	hardware
+        description "
+           This package contains hardware support for AMD AM29xxxxx
+           flash memory devices."
+}
+
 package CYGPKG_DEVS_FLASH_ATMEL_AT29CXXXX {
 	alias 		{ "Support for Atmel AT29Cxxxx flash memory" flash_atmel_at29cxxxx }
 	directory	devs/flash/atmel/at29cxxxx