This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

V2 flash - new AM29xxxxx driver


This patch adds a new driver for AM29xxxxx flash devices and
compatibles, for use with the V2 flash API. It can coexist with the
old driver so existing platforms are unaffected.

This driver is structured very differently from the previous driver -
see the documentation on how to instantiate support for a given
platform. Amongst the key differences are:

1) there is no attempt to maintain a central parts file with details
   of all the devices. With hundreds of such devices and more being
   added all the time, a central parts file makes little sense. This
   should eliminate the need to update the AM29xxxxx driver for almost
   every port that uses those chips.

2) instead the device size and boot block layout can be provided
   statically in the platform HAL, as a simple part of the porting
   process. Alternatively the driver can use CFI to figure out these
   details at run-time, although that will add a bit to the code size.

3) it is much easier for a platform HAL to customize the behaviour of
   various operations like erase and program.

4) the code that actually manipulates the hardware is carefully
   isolated. I need this for future work. As a side effect the amount
   of code in .2ram should be kept to a minimum, which will help with
   code size in ROM startup applications.

5) this driver comes with documentation.

The boards I am currently using all have a single 16-bit device, so
only the 16 bus configuration has been tested. Also I have only used
the code on big-endian processors.

Bart

Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/ChangeLog,v
retrieving revision 1.142.2.2
diff -u -r1.142.2.2 ChangeLog
--- ChangeLog	6 Aug 2004 11:17:08 -0000	1.142.2.2
+++ ChangeLog	20 Nov 2004 17:29:57 -0000
@@ -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.
Index: ecos.db
===================================================================
RCS file: /cvs/ecos/ecos/packages/ecos.db,v
retrieving revision 1.126.2.3
diff -u -r1.126.2.3 ecos.db
--- ecos.db	5 Oct 2004 09:24:46 -0000	1.126.2.3
+++ ecos.db	20 Nov 2004 17:30:25 -0000
@@ -181,6 +181,16 @@
            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
Index: devs/flash/amd/am29xxxxxv2/current/ChangeLog
===================================================================
RCS file: devs/flash/amd/am29xxxxxv2/current/ChangeLog
diff -N devs/flash/amd/am29xxxxxv2/current/ChangeLog
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/flash/amd/am29xxxxxv2/current/ChangeLog	20 Nov 2004 17:30:30 -0000
@@ -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####
+//===========================================================================
Index: devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl
===================================================================
RCS file: devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl
diff -N devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl	20 Nov 2004 17:30:31 -0000
@@ -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."
+        }
+    }
+}
Index: devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h
===================================================================
RCS file: devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h
diff -N devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h	20 Nov 2004 17:30:36 -0000
@@ -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
Index: devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c
===================================================================
RCS file: devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c
diff -N devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c	20 Nov 2004 17:30:40 -0000
@@ -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"
Index: devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c
===================================================================
RCS file: devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c
diff -N devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c	20 Nov 2004 17:30:42 -0000
@@ -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
Index: devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml
===================================================================
RCS file: devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml
diff -N devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml	20 Nov 2004 17:30:36 -0000
@@ -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>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]