summaryrefslogtreecommitdiff
path: root/ecos/packages/devs/flash/amd/am29xxxxxv2
diff options
context:
space:
mode:
Diffstat (limited to 'ecos/packages/devs/flash/amd/am29xxxxxv2')
-rw-r--r--ecos/packages/devs/flash/amd/am29xxxxxv2/current/ChangeLog220
-rw-r--r--ecos/packages/devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl222
-rw-r--r--ecos/packages/devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml789
-rw-r--r--ecos/packages/devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h138
-rw-r--r--ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c514
-rw-r--r--ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c985
6 files changed, 2868 insertions, 0 deletions
diff --git a/ecos/packages/devs/flash/amd/am29xxxxxv2/current/ChangeLog b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/ChangeLog
new file mode 100644
index 0000000..f3d9a9d
--- /dev/null
+++ b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/ChangeLog
@@ -0,0 +1,220 @@
+2009-04-20 Rene Schipp von Branitz Nielsen <rbn@vitesse.com>
+
+ * src/am29xxxxx.c: Added set of parentheses around macro
+ parameters used in multiplications. Fixes 16as8 bug.
+
+2008-12-19 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * cdl/flash_am29xxxxx_v2.cdl: Doh, fix doc link properly.
+
+2008-11-20 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * cdl/flash_am29xxxxx_v2.cdl: Fix doc link.
+
+2008-09-24 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx_aux.c (am29_hw_program): fix handling of parallel
+ chips. Get the debug diagnostics to build cleanly.
+
+2008-05-13 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/am29xxxxx_aux.c (am29_hw_query): Allow devices to return
+ device IDs of larger than a byte.
+
+2007-07-08 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx.c, src/am29xxxxx_aux.c: add 2ram entry and exit
+ hooks to give HALs some extra control over the low-level flash
+ operations.
+
+2007-06-21 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx_aux.c: issue a memory barrier after every command
+ that gets sent to the flash, to avoid problems with pipelines that
+ mess about with write ordering.
+
+2007-05-31 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx.c: skip data cache manipulation on architectures
+ which do not have a data cache.
+
+2007-05-29 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * cdl/flash_am29xxxxx_v2.cdl
+ (CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME): New option.
+ Allow Flash devices to indicate that they should be sent a "resume"
+ command on startup.
+ * src/am29xxxxx_aux.c (am29_hw_force_all_suspended_resume): New
+ function to implement above CDL.
+ (cyg_am29xxxxx_init_check_dev): Call the new function.
+ (cyg_am29xxxxx_init_cfi): Ditto.
+ (am29_hw_cfi): manufacturer_id and vendor private areas need only
+ lowest byte taken, to handle multiple parallel devices.
+
+2007-03-29 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx_aux.c (am29_hw_erase): use DQ7 to detect
+ termination instead of DQ6. This avoids hardware problems where
+ the toggling of DQ6 is not detected.
+
+2007-03-05 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/am29xxxxx_aux.c (am29_hw_cfi): Added missing AM29_SWAP() to
+ fetch of offset of vendor specific data.
+
+2006-09-27 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/am29xxxxx_aux.c (am29_hw_cfi): Added generic code to deal
+ with flash parts that may specify their erase regions in reverse
+ order to reality. Removed older code that was too specific to
+ particular devices.
+ A few changes to the diagnostics in various places.
+
+ * cdl/flash_am29xxxxx_v2.cdl: Replaced
+ CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_AT49_CFI with
+ CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CFI_BOGOSITY. This option
+ performs much the same purpose, but is generic to many more flash
+ parts.
+
+2006-08-31 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/am29xxxxx_aux.c: Added support for ST flash parts which have
+ similar, but not identical, peculiarities in their CFI data to the
+ Atmel parts supported earlier.
+
+2006-08-24 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/am29xxxxx.c: Provide a default HAL_MEMORY_BARRIER()
+ define if the HAL hasn't provided one.
+ * src/am29xxxxx_aux.c: Use HAL_MEMORY_BARRIER() any time the
+ flash is reset back to read array mode. Some processors
+ need to have their write buffers flushed.
+
+2006-06-29 Nick Garnett <nickg@ecoscentric.com>
+
+ * cdl/flash_am29xxxxx_v2.cdl:
+ * src/am29xxxxx_aux.c:
+ Added configurable delay between each word during
+ programming. Some targets seem to need this.
+ Also added some simple diagnostics.
+
+2006-05-15 John Dallaway <jld@ecoscentric.com>
+
+ * doc/am29xxxxx.sgml: Fix missing </refentry> tag.
+ * cdl/flash_am29xxxx_v2.cdl: Reference package documentation.
+
+2005-09-26 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx.c, src/am29xxxxx_aux.c: add AM29_SWAP() support for
+ platforms where the bus connection is wired up strangely.
+
+ * src/am29xxxxx_aux.c, cdl/flash_am29xxxxx_v2.cdl: add optional
+ support for certain Atmel chips which have a peculiar
+ implementation of CFI.
+
+2005-08-17 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * cdl/flash_am29xxxx_v2.cdl: Provide new
+ CYGIMP_DEVS_FLASH_AMD_AM29XXXXX_V2_LEAVE_INTERRUPTS_ENABLED
+ and CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY options
+ to provide better control of when to enable/disable interrupts
+ or caches. Taken from the Strata flash example.
+ * include/am29xxxxx_dev.h: Declare cyg_at49xxxx_softlock, _hardlock
+ and _unlock variants.
+ * src/am29xxxxx.c: Define AT49 locking commands.
+ Provide AM29_UNCACHE_ADDRESS in line with the Strata driver,
+ to be controlled by the above new CDL options, in place of
+ AM29_P2V.
+ * src/am29xxxxx_aux.c: Provide AT49 lock status definition.
+ Provide AT49 softlock/hardlock/unlock API functions and
+ underlying implementation functions.
+ Adopt AM29_UNCACHED_ADDRESS rename.
+ * doc/am29xxxxx.sgml: Update documentation to cover AT49xxxx
+ locking operations and above new CDL options.
+
+2005-06-12 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx_aux.c (cyg_am29xxxxx_program): remove unnecessary
+ loops variable
+ * cdl/flash_am29xxxxx_v2.cdl: minor reorganization to put the
+ important config option first
+ * doc/am29xxxxx.sgml: document the important config options
+
+2005-02-23 Bart Veer <bartv@ecoscentric.com>
+
+ * doc/am29xxxxx.sgml: bring up to date.
+
+2005-01-19 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/am29xxxxx_aux.c (am29_hw_erase): Handle interleaved
+ (parallel) flash correctly when one device finishes before another.
+ (am29_hw_program): Similar.
+ (cyg_am29xxxxx_program): Use assert correctly.
+
+ * src/am29xxxxx.c (AM29_NEXT_DATUM_32): Use cyg_uint32, not
+ cyg_uint16.
+
+2004-12-02 Bart Veer <bartv@ecoscentric.com>
+
+ * src/am29xxxxx.c, include/am29xxxxx_dev.h: <cyg/io/flash_priv.h>
+ no longer exists, use <cyg/io/flash_dev.h> instead.
+
+2004-11-29 Bart Veer <bartv@ecoscentric.com>
+
+ * include/am29xxxxx_dev.h, src/am29xxxxx.c: eliminate
+ hwr_map_error() support, no longer needed
+
+ * include/am29xxxxx_dev.h, src/am29xxxxx.c, src/am29xxxxx_aux.c:
+ The dummy init/query/lock/unlock functions have been moved to the
+ generic flash package. That also now exports an anonymizer
+ function.
+
+2004-11-25 Bart Veer <bartv@ecoscentric.com>
+
+ * cdl/flash_am29xxxxx_v2.cdl, src/am29xxxxx.c,
+ src/am29xxxxx_aux.c: this driver can manage the flash and
+ interrupts itself, without support from the generic flash code.
+
+2004-11-22 Bart Veer <bartv@ecoscentric.com>
+
+ * include/am29xxxxx_dev.h, src/am29xxxxx.c, src/am29xxxxx_aux.c,
+ doc/am29xxxxx.sgml: implement changes to the interface between the
+ generic flash code and the device drivers.
+ * include/am29xxxxx_dev.h: rename cyg_block_info to
+ cyg_flash_block_info
+
+2004-11-21 Bart Veer <bartv@ecoscentric.com>
+
+ * doc/am29xxxxx.sgml: describe CDL implications for custom locking
+ functions and additional devices.
+
+ * cdl/flash_am29xxxxx_v2.cdl: CYGHWR_IO_FLASH_DEVICE_V2 is now
+ implicit
+
+2004-11-05 Bart Veer <bartv@ecoscentric.com>
+
+ * New AM29xxxxx flash driver created
+
+//===========================================================================
+// ####GPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+//
+// This program 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.
+//
+// This program 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 this program; if not, write to the
+// Free Software Foundation, Inc., 51 Franklin Street,
+// Fifth Floor, Boston, MA 02110-1301, USA.
+// -------------------------------------------
+// ####GPLCOPYRIGHTEND####
+//===========================================================================
diff --git a/ecos/packages/devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl
new file mode 100644
index 0000000..f59b383
--- /dev/null
+++ b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/cdl/flash_am29xxxxx_v2.cdl
@@ -0,0 +1,222 @@
+# ====================================================================
+#
+# 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, 2005, 2006, 2007 Free Software Foundation, Inc.
+##
+## 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.,
+## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2.
+##
+## 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"
+ doc ref/devs-flash-am29xxxxx.html
+ parent CYGPKG_IO_FLASH
+ active_if CYGPKG_IO_FLASH
+ implements CYGHWR_IO_FLASH_DEVICE
+ 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_PROGRAM_TIMEOUT {
+ display "Maximum number of iterations during a write"
+ flavor data
+ default_value 100000000
+ legal_values 1024 to 0x7fffffff
+ description "
+ Flash program operations may take a long time, and the driver
+ needs to poll the device 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_DELAY {
+ display "Delay between words while programming"
+ flavor data
+ default_value 0
+ legal_values 0 to 0x7fffffff
+ description "The timings of certain processors and flash devices mean that
+ a short delay may be required between each word as it is programmed.
+ This option defines that delay in terms of iterations of a delay
+ loop."
+ }
+
+ cdl_option CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_TIMEOUT {
+ display "Maximum number of iterations during a block erase"
+ flavor data
+ default_value 100000000
+ legal_values 1024 to 0x7fffffff
+ 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 CYGIMP_DEVS_FLASH_AMD_AM29XXXXX_V2_LEAVE_INTERRUPTS_ENABLED {
+ display "Leave interrupts enabled during flash operations"
+ active_if { ! CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY }
+ default_value 0
+ description "
+ On typical hardware erasing or programming a flash block requires
+ disabling interrupts and possibly the cache. During these operations
+ some or all of the flash hardware will be unusable, and disabling
+ interrupts is the only reliable way of ensuring that no interrupt
+ handler or other thread will try to access the flash in the middle
+ of the operation. This can have a major impact on the real-time
+ responsiveness of typical applications.
+
+ In some circumstances it is possible to leave interrupts enabled.
+ The application must run in RAM, not in flash. There must be some
+ way of accessing the flash which bypasses the cache. The application
+ must only access the flash using the proper API, for example
+ cyg_flash_read(), which ensures that only one thread at a time can
+ access a flash device. Finally there must be no possibility of
+ entering a ROM monitor running in flash. This can happen if RedBoot
+ is used as the ROM monitor and virtual vectors are enabled. It can
+ also happen when debugging the application via RedBoot or gdb stubs.
+
+ If the application can absolutely guarantee that the flash will not be
+ accessed during a flash operation then it is possible to enable this option,
+ improving interrupt latency. Any unexpected flash accesses are likely
+ to cause a system crash. If in doubt leave this option disabled."
+ }
+
+ cdl_interface CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY {
+ display "Flash memory accesses are always cached"
+ flavor bool
+ description "
+ Flash memory devices are usually accessed via the cache to achieve
+ acceptable performance. However erase and program operations need
+ to access the flash directly, bypassing the cache. On some targets
+ it is possible to access the flash in an uncached part of the
+ address space, for example by suitable MMU settings. On other
+ targets it is necessary to disable the cache while erasing or
+ programming blocks of flash. In the latter case the platform HAL
+ will implement this interface."
+ }
+
+ cdl_interface CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CFI_BOGOSITY {
+ display "Include support for unusual CFI implementation"
+ flavor bool
+ description "
+ CFI, Common Flash Interface, is a standard allowing device drivers
+ to query the hardware for characteristics such as the erase region
+ layout. Some flash chips have a somewhat strange implementation of CFI,
+ requiring extra code within the device driver. If CFI is used for device
+ initialization and if the platform may come with one of these flash chips
+ then the platform HAL will implement this interface."
+ }
+
+ cdl_interface CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME {
+ display "Erase/program resume is needed after reset"
+ flavor bool
+ description "
+ With true AMD-compatible flash parts, a reset command will also
+ abort any suspended erase or program operations. But on some
+ parts which are nearly but not quite compatible, such as AT49xxxxx,
+ this does not happen, and so an erase/program resume command is
+ needed after a soft reset in order to be able to use the chip."
+ }
+
+ 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_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."
+ }
+ }
+}
diff --git a/ecos/packages/devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml
new file mode 100644
index 0000000..cbe7e29
--- /dev/null
+++ b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/doc/am29xxxxx.sgml
@@ -0,0 +1,789 @@
+<!-- DOCTYPE part PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->
+
+<!-- {{{ Banner -->
+
+<!-- =============================================================== -->
+<!-- -->
+<!-- am29xxxxx.sgml -->
+<!-- -->
+<!-- Documentation for the am29xxxxx flash device driver. -->
+<!-- -->
+<!-- =============================================================== -->
+<!-- ####ECOSDOCCOPYRIGHTBEGIN#### -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. -->
+<!-- This material may be distributed only subject to the terms -->
+<!-- and conditions set forth in the Open Publication License, v1.0 -->
+<!-- or later (the latest version is presently available at -->
+<!-- http://www.opencontent.org/openpub/) -->
+<!-- Distribution of the work or derivative of the work in any -->
+<!-- standard (paper) book form is prohibited unless prior -->
+<!-- permission obtained from the copyright holder -->
+<!-- =============================================================== -->
+<!-- ####ECOSDOCCOPYRIGHTEND#### -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN#### -->
+<!-- -->
+<!-- Author(s): 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. Normally the driver is not
+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>
+There are a 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_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>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>cyg_flashaddr_t <parameter>addr</parameter></paramdef>
+ <paramdef>const void* <parameter>data</parameter></paramdef>
+ <paramdef>size_t <parameter>len</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>int <function>cyg_at49xxxx_softlock</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_at49xxxx_hardlock</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_at49xxxx_unlock</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 but 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 the details of every chip and
+every platform. Instead it is the responsibility of another package,
+usually the platform HAL, to supply the necessary information by
+instantiating some data 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 there will be a trade off between cost and performance: 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 top 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>
+In most cases flash support is specific to a 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 should be 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_dev.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_flash_devfn_query_nop,
+ &amp;cyg_am29xxxxx_erase_16,
+ &amp;cyg_am29xxxxx_program_16,
+ (int (*)(struct cyg_flash_dev*, const cyg_flashaddr_t, void*, size_t))0,
+ &amp;cyg_flash_devfn_lock_nop,
+ &amp;cyg_flash_devfn_unlock_nop);
+
+static const cyg_am29xxxxx_dev hal_alaia_flash_priv = {
+ .devid = 0x45,
+ .block_info = {
+ { 0x00004000, 1 },
+ { 0x00002000, 2 },
+ { 0x00008000, 1 },
+ { 0x00010000, 63 }
+ }
+};
+
+CYG_FLASH_DRIVER(hal_alaia_flash,
+ &amp;hal_alaia_flash_amd_funs,
+ 0,
+ 0xFFC00000,
+ 0xFFFFFFFF,
+ 4,
+ hal_alaia_flash_priv.block_info,
+ &amp;hal_alaia_flash_priv
+);
+#endif
+ </programlisting>
+ <para>
+The bulk of the file is protected by an <literal>#ifdef</literal> 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 instantiating the data structures
+would serve no purpose. The rest of the file is split into three
+structure 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_dev.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
+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 seven function pointers for various
+operations: initialization, query, erase, program, read, locking and
+unlocking. The query operation is optional and the generic flash
+support provides a dummy implementation
+<function>cyg_flash_devfn_query_nop</function>. AM29xxxxx flash
+devices are always directly accessible so there is no need for a
+separate read function. 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_flash_devfn_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.
+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
+increases the code size.
+ </para>
+ <caution><para>
+If CFI is used then the <structname>cyg_am29xxxxx_dev</structname>
+structure must not be declared <literal>const</literal>. The CFI code
+will attempt to update the structure and will fail if the structure is
+held in read-only memory. This would leave the flash driver
+non-functional.
+ </para></caution>
+ <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 problem was fixed in the next revision. The
+platform-specific initialization function can figure out which model
+board it is running on and replace the default
+<literal>16as8</literal> functions with faster <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. As
+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, 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, so a timeout 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 all AM29xxxxx devices. If these operations are supported at
+all then usually they involve manipulating the voltages on certain
+pins. This would not be able to be handled by generic driver code since it requires
+knowing how these pins can be manipulated via the processor's GPIO
+lines. Therefore the AM29xxxxx driver does not usually provide lock and unlock
+functions, and instead the generic dummy functions
+<function>cyg_flash_devfn_lock_nop</function> and
+<function>cyg_flash_devfn_unlock_nop</function> should be used. An <link
+linkend="am29xxxxx-at49xxxx-locking">exception</link> exists for
+the AT49xxxx family of devices which are sufficiently AMD
+compatible in other respects. Otherwise, if a
+platform does provide 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>
+ <para>
+If real locking functions are implemented then the platform HAL's CDL
+script should implement the CDL interface
+<varname>CYGHWR_IO_FLASH_BLOCK_LOCKING</varname>. Otherwise the
+generic flash package may believe that none of the flash drivers in the
+system provide locking functionality and disable the interface functions.
+ </para>
+ <refsect3 id="am29xxxxx-at49xxxx-locking">
+ <title>AT49xxxx locking</title>
+ <para>
+As locking is standardised across the AT49xxxx family of AMD AM29xxxxx
+compatible Flash parts, a method supporting this is included within this
+driver. <function>cyg_at49xxxx_softlock_XX</function> provides a means of
+locking a Flash sector such that it may be subsequently unlocked.
+<function>cyg_at49xxxx_hardlock_XX</function> locks a sector such that
+it cannot be unlocked until after reset or a power cycle.
+<function>cyg_at49xxxx_unlock_XX</function> unlocks a sector that has
+previously been softlocked. At power on or Flash device reset, all sectors
+default to being softlocked.
+ </para>
+ </refsect3>
+ </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_flash_devfn_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 is 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 generic 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_dev</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>
+ <para>
+If more than one <structname>cyg_flash_dev</structname> structure is
+instantiated then the platform HAL's CDL script should implement the
+CDL interface <varname>CYGHWR_IO_FLASH_DEVICE</varname> once for every
+device past the first. Otherwise the generic code may default to the
+case of a single flash device and optimize for that.
+ </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>
+ </refsect1>
+
+ <refsect1 id="am29xxxxx-instance-cache"><title>Cache Management</title>
+ <para>
+By default the AM29xxxxx driver assumes that the flash can be accessed
+uncached, and it will use the HAL
+<function>CYGARC_UNCACHED_ADDRESS</function> macro to map the cached
+address in the <structfield>start</structfield> field of the
+<structname>cyg_flash_dev</structname> structure into an uncached
+address. If for any reason this HAL macro is inappropriate for the
+flash then an alternative macro
+<function>HAL_AM29XXXXX_UNCACHED_ADDRESS</function> can be defined
+instead. However fixing the
+<function>CYGARC_UNCACHED_ADDRESS</function> macro is normally the
+better solution.
+ </para>
+ <para>
+If there is no way of bypassing the cache then the platform HAL should
+implement the CDL interface
+<varname>CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY</varname>. The flash
+driver will now disable and re-enable the cache as required. For
+example a program operation will involve the following:
+ </para>
+ <programlisting width=72>
+ AM29_INTSCACHE_STATE;
+ AM29_INTSCACHE_BEGIN();
+ while ( ! finished ) {
+ program data
+ }
+ AM29_INTSCACHE_END();
+ </programlisting>
+ <para>
+The default implementations of these INTSCACHE macros are as follows:
+<varname>STATE</varname> defines any local variables that may be
+needed, e.g. to save the current interrupt state;
+<function>BEGIN</function> disables interrupts, synchronizes the data
+caches, disables it, and invalidates the current contents;
+<function>END</function> re-enables the cache and then
+interrupts. The cache is only disabled when interrupts are disabled,
+so there is no possibility of an interrupt handler running or a
+context switch occurring while the cache is disabled, potentially
+leaving the system running very slowly. The data cache synchronization
+ensures that there are no dirty cache lines, so when the cache is
+disabled the low-level flash write code will not see stale data in
+memory. The invalidate ensures that at the end of the operation
+higher-level code will not pick up stale cache contents instead of the
+newly written flash data.
+ </para>
+ <para>
+Some implementations of the HAL cache macros may not provide the exact
+semantics required by the flash driver. For example
+<function>HAL_DCACHE_DISABLE</function> may have an unwanted side
+effect, or it may do more work than is needed here. The driver will
+check for alternative macros
+<function>HAL_AM29XXXXX_INTSCACHE_STATE</function>,
+<function>HAL_AM29XXXXX_INTSCACHE_BEGIN</function> and
+<function>HAL_AM29XXXXX_INTSCACHE_END</function>, using these instead of
+the defaults.
+ </para>
+ </refsect1>
+ </refentry>
+</part>
diff --git a/ecos/packages/devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h
new file mode 100644
index 0000000..695b0da
--- /dev/null
+++ b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/include/am29xxxxx_dev.h
@@ -0,0 +1,138 @@
+#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, 2005 Free Software Foundation, Inc.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2.
+//
+// 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_dev.h>
+
+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*, cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_16( struct cyg_flash_dev*, cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_32( struct cyg_flash_dev*, cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_88( struct cyg_flash_dev*, cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_8888( struct cyg_flash_dev*, cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_1616( struct cyg_flash_dev*, cyg_flashaddr_t);
+externC int cyg_am29xxxxx_erase_16as8( struct cyg_flash_dev*, cyg_flashaddr_t);
+
+externC int cyg_am29xxxxx_program_8( struct cyg_flash_dev*, cyg_flashaddr_t, const void*, size_t);
+externC int cyg_am29xxxxx_program_16( struct cyg_flash_dev*, cyg_flashaddr_t, const void*, size_t);
+externC int cyg_am29xxxxx_program_32( struct cyg_flash_dev*, cyg_flashaddr_t, const void*, size_t);
+externC int cyg_am29xxxxx_program_88( struct cyg_flash_dev*, cyg_flashaddr_t, const void*, size_t);
+externC int cyg_am29xxxxx_program_8888( struct cyg_flash_dev*, cyg_flashaddr_t, const void*, size_t);
+externC int cyg_am29xxxxx_program_1616( struct cyg_flash_dev*, cyg_flashaddr_t, const void*, size_t);
+externC int cyg_am29xxxxx_program_16as8( struct cyg_flash_dev*, cyg_flashaddr_t, const void*, size_t);
+
+externC int cyg_at49xxxx_softlock_8( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_softlock_16( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_softlock_32( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_softlock_88( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_softlock_8888( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_softlock_1616( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_softlock_16as8( struct cyg_flash_dev*, const cyg_flashaddr_t );
+
+externC int cyg_at49xxxx_hardlock_8( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_hardlock_16( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_hardlock_32( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_hardlock_88( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_hardlock_8888( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_hardlock_1616( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_hardlock_16as8( struct cyg_flash_dev*, const cyg_flashaddr_t );
+
+externC int cyg_at49xxxx_unlock_8( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_unlock_16( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_unlock_32( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_unlock_88( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_unlock_8888( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_unlock_1616( struct cyg_flash_dev*, const cyg_flashaddr_t );
+externC int cyg_at49xxxx_unlock_16as8( struct cyg_flash_dev*, const cyg_flashaddr_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_flash_block_info_t block_info[CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_REGIONS];
+} cyg_am29xxxxx_dev;
+
+// TODO: An AM29 specific macro could optimise the common case of CYG_FLASH_FUNS.
+// Bart and Jifl discussed this in mid July/start Aug 2005.
+
+#endif // CYGONCE_DEVS_FLASH_AM29xxxxx_dev_V2_H
diff --git a/ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c
new file mode 100644
index 0000000..f6ebcd9
--- /dev/null
+++ b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx.c
@@ -0,0 +1,514 @@
+//==========================================================================
+//
+// am29xxxxx.c
+//
+// Flash driver for the AMD family
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2.
+//
+// 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_dev.h>
+#include <cyg/io/am29xxxxx_dev.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.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 (*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.
+//
+// Erase, program, and the locking functions need real
+// implementations, although locking is not always available.
+
+// ----------------------------------------------------------------------------
+// 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. The AM29_SWAP() macro deals with endianness issues
+// on some targets and can also help with h/w where things are just not
+// wired right.
+#define AM29_COMMAND_SETUP1 AM29_SWAP(AM29_PARALLEL(0x00AA))
+#define AM29_COMMAND_SETUP2 AM29_SWAP(AM29_PARALLEL(0x0055))
+#define AM29_COMMAND_RESET AM29_SWAP(AM29_PARALLEL(0x00F0))
+#define AM29_COMMAND_AUTOSELECT AM29_SWAP(AM29_PARALLEL(0x0090))
+#define AM29_COMMAND_ERASE AM29_SWAP(AM29_PARALLEL(0x0080))
+#define AM29_COMMAND_ERASE_SECTOR AM29_SWAP(AM29_PARALLEL(0x0030))
+#define AM29_COMMAND_ERASE_RESUME AM29_SWAP(AM29_PARALLEL(0x0030))
+#define AM29_COMMAND_CFI AM29_SWAP(AM29_PARALLEL(0x0098))
+#define AM29_COMMAND_PROGRAM AM29_SWAP(AM29_PARALLEL(0x00A0))
+// Following are specific to AT49 derivatives
+#define AM29_COMMAND_AT49_SOFTLOCK_BLOCK_0 AM29_SWAP(AM29_PARALLEL(0x0080))
+#define AM29_COMMAND_AT49_SOFTLOCK_BLOCK_1 AM29_SWAP(AM29_PARALLEL(0x0040))
+#define AM29_COMMAND_AT49_HARDLOCK_BLOCK_0 AM29_SWAP(AM29_PARALLEL(0x0080))
+#define AM29_COMMAND_AT49_HARDLOCK_BLOCK_1 AM29_SWAP(AM29_PARALLEL(0x0060))
+#define AM29_COMMAND_AT49_UNLOCK_BLOCK AM29_SWAP(AM29_PARALLEL(0x0070))
+
+// 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_SWAP(AM29_PARALLEL(0x0080))
+#define AM29_STATUS_DQ6 AM29_SWAP(AM29_PARALLEL(0x0040))
+#define AM29_STATUS_DQ5 AM29_SWAP(AM29_PARALLEL(0x0020))
+#define AM29_STATUS_DQ4 AM29_SWAP(AM29_PARALLEL(0x0010))
+#define AM29_STATUS_DQ3 AM29_SWAP(AM29_PARALLEL(0x0008))
+#define AM29_STATUS_DQ2 AM29_SWAP(AM29_PARALLEL(0x0004))
+#define AM29_STATUS_DQ1 AM29_SWAP(AM29_PARALLEL(0x0002))
+#define AM29_STATUS_DQ0 AM29_SWAP(AM29_PARALLEL(0x0001))
+#define AM29_ID_LOCKED AM29_SWAP(AM29_PARALLEL(0x03))
+
+// 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_uint32 _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_uint32 _result_; \
+ _result_ = (_ptr_[0] << 24) | (_ptr_[1] << 16) | (_ptr_[2] << 8) | _ptr_[3]; \
+ _ptr_ += 4; \
+ _result_; })
+
+#endif
+
+// The addresses used for programming the flash may be different from
+// the ones used to read the flash. The macro
+// HAL_AM29XXXXX_UNCACHED_ADDRESS() can be supplied by one of the HAL
+// packages. Otherwise if CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY
+// is not implemented then the macro CYGARC_UNCACHED_ADDRESS()
+// will be used. If there is no way of bypassing the cache then
+// the addresses will remain unchanged and instead the INTSCACHE
+// macros will disable the cache.
+
+#if defined(HAL_AM29XXXXX_UNCACHED_ADDRESS)
+# define AM29_UNCACHED_ADDRESS(_addr_) ((volatile AM29_TYPE*)HAL_AM29XXXXX_UNCACHED_ADDRESS(_addr_))
+#elif !defined(CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY)
+# ifndef CYGARC_UNCACHED_ADDRESS
+# error Cache should be bypassed but CYGARC_UNCACHED_ADDRESS is not defined.
+# endif
+# define AM29_UNCACHED_ADDRESS(_addr_) ((volatile AM29_TYPE*)CYGARC_UNCACHED_ADDRESS(_addr_))
+#elif defined(HAL_AM29XXXXX_P2V)
+// HAL_AM29XXXXX_P2V is a deprecated macro that is only retained for
+// backward compatibility.
+# define AM29_UNCACHED_ADDRESS(_addr_) ((volatile AM29_TYPE*)HAL_AM29XXXXX_P2V(_addr_))
+#else
+# define AM29_UNCACHED_ADDRESS(_addr_) ((volatile AM29_TYPE*)(_addr_))
+#endif
+
+// The bits on the data bus may need swapping, either because of
+// endianness issues or because some lines are just wired wrong.
+// SWAP is for commands going to the flash chip. UNSWAP is for
+// data coming back from the flash chip. The swapping takes
+// effect after allowing for AM29_PARALLEL(). Data is never
+// swapped, it does not matter if bit 5 of a datum is actually
+// stored in bit 3 of the flash as long as the data reads back
+// right.
+#if defined(HAL_AM29XXXXX_SWAP)
+# define AM29_SWAP(_data_) HAL_AM29XXXXX_SWAP(_data_)
+#else
+# define AM29_SWAP(_data_) (_data_)
+#endif
+#if defined(HAL_AM29XXXXX_UNSWAP)
+# define AM29_UNSWAP(_data_) HAL_AM29XXXXX_UNSWAP(_data_)
+#else
+# define AM29_UNSWAP(_data_) (_data_)
+#endif
+
+// On some platforms there may be almost inexplicable failures, caused
+// by very subtle effects such as instruction cache lines still being
+// filled from flash memory which the _hw routines in .2ram sections are
+// already running and have taken the flash out of read-array mode.
+// These are very rare effects and not amenable to a generic solution,
+// so instead the platform HAL (usually) can define additional hook
+// macros that get invoked by the .2ram functions. These can e.g.
+// add a short delay or invalidate a couple of instruction cache lines,
+// but only if the code is executing from flash. Any such hooks will
+// affect interrupt latency so should only be used when absolutely
+// necessary. They must also be simple code, e.g. no calls to other
+// functions that may be in flash.
+
+#ifdef HAL_AM29XXXXX_2RAM_ENTRY_HOOK
+# define AM29_2RAM_ENTRY_HOOK() HAL_AM29XXXXX_2RAM_ENTRY_HOOK()
+#else
+# define AM29_2RAM_ENTRY_HOOK() CYG_EMPTY_STATEMENT
+#endif
+#ifdef HAL_AM29XXXXX_2RAM_EXIT_HOOK
+# define AM29_2RAM_EXIT_HOOK() HAL_AM29XXXXX_2RAM_EXIT_HOOK()
+#else
+# define AM29_2RAM_EXIT_HOOK() CYG_EMPTY_STATEMENT
+#endif
+
+// Cache and interrupt manipulation. This driver supports fine-grained
+// control over interrupts and the cache, using three macros. These may
+// be provided by the platform HAL, or by defaults here. There are
+// three variants:
+//
+// 1) control both interrupts and cache. This is necessary if
+// CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY is implemented,
+// i.e. if the cache cannot be bypassed. The cache must be temporarily
+// disabled for flash operations, and interrupts have to be disabled
+// while the cache is disabled to prevent interrupts and context switches.
+// 2) control interrupts only, the default if the cache can be bypassed
+// when accessing the flash. The flash is still in an unusable
+// state during flash operations so interrupts and context switches
+// should be avoided.
+// 3) only invalidate at the end, if the cache can be bypassed and the
+// application guarantees that the flash will not be accessed by any interrupt
+// handlers or other threads.
+
+#if defined(CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CACHED_ONLY)
+
+// First, the amount of state that should be preserved. By default
+// this means the interrupt state and the data cache state.
+# define AM29_INTSCACHE_DEFAULT_STATE int _saved_ints_, _saved_dcache_
+
+// Start an operation on the flash. Make sure that interrupts are
+// disabled and then save the current state of the data cache. The
+// actual flash manipulation should happen with the cache disabled.
+// There may still be data in the cache that has not yet been flushed
+// to memory, so take care of that first. The invalidate the cache
+// lines so that when the cache is re-enabled later on the processor
+// gets everything from memory, rather than reusing old data in the
+// cache.
+# define AM29_INTSCACHE_DEFAULT_BEGIN() \
+ CYG_MACRO_START \
+ HAL_DISABLE_INTERRUPTS(_saved_ints_); \
+ HAL_DCACHE_IS_ENABLED(_saved_dcache_); \
+ HAL_DCACHE_SYNC(); \
+ if (_saved_dcache_) { \
+ HAL_DCACHE_DISABLE(); \
+ } \
+ HAL_DCACHE_INVALIDATE_ALL(); \
+ CYG_MACRO_END
+
+// A flash operation has completed. Restore the situation to what it
+// was before. Because of suspend/resume support interrupt handlers
+// and other threads may have run, filling various cache lines with
+// useful data. However it is assumed that none of those cache
+// lines contain any of the data that has been manipulated by this
+// flash operation (the stack and the flash block), so there is
+// no need for another sync or invalidate. It is also assumed that
+// we have not been executing any code out of the block of flash
+// that has just been erased or programmed, so no need to worry
+// about the icache.
+#define AM29_INTSCACHE_DEFAULT_END() \
+ CYG_MACRO_START \
+ if (_saved_dcache_) { \
+ HAL_DCACHE_ENABLE(); \
+ } \
+ HAL_RESTORE_INTERRUPTS(_saved_ints_); \
+ CYG_MACRO_END
+
+#elif !defined(CYGIMP_DEVS_FLASH_AMD_AM29XXXXX_V2_LEAVE_INTERRUPTS_ENABLED)
+
+# define AM29_INTSCACHE_DEFAULT_STATE int _saved_ints_
+# define AM29_INTSCACHE_DEFAULT_BEGIN() HAL_DISABLE_INTERRUPTS(_saved_ints_)
+
+# if defined(HAL_DCACHE_SYNC) && defined(HAL_DCACHE_INVALIDATE_ALL)
+// The following blips the interrupt enable to allow pending interrupts
+// to run, which will reduce interrupt latency given the dcache sync/invalidate
+// may be relatively lengthy.
+# define AM29_INTSCACHE_DEFAULT_END() \
+ CYG_MACRO_START \
+ HAL_RESTORE_INTERRUPTS(_saved_ints_); \
+ HAL_DISABLE_INTERRUPTS(_saved_ints_); \
+ HAL_DCACHE_SYNC(); \
+ HAL_DCACHE_INVALIDATE_ALL(); \
+ HAL_RESTORE_INTERRUPTS(_saved_ints_); \
+ CYG_MACRO_END
+# else
+# define AM29_INTSCACHE_DEFAULT_END() HAL_RESTORE_INTERRUPTS(_saved_ints_)
+# endif
+#else
+
+# define AM29_INTSCACHE_DEFAULT_STATE CYG_EMPTY_STATEMENT
+# define AM29_INTSCACHE_DEFAULT_BEGIN() CYG_EMPTY_STATEMENT
+# if defined(HAL_DCACHE_SYNC) && defined(HAL_DCACHE_INVALIDATE_ALL)
+# define AM29_INTSCACHE_DEFAULT_END() \
+ CYG_MACRO_START \
+ int _saved_ints_; \
+ HAL_DISABLE_INTERRUPTS(_saved_ints_); \
+ HAL_DCACHE_SYNC(); \
+ HAL_DCACHE_INVALIDATE_ALL(); \
+ HAL_RESTORE_INTERRUPTS(_saved_ints_); \
+ CYG_MACRO_END
+# else
+# define AM29_INTSCACHE_DEFAULT_END() CYG_EMPTY_STATEMENT
+# endif
+#endif
+
+#ifdef HAL_AM29XXXXX_INTSCACHE_STATE
+# define AM29_INTSCACHE_STATE HAL_AM29XXXXX_INTSCACHE_STATE
+#else
+# define AM29_INTSCACHE_STATE AM29_INTSCACHE_DEFAULT_STATE
+#endif
+#ifdef HAL_AM29XXXXX_INTSCACHE_BEGIN
+# define AM29_INTSCACHE_BEGIN HAL_AM29XXXXX_INTSCACHE_BEGIN
+#else
+# define AM29_INTSCACHE_BEGIN AM29_INTSCACHE_DEFAULT_BEGIN
+#endif
+#ifdef HAL_AM29XXXXX_INTSCACHE_END
+# define AM29_INTSCACHE_END HAL_AM29XXXXX_INTSCACHE_END
+#else
+# define AM29_INTSCACHE_END AM29_INTSCACHE_DEFAULT_END
+#endif
+
+// Some HALs require a special instruction to flush write buffers.
+// Not all HALs do though, so we define it empty if it isn't already present.
+#ifndef HAL_MEMORY_BARRIER
+# define HAL_MEMORY_BARRIER() CYG_EMPTY_STATEMENT
+#endif
+
+// ----------------------------------------------------------------------------
+// Generic code.
+
+// 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_MANUFACTURER_ID 0x0000
+#define AM29_OFFSET_DEVID 0x0002
+#define AM29_OFFSET_DEVID2 0x001C
+#define AM29_OFFSET_DEVID3 0x001E
+#define AM29_OFFSET_AT49_LOCK_STATUS 04
+#define AM29_OFFSET_CFI 0x00AA
+#define AM29_OFFSET_CFI_DATA(_idx_) (2 * (_idx_))
+
+#include "am29xxxxx_aux.c"
diff --git a/ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c
new file mode 100644
index 0000000..c5f392c
--- /dev/null
+++ b/ecos/packages/devs/flash/amd/am29xxxxxv2/current/src/am29xxxxx_aux.c
@@ -0,0 +1,985 @@
+//==========================================================================
+//
+// 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, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2.
+//
+// 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_MANUFACTURER_ID
+# define AM29_OFFSET_MANUFACTURER_ID 0x0000
+#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
+#ifndef AM29_OFFSET_AT49_LOCK_STATUS
+# define AM29_OFFSET_AT49_LOCK_STATUS 0x02
+#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
+
+// ----------------------------------------------------------------------------
+// Diagnostic routines.
+
+#if 0
+#define amd_diag( __fmt, ... ) diag_printf("AMD: %s[%d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ );
+#define amd_dump_buf( __addr, __size ) diag_dump_buf( __addr, __size )
+#else
+#define amd_diag( __fmt, ... )
+#define amd_dump_buf( __addr, __size )
+#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 int AM29_RAMFNDECL(am29_hw_erase, (volatile AM29_TYPE*));
+static int AM29_RAMFNDECL(am29_hw_program, (volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32 count, int retries));
+static int AM29_RAMFNDECL(at49_hw_softlock, (volatile AM29_TYPE*));
+static int AM29_RAMFNDECL(at49_hw_hardlock, (volatile AM29_TYPE*));
+static int AM29_RAMFNDECL(at49_hw_unlock, (volatile AM29_TYPE*));
+
+
+// ----------------------------------------------------------------------------
+
+#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
+// With this flash component (e.g. AT49xxxxx), the reset does not
+// cause a suspended erase/program to be aborted. Instead all we
+// can do is resume any suspended operations. We do this on each
+// block as some parts have different granularity.
+
+static void
+AM29_FNNAME(am29_hw_force_all_suspended_resume)(struct cyg_flash_dev* dev, cyg_am29xxxxx_dev* am29_dev, volatile AM29_TYPE* addr)
+{
+ cyg_ucount16 i,j;
+ AM29_TYPE datum1, datum2;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ for (i=0; i<dev->num_block_infos; i++)
+ {
+ for (j=0; j<am29_dev->block_info[i].blocks; j++)
+ {
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_ERASE_RESUME;
+ HAL_MEMORY_BARRIER();
+ // We don't know if the suspended operation was an erase or
+ // program, so just compare the whole word to spot _any_ toggling.
+ do {
+ datum1 = addr[AM29_OFFSET_COMMAND];
+ datum2 = addr[AM29_OFFSET_COMMAND];
+ } while (datum1 != datum2);
+
+ addr += am29_dev->block_info[i].block_size/sizeof(AM29_TYPE);
+ }
+ }
+
+ AM29_2RAM_EXIT_HOOK();
+}
+#endif // ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
+
+// 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;
+ cyg_uint32 onedevmask;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ // Fortunately the compiler should optimise the below
+ // tests such that onedevmask is a constant.
+ if ( 1 == (sizeof(AM29_TYPE) / AM29_DEVCOUNT) )
+ onedevmask = 0xFF;
+ else if ( 2 == (sizeof(AM29_TYPE) / AM29_DEVCOUNT) )
+ onedevmask = 0xFFFF;
+ else {
+ CYG_ASSERT( 4 == (sizeof(AM29_TYPE) / AM29_DEVCOUNT),
+ "Unexpected flash width per device" );
+ onedevmask = 0xFFFFFFFF;
+ }
+
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_AUTOSELECT;
+ HAL_MEMORY_BARRIER();
+
+ devid = AM29_UNSWAP(addr[AM29_OFFSET_DEVID]) & onedevmask;
+
+// amd_diag("devid %x\n", devid );
+// amd_dump_buf(addr, 64 );
+
+ // 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.
+ // FIXME by jifl: What happens when a single device is connected 16-bits
+ // (or 32-bits) wide per device? Is the code still 0x7E, and all the
+ // other devids are 8-bits only?
+ if (0x007E == devid) {
+ devid <<= 16;
+ devid |= ((AM29_UNSWAP(addr[AM29_OFFSET_DEVID2]) & 0x00FF) << 8);
+ devid |= (AM29_UNSWAP(addr[AM29_OFFSET_DEVID3]) & 0x00FF);
+ }
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+
+// amd_diag("devid %x\n", devid );
+
+ AM29_2RAM_EXIT_HOOK();
+ 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;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CFI_BOGOSITY
+ int manufacturer_id;
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_AUTOSELECT;
+ HAL_MEMORY_BARRIER();
+
+ manufacturer_id = AM29_UNSWAP(addr[AM29_OFFSET_MANUFACTURER_ID]) & 0x00FF;
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+#endif
+
+ // Just a single write is needed to put the device into CFI mode
+ addr[AM29_OFFSET_CFI] = AM29_COMMAND_CFI;
+ HAL_MEMORY_BARRIER();
+// amd_diag("CFI data:\n");
+// amd_dump_buf( addr, 256 );
+ // 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' != (AM29_UNSWAP(addr[AM29_OFFSET_CFI_Q]) & 0x00FF)) {
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+ AM29_2RAM_EXIT_HOOK();
+ 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 << (AM29_UNSWAP(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 = AM29_UNSWAP(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;
+ HAL_MEMORY_BARRIER();
+ AM29_2RAM_EXIT_HOOK();
+ 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 = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_COUNT_LSB(i)]) & 0x00FF;
+ cyg_uint32 count_msb = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_COUNT_MSB(i)]) & 0x00FF;
+ cyg_uint32 size_lsb = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_SIZE_LSB(i)]) & 0x00FF;
+ cyg_uint32 size_msb = AM29_UNSWAP(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;
+ }
+
+#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CFI_BOGOSITY
+
+ // Some flash parts have a peculiar implementation of CFI. The
+ // device erase regions may not be in the order specified in the
+ // main CFI area. Instead the erase regions are given in a
+ // manufacturer dependent fixed order, regardless of whether this
+ // is a top or bottom boot block device. A vendor-specific
+ // extended query block has an entry saying whether the boot
+ // blocks are at the top or bottom. This code works out whether
+ // the erase regions appear to be specified in the wrong order,
+ // and then swaps them over.
+
+ {
+ enum { bottom, symmetric, top } boot_type = symmetric;
+ cyg_uint32 vspec = AM29_SWAP(addr[AM29_OFFSET_CFI_DATA(0x15)]) & 0x00FF;
+
+ // Take a look at the vendor specific area for the boot block
+ // order.
+
+ switch( manufacturer_id )
+ {
+ // Atmel appear to have their own layout for the vendor
+ // specific area. Offset 0x06 of the vendor specific area
+ // contains a single bit: 0x00 = top boot, 0x01 = bottom
+ // boot. There appears to be no way of specifying
+ // symmetric formats.
+ case 0x1F:
+ if( (addr[AM29_OFFSET_CFI_DATA(vspec+0x06)] & AM29_SWAP(0x1)) == AM29_SWAP(0x1) )
+ boot_type = bottom;
+ else boot_type = top;
+ break;
+
+ // Most other manufacturers seem to follow the same layout
+ // and encoding. Offset 0xF of the vendor specific area
+ // contains the boot sector layout: 0x00 = uniform, 0x01 =
+ // 8x8k top and bottom, 0x02 = bottom boot, 0x03 = top
+ // boot, 0x04 = both top and bottom.
+ //
+ // The following manufacturers support this layout:
+ // AMD, Spansion, ST, Macronix.
+ default:
+ if( (addr[AM29_OFFSET_CFI_DATA(vspec+0xF)] == AM29_SWAP(0x2)) )
+ boot_type = bottom;
+ else if( (addr[AM29_OFFSET_CFI_DATA(vspec+0xF)] == AM29_SWAP(0x3)) )
+ boot_type = top;
+ // All other options are symmetric
+ break;
+ }
+
+ // If the device is marked as top boot, but the erase region
+ // list appears to be in bottom boot order, then reverse the
+ // list. Also swap, if it is marked as bottom boot but the
+ // erase regions appear to be in top boot order. This code
+ // assumes that the first boot block is always smaller than
+ // regular blocks; it is possible to imagine flash layouts for
+ // which that is not true.
+
+ if( ((boot_type == top) &&
+ (am29_dev->block_info[0].block_size < am29_dev->block_info[erase_regions-1].block_size)) ||
+ ((boot_type == bottom) &&
+ (am29_dev->block_info[0].block_size > am29_dev->block_info[erase_regions-1].block_size)))
+ {
+ int lo, hi;
+
+ for( lo = 0, hi = erase_regions-1 ; lo < hi ; lo++, hi-- )
+ {
+ size_t size = am29_dev->block_info[lo].block_size;
+ cyg_uint32 count = am29_dev->block_info[lo].blocks;
+ am29_dev->block_info[lo].block_size = am29_dev->block_info[hi].block_size;
+ am29_dev->block_info[lo].blocks = am29_dev->block_info[hi].blocks;
+ am29_dev->block_info[hi].block_size = size;
+ am29_dev->block_info[hi].blocks = count;
+ }
+ }
+ }
+#endif
+
+ // Get out of CFI mode
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+
+ AM29_2RAM_EXIT_HOOK();
+ 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 int
+AM29_FNNAME(am29_hw_erase)(volatile AM29_TYPE* addr)
+{
+ int retries;
+ AM29_TYPE datum;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ // Start the erase operation
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_ERASE;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_ERASE_SECTOR;
+ HAL_MEMORY_BARRIER();
+ // 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.
+ for (retries = CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_TIMEOUT;
+ retries > 0;
+ retries--) {
+
+ datum = addr[AM29_OFFSET_COMMAND];
+ // The operation completes when all DQ7 bits are set.
+ if ((datum & AM29_STATUS_DQ7) == AM29_STATUS_DQ7) {
+ break;
+ }
+ // Otherwise, for any flash chips where DQ7 is still clear, it is
+ // necessary to test DQ5.
+ if (((datum ^ AM29_STATUS_DQ7) >> 2) & datum & AM29_STATUS_DQ5) {
+ // DQ5 is set, indicating a hardware error. The calling code
+ // will always verify that the erase really was successful
+ // so we do not need to distinguish between error conditions.
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+ break;
+ }
+ }
+
+ // A result of 0 indicates a timeout.
+ // A non-zero result indicates
+ // that the erase completed or there has been a fatal error.
+ AM29_2RAM_EXIT_HOOK();
+ return retries;
+}
+
+// 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 int
+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;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ for (i = 0; (i < count) && (retries > 0); i++) {
+ AM29_TYPE datum, current, active_dq7s;
+
+ // 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;
+ HAL_MEMORY_BARRIER();
+ block_start[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ block_start[AM29_OFFSET_COMMAND] = AM29_COMMAND_PROGRAM;
+ HAL_MEMORY_BARRIER();
+ addr[i] = datum;
+ HAL_MEMORY_BARRIER();
+
+ // The data is now being written. The official algorithm is
+ // to poll either DQ7 or DQ6, checking DQ5 along the way for
+ // error conditions. This gets complicated with parallel
+ // flash chips because they may finish at different times.
+ // The alternative approach is to ignore the status bits
+ // completely and just look for current==datum until the
+ // retry count is exceeded. However that does not cope
+ // cleanly with cases where the flash chip reports an error
+ // early on, e.g. because a flash block is locked.
+
+ while (--retries > 0) {
+#if CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_DELAY > 0
+ // Some chips want a delay between polling
+ { int j; for( j = 0; j < CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_DELAY; j++ ); }
+#endif
+ // While the program operation is in progress DQ7 will read
+ // back inverted from datum.
+ current = addr[i];
+ if ((current & AM29_STATUS_DQ7) == (datum & AM29_STATUS_DQ7)) {
+ // All DQ7 bits now match datum, so the operation has completed.
+ // But not necessarily successfully. On some chips DQ7 may
+ // toggle before DQ0-6 are valid, so we need to read the
+ // data one more time.
+ current = addr[i];
+ if (current != datum) {
+ retries = 0; // Abort this burst.
+ }
+ break;
+ }
+
+ // Now we want to check the DQ5 status bits, but only for those
+ // chips which are still programming. ((current^datum) & DQ7) gives
+ // ones for chips which are still programming, zeroes for chips when
+ // the programming is complete.
+ active_dq7s = (current ^ datum) & AM29_STATUS_DQ7;
+
+ if (0 != (current & (active_dq7s >> 2))) {
+ // Unfortunately this is not sufficient to prove an error. On
+ // some chips DQ0-6 switch to the data while DQ7 is still a
+ // status flag, so the set DQ5 bit detected above may be data
+ // instead of an error. Check again, this time DQ7 may
+ // indicate completion.
+ //
+ // Next problem. Suppose chip A gave a bogus DQ5 result earlier
+ // because it was just finishing. For this read chip A gives
+ // back datum, but now chip B is finishing and has reported a
+ // bogus DQ5.
+ //
+ // Solution: if any of the DQ7 lines have changed since the last
+ // time, go around the loop again. When an error occurs DQ5
+ // remains set and DQ7 remains toggled, so there is no harm
+ // in one more polling loop.
+
+ current = addr[i];
+ if (((current ^ datum) & AM29_STATUS_DQ7) != active_dq7s) {
+ continue;
+ }
+
+ // DQ5 has been set in a chip where DQ7 indicates an ongoing
+ // program operation for two successive reads. That is an error.
+ // The hardware is in a strange state so must be reset.
+ block_start[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+ retries = 0;
+ break;
+ }
+ // No DQ5 bits set in chips which are still programming. Poll again.
+ } // Retry for current word
+ } // Next word
+
+ // At this point retries holds the total number of retries left.
+ // 0 indicates a timeout or fatal error.
+ // >0 indicates success.
+ AM29_2RAM_EXIT_HOOK();
+ return retries;
+}
+
+// FIXME: implement a separate program routine for buffered writes.
+
+#if 0
+// Unused for now, but might be useful later
+static int
+AM29_FNNAME(at49_hw_is_locked)(volatile AM29_TYPE* addr)
+{
+ int result;
+ AM29_TYPE plane;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ // Plane is bits A21-A20 for AT49BV6416
+ // A more generic formula is needed.
+ plane = AM29_PARALLEL( ((((CYG_ADDRESS)addr)>>21) & 0x3) );
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND + plane] = AM29_COMMAND_AUTOSELECT;
+ HAL_MEMORY_BARRIER();
+ result = addr[AM29_OFFSET_AT49_LOCK_STATUS];
+ addr[0] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+ // The bottom two bits hold the lock status, LSB indicates
+ // soft lock, next bit indicates hard lock. We don't distinguish
+ // in this function.
+ AM29_2RAM_EXIT_HOOK();
+ return (0 != (result & AM29_ID_LOCKED));
+}
+#endif
+
+static int
+AM29_FNNAME(at49_hw_softlock)(volatile AM29_TYPE* addr)
+{
+ int result = CYG_FLASH_ERR_OK;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_AT49_SOFTLOCK_BLOCK_0;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[0] = AM29_COMMAND_AT49_SOFTLOCK_BLOCK_1;
+ HAL_MEMORY_BARRIER();
+ // not sure if this is required:
+ addr[0] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+ AM29_2RAM_EXIT_HOOK();
+ return result;
+}
+
+static int
+AM29_FNNAME(at49_hw_hardlock)(volatile AM29_TYPE* addr)
+{
+ int result = CYG_FLASH_ERR_OK;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_AT49_HARDLOCK_BLOCK_0;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[AM29_OFFSET_COMMAND2] = AM29_COMMAND_SETUP2;
+ HAL_MEMORY_BARRIER();
+ addr[0] = AM29_COMMAND_AT49_HARDLOCK_BLOCK_1;
+ HAL_MEMORY_BARRIER();
+ // not sure if this is required:
+ addr[0] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+ AM29_2RAM_EXIT_HOOK();
+ return result;
+}
+
+static int
+AM29_FNNAME(at49_hw_unlock)(volatile AM29_TYPE* addr)
+{
+ int result = CYG_FLASH_ERR_OK;
+
+ AM29_2RAM_ENTRY_HOOK();
+
+ addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_SETUP1;
+ HAL_MEMORY_BARRIER();
+ addr[0] = AM29_COMMAND_AT49_UNLOCK_BLOCK;
+ HAL_MEMORY_BARRIER();
+ // not sure if this is required:
+ addr[0] = AM29_COMMAND_RESET;
+ HAL_MEMORY_BARRIER();
+ AM29_2RAM_EXIT_HOOK();
+ return result;
+}
+
+
+// ----------------------------------------------------------------------------
+// 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;
+ AM29_INTSCACHE_STATE;
+
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+
+ amd_diag("\n");
+
+ addr = AM29_UNCACHED_ADDRESS(dev->start);
+ query_fn = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_query) );
+ AM29_INTSCACHE_BEGIN();
+ devid = (*query_fn)(addr);
+ AM29_INTSCACHE_END();
+ 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;
+
+ amd_diag("\n");
+
+ 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;
+ }
+
+#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
+ {
+ volatile AM29_TYPE *addr = AM29_UNCACHED_ADDRESS(dev->start);
+ void (*resume_fn)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*);
+ resume_fn = (void (*)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*))
+ cyg_flash_anonymizer( &AM29_FNNAME(am29_hw_force_all_suspended_resume) );
+ AM29_INTSCACHE_STATE;
+
+ AM29_INTSCACHE_BEGIN();
+ (*resume_fn)(dev, am29_dev, addr);
+ AM29_INTSCACHE_END();
+ }
+#endif
+
+ // 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;
+ AM29_INTSCACHE_STATE;
+
+ amd_diag("\n");
+
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+ am29_dev = (cyg_am29xxxxx_dev*) dev->priv; // Remove const, only place where this is needed.
+ addr = AM29_UNCACHED_ADDRESS(dev->start);
+ cfi_fn = (int (*)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*))
+ cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_cfi));
+
+ AM29_INTSCACHE_BEGIN();
+ result = (*cfi_fn)(dev, am29_dev, addr);
+ AM29_INTSCACHE_END();
+
+ // 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++) {
+ amd_diag("region %d: 0x%08x * %d\n", i, (int)dev->block_info[i].block_size, dev->block_info[i].blocks );
+ size += (dev->block_info[i].block_size * dev->block_info[i].blocks);
+ }
+ dev->end = dev->start + size - 1;
+
+#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
+ {
+ void (*resume_fn)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*);
+ resume_fn = (void (*)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*))
+ cyg_flash_anonymizer( &AM29_FNNAME(am29_hw_force_all_suspended_resume) );
+
+ AM29_INTSCACHE_BEGIN();
+ (*resume_fn)(dev, am29_dev, addr);
+ AM29_INTSCACHE_END();
+ }
+#endif
+ }
+ 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, cyg_flashaddr_t addr)
+{
+ int (*erase_fn)(volatile AM29_TYPE*);
+ volatile AM29_TYPE* block;
+ cyg_flashaddr_t block_start;
+ size_t block_size;
+ int i;
+ int result;
+ AM29_INTSCACHE_STATE;
+
+ 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");
+
+ amd_diag("addr %p block %p[%d]\n", (void*)addr, (void*)block_start, (int)block_size );
+
+ block = AM29_UNCACHED_ADDRESS(addr);
+ erase_fn = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_erase) );
+
+ AM29_INTSCACHE_BEGIN();
+ result = (*erase_fn)(block);
+ AM29_INTSCACHE_END();
+
+ // 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, cyg_flashaddr_t dest, const void* src, size_t len)
+{
+ int (*program_fn)(volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32, int);
+ volatile AM29_TYPE* block;
+ volatile AM29_TYPE* addr;
+ cyg_flashaddr_t block_start;
+ size_t block_size;
+ const cyg_uint8* data;
+ int retries;
+ int i;
+
+ AM29_INTSCACHE_STATE;
+
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+
+ amd_diag("dest %p src %p len %d\n", (void*)dest, (void*)src, (int)len );
+
+ // 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;
+ }
+
+ addr = AM29_UNCACHED_ADDRESS(dest);
+ CYG_ASSERT((dest >= dev->start) && (dest <= dev->end), "flash address out of device range");
+
+ 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_UNCACHED_ADDRESS(block_start);
+ data = (const cyg_uint8*) src;
+ retries = CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_TIMEOUT;
+
+ program_fn = (int (*)(volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32, int))
+ cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_program) );
+
+ AM29_INTSCACHE_BEGIN();
+ (*program_fn)(block, addr, data, len / sizeof(AM29_TYPE), retries);
+ AM29_INTSCACHE_END();
+
+ // 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;
+ data = (const cyg_uint8*) src;
+ 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) {
+ amd_diag("data %p addr[i] %p datum %08x current %08x\n", data-sizeof(AM29_TYPE), &addr[i], datum, current );
+ return CYG_FLASH_ERR_PROGRAM;
+ }
+ }
+ return CYG_FLASH_ERR_OK;
+}
+
+int
+AM29_FNNAME(cyg_at49xxxx_softlock)(struct cyg_flash_dev* dev, const cyg_flashaddr_t dest)
+{
+ volatile AM29_TYPE* uncached;
+ int result;
+ int (*lock_fn)(volatile AM29_TYPE*);
+ AM29_INTSCACHE_STATE;
+
+ amd_diag("\n");
+
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+ CYG_ASSERT((dest >= (cyg_flashaddr_t)dev->start) &&
+ ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range");
+
+ uncached = AM29_UNCACHED_ADDRESS(dest);
+ lock_fn = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(at49_hw_softlock) );
+ AM29_INTSCACHE_BEGIN();
+ result = (*lock_fn)(uncached);
+ AM29_INTSCACHE_END();
+ return result;
+}
+
+int
+AM29_FNNAME(cyg_at49xxxx_hardlock)(struct cyg_flash_dev* dev, const cyg_flashaddr_t dest)
+{
+ volatile AM29_TYPE* uncached;
+ int result;
+ int (*lock_fn)(volatile AM29_TYPE*);
+ AM29_INTSCACHE_STATE;
+
+ amd_diag("\n");
+
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+ CYG_ASSERT((dest >= (cyg_flashaddr_t)dev->start) &&
+ ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range");
+
+ uncached = AM29_UNCACHED_ADDRESS(dest);
+ lock_fn = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(at49_hw_hardlock) );
+ AM29_INTSCACHE_BEGIN();
+ result = (*lock_fn)(uncached);
+ AM29_INTSCACHE_END();
+ return result;
+}
+
+int
+AM29_FNNAME(cyg_at49xxxx_unlock)(struct cyg_flash_dev* dev, const cyg_flashaddr_t dest)
+{
+ volatile AM29_TYPE* uncached;
+ int result;
+ int (*unlock_fn)(volatile AM29_TYPE*);
+ AM29_INTSCACHE_STATE;
+
+ amd_diag("\n");
+
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+ CYG_ASSERT((dest >= (cyg_flashaddr_t)dev->start) &&
+ ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range");
+
+ uncached = AM29_UNCACHED_ADDRESS(dest);
+ unlock_fn = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(at49_hw_unlock) );
+
+ AM29_INTSCACHE_BEGIN();
+ result = (*unlock_fn)(uncached);
+ AM29_INTSCACHE_END();
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+// 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_OFFSET_AT49_LOCK_STATUS
+#undef AM29_PARALLEL