Mercurial > nand-ecoscentric
changeset 3016:8a3124bc5a6e
Merge from anoncvs
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Fri, 07 May 2010 11:35:21 +0100 |
| parents | bbc23f085599 (diff) 9b59569aaea9 (current diff) |
| children | 8502a048ad17 |
| files | packages/redboot/current/ChangeLog |
| diffstat | 83 files changed, 21403 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/samsung_k9/current/ChangeLog @@ -0,0 +1,68 @@ +2009-11-13 Ross Younger <wry@eCosCentric.com> + + * Don't provide BBT data when the NAND layer doesn't call for it. + +2009-11-09 Ross Younger <wry@eCosCentric.com> + + * Add read_part_page function. + +2009-10-02 Ross Younger <wry@eCosCentric.com> + + * Update driver to expose v2 device functions. + +2009-09-02 Ross Younger <wry@eCosCentric.com> + + * nand_k9.sgml: Created (by breaking up docs in io/nand/) + +2009-07-02 Ross Younger <wry@eCosCentric.com> + + * k9fxx08x0x.inl: Don't unnecessarily reset the chip. Minor + optimisation to k9_write_page. + +2009-06-16 Ross Younger <wry@eCosCentric.com> + + * Refactor to have a chip-level priv struct with per-chip in-RAM BBT. + * include/k9fxx08x0x.h: Created. + * Properly allow platform to define where the locking should be. + * Replace use of diag_printf with NAND_ERROR. + * Retab for consistency with other eCos sources. + +2009-03-04 Ross Younger <wry@eCosCentric.com> + + * New package. Samsung K9F1G08U0A NAND flash chip. + +//=========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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#### +//=========================================================================== + +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/samsung_k9/current/cdl/k9fxx08x0a.cdl @@ -0,0 +1,68 @@ +# ==================================================================== +# +# samsung_k9.cdl +# +# Drivers for the Samsung K9 family of NAND chips +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 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): wry +# Date: 2009-03-02 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_NAND_SAMSUNG_K9 { + display "Samsung K9 NAND chip family support" + parent CYGPKG_IO_NAND + active_if CYGPKG_IO_NAND + # This does NOT implement CYGHWR_IO_NAND_DEVICE - it only provides + # functions for the platform HAL to draw on and itself implement + # CYGHWR_IO_NAND_DEVICE. + include_dir cyg/devs/nand + description " + This package provides support for the Samsung K9Fxx08X0A family + of NAND flash devices. It is intended to be easy to port to + further chips from the same family. + This package can only be used in conjunction with the platform HAL + for the target, in order to bring it in and properly + configure it to talk to the hardware present." + # This is a 2k page device. + requires ( CYGNUM_NAND_PAGEBUFFER >= 2048 ) + requires ( CYGSEM_IO_NAND_INTERFACE_VERSION >= 2 ) +} +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/samsung_k9/current/doc/makefile @@ -0,0 +1,8 @@ +TOPLEVEL := ../../../../.. +MAIN_SGML := nand_k9.sgml +MAIN_HTML := aaa-XXX-book.html +MAIN_PDF := +OTHER_SGML := +PICTURES := + +include $(TOPLEVEL)/pkgconf/rules.doc
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/samsung_k9/current/doc/nand_k9.sgml @@ -0,0 +1,164 @@ +<!-- DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook V3.1//EN" --> + +<!-- =============================================================== --> +<!-- --> +<!-- nand_k9.sgml --> +<!-- --> +<!-- NAND chip support for the Samsung K9 family --> +<!-- --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> +<!-- =============================================================== --> +<!-- Copyright (C) 2009 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): wry --> +<!-- Contact(s): wry --> +<!-- Date: 2009/09/01 --> +<!-- Version: 0.01 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<chapter id="nanddev-samsung-k9"> +<title>Samsung K9 family NAND chips</title> +<sect1 id="nanddev-samsung-k9-overview"> +<title>Overview</title> + +<para> +The <varname>CYGPKG_DEVS_NAND_SAMSUNG_K9</varname> driver package currently +provides support for the Samsung K9F1G08x0x series of NAND flash chips, and +is intended to be expanded to provide support for more of the K9 family. +</para> + +<para> +Most users will only need to add this package to their eCos configuration +and not need to interact with it further. This package provides only an +inline code fragment which is intended to be instantiated by the target +platform HAL and provided with appropriate board-specific low-level +functions allowing it to access the hardware. +</para> + +<note><para> This part is not quite ONFI-compliant, but this code could +probably be extended to a much wider set of chips - or indeed to the ONFI +specification - without too much trouble. Appropriate definitions will +be required for the chip identifier, decoding of the Read ID response, +and the chip's blockcount-bits and device-size fields.</para> +</note> + +<note><para> At the present time, this driver has the limitation that it only +supports 8-bit parts. This is an area of probable future expansion. +</para></note> +</sect1> + +<sect1 id="devs-nand-samsung-k9-instantiation"><title>Using this driver in a board port</title> +<para> +This driver's chip support is currently provided as two files:</para> + +<glosslist> +<glossentry><glossterm><filename>cyg/devs/nand/k9fxx08x0x.h</filename></glossterm> +<glossdef><para>Prototypes the low-level chip access functions required by the chip driver and +declares a private struct for use by the driver.</para></glossdef></glossentry> +<glossentry><glossterm><filename>cyg/devs/nand/k9fxx08x0x.inl</filename></glossterm> +<glossdef><para>Implements high-level chip functions and exposes them via the <constant>CYG_NAND_FUNS</constant> macro. This file is not intended to be compiled on its own. +</para></glossdef></glossentry> +</glosslist> + +<para> A platform HAL would typically make use of this driver in a single source file +with the following steps:</para> +<itemizedlist> +<listitem><para> Declare a private struct and one or more static instances of it as appropriate,</para></listitem> +<listitem><para> <filename>#include <cyg/devs/nand/k9fxx08x0x.h></filename></para></listitem> +<listitem><para> implement the required low-level functions,</para></listitem> +<listitem><para> <filename>#include <cyg/devs/nand/k9fxx08x0x.inl></filename></para></listitem> +<listitem><para> finally, instantiate the chip with the <constant>CYG_NAND_DEVICE</constant> macro the appropriate number of times, giving each chip an appropriate name, its own private struct if need be, and selecting the ECC and OOB semantics to use.</para></listitem> +</itemizedlist> + +<para> +For more details about the infrastructure provided by the NAND layer +and the semantics it expects of the chip driver, refer to +<xref linkend="io-nand-overview">. An example driver instantiation can be +found in <link linkend="nanddev-ea-lpc2468">the NAND driver for the EA LPC2468 platform</link>.</para> + +<sect2 id="nanddev-samsung-k9-memory-note"> +<title>Memory usage</title> +<para> +As discussed in <xref linkend="nand-devs-highlevel">, the chip +initialisation function must set up the <varname>bbt.data</varname> +pointer in the <type>cyg_nand_device</type> struct. This driver does so +by including a sufficiently large byte array in the <type>k9_priv</type> +struct. That struct is intended to be allocated as a static struct in the +data or BSS segment (one per chip), which avoids adding a dependency +on <function>malloc</function>.</para> +</sect2> + +<sect2 id="nanddev-samsung-k9-functions-required"> +<title>Low-level functions required from the platform HAL</title> +<para> +These functions are prototyped in +<filename>k9fxx08x0x.h</filename>. +They have no return value ("void"), except for +<function>read_data_1</function> which returns the byte it has read.</para> + +<glosslist> +<glossentry><glossterm><function>write_cmd(device, +command)</function></glossterm><glossdef><para>Writes a single command +byte to the chip's command latch.</para></glossdef></glossentry> +<glossentry><glossterm><function>write_addrbytes(device, pointer to bytes, +number of bytes)</function></glossterm><glossdef><para>Writes a number +of address bytes in turn to the chip's address latch.</para></glossdef></glossentry> +<glossentry><glossterm><function>CYG_BYTE read_data_1(device)</function>, +<function>read_data_bulk(device, output pointer, number of +bytes)</function></glossterm><glossdef><para>Reads data from the device, +respectively a single byte and in bulk.</para></glossdef></glossentry> +<glossentry><glossterm><function>write_data_1(device, byte)</function>, +<function>write_data_bulk(device, data pointer, number of +bytes)</function></glossterm><glossdef><para>Writes data to the device, +respectively a single byte and in bulk.</para></glossdef></glossentry> +<glossentry><glossterm><function>wait_ready_or_time(device, initial delay, +fallback time)</function></glossterm><glossdef><para>Wait for the chip +to signal READY line or, if this line is not available, fall back to a worst-case +time delay (measured in microseconds).</para></glossdef></glossentry> +<glossentry><glossterm><function>wait_ready_or_status(device, +mask)</function></glossterm><glossdef><para>Wait for the chip to signal +READY line or, if this line is not available, enter a loop waiting for +its Status register (ANDed with the given mask) to be non-zero.</para></glossdef></glossentry> +<glossentry><glossterm><function>k9_devlock(device)</function>, +<function>k9_devunlock(device)</function></glossterm> +<glossdef><para>Hooks for any board-specific locking which may be required in +addition to the NAND library's chip-level locking. (This would be useful if, for example, +access to multiple chips was mediated by a single set of GPIO lines which ought not to be +invoked concurrently.)</para> +</glossdef></glossentry> +<glossentry><glossterm><function>k9_plf_init(device)</function></glossterm> +<glossdef><para>Board-level platform initialisation hook. This is called very early +on in the chip initialisation routine; it should set up any locking required by the +devlock and devunlock functions, interrupts for the driver and any further lines +required to access the chip as approprate. +<emphasis>Once this has returned, the chip driver assumes that the platform is fully prepared +for it to call the other chip access functions.</emphasis></para> +</glossdef></glossentry> +<glossentry><glossterm><function>k9_plf_partition_setup(device)</function></glossterm> +<glossdef><para>Board-level partition initialisation hook. +This should set up the <varname>partition</varname> array of the device struct in a way which +is appropriate to the platform. For example, the partitions may be set as fixed ranges +of blocks, or by CDL. This is called at the end of the chip initialisation routine and may, +for example, call into the chip to read out a "partition table" if one is present on the board. +<emphasis>If you do not set up partitions, applications will not be able to use the high-level +chip access functions provided the NAND library.</emphasis></para> +</glossdef></glossentry> +</glosslist> +</sect2> +</sect1> +</chapter> +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/samsung_k9/current/include/k9fxx08x0x.h @@ -0,0 +1,137 @@ +#ifndef CYGONCE_K9FXX08X0X_H +#define CYGONCE_K9FXX08X0X_H +//============================================================================= +// +// k9fxx08x0x.h +// +// Definitions header for the Samsung K9Fxx08x0x family +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-06-05 +// Description: Early definitions for the driver. +// The intention is that the instantiating C file include +// this file once, define the things it needs to, then +// include k9fxx08x0x.inl as many times as necessary +// (probably just once). +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/io_nand.h> +#include <cyg/nand/nand_device.h> +#include <cyg/hal/drv_api.h> +#include <cyg/infra/diag.h> + +#define k9_WAIT_tWB() HAL_DELAY_US(1) + +// This is a 1Gbit device with 1024 eraseblocks. +#define k9f1g_blockcount_bits 10 +#define k9f1g_chipsize_log 27 // 1Gbit = 2^30 bits = 2^27 bytes + +// The in-RAM BBT for a device is currently 2 bits per eraseblock. +// See nand_bbt.c for more. +#define k9f1g_bbt_datasize (1<<(k9f1g_blockcount_bits-2)) + +/* Our private structure ======================================= */ +// Every instance of the chip needs its own copy of this struct. +// N.B. that this is too big to go on the stack in certain +// eCos configurations; it should normally be static. + +struct _k9_priv { + void *plat_priv; // For use by the platform HAL, if desired. + cyg_nand_page_addr pagestash; // Guarded by dev lock. +#ifdef CYGSEM_IO_NAND_USE_BBT + unsigned char bbt_data[k9f1g_bbt_datasize]; +#endif +}; + +typedef struct _k9_priv k9_priv; + +/* Prototypes for functions to be provided by the platform driver ==== */ + +// Low-level chip access functions ------------------ + +static inline void write_cmd(cyg_nand_device *ctx, unsigned char cmd); +static inline void write_addrbytes(cyg_nand_device *ctx, CYG_BYTE *bytes, size_t n); +static inline unsigned char read_data_1(cyg_nand_device *ctx); +static inline void read_data_bulk(cyg_nand_device *ctx, unsigned char *dp, size_t n); +static inline void write_data_1(cyg_nand_device *ctx, unsigned char b); +static inline void write_data_bulk(cyg_nand_device *ctx, const unsigned char *dp, size_t n); + +// Chip BUSY line access / fallback ----------------- + +/* Waits either for the !BUSY line to signal that the device is finished, + or for the prescribed amount of time, depending on what is available + on the platform. + * wait_init specifies the time in microseconds to wait to ensure that + BUSY is asserted. + * wait_fallback specifies the worst-case time to wait (from the spec + sheet; again in microseconds) for the operation to complete. */ +static void wait_ready_or_time(cyg_nand_device *ctx, + size_t wait_init, size_t wait_fallback); + +/* Waits either for the !BUSY line to signal that the device is finished, + * or (if not available) polls the chip by sending the Read Status command + * and waits for (response & mask) to be non-zero. */ +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask); + +// Chip concurrent-access protection ---------------- +// (This need not do anything, if the library-provided +// per-device locking is sufficient.) + +static inline void k9_devlock(cyg_nand_device *ctx); +static inline void k9_devunlock(cyg_nand_device *ctx); + +// Initialisation hooks ----------------------------- + +/* Platform-specific chip initialisation. + * Set up chip access lines, GPIO config, &c; should also set up + * locking to guard against concurrent access. + * Return 0 on success, or a negative error code. */ +static int k9_plf_init(cyg_nand_device *ctx); + +/* (N.B. There is no deinit hook, as the library does not currently + * support a device being deconfigured.) */ + +/* Platform-specific in-memory partition table setup. + * Return 0 on success, or a negative error code. + * (This is called at the end of devinit, so you can read from the chip + * if need be.) */ +static int k9_plf_partition_setup(cyg_nand_device *dev); + +#endif
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/samsung_k9/current/include/k9fxx08x0x.inl @@ -0,0 +1,349 @@ +//============================================================================= +// +// k9fxx08x0x.inl +// +// Inline include file for the Samsung K9Fxx08x0x family +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-03 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/io_nand.h> +#include <cyg/devs/nand/k9fxx08x0x.h> +#include <cyg/infra/cyg_ass.h> + +#define LOCK(dev) k9_devlock(dev) +#define UNLOCK(dev) k9_devunlock(dev) + +/* Helpers ===================================================== */ + +static inline void change_read_column(cyg_nand_device *dev, cyg_nand_column_addr col) +{ + CYG_BYTE addr[2] = { col & 0xff, (col>>8) & 0xff }; + write_cmd(dev,0x05); + write_addrbytes(dev, &addr[0], 2); + write_cmd(dev,0xe0); + // wait tREA before reading further. + // This is 18ns, less than an instruction. +} + +static inline void change_write_column(cyg_nand_device *dev, cyg_nand_column_addr col) +{ + CYG_BYTE addr[2] = { col & 0xff, (col>>8) & 0xff }; + write_cmd(dev,0x85); + write_addrbytes(dev, &addr[0], 2); + // We must wait at least tADL (100ns) before writing further. + HAL_DELAY_US(1); // TODO: 1us is a bit wasteful; prefer a tighter sleep duration +} + +static inline CYG_BYTE read_status(cyg_nand_device *dev) +{ + write_cmd(dev,0x70); + return read_data_1(dev); +} + +/* Sends a reset command and waits for the RDY signal (or timeout) before + * returning. + * Timeout is tRST: + * 5us during a Read or idle; 10us during Program; 500us during Erase. + */ +static void k9_reset(cyg_nand_device *dev, size_t howlong) +{ + NAND_CHATTER(8,dev, "Resetting device\n"); + write_cmd(dev,0xFF); + wait_ready_or_time(dev, 1, howlong); +} + +/* Entrypoints ================================================= */ + +static int k9_devinit(cyg_nand_device *dev) +{ + k9_priv *priv = dev->priv; + CYG_BYTE addr = 0; + CYG_BYTE id[4]; + int rv = 0; + + // We are protected by the master devinit lock, so we are safe + // in the knowledge that there's only one of us running right now. + // (We still need to take out the chip-lock, though, in case there's + // another thread trying to access another device which interferes + // with us.) + + rv = k9_plf_init(dev); // sets up device locking as necessary + if (rv != ENOERR) return rv; // _not_ ER(), we haven't locked the chip yet + + LOCK(dev); // +++++++++++++++++++++++++++++++++++++++++++++ +#define ER(x) do { rv = (x); if (rv != ENOERR) goto err_exit; } while(0) + + k9_reset(dev,500); /* We must wait the worst-case reset time */ + + write_cmd(dev,0x90); + write_addrbytes(dev, &addr, 1); + // wait tWHR. + read_data_bulk(dev, &id[0], sizeof(id) / sizeof(id[0])); + + NAND_CHATTER(6,dev, "Reading device ID... %02x %02x %02x %02x\n", id[0], id[1], id[2], id[3]); + if (id[0] != 0xEC) { + NAND_CHATTER(1,dev, "Unrecognised manufacturer code %02x (expected EC)\n", id[0]); + ER(-ENODEV); + } + switch (id[1]) { + case 0xF1: + // We don't get chip size and block count from the fourth ID + // byte, so have to hard-code based on chip ID. + NAND_CHATTER(3,dev, "SAMSUNG K9F1G08X0X: 1Gbit, 8-bit data bus\n"); + // This is a 1Gbit device with 1024 eraseblocks. + dev->blockcount_bits = k9f1g_blockcount_bits; + dev->chipsize_log = k9f1g_chipsize_log; +#ifdef CYGSEM_IO_NAND_USE_BBT + dev->bbt.data = priv->bbt_data; + dev->bbt.datasize = sizeof(priv->bbt_data); +#endif + break; + default: + NAND_CHATTER(1,dev, "Unrecognised device code (expected F1)\n"); + ER(-ENODEV); + } + + // id[2] ignored + + if (id[3] != 0x15) { + // TODO: How generic is this decode code? + // Could relax this restriction later depending on chips to support. + NAND_CHATTER(1,dev, "Unrecognised info code (expected 15)\n"); + ER(-ENODEV); + } + + dev->page_bits = (id[3] & 3) + 10; // 00 -> 1kbyte; 01 -> 2k. + int bytes_per_page = 1 << (dev->page_bits); + CYG_ASSERT(bytes_per_page <= CYGNUM_NAND_PAGEBUFFER, "max pagebuffer not big enough"); + NAND_CHATTER(6,dev, "Page size: %u bytes (2^%u)\n", bytes_per_page, dev->page_bits); + + dev->spare_per_page = ( (id[3] & (1<<2)) ? 16 : 8 ) * (bytes_per_page /512); + NAND_CHATTER(6,dev, "Spare per page: %u bytes\n", dev->spare_per_page); + + size_t log2_blocksize = 16 /* 64KB */ + ((id[3] >> 4) & 3); // 00 -> 64KB per block, &c. + + dev->block_page_bits = log2_blocksize - dev->page_bits; + NAND_CHATTER(6,dev, "Pages per block: %u (2^%u)\n", 1<<dev->block_page_bits, dev->block_page_bits); + + if (id[3] & (1<<6)) { + NAND_ERROR(dev, "NAND Data bus 16 bits is NYI\n"); + ER(-ENODEV); + } + + if (dev->chipsize_log != + dev->page_bits + dev->block_page_bits + dev->blockcount_bits) { + NAND_ERROR(dev, "NAND device error: Coded chip size (2^%u bytes) does not match computed (2^%u by/pg, 2^%u pg/bl, 2^%u bl/chip)\n", dev->chipsize_log, dev->page_bits, dev->block_page_bits, dev->blockcount_bits); + ER(-ENODEV); + } + + // Could read the serial-access timing as well and configure a delay loop? + + ER(k9_plf_partition_setup(dev)); + +err_exit: + //k9_reset(dev,5); // Unnecessary. + UNLOCK(dev); // ------------------------------------------------ + return rv; +} +#undef ER + +static int k9_read_begin(cyg_nand_device *dev, cyg_nand_page_addr page) +{ + //k9_priv *priv = dev->priv; + CYG_BYTE addr[4] = { 0,0, page & 0xff, (page >> 8) & 0xff }; + + NAND_CHATTER(7,dev,"Reading page %d\n",page); + LOCK(dev); + + write_cmd(dev,0x00); + write_addrbytes(dev, &addr[0], 4); + write_cmd(dev,0x30); + wait_ready_or_time(dev, 1, 25 /* tR */); + return 0; +} + +static int k9_read_stride(cyg_nand_device *dev, void * dest, size_t size) +{ + read_data_bulk(dev, dest, size); + return 0; +} + +static int k9_read_finish(cyg_nand_device *dev, void * spare, size_t spare_size) +{ + + if (spare && spare_size) { + change_read_column(dev, 1 << dev->page_bits); + read_data_bulk(dev, spare, spare_size); + } + //k9_reset(dev,5); // Unnecessary. + UNLOCK(dev); + return 0; +} + +static int k9_read_part(cyg_nand_device *dev, void *dest, + cyg_nand_page_addr page, size_t offset, size_t length) +{ + //k9_priv *priv = dev->priv; + CYG_BYTE addr[4] = { offset & 0xff, (offset >> 8) & 0xff, + page & 0xff, (page >> 8) & 0xff }; + + NAND_CHATTER(7,dev,"Reading page %d (partial; offset %d, length %d)\n", + page, offset, length); + LOCK(dev); + + write_cmd(dev,0x00); + write_addrbytes(dev, &addr[0], 4); + write_cmd(dev,0x30); + wait_ready_or_time(dev, 1, 25 /* tR */); + + read_data_bulk(dev, dest, length); + + UNLOCK(dev); + return 0; +} + +static int k9_write_begin(cyg_nand_device *dev, cyg_nand_page_addr page) +{ + k9_priv *priv = dev->priv; + CYG_BYTE addr[4] = { 0,0, page & 0xff, (page >> 8) & 0xff }; + // NB: Program with random data input takes a _five_ byte address, + // according to spec p24. This doesn't make sense - everything else + // about this chip takes a four-byte address - and is contradicted by p32. + + LOCK(dev); + priv->pagestash = page; + write_cmd(dev,0x80); + write_addrbytes(dev, &addr[0], 4); + + return 0; +} + +static int k9_write_stride(cyg_nand_device *dev, const void * src, size_t size) +{ + write_data_bulk(dev, src, size); + return 0; +} + +static int k9_write_finish(cyg_nand_device *dev, const void * spare, size_t spare_size) +{ + k9_priv *priv = dev->priv; + int rv = 0; + if (spare && spare_size) { + change_write_column(dev, 1 << dev->page_bits); + write_data_bulk(dev, spare, spare_size); + } + write_cmd(dev,0x10); + wait_ready_or_status(dev, 1<<6); + + if (read_status(dev) & 1) { + NAND_ERROR(dev, "k9fxx08x0x: Programming failed! Page %u", priv->pagestash); + rv =-EIO; + goto done; + } else { + NAND_CHATTER(7,dev, "Programmed %u OK\n", priv->pagestash); + } +done: + //k9_reset(dev,5); // Unnecessary. + UNLOCK(dev); + return rv; +} + +static int k9_erase_block(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + //k9_priv *priv = dev->priv; + unsigned row = blk << (dev->block_page_bits); + CYG_BYTE addr[2] = { row & 0xff, (row >> 8) & 0xff }; + int rv = 0; + + LOCK(dev); + write_cmd(dev,0x60); + write_addrbytes(dev, &addr[0], 2); + write_cmd(dev,0xd0); + wait_ready_or_status(dev, 1<<6); + if (read_status(dev) & 1) { + rv = -EIO; + NAND_ERROR(dev, "k9fxx08x0x: Erasing block %u failed.\n",blk); + goto done; + } + NAND_CHATTER(7,dev, "Erased block %u OK\n", blk); +done: + UNLOCK(dev); + return rv; +} + +// The spec sheet says to check the 1st OOB byte (address 2048) in +// both the 1st and 2nd page of the block. If both are 0xFF, the block is OK; +// else it's bad. +#define K9_FACTORY_BAD_COLUMN_ADDR 2048 +static int k9_factorybad(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + cyg_nand_page_addr page, + pagebase = blk * (1<<dev->block_page_bits); + const int col = K9_FACTORY_BAD_COLUMN_ADDR; + int rv = 0, i; + + LOCK(dev); + + for (i=0; i<2; i++) { + page = pagebase+i; + CYG_BYTE addr[4] = { col & 0xff, (col>>8) & 0xff, + page & 0xff, (page>>8) & 0xff }; + + write_cmd(dev,0x00); + write_addrbytes(dev, &addr[0], 4); + write_cmd(dev,0x30); + wait_ready_or_time(dev, 1, 25 /* tR */); + unsigned char t = read_data_1(dev); + if (t != 0xff) rv=1; + //k9_reset(dev,5); // Unnecessary. + } + + UNLOCK(dev); + return rv; +} + +CYG_NAND_FUNS_V2(k9f8_funs, k9_devinit, + k9_read_begin, k9_read_stride, k9_read_finish, + k9_read_part, + k9_write_begin, k9_write_stride, k9_write_finish, + k9_erase_block, k9_factorybad); +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/st/nandxxxx3a/current/ChangeLog @@ -0,0 +1,59 @@ +2009-11-13 Ross Younger <wry@ecoscentric.com> + + * Don't provide bbt_data if it isn't called for. + +2009-11-09 Ross Younger <wry@ecoscentric.com> + + * Driver update: add read_part_page function. + +2009-11-06 Ross Younger <wry@ecoscentric.com> + + * nand_st_xxxx3a.sgml: Remove link to cortexm hal. + +2009-10-19 Ross Younger <wry@ecoscentric.com> + + * Update to driver v2. Require CYGSEM_IO_NAND_INTERFACE_VERSION >= 2. + +2009-08-11 Ross Younger <wry@ecoscentric.com> + + * Improve driver timings, sundry tidyups + +2009-06-30 Simon Kallweit <simon.kallweit@intefo.ch> + + * New package. ST Microelectronics NANDxxxx3A flash chips. + +//=========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 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#### +//=========================================================================== + +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/st/nandxxxx3a/current/cdl/nandxxxx3a.cdl @@ -0,0 +1,66 @@ +# ==================================================================== +# +# nandxxxx3a.cdl +# +# Drivers for the ST Microelectronics familiy of NANDxxxx3A chips. +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 Free Software Foundation +# +# 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): Simon Kallweit +# Date: 2009-06-30 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_NAND_ST_NANDXXXX3A { + display "ST Microelectronics NANDxxxx3A chip family support" + parent CYGPKG_IO_NAND + active_if CYGPKG_IO_NAND + # This does NOT implement CYGHWR_IO_NAND_DEVICE - it only provides + # functions for the platform HAL to draw on and itself implement + # CYGHWR_IO_NAND_DEVICE. + include_dir cyg/devs/nand + description " + This package provides support for the ST Microelectronics NANDxxxx3A + family of NAND flash devices. It is intended to be easy to port to + further chips from the same family. This package can only be used in + conjunction with the platform HAL for the target, in order to bring it + in and properly configure it to talk to the hardware present." + # This is a 512 byte page device. + requires ( CYGNUM_NAND_PAGEBUFFER >= 512 ) + requires ( CYGSEM_IO_NAND_INTERFACE_VERSION >= 2 ) +}
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/st/nandxxxx3a/current/doc/makefile @@ -0,0 +1,8 @@ +TOPLEVEL := ../../../../../.. +MAIN_SGML := nand_st_xxxx3a.sgml +MAIN_HTML := aaa-XXX-book.html +MAIN_PDF := +OTHER_SGML := +PICTURES := + +include $(TOPLEVEL)/pkgconf/rules.doc
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/st/nandxxxx3a/current/doc/nand_st_xxxx3a.sgml @@ -0,0 +1,151 @@ +<!-- DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook V3.1//EN" --> + +<!-- =============================================================== --> +<!-- --> +<!-- nand_k9.sgml --> +<!-- --> +<!-- NAND chip support for the ST Microelectronics xxxx3a family --> +<!-- --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> +<!-- =============================================================== --> +<!-- Copyright (C) 2009 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): wry --> +<!-- Contact(s): wry --> +<!-- Date: 2009/09/01 --> +<!-- Version: 0.01 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<chapter id="devs-nand-st-xxxx3a"> +<title>ST Microelectronics NANDxxxx3a chips</title> +<sect1 id="devs-nand-st-xxxx3a-overview"> +<title>Overview</title> + +<para> +The <varname>CYGPKG_DEVS_NAND_ST_NANDXXXX3A</varname> driver package +provides support for the NANDxxxx3A chip family by ST Microelectronics. +</para> + +<para> +Most users will only need to add this package to their eCos configuration +and not need to interact with it further. This package provides only an +inline code fragment which is intended to be instantiated by the target +platform HAL and provided with appropriate board-specific low-level +functions allowing it to access the hardware. +</para> + +<sect2 id="devs-nand-st-xxxx3a-instantiation"><title>Using this driver in a board port</title> +<para> +This driver's chip support is currently provided as two files:</para> + +<glosslist> +<glossentry><glossterm><filename>cyg/devs/nand/nandxxxx3a.h</filename></glossterm> +<glossdef><para>Prototypes the low-level chip access functions required by the chip driver, +declares a private struct for use by the driver and provides a +<constant>NANDXXXX3A_DEVICE</constant> macro for convenience.</para></glossdef></glossentry> +<glossentry><glossterm><filename>cyg/devs/nand/nandxxxx3a.inl</filename></glossterm> +<glossdef><para>Implements high-level chip functions and exposes them via the <constant>CYG_NAND_FUNS</constant> macro. This file is not intended to be compiled on its own. +</para></glossdef></glossentry> +</glosslist> + +<para> +A platform HAL would typically make use of this driver in a single source file with the following steps:</para> +<itemizedlist> +<listitem><para> Declare a private struct and one or more static instances of it as appropriate,</para></listitem> +<listitem><para> <filename>#include <cyg/devs/nand/nandxxxx3a.h></filename></para></listitem> +<listitem><para> implement the required low-level functions,</para></listitem> +<listitem><para> <filename>#include <cyg/devs/nand/nandxxxx3a.inl></filename></para></listitem> +<listitem><para> finally, instantiate the chip with the <constant>NANDXXXX3A_DEVICE</constant> macro the appropriate number of times, giving each chip an appropriate name and its own private struct if need be, declaring its size, and selecting the ECC and OOB semantics to use.</para></listitem> +</itemizedlist> + +<para> +For more details about the infrastructure provided by the NAND layer +and the semantics it expects of the chip driver, refer to +<xref linkend="io-nand-overview">. An example driver instantiation can be +found in the platform HAL for the STM3210E-EVAL board. +</para></sect2> + +<sect2 id="devs-nand-st-xxxx3a-memory-note"> +<title>Memory usage note</title> +<para> +As discussed in <xref linkend="nand-devs-highlevel">, the chip +initialisation function must set up the <varname>bbt.data</varname> +pointer in the <type>cyg_nand_device</type> struct. This driver does so +by including pointer to a sufficiently large byte array in the +<type>nandxxx3a_priv</type> struct. That struct is intended to be +allocated as a static struct in the data or BSS segment (one per chip), +which avoids adding a dependency on <function>malloc</function>. +</para></sect2> + +<sect2 id="devs-nand-st-xxxx3a-functions-required"> +<title>Low-level functions required from the platform HAL</title> +<para> +These functions are prototyped in +<filename>nandxxxx3a.h</filename>. +They have no return value ("void"), except where indicated.</para> + +<glosslist> +<glossentry><glossterm><function>write_cmd(device, +command)</function></glossterm><glossdef><para>Writes a single command +byte to the chip's command latch.</para></glossdef></glossentry> +<glossentry><glossterm><function>write_addrbytes(device, pointer to bytes, +number of bytes)</function></glossterm><glossdef><para>Writes a number +of address bytes in turn to the chip's address latch.</para></glossdef></glossentry> +<glossentry><glossterm><type>CYG_BYTE</type> <function>read_data_1(device)</function>, +<function>read_data_bulk(device, output pointer, number of +bytes)</function></glossterm><glossdef><para>Reads data from the device, +respectively a single byte and in bulk.</para></glossdef></glossentry> +<glossentry><glossterm><function>write_data_1(device, byte)</function>, +<function>write_data_bulk(device, data pointer, number of +bytes)</function></glossterm><glossdef><para>Writes data to the device, +respectively a single byte and in bulk.</para></glossdef></glossentry> +<glossentry><glossterm><function>wait_ready_or_time(device, initial delay, +fallback time)</function></glossterm><glossdef><para>Wait for the chip +to signal READY or, if this line is not available, fall back to a worst-case +time delay (measured in microseconds).</para></glossdef></glossentry> +<glossentry><glossterm><function>wait_ready_or_status(device, +mask)</function></glossterm><glossdef><para>Wait for the chip to signal +READY or, if this line is not available, enter a loop waiting for +its Status register (ANDed with the given mask) to be non-zero.</para></glossdef></glossentry> +<glossentry><glossterm><function>nandxxxx3a_devlock(device)</function>, +<function>nandxxxx3a_devunlock(device)</function></glossterm> +<glossdef><para>Hooks for any board-specific locking which may be required in +addition to the NAND library's chip-level locking. (This would be useful if, for example, +access to multiple chips was mediated by a single set of GPIO lines which ought not to be +invoked concurrently.)</para> +</glossdef></glossentry> +<glossentry><glossterm><type>int</type> <function>nandxxxx3a_plf_init(device)</function></glossterm> +<glossdef><para>Board-level platform initialisation hook. This is called very early +on in the chip initialisation routine; it should set up any locking required by the +devlock and devunlock functions, interrupts for the driver and any further lines +required to access the chip as approprate. +<emphasis>Once this has returned, the chip driver assumes that the platform is fully prepared +for it to call the other chip access functions.</emphasis></para> +</glossdef></glossentry> +<glossentry><glossterm><type>int</type> <function>nandxxxx3a_plf_partition_setup(device)</function></glossterm> +<glossdef><para>Board-level partition initialisation hook. +This should set up the <varname>partition</varname> array of the device struct in a way which +is appropriate to the platform. For example, the partitions may be set as fixed ranges +of blocks, or by CDL. This is called at the end of the chip initialisation routine and may, +for example, call into the chip to read out a "partition table" if one is present on the board. +<emphasis>If you do not set up partitions, applications will not be able to use the high-level +chip access functions provided the NAND library.</emphasis></para> +</glossdef></glossentry> +</glosslist> +</sect2> +</sect1> +</chapter>
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/st/nandxxxx3a/current/include/nandxxxx3a.h @@ -0,0 +1,150 @@ +#ifndef CYGONCE_ST_NANDXXXX3A_H +#define CYGONCE_ST_NANDXXXX3A_H +//============================================================================= +// +// nandxxxx3a.h +// +// Definitions header for the ST Microelectronics NANDxxxx3A family. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation. +// +// 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): Simon Kallweit +// Date: 2009-06-30 +// Description: Early definitions for the driver. +// The intention is that the instantiating C file include +// this file once, define the things it needs to, then +// include st_nand.inl as many times as necessary +// (probably just once). +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/io_nand.h> +#include <cyg/nand/nand_device.h> +#include <cyg/hal/drv_api.h> +#include <cyg/infra/diag.h> + +#define st_nand_wait_for_BUSY() HAL_DELAY_US(1) + +/* Our private structure ======================================= */ +// Every instance of the chip needs its own copy of this struct. +// N.B. that this is too big to go on the stack in certain +// eCos configurations; it should normally be static. + +struct nandxxxx3a_priv { + void *plat_priv; // For use by the platform HAL, if desired. + int mbit; +#ifdef CYGSEM_IO_NAND_USE_BBT + unsigned char *bbt_data; +#endif + cyg_nand_page_addr pageop; // Protected by device lock + size_t written; // Protected by device lock +}; + +#ifdef CYGSEM_IO_NAND_USE_BBT +#define DECLARE_BBT_DATA(_structname_, _mbit_) unsigned char _structname_##_bbt_data[_mbit_ * 8] +#define INIT_BBT_DATA(_structname_) .bbt_data = _structname_##_bbt_data, +#else +#define DECLARE_BBT_DATA(_structname_, _mbit_) +#define INIT_BBT_DATA(_structname_) +#endif + + +// Macro to instantiate a ST NANDxxxx3A device +#define NANDXXXX3A_DEVICE(_structname_, _devname_, _mbit_, _priv_, _ecc_, _oob_)\ + DECLARE_BBT_DATA(_structname_, _mbit_); \ +struct nandxxxx3a_priv _structname_##_priv = \ +{ \ + .plat_priv = _priv_, \ + .mbit = _mbit_, \ + INIT_BBT_DATA(_structname_) \ +}; \ +CYG_NAND_DEVICE(_structname_, _devname_, &nandxxxx3a_funs, \ + &_structname_##_priv, _ecc_, _oob_); + +/* Prototypes for functions to be provided by the platform driver ==== */ + +// Low-level chip access functions ------------------ + +static inline void write_cmd(cyg_nand_device *ctx, unsigned char cmd); +static inline void write_addrbytes(cyg_nand_device *ctx, CYG_BYTE *bytes, size_t n); +static inline unsigned char read_data_1(cyg_nand_device *ctx); +static inline void read_data_bulk(cyg_nand_device *ctx, unsigned char *dp, size_t n); +static inline void write_data_1(cyg_nand_device *ctx, unsigned char b); +static inline void write_data_bulk(cyg_nand_device *ctx, const unsigned char *dp, size_t n); + +// Chip BUSY line access / fallback ----------------- + +/* Waits either for the !BUSY line to signal that the device is finished, + or for the prescribed amount of time, depending on what is available + on the platform. + * wait_init specifies the time in microseconds to wait to ensure that + BUSY is asserted. + * wait_fallback specifies the worst-case time to wait (from the spec + sheet; again in microseconds) for the operation to complete. */ +static void wait_ready_or_time(cyg_nand_device *ctx, + size_t wait_init, size_t wait_fallback); + +/* Waits either for the !BUSY line to signal that the device is finished, + * or (if not available) polls the chip by sending the Read Status command + * and waits for (response & mask) to be non-zero. */ +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask); + +// Chip concurrent-access protection ---------------- +// (This need not do anything, if the library-provided +// per-device locking is sufficient.) + +static inline void nandxxxx3a_devlock(cyg_nand_device *ctx); +static inline void nandxxxx3a_devunlock(cyg_nand_device *ctx); + +// Initialisation hooks ----------------------------- + +/* Platform-specific chip initialisation. + * Set up chip access lines, GPIO config, &c; should also set up + * locking to guard against concurrent access. + * Return 0 on success, or a negative error code. */ +static int nandxxxx3a_plf_init(cyg_nand_device *ctx); + +/* (N.B. There is no deinit hook, as the library does not currently + * support a device being deconfigured.) */ + +/* Platform-specific in-memory partition table setup. + * Return 0 on success, or a negative error code. + * (This is called at the end of devinit, so you can read from the chip + * if need be.) */ +static int nandxxxx3a_plf_partition_setup(cyg_nand_device *dev); + +#endif // CYGONCE_ST_NANDXXXX3A_H
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/st/nandxxxx3a/current/include/nandxxxx3a.inl @@ -0,0 +1,365 @@ +//============================================================================= +// +// nandxxxx3a.inl +// +// Inline include file for the ST Microelectronics NANDxxxx3A family. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation. +// +// 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): Simon Kallweit +// Date: 2009-06-30 +// Contributors: wry, for updates to the NAND interface +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/io_nand.h> +#include <cyg/devs/nand/nandxxxx3a.h> +#include <cyg/infra/cyg_ass.h> + +#define LOCK(dev) nandxxxx3a_devlock(dev) +#define UNLOCK(dev) nandxxxx3a_devunlock(dev) + +/* Helpers ===================================================== */ + +static inline void write_addr(cyg_nand_device *dev, cyg_nand_page_addr page, + cyg_nand_column_addr col) +{ + struct nandxxxx3a_priv *priv = dev->priv; + + if (priv->mbit <= 256) { + CYG_BYTE addr[3] = { col & 0xff, page & 0xff, (page >> 8) & 0xff }; + write_addrbytes(dev, addr, 3); + } else { + CYG_BYTE addr[4] = { col & 0xff, page & 0xff, (page >> 8) & 0xff, + (page >> 16) & 0xff }; + write_addrbytes(dev, addr, 4); + } +} + +static inline CYG_BYTE read_status(cyg_nand_device *dev) +{ + write_cmd(dev, 0x70); + return read_data_1(dev); +} + +/* Sends a reset command and waits for the RDY signal (or timeout) before + * returning. + * Timeout is tRST: + * 5us during a Read or idle; 10us during Program; 500us during Erase. + */ +static void nandxxxx3a_reset(cyg_nand_device *dev, size_t howlong) +{ + NAND_CHATTER(8, dev, "Resetting device\n"); + write_cmd(dev, 0xff); + wait_ready_or_time(dev, 1, howlong); +} + +/* Entrypoints ================================================= */ + +static int nandxxxx3a_devinit(cyg_nand_device *dev) +{ + struct nandxxxx3a_priv *priv = dev->priv; + CYG_BYTE addr = 0; + CYG_BYTE id[2]; + int rv = 0; + int size_log; + const char *typ; + + // We are protected by the master devinit lock, so we are safe + // in the knowledge that there's only one of us running right now. + // (We still need to take out the chip-lock, though, in case there's + // another thread trying to access another device which interferes + // with us.) + + rv = nandxxxx3a_plf_init(dev); // Sets up device locking as necessary + if (rv != ENOERR) + return rv; // _not_ ER(), we haven't locked the chip yet + + LOCK(dev); // +++++++++++++++++++++++++++++++++++++++++++++ +#define ER(x) do { rv = (x); if (rv != ENOERR) goto err_exit; } while(0) + + nandxxxx3a_reset(dev, 500); // We must wait the worst-case reset time + + write_cmd(dev, 0x90); + write_addrbytes(dev, &addr, 1); + read_data_bulk(dev, id, sizeof(id)); + + NAND_CHATTER(6, dev, "Reading device ID... %02x %02x\n", id[0], id[1]); + if (id[0] != 0x20) { + NAND_CHATTER(1, dev, "Unrecognised manufacturer code %02x (expected 20)\n", id[0]); + ER(-ENODEV); + } + + switch (id[1]) { + case 0x33: // NAND128R3A + typ = "128R"; size_log = 24; break; + case 0x73: // NAND128W3A + typ = "128W"; size_log = 24; break; + case 0x35: // NAND256R3A + typ = "256R"; size_log = 25; break; + case 0x75: // NAND256W3A + typ = "256W"; size_log = 25; break; + case 0x36: // NAND512R3A + typ = "512R"; size_log = 26; break; + case 0x76: // NAND512W3A + typ = "512W"; size_log = 26; break; + case 0x39: // NAND01GR3A + typ = "01GR"; size_log = 27; break; + case 0x79: // NAND01GW3A + typ = "01GW"; size_log = 27; break; + default: + NAND_CHATTER(1, dev, "Unrecognised NAND device\n"); + ER(-ENODEV); + break; + } + + NAND_CHATTER(3, dev, "ST Microelectronics NAND%s3A: %dMbit, 8-bit data bus\n", typ, 1 << (size_log - 17)); + if (1 << (size_log - 17) != priv->mbit) { + NAND_ERROR(dev, "NAND device error: Chip size does not match configured size\n"); + ER(-ENODEV); + } + + dev->page_bits = 9; // Pages are 512 bytes + dev->spare_per_page = 16; // OBB area is 16 bytes + dev->block_page_bits = 5; // 32 pages per block + dev->blockcount_bits = size_log - 14; + dev->chipsize_log = size_log; +#ifdef CYGSEM_IO_NAND_USE_BBT + dev->bbt.data = priv->bbt_data; + dev->bbt.datasize = priv->mbit * 8; +#endif + + int bytes_per_page = 1 << (dev->page_bits); + CYG_ASSERT(bytes_per_page <= CYGNUM_NAND_PAGEBUFFER, "max pagebuffer not big enough"); + NAND_CHATTER(6, dev, "Page size: %u bytes (2^%u)\n", bytes_per_page, dev->page_bits); + NAND_CHATTER(6, dev, "Spare per page: %u bytes\n", dev->spare_per_page); + NAND_CHATTER(6, dev, "Pages per block: %u (2^%u)\n", 1 << dev->block_page_bits, dev->block_page_bits); + + if (dev->chipsize_log != + dev->page_bits + dev->block_page_bits + dev->blockcount_bits) { + NAND_ERROR(dev, "NAND device error: Coded chip size (2^%u bytes) does not match computed (2^%u by/pg, 2^%u pg/bl, 2^%u bl/chip)\n", dev->chipsize_log, dev->page_bits, dev->block_page_bits, dev->blockcount_bits); + ER(-ENODEV); + } + + // Could read the serial-access timing as well and configure a delay loop? + + ER(nandxxxx3a_plf_partition_setup(dev)); + +err_exit: + UNLOCK(dev); // ------------------------------------------------ + return rv; +} +#undef ER + + +static int nandxxxx3a_read_begin(cyg_nand_device *dev, cyg_nand_page_addr page) +{ + struct nandxxxx3a_priv *priv = dev->priv; + NAND_CHATTER(7, dev, "Reading page %d\n",page); + LOCK(dev); + priv->pageop = page; + + write_cmd(dev, 0x00); + write_addr(dev, priv->pageop, 0); + wait_ready_or_time(dev, 1, 12); + return 0; +} + +static int nandxxxx3a_read_stride(cyg_nand_device *dev, void *dest, size_t size) +{ + //struct nandxxxx3a_priv *priv = dev->priv; + read_data_bulk(dev, dest, size); + return 0; +} + +static int nandxxxx3a_read_finish(cyg_nand_device *dev, + void *spare, size_t spare_size) +{ + struct nandxxxx3a_priv *priv = dev->priv; + if (spare && spare_size) { + write_cmd(dev, 0x50); + write_addr(dev, priv->pageop, 0); + wait_ready_or_time(dev, 1, 12); + read_data_bulk(dev, spare, spare_size); + } + + UNLOCK(dev); + return 0; +} + +static int nandxxxx3a_read_part(cyg_nand_device *dev, void *dest, + cyg_nand_page_addr page, size_t offset, size_t length) +{ + //struct nandxxxx3a_priv *priv = dev->priv; + + NAND_CHATTER(7,dev,"Reading page %d (partial; offset %d, length %d)\n", + page, offset, length); + + cyg_nand_column_addr col = offset & 0xff; + CYG_BYTE cmd = offset & 256 ? 1 /* READ_B */ : 0 /* READ_A */; + LOCK(dev); + + write_cmd(dev, cmd); + write_addr(dev, page, col); + wait_ready_or_time(dev, 1, 12); + read_data_bulk(dev, dest, length); + + UNLOCK(dev); + return 0; +} + + +static int nandxxxx3a_write_begin(cyg_nand_device *dev, cyg_nand_page_addr page) +{ + struct nandxxxx3a_priv *priv = dev->priv; + LOCK(dev); + priv->pageop = page; + priv->written = 0; + + write_cmd(dev, 0x00); + write_cmd(dev, 0x80); + write_addr(dev, page, 0); + return 0; +} + +static int nandxxxx3a_write_stride(cyg_nand_device *dev, + const void *src, size_t size) +{ + struct nandxxxx3a_priv *priv = dev->priv; + write_data_bulk(dev, src, size); + priv->written += size; + return 0; +} + +static int nandxxxx3a_write_finish(cyg_nand_device *dev, + const void *spare, size_t spare_size) +{ + struct nandxxxx3a_priv *priv = dev->priv; + int rv = 0; + + if (priv->written) { + write_cmd(dev, 0x10); + wait_ready_or_status(dev, 1 << 6); + if (read_status(dev) & 1) + goto fail; + } + + if (spare && spare_size) { + write_cmd(dev, 0x50); + write_cmd(dev, 0x80); + write_addr(dev, priv->pageop, 0); + write_data_bulk(dev, spare, spare_size); + write_cmd(dev, 0x10); + wait_ready_or_status(dev, 1 << 6); + } + + if (read_status(dev) & 1) { +fail: + NAND_ERROR(dev, "NAND: Programming page %u failed!", priv->pageop); + rv = -EIO; + goto done; + } else { + NAND_CHATTER(7, dev, "Programmed %u OK\n", priv->pageop); + } + +done: + UNLOCK(dev); + return rv; +} + +static int nandxxxx3a_erase_block(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + struct nandxxxx3a_priv *priv = dev->priv; + cyg_nand_page_addr page = blk << dev->block_page_bits; + int rv = 0; + + LOCK(dev); + + write_cmd(dev, 0x60); + if (priv->mbit <= 256) { + CYG_BYTE addr[2] = { page & 0xff, (page >> 8) & 0xff }; + write_addrbytes(dev, addr, 2); + } else { + CYG_BYTE addr[3] = { page & 0xff, (page >> 8) & 0xff, (page >> 16) & 0xff }; + write_addrbytes(dev, addr, 3); + } + write_cmd(dev, 0xd0); + wait_ready_or_status(dev, 1 << 6); + if (read_status(dev) & 1) { + rv = -EIO; + NAND_ERROR(dev, "NAND: Erasing block %u failed.\n", blk); + goto done; + } + NAND_CHATTER(7, dev, "Erased block %u OK\n", blk); + +done: + UNLOCK(dev); + return rv; +} + +// The spec sheet says to check the 6th OOB byte (address 6) in the first +// page of the block. If it is 0xFF, the block is OK, otherwise it's bad. +// (N.B. Chips with a 16-bit data bus, check the 1st OOB word.) +#define NANDXXXX3A_FACTORY_BAD_COLUMN_ADDR 6 +static int nandxxxx3a_factorybad(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + //struct nandxxxx3a_priv *priv = dev->priv; + cyg_nand_page_addr page = blk * (1 << dev->block_page_bits); + const int col = NANDXXXX3A_FACTORY_BAD_COLUMN_ADDR; + int rv = 0; + + LOCK(dev); + + write_cmd(dev, 0x50); + write_addr(dev, page, col); + wait_ready_or_time(dev, 1, 12); + unsigned char t = read_data_1(dev); + if (t != 0xff) + rv = 1; + + UNLOCK(dev); + return rv; +} + +CYG_NAND_FUNS_V2(nandxxxx3a_funs, nandxxxx3a_devinit, + nandxxxx3a_read_begin, nandxxxx3a_read_stride, + nandxxxx3a_read_finish, + nandxxxx3a_read_part, + nandxxxx3a_write_begin, + nandxxxx3a_write_stride, nandxxxx3a_write_finish, + nandxxxx3a_erase_block, + nandxxxx3a_factorybad);
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/ChangeLog @@ -0,0 +1,103 @@ +2009-11-13 Ross Younger <wry@ecoscentric.com> + + * Don't provide BBT data if it's not called for. + +2009-11-09 Ross Younger <wry@ecoscentric.com> + + * nand_synth.c: Provide read_part_page function. + +2009-11-06 Ross Younger <wry@ecoscentric.com> + + * nand_synth.c: Use new fast ECC implementation. + +2009-10-19 Ross Younger <wry@ecoscentric.com> + + * nand_synth.c: Update to interface v2. + * nand_synth.cdl: Require CYGSEM_IO_NAND_INTERFACE_VERSION >= 2. + +2009-09-28 Ross Younger <wry@ecoscentric.com> + + * tests: Don't put unreasonably large arrays on stack. Build-fix + multipagebbt. + +2009-09-16 Ross Younger <wry@ecoscentric.com> + + * tests: Buildfix bbt.c and eccdamage.c + * nand_synth.c: Ensure that bit errors induced by RANDOMLY_LOSE mode + can occur over the whole range of the page data and spare area. + +2009-08-28 Ross Younger <wry@ecoscentric.com> + + * tests: Add bbt.c and multipagebbt.c (moved from io/nand). + * doc/synth_nand.sgml: Document this device's test programs. + +2009-07-31 Bart Veer <bartv@ecoscentric.com> + + * doc/synth_nand.sgml, src/nand_synth.c: add support for per-block + erase counts and per-page write counts to monitor wear-levelling. + +2009-07-14 Bart Veer <bartv@ecoscentric.com> + + * host/nand.tcl (dialog): avoid the use of max() for compatibility + with ancient Tcl 8.4 installations. + + * host/configure.in: allow builds on x86_64 machines. + + * host/configure: regenerate. + + * doc/synth_nand.sgml, doc/dialog1.png, doc/dialog2.png: add + documentation. + +2009-07-09 Bart Veer <bartv@ecoscentric.com> + + * host/nand.tcl, host/nand.tdf, src/nand_synth.c: first attempt at + a full-blown implementation complete with logging and error + injection. + + * cdl/nand_synth.cdl: add dependencies on other packages. Fix name + of CYGDAT_NAND_SYNTH_FILENAME option as per CDL coding standards. + +2009-06-17 Ross Younger <wry@eCosCentric.com> + + * Retab for consistency with other eCos sources. + * Move eccdamage test from io/nand. + +2009-03-06 Ross Younger <wry@eCosCentric.com> + + * New package. Synthetic NAND flash chip. + +//=========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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#### +//=========================================================================== + +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/cdl/manual_partition.cdl @@ -0,0 +1,124 @@ +# ==================================================================== +# +# manual_partition.cdl +# +# NAND device manual partition logic +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 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): wry +# Date: 2009-03-10 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +# This file can be used by drivers to implement manual CDL-driven +# partition config. +# +# To use, create a cdl_component with an appropriate name; +# make it boolean or otherwise selectable (you might for example want +# to turn it off, or pick partitioning strategy from a drop-down list), +# then choose and set a name-fragment for your device before including +# this script file along these lines: +# +# set ::partition_device "SYNTH" +# script manual_partition.cdl +# +# For a full example, see the synthetic NAND device. + + +####################################################### + +# Partition table support + +# Every NAND board driver has to decide how it will determine the +# NAND partition layout. In a simple case, there might be just +# a single partition covering the whole chip. Alternatively, +# the driver could read a partition table during _devinit, or +# the partition layout might be hard-wired (e.g. to inter-operate +# with some other fixed code). + +### +# Unfortunately, it is not currently possible within CDL to +# directly access the value of CYGNUM_NAND_MAX_PARTITIONS in a +# Tcl loop, so we cannot automatically have the second argument +# to this for loop be { $::part < CYGNUM_NAND_MAX_PARTITIONS } . +# The best we can do is pick an arbitrary number - we'll choose 4, +# because that's the same as the default CYGNUM_NAND_MAX_PARTITIONS, +# and put only that many in the loop. The current limitations of +# also mean that we have to manually check for each of the four +# partitions in C - so if you edit the number 4 below, be sure +# to tweak the corresponding macro use which makes use of it! +# +# (Four ought to be enough for everybody, shouldn't it?) +### + +for { set ::part 0 } { $::part < 4 } { incr ::part } { + cdl_option CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] { + active_if $::part < CYGNUM_NAND_MAX_PARTITIONS + display "Configure partition [set ::part]" + flavor bool + default_value [set ::part] == 0 + description " + Set in order to manually configure partition [set ::part] + in CDL." + } + + cdl_option CYGNUM_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part]_BASE { + display "Partition [set ::part] base block address" + active_if CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] == 1 + flavor data + legal_values 0 to 0x7fffffff + default_value 0 + description " + The address (number) of the eraseblock at which + partition [set ::part] begins." + } + + cdl_option CYGNUM_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part]_SIZE { + display "Partition [set ::part] size in blocks" + active_if CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] == 1 + flavor data + legal_values 0 to 0x7fffffff + default_value 0 + description " + The size of partition [set ::part], expressed + in eraseblocks. A value of 0 is special and + consumes all the remaining space on the device." + } +} +# / for loop for partitions.
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/cdl/nand_synth.cdl @@ -0,0 +1,193 @@ +# ==================================================================== +# +# nand_synth.cdl +# +# Synthetic NAND device +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 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): wry +# Date: 2009-03-05 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_NAND_SYNTH { + display "Synthetic NAND device" + parent CYGPKG_IO_NAND + active_if CYGPKG_IO_NAND && CYGPKG_HAL_SYNTH + compile -library=libextras.a nand_synth.c + implements CYGHWR_IO_NAND_DEVICE + requires CYGINT_ISO_RAND + requires CYGINT_ISO_ERRNO_CODES + requires CYGINT_ISO_STRING_STRFUNCS + requires { CYGSEM_IO_NAND_INTERFACE_VERSION >= 2 } + + description " + This package provides support for a synthetic NAND device. + " + + cdl_component CYGPKG_DEVS_NAND_SYNTH_OPTIONS { + display "Synthetic NAND driver build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building the synthetic NAND + target." + + cdl_option CYGPKG_DEVS_NAND_SYNTH_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "-Wall -Werror" } + description " + This option modifies the set of compiler flags for + building the synthetic NAND target. These flags + are used in addition to the set of global flags." + } + + cdl_option CYGPKG_DEVS_NAND_SYNTH_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the synthetic NAND target. These flags + are removed from the set of global flags if present." + } + + } + + cdl_option CYGNUM_NAND_SYNTH_PAGESIZE { + display "Page size" + flavor data + legal_values { 512 2048 } + # 256 generally not yet implemented; see nand_oob.c + default_value 2048 + requires ( CYGNUM_NAND_PAGEBUFFER >= CYGNUM_NAND_SYNTH_PAGESIZE ) + description " + Sets the page size of the synthetic NAND device. + This option also affects the size of the synthetic spare + (Out Of Band) area for each page: it is always 8 bytes OOB + per 256 bytes of data." + } + + cdl_option CYGNUM_NAND_SYNTH_SPARE_PER_PAGE { + display "Spare area per page" + flavor data + calculated (CYGNUM_NAND_SYNTH_PAGESIZE * 8 / 256) + description "This calculated option shows you the size of the Spare (OOB) area for each page, in bytes." + } + + + cdl_option CYGNUM_NAND_SYNTH_PAGES_PER_BLOCK { + display "Pages per eraseblock" + flavor data + legal_values { 32 64 128 256 } + default_value 32 + } + + cdl_option CYGNUM_NAND_SYNTH_BLOCK_COUNT { + display "Number of eraseblocks" + flavor data + legal_values { 256 512 1024 2048 4096 8192 } + default_value 1024 + } + + cdl_option CYGNUM_NAND_SYNTH_BLOCKSIZE { + display "Erase block size (kbytes)" + flavor data + calculated (CYGNUM_NAND_SYNTH_PAGESIZE * CYGNUM_NAND_SYNTH_PAGES_PER_BLOCK / 1024) + description "This calculated option shows you the total data size of an eraseblock, in kilobytes." + } + + cdl_option CYGNUM_NAND_SYNTH_CHIPSIZE { + display "Total chip size (kbytes)" + flavor data + calculated (CYGNUM_NAND_SYNTH_BLOCKSIZE * CYGNUM_NAND_SYNTH_BLOCK_COUNT) + description "This calculated option shows you the total data size of the whole synthetic device, in kilobytes." + } + + cdl_option CYGDAT_NAND_SYNTH_FILENAME { + display "Filename for synth nand" + flavor data + default_value { "\"synth_nand.dat\"" } + } + + cdl_option CYGSEM_NAND_SYNTH_RANDOMLY_LOSE { + display "Simulate random bit errors" + flavor bool + default_value 0 + description "This option causes the synthetic NAND device to suffer frequent random bit flips, in order to confirm that they are handled properly (in conjunction with the eccdamage test)." + } + + # Partition table support + + # Every NAND board driver has to decide how it will determine the + # NAND partition layout. In a simple case, there might be just + # a single partition covering the whole chip. Alternatively, + # the driver could read a partition table during _devinit, or + # the partition layout might be hard-wired (e.g. to inter-operate + # with some other fixed code). + # + # At the moment we expose only manual partition config. + # Further options may follow later. + + cdl_component CYGSEM_DEVS_NAND_SYNTH_PARTITION_MANUAL_CONFIG { + display "Manual partition configuration" + flavor bool + default_value 1 + description " + Set in order to use CDL to manually configure the + partitions of the synthetic NAND target." + + set ::partition_device "SYNTH" + script manual_partition.cdl + } + + cdl_option CYGPKG_DEVS_NAND_SYNTH_TESTS { + display "Synthetic NAND device tests" + flavor data + no_define + calculated { "tests/eccdamage tests/bbt tests/multipagebbt" } + description " + This option specifies the set of tests for the synthetic NAND device." + } + +} +
new file mode 100644 index 0000000000000000000000000000000000000000..4dcbe84803677d75960d7a4432a63ff7b5dbbda2 GIT binary patch literal 9478 zc$~F*XE<El*S8jg7%d3KFhWSQ=!~8rgy^C~5WPq5oy2H~-dl#~L>nY}CwlL_jNV)H zXX3u^=Xvh;`oGupetGA^th3i%`?t#3XYF;?b%K=?qzUk-@X*lE2wurZs-U4^K+(|9 zLvb-toFjzE4vKND^jb{{H7qSHEiNuDDk>@{D9Fpp%gM>f%F4>j%!I??>FMdIsj11y z$%%=H@$vDov9Zz7(UFmn;o;$*KYtDl4Gj(shQVN;K79%Z2=Mds^YQWV^78WV@Njc; zb8&HTa&mHTaImwpv$3(Uw6rugH#apkH8wUjG&I!L*Voh2)6vn<*4Eb2($dh-c=P6s zs;a88va+J0qP)EP&CQLRoZQvb)vH&pE-o&lrKNxW{w*aXb$WUVg+h;yk0m4|4i68- z#KiXZ_eDfRc6WD$goL)Yw*>_SH#ax=`T5t^*Lit)kw_#rH}}fQ3MVJ$($W$K2gky~ z0vj9K+}s=s3(L&R%+se&r>3Tun3yIeCKwqR$HvAUKYlziG6DvJhlYk|X=w)r254w# z`uh5)si}K<dMGI=ySln4C@4BRJITn%+S}VnNl9B<TZxH@o12>n2?-k;8wm&q>g((A z@$qYGYwzE`UtL{|gM;(q$B%pW?p0P+Vq#(<5D0X1^s=(Dl9H0|-@g|Y7Ut*Y=jP^S zXJ>!=_AMhL<LlS2X=!OGDJe-wNeKxFadB}mF)>k5Q4tXlU%q?^3kwSg2?+`c3JeVV z`0=B^zrU}queZ0ir>Cd8ySuBatFyDSqobp}y}hli?S~H^tgNgoEG*2-%uGy7jEsy7 z3=H1Cf3K^n`|jPlw{PESYHF&htE;K0si>$ZDJdx^DBRxOzJC4s`ubW{R`&ApQbtDR z{QUgo%a><oXOfbVCnqN_Uc5LuIuaKbKR7rL6&2mv+Y=TR-r3oKKp<ONTLJ<C8yg#Z ze0*zbYdkzWtE;PATwKe`%g>)bUtC;dXJ?<EpJ!!dot>S1_Uzg8^fWUw^W@~@lP6Ec z$Hy5M7)D1&>FMc*hllCt=mrM|K_F0ne?Jfi?CtHPqN3{V?tb*>(XU^>$jQk&IyxRc zeAw33MnXc;($YdiMAX#O1ONaU8X6uvcu-eYhlht(Q&WSBi~IBEPi$=Ls;Vk1EUb!( z3JeU4^78VUapzGqG&;0bk`ijJDLbk7o)1UsI^s3Z*cL)rIAVuF3>GU%h}lANV^t!g z$*f+y(0t*GMhtF^c$x8nMEjncC4Sz>v)o*z;&BkEAM=v6r!N`a+Y^SDx?pe#7700S z%=%j2ate1%w^4by>1pKZ*>xvsEa>p$(h1qK>vOyO6|Hme>o>9&=E~axQ-m*_n1`se zb7U?#UeXm^y~hQH2-q^yH^P}Q08$`<hr|m?57A-tguoD7TjmhlMCj<w$nA@Jz!3Uv z7qc=boMy)x3vdq?cxZgsm8Y8XB;TQQMF}_j9w4=2g#{7p%~n9W>s$msj&)1SJ9pk? zzyg$d^9R_!C7=Y`%G5lvs`xpG#4Uo7>7At8vl>fDoDjdgjYt)`Ujv0RJOt!X1jt(R zy{dg4)x#G7#sZ{5ysvbTO7+?s`<qdGPN^)`v(mUUUDJ^|bx}jk(bSdogYyZ`V9V~_ z?<`(rm3HyHSR}fnZ9ZvU)7#?M{(*2y=D-KrnmKu0D<cO&%27|@o4tXIU@iXs3I`^z zLoS!KeA`grk1lAPxrDP%S56X?pOJA#*SxUovl8TZxJz>96HPpy&6zP6F<$oLShBLx zx!YaHg@g+R=_~l^xDcKuP}nm+lzy0pR03vk6!WW3zGMcfuw!>zJ_TF{Zr<5YgR%ic z7~6mdPct7!APl<XskdidbpqcW_#O_O#gV16M5A9nO}7B7Do^b>8OB<FYzD6yDEUNK zc#Y{!*ln;_)w6#5UB3<QP1GVy@8an1nlae=EHBvyt%epY3%3><&w%YfUBhG3?plp5 zG{9^1?6PW`HWC+o<BM{{LJSwkK$Q^I`fM6^)NAq~A#B3V{K#34e1S;%Qf8IuxYTZv zTSIy3W-G8r%zH9{3K0CJk~qH~R)1(4L>mu5IgbwD?MIHzsYcUlH?EBkgI54fxml^@ z6qG2=v@i4zgUpy`yJ5!ALdA$0wVM_^F8|kdf(t&}n16-scW4@ZtZ2QHSwS1NM1*GF z2&M}Sa7Gu$9)-*3DM}QWJOE-u{b7>9o}>T}qut0}v1UHkc|lW2B@sDM5~Yfi)Lst1 zlCMIJjipHu)72#QLw1ada=c%phl_7JGe1atwHe56zZBs!vl)eh#`BBI02@WV11&(v z8Zblf_}b?)gJ)hl=kbk1roZ{|FtDFd;NkLfSlI{9cMfLu)8%4oa=d^SyPb*Mmb%EE zH|+AM&a^j|?bUDXjV+v;4L^>=_4_Ee&9~3RXpJf(1T(r89mh%ten4xxzJGjTxEGws zMJOg`l0yhK>J4Q$-z+<pd-eI~$MlA0JVWtoXT4_@o5r41RvTt+ExdueR<DYiwb9`) zp%JwVh@^vT)omO{9w4$moo_S0C0T*C-eogV?1YhGmiE^5l&0<J?2?C&bJUI{Ont=b z>9gG)PQC@e!81L`QW!bT$!8yz%8b?)hI$M3SG$T)WpZt9>+SlcBaAfa*?Vzp1g~^J zKCuBpt?`;<DX?a2ms|nk+NFV2?O&rd`;5Kt@Z0X(0zrh|cB)#5gto#wKU;ai%+7>X zqK6RJhg*T_3E*6PP)p3V5VCQNCs?ha8VtNu5r~lv(supTjhHRV+SoO)54Y`fc$J6o z2R`W7Q{B$Yl~^!ZForEL9flpT(m&OpfajtnNYO8lno%fPb>#Q~mEB|YlY^o4Zyejd ziy^8o!DLR*OP#E6U#@4u9nj4vfcB6}cihCB7D0V$ej~gD45ZqcnL6p4DHjy{GHmtB zRCr}$;OoI;Ic}nAOCMAf;K9GSGZ4kK+Ex`pC&rx?VdwTnmB3QHNEN>aXi#G;hqH<6 zrkDboASrHsiw>6-ki_P9-m%TqO#E&v*X1?YaBHeot32KU4>{k9<olAeRM-7VaaE_* zWi-1=@ihrq9nF-gOZZ_|!L~}Va!RfBH|szyFJx$cu)chJ8Mt)@T&Z2j(|Z2=JZ&># z?1}c$8%-9v<41s1!RooMX*cOtfo!7!Ad#!2gYyB3z8S|g(jM^P%=qK6?6HW+Rmy&3 z7^4slKTp`clgzw$qL#z6Ed}K^%h%WOj#bXde5cc())HhuSs22lx7gSUwU0V?mB&+O ze@z?772;Xm`v^MUgUB}2=~PoxRr@f`Vh25p0`y+rb94XZ$x-daJb%Yv6BAxr4v8zM z5D#(R;mnB#)MJMl?AM7z+ykI%ZQC>N{~#i={O!QpwAi_>H}x7$$kz7hfg7)g%gBQl zqHZ|{M_QX9l$$%Ay<gg60OaoY8N>|$Cm^IQA0~1+IpWe)$;&<eL~K&&0(Nafs^U5R zA!~JIv@Lwa+n^sL{%wCt2?*x6t(t#MDB>Cbb1RgSOWye1D%=BIRPE@~|LM^=eYACd z<8YkXBVws-_`cv9>aqY#efT|?xAF}|gFcAWwdE1v$rR8AgoF>MiF`X8oE{HraH0IU z=66O0>s%<{tC$pH<&nm2{-g&(()O{P!}zA(CE(!C5dqi=r^a3<;DB9xhSPc=HANp5 zb$sZG9l`m~vmAjL(`^wtBIhdz;)-H3XiD$Tk_CWu!P^PcYD)EN8P)S#F7j%Z$-?_> z`OvJViq`J7X;-E(bQuU95Phr9ANc{AkolQV9ttEU;#>M5gw+L)lB=P<Ac=i|bA7?U zcsRUf(vg|&1!6k_<v*wvE`+dmErr;SBb9~C7D|SOTo0qsp&H)+Z^oI|;MPA=mkEuo zA(AlcX31{AIl<BUCTi9mLw}*ij}4Q}6FL-jdQ_q9Gh+hE4aBM)P`QS##GlU`ad4Xb zv-<OPaF5V9r56B`50U5wUm9u3n0hc<LBHofoft4*R%gLuWw&xYtr^c|D>i>A18g4v z4P~l_E7W&KxIxA3+(k>F`IYEXCjroG@lCUxe&QrH+Y{oSCpb=@F-IubWU(YUyn)Yp ze_z)aVq6iqMO(%nLJr&XDQJAs<z;D9Kj<XXgh%{FbiH>UD`wru#JL|%f<72Z3wuUk znGT6YjK5T@m-#kB*Y`na2>bk_Z-n7ymAMd2I!V-&A8LJ<&dkke*M*<PBQi_?Ipt>d zMHo3FM#dvCK;70wljBKFhIw&hX@?l;IZw*13xDED@<!%#Z&!EAWLNhXJ)bg=%AQMG z-eh#y=4B>2PAJ0|S#QAwXi=G-&i#NNBulk!FOn(X7#Q(cr-Ii)lweK8-kU1?O+ZY1 z$7W1?@@?0XF4xY3qEo4MMt*8*Y#=Mw)=af__^R3=Gci%!?*@)gy#-zIA&dKNb+FEy zMYR^V*Rqg$t<>v2=mC$QUZS30ry1wM`^cwX^oS43zq6vE#mP21JwNvOTLswY_b`2W zpz5^<+{UwG18dc|)-Vi0WI$>ye7sc9b%8#on2F1(xpLap)n>gi%qlCnge#GIuso3J zbF-Qqy=%x|ZMYGpdP{!J!vpi=_L@mMcUW~AnHuUl+A|_ut>519@i{Oxb}Ex@b!=>+ zH(H(om-kt?I0_I-@p}WQP6I6ubd6)8Dv<*zp;EZG4xLQHI2%5}hli^$({9D1;EQvm z_JS@M(=jj5XO!nJ+HLG|ycClIpo8*g>8d%rmxiu{-sf%8y<`LyrlpEso%G|OMm+;a z*>>$MVl(RrB+-xeO=qX#<N{bm!B1evLZU~o)_3D9Gj-^G1{!mOLbhdo@spUMuW2sk zTh^Y4va5vn;u3$arS*G136B;MTTgPpQGAL)FInOyruhIT;1g{B5kN%v<6>PDZ#&=F z7dpFoTeCi{W*S+lMBa0;uH(d!LZ2@hH2LzWPTuU1(o~46rgTU|DW?He@)@+%)~sZo z2-E_H!JgM@l;M(8{&c|#K0*!!<aoEyBn{O3czT3+I2|L&b;;cZ56F`awqcJP|I$Br z^qc?9W4K!@F5ez3XmMbm1uFRfMh<Fzu9a9HZoNx-ym<8`qL(EBx=ibp9x=P~OI;-D zu$tBsA=m)B{c(GlIbt(25<^d?^0yW1i(vXdC_bV7??NMDh6|*q1g%0=EJ0lYba)gu z%B4CA>)LW+YepM8>4ej}k26jMOA;@*me&0NED!{u?@9rsTX_^eBxacUvvSI9o#Zqk zK}U2AE_$2W$G>IdPAZ3rnG`B!l7Fo*5D=z0)cy5XW&$}!%+Td(=03)76OnM~-obC| zC7Jdb{_Q0VVdRr>rnyCMbez|PgyI>Fa29S5Q4{idLD6zhe-SJk*wPK&i!J25i<!IL zX$&M&gu$dMSM}GX4O+EE=_Qx_wf3ChrjCm-a#sNS=SJ!)&JlXDd4LU3RKW2cLMlK1 z(|_zf5Ti`fxs$Tfc&p6qC|q+7-$3jwlQ$5upef&Jt>ZO@z4WJa3)l!<-P@tG%k0l1 z%owF*GL-bE)00WqUmFlyi&y|&@G#}pV{Hv&@KLM5jyrw@$q=pJ->0|%c2ytPje@Vi zeg9N!ps)H=$fjoAmuiA3ffkkR-un@x=|mB<?+UUNO~a%0Bk4LRNZ79+BWg>F1F*eR z_Z3AiH{U>WR30BE>aQ9v;XMt2rTi9Fc<B@*rVzM(C(m~UQA^>Pvo*t<6v}&#i9hh1 z;AmlyN*6FmeYr?uPp?F?^ba&jRMK74Qh>*o!DsBoiTuu-7T#K58UJaE(2C^ObQq%J zSIM3Iv^O-Ux+cFiv_s}f3pqe{CtTXSEo|hm4U_H+7N;dN{|8s}O6X6~!pP{u5H9op zc8o?a{G5>d`=SV_?9O6WV_Zs=i$j(y=)|&-FujB=2#=6WAZBe{)?|<7di+5PSVX*q zrzZer=_+Vsxs5|8ctEA9myu>)UDol-Rnor^zVEvS@nyBey*nvTBtwt~8}0r>7+ORN zx-V;F+#`fLkjKBJREAc#<X#&*Xs3qRzysU)Z|Q#%`c)+-p**jug$NdoMrYj}8&SgM z07lpoA&`^edNe~E0c<FsG|vr&KpN5D<tsKq#(<k?JOu>~nVNx6-?vWdc&n@9^XyqC zEwkTwlb{zfjcpG3HAfZbnS#e%wLK$OmV7J@{DnE+*E+J|)XI?Wq<($w!U!N6v>Yyv z=HMfbkKwoS3UF&#J9*~*nC@89CFqH;#=)E0ryVNl%zy*IlUp}Y+UNPud!y23*HA)} z@qusEj3Z8}Dnq-mSHf!QLj1;z#XX_wJ+j+rf}c6m)%9X0@|0a<ddi;(5Pk}#15%x< z)N50c7O^V>mmD@P+tx5&I_1jin4YMqjs>tQs!IlE9<QFvz~_~!KZu}^)K1rq+P+W* z$IN95tq2yY`$6^T6OIPnu=Hhr`=(ZxDbTt$au(W;6Xwjul9b?d^v?a<?CqhyDAwj# zb%(2r&cLFaNP}##=$Ur?k0sG8GvD3M38rrrloCpI2QqA?+p?G}x<?ImBM!X}&VBU_ zH>cRPHtGXww@Cw;VM$KR#fxGw5RRo#nu6GjrfuO?q+2Z1mRVS{j-z0s%;j+rvyVBg z$glzpVd>A0a(SB6sL;sEv1HF6{D%0uq?Mu66@m^h2rx}H-4Pe|%#=M7e>MbKkVbM; z8#0EAD?%<tYi~50<1KnTfb1y@R?Isyw%VoCFd@7P^7*P(qV^YNCSn-G9XVyzn+S>d zoq3)4A%PW`u>*R<f5p}YFQW}{)0MKs`j}>R{@qYwxhd!bvy+$&P<LU{T8+*S41i@D zd)1XB%ASl;oh)vU;QFuI;v!5Ii0<mwzsW;b2>r`%grErwZyQ1*Kd3nQiWOSf`_}|_ z*QlfE-z3-oX4O5pFs#(L<KKviBWaC8xr<Ag;r!x7od^(*Esh4VP>)>jW5VB_;0J~f zunHX~7>0;un!a?sAvbouCWt%Y&Hcz?8c@)$d-hrNv;2|S4Lp?Xl#D0b7-eql$qK8} z%l<Ii3_FOty;Dg_u>|8gLF#wYmL@YEMWyDtYsUhXBKK}eL_rV{v)ii2lf}<Z*M@0k zH=^^#{z1miQp}=C{+>8Fw#13)gXN^>jIgTd3>(;Dzi8ml>L33~@;!y%J6{aam^#_S zs>HkVtDApK)$OcjB;}%vf*11fKS-8|&LEOx=bLOBqK*eiEoD$9JprAc>!xC)iNxzV zw4y|k_1LktD^^Nls^htoIMT&O6UP#3qhs!PSNfCisU{dXzm@P4uEzsnknivj`@e<9 zYc9SS5zMXqG{3$P9jnH>B4SHdeQXNdVtfmH(HA%-=P2+og`g<$KisT{a`aCB`Dx6% zu^_cC>myZ6t$&OB56O~(VaN=Y)affKT?Rr+CFB72A~N*#zi|Ix%4vpAd}X|wc6Mzj ziec0%LD&d9q(-bLp*^KKy*=nz%49wF&+=+P$+aCQg+8Ui>+kz|U*li}U)>jlMR#U= zqsnu2MlL(<*%r;Ai4JJPMxUL&lp8GRPu;QS6_`>IIrk@9P_i0`g0f|s{it1R9n6%z zbrVsn7e5icf0Zuw-*e10x?b0HEMFM)zPjIF-SpGiGV?XAjr@nr_cxK~!=}Ukf8DJ{ z={EE4psw|Gy;!>gLkg*Q4M*~Q1Nzmi^~o+W!lVLpNp_vCPo4wuo{|G0Ndgr+k40I$ zfMuue-=pH8X=}!wg&(I>y;jrgPZ}c%)JX8z?;*W+F1>-Mq&cGfhFEBg%Btm|<AEX6 z2*<6|ksmY_b^62Q*z&$%QuOETD(Ik+EaTGIcwx}$7ot$PF6zqqrrO0Lcd|NS>tRuk zS$+jxzTV7p7(3vY5bJGg6x3siJp(b@66`TWE1017>TG+k4;p;Vw0_(ifS}`ujK?0! z*o;WqTx{B=N>Z!(Sp7j(cB(Ea9oA*BmR-0K>lT?N<o~bS+wNxO(HrJbjMB4}0;1Tb z#YF^V9Vq2=u&g(|Xp4a*0a{0MDcDEhl$+G{Cd6#H@LHY{@;5Ned{`OC(XH(81B-lJ zZJN+Awd{DXp576C?De^4sbOGQ!}P?_jtFw}Ss+vgu{IqlKi*?Sy}%hDUg8K!0`Z4} z+%mi_PtV<sC!(6OpC&=2N6suHNZArzN|}qBjdO{Nwyb8F|H5xC|JCNYUTYeCG(&7< z*XAWVh&D^j*`NOiPyy%Rn4aJ<g!;lBU^Gv;=GN1QO!yV&UVVr>bCa>_WF|o4%T`wv z*|zNL7S#{3&((st?&4NXl)imR)zb&HO4ATz0KUymg|%j<Hf&hJ<G(T%3aSxn$W5mf ze!a|AOjaPJ)smck3QcbX;Kv*cJm>|hQ)!0gLxo3Ms8=&{;quK{2+BK5O+g1ro%P+~ zRoKFx^c|GM-^^>#-ZZ!+%;z=WR#DMFvJc~ht^cZYRMgd9jMBoHCL>3_8Txte6X6i1 zwUD#YUN@=+8)|&3M$=`Q2ZBIG2D!(Pf3m&9AAH@3T|c{)`OV@r*!w&D>bX%SM$3KC ze)+Alv(n!#7`>#ZB*9@O{HW9$O)#Skt}!2`$?wZBxHy0)ET-U7&8vT#DJrakAwfg~ z@Ed!8Dj*xdbohT0dp<O+eGiYjF`X%9#63fc|DO972_*oqC2jB0j0B>dL4kSrFM#w| zoS`U7n@z>*30tp-KY7G27&;rRpy1kVniURxm4+{-<8)K)>w7n$p>%O2DZ2%$(XrH2 zxF>QeG52MAGd8AL_xF{hZvMW>^1&we6hwE<(&qF8|0Vwys|`~Vl&0rSxi@-Z8Gm=V zKc%Tk2ob)?F3QtPB9qn;D|&5|HHBUEbPep3%FI#V=6dr(kM_q|68R|s%m8!vAj0rc zEoo1kU7<h@rF0bj<>(nR&F{x-@fa+ld;`FX&(h~oUDdQI7x7JO+tjE;WwHiuJ?&_a z)<}_m^(xODwyLH?^Y*}3W$KK4hbg;OP0E3}zou65r|OoQ9R8il=dQVmZU*lliWb>O zHGvg3kP47fmH;N)y*P01<4@=?lB4*qYTyeB>xfoO{j5lHiG2j9k1~7)+;6W48$qCQ z9>pJDU4rTn0ip;&Zp$TA)*S!1+l4<Z<wTA`wP|0W6|LQkh$KG0+anB=p})UlcK*jw z@ek>oL^EpI+wuD|_D>-YClAZ>`_GaRLPlwMO+)3&i%M2RKcJ#Nfj!*3jc|M-e1O}U z{qz12G#I-$tH4TZcT?xcLgKVvbx0Jo+%rroVw4SWz{Ac}Ixb$<HD}w{(LQ-C%J-ot zH%fRw|IJq#FVv>}i)#-$?7HKwI`4a@x#Bm%CmN?*J0Hhmx^xOvVFIhsN|6zf-4X&T zsnh5H9bZj{&d$~MMi%>BJAaJW*TMPEXW9R8_~Bv{cLxVJqc_qc)`iHfW0?U`&ku0S zV#5Y$=xuSa@LhuB7l=y2b|aF+HicnP;Rz!R-zkz4ZL7~;awPN5TWOQN);<_VG;j?o z<Wkq}rEt>^^!genKsP6*Y}dmt9b7aJ3rbCWCet$`u0CID&MdMzD%kjTs(KKl7uY+C zO6vo_q2Y=9Fz?%5KW)W5^CqyEXA<c<y&urZh1vT84_`RKj*~rim7G%4V`{l3y`F*% zZMq6Kb6G{BlTP{%@}U)Z<(<ZT?@ltJJe{<vRkA8QZyW@dusH9!<PqN@wW4n`Ss^t$ zGSscz$L+g$5ZTH%<A>@b(#9a~xDkQyn$$j*Yrdj*rzx-Bd(>MNzhd(y?}rCJt4-HU zegBygR$Gw3DddF<w$xqWJxN2q%>^7-CH25lzZ|?(KK$I$XB7W;bNrQea+HjTPqu*L z^OM}S`2??{E~CF~4=u%fIH;p(momw5#!L9?-M<ZfTa)~HNvg1vJKDylJjcvfY5up1 zDe1ECN{)F^;qc$@g}<cEI>gevaEhCgPIs|r#Ww)wYMhVH^-1)2<HuJ-FmDEcOX+-@ zfE~NqVlu`x;-#B1t~2KsH_lHdr{uNWX2ZFs%(yS8ub+cE8dBo4UhkednO$YdveZno z0N8j>+o>O0c6bR(BFelMG>b;2!Nb{3FusVoXgof%?u|=LvO$C?Q&2p#{!P#NUH5(D zk4_~ZSJVYc=h7P3SU5)64#E!x!#5jbUZhnXLeAp+rowJsZoN^7nRE~Z$oH%3&TZri z@N`d5+k~k>;wX#4bbQQgaF(_r%!jL?m@<c^J9<o?gz{5DO-r6-nD;9Xalkwa5|ows z5%X^{p6pTX!!{!h-oQjbvZl-69i0?=&En2}sMn2hYH^=y?O^sATxUsG&2alOKi^7A z1-BS+5%Y>^J879kYW+fvIUx-DbHDm_ifT*#es&!Md|L9Y$8gV^GG2psv^;x^dx7wj z@-fsU_mUrnk8P%9PRf2SU*0A?;eUD+@fW8awS#RQ@zH5(pJBUOH1jbhkyX&z(hQOz zhsTRWE7p&#xns=Zxppp)#pa5zXUGQWDFF*tvN41U(+{Y}<}T-{f-|Ef)0@5f%ZVJK z{1%64=su`38?zVwo28&{M_~!D1DqLn{^GpFrP$!ic;%w1^RFg-ZP)f;n5jcpWWdd- zJf+h!t)G^M&N4QIr~8i%PsKF$)o-G970gud#F)EfJjQK?-6<V{gwIZbD)M-1@%C~w zm^2N$>c;X4g`{FRXr>a!JenU}S`!W`4x-#11uwH)Ei`N~U!OXA2$|%WQ=fSkTxvM; zI>FzELLGc0(m>`O;~3Ucb9FA41C`nA53TIX&KCt~H74dN#FHzX_MYbPvT0!GPB^h) zQm~`4<5CAaH|+Yk#4)!oJD7w4D*^Jbt(5jjkT>=Kqon^wG;Y{it!<dOn3p(%3@)bw zv%8^~CIZJsb&q5#r+yYX&)kNoF-3a6S*VHdUV_1r(!&n#^+8ar{21eyqF2pQB2H%! zLG*SA)*u87xD!z8@Xq~9pf26BhC(BHuRWClNo>RrG<V;Qx$z+>EJNTF8h*N9UB+H& zGdAITLKrcwp7ys0Lg3;1kV#i&i@(f>PKVV3pNS$Ae~M2&yr02ehrb4HNDzEjQA*1? z6;So7dS!>`yeY_sQs{6uYE_14j7JQ$J`p-dec6;D;+pIpuPF~gmNwdDO++fjvr7Ay zWS_&)R1F@VVoF9m3c5xkeu8ZvCjRlCCgp!DvHyRPCiQnxXlUp^{(K97VwJB=W4^!l zzyD8!83Lg{;{528XqEyt>ECsW6PYc8y{Y`6bhtb)Tp@xcFcH>;7v*0U)lf;XyNm53 z@HGz>Oq}RB3^%zE{GReg&?(Z^>;c-?0^nc|f>sjN??Qvti4Mae$GI1|`{5W3hBa2m zjHk@;7Hlhn2J^=P++R?NXau7J@kj(1e4!E;Ff3bUnS}^6z`grGl14b4AJqQ{SbbGc zPI=26I`m6J$=wdQSBt-hlDO|lv*}j5mG(*O+8}&$;IM~XH0uv47Ap5x{|-2;&Z(BM zTaOA1^|Wk3X(0J6p!UNxAM$gN9CBV6$kbOrfKn#2u&h*tZ9QZol$ugu*zZ<xhnyrv zc<t7_FFQZ=H{g!pGCZxzHP>Vb$&mgRv;NGu4slubF>ljL%lceil%(m8l9aRa0q*-h zkLGem#b}d~uS`B^fKiTs(M59r|5q0=1RgT{D;|E*Q@i3pjxL!vsM~k$Q%LZ`Al8ea R3=Q>rC8Z$w{l$C#{{q$25rzN&
new file mode 100644 index 0000000000000000000000000000000000000000..52020686eb16ffa5fc65cacc6ade771ecdff4d35 GIT binary patch literal 8291 zc$~d>bzD?!*Dfg`3@8W!Gr%C7QZjT5t)zf-j}9Qx4MQ_@cMl;UEeO&`gT&AwN|&@W z0v|rldw%ErzV|!lJ?H#!_8)ugz3;WIb*(%0TK65MuBt#xNKJ@=fkCXKD65Hqfd$3D zz>L7hzWeg4_Vw=FhcopTT5@-<)z#INm6he?<sUwLC@Co^Dk>^0EX>c(N1;$TIXPKb zSs57_X=!OGDJe-wNeKxFadB}mF)>k5Q4tXlVPRoNBr-TSI505K-{0TY*Vo6#$IHvh z!^6YP&CSKd#mULZ&d$!(*4D<x#>&d-&6_tc7|g=L!pzLf#KgqN$jHFJKu=Ha)vH(9 z+S)H)zSPjrP*YP=QBk?Mxq1Hl`S0Jqm6Vh&FE14o6wc4j<>cf}Pfwvx=<)Hfw6yfm z(UGL2<iWv#xVZS<-rmm6j<B$>kdV;k=BA*a;QIPHKR^HK>MAcU@AC384-e1c;vyFp z*Z1$=IXF1Jef!47#x^%M$HKxgGc&`)#56TE_2kKuiHQj?7(6yMMn^|CIywphfrf{N zX=rG^e*H>CMKv%mKuJm2*Vp&x(W9Q89x^hruCA^J4<3B^@`Z$iq`keJn3%Y=we|k} z`_0YG1Ox<)jg5GCcnu8=xVX5VK7GQ*#;&cc#l*y{si~=|s;a1{C@U)~EiElBE`I<1 zeL+D%US3{qZf<sVc4lT~dU|?lYHD(Fa$;g)e0+RtY;1INbYx^?czAedXlO`CNKjBv zKtO<>pC1B&@b>oh^z?LhcXxGlb#``kbab@0w}1EU-P^Zst*x!$aQN%juPrSt&CShC zO-+rBjSUSA_4W02b#--gbhNazG&MEV)zwv1Rc~)^U%Ys6eSNL0tbBEKrKqTQad9Cp zFMoD+CMzp@a&jUgBlGLmFDWUh!^1-f35osveK9ey-Q8Ug5s{xie?lOTt*xzR&z@~; zYzPPltgWr_@$s#!tUP`CbZKdco16Q`j~|?zoC^yJ?Ck9G^Yg5%th2MT%*@Qw)6<NM zjFXd-3=9n8<Ky)7^k_7imX>y8WCREV4h;=aQ&SHP4nBVTxWB)jf`X#Ax0jrpyt}*m z;lqcWot>nlq#Yd{005w^t&NC?sHLTakdUycsR<t+|MTb1_wL=Rudm0!!KtgO!@|P) z`0*ou1hp{+28cyTR$9wFb2rP^o4k9WHztHG09Tpm5zeD*3Tw;{xN{8Jv<ALfPc><* z5Ypzdp|K1hq-;!tIAxL%V<B2Lj~-PW=pO6IaU_pPOz59T%jIm7M$=((697r0$seF^ z4tHYGW*3_7$Yd?Nb-ZXcY4oZW<rnR3<!`DN`jJM8DHTat^3#u$0R||5W@CZ6QMrPu zbV}De(BdbcL-I{Udsh2Jb^3OcD-Mv57DA41Ukt)T2H*j3v4GYJ?O+z!n%|rt0B*nr z;L&mYe1^}=cwjdsGM?e~@bdI*z6Wq|AE;bF&zMm7`_L7FEUkYfXHC%09%{P)F*F&> zd2%VMy7j)QwIAwjuPBadAkHm7)e6xvFf`1pY~F?gf{Q9EO!Q~PzX^nLexO#J(RYEr zHCu|-_ensWFU2|%e%T(BY0V|qhmm$rB5T{McJ*DoWo(=U!9Ulv5~tkV@N<CMyhYiu z8c+6x8QW-uGOOyg)!k&K%BF=pLg@hL=T67{B(7HX=f0Fyic3=6h-lrS4@!F9m+Mjp zzli>^w*dBbgm;sB@LGNgCs~~o3L*QX11e><+;qBRCOI5O9WHshNE_&$)Sa<(;vrQ( z)xO9BOx6ylY*=J80(YrSk4Q0Vq3KXiAt+u=dQg29WkPBzEtz&Xca^Xd2#o<rB7#I} zmyc_$#sSUp+m0M<{PRsv_x)H;><7_AB_?ByVuq)zdajzSba^&`Q18E@_9l#`W3(=x z#I-f6BhJnt@~wm|3?6Mwt#kcs5e+&6u$fqLGr4VO4e81$P8(I1r<9?m8~?KP;IaT5 zx)$p%>>c(WTp-{Z{8xP}dO2L>IU=rsZb*3G#zdvWYh#0*BmB136cs^;>_0-=*oW1( z>1(8U`3?;agmckK?3~P^-VGJJnasMJGfzRDpLlOR351pfYa4s{@*Nl`Fu1H$hd2@0 zL>L*<5|5MwVzkZIKUq{iXh%u;L3i;X<YM-$q>JjJGA^u}5H-p^K@yS1aZyF27_LYS z6eAQ9>Bnl1ABy!q#UWr8iIWJMZ6Oxux`!hl0QFS#!?nj}j9-j>-$Ayr+I{(elRGfv zRg}H}M|^oNF5J$l&kyWmm`c%S9}jU}p5Q8YIv3Rgt2$t>TjK4)Wwq1m^UD_IesSMY zgaCk!_1m3YZPk=n;nQ_bVvhoIOL+`7ZkMK&e|aMHo{TSAS@}5D?-xQU+c%`DfoO`! zs0DLu1uL<h(^9H~@5P6F5--9XG;qvUeB3UAga=}L==5coFBPgXry>w>AMQ8>z&-b( zKLBmVqKwSJn5%e|gF^&SgNuN*6aMbMxL}L`>E7e=rHODL;ffd++M6;SCEYN4q>ent zy~oRcdGdRsia(A;6`2I3U2))~fZLt##FA9&=C&+-gi3Uo`=83w7!FE>VE;?s{kP&7 zV9N+(i|h5QIwGwzlb*lIsc&YQS6Bzoy~c?j%w7-VzbDyBHJ|^k?Sspa>ByUEOxp-- zq)a1Jr)WM5IvaeO{yPtR?(jVz9x->C=A&$UxS8+gr?{&gDqNtdFN;lqOwxXorP3Fl zl?)Cg0GzO_h8aSMc3zT&yepjVACWNG9#O!y4JwC%wZVI%=k^l!bq#s>C7YJl?N@*Q z{-`SKxOv|6gcu<Bdpki+Vdkp2_xb{!8&&1TTEHd?y2M?=j36Wy6d(9S@cA41T77fK zT>RYOV#`43`^8t3P4?l>PXA}%U}(C`1Q>?(gt`iHkYCf6=Jo2EB4<(H^S8*Orcd4) zB#7VZ6f!!#UGu14*H`Yj#8qu{d4yX4v|so3Oi@tc@%Do_lNeW5Ndfma5>3gwHs#^+ z7AWqyD^bZamu>e&QMSDjX#6agx@u-uo%b`(1c%rPCST=b8dPY+Cl*&Sn@rSUwJ)xo zN3%6W@br7cJ`9v8kWErT_SgzD;^GNS1xRBw!cwI_?I4dI*~dSxcd+s)A~A|Y;eOJF zywLK6x<YRcm~9wmqhW+Vg#NsR=-&?Oe-?Wd<WKsW=osXyUoJ_=^IqA1`R%6UC~<-9 zp^?W;i(YwjMTr!+oFAFTpA+5cX5B8%A_0j^wA97^7I>IMiL&r)Huu#uH2ikdy}ays z<v}Cu)$0*yzKio2M5UlOZqB988(%ntQp~5|a^yq4&(@crMcjyZph@W}XT~B-FNdR} ze?9KLcy!Xs0JB7t8As`8?I9CgL*=;Aozg1<?6TG5rz+woQ@VONzMzQcqaJs^XNvi~ z)T3ro4@ZZ81zSwyWsmQSj#tJti|(gTwms|Opa$llB62O_<s+9jdlkwJg$~B<!-Mc# z{>B7t3%^<Cbgc4T-?-)bPs)B=xV>I&5b@`3ifPa|m5+~8##cvM`3HcLFSFqchlk+} z$uJD7E>?tNjXy9_n_?Tl=EPcKMX}<Po=v!#NWyFhy?~pCz7l|Rt=r;&;+?Ze<Z@UT zUwM4(1Zr-m7mRbxtsBzl%k*`k{JTgi;r5|J^Y|i+p&B@Oi)VcFgg~skcJTkH2p!3X zYqOe@i;^w>V%4Vzzkz1qzv2xqd99!r_wgwLdvmmaH->>&UJILiODz1aRL3aKHn*ll zIXVA<q0Sk5a}yGyVc8LC?U(l~X1S)%%<=bW7pq)T<^Y43kIVJgz~0=wQM3bXeqX?Y zNesE*kaTVZuaNRQ@?A&v2wJCY0xCgG9zti!%wE<SQ(3`cXof=E#F`G`jjMTLo{_4{ zvmUmi2=GcRac=&Kn0y@W6LyyD;e6IMo9{Ieyvk_iqQ=EtQs4m2-}Y-=;~wOa2KtgN zJ0W*0GBURrfK-}o1unwC0irQ?3E990Nn~mp8fCM3dev+8cP>;^Z5`ZHCnL3S0I+-i zZ+-Yr!mSv9k@6IYVIQ?kiXroVWgE_q+~b6U$om=M$|jVun6Rj1o1wVZ<(jq)p|Lxi zuAYgo>flU(Gkd1603xZ;ag}uQEu%xIYH6G{>3pLD#A8Y8`6}72{_E77PKa4=vD`<7 z*=-pmavz2w=a;E(irAz>%y&t%w4VG`;KVaEcqh%_%heG5a!O^{8J!1rqpE|0MXd=2 zD+=GPkldRivO#W|o}K~YO=9>(Ebl<Y%#gFFy`VBZHC<OOramp1o-`5yr#k}G%h(<# z#QD&k3*i@JuBm?)EkSQyy`(0=;X^hw0OD&vd?O=fsa5%G5nRqlcUQqet8=GVUdA3) ziU|rzO5|1n^-_&Oe@(*sE3gj&@GA)9alNXtE#npno7TJ>iwy9q4tL^GXO3=6R4GNf zyn6eS$%Y6(wZ8FGZKj$}pI6FY6HvV)z|<#|*{$4mnK~+s^D*#L#TwZtn2@dQ)+pg; z>N<L(w5x99QMLs1#}0+z?b1bFVaobLrN|*T|0)t+*t2H+Nbx_j41%hXO<m|k4B!9n z22EK6P{?l`_%iX`G@H9?!zWcwLkKzN6rfPly0e-u1LEaT#AFSCOdKlpqE_>tmCeCd zVw=YwLK49<B8k=$A&<)PkI#9mECgjo<_%oXpy{l}b&A<&RD!GT2i=7d;u-s;4@Vgf ze$K)H0t!ZGHW(c5SyyLOO=;f8llteb)=wl@`+5am-BmFG-NUHF{AXf9`p;?KeGdM_ zK2N<dGITL}qeMASX~I!PC;8$J-obdOyr#P|0nL#A8a!KE1=0DeA~h|?$bp~k5bTJ! z(JN|z9zM!zN10YT_4OAMv!AtgL~b$_T~dSFlGeh%D=3a=y0Cz%%;qtUOdpu#3y%WZ z=q-0Weez|X#9s6HVkX?NqU0uELLec9C=wVomurv44Qa|y3B;#@s3Lsoy?M*VT&=O6 zWjcXoj~SO9REZ&vLdx+FS`@-gJamUk@}6+qiw1|kC^$?4(iCjzEzd@_bcvafm!xA& zTJv{7RPpE-xyVcx_J2YBojc9#yku7y^U;7hyLiaz+lhOgYS)$6LD7?@j+?tZ22N9@ zqO*R)G;YSvoo(F#fzSoOql7D&Z>WPvyuN0gi_s5zulAA4?6P5Qib`K^gnV^lZV&yG zA0jiO=A`yZ@S+kaxBn2hw_gryQCsN0_jdC^{C@i9XJW_>)bBXr>1ftPKwKG{Fqv_p z?d+-G$><&bF3|$U*S8sxWgEBNeh^<(TcMpVCUjME$~nIuyM1@qHf=m{(gYh026Tr( zOG1nq>~kh{wqqSOKJqk_m=6$k+=ag!+hj)hFk9+};b$A;xk5+@>0Ph>en;|O=4(Gb za_n&gjk_8%1SbF&fT^)aO8QTNuLJenYMIeaJ*V(V`~yIt(Cm~fo(BuFD1~CdM@T_Y z#q(|T8iDrg;Z=3kg0F@)`?1>8rfQx5VPFNAH*LtCWEm<2aaP=VLaV$K3%hHIm$-1t zicLw7iCEEmBbq_Ls}Zr<DGuQpzc(9*{2|W&;v{!tm|t!v84xV+5H!&8Q^7I77FA&7 zC$0pXYf6v37^mzJU5%C1jwd-=#H_)4zE4{sGQo9psD0&|xT^m?ZgX^4JO0?$OKk<w z$D{<L7Kw^2$`Ni!jYb_fyd@BRw!!I=t<zaW6cJ5Yb7Rw0s{%H24(?i_C7*}`uG*5w z<)af4qP)hSEwnz`E^uX%j4SYE7#Xm1FrnZVtpNtoFun`*=(CYhXI2f=nJ5@jPRPzn zCxd71DJQmDUzG~j!8tf+iPo|<4p{qXYjMv%MBFM*)Y%0tWjWk9L;;`@@neKcxM+UV zI!?e<8prU87Zz~uJaX&5+Y?TyL;I2gvb+S4M4f#0NTPZ2hxzH{AzrypgjoS=CarN@ zBsfdJ1yoMZjpvC$g6|t&udGe=wxXC8FqdNby_tlss9E%eZ$3n}SDoHR1{*)8K0CO^ z@eT;Tn%bztu>sGP5w9C{o7#;02T~ZSJKp&=%F1}K@g{%kj6|s+`7=`*)beM5{4Drc z$d{Y3DCBEqh_mv|>1lHz6oB+nmv@X6I!kjA1s`HdLwfBc$#)q<kNpdw{cR~ONj=$( z$}adn2EWBlpgfLncaF{PK$w1jechQlP;MhkEc%=vW#MnwOHYJlYY<aoP=w7)0&@)> zkDc+ycfSVXotLKeZ^bvTe!8;G{sPaU&g>FuUGYbdhOrai;PHs9$Al#PQKL5@Nr!;R zonar_+CnHB(u>}k5ve#e8VrNM42ZnOWKT`29QR;u+y+ARuo;+A1xzXX<sg8Kv)#!$ zrMANk<k~6jj)ma4Pmu#s7W@{-a`(45oCUjeiWh{DA>U?`6u!XT+2U-Qr;)k^$J{Lt z=J&{iW@(?~XvP24A_2!emZMjdhcF&QJ_sGx1CG61aU-hSdI3P0ASD~@S-Z*0lp%RF zsvPPX_<yO!OTd$cg2du&vY3LQcTF<-{^2skfEHiJ%ogb8#x|uAFujQzgd~izgG0<| z?y;8wS{k^5p+t~X!G3dcj+kPAo*Y;nZ{Jp%Ir2SkFq%bjrttOHmxq(~vTNmmQgU31 z8jrhCJdrndKhsdl>k^a4X0Ck@v*V1YdR1z9-4|xg-nztnxn^P3(^kO~{^0_5`m-pG zBgET%(#w<!1wQ0@PIKpKtizYh??K;81}q4Z(om1!kk}5C*8kA{aV=lt)`tN+N-b~z zQTmSGX~z$7ZwH|{-^VV{qN`*Bp={WX>geUnJfAN$53vFHyv-r2yh@<Pd~25q7jpAs z%sP-cZ}3-?z#Lc{s6n7f{=R-<!%|Q0=hj05<Uz|<p7`FBsMHJ_Q1IiH)2YDe^0hl{ zFm*D#nNImZao_t4io*Kimiq6WHU~j;bM;VniB+<Gkcei|9}AF}O4`%(Zt|nbO94&| zH&*RjhKzUm<hxWB+cs3$FR!2m*HcSxavAPsLh>j3zI`dVyYy?j6#K(JoPjr7Ds%X# zsRi?nFV#}4R3rl_3mFir<KOLM5W<$Apw}&v?7Dq&V)-{8*l+0P5*Y#4d_~sMdv^EB zf2Fd1lo;HCSf(n)rK~e#R}YsK;T_P~An*0m*v<d2_!hT%(O^sqvGn`X`T&3%R0zE? zFKZ%+fO`L_#b$uX#Y0sPYjm07CkMhVGBS1xo<61Ra8)YDs`AN#_giltf<&z9AFe4{ zJWkS+s>OyE_BVvR34&spZH*qub<f?WMM6GR*(;O_bH)u<71sho*hufYT_a4~(;iOD zh<Q<ubkysdasK44H2#zKBNYVM0akc-B_8Erq&+J=Cuo}{fpR_%edPhn^Io1VQ^S9* z^;%bJxY3NT3+7b!Av4~R>kgtK`w$oALI)Oq?jaDj9P5g4ADP+9{{`h&<y_pGCmtj~ zm-c=7F%oht?4-+(Wu_tg^Nz=4gRIQ5<3ahFHLLpZJFbB^dBHKN^3_!efN;!TA^1pY z9ahy?Z`wpc6V<8@xiZYE*#-r0mur$`B7ojDBMZ<(Z8{mxjCt_3`pW?5@CwzEx|FUj zk0{TS?|N&Y6D?m4c%W$JJb9=pb$Ubq*ZjJ|rF$+bh8Nj-Qp7~r_o1G~Zb)x1pPCrJ zR#?&y`p4<rfQ*K_sd4pzfX{ls>_syN$-`BOf1P&}NoBgN_0JSCO5EAIcbdYEsRRe& zdY)1PHJ`t<e=vfN#A1m3A)+b4>==xL3;+iLu`vG}8GS>EU>JS@VzmpFLNW0F^$_X5 ziiY;%1U=T>*%nNCms_3DWKGruv<GHtu`pu?c#&eA)Tjd-`z#%*Tpxpj3<nq#++KPd zcdy1IP+qPHJCz^lo9cxdp<S;yIZ&48&-=?bvR-3bK|z{(<t|9X<lS8GAw(v(B-DPD z%)YE1@61r9dddkyfBK^j+ayH(hPo(5AQl1Q&0e=Kx_zakSmN8Jb|a%yXtrqu4)Ex~ z5P0{wgcIwS(So*?!Ni<ed<C6>LoV{SE6i$bUWgSSm@=H$YFMNGxtQFjs{DoOShLgK z%6)fihc$n7C8c~VcNJJi(b0T->wJ;P*Hf!tBcH|4;}}JL4yN0=aA=Hj6cblD6O(TZ zm;SulR5bMVdI0@;>)TjqbCbtI9krKCaI*=p(?gDT99N$h%Ms~?6V~^3G=S#Px)Ufj z8KL5)@Ya(SwbEzL?IcbXF7xS>&r}Cf-g%k0ZkldAfK_^0XbKpzm(Beit8KNo7knJ? zRn(g7smJK^9PQsKuA7ywl!U5{YOB-;E8NZKdDfP}7B|ir1@+Kpav!dSJ+DVtd~be& zH7n_2^bAjOI0?As3<+GZ3x&y3y2A4=#!|6A>M85+n<BSKz2=IAYgvvdU0!L_G1eg- z8@mTHUcZvGvN3U4ndV{J&ubl3J@!_zzBpJ9Pbv7Y3~F5B{+tLhf+3T)6)b|4)Yh60 zZH)&mHKsp!4FU8h%7tsC=e)*ih_|n5d;|!1=5z`ASJk~Aa@;FVh~8Oa(;M;wktIO@ zr+xZPo8nV|{xj&>2_4VZ!9mf3M{Je)3+E?OT=^4}b752QFA_|$!<;sg**y;R>1I)B zmuOuxO~|pI@xaN?j8oTyWl#<09SV&m`pPILA=yq+y=GG<J&4k_EXdN4RU+)si9(y` zv3GX-B+(2nnq2Mu0!b433Vgz;Dqg^3xjVXe8#ckpL&P#y1M-ZiherLu|ADwJp|U&F zw6tdLQ5-9+o1@9dBL*0GLzCWal*y+DJ+dvuk^B;G8<IaC|I#OSCRMYXswz;zq5uwn z?SH@R_3+x%OJpv;Tp46}7r&PwUm(ARP`u<U%|vvDA*}WT$J&FgP&9Z^7iCBLuaUZD zE*S;>m5ODF+rEk>tSQqi^(E6nO?gp($&u@i6HF6*@uPV|Nv42ZVb3~*^HvK(orYi~ zE644H|39JvCKQVZtbfCP<4Vql{7wamFk-vyd_$M}W3V8?IPpfWrmAd}HhJ|^)>;hr z=svJ^T<ByjLGGxY`6E={YzWD$%+uBqkaRR(Gu1q@n&msMBXO<vNzUe~7&^AnRN-A( z8^>gJBA^{W!R$LNqIcnwz1kT&H<tb?@uwtR`_F!xdpoJ{$jVBmTZ7*9k;;Ql=2nk( zm(V;m*I}>ZTqwjG;HM;o$cn>eYt@L;(@h_fv$Eph02Y9_JA8`fB>UBn6*`;NN8id~ zTedyu)imFz$DbVl4RQ|lgXF%uI7o{?T-v*R4CVUmtP{&v4NqG}jg+p+u{iMLx~l9A zaFby9i4LIdM=M=zJs!u)4-d<WlJ`#+j`lR_z8~Y5C7IIU>Y6X9i|$>aPEJi>W9(>8 z>kH%bYLiAz*MwK%(i6%DF<6|{_QghL*Xo{LReV-SwVpNJYLd*?qAaKk<X|?vKGV4Z zX0k41BKiseZxPo`t5rTu5lr7dC*L}&BUlhKJjFqWumADmB02Hy3NiYfw(P|eAPwkQ zVwL0Ve^ks8s&niGN4~9gEM7Rh&ixzWHL{@6_@V+q@02vQM<5gN`VYXG`ql20wAUSt zI(BqoSw=4i<#ge{T$<>rMyfAx#o8YKb@K`{fD!u=;pf-y*Gflkde9_J`md$m{}<71 zjqt)4>-eX;v=#Dvm$U-bjvEf$dEW?_=3B%%L4*oI?~;X-i(=joDG-Z$v^53&8Xtg3 z2?r?Y^Wz}>?r;7Ams15m+i@qrVHJy{iZrL0jnSe45B!cz0o6Z5FcdQy?(U@60Ee+= zHvGoMT|7va(nz>Sjx`$79}0x5K7@4nL%IL=k4pBNnK7y<w`R;>+-m~irsb6NEc;Mw zB;*i4{C4Z(oA2kodm2E`syw%E#(xYmA;@rxn7%>rIFVTtPq$}xQOF%qSC|w0BF`Kq zXbxm+5OY<NvHpkdWzWRqsF0HM+Nn4}$r33Zz#+aK+Lk5;2If!$92QAghEYDp2zaiy z<V5O~wVC1HcIW%BjglXON8w5Pup!aj9wi(k#6C3Pz#9(x{zaH3qizHGF~Yc5XgBDO z?~c2TLOU1$bR+;Sw}b!9<KvKBSDDdCTgi4X{lG2uSA(yxsKtgHjJr!oPF1!-#x&qR E0NsUH7XSbN
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/doc/makefile @@ -0,0 +1,8 @@ +TOPLEVEL := ../../../../.. +MAIN_SGML := synth_nand.sgml +MAIN_HTML := devs-nand-synth-ref.html +MAIN_PDF := +OTHER_SGML := +PICTURES := + +include $(TOPLEVEL)/pkgconf/rules.doc
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/doc/synth_nand.sgml @@ -0,0 +1,679 @@ +<!-- DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V3.1//EN" --> + +<!-- =============================================================== --> +<!-- --> +<!-- synth_nand.sgml --> +<!-- --> +<!-- Synthetic target nand flash device --> +<!-- --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> +<!-- =============================================================== --> +<!-- Copyright (C) 2009 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 --> +<!-- Contact(s): bartv --> +<!-- Date: 2009/07/09 --> +<!-- Version: 0.01 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<part id="devs-nand-synth-ref"> + <title>Synthetic Target NAND Flash Device</title> + +<refentry id="devs-nand-synth"> + <refmeta> + <refentrytitle>Synthetic Target NAND Flash Device</refentrytitle> + </refmeta> + <refnamediv> + <refname>Synthetic Target NAND Flash Device</refname> + <refpurpose>Emulate NAND flash hardware in the synthetic target</refpurpose> + </refnamediv> + + <refsect1 id="devs-nand-synth-overview"><title>Overview</title> + <para> +The device driver <varname>CYGPKG_DEVS_NAND_SYNTH</varname> emulates +NAND flash hardware inside the eCos synthetic target. In addition it +provides a number of debug facilities which cannot readily be +implemented on real embedded hardware, including: + </para> + <orderedlist> + <listitem><para> +The emulated NAND contents are held on a file in the Linux host. This +makes it easy to archive and restore NAND images, allowing test runs +to be repeated with the exact same state each time. + </para></listitem> + <listitem><para> +The device driver can log details of all NAND I/O to a separate +logfile in the Linux host. This makes it easier to work out exactly +what is happening in the application, and more importantly it can help +with figuring out what went wrong when. For extended runs it is +possible to limit the disk space used for logging. It is also possible +to generate checkpoints, where the current NAND image is saved to a +separate file. + </para></listitem> + <listitem><para> +It is possible to inject bad blocks at run-time, to check how the +application would cope on real hardware if and when a NAND erase block +developed a fault. These can be made to affect random blocks or +specific blocks, for example ones holding filesystem metadata. + </para></listitem> + </orderedlist> + <para> +Some of the functionality is always available and uses compile-time +configuration via CDL. This allows applications to be run stand-alone. +The more advanced functionality such as logging and bad block +injection is only available when running in conjunction with the +synthetic target I/O auxiliary, when +<parameter>--io</parameter> is used on the command line. The settings +for logging and bad block injection usually come from the +<filename>default.tdf</filename> target definition file. These can be +changed on a per-run basis by adding +<parameter>--nanddebug</parameter> to the command line, which will +cause a suitable dialog box to pop up during NAND driver +initialization. + </para> + </refsect1> + + <refsect1 id="devs-nand-synth-config"><title>Compile-time Configuration</title> + <para> +This package <varname>CYGPKG_DEVS_NAND_SYNTH</varname> will +automatically be loaded when creating a new eCos configuration for the +Linux synthetic target. However the package will be inactive until +the generic NAND support is added to the configuration. + </para> + <para> +The synthetic target NAND driver has been designed to be functional +both when running stand-alone and when used with the I/O auxiliary. +Hence some of the basic parameters of the emulated NAND device must be +specified at compile-time, and this is handled via CDL configuration +options. + </para> + <para> +<varname>CYGDAT_NAND_SYNTH_FILENAME</varname> specifies the host-side +file that will be used to hold the NAND data. The default is +<filename>synth_nand.dat</filename> in the current directory. If the +file does not exist then the driver will create it during +initialization. All data in a newly-created image file will be set to +0xFF, corresponding to an erased device. Hence deleting the current +image file makes it possible to start a test run with a blank NAND +device. + </para> + <para> +A NAND device consists of some number of erase blocks: erase +operations affect all data in an erase block. Erase blocks are made up +of some number of pages, and write operations typically affect a page +at a time. Each page consists of a main data block plus some spare +bytes, also known as out of band or OOB data. There are four CDL +configuration options controlling the size and layout of the emulated +flash device: <varname>CYGNUM_NAND_SYNTH_BLOCK_COUNT</varname>, +<varname>CYGNUM_NAND_SYNTH_PAGES_PER_BLOCK</varname>, <varname>CYGNUM_NAND_SYNTH_PAGESIZE</varname>, +and <varname>CYGNUM_NAND_SYNTH_SPARE_PER_PAGE</varname>. The default +settings are 1024 erase blocks, 32 pages per block, 2K of data per +page, and 64 bytes of OOB data per page. This gives an emulated device +size of 64MB plus 2M OOB. + </para> + <para> +The size and layout parameters are encoded in each NAND image file. If +these configuration options are changed then existing image files will +be incompatible and the device driver will report a fatal error at +run-time. This avoids compatibility problems with higher-level code: +if a file system has formatted the NAND device for a 2K page size then +it is likely to get very confused if the page size suddenly changes to +512 bytes. + </para> + <para> +The NAND device can be partitioned manually by enabling the component +<varname>CYGSEM_DEVS_NAND_SYNTH_PARTITION_MANUAL_CONFIG</varname> and +manipulating the options below this. The default is for a single +partition occupying the entire NAND device. + </para> + <para> +Option <varname>CYGSEM_NAND_SYNTH_RANDOMLY_LOSE</varname> activates +code in the driver which triggers frequent bit errors during read +operations. These should be handled by error correcting codes within +the generic NAND layer so should be transparent to higher-level code. +The option exists mainly as an easy way of testing the automatic error +correction support. + </para> + </refsect1> + + <refsect1 id="devs-nand-synth-customization"><title>Run-time Customization</title> + <para> +Logging and bad block injection are controlled by run-time +customization via the synthetic target I/O auxiliary, not by +compile-time CDL options. This allows the same test executable to be +run with and without logging or with different sequences of injected +bad blocks. If the executable is run without the I/O auxiliary, +without the <parameter>--io</parameter> command line option, +then both logging and bad block injection will be disabled. + </para> + <para> +The main way of customizing both logging and bad block injection is +via the target definition file, +usually <filename>default.tdf</filename>. The driver comes with a +file <filename>nand.tdf</filename> holding the various options and +explanatory text. This file should be incorporated +into <filename>default.tdf</filename> and edited as appropriate. +Note that all NAND-related settings should be inside +a <literal>synth_device nand</literal> section. + </para> + + <refsect2 id="devs-nand-synth-customization-logging"><title>Logging</title> + <para> +The target definition file settings related to logging are as follows: + </para> + <programlisting width=72> + logfile "/tmp/synthnand.log" + log read write erase error + max_logfile_size 16M + number_of_logfiles 4 + generate_checkpoint_images + </programlisting> + <para> +The <varname>logfile</varname> setting controls the location of the +logfile. The default is to add a suffix <filename>.log</filename> to +the <varname>CYGDAT_NAND_SYNTH_FILENAME</varname> setting, thus +creating logfiles in the same directory as the NAND image file. + </para> + <para> +The <varname>log</varname> setting specifies which events should be +logged. It is followed by a list of some or all of the following: +<literal>read</literal>, <literal>READ</literal>, <literal>write</literal>, <literal>WRITE</literal>, +<literal>erase</literal>, +and <literal>error</literal>. <literal>read</literal> logs all calls +to the driver's page read function, but not the data actually read. +<literal>READ</literal> is like <literal>read</literal> but logs the +actual data as well as the event. Similarly <literal>write</literal> +and <literal>WRITE</literal> log calls to the driver's page write +function, without or with the data being +written. <literal>erase</literal> logs calls to the driver's block +erase function. <literal>error</literal> logs any bad block injection +events. + </para> + <para> +Logging can quickly generate very large files, especially +when <literal>READ</literal> or <literal>WRITE</literal> debugging is +enabled. This can have unfortunate side effects, for example an +overnight stress test can fail because the logfile has filled all +available disk space. To avoid this it is possible to limit the size +of each logfile using the <varname>max_logfile_size</varname> setting. +This is simply a number followed by a unit K, M or G. + </para> + <para> +When <varname>max_logfile_size</varname> is exceeded the NAND driver +takes appropriate action. The default behaviour is just to delete the +current logfile and create a new one, with the same name as before. +This can be unfortunate if some particularly interesting event +happened just before the maximum logfile size was exceeded because all +logging information related to that event will have been lost. To +avoid this it is possible to have multiple logfiles, limited by the +<varname>number_of_logfiles</varname> setting. Assume a logfile name +of <filename>/tmp/synthnand.log</filename>, a maximum logfile size of +16M and four logfiles. After the first 16MB of logging data has been +written to <filename>/tmp/synthnand.log</filename> that file will be +renamed to <filename>/tmp/synthnand.log.0</filename> and a new current +logfile <filename>/tmp/synthnand.log</filename> will be created. +After another 16MB the current logfile will be renamed to +<filename>/tmp/synthnand.log.1</filename>, and so on. After 64MB +the maximum allowed number of logfiles has been created, so +<filename>/tmp/synthnand.log.0</filename> will be deleted and then +<filename>/tmp/synthnand.log</filename> will be renamed to +<filename>/tmp/synthnand.log.3</filename>. Hence the maximum disk +space used will be between 48MB and 64MB, plus a small amount of +overflow for each logfile. All logfiles are +in <link linkend="devs-nand-synth-file-formats">plain +text</link>, one event per line, and a single event will not be spread +over multiple logfiles. + </para> + <para> +In addition to the logfiles the NAND driver will generate image +checkpoint files if <varname>generate_checkpoint_images</varname> is +enabled. At the start of the test run the driver will copy the current +NAND image to a new +file <filename>/tmp/synthnand.log.checkpoint</filename>, using the +same base filename as for logfiles. If support for multiple logfiles +is enabled then the current checkpoint file will be renamed in the +same way and at the same time as the current logfile, and a new +checkpoint file will be created using the current image data. Hence +for any logfile it is possible to examine both the starting image and +the final image (which may be the current one). + </para> + </refsect2> + + <refsect2 id="devs-nand-synth-customization-inject"><title>Bad Block Injection</title> + <para> +There are two settings related to bad block +injection: <varname>factory_bad</varname> +and <varname>inject</varname>. The former is straightforward: + </para> + <programlisting width=72> + factory_bad 17 42 256 1019 + </programlisting> + <para> +This setting is used only when the NAND image file does not yet exist +and the driver has to create a new one. The specified erase blocks are +marked as factory-bad and hence unusable. The setting consists simply +of one or more numbers, each in the range 0 +to <varname>CYGNUM_NAND_SYNTH_BLOCK_COUNT-1</varname>. A maximum of 32 +blocks can be marked factory bad. + </para> + <para> +Bad block injection is rather more complicated, in an attempt to make +it sufficiently flexible for a variety of uses. The target definition +file can contain one or more <varname>inject</varname> settings. There +is a limit of eight erase definitions and eight write definitions, +giving a maximum of sixteen bad block injection definitions. However +some of these can use <literal>repeat</literal>, so the number of bad blocks injected +during a test run is limited only by the size of the emulated device. +Example settings are: + </para> + <programlisting width=72> + inject erase current after rand% 1024 erases + inject write current after rand% 100000 calls repeat + inject erase block 1 after 3 block_erases + inject write page 9860 after 1000 writes + </programlisting> + <para> +The <literal>inject</literal> keyword should be followed by +either <literal>erase</literal> or <literal>write</literal>. +If <literal>erase</literal> then the bad block injection happens +during a call to the driver's erase function, otherwise it happens +during a call to write. This is followed by a block or page +definition, the keyword <literal>after</literal>, an event counter, +and a couple of optional flags. + </para> + <para> +The simplest block or page definition is the +keyword <literal>current</literal>. This simply means that whichever +block is being erased, or whichever block contains the page being +written, will be marked bad. Typically this will be used for injecting +random faults. If a given block is the subject of an above-average +number of erase or write operations then it is more likely to be the +current block in one of these definitions, so heavily-used blocks are +more likely to fail. + </para> + <para> +The alternative to <literal>current</literal> is to list a specific +block for an erase definition, or a specific page for a write +definition. Blocks go from 0 +to <varname>CYGNUM_NAND_SYNTH_BLOCK_COUNT</varname> - 1. Pages go from +0 to (<varname>CYGNUM_NAND_SYNTH_BLOCK_COUNT</varname> * +<varname>CYGNUM_NAND_SYNTH_PAGES_PER_BLOCK</varname>) - 1. This can be +particularly useful when testing higher-level code that uses certain +blocks specially, for example for storing filesystem metadata. It can +also be useful when attempting to repeat a test run using information +from a logfile. + </para> + <para> +The fields immediately following the <literal>after</literal> keyword +specify when the bad block injection should trigger. They consist of +the optional keyword <literal>rand%</literal>, a count, and an event +identifier. If <literal>rand%</literal> is not specified then exactly +the specified number of events must occur before the bad block +injection triggers. Otherwise some number between 0 and count-1 events +must occur. The event identifier can be one +of <literal>erases</literal>, <literal>writes</literal>, <literal>calls</literal>, <literal>block_erases</literal>, +or <literal>page_writes</literal>. <literal>erases</literal> means the +number of calls to the driver's block erase +function. <literal>writes</literal> means the number of calls to the +page write function. <literal>calls</literal> means the total number +of read, write or erase calls. <literal>block_erases</literal> means +erase calls for a specific block. +Similarly <literal>page_writes</literal> means write calls for a +specific page. <literal>block_erases</literal> +and <literal>page_writes</literal> cannot be used together with +<literal>current</literal>, only with a specific block or page. + </para> + <para> +So, consider the first example again: + </para> + <programlisting width=72> + inject erase current after rand% 1024 erases + </programlisting> + <para> +The driver will calculate a random number between 0 and 1023, say 427. +Once there have been at least 427 erase calls the bad block injection +will trigger. Since the definition is for erase current, the injection +can happen immediately. Hence whichever block is specified during +the 427th erase call will be marked bad and that erase call will fail +with error code <literal>EIO</literal>. + </para> + <para> +Suppose that the definition used <literal>write current</literal> +instead of <literal>erase current</literal>. The definition will still +trigger during erase call 427, but it will not take effect +immediately. Instead whichever page is the subject of the next write +operation will be marked bad. Alternatively, suppose that the +definition was for <literal>erase block 42</literal> but call 427 was +for block 512 instead. If some time after call 427 there was another +erase call for block 42, that later erase call will fail and cause the block to +be marked bad. + </para> + <para> +Now consider the next definition: + </para> + <programlisting width=72> + inject write current after rand% 100000 calls repeat + </programlisting> + <para> +This event will trigger after between 0 and 99999 calls into the +driver. These calls can be reads, writes, or erases. If the triggering +call is a write then the block affected will be the one containing +the page being written. Otherwise whichever page is the subject of the +next write operation will be the one affected. + </para> + <programlisting width=72> + inject erase block 1 after 3 block_erases + </programlisting> + <para> +This definition will only ever affect block 1. The first two calls to +erase block 1 will succeed. The third call will fail. Erase calls for +any other block have no effect on this definition. + </para> + <programlisting width=72> + inject write page 9860 after 1000 writes + </programlisting> + <para> +This definition will only ever affect page 9860. The definition will +trigger after 1000 writes to any page. If the thousandth write happens +to be for page 9860, it will fail. Otherwise the next write for page +9860 will fail, whenever that happens. If the definition specified +event type <literal>page_writes</literal> instead +of <literal>writes</literal> it would trigger only after 1000 writes +to page 9860 instead of 1000 writes to any page. + </para> + <para> +Trigger definitions can be followed by two optional keywords. The +first is <literal>repeat</literal> and indicates that the definition +should trigger multiple times, not just +once. <literal>repeat</literal> can only be used for block or +page <literal>current</literal>, not for a specific block or page, +since any given block can only fail once. The second keyword is +<literal>disabled</literal>. This can be used to create a bad block +injection definition which is not active by default but which can be +enabled in the GUI interface. + </para> + <para> +All bad block injection definitions operate in parallel, not +sequentially. It is possible for multiple definitions to trigger +during a single call but a given block can only fail once. + </para> + </refsect2> + + <refsect2 id="devs-nand-synth-customization-dialog"><title>Interactive Dialog</title> + <para> +Although it is possible to change the logging and other settings +between test runs by editing the target definition file, the package +also provides a way of changing these during driver initialization +time. If the command line option <parameter>--nanddebug</parameter> is +used in addition to <parameter>--io</parameter> then the I/O auxiliary +will pop up a dialog box allowing the various settings to be edited. + </para> + <informalfigure PgWide=1> + <mediaobject> + <imageobject> + <imagedata fileref="dialog1.png" Scalefit=1 Align="Center"> + </imageobject> + </mediaobject> + </informalfigure> + <para> +The dialog consists of a tabbed notebook with separate tabs for Files, +Logging, and Errors. The default tab is Files. This shows the NAND +device settings as configured via CDL options. If a current NAND image +file exists then it can be deleted with a single click, allowing the +test run to proceed with a new blank NAND device. The current image +file can be saved away to an archive, either using a default name +based on the current image name or by letting the user select a file. +It is also possible to restore a previously-saved archive, again using +the default name if that archive exists, or by selecting an +alternative file. If any of the relevant files are changed outside +this dialog then the refresh button forces the dialog to check the +filesystem again. The various operations will be reported at the +bottom of the dialog. + </para> + <para> +If the Logging tab is selected then the dialog changes to the following: + </para> + <informalfigure PgWide=1> + <mediaobject> + <imageobject> + <imagedata fileref="dialog2.png" Scalefit=1 Align="Center"> + </imageobject> + </mediaobject> + </informalfigure> + <para> +There are separate checkbuttons for the six types of events that can +be logged. It is also possible to change the current logfile and to +edit the other settings related to logfiles. + </para> + <para> +The Errors tab is not yet implemented. + </para> + <para> +The dialog can be dismissed using the OK button or by hitting the ESC +key. At that point the eCos application will resume running with the +selected settings. + </para> + </refsect2> + </refsect1> + + <refsect1 id="devs-nand-synth-file-formats"><title>File Formats</title> + <para> +A NAND image is a binary file with six sections: a 64-byte header +block; an array of erase counts; an array of write counts; an array of +the factory-bad blocks; a bitmap of the good and bad blocks; and the +actual data. The header consists of the following data structure: + </para> + <programlisting width=72> +struct header { + cyg_uint32 magic; // 0xEC05A11F + cyg_uint32 page_size; // CYGNUM_DEVS_NAND_SYNTH_PAGESIZE + cyg_uint32 spare_size; // CYGNUM_DEVS_NAND_SYNTH_SPARE_PER_PAGE + cyg_uint32 pages_per_block; // CYGNUM_DEVS_NAND_SYNTH_PAGES_PER_BLOCK + cyg_uint32 number_of_blocks;// CYGNUM_DEVS_NAND_SYNTH_BLOCK_COUNT + cyg_uint32 tv_sec; + cyg_uint32 tv_usec; + cyg_uint32 spare[9]; +}; + </programlisting> + <para> +All integers in the header and in the following three sections are +stored in bigendian format. The <structfield>magic</structfield> field +is used to check that a file really holds a NAND image. The next four +fields specify the emulated device size and layout, as per the +corresponding CDL options. The <structfield>tv_sec</structfield> and +<structfield>tv_usec</structfield> fields are filled in with the +result of a <function>gettimeofday()</function> system call during +driver initialization. These fields also appear in logfiles, so code +can check that a logfile and an image file correspond to the same test +run. + </para> + <para> +Following the header is an array of BLOCK_COUNT integers holding the +number of erase calls for each block. Next is an array of (BLOCK_COUNT +* PAGES_PER_BLOCK) integers holding the number of write calls for +each page. These arrays can be used to check that higher-level code is +performing wear levelling. + </para> + <para> +The array of factory-bad blocks consists of 32 integers holding the +settings of the target definition's file +<varname>factory_bad</varname> setting at the time that the image file +was created. + </para> + <para> +The bitmap following the factory-bad block array holds the current +state of each erase block. Bit 0 of byte 0 corresponds to erase block +0, bit 0 of byte 1 corresponds to erase block 8, and so on. If a bit +is set then the erase block is ok. If a bit is clear then the erase +block is bad, either factory-bad or because it has failed subsequently +due to a bad block injection. + </para> + <para> +The bad block bitmap is followed by the actual data. This consists of +all erase blocks concatenated without padding, starting with erase +block 0. Each erase block is stored starting from page 0 within that +block, and again all the pages are concatenated without padding. For +each page the actual data is stored first, followed by the spare (OOB) +data. + </para> + <para> +A logfile is a plain text file, not a binary file. It holds one log +event per line. Some of these lines can be rather long if READ or +WRITE logging is enabled. The fields within each line are separated by +a single space. The first field indicates the type of record. The next +two fields are call counts, one for the event in question and one for +the total number of calls into the driver. The remaining fields depend +on the record type. + </para> + <programlisting width=72> +I 0 0 1247514233 562000 synth_nand.dat 2048 64 32 1024 + </programlisting> + <para> +This is an initialization record when the logfile is created. There +have been no calls to the driver yet so the two counts are 0. The next +two fields are the <structfield>tv_sec</structfield> +and <structfield>tv_usec</structfield> timestamp values which are also +written into the NAND image file. This allows logfiles and image files +to be matched up. The remaining fields identify the page size, the +spare size, the number of pages per erase block, and the number of +erase blocks. + </para> + <programlisting width=72> +F 2 4 43 0 + </programlisting> + <para> +This is a call into the driver's <function>factorybad</function> +function. It is the second such call, and the fourth call into the +driver. The query is for erase block 42, and that block has not been +marked as factory-bad. + </para> + <programlisting width=72> + r 5 12 32736 0x0200f0c0 2048 0x0200eeb0 64 + </programlisting> + <para> +This is a <literal>read</literal> event. It is the fifth page read +into the driver and the 12th call. The request is for page number +32736. 2048 bytes of data should be read into a buffer at location +0x0200f0c0, and 64 bytes of OOB data should be read into 0x0200eeb0. + </para> + <programlisting width=72> +Rd 5 12 32736 0x0200f0c0 2048 FFFFFFFFFFFF… +Ro 5 12 32736 0x0200eeb0 64 FFFFFFFFFFFF… + </programlisting> + <para> +These are two <literal>READ</literal> log events corresponding to the +previous <literal>read</literal>. The first line <literal>Rd</literal> +is for the data part, and the final field consists of 4096 bytes of +hexadecimal data. The second line <literal>Ro</literal> is for the OOB +part and the final field consists of 128 bytes of hexadecimal data. + </para> + <programlisting width=72> +w 1 1030 32736 0x0200f0c0 2048 0x0200eed0 64 +Wd 1 1030 32736 0x0200f0c0 2048 FFFFFFFFF3FFFFFFFFFFCF… +Wo 1 1030 32736 0x0200eed0 64 FFFFFFFFFFFFFFFF426274… + </programlisting> + <para> +These lines show a <literal>write</literal> log event and +a <literal>WRITE</literal> log event for the same call into the +driver. The fields are the same as for <literal>read</literal> +and <literal>READ</literal>. + </para> + <programlisting width=72> +E 2 1031 1022 + </programlisting> + <para> +This logs an erase call into the library for block 1022. It is the +second erase call, and by this time there have been 1031 calls into +the driver. + </para> + <programlisting width=72> +Bb 1 2857 631 +… +Bp 2 4012 3189 99 + </programlisting> + <para> +These lines show bad block injections. The first is for an erase +operation for block 631. That erase call is about to fail with EIO and +the block will be marked bad. The second is for a write operation for +page 3189, which is part of erase block 99. That write operation is +about to fail and all of erase block 99 will be marked bad. + </para> + </refsect1> + + <refsect1 id="devs-nand-synth-install"><title>Installation</title> + <para> +Before a synthetic target eCos application can use a NAND device it is +necessary to build and install host-side support. The relevant code +resides in the <filename class="directory">host</filename> +subdirectory of the synthetic target NAND package and building it +involves the +standard <command>configure</command>, <command>make</command> +and <command>make install</command> steps. The implementation of the +NAND support does not require any executables, just a Tcl +script <filename>nand.tcl</filename> and some support files, so +the <command>make</command> step is a no-op. + </para> + <para> +There are two main ways of building the host-side software. It is +possible to build both the generic host-side software and all +package-specific host-side software, including the NAND support, +in a single build tree. This involves using the +<command>configure</command> script at the toplevel of the eCos +repository. For more information on this, see the +<filename>README.host</filename> file at the top of the repository. +Note that if you have an existing build tree which does not include +the synthetic target NAND support then it will be necessary to +rerun the toplevel configure script: the search for appropriate +packages happens at configure time. + </para> + <para> +The alternative is to build just the host-side for this package. +This requires a separate build directory, building directly in the +source tree is disallowed. The <command>configure</command> options +are much the same as for a build from the toplevel, and the +<filename>README.host</filename> file can be consulted for more +details. It is essential that the NAND support be configured with +the same <option>--prefix</option> option as other eCos host-side +software, especially the I/O auxiliary provided by the +synthetic target architectural HAL package, otherwise the I/O auxiliary will be +unable to locate the NAND support. + </para> + </refsect1> + + <refsect1 id="devs-nand-synth-tests"><title>Test programs</title> +<glosslist> +<glossentry><glossterm>bbt</glossterm><glossdef><para>Bad Block Table +unit test. Finds a readable block, then fiddles with its status in the +BBT confirming expected behaviour. Requires the synthetic NAND device. +</para></glossdef></glossentry> +<glossentry><glossterm>multipagebbt</glossterm><glossdef><para>As for +<emphasis>bbt</emphasis> but insists that the device parameters mean that +the BBT spans multiple pages on-chip. (This is perhaps a contrived case, +but might crop up in future with larger devices, so needed to be tested.) +</para></glossdef></glossentry> +<glossentry><glossterm>eccdamage</glossterm><glossdef><para>An ECC +error fuzzing exercise. Requires +<option>CYGSEM_NAND_SYNTH_RANDOMLY_LOSE</option>, which induces +pseudo-random bit errors; after 1,000 runs, the number of errors corrected +is reported.</para></glossdef></glossentry> +</glosslist> + <para> +</para> +</refsect1> + +</refentry> +</part>
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/Makefile.am @@ -0,0 +1,57 @@ +## Process this file with automake to produce Makefile.in +## ===================================================================== +## +## Makefile.am +## +## Build support for the host-side synthetic target support, +## the nand driver package +## +## ===================================================================== +# ####ECOSHOSTGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of the eCos host tools. +# Copyright (C) 2009 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. +# ------------------------------------------- +# ####ECOSHOSTGPLCOPYRIGHTEND#### +## ===================================================================== +#######DESCRIPTIONBEGIN#### +## +## Author(s): bartv +## Contact(s): bartv +## Date: 2009/07/01 +## Version: 0.01 +## +######DESCRIPTIONEND#### +## ===================================================================== + +AUTOMAKE_OPTIONS = 1.10 foreign + +## Only some platforms are supported. Having the configure script throw +## an error when attempting to configure on an unsupported platform +## would be a mistake, since that would prevent any configury from +## the toplevel on unsupported platforms. Instead an automake conditional +## is used, leading to null makefiles on unsupported platforms. + +if SUPPORTED + +## The only thing that needs to be installed is a Tcl script and some +## data files. +nanddir = $(libexecdir)/ecos/@PACKAGE_INSTALL@ +nand_DATA = nand.tcl \ + nand.tdf +endif
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/Makefile.in @@ -0,0 +1,543 @@ +# Makefile.in generated by automake 1.11 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# ####ECOSHOSTGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of the eCos host tools. +# Copyright (C) 2009 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. +# ------------------------------------------- +# ####ECOSHOSTGPLCOPYRIGHTEND#### +#######DESCRIPTIONBEGIN#### +######DESCRIPTIONEND#### + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = $(am__configure_deps) \ + $(srcdir)/../../../../../../acsupport/config.guess \ + $(srcdir)/../../../../../../acsupport/config.sub \ + $(srcdir)/../../../../../../acsupport/install-sh \ + $(srcdir)/../../../../../../acsupport/missing \ + $(srcdir)/../../../../../../acsupport/mkinstalldirs \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/configure ../../../../../../acsupport/ChangeLog \ + ../../../../../../acsupport/config.guess \ + ../../../../../../acsupport/config.sub \ + ../../../../../../acsupport/depcomp \ + ../../../../../../acsupport/install-sh \ + ../../../../../../acsupport/ltconfig \ + ../../../../../../acsupport/ltmain.sh \ + ../../../../../../acsupport/missing \ + ../../../../../../acsupport/mkinstalldirs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/../../../../../../acsupport/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) \ + $(top_srcdir)/../../../../../../acsupport/mkinstalldirs +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(nanddir)" +DATA = $(nand_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +ECOS_REPOSITORY = @ECOS_REPOSITORY@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_DIR = @PACKAGE_DIR@ +PACKAGE_INSTALL = @PACKAGE_INSTALL@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = 1.10 foreign +@SUPPORTED_TRUE@nanddir = $(libexecdir)/ecos/@PACKAGE_INSTALL@ +@SUPPORTED_TRUE@nand_DATA = nand.tcl \ +@SUPPORTED_TRUE@ nand.tdf + +all: all-am + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): +install-nandDATA: $(nand_DATA) + @$(NORMAL_INSTALL) + test -z "$(nanddir)" || $(MKDIR_P) "$(DESTDIR)$(nanddir)" + @list='$(nand_DATA)'; test -n "$(nanddir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nanddir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(nanddir)" || exit $$?; \ + done + +uninstall-nandDATA: + @$(NORMAL_UNINSTALL) + @list='$(nand_DATA)'; test -n "$(nanddir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(nanddir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(nanddir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(nanddir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-nandDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-nandDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am am--refresh check check-am clean clean-generic dist \ + dist-all dist-bzip2 dist-gzip dist-lzma dist-shar dist-tarZ \ + dist-xz dist-zip distcheck distclean distclean-generic \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-nandDATA install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am uninstall uninstall-am uninstall-nandDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT:
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/acinclude.m4 @@ -0,0 +1,43 @@ +dnl Process this file with aclocal to get an aclocal.m4 file. Then +dnl process that with autoconf. +dnl ==================================================================== +dnl +dnl acinclude.m4 +dnl +dnl ==================================================================== +dnl ####ECOSHOSTGPLCOPYRIGHTBEGIN#### +dnl ------------------------------------------- +dnl This file is part of the eCos host tools. +dnl Copyright (C) 2002 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 or (at your option) any +dnl later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the +dnl Free Software Foundation, Inc., 51 Franklin Street, +dnl Fifth Floor, Boston, MA 02110-1301, USA. +dnl ------------------------------------------- +dnl ####ECOSHOSTGPLCOPYRIGHTEND#### +dnl ==================================================================== +dnl#####DESCRIPTIONBEGIN#### +dnl +dnl Author(s): bartv +dnl Contact(s): bartv +dnl Date: 2002/09/04 +dnl Version: 0.01 +dnl +dnl####DESCRIPTIONEND#### +dnl ==================================================================== + +dnl Access shared macros. +dnl AM_CONDITIONAL needs to be mentioned here or else aclocal does not +dnl incorporate the macro into aclocal.m4 +sinclude(../../../../../../acsupport/acinclude.m4)
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/aclocal.m4 @@ -0,0 +1,678 @@ +# generated automatically by aclocal 1.11 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.63],, +[m4_warning([this file was generated for autoconf 2.63. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4])
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/configure @@ -0,0 +1,3587 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.63. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell bug-autoconf@gnu.org about your system, + echo including any error possibly output before this message. + echo This can help us improve future autoconf versions. + echo Configuration will now proceed without shell functions. +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 </dev/null 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="nand.tcl" +ac_subst_vars='LTLIBOBJS +LIBOBJS +PACKAGE_INSTALL +PACKAGE_DIR +ECOS_REPOSITORY +SUPPORTED_FALSE +SUPPORTED_TRUE +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_maintainer_mode +' + ac_precious_vars='build_alias +host_alias +target_alias' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { $as_echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { $as_echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 + { (exit 1); exit 1; }; } ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { $as_echo "$as_me: error: working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.63 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.63. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in ../../../../../../acsupport "$srcdir"/../../../../../../acsupport; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in ../../../../../../acsupport \"$srcdir\"/../../../../../../acsupport" >&5 +$as_echo "$as_me: error: cannot find install-sh or install.sh in ../../../../../../acsupport \"$srcdir\"/../../../../../../acsupport" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + + + { $as_echo "$as_me:$LINENO: checking that a separate build tree is being used" >&5 +$as_echo_n "checking that a separate build tree is being used... " >&6; } + ecos_cwd=`/bin/pwd` + if test "${srcdir}" = "." ; then + srcdir=${ecos_cwd} + fi + if test "${ecos_cwd}" = "${srcdir}" ; then + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:$LINENO: error: This configure script should not be run inside the source tree. Instead please use a separate build tree" >&5 +$as_echo "$as_me: error: This configure script should not be run inside the source tree. Instead please use a separate build tree" >&2;} + { (exit 1); exit 1; }; } + else + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + fi + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ $as_echo "$as_me:$LINENO: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +$as_echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:$LINENO: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +$as_echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + +done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + { { $as_echo "$as_me:$LINENO: error: unsafe absolute working directory name" >&5 +$as_echo "$as_me: error: unsafe absolute working directory name" >&2;} + { (exit 1); exit 1; }; };; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + { { $as_echo "$as_me:$LINENO: error: unsafe srcdir value: \`$srcdir'" >&5 +$as_echo "$as_me: error: unsafe srcdir value: \`$srcdir'" >&2;} + { (exit 1); exit 1; }; };; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { $as_echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +$as_echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { $as_echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +$as_echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done +done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:$LINENO: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + { { $as_echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +$as_echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=eCos_synthetic_target_nand + VERSION=0.1 + + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +{ $as_echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +case "${host}" in + i[34567]86-*-linux-gnu* ) SUPPORTED="yes";; + x86_64-*-linux-gnu* ) SUPPORTED="yes";; + * ) SUPPORTED="no" +esac + if test "${SUPPORTED}" = "yes"; then + SUPPORTED_TRUE= + SUPPORTED_FALSE='#' +else + SUPPORTED_TRUE='#' + SUPPORTED_FALSE= +fi + + +if test "${SUPPORTED}" = "yes" ; then + + + package_dir=`cd ${srcdir} && /bin/pwd` + PACKAGE_VERSION=`dirname ${package_dir}` + PACKAGE_VERSION=`basename ${PACKAGE_VERSION}` + + package_dir=`dirname ${package_dir}` + package_dir=`dirname ${package_dir}` + + possibles="${package_dir}/.. ${package_dir}/../.. ${package_dir}/../../.. ${package_dir}/../../../.." + possibles="${possibles} ${package_dir}/../../../../.. ${package_dir}/../../../../../.." + + repository_root="" + for i in ${possibles}; do + if test -d "$i/"acsupport""; then + repository_root=$i + break + fi + done + + if test "${repository_root}" = "" ; then + { { $as_echo "$as_me:$LINENO: error: Failed to identify this package's position within the eCos repository" >&5 +$as_echo "$as_me: error: Failed to identify this package's position within the eCos repository" >&2;} + { (exit 1); exit 1; }; } + fi + ECOS_REPOSITORY=`cd "${repository_root}/packages/pkgconf/.." && /bin/pwd` + + PACKAGE_DIR=`echo ${package_dir} | sed -e "s:${ECOS_REPOSITORY}/::"` + + PACKAGE_INSTALL="${PACKAGE_DIR}/${PACKAGE_VERSION}" + + + + + + +fi + +ac_config_files="$ac_config_files Makefile:Makefile.in" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${SUPPORTED_TRUE}" && test -z "${SUPPORTED_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"SUPPORTED\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"SUPPORTED\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.63. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTION]... [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to <bug-autoconf@gnu.org>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.63, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { $as_echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile:Makefile.in" ;; + + *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + $as_echo "$as_me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=' ' +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 +$as_echo "$as_me: error: could not setup config files machinery" >&2;} + { (exit 1); exit 1; }; } +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 +$as_echo "$as_me: error: invalid tag $ac_tag" >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + ac_file_inputs="$ac_file_inputs '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + ;; + + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/configure.in @@ -0,0 +1,72 @@ +dnl Process this file with autoconf to produce a configure script. +dnl ==================================================================== +dnl +dnl configure.in +dnl +dnl configure script for eCos synthetic target nand driver +dnl host-side support +dnl +dnl ==================================================================== +dnl ####ECOSHOSTGPLCOPYRIGHTBEGIN#### +dnl ------------------------------------------- +dnl This file is part of the eCos host tools. +dnl Copyright (C) 2009 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 or (at your option) any +dnl later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the +dnl Free Software Foundation, Inc., 51 Franklin Street, +dnl Fifth Floor, Boston, MA 02110-1301, USA. +dnl ------------------------------------------- +dnl ####ECOSHOSTGPLCOPYRIGHTEND#### +dnl ==================================================================== +dnl#####DESCRIPTIONBEGIN#### +dnl +dnl Author(s): bartv +dnl Contact(s): bartv +dnl Date: 2009/07/01 +dnl Version: 0.01 +dnl +dnl####DESCRIPTIONEND#### +dnl ==================================================================== + + +AC_INIT(nand.tcl) + +dnl Pick up the support files from the top-level acsupport directory. +AC_CONFIG_AUX_DIR(../../../../../../acsupport) + +ECOS_CHECK_BUILD_ne_SRC +AC_CANONICAL_HOST +AM_INIT_AUTOMAKE(eCos_synthetic_target_nand,0.1,0) +AM_MAINTAINER_MODE + +dnl The current version of the synthetic target is implemented only for +dnl x86 Linux platforms, so a test is appropriate here. However +dnl it is not a good idea for the configure script to report an error: +dnl that would prevent any top-level configury working for other +dnl platforms. Instead an automake conditional is used to suppress adding +dnl targets to the build. +case "${host}" in + i[[34567]]86-*-linux-gnu* ) SUPPORTED="yes";; + x86_64-*-linux-gnu* ) SUPPORTED="yes";; + * ) SUPPORTED="no" +esac +AM_CONDITIONAL(SUPPORTED, test "${SUPPORTED}" = "yes") + +dnl The nand host-side support only involves a Tcl +dnl script and data files, so nothing needs to be compiled +if test "${SUPPORTED}" = "yes" ; then + ECOS_PACKAGE_DIRS +fi + +AC_OUTPUT(Makefile:Makefile.in)
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/nand.tcl @@ -0,0 +1,1058 @@ +# {{{ Banner + +# ============================================================================ +# +# nand.tcl +# +# Nand flash support for the eCos synthetic target I/O auxiliary +# +# ============================================================================ +# ####ECOSHOSTGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of the eCos host tools. +# Copyright (C) 2009 eCosCentric Ltd. +# +# 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. +# ------------------------------------------- +# ####ECOSHOSTGPLCOPYRIGHTEND#### +# ============================================================================ +# #####DESCRIPTIONBEGIN#### +# +# Author(s): bartv +# Contact(s): bartv +# Date: 2009/07/01 +# Version: 0.01 +# Description: +# Host-side support for the synthetic nand driver. +# +# ####DESCRIPTIONEND#### +# ============================================================================ + +# }}} + +# Overview. +# +# The host-side support for the synth nand driver is aimed primarily +# at controlling various debug features. These are set up during +# initialization. Once the driver is up and running there is no +# further interaction with the host-side. +# +# All required parameters for the target-side are controlled by +# CDL, including: +# +# image filename +# page size +# spare (OOB) size +# pages per block +# block count +# +# This means the target-side can run in the absence of the I/O +# auxiliary. This module only extends the functionality, and +# only when --nanddebug is added to the command line. +# +# The desired facilities are: +# +# 1) image selection. The image file itself remains as per the +# CDL setting, to maintain consistent behaviour when running +# with or without the I/O auxiliary. There are now buttons +# for deleting the current image, restoring the image from +# a previous run, or saving the image. +# +# 2) enabling/disabling logging. Specifically we want to be able +# to log +# read calls +# read calls plus the data read +# write calls +# write calls with the data written +# erase calls +# errors +# +# Obviously it should be possible to specify the logfile, and +# default settings should come from default.tdf. It is also a good +# idea to impose some limits on the logfile size, e.g. n MB, and to +# control the behaviour when a logfile overflows. Maximum flexibility +# is achieved by allowing n (>=1) logfiles, with the option of +# creating checkpoint images. +# +# 3) error injection. We want to be able to set the initial factory-bad +# blocks when creating a new nand image. We also want to be able to +# inject new bad blocks at run-time, using an appropriately flexible +# .tdf syntax and GUI. +# +# For now only one nand device is supported here, but the protocol and +# target-side do support multiple devices. Basically that would require +# turning the settings from global to array entries. + +namespace eval nand { + + variable debug_enabled 0 + + # This information comes from the target-side, and helps with the UI. + variable target_protocol_version 0 + variable image_filename "" + variable pagesize 0 + variable sparesize 0 + variable pages_per_block 0 + variable number_of_blocks 0 + variable number_of_partitions 0 ;# 0 indicates that manual partitioning is disabled + array set partitions [list] ;# (id,base) and (id,size) + + # These are the logging settings. They can come from the config file, + # and are editable in the dialog's logging tab + variable log_read 0 + variable log_READ 0 + variable log_write 0 + variable log_WRITE 0 + variable log_erase 0 + variable log_error 0 + variable logfile "" + variable max_logfile_size 1024 + variable max_logfile_unit "K" + variable number_of_logfiles 1 + variable generate_checkpoints 0 + + # These are the bad-block injection settings. They can also come + # from the config file, and are editable in the dialog's errors + # tab. + variable factory_bad_blocks [list] + variable MAX_INJECTIONS 8 ;# each for erase and write, giving 16 + array set erase_injections [list] + array set write_injections [list] + for { set i 0 } { $i < $nand::MAX_INJECTIONS } { incr i } { + set erase_injections($i,enabled) 0 + set erase_injections($i,str) "" + set erase_injections($i,affects) "c" ;# "c" for current block, "n" for specific block or page + set erase_injections($i,number) "0" ;# + set erase_injections($i,after_type) "e" ;# "r" for rand() %, "e" for exactly + set erase_injections($i,after_count) "1" ;# + set erase_injections($i,after_which) "E" ;# "E" for any erase, "W" for any write, "C" for any call, "e" for erase block, "w" for write page + set erase_injections($i,repeat) "o" ;# "o" for once, "r" for repeat + set write_injections($i,enabled) 0 + set write_injections($i,str) "" + set write_injections($i,affects) "c" ;# "c" for current block, "p" for specific page + set write_injections($i,number) "0" ;# + set write_injections($i,after_type) "e" ;# "r" for rand() %, "e" for exactly + set write_injections($i,after_count) "1" ;# + set write_injections($i,after_which) "W" ;# "E" for any erase, "W" for any write, "C" for any call, "e" for erase block, "w" for write page + set write_injections($i,repeat) "o" ;# "o" for once, "r" for repeat + } + + # A couple of utilities to help with parsing .tdf inject options + proc inject_get_next_word { } { + upvar 1 idx idx_l + upvar 1 option option_l + + if { $idx_l >= [llength $option_l] } { + synth::report_warning "nand device, incomplete \"inject\" entry in target definition file $synth::target_definition\n \ + \"[join $option_l]\"\n" + return -code continue + } + set result [string tolower [lindex $option_l $idx_l]] + incr idx_l + return $result + } + + proc report_bogus_inject { text } { + upvar 1 option option_l + synth::report_warning "nand device, invalid \"inject\" entry in target definition file $synth::target_definition\n \ + \"inject [join $option_l]\"\n \ + $text" + return -code continue + } + + proc instantiate { id name data } { + # NOTE: the argument will remain unconsumed until the target-side + # switches to initialization via a static constructor. + if { [synth::argv_defined "-nanddebug"] } { + set nand::debug_enabled 1 + } + # Pick up logging configuration options from default.tdf + set tmp [synth::tdf_get_option "nand" "logfile"] + if { 0 == [llength $tmp] } { + # Option not specified, the default will be based on the image filename + } elseif { 1 == [llength $tmp] } { + set nand::logfile $tmp + } else { + synth::report_error "nand device, invalid \"logfile\" entry in target definition file $synth::target_definition\n \ + This entry should be a single string, a filename.\n" + } + + foreach entry [synth::tdf_get_option "nand" "log"] { + switch -exact -- $entry { + "read" - + "reads" { + set nand::log_read 1 + } + "READ" - + "READS" { + set nand::log_READ 1 + } + "write" - + "writes" { + set nand::log_write 1 + } + "WRITE" - + "WRITES" { + set nand::log_WRITE 1 + } + "erase" - + "erases" { + set nand::log_erase 1 + } + "error" - + "errors" { + set nand::log_error 1 + } + default { + synth::report_warning "nand device, invalid \"log\" entry in target definition file $synth::target_definition\n \ + Unknown value $entry.\n \ + Valid values are read READ write WRITE erase error\n" + } + } + } + set tmp [synth::tdf_get_option "nand" "max_logfile_size"] + if { 0 != [llength $tmp] } { + set ok 1 + if { 1 != [llength $tmp] } { + set ok 0 + } else { + set tmp [lindex $tmp 0] + set value "" + set unit "" + if { ! [regexp -- {^(\d*)([kKgGmM])$} $tmp junk value unit] } { + set ok 0 + } + # Only digits are allowed in the regexp, so we know we have a number. + # Round up 0. + if { 0 == $value } { + set value 1 + synth::report_warning "nand device, invalid \"max_logfile_size\" entry in target definition file $synth::target_definition\n \ + Rounding size up to 1.\n" + } + switch -- $unit { + "k" { set unit "K" } + "g" { set unit "G" } + "m" { set unit "M" } + } + set nand::max_logfile_size $value + set nand::max_logfile_unit $unit + } + if { ! $ok } { + synth::report_warning "nand device, invalid \"max_logfile_size\" entry in target definition file $synth::target_definition\n \ + Value should be a single number followed by a unit K, M or G.\n" + } + } + + set tmp [synth::tdf_get_option "nand" "number_of_logfiles"] + if { 0 != [llength $tmp] } { + set ok 1 + if { 1 != [llength $tmp] } { + set ok 0 + } else { + set count [lindex $tmp 0] + if { ! [string is integer -strict $count] } { + set ok 0 + } else { + if { $count < 1 } { + synth::report_warning "nand device, invalid \"number_of_logfiles\" entry in target definition file $synth::target_definition\n \ + Value should be at least 1.\n" + set count 1 + } + set nand::number_of_logfiles $count + } + } + if { ! $ok } { + synth::report_warning "nand device, invalid \"number_of_logfiles\" entry in target definition file $synth::target_definition\n \ + Value should be a single number.\n" + } + } + + if { [synth::tdf_has_option "nand" "generate_checkpoint_images"] } { + set nand::generate_checkpoints 1 + } + + set tmp [synth::tdf_get_option "nand" "factory_bad"] + if { 0 != [llength $tmp] } { + foreach entry $tmp { + if { ![string is integer -strict $entry] } { + synth::report_warning "nand device, invalid \"factory_bad\" entry in target definition file $synth::target_definition\n \ + All entries should be simple integers.\n" + } elseif { $entry < 0 } { + synth::report_warning "nand device, invalid \"factory_bad\" entry in target definition file $synth::target_definition\n \ + All entries should be positive integers.\n" + } else { + lappend nand::factory_bad_blocks $entry + } + } + } + + # Parse the inject filters. Some of this could be done by a regexp, but + # diagnostics are easier if the parsing is done a word at a time. + set erase_idx 0 + set write_idx 0 + foreach option [synth::tdf_get_options "nand" "inject"] { + set erase 0 + set affects "" + set number 0 + set after_type "" + set after_count 0 + set after_which "" + set repeat "o" + set disabled 0 + + set idx 0 + set word [inject_get_next_word] + switch -- $word { + "erase" { + set erase 1 + } + "write" { + set erase 0 + } + default { + report_bogus_inject "inject should be followed by erase or write, not \"$word\"\n" + } + } + set word [inject_get_next_word] + switch -- $word { + "current" { + set affects "c" + } + "page" { + if { $erase } { + report_bogus_inject "page can only be specified after write.\n" + } + set affects "n" + } + "block" { + if { ! $erase } { + report_bogus_inject "block can only be specified after erase.\n" + continue + } + set affects "n" + } + default { + report_bogus_inject "write/erase should be followed by current/page/block, not \"$word\"\n" + } + } + if { $affects == "n" } { + set number [inject_get_next_word] + if { ! [string is integer -strict $number] } { + report_bogus_inject "page/block should be followed by a number.\n" + } + if { $number < 0 } { + report_bogus_inject "page and block numbers should be positive integers.\n" + } + } + set word [inject_get_next_word] + switch -- $word { + "after" - + "during" { + # Syntactic sugar, just ignore these. + set word [inject_get_next_word] + } + } + + if { [string equal $word "rand%"] } { + set after_type "r" + set word [inject_get_next_word] + } else { + set after_type "e" + } + if { ! [string is integer -strict $word] } { + report_bogus_inject "event count \"$word\" should be an integer or rand% integer.\n" + } + if { $word < 0 } { + report_bogus_inject "event count \"$word\" should be >= 0.\n" + } + set after_count $word + + set word [inject_get_next_word] + switch -regexp -- $word { + "^erases$" { + set after_which "E" + } + "^writes$" { + set after_which "W" + } + "^calls$" { + set after_which "C" + } + "^block_?erases$" { + set after_which "e" + } + "^page_?writes$" { + set after_which "w" + } + default { + report_bogus_inject "Invalid event type \"$word\"\n Should be erases, writes, calls, block_erases or page_writes\n" + } + } + if { (($after_which == "e") || ($after_which == "w")) && ($affects != "n") } { + report_bogus_inject "Event types block_erases and page_writes cannot be combined with \"current\"\n" + } + + if { $idx != [llength $option] } { + set word [inject_get_next_word] + if { [string equal $word "repeat"] } { + if { $affects != "c" } { + report_bogus_inject "repeat can only be used with current, not with a specific block or page.\n" + } else { + set repeat "r" + } + if { $idx != [llength $option] } { + set word [inject_get_next_word] + } else { + set word "" + } + } + if { [string equal $word "disabled"] } { + set disabled 1 + if { $idx != [llength $option] } { + set word [inject_get_next_word] + } else { + set word "" + } + } + if { ! [string equal $word ""] } { + report_bogus_inject "unexpected data \"$word\" at end of inject pattern.\n" + } + } + + # puts "Parsed filter $option" + # puts " Erase $erase, affects $affects, number $number" + # puts " after_type $after_type, after_count $after_count after_which $after_which" + # puts " repeat $repeat disabled $disabled" + + if { $erase } { + if { $erase_idx >= $nand::MAX_INJECTIONS } { + report_bogus_inject "Too many erase patters, the limit is $nand::MAX_INJECTIONS.\n" + } + set nand::erase_injections($erase_idx,enabled) [expr !$disabled] + set nand::erase_injections($erase_idx,affects) $affects + set nand::erase_injections($erase_idx,number) $number + set nand::erase_injections($erase_idx,after_type) $after_type + set nand::erase_injections($erase_idx,after_count) $after_count + set nand::erase_injections($erase_idx,after_which) $after_which + set nand::erase_injections($erase_idx,repeat) $repeat + set nand::erase_injections($erase_idx,str) [join $option] + incr erase_idx + } else { + if { $write_idx >= $nand::MAX_INJECTIONS } { + report_bogus_inject "Too many write patters, the limit is $nand::MAX_INJECTIONS.\n" + } + set nand::write_injections($write_idx,enabled) [expr !$disabled] + set nand::write_injections($write_idx,affects) $affects + set nand::write_injections($write_idx,number) $number + set nand::write_injections($write_idx,after_type) $after_type + set nand::write_injections($write_idx,after_count) $after_count + set nand::write_injections($write_idx,after_which) $after_which + set nand::write_injections($write_idx,repeat) $repeat + set nand::write_injections($write_idx,str) [join $option] + incr write_idx + } + } + return nand::handle_request + } + + proc handle_request { id reqcode arg1 arg2 reqdata reqlen reply_len } { + + switch -- $reqcode { + 1 { + # SET_PARAMS + if { ! [regexp -- {^(\d*),.*} $reqdata junk protocol] } { + synth::report_warning "nand: invalid SET_PARAMS request from target.\nHost-side nand support disabled.\n" + } else { + if { 1 != $protocol } { + synth::report_warning "nand: target uses unrecognised protocol $protocol\nHost-side nand support disabled.\n" + } else { + if { ! [regexp -- {^(\d*),(\d*),(\d*),(\d*),(\d*),(.*)$} $reqdata junk \ + nand::target_protocol_version nand::pagesize \ + nand::sparesize nand::pages_per_block \ + nand::number_of_blocks nand::image_filename] + } { + synth::report_warning "nand: invalid SET_PARAMS request from target.\nHost-side nand support disabled.\n" + set nand::target_protocol_version 0 + } else { + if { "" == $nand::logfile } { + set nand::logfile "[set nand::image_filename].log" + } + } + } + } + # We can now do some more sanity checks of the target definition file entries. + foreach block $nand::factory_bad_blocks { + if { $block >= $nand::number_of_blocks } { + synth::report_warning "nand device, invalid \"factory_bad\" entry in target definition file $synth::target_definition\n \ + Block $block has been listed, but valid values are from 0 to [expr $nand::number_of_blocks]\n" + } + } + for { set i 0 } { $i < $nand::MAX_INJECTIONS } { incr i } { + if { $nand::erase_injections($i,enabled) && ($nand::erase_injections($i,affects) == "n") } { + if { $nand::erase_injections($i,number) >= $nand::number_of_blocks } { + synth::report_warning "nand device, invalid \"inject\" entry in target definition file $synth::target_definition\n \ + \"$nand::erase_injections($i,str)\"\n \ + Blocks should be between 0 and [expr $nand::number_of_blocks - 1]\n" + set nand::erase_injections($i,enabled) 0 + } + } + if { $nand::write_injections($i,enabled) && ($nand::write_injections($i,affects) == "n") } { + if { $nand::write_injections($i,number) >= ($nand::number_of_blocks * $nand::pages_per_block) } { + synth::report_warning "nand device, invalid \"inject\" entry in target definition file $synth::target_definition\n \ + \"$nand::write_injections($i,str)\"\n \ + Pages should be between 0 and [expr ($nand::number_of_blocks * $nand::pages_per_block) - 1]\n" + set nand::write_injections($i,enabled) 0 + } + } + } + } + 2 { + # SET_PARTITIONS + if { 1 == $nand::target_protocol_version } { + if { ! [regexp -- {^(\d*),(\d*)(?:,(\d*),(\d*))?(?:,(\d*),(\d*))?(?:,(\d*),(\d*))?} \ + $reqdata junk \ + nand::partitions(0,base) nand::partitions(0,size) \ + nand::partitions(1,base) nand::partitions(1,size) \ + nand::partitions(2,base) nand::partitions(2,size) \ + nand::partitions(3,base) nand::partitions(3,size)] } { + synth::report_warning "nand: invalid SET_PARTITIONS request from target.\n" + } else { + if { [string is integer -strict $nand::partitions(3,size)] } { + set nand::number_of_partitions 4 + } elseif { [string is integer -strict $nand::partitions(2,size)] } { + set nand::number_of_partitions 3 + } elseif { [string is integer -strict $nand::partitions(1,size)] } { + set nand::number_of_partitions 2 + } else { + set nand::number_of_partitions 1 + } + } + } + } + 3 { + # DIALOG + if { (1 == $nand::target_protocol_version) && $nand::debug_enabled && $synth::flag_gui } { + nand::dialog + } + synth::send_reply 0 + } + 4 { + # GET_LOGFILE_SETTINGS + if { 1 != $nand::target_protocol_version } { + synth::send_reply + return + } + set size [expr $nand::max_logfile_size * 1024] + switch -- $nand::max_logfile_unit { + "M" { + set size [expr $size * 1024] + } + "G" { + set size [expr $size * 1024 * 1024] + } + } + set reply [format "%d%d%d%d%d%d%d%d,%d,%s" \ + $nand::log_read $nand::log_READ $nand::log_write $nand::log_WRITE \ + $nand::log_erase $nand::log_error \ + $nand::generate_checkpoints \ + $size \ + $nand::number_of_logfiles \ + $nand::logfile] + if { [string length $reply] > $arg1 } { + synth::send_reply 0 + } else { + synth::send_reply 1 [string length $reply] $reply + } + } + 5 { + # GET_FACTORY_BADS + if { 1 != $nand::target_protocol_version } { + synth::send_reply + return + } + set reply "" + foreach block $nand::factory_bad_blocks { + if { ($block >= 0) && ($block < $nand::number_of_blocks) } { + append reply [format "%d" $block] "," + } + } + set len [string length $reply] + if {[string length $reply] > $arg1 } { + synth::send_reply 0 + } elseif {[string length $reply] > 0} { + synth::send_reply 1 [expr $len - 1] [string range $reply 0 end-1] + } else { + synth::send_reply 1 + } + } + 6 { + # GET_BAD_BLOCK_INJECTIONS + set reply "" + for { set i 0 } { $i < $nand::MAX_INJECTIONS } { incr i } { + if { $nand::erase_injections($i,enabled) } { + append reply [format "E%s%d%s%d%s%s" \ + $nand::erase_injections($i,affects) \ + $nand::erase_injections($i,number) \ + $nand::erase_injections($i,after_type) \ + $nand::erase_injections($i,after_count) \ + $nand::erase_injections($i,after_which) \ + $nand::erase_injections($i,repeat) ] + } + if { $nand::write_injections($i,enabled) } { + append reply [format "W%s%d%s%d%s%s" \ + $nand::write_injections($i,affects) \ + $nand::write_injections($i,number) \ + $nand::write_injections($i,after_type) \ + $nand::write_injections($i,after_count) \ + $nand::write_injections($i,after_which) \ + $nand::write_injections($i,repeat) ] + } + } + if { [string length $reply] > $arg1 } { + synth::send_reply 0 + } else { + synth::send_reply 1 [string length $reply] $reply + } + } + } + } + + # ---------------------------------------------------------------------------- + # ---------------------------------------------------------------------------- + # The GUI dialog on startup. + + variable dialog_done 0 + variable restore_filename "" + variable save_filename "" + + proc dialog_exit { } { + set nand::dialog_done 1 + } + + proc dialog_select_tab { widget new } { + set current [lindex [pack slaves .nand_dialog.notebook] 0] + if { $new != $current } { + pack forget $current + pack $new -side top -fill x + foreach child [pack slaves .nand_dialog.buttons] { + $child configure -relief sunken + } + $widget configure -relief raised + } + } + + proc log { message } { + if { ! $nand::dialog_done } { + .nand_dialog.log.text insert end $message + .nand_dialog.log.text see end + } + } + + # ---------------------------------------------------------------------------- + # Enable/disable the various buttons in the files tab + proc dialog_check_files { first check } { + set frm .nand_dialog.notebook.files.buttons + # Only enable the delete button if the image file exists. + if { [file exists $nand::image_filename] } { + if { $first } { + nand::log "Checking for existing image file... yes\n" + } + if { ! [file isfile $nand::image_filename] } { + nand::log "Error: $nand::image_filename is not a file." + } + $frm.delete configure -state normal + $frm.save configure -state normal + $frm.save_as configure -state normal + } else { + if { $first } { + nand::log "Checking for existing image file... no\n" + } + $frm.delete configure -state disabled + $frm.save configure -state disabled + $frm.save_as configure -state disabled + } + # The save button can never be enabled/disabled, but we do want + # to check that it is a file. + if { [file exists $nand::save_filename] && ![file isfile $nand::save_filename] } { + nand::log "Error: $nand::save_filename is not a file.\n" + return + } + # The restore button should depend on the existence of an archive file. + if { [file exists $nand::restore_filename] } { + if { $first } { + nand::log "Checking for existing archive file... yes\n" + } + if { ! [file isfile $nand::restore_filename] } { + nand::log "Error: $nand::restore_filename is not a file." + } + $frm.restore configure -state normal + } else { + if { $first } { + nand::log "Checking for existing archive file... no\n" + } + $frm.restore configure -state disabled + } + + # FIXME: when a file is specified, we should also check the header + # to ensure it is compatible with the current settings. + if { $check } { + } + } + + proc dialog_delete { } { + if { [catch { file delete -- $nand::image_filename } msg] } { + nand::log "Error: failed to delete $nand::image_filename\n $msg\n" + } else { + nand::log "File $nand::image_filename deleted.\n" + } + dialog_check_files 0 0 + } + + proc dialog_save { } { + if { [catch { file copy -force -- $nand::image_filename $nand::save_filename } msg] } { + nand::log "Error: failed to save $nand::image_filename as $nand::save_filename\n $msg\n" + } else { + nand::log "File $nand::image_filename copied to $nand::save_filename\n" + } + dialog_check_files 0 0 + } + + proc dialog_save_as { } { + set filename [tk_getSaveFile -parent .nand_dialog -title "Select new archive file"] + if { "" != $filename } { + # This version changes the current save image + # set nand::save_filename $filename + # nand::dialog_save + + # This version preserves the current save image + if { [catch { file copy -force -- $nand::image_filename $filename } msg] } { + nand::log "Error: failed to save $nand::image_filename as $filename\n $msg\n" + } else { + nand::log "File $nand::image_filename copied to $filename\n" + } + dialog_check_files 0 0 + } + } + + proc dialog_restore { } { + if { [catch { file copy -force -- $nand::restore_filename $nand::image_filename } msg] } { + nand::log "Error: failed to save $nand::restore_filename as $nand::image_filename\n $msg\n" + } else { + nand::log "File $nand::restore_filename copied to $nand::image_filename\n" + } + dialog_check_files 0 1 + } + + proc dialog_restore_from { } { + set filename [tk_getOpenFile -parent .nand_dialog -title "Select existing archive file"] + if { "" != $filename } { + # This version changes the current restore image + # set nand::restore_filename $filename + # nand::dialog_restore + + # This version preserves the current restore image + if { [catch { file copy -force -- $filename $nand::image_filename } msg] } { + nand::log "Error: failed to restore from $filename to $nand::image_filename\n $msg\n" + } else { + nand::log "File $filename copied to $nand::image_filename\n" + } + dialog_check_files 0 1 + } + } + + # ---------------------------------------------------------------------------- + # Support for the logging tab. + # + # This is used to enable/disable logfile-related widgets depending on + # whether or not any of the logging options are enabled. + variable dialog_logfile_widgets [list] + # These are used for the relevant spinboxes. There are problems with + # validation and users clicking on OK without moving focus from a + # spinbox, so copies of the relevant variables are needed here. + variable dialog_max_logfile_size "" + variable dialog_max_logfile_unit "" + variable dialog_number_of_logfiles "" + + proc dialog_check_logging_enabled { } { + set enabled [expr $nand::log_read || $nand::log_READ || $nand::log_write || $nand::log_WRITE || $nand::log_erase || $nand::log_error] + foreach widget $nand::dialog_logfile_widgets { + if { $enabled } { + $widget configure -state normal + } else { + $widget configure -state disabled + } + } + } + + proc dialog_new_logfile { widget } { + set filename [tk_getSaveFile -parent .nand_dialog -title "Select new logfile"] + if { "" != $filename } { + set nand::logfile $filename + $widget configure -text "Logfile: $nand::logfile" + nand::log "New logfile is $nand::logfile" + } + } + + proc dialog_check_logfile_size { } { + if { [string is integer -strict $nand::dialog_max_logfile_size] && ($nand::dialog_max_logfile_size > 0) } { + set nand::max_logfile_size $nand::dialog_max_logfile_size + return 1 + } else { + nand::log "Invalid value for logfile size, resetting to $nand::max_logfile_size\n" + set nand::dialog_max_logfile_size $nand::max_logfile_size + return 0 + } + } + proc dialog_check_logfile_unit { } { + set current $nand::dialog_max_logfile_unit + switch -- $current { + "k" - + "K" - + "m" - + "M" - + "g" - + "G" { + set nand::max_logfile_unit [string toupper $current] + return 1 + } + default { + nand::log "Invalid setting for logfile units, resetting to $nand::max_logfile_unit\n" + set nand::dialog_max_logfile_unit $nand::max_logfile_unit + return 0 + } + } + } + + proc dialog_check_logfile_count { } { + if { [string is integer -strict $nand::dialog_number_of_logfiles] && ($nand::dialog_number_of_logfiles > 0) } { + set nand::number_of_logfiles $nand::dialog_number_of_logfiles + return 1 + } else { + nand::log "Invalid value for number of logfiles, resetting to $nand::number_of_logfiles\n" + set nand::dialog_number_of_logfiles $nand::number_of_logfiles + return 0 + } + } + + # ---------------------------------------------------------------------------- + proc dialog { } { + toplevel .nand_dialog + # Do not show anything until the sizes have been sorted out. + wm withdraw .nand_dialog + wm title .nand_dialog "NAND driver settings" + wm protocol .nand_dialog WM_DELETE_WINDOW nand::dialog_exit + + # A close button at the bottom + frame .nand_dialog.done + button .nand_dialog.done.ok -text "OK" -command nand::dialog_exit + synth::register_balloon_help .nand_dialog.done.ok "Close this dialog and let the eCos application continue." + pack .nand_dialog.done.ok -side bottom + pack .nand_dialog.done -side bottom -fill x + + # We also want a logging tab with scrollbar. + frame .nand_dialog.log + text .nand_dialog.log.text -height 5 -yscrollcommand { .nand_dialog.log.scroll set} + scrollbar .nand_dialog.log.scroll -command { .nand_dialog.log.text yview } + pack .nand_dialog.log.scroll -side right -fill y + pack .nand_dialog.log.text -fill both -expand 1 + pack .nand_dialog.log -side bottom -fill x + + # This should be a notebook widget, but for portability I + # cannot assume the presence of ttk or bwidgets. So for now + # just use a couple of buttons. + frame .nand_dialog.buttons + button .nand_dialog.buttons.files -text "Files" -relief raised \ + -command [list nand::dialog_select_tab .nand_dialog.buttons.files .nand_dialog.notebook.files] + button .nand_dialog.buttons.logging -text "Logging" -relief sunken \ + -command [list nand::dialog_select_tab .nand_dialog.buttons.logging .nand_dialog.notebook.logging] + button .nand_dialog.buttons.errors -text "Errors" -relief sunken \ + -command [list nand::dialog_select_tab .nand_dialog.buttons.errors .nand_dialog.notebook.errors] + pack .nand_dialog.buttons.files .nand_dialog.buttons.logging .nand_dialog.buttons.errors -fill x -expand 1 -side left + pack .nand_dialog.buttons -side top -fill x + synth::register_balloon_help .nand_dialog.buttons.files "Select Files tab" + synth::register_balloon_help .nand_dialog.buttons.logging "Select Logging tab" + synth::register_balloon_help .nand_dialog.buttons.errors "Select Errors tab" + + frame .nand_dialog.notebook + pack .nand_dialog.notebook -side top -fill both -expand 1 + + set nand::restore_filename "[set nand::image_filename].bak" + set nand::save_filename $nand::restore_filename + set frm [frame .nand_dialog.notebook.files] + set txt [text $frm.text -height 5] + $txt insert end "NAND image file: $nand::image_filename\n" + $txt insert end " Page size: $nand::pagesize\n" + $txt insert end " Spare (OOB) size: $nand::sparesize\n" + $txt insert end " Pages per erase block: $nand::pages_per_block\n" + $txt insert end " Number of erase blocks: $nand::number_of_blocks\n" + pack $txt -side top -fill x + frame $frm.separator -height 1 -background black + pack $frm.separator -side top -fill x + set frm [frame $frm.buttons] + button $frm.delete -text "Delete" -command [list nand::dialog_delete] + synth::register_balloon_help $frm.delete "Delete the current NAND image file.\nA new, blank, image file will be created by the target-side driver." + button $frm.save -text "Save" -command [list nand::dialog_save] + synth::register_balloon_help $frm.save "Save the current NAND image file to the archive." + button $frm.save_as -text "Save As ..." -command [list nand::dialog_save_as] + synth::register_balloon_help $frm.save_as "Save the current NAND image file to a new archive." + button $frm.restore -text "Restore" -command [list nand::dialog_restore] + synth::register_balloon_help $frm.restore "Restore the NAND image from the archive." + button $frm.restore_from -text "Restore from ..." -command [list nand::dialog_restore_from] + synth::register_balloon_help $frm.restore_from "Restore the NAND image from another archive." + button $frm.refresh -text "Refresh" -command [list nand::dialog_check_files 1 1] + synth::register_balloon_help $frm.refresh "Check the filesystem again." + label $frm.image_file -textvariable nand::image_filename -anchor w + label $frm.save_file -textvariable nand::save_filename -anchor w + label $frm.restore_file -textvariable nand::restore_filename -anchor w + grid configure $frm.delete -row 0 -column 0 -sticky we + grid configure $frm.save -row 1 -column 0 -sticky we + grid configure $frm.save_as -row 2 -column 0 -sticky we + grid configure $frm.restore -row 3 -column 0 -sticky we + grid configure $frm.restore_from -row 4 -column 0 -sticky we + grid configure $frm.refresh -row 5 -column 0 -sticky we + grid configure $frm.image_file -row 0 -column 1 -sticky we + grid configure $frm.save_file -row 1 -column 1 -sticky we + grid configure $frm.restore_file -row 3 -column 1 -sticky we + grid columnconfigure $frm 0 -weight 0 + grid columnconfigure $frm 1 -weight 1 + pack $frm -side top -fill x + nand::dialog_check_files 1 1 + + frame .nand_dialog.notebook.logging + + set frm [frame .nand_dialog.notebook.logging.events -borderwidth 2 -relief groove] + pack $frm -fill both -expand 1 -pady 10 -padx 2 + label .nand_dialog.notebook.logging.events_title -text "Events to Log" + place .nand_dialog.notebook.logging.events_title -in .nand_dialog.notebook.logging.events -relx 0 -x +10 -y -10 -bordermode outside + set frm [frame $frm.contents -padx 10 -pady 10] + checkbutton $frm.read -variable nand::log_read -command nand::dialog_check_logging_enabled -text "read" + synth::register_balloon_help $frm.read "Enable/disable logging of read calls, without the data" + checkbutton $frm.rEAD -variable nand::log_READ -command nand::dialog_check_logging_enabled -text "READ" + synth::register_balloon_help $frm.rEAD "Enable/disable logging of read calls, with all the data" + checkbutton $frm.write -variable nand::log_write -command nand::dialog_check_logging_enabled -text "write" + synth::register_balloon_help $frm.write "Enable/disable logging of write calls, without the data" + checkbutton $frm.wRITE -variable nand::log_WRITE -command nand::dialog_check_logging_enabled -text "WRITE" + synth::register_balloon_help $frm.wRITE "Enable/disable logging of write calls, with all the data" + checkbutton $frm.erase -variable nand::log_erase -command nand::dialog_check_logging_enabled -text "erase" + synth::register_balloon_help $frm.erase "Enable/disable logging of erase calls" + checkbutton $frm.error -variable nand::log_error -command nand::dialog_check_logging_enabled -text "error" + synth::register_balloon_help $frm.error "Enable/disable logging of bad block errors" + grid configure $frm.read -row 0 -column 0 -sticky w -pady 2 + grid configure $frm.rEAD -row 0 -column 1 -sticky w -pady 2 + grid configure $frm.write -row 1 -column 0 -sticky w -pady 2 + grid configure $frm.wRITE -row 1 -column 1 -sticky w -pady 2 + grid configure $frm.erase -row 2 -column 0 -sticky w -pady 2 + grid configure $frm.error -row 2 -column 1 -sticky w -pady 2 + pack $frm -side top -fill x + + set frm [frame .nand_dialog.notebook.logging.file -borderwidth 2 -relief groove] + pack $frm -fill both -expand 1 -pady 10 -padx 2 + label .nand_dialog.notebook.logging.file_title -text "Logfile settings" + place .nand_dialog.notebook.logging.file_title -in .nand_dialog.notebook.logging.file -relx 0 -x +10 -y -10 -bordermode outside + set frm [frame $frm.contents -padx 10 -pady 10] + label $frm.name -anchor w -text "Logfile: $nand::logfile" + button $frm.new -text "..." -command [list nand::dialog_new_logfile $frm.name] + synth::register_balloon_help $frm.new "Change the initial logfile" + label $frm.size_label -text "Maximum logfile size" -anchor w + label $frm.number_label -text "Number of logfiles" -anchor w + label $frm.checkpoint_label -text "Generate checkpoint files" -anchor w + set nand::dialog_max_logfile_size $nand::max_logfile_size + set nand::dialog_max_logfile_unit $nand::max_logfile_unit + set nand::dialog_number_of_logfiles $nand::number_of_logfiles + spinbox $frm.size_entry -textvariable nand::dialog_max_logfile_size -from 1 -to 0x7fffffff \ + -width 4 -validate focus -invcmd bell \ + -validatecommand nand::dialog_check_logfile_size + $frm.size_entry set $nand::max_logfile_size + synth::register_balloon_help $frm.size_entry \ + "Set the maximum size of a logfile.\n\ + The action taken when this size is exceeded depends on the \"Number of logfiles\" setting." + spinbox $frm.size_unit -values { K M G } -textvariable nand::dialog_max_logfile_unit \ + -width 1 -validate focus -invcmd bell \ + -validatecommand nand::dialog_check_logfile_unit + $frm.size_unit set $nand::max_logfile_unit + synth::register_balloon_help $frm.size_unit "Specify the unit for logfile size. Valid values are K, M and G." + spinbox $frm.number_entry -textvariable nand::dialog_number_of_logfiles -from 1 -to 0x7fffffff \ + -width 4 -validate focus -invcmd bell \ + -validatecommand nand::dialog_check_logfile_count + $frm.number_entry set $nand::number_of_logfiles + synth::register_balloon_help $frm.number_entry "Limit the number of logfiles that will be generated during a single testrun." + # Without these extra bindings, there is a problem when the user edits + # an entry but hits ok without moving the focus. If the changes are + # valid then they will be lost. + bind $frm.size_entry <Destroy> +nand::dialog_check_logfile_size + bind $frm.size_unit <Destroy> +nand::dialog_check_logfile_unit + bind $frm.number_entry <Destroy> +nand::dialog_check_logfile_count + checkbutton $frm.checkpoint -variable nand::generate_checkpoints -anchor w + set nand::dialog_logfile_widgets [list $frm.new $frm.size_entry $frm.size_unit $frm.number_entry $frm.checkpoint] + nand::dialog_check_logging_enabled + + synth::register_balloon_help $frm.checkpoint \ + "Generate a checkpoint file at the start of a run and whenever a new logfile is created." + grid configure $frm.name -row 0 -column 0 -sticky w -pady 2 + grid configure $frm.size_label -row 1 -column 0 -sticky w -pady 2 + grid configure $frm.number_label -row 2 -column 0 -sticky w -pady 2 + grid configure $frm.checkpoint_label -row 3 -column 0 -sticky w -pady 2 + grid configure $frm.new -row 0 -column 1 -sticky w -pady 2 -padx 5 + grid configure $frm.size_entry -row 1 -column 1 -sticky w -pady 2 -padx 5 + grid configure $frm.size_unit -row 1 -column 2 -sticky w -pady 2 -padx 5 + grid configure $frm.number_entry -row 2 -column 1 -sticky w -pady 2 -padx 5 + grid configure $frm.checkpoint -row 3 -column 1 -sticky w -pady 2 -padx 5 + pack $frm -side top -fill x + + frame .nand_dialog.notebook.errors + label .nand_dialog.notebook.errors.message -anchor w -text "Error tab not yet implemented" + pack .nand_dialog.notebook.errors.message -side top -fill x + + # We now want to set the notebook width to the reqwidth of the larger + # of the .files, .logging or .errors tabs. Ditto for reqheight but + # ignoring the errors tab because that is scrolled. + update + set width [winfo reqwidth .nand_dialog.notebook.files] + if { [winfo reqwidth .nand_dialog.notebook.logging] > $width } { + set width [winfo reqwidth .nand_dialog.notebook.logging] + } + if { [winfo reqwidth .nand_dialog.notebook.errors] > $width } { + set width [winfo reqwidth .nand_dialog.notebook.errors] + } + set height [winfo reqheight .nand_dialog.notebook.files] + if { [winfo reqheight .nand_dialog.notebook.logging] > $height } { + set height [winfo reqheight .nand_dialog.notebook.logging] + } + .nand_dialog.notebook configure -width $width -height $height + + # Default to the files tab + pack .nand_dialog.notebook.files -side top -fill both -expand 1 + + # Size the dialog to prevent resizing when switching tabs. + # Also centre the dialog. + update + set width [winfo reqwidth .nand_dialog] + set height [winfo reqheight .nand_dialog] + .nand_dialog configure -width $width + .nand_dialog configure -height $height + set x [expr ([winfo screenwidth .] - $width) / 2] + set y [expr ([winfo screenheight .] - $height) / 2] + wm geometry .nand_dialog [set width]x[set height]+[set x]+[set y] + wm transient .nand_dialog . + wm deiconify .nand_dialog + bind .nand_dialog <KeyPress-Escape> nand::dialog_exit + + vwait nand::dialog_done + destroy .nand_dialog + } +} + +return nand::instantiate \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/host/nand.tdf @@ -0,0 +1,147 @@ +# Target definition file fragment for nand devices + +synth_device nand { + ## The initial logfile. The default is the image file + ## configured via CDL with .log appended. + # logfile "/tmp/synthnand.log" + + ## Which logging options should be enabled. The full set is read, + ## READ, write, WRITE, erase, error. READ logs all of the data read + ## as well as the basic event, whereas read only logs the event. + ## Similarly WRITE logs the data written as well as the basic event, + ## whereas write only logs the event. + # log read write erase error + # log READ WRITE erase error + + ## Maximum size of a logfile. This is a number followed by a + ## unit K, M or G. + # max_logfile_size 16M + + ## What should be done when the logfile size is exceeded? The + ## default is to close the current logfile, then open it again + ## truncating the current contents. This is a bit unfortunate if + ## the run finishes shortly after an overflow. The alternative is + ## to specify a number of logfiles. Assume four logfiles: + ## first overflow: <logfile> -> <logfile>.0 and is truncated + ## second overflow: <logfile> -> <logfile>.1 and is truncated + ## third overflow: <logfile> -> <logfile>.2 and is truncated + ## fourth overflow: <logfile>.0 is deleted, <logfile>-><logfile>.3 and is truncated + ## Hence the maximum number of full-sized logfiles at any time + ## is 4. The total space used by logfiles is limited to + ## (n * max_logfile_size) but there is no risk of losing all + ## log data. + ## + ## A value of 1 gives the default behaviour of only <logfile> + # number_of_logfiles 4 + + ## Logfiles by themselves are not enough to really figure out + ## what is happening. Hence it is also possible to generate + ## checkpoint files. <logfile>.checkpoint is created at the + ## same time as <logfile>, as a copy of the current nand image + ## file. <logfile>.checkpoint gets renamed to <logfile>.checkpoint.0 + ## when <logfile> gets renamed to <logfile>.0, and a new + ## <logfile>.checkpoint gets created from the current nand image. + ## Checkpoint files get deleted at the same time as the logfiles. + ## + ## Obviously checkpointing is expensive in terms of diskspace. + #generate_checkpoint_images + + ## Bad block handling. + ## NOTE: when experimenting with bad blocks it may be convenient to store + ## the bad block settings in another file and source that file from here. + ## + ## It is possible to mark up to 32 erase blocks as factory-bad. This is + ## only used when creating a new image. If you are running applications + ## with a single image then changing these blocks will have no effect. + # factory_bad 42 17 256 1019 + + ## It is also possible to inject bad blocks at run-time, in a variety of + ## ways. Typical entries looks like this: + ## inject erase current after rand% 1024 erases + ## inject write current after rand% 1000000 calls repeat disabled + ## inject erase block 1 after 3 block_erases + ## inject write page 9860 after 100000 writes disabled + ## + ## All entries begin with the keyword inject. + ## + ## The next word should be one of erase or write, indicating when + ## the injection should occur. With real nand chips it is only + ## possible to detect that they have gone bad during an erase or + ## program operation, although the actual damage may have occurred + ## earlier. With the synthetic target nand device, bad block injection + ## will only occur during the driver's write or erase call. + ## + ## The next one or two words indicate which block is affected by + ## the injection. "current" means that it is the block specified + ## in the erase call to the driver, or the block containing the + ## page specified in the write call. This allows for fairly random + ## injections of bad blocks, although more heavily used blocks + ## will be more prone to going bad. "block <number>" or "page + ## <number>" identifies one specific block that will become bad. + ## This allows developers to check what happens when e.g. the + ## first block in a partition goes bad. + ## + ## "after" is just syntactic sugar and can be omitted if desired. + ## Note that it can be misleading: sometimes bad block injection + ## happens during a call, not after. + ## + ## The next one or two words give a count of how many events have + ## to elapse before the bad block injection occurs. This can be + ## "rand% <number>" to specify a random interval up to a maximum, + ## e.g. "rand% 1024" means that the injection will occur after + ## between 1 and 1023 events. Alternatively it can be just a number + ## indicating an exact number of events. This can be particularly + ## useful when replaying events from a log. + ## + ## The next word indicates the type of event being counted, and + ## can be one of writes, erases, calls, block_erases or + ## page_writes. Only the first three can be used when the block + ## is "current". All five can be used when one particular block + ## is specified. + ## writes == total number of write calls into the driver + ## erases == total number of erase calls into the driver + ## calls == total number of calls (including reads) into the driver + ## block_erases == number of erase calls for this particular block + ## page_writes == number of write calls for this particular page + ## + ## In some cases the bad block injection happens during the + ## erase or write calls, e.g.: + ## + ## inject erase block 1 after 3 block erases + ## The block can be erased twice without problems. The third + ## erase call affecting this block will cause the block to go bad. + ## + ## inject write current after 50000 writes + ## During write call number 50000, whichever page is specified + ## will go bad. + ## + ## In other cases the bad block injection happens as soon as + ## possible after the specified event, e.g.: + ## + ## inject write current after rand% 100000 calls + ## Assume the random number generator yields 42567, and call + ## 42567 is a read() call instead of a write(). The injection + ## will happen during the very next write() call and will affect + ## that page, not the one specified for the read(). + ## + ## inject erase 64 after 4096 erases + ## If erase call 4096 affects block 64 then a bad block will be + ## injected immediately. Otherwise the injection will remain pending + ## until the next time that block 64 is erased. + ## + ## Next there is an optional keyword "repeat", which can only be + ## used when the specified block is "current" - there is no point + ## in injecting another fault into a block that has already gone + ## bad. Event counting is restarted, and when the count is reached + ## again another block will fail. + ## + ## Finally there is an optional keyword "disabled". This can be + ## used to define injections which are inactive by default but + ## which can be re-enabled via the GUI interface without having + ## to fill in all the fields. + + # inject erase current after rand% 1024 erases + # inject write current after rand% 100000 calls repeat + # inject erase block 1 after 3 block_erases + # inject write page 9860 after 1000 writes +}
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/src/nand_synth.c @@ -0,0 +1,1811 @@ +//============================================================================= +// +// nand_synth.c +// +// Synthetic NAND flash driver +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry, bartv +// Date: 2009-03-06 +// Note: This file borrows in places from the synthetic flash driver. +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand_device.h> +#include <cyg/nand/nand.h> +#include CYGBLD_ISO_ERRNO_CODES_HEADER +#include <cyg/hal/drv_api.h> +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_endian.h> +#include <cyg/infra/diag.h> +#include <cyg/infra/cyg_ass.h> +#include <pkgconf/io_nand.h> +#include <pkgconf/devs_nand_synth.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +// ---------------------------------------------------------------------------- +// Multiple devices can be supported in future by #include'ing this file +// from several different modules (possibly generated) e.g. nand_synth_dev0.c, +// nand_synth_dev1.c, etc. This makes it simpler to have separate logging +// for each device etc. Everything is static so there are no name clashes, +// but debugging the driver via gdb becomes tricky when multiple devices +// are configured. +// +// These #define's would be provided by nand_synth_dev0.c etc. + +#define DEVID 0 +#define IMAGE_FILENAME CYGDAT_NAND_SYNTH_FILENAME +#define PAGESIZE CYGNUM_NAND_SYNTH_PAGESIZE +#define SPARE_PER_PAGE CYGNUM_NAND_SYNTH_SPARE_PER_PAGE +#define PAGES_PER_BLOCK CYGNUM_NAND_SYNTH_PAGES_PER_BLOCK +#define BLOCK_COUNT CYGNUM_NAND_SYNTH_BLOCK_COUNT + +// ---------------------------------------------------------------------------- +// Statics. + +// A driver lock to control access to this device. +static cyg_drv_mutex_t lock; + +// A timestamp for when the test run started. This ends up in both the +// nand image and the logfile, so that images, logfiles and checkpoint +// files can be matched up. +static struct cyg_hal_sys_timeval timeval; + +// The current image file. +static int image_fd = -1; +static int* image_header; +static int* image_erase_counts; +static int* image_write_counts; +static int* image_factory_bads; +static unsigned char* image_ok_blocks; +static unsigned char* image_data; + +// Various size fields. +#define HEADER_SIZE 64 +#define DATA_SIZE (BLOCK_COUNT * PAGES_PER_BLOCK * (PAGESIZE + SPARE_PER_PAGE)) +#define IMAGE_SIZE (HEADER_SIZE + \ + (BLOCK_COUNT * sizeof(int)) + \ + (BLOCK_COUNT * PAGES_PER_BLOCK * sizeof(int)) + \ + (MAX_FACTORY_BAD * sizeof(int)) + \ + (BLOCK_COUNT / 8) + DATA_SIZE) + +// For interacting with the I/O auxiliary. synth_buf can be used for +// other things. +static int synth_id = -1; +#define SYNTH_BUFSIZE 1024 +static unsigned char synth_buf[SYNTH_BUFSIZE]; + +// The number of various calls made so far. This is used for both +// logging and for triggering new bad blocks. +static int number_of_calls = 0; +static int number_of_read_calls = 0; +static int number_of_write_calls = 0; +static int number_of_erase_calls = 0; +static int number_of_factory_bad_calls = 0; +static int number_of_errors_injected = 0; + +// The different types of event that can be logged. +static int log_read = 0; +static int log_READ = 0; +static int log_write = 0; +static int log_WRITE = 0; +static int log_erase = 0; +static int log_error = 0; +// The logical or of all the above. +static int logging_enabled = 0; + +// Allow for a .checkpoint.0000 suffix. +#define MAX_LOGFILE_NAME (1024 - 32) +static char logfile_name[MAX_LOGFILE_NAME]; +static int max_logfile_size = 0; +static int number_of_logfiles = 0; +static int generate_checkpoints = 0; + +// Another static, buffer to hold the current log entry. This needs to be +// (two bytes * PAGESIZE) to allow for READ and WRITE logging, plus some +// spare for the header. +static char logfile_data[SYNTH_BUFSIZE + (2 * PAGESIZE)]; + +// Support for up to 32 factory-bad blocks. Changing the limit affects the +// image file format, so don't. +#define MAX_FACTORY_BAD 32 +static int factory_bad_blocks[MAX_FACTORY_BAD] = { -1 } ; + +// Maximum number of bad block injections. The limit is +// imposed primarily for the sake of the GUI interface which allows +// for 8 erase and 8 program definitions. Because of the repeat option +// it is still possible to generate any number of bad blocks. +#define MAX_BAD_BLOCK_INJECTIONS 16 + +// Data structure used for run-time bad block injections +typedef struct bad_block_injection { + int enabled; + enum { ERASE, WRITE } type; + enum { CURRENT, NUMBER } affects; // The failure affects the current block/page in the operation, or for a specific block. + int number; // of block or page, ignored for type==CURRENT + enum { RAND,SET } after_type; // The failure occurs after a random number of operations, or after a set number + int after_count; // The number of operations, or the max for RAND + enum { ERASES, + WRITES, + CALLS, + BLOCK_ERASES, + PAGE_WRITES } after_which; // The failure occurs after n per-block/per-page operations, or after n calls into the driver, + // or after n erase/write calls. + int repeat; // If CURRENT, fail another block after n operations + + int actual_count; // after_count or rand() % after_count. + // compared with number_of_calls/number_of_erase_calls/number_of_write_calls + // or decrements to 0 for BLOCK_ERASES and PAGE_WRITES + int pending; +} bad_block_injection; + +static bad_block_injection injections[MAX_BAD_BLOCK_INJECTIONS]; + +// Used as a heuristic for suppressing unwanted diagnostics. +static int last_block_gone_bad = -1; + +// The bad block table needed by the generic NAND layer. +// 2 bits per block. This is separate from the bad block table +// held in the image, which is what gets used by the driver. +#ifdef CYGSEM_IO_NAND_USE_BBT +static unsigned char bbtable[BLOCK_COUNT / 4]; +#endif + +// ---------------------------------------------------------------------------- +// Interaction with the I/O auxiliary and its nand.tcl script. +// +// First the protocol. This must be kept in step with nand.tcl +// +// Protocol version +#define NAND_PROTOCOL_VERSION 0x01 +// Inform the host-side of the parameters. +#define NAND_SET_PARAMS 0x01 +// And of the partition table +#define NAND_SET_PARTITIONS 0x02 +// Pop up a dialog, iff running in GUI mode +#define NAND_DIALOG 0x03 +// Retrieve the logfile settings +#define NAND_GET_LOGFILE_SETTINGS 0x04 +// Retrieve the factory-bad blocks +#define NAND_GET_FACTORY_BADS 0x05 +// And retrieve the bad block injection details +#define NAND_GET_BAD_BLOCK_INJECTIONS 0x06 + +static void +nand_synth_init(void) +{ + int bufsize; + diag_sprintf((char*)synth_buf, "%d", DEVID); + synth_id = synth_auxiliary_instantiate("devs/nand/synth", + SYNTH_MAKESTRING(CYGPKG_DEVS_NAND_SYNTH), + "nand", + (const char*)synth_buf, + NULL); + if (-1 == synth_id) { + diag_printf("NAND synth_devinit: warning, failed to instantiate host-side support.\n"); + } else { + // Protocol first so that the host-side can detect mismatches immediately. + // Filename last so no need to worry about special characters. + bufsize = diag_snprintf((char*)synth_buf, SYNTH_BUFSIZE, "%d,%d,%d,%d,%d,%s", + NAND_PROTOCOL_VERSION, + PAGESIZE, + SPARE_PER_PAGE, + PAGES_PER_BLOCK, + BLOCK_COUNT, + IMAGE_FILENAME); + if (bufsize >= SYNTH_BUFSIZE) { + diag_printf("NAND synth_devinit: internal error, buffer overflow.\n"); + synth_id = -1; + } else { + synth_auxiliary_xchgmsg(synth_id, NAND_SET_PARAMS, + 0, 0, + synth_buf, bufsize, + NULL, NULL, NULL, 0); + } + } +#ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_0 + if (-1 != synth_id) { + // No need to worry about overflow here with at most four + // partitions and a 1K buffer + bufsize = diag_sprintf((char*)synth_buf, "%d,%d", + CYGNUM_DEVS_NAND_SYNTH_PARTITION_0_BASE, + CYGNUM_DEVS_NAND_SYNTH_PARTITION_0_SIZE); +# ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_1 + bufsize += diag_sprintf((char*)synth_buf + bufsize, ",%d,%d", + CYGNUM_DEVS_NAND_SYNTH_PARTITION_1_BASE, + CYGNUM_DEVS_NAND_SYNTH_PARTITION_1_SIZE); +# endif +# ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_2 + bufsize += diag_sprintf((char*)synth_buf + bufsize, ",%d,%d", + CYGNUM_DEVS_NAND_SYNTH_PARTITION_2_BASE, + CYGNUM_DEVS_NAND_SYNTH_PARTITION_2_SIZE); +# endif +# ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_3 + bufsize += diag_sprintf((char*)synth_buf + bufsize, ",%d,%d", + CYGNUM_DEVS_NAND_SYNTH_PARTITION_3_BASE, + CYGNUM_DEVS_NAND_SYNTH_PARTITION_3_SIZE); +# endif + synth_auxiliary_xchgmsg(synth_id, NAND_SET_PARTITIONS, + 0, 0, + synth_buf, bufsize, + NULL, NULL, NULL, 0); + } +#endif // PARTITION_0 + + if (-1 != synth_id) { + // Now pop up the dialog box if -nanddebug was set, and + // wait for completion. + int response; + synth_auxiliary_xchgmsg(synth_id, NAND_DIALOG, + 0, 0, NULL, 0, + &response, + NULL, NULL, 0); + } + + if (-1 != synth_id) { + // Retrieve the log information. + int response, len; + len = SYNTH_BUFSIZE - 1; + synth_auxiliary_xchgmsg(synth_id, NAND_GET_LOGFILE_SETTINGS, + SYNTH_BUFSIZE - 1, 0, + NULL, 0, + &response, + synth_buf, &len, SYNTH_BUFSIZE - 1); + if (! response) { + diag_printf("NAND synth_devinit: failed to retrieve logfile settings, logging disabled.\n"); + } else { + unsigned char* tmp; + int ok = 1; + synth_buf[len] = '\0'; + log_read = (synth_buf[0] == '1'); + log_READ = (synth_buf[1] == '1'); + log_write = (synth_buf[2] == '1'); + log_WRITE = (synth_buf[3] == '1'); + log_erase = (synth_buf[4] == '1'); + log_error = (synth_buf[5] == '1'); + generate_checkpoints = (synth_buf[6] == '1'); + tmp = &(synth_buf[7]); + while (ok && (*tmp != '\0') && (*tmp != ',')) { + if ((*tmp < '0') || (*tmp > '9')) { + diag_printf("NAND synth_devinit: invalid response to GET_LOGFILE_SETTINGS\n Logging disabled."); + ok = 0; + break; + } + max_logfile_size = (10 * max_logfile_size) + (*tmp++ - '0'); + } + if (ok && (*tmp != ',')) { + diag_printf("NAND synth_devinit: invalid response to GET_LOGFILE_SETTINGS\n Logging disabled."); + ok = 0; + } else { + tmp++; + } + while (ok && (*tmp != '\0') && (*tmp != ',')) { + if ((*tmp < '0') || (*tmp > '9')) { + diag_printf("NAND synth_devinit: invalid response to GET_LOGFILE_SETTINGS\n Logging disabled."); + ok = 0; + break; + } + number_of_logfiles = (10 * number_of_logfiles) + (*tmp++ - '0'); + } + if (ok && (*tmp != ',')) { + diag_printf("NAND synth_devinit: invalid response to GET_LOGFILE_SETTINGS\n Logging disabled."); + ok = 0; + } else { + tmp++; + } + if (ok) { + if (strlen((char*)tmp) >= MAX_LOGFILE_NAME) { + diag_printf("NAND synth_devinit: invalid response to GET_LOGFILE_SETTINGS\n Logging disabled."); + ok = 0; + } else { + strcpy(logfile_name, (char*)tmp); + } + } + if (ok) { + logging_enabled = log_read || log_READ || log_write || log_WRITE || log_erase || log_error; + } +#if 0 + diag_printf("logging enabled %d\n", logging_enabled); + diag_printf("log_read %d, log_READ %d, log_write %d, log_WRITE %d\n", log_read, log_READ, log_write, log_WRITE); + diag_printf("log_erase %d, log_error %d\n", log_erase, log_error); + diag_printf("logfile %s\n", logfile_name); + diag_printf("max logfile size %d\n", max_logfile_size); + diag_printf("number of logfiles %d\n", number_of_logfiles); + diag_printf("generate checkpoints %d\n", generate_checkpoints); +#endif + } + } + + if (-1 != synth_id) { + // Retrieve the bad block information. This will only be used when a new + // nand image is created. + int i; + unsigned char* str; + int response, len; + int ok = 1; + + len = SYNTH_BUFSIZE - 1; + synth_auxiliary_xchgmsg(synth_id, NAND_GET_FACTORY_BADS, + SYNTH_BUFSIZE - 1, 0, + NULL, 0, + &response, + synth_buf, &len, len); + if (!response) { + diag_printf("NAND synth_devinit: failed to retrieve factory bad block settings.\n" + " If a new nand image is created it will not have any factory-bad blocks.\n"); + } else { + str = synth_buf; + str[len] = '\0'; + for (i = 0; i < MAX_FACTORY_BAD; i++) { + factory_bad_blocks[i] = 0; + while (('0' <= *str) && (*str <= '9')) { + factory_bad_blocks[i] = (10 * factory_bad_blocks[i]) + (*str++ - '0'); + } + if ('\0' == *str) { + break; + } + if (',' != *str) { + diag_printf("NAND synth_devinit: invalid factory bad block response from I/O auxiliary\n" + " \"s\"\n" + " Unexpected character '%c'\n" + " Ignoring rest of string.\n", + *str); + ok = 0; + break; + } + str++; + } + for ( i++ ; i < MAX_FACTORY_BAD; i++) { + factory_bad_blocks[i] = -1; + } + if (ok && ('\0' != *str)) { + diag_printf("NAND synth_devinit: invalid factory bad block response from I/O auxiliary.\n" + " Too many bad blocks in response string.\n" + " Using only the first %d entries.\n", MAX_FACTORY_BAD); + } +#if 0 + if (factory_bad_blocks[0] == -1) { + diag_printf("NAND synth_devinit: no factory bad blocks defined.\n"); + } else { + diag_printf("NAND synth_devinit: factory bad blocks are "); + for (i = 0; (i < MAX_FACTORY_BAD) && (factory_bad_blocks[i] != -1); i++) { + diag_printf("%d ", factory_bad_blocks[i]); + } + diag_printf("\n"); + } +#endif + } + } + + if (-1 != synth_id) { + // Retrieve the bad block injection information. + int i; + int ok = 1; + unsigned char* str; + int response, len; + + len = SYNTH_BUFSIZE - 1; + synth_auxiliary_xchgmsg(synth_id, NAND_GET_BAD_BLOCK_INJECTIONS, + SYNTH_BUFSIZE - 1, 0, + NULL, 0, + &response, + synth_buf, &len, len); + if (!response) { + diag_printf("NAND synth_devinit: failed to retrieve bad block injection settings.\n" + " No run-time block failures will occur.\n"); + } else { + synth_buf[len] = '\0'; + str = synth_buf; + for (i = 0; i < MAX_BAD_BLOCK_INJECTIONS; i++) { + if (*str == '\0') { + break; + } + if (*str == 'E') { + injections[i].type = ERASE; + } else if (*str == 'W') { + injections[i].type = WRITE; + } else { + ok = 0; + break; + } + str++; + if (*str == 'c') { + injections[i].affects = CURRENT; + } else if (*str == 'n') { + injections[i].affects = NUMBER; + } else { + ok = 0; + break; + } + str++; + injections[i].number = 0; + while (('0' <= *str) && (*str <= '9')) { + injections[i].number = (10 * injections[i].number) + (*str++ - '0'); + } + if (*str == 'r') { + injections[i].after_type = RAND; + } else if (*str == 'e') { + injections[i].after_type = SET; + } else { + ok = 0; + break; + } + str++; + injections[i].after_count = 0; + while (('0' <= *str) && (*str <= '9')) { + injections[i].after_count = (10 * injections[i].after_count) + (*str++ - '0'); + } + if (*str == 'E') { + injections[i].after_which = ERASES; + } else if (*str == 'W') { + injections[i].after_which = WRITES; + } else if (*str == 'C') { + injections[i].after_which = CALLS; + } else if (*str == 'e') { + injections[i].after_which = BLOCK_ERASES; + } else if (*str == 'w') { + injections[i].after_which = PAGE_WRITES; + } else { + ok = 0; + break; + } + str++; + if (*str == 'o') { + injections[i].repeat = 0; + } else if (*str == 'r') { + injections[i].repeat = 1; + } else { + ok = 0; + break; + } + str++; + + // This failure definition is ok. + injections[i].enabled = 1; + injections[i].pending = 0; + if (RAND == injections[i].after_type) { + injections[i].actual_count = rand() % injections[i].after_count; + } else { + injections[i].actual_count = injections[i].after_count; + } + } + for ( ; i < MAX_BAD_BLOCK_INJECTIONS; i++) { + injections[i].enabled = 0; + } + if (! ok) { + diag_printf("NAND synth_devinit: invalid response from I/O auxiliary to GET_FAILURE_SETTINGS request.\n" + " Reply string was \"%s\"\n" + " Disabling run-time block failures.\n", + synth_buf); + for (i = 0; i < MAX_BAD_BLOCK_INJECTIONS; i++) { + injections[i].enabled = 0; + } + } + +#if 0 + if (!injections[0].enabled) { + diag_printf("NAND synth_devinit: no bad block injections.\n"); + } else { + diag_printf("NAND synth_devinit: bad block injections:\n"); + for (i = 0; i < MAX_BAD_BLOCK_INJECTIONS; i++) { + if (!injections[i].enabled) { + continue; + } + diag_printf(" %s %s ", + ((injections[i].type == ERASE) ? "Erase" : "Write"), + ((injections[i].affects == CURRENT) ? "current" : + ((injections[i].type == ERASE) ? "block" : "page"))); + if (injections[i].affects != CURRENT) { + diag_printf("%d ", injections[i].number); + } + diag_printf("after %s %d %s%s\n", + ((injections[i].after_type == RAND) ? "rand% " : ""), + injections[i].after_count, + ((injections[i].after_which == ERASES) ? "erases" : + (injections[i].after_which == WRITES) ? "writes" : + (injections[i].after_which == CALLS) ? "calls" : + (injections[i].after_which == BLOCK_ERASES) ? "block erases" : "page writes"), + (injections[i].repeat ? " repeat" : "")); + } + } +#endif + } + } + +} + +// ---------------------------------------------------------------------------- +// Logging support. Some of this is also used for errors. + +static int logfile_fd = -1; +static int logfile_size = 0; +static int oldest_logfile_suffix = -1; +static int next_logfile_suffix = 0; + +static void +create_checkpoint(void) +{ + int fd; + int written; + if ( !logging_enabled || !generate_checkpoints) { + return; + } + + diag_sprintf((char*)synth_buf, "%s.checkpoint", logfile_name); + fd = cyg_hal_sys_open((char*)synth_buf, CYG_HAL_SYS_O_WRONLY | CYG_HAL_SYS_O_CREAT | CYG_HAL_SYS_O_TRUNC, + CYG_HAL_SYS_S_IRUSR | CYG_HAL_SYS_S_IWUSR | CYG_HAL_SYS_S_IRGRP | CYG_HAL_SYS_S_IWGRP); + if (fd < 0) { + diag_printf("NAND: failed to create checkpoint file %s, errno %d\n Disabling checkpoints.\n", + synth_buf, -fd); + generate_checkpoints = 0; + return; + } + written = cyg_hal_sys_write(fd, image_header, IMAGE_SIZE); + cyg_hal_sys_close(fd); + if (written < 0) { + diag_printf("NAND: error writing current image to checkpoint file %s, errno %d\n Disabling checkpoints.\n", + synth_buf, -written); + generate_checkpoints = 0; + } else if (written != IMAGE_SIZE) { + diag_printf("NAND: error writing current image to checkpoint file %s\n Only write %d out of %d bytes\n Disabling checkpoints.\n", + synth_buf, written, IMAGE_SIZE); + generate_checkpoints = 0; + } +} + +static void +logfile_overflow(void) +{ + int result; + + cyg_hal_sys_close(logfile_fd); + + if (number_of_logfiles > 1) { + if (-1 != oldest_logfile_suffix) { + // We have some number of existing files .0, .1 ... (next_logfile_suffix - 1) + // plus the current logfile. ((next + 1) - oldest) -> number of logfiles, + // including the current one. + if (((next_logfile_suffix + 1) - oldest_logfile_suffix) >= number_of_logfiles) { + // So time to delete the oldest. + diag_sprintf((char*)synth_buf, "%s.%d", logfile_name, oldest_logfile_suffix); + result = cyg_hal_sys_unlink((const char*)synth_buf); + if (result < 0) { + diag_printf("NAND logfile overflow: warning, failed to delete old logfile %s, errno %d\n", + (char*)synth_buf, -result); + } + if (generate_checkpoints) { + diag_sprintf((char*)synth_buf, "%s.checkpoint.%d", logfile_name, oldest_logfile_suffix); + result = cyg_hal_sys_unlink((const char*)synth_buf); + if (result < 0) { + diag_printf("NAND logfile overflow: warning, failed to delete old checkpoint file %s, errno %d\n", + (char*)synth_buf, -result); + } + } + oldest_logfile_suffix += 1; + } + } + // We now know we won't exceed the number_of_logfiles limit, so rename the current + // logfile and checkpoint file. + diag_sprintf((char*)synth_buf, "%s.%d", logfile_name, next_logfile_suffix); + result = cyg_hal_sys_rename((const char*)logfile_name, (const char*)synth_buf); + if (result < 0) { + diag_printf("NAND logfile overflow: warning, failed to rename current logfile %s\n" + " to archive logfile %s, errno %d\n" + " Discarding current logfile contents.\n", + logfile_name, synth_buf, -result); + } + if (generate_checkpoints) { + // We need a second buffer, Any logdata has already been written so + // logfile_data can be reused. + diag_sprintf((char*)logfile_data, "%s.checkpoint", logfile_name); + diag_sprintf((char*)synth_buf, "%s.checkpoint.%d", logfile_name, next_logfile_suffix); + result = cyg_hal_sys_rename((const char*)logfile_data, (const char*)synth_buf); + if (result < 0) { + diag_printf("NAND logfile overflow: warning, failed to rename current checkpoint file %s\n" + " to archive checkpoint %s, errno %d\n" + " Discarding current checkpoint data.\n", + logfile_data, synth_buf, -result); + } + } + if (-1 == oldest_logfile_suffix) { + oldest_logfile_suffix = next_logfile_suffix; + } + next_logfile_suffix += 1; + } + + logfile_fd = cyg_hal_sys_open(logfile_name, CYG_HAL_SYS_O_WRONLY | CYG_HAL_SYS_O_CREAT | CYG_HAL_SYS_O_TRUNC, + CYG_HAL_SYS_S_IRUSR | CYG_HAL_SYS_S_IWUSR | CYG_HAL_SYS_S_IRGRP | CYG_HAL_SYS_S_IWGRP); + if (logfile_fd < 0) { + diag_printf("NAND logfile overflow: failed to reopen logfile %s\n Logging has been disabled.\n", logfile_name); + logging_enabled = 0; + return; + } + logfile_size = 0; + create_checkpoint(); +} + +static void +logfile_write(int len) +{ + int written; + if ( ! logging_enabled) { + return; + } + + CYG_ASSERTC(logfile_fd >= 0); + written = cyg_hal_sys_write(logfile_fd, logfile_data, len); + if (written < 0) { + diag_printf("NAND write_log: error writing to logfile (errno %d).\n Disabling logging.\n", 0 - written); + cyg_hal_sys_close(logfile_fd); + logging_enabled = 0; + return; + } + if (written != len) { + diag_printf("NAND write_log: error writing to logfile, only wrote %d out of %d bytes.\n Disabling logging.\n", written, len); + cyg_hal_sys_close(logfile_fd); + logging_enabled = 0; + return; + } + + logfile_size += len; + if (logfile_size >= max_logfile_size) { + logfile_overflow(); + } +} + +static void +logfile_open(void) +{ + int len; + if ( ! logging_enabled) { + return; + } + + logfile_fd = cyg_hal_sys_open(logfile_name, CYG_HAL_SYS_O_WRONLY | CYG_HAL_SYS_O_CREAT | CYG_HAL_SYS_O_TRUNC, + CYG_HAL_SYS_S_IRUSR | CYG_HAL_SYS_S_IWUSR | CYG_HAL_SYS_S_IRGRP | CYG_HAL_SYS_S_IWGRP); + if (logfile_fd < 0) { + diag_printf("NAND synth_devinit: failed to open logfile %s\n Logging has been disabled.\n", logfile_name); + logging_enabled = 0; + return; + } + + len = diag_sprintf(logfile_data, "I 0 0 %ld %ld %s %d %d %d %d\n", timeval.hal_tv_sec, timeval.hal_tv_usec, + IMAGE_FILENAME, PAGESIZE, SPARE_PER_PAGE, PAGES_PER_BLOCK, BLOCK_COUNT); + logfile_write(len); +} + +static int +addhex(char* dest, unsigned char* data, int len) +{ + static const char hexdigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + int i; + + for (i = 0; i < len; i++) { + *dest++ = hexdigits[(*data >> 4) & 0x0F]; + *dest++ = hexdigits[ *data++ & 0x0F]; + } + return len + len; +} + +// ---------------------------------------------------------------------------- +// Bad block handling. +static void +mark_block_bad(int block) +{ + CYG_ASSERTC((block >= 0) && (block < BLOCK_COUNT)); + image_ok_blocks[block / 8] &= ~(0x01 << (block % 8)); + last_block_gone_bad = block; +} + +static int +is_block_ok(int block) +{ + CYG_ASSERTC((block >= 0) && (block < BLOCK_COUNT)); + if (image_ok_blocks[block / 8] & (0x01 << (block % 8))) { + return 1; + } else { + return 0; + } +} + +static int +is_block_bad(int block) +{ + return !is_block_ok(block); +} + +static void +mark_page_bad(int page) +{ + CYG_ASSERTC((page >= 0) && (page < (PAGES_PER_BLOCK * BLOCK_COUNT))); + mark_block_bad(page / PAGES_PER_BLOCK); +} + +static int +is_page_ok(int page) +{ + CYG_ASSERTC((page >= 0) && (page < (PAGES_PER_BLOCK * BLOCK_COUNT))); + return is_block_ok(page / PAGES_PER_BLOCK); +} + +static int +is_page_bad(int page) +{ + return !is_page_ok(page); +} + +static int +write_check_injections(cyg_nand_page_addr page) +{ + int i; + int make_bad = 0; + int containing_block = page / PAGES_PER_BLOCK; + + for (i = 0; i < MAX_BAD_BLOCK_INJECTIONS; i++) { + if ( ! injections[i].enabled) { + continue; + } + + // First, figure out which injections should become pending. + if (! injections[i].pending) { + switch(injections[i].after_which) { + case ERASES: + if (number_of_erase_calls >= injections[i].actual_count) { + injections[i].pending = 1; + } + break; + case WRITES: + if (number_of_write_calls >= injections[i].actual_count) { + injections[i].pending = 1; + } + break; + case CALLS: + if (number_of_calls >= injections[i].actual_count) { + injections[i].pending = 1; + } + break; + case BLOCK_ERASES: + // A BLOCK_ERASE counter cannot decrement because of a page write + break; + case PAGE_WRITES: + if ((injections[i].type == ERASE) && (containing_block == injections[i].number)) { + injections[i].actual_count -= 1; + if (injections[i].actual_count <= 0) { + injections[i].pending = 1; + } + } + if ((injections[i].type == WRITE) && (page == injections[i].number)) { + injections[i].actual_count -= 1; + if (injections[i].actual_count <= 0) { + injections[i].pending = 1; + } + } + break; + } + } + if ((injections[i].type == WRITE) && (injections[i].pending)) { + if ((injections[i].affects == CURRENT) || (injections[i].number == page)) { + // This will cause the block to be made bad later on. The flag may + // be set several times because multiple injection definitions trigger. + make_bad = 1; + // Now, if this injection is not repeatable then we can disable it and + // it will be ignored from here on. + if (! injections[i].repeat) { + injections[i].enabled = 0; + } else { + // OK, we need to reset actual_count. Note that this is done relative to the + // current number_of_erase_calls etc., not relative to actual_count. Otherwise + // the injection is too likely to trigger again during the next call, which will + // probably be for the primary bad block table. Using number_of_erase_calls + // keeps the faults spread over the device. + switch (injections[i].after_which) { + case ERASES: + if (injections[i].after_type == RAND) { + injections[i].actual_count = number_of_erase_calls + rand() % injections[i].after_count; + } else { + injections[i].actual_count = number_of_erase_calls + injections[i].after_count; + } + break; + + case WRITES: + if (injections[i].after_type == RAND) { + injections[i].actual_count = number_of_write_calls + rand() % injections[i].after_count; + } else { + injections[i].actual_count = number_of_write_calls + injections[i].after_count; + } + break; + + case CALLS: + if (injections[i].after_type == RAND) { + injections[i].actual_count = number_of_calls + rand() % injections[i].after_count; + } else { + injections[i].actual_count = number_of_calls + injections[i].after_count; + } + break; + + case BLOCK_ERASES: + case PAGE_WRITES: + // actual_count decrements with each relevant operation, so reset it + injections[i].actual_count = injections[i].after_count; + break; + } + + // And clear the pending flag until the next time the actual_count triggers. + injections[i].pending = 0; + } + } + } + } + + if ( make_bad && !is_page_bad(page)) { + number_of_errors_injected += 1; + if (log_error) { + int len = diag_sprintf(logfile_data, "Bp %d %d %d %d\n", + number_of_errors_injected, number_of_calls, page, page / PAGES_PER_BLOCK); + logfile_write(len); + } + mark_page_bad(page); + // Actual corruption of the written data happens in the write call, + // which has a better idea of what gets written where. + return 1; + } + return 0; +} + +static int +erase_check_injections(cyg_nand_block_addr block) +{ + int i; + int make_bad = 0; + + for (i = 0; i < MAX_BAD_BLOCK_INJECTIONS; i++) { + if ( ! injections[i].enabled) { + continue; + } + + // First, figure out which injections should become pending. + if (! injections[i].pending) { + switch(injections[i].after_which) { + case ERASES: + if (number_of_erase_calls >= injections[i].actual_count) { + injections[i].pending = 1; + } + break; + case WRITES: + if (number_of_write_calls >= injections[i].actual_count) { + injections[i].pending = 1; + } + break; + case CALLS: + if (number_of_calls >= injections[i].actual_count) { + injections[i].pending = 1; + } + break; + case PAGE_WRITES: + // A PAGE_WRITES counter cannot decrement because of an erase + break; + case BLOCK_ERASES: + if ((injections[i].type == ERASE) && (block == injections[i].number)) { + injections[i].actual_count -= 1; + if (injections[i].actual_count <= 0) { + injections[i].pending = 1; + } + } + if ((injections[i].type == WRITE) && (block == (injections[i].number / PAGES_PER_BLOCK))) { + injections[i].actual_count -= 1; + if (injections[i].actual_count <= 0) { + injections[i].pending = 1; + } + } + break; + } + } + if ((injections[i].type == ERASE) && (injections[i].pending)) { + if ((injections[i].affects == CURRENT) || (injections[i].number == block)) { + // This will cause the block to be made bad later on. The flag may + // be set several times because multiple injection definitions trigger. + make_bad = 1; + // Now, if this injection is not repeatable then we can disable it and + // it will be ignored from here on. + if (! injections[i].repeat) { + injections[i].enabled = 0; + } else { + // OK, we need to reset actual_count. + switch (injections[i].after_which) { + case ERASES: + if (injections[i].after_type == RAND) { + injections[i].actual_count = number_of_erase_calls + rand() % injections[i].after_count; + } else { + injections[i].actual_count = number_of_erase_calls + injections[i].after_count; + } + break; + + case WRITES: + if (injections[i].after_type == RAND) { + injections[i].actual_count = number_of_write_calls + rand() % injections[i].after_count; + } else { + injections[i].actual_count = number_of_write_calls + injections[i].after_count; + } + break; + + case CALLS: + if (injections[i].after_type == RAND) { + injections[i].actual_count = number_of_calls + rand() % injections[i].after_count; + } else { + injections[i].actual_count = number_of_calls + injections[i].after_count; + } + break; + + case BLOCK_ERASES: + case PAGE_WRITES: + // actual_count decrements with each relevant operation, so reset it + injections[i].actual_count = injections[i].after_count; + break; + } + + // And clear the pending flag until the next time the actual_count triggers. + injections[i].pending = 0; + } + } + } + } + + if ( make_bad && !is_block_bad(block)) { + number_of_errors_injected += 1; + if (log_error) { + int len = diag_sprintf(logfile_data, "Bb %d %d %d\n", number_of_errors_injected, number_of_calls, block); + logfile_write(len); + } + // Actual corruption of the data happens in the erases call, + // which has a better idea of what gets written where. + mark_block_bad(block); + return 1; + } + return 0; +} + +// ---------------------------------------------------------------------------- +// Opening the nand image file, or creating a new one. +// +// The file format is as follows: +// A 64-byte parameter block containing: +// A magic number 0xEC05A11F +// Page size +// Spare (OOB) size +// Pages per block +// Number of blocks +// timeval.tv_sec +// timeval.tv_usec +// Spare fields. +// Erase counts +// Number_of_blocks integers +// Write counts +// (Number_of_blocks * Pages_per_block) integers +// Factory-bad blocks. +// 32 integers. -1 indicates no entry. +// An array of good/bad blocks +// 1 bit per block. 1 == ok, 0 == bad +// The data: +// All eraseblocks concatenated without padding +// All pages without padding +// The data area followed by the spare area. + +#define NAND_SYNTH_MAGIC 0xec05a11F + + +static int +open_image(void) +{ + int* header; + int* factory_bads; + int written; + int i; + int to_write; + int file_size; + int ok; + + image_fd = cyg_hal_sys_open(IMAGE_FILENAME, CYG_HAL_SYS_O_RDWR, + CYG_HAL_SYS_S_IRUSR | CYG_HAL_SYS_S_IWUSR | CYG_HAL_SYS_S_IRGRP | CYG_HAL_SYS_S_IWGRP); + if (-ENOENT == image_fd) { + diag_printf("NAND synth_devinit: creating new image file %s\n", IMAGE_FILENAME); + image_fd =cyg_hal_sys_open(IMAGE_FILENAME, CYG_HAL_SYS_O_RDWR | CYG_HAL_SYS_O_CREAT, + CYG_HAL_SYS_S_IRUSR | CYG_HAL_SYS_S_IWUSR | CYG_HAL_SYS_S_IRGRP | CYG_HAL_SYS_S_IWGRP); + if (image_fd < 0) { + diag_printf("NAND synth_devinit: error, failed to create image file %s\n", IMAGE_FILENAME); + return -EIO; + } + + // We can use synth_buf to populate the file. Start with the + // header. + memset(synth_buf, 0x00FF, SYNTH_BUFSIZE); + header = (int*)synth_buf; + *header++ = CYG_CPU_TO_BE32(NAND_SYNTH_MAGIC); + *header++ = CYG_CPU_TO_BE32(PAGESIZE); + *header++ = CYG_CPU_TO_BE32(SPARE_PER_PAGE); + *header++ = CYG_CPU_TO_BE32(PAGES_PER_BLOCK); + *header++ = CYG_CPU_TO_BE32(BLOCK_COUNT); + *header++ = CYG_CPU_TO_BE32((cyg_uint32)timeval.hal_tv_sec); + *header++ = CYG_CPU_TO_BE32((cyg_uint32)timeval.hal_tv_usec); + + written = cyg_hal_sys_write(image_fd, synth_buf, HEADER_SIZE); + if (written != HEADER_SIZE) { + cyg_hal_sys_close(image_fd); + diag_printf("NAND synth_devinit: error, failed to write header to image file %s\n", IMAGE_FILENAME); + return -EIO; + } + // And the erase count and page write count arrays + memset(synth_buf, 0x00, SYNTH_BUFSIZE); + to_write = BLOCK_COUNT * (PAGES_PER_BLOCK + 1) * sizeof(int); + while (to_write > 0) { + int this_write = (to_write > SYNTH_BUFSIZE) ? SYNTH_BUFSIZE : to_write; + written = cyg_hal_sys_write(image_fd, synth_buf, this_write); + if (written != this_write) { + cyg_hal_sys_close(image_fd); + diag_printf("NAND synth_devinit: error, failed to write counters to image file %s\n", IMAGE_FILENAME); + return -EIO; + } + to_write -= written; + } + + // And the factory-bad blocks. + memset(synth_buf, 0x00FF, SYNTH_BUFSIZE); + factory_bads = (int*)synth_buf; + for (i = 0; (i < MAX_FACTORY_BAD) && (-1 != factory_bad_blocks[i]); i++) { + if (factory_bad_blocks[i] >= BLOCK_COUNT) { + diag_printf("NAND synth_devinit: warning, invalid factory bad block %d\n There are only %d erase blocks.\n", + factory_bad_blocks[i], BLOCK_COUNT); + } else { + *factory_bads++ = CYG_CPU_TO_BE32((cyg_uint32)factory_bad_blocks[i]); + } + } + written = cyg_hal_sys_write(image_fd, synth_buf, MAX_FACTORY_BAD * 4); + if (written != (MAX_FACTORY_BAD * 4)) { + cyg_hal_sys_close(image_fd); + diag_printf("NAND synth_devinit: error, failed to write factory bad block data to image file %s\n", IMAGE_FILENAME); + return -EIO; + } + + // Now for the ok/bad blocks array. The current maximum is 8K blocks so 1K + // will do nicely. +#if (BLOCK_COUNT > 8192) +# error Driver init does not support block counts > 8192. +#endif +#if ((BLOCK_COUNT % 8) != 0) +# error Erase block count should be a multiple of 8. +#endif +#if ((BLOCK_COUNT + 7) / 8) > SYNTH_BUFSIZE +# error Buffer sizes need adjusting. +#endif + memset(synth_buf, 0x00FF, SYNTH_BUFSIZE); + for (i = 0; (i < MAX_FACTORY_BAD) && (-1 != factory_bad_blocks[i]); i++) { + int block = factory_bad_blocks[i]; + if (block >= BLOCK_COUNT) { + continue; // A warning has been issued already. + } + synth_buf[block / 8] &= ~(0x01 << (block % 8)); + } + written = cyg_hal_sys_write(image_fd, synth_buf, BLOCK_COUNT / 8); + if ((BLOCK_COUNT / 8) != written) { + cyg_hal_sys_close(image_fd); + diag_printf("NAND synth_devinit: error, failed to write bad block data to image file %s\n", IMAGE_FILENAME); + return -EIO; + } + + // And finally the data. + memset(synth_buf, 0x00FF, SYNTH_BUFSIZE); + to_write = DATA_SIZE; + while (to_write > 0) { + int this_write = (to_write > SYNTH_BUFSIZE) ? SYNTH_BUFSIZE : to_write; + written = cyg_hal_sys_write(image_fd, synth_buf, this_write); + if (written > this_write) { + cyg_hal_sys_close(image_fd); + diag_printf("NAND synth_devinit: error, failed to write initial empty data to image file %s\n", IMAGE_FILENAME); + return -EIO; + } + to_write -= written; + } + + // Move back to the start of the file + if (cyg_hal_sys_lseek(image_fd, 0, CYG_HAL_SYS_SEEK_SET) < 0) { + cyg_hal_sys_close(image_fd); + diag_printf("NAND synth_devinit: error, failed to seek back to start of image file %s\n", IMAGE_FILENAME); + return -EIO; + } + } + + // The image file exists and has been opened, and the current seek position is at the start. + // Before doing anything else, check the header. + if (HEADER_SIZE != cyg_hal_sys_read(image_fd, synth_buf, HEADER_SIZE)) { + cyg_hal_sys_close(image_fd); + diag_printf("NAND synth_devinit: error, failed to read header from image file %s\n", IMAGE_FILENAME); + return -EIO; + } + header = (int*)synth_buf; + ok = 1; + if (*header++ != CYG_CPU_TO_BE32(NAND_SYNTH_MAGIC)) { + diag_printf("NAND synth_devinit: error, invalid header magic in image file %s\n", IMAGE_FILENAME); + ok = 0; + } else { + if (*header != CYG_CPU_TO_BE32(PAGESIZE)) { + diag_printf("NAND synth_devinit: page size mismatch in image file %s\n", IMAGE_FILENAME); + diag_printf(" Expected page size is %d bytes, file uses %d bytes\n", + PAGESIZE, (int)CYG_BE32_TO_CPU(*header)); + ok = 0; + } + header++; + if (*header != CYG_CPU_TO_BE32(SPARE_PER_PAGE)) { + diag_printf("NAND synth_devinit: spare per page (OOB) mismatch in image file %s\n", IMAGE_FILENAME); + diag_printf(" Expected size is %d bytes, file uses %d bytes\n", + SPARE_PER_PAGE, (int)CYG_BE32_TO_CPU(*header)); + ok = 0; + } + header++; + if (*header != CYG_CPU_TO_BE32(PAGES_PER_BLOCK)) { + diag_printf("NAND synth_devinit: pages per block mismatch in image file %s\n", IMAGE_FILENAME); + diag_printf(" Expected size is %d pages, file uses %d pages\n", + SPARE_PER_PAGE, (int)CYG_BE32_TO_CPU(*header)); + ok = 0; + } + header++; + if (*header != CYG_CPU_TO_BE32(BLOCK_COUNT)) { + diag_printf("NAND synth_devinit: erase block count mismatch in image file %s\n", IMAGE_FILENAME); + diag_printf(" Expected count is %d blocks, file uses %d blocks\n", + BLOCK_COUNT, (int)CYG_BE32_TO_CPU(*header)); + ok = 0; + } + if (!ok) { + cyg_hal_sys_close(image_fd); + return -EIO; + } + } + + // Also check the file size. + file_size = cyg_hal_sys_lseek(image_fd, 0, CYG_HAL_SYS_SEEK_END); + if (file_size != IMAGE_SIZE) { + diag_printf("NAND synth_devinit: file size mismatch for image file %s\n", IMAGE_FILENAME); + diag_printf(" The file should be %d bytes long. It is %d bytes long.\n", IMAGE_SIZE, file_size); + cyg_hal_sys_close(image_fd); + return -EIO; + } + + // The file appears to be ok. Try to mmap it. + // NOTE: allowing both READ and WRITE access here leaves the NAND image + // open to accidental memory corruption. An alternative approach would + // be to only specify READ here, and add mprotect() calls in the + // write and erase functions. That would slow those operations by two + // system calls, but arguably those operations should be a lot slower + // than reads anyway. + i = cyg_hal_sys_mmap(NULL, + IMAGE_SIZE, + CYG_HAL_SYS_PROT_READ | CYG_HAL_SYS_PROT_WRITE, + CYG_HAL_SYS_MAP_SHARED, + image_fd, + 0); + // The resulting address may be in the top half of the address map, so + // testing for errors requires a bit of a kludge. + if ((i < 0) && (i > -256)) { + diag_printf("NAND synth_devinit: failed to mmap image file %s, error 0x%08x\n", IMAGE_FILENAME, i); + cyg_hal_sys_close(image_fd); + return -EIO; + } + image_header = (int*) i; + image_erase_counts = (int*) (i + HEADER_SIZE); + image_write_counts = image_erase_counts + BLOCK_COUNT; + image_factory_bads = image_write_counts + (BLOCK_COUNT * PAGES_PER_BLOCK); + image_ok_blocks = (unsigned char*) (image_factory_bads + MAX_FACTORY_BAD); + image_data = image_ok_blocks + (BLOCK_COUNT / 8); + +#if 0 + diag_printf("Image header @ %p\n", image_header); + diag_printf("Erase counts @ %p\n", image_erase_counts); + diag_printf("Write counts @ %p\n", image_write_counts); + diag_printf("Factory-bads @ %p\n", image_factory_bads); + diag_printf("OK block bitmap @ %p\n", image_ok_blocks); + diag_printf("Image data @ %p\n", image_data); +#endif + // Final sanity check. Make sure that all the factory bad blocks are marked bad. + for (i = 0; i < MAX_FACTORY_BAD; i++) { + int bad = CYG_BE32_TO_CPU(image_factory_bads[i]); + if ( (-1 != bad) && is_block_ok(bad)) { + diag_printf("NAND synth_devinit: warning, block %d should be factory-bad but is marked as OK.\n", bad); + } + } + + // Update the timestamp in the header to match this test run. + image_header[5] = CYG_CPU_TO_BE32((cyg_uint32)timeval.hal_tv_sec); + image_header[6] = CYG_CPU_TO_BE32((cyg_uint32)timeval.hal_tv_usec); + + create_checkpoint(); + return 0; +} + + + +/* -------------------------------------------------------------------- */ + +static size_t log2u(size_t v) +{ + size_t r = 0; + while (v>>=1) ++r; + return r; +} + +static int synth_devinit(cyg_nand_device *dev) +{ + int rv = 0; + + cyg_drv_mutex_init(&lock); + cyg_drv_mutex_lock(&lock); + +#define xreturn(_r) do { rv = _r; goto err_exit; } while(0) + + // Remember the start of this run. This timestamp is incorporated into + // both the image file header and the logfile, allowing the two to be + // matched up. + cyg_hal_sys_gettimeofday(&timeval, (struct cyg_hal_sys_timezone*)0); + + if (synth_auxiliary_running) { + nand_synth_init(); + } + + rv = open_image(); + if (rv < 0) { + image_fd = -1; + goto err_exit; + } + + logfile_open(); + + /* OK, synth file is good, so we set up the usual dev struct */ + dev->page_bits = log2u(PAGESIZE); + dev->spare_per_page = SPARE_PER_PAGE; + dev->block_page_bits = log2u(PAGES_PER_BLOCK); + dev->blockcount_bits = log2u(BLOCK_COUNT); + dev->chipsize_log = dev->page_bits + dev->block_page_bits + dev->blockcount_bits; + +#ifdef CYGSEM_IO_NAND_USE_BBT + dev->bbt.datasize = BLOCK_COUNT / 4; + dev->bbt.data = bbtable; +#endif + if (SPARE_PER_PAGE >= 64) { + dev->oob = &nand_mtd_oob_64; + } else if (SPARE_PER_PAGE >= 16) { + dev->oob = &nand_mtd_oob_16; + } + else { +#if 0 /* cannot use - see comment in nand_oob.c*/ + if (priv->params->sparesize >= 8) + dev->oob = &nand_mtd_oob_8; +#endif + diag_printf("NAND synth_devinit: error, OOB per page %u is not large enough (needs 16)\n", (unsigned)SPARE_PER_PAGE); + rv = -ENOSYS; + goto err_exit; + } + + /* Partition table setup. So far only manual-cdl implemented. */ +#ifdef CYGSEM_DEVS_NAND_SYNTH_PARTITION_MANUAL_CONFIG +# define LASTBLOCK ((1<<dev->blockcount_bits)-1) +# define PARTITION(i) do { \ + cyg_nand_block_addr \ + base = CYGNUM_DEVS_NAND_SYNTH_PARTITION_ ## i ## _BASE, \ + size = CYGNUM_DEVS_NAND_SYNTH_PARTITION_ ## i ## _SIZE, \ + last = size ? base + size - 1 : LASTBLOCK; \ + dev->partition[i].dev = dev; \ + dev->partition[i].first = base; \ + dev->partition[i].last = last; \ + if ((base>LASTBLOCK)||(last>LASTBLOCK)) { \ + diag_printf("ERROR: Partition %d extends beyond file params (%d+%d=%d > %d), disabling\n", i, base, size, last, LASTBLOCK); \ + dev->partition[i].dev = 0; \ + } \ +} while(0) + +# ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_0 + PARTITION(0); +# endif +# ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_1 + PARTITION(1); +# endif +# ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_2 + PARTITION(2); +# endif +# ifdef CYGPKG_DEVS_NAND_SYNTH_PARTITION_3 + PARTITION(3); +# endif +#endif // MANUAL_CONFIG + +err_exit: + cyg_drv_mutex_unlock(&lock); + return rv; +} + +#ifdef CYGSEM_NAND_SYNTH_RANDOMLY_LOSE +unsigned losscount=0; + +externC unsigned +cyg_nand_synth_get_losscount(void) +{ + return losscount; +} +#endif + +// Hacky state storage, protected by the dev lock: +static size_t _offset; +static size_t _stridden; +#ifdef CYGSEM_NAND_SYNTH_RANDOMLY_LOSE +static unsigned _lose; +static unsigned _lose_where; +static unsigned _lose_bit; +#endif +static int _page_going_bad; +static cyg_nand_page_addr _writepage; + +static int +synth_readbegin(cyg_nand_device *dev, cyg_nand_page_addr page) +{ + CYG_ASSERTC(image_fd >= 0); + CYG_ASSERTC(dev != NULL); + CYG_ASSERTC((page >= 0) && (page < (PAGES_PER_BLOCK * BLOCK_COUNT))); + + cyg_drv_mutex_lock(&lock); + number_of_calls += 1; + number_of_read_calls += 1; + + if (log_read) { + int len = diag_sprintf(logfile_data, "rb %d %d %d\n", + number_of_read_calls, number_of_calls, page); + logfile_write(len); + } + + if (log_READ) { + int len = diag_sprintf(logfile_data, "Rdb %d %d %d\n", + number_of_read_calls, number_of_calls, page); + logfile_write(len); + } + + if (is_page_bad(page)) { + // This is actually allowed. After a failed page write, higher-level code + // may need to recover the data in the other blocks. We use a heuristic + // to suppress unwanted warnings, although that may fail if two blocks + // go bad in quick succession. + if ((-1 == last_block_gone_bad) || ((page / PAGES_PER_BLOCK) != last_block_gone_bad)) { + diag_printf("NAND synth_readpage: warning, attempt to read page %d which is in a block previously marked bad.\n" + " This should only happen immediately after a previous write failure\n" + " to recover the data in the remaining pages in the erase block.\n", + page); + } + } + + _offset = page * (PAGESIZE + SPARE_PER_PAGE); + _stridden = 0; + +#ifdef CYGSEM_NAND_SYNTH_RANDOMLY_LOSE + { + if (rand()&(1<<13)) { // 50% chance of bitloss.. + _lose = ++losscount; + // where (which byte) will we lose: in the page or in its ECC? +#define ECC_COUNT ((PAGESIZE/256)*3) + int range = PAGESIZE + SPARE_PER_PAGE; + _lose_where=rand()%range; // slightly biased selection but will do + _lose_bit = rand()%8; + + } else + _lose = 0; + } +#endif + + return 0; +} + +static int +synth_readstride(cyg_nand_device *dev, void * dest, size_t size) +{ + CYG_ASSERTC((dest == NULL) || ((size >= 0) && (size <= PAGESIZE))); + + if (dest && (size > 0)) { + memcpy(dest, &(image_data[_offset + _stridden]), size); + } + +#ifdef CYGSEM_NAND_SYNTH_RANDOMLY_LOSE + if (_lose && dest) { + if (_lose_where < PAGESIZE) { + if ((_lose_where >= _stridden) && (_lose_where < _stridden+size)) { + ((unsigned char*)dest)[_lose_where - _stridden] ^= (1<<_lose_bit); + _lose = 0; + } + } + } +#endif + + if (log_read) { + int len = diag_sprintf(logfile_data, "rs %p %d\n", dest, (int)size); + logfile_write(len); + } + + if (log_READ) { + if (dest) { + int len = diag_sprintf(logfile_data, "Rdd %p %d ", dest, (int)size); + len += addhex(&(logfile_data[len]), (unsigned char*)dest, (int) size); + logfile_data[len++] = '\n'; + logfile_write(len); + } + } + + _stridden += size; + return 0; +} + +static int +synth_readfinish(cyg_nand_device *dev, void * spare, size_t spare_size) +{ + CYG_ASSERTC((spare == NULL) || ((spare_size >= 0) && (spare_size <= SPARE_PER_PAGE))); + CYG_ASSERTC(_stridden || spare); // No data and no spare probably means an error + + if (spare && (spare_size > 0)) { + memcpy(spare, &(image_data[_offset + PAGESIZE]), spare_size); + } + +#ifdef CYGSEM_NAND_SYNTH_RANDOMLY_LOSE + if (_lose && spare) { + if (_lose_where >= PAGESIZE) { + unsigned spare_offset = _lose_where - PAGESIZE; + if (spare_offset <= spare_size) { + ((unsigned char*)spare)[spare_offset] ^= (1<<_lose_bit); + _lose = 0; + } + } + } +#endif + + if (log_read) { + int len = diag_sprintf(logfile_data, "rf t=%d %p %d\n", + _stridden, spare, (int)spare_size); + logfile_write(len); + } + if (log_READ) { + if (spare) { + int len = diag_sprintf(logfile_data, "Rdf %p %d ", + spare, (int)spare_size); + len += addhex(&(logfile_data[len]), (unsigned char*)spare, (int)spare_size); + logfile_data[len++] = '\n'; + logfile_write(len); + } + } + + cyg_drv_mutex_unlock(&lock); + return 0; +} + +static int synth_readpart(cyg_nand_device *dev, void *dest, + cyg_nand_page_addr page, + size_t offset, size_t length) +{ + size_t page_offset = page * (PAGESIZE + SPARE_PER_PAGE); + + cyg_drv_mutex_lock(&lock); + number_of_calls += 1; + number_of_read_calls += 1; + + memcpy(dest, &image_data[page_offset + offset], length); + +#ifdef CYGSEM_NAND_SYNTH_RANDOMLY_LOSE + { + if (rand()&(1<<13)) { // 50% chance of bitloss.. + _lose = ++losscount; + // where (which byte) will we lose: we might be lucky and + // choose something outside of the read range. + + int range = PAGESIZE; + int _lose_where=rand()%range; // slightly biased selection but will do + + if ( (_lose_where >= offset) && (_lose_where < offset+length) ) { + CYG_BYTE *b = (CYG_BYTE*) dest; + int _lose_bit = rand()%8; + b[_lose_where - offset] ^= 1<< _lose_bit; + } + + } else + _lose = 0; + } +#endif + + if (log_read) { + int len = diag_sprintf(logfile_data, "rpp %d %d %d %d %d\n", + number_of_read_calls, number_of_calls, + page, offset, length); + logfile_write(len); + } + + if (log_READ) { + int len = diag_sprintf(logfile_data, "Rpp %d %d %d %d %d ", + number_of_read_calls, number_of_calls, page, offset, length); + len += addhex(&(logfile_data[len]), (unsigned char*)dest, (int) length); + logfile_data[len++] = '\n'; + logfile_write(len); + } + + cyg_drv_mutex_unlock(&lock); + return 0; +} + +static int +synth_writebegin(cyg_nand_device *dev, cyg_nand_page_addr page) +{ + int result = 0; + int i; + int counter; + CYG_ASSERTC(image_fd >= 0); + CYG_ASSERTC(dev != NULL); + CYG_ASSERTC((page >= 0) && (page < (PAGES_PER_BLOCK * BLOCK_COUNT))); + + cyg_drv_mutex_lock(&lock); + number_of_calls += 1; + number_of_write_calls += 1; + _offset = page * (PAGESIZE + SPARE_PER_PAGE); + _stridden = 0; + _writepage = page; + + if (log_write) { + int len = diag_sprintf(logfile_data, "wb %d %d %d\n", + number_of_write_calls, number_of_calls, page); + logfile_write(len); + } + if (log_WRITE) { + int len = diag_sprintf(logfile_data, "Wb %d %d %d ", + number_of_write_calls, number_of_calls, page); + logfile_write(len); + } + + if (is_page_bad(page)) { + diag_printf("NAND synth_writepage: attempt to write page %d which is in a block previously marked bad.\n", page); + result = -EIO; // Disallow overwrites of a page in a bad block. Arguably this should be permitted. + } + + // Do we make it bad this time? + if (0 == result) _page_going_bad = write_check_injections(page); + + // Do not allow multiple writes to a single page, for now. + if (0 == result) { + for (i = 0; i < PAGESIZE; i++) { + if (0x00FF != image_data[_offset + i]) { + diag_printf("NAND synth_writepage: attempt to write to page %d which is not erased.\n", page); + diag_printf(" Value at offset 0x%08x is 0x%02x\n", (int)(_offset + i), image_data[_offset + i]); + result = -EIO; + break; + } + } + } + + if (0 == result) { + counter = CYG_BE32_TO_CPU(image_write_counts[page]); + counter += 1; + image_write_counts[page] = CYG_CPU_TO_BE32(counter); + } + + if (0 != result) cyg_drv_mutex_unlock(&lock); + return result; +} + +static int +synth_writestride(cyg_nand_device *dev, const void * src, size_t size) +{ + int idx,i; + CYG_ASSERTC((src == NULL) || ((size >= 0) && (size <= PAGESIZE))); + + if (log_write) { + int len = diag_sprintf(logfile_data, "ws %p %d\n", + src, (int)size); + logfile_write(len); + } + if (log_WRITE) { + if (src) { + int len = diag_sprintf(logfile_data, "Wds %p %d ", src, (int)size); + len += addhex(&(logfile_data[len]), (unsigned char*)src, (int) size); + logfile_data[len++] = '\n'; + logfile_write(len); + } + } + + if (src && (size > 0)) { + memcpy(&(image_data[_offset + _stridden]), src, size); + if (_page_going_bad) { + // Fake it so that most of the write has succeeded, but one byte + // is stuck at 0xFF. That means looking for a byte in src that + // is not 0xFF. A minor improvement would be to affect just one + // bit, not all bits. + idx = rand() % size; + for (i = 0; i < size; i++) { + if (image_data[_offset + _stridden + idx] != 0x00FF) { + image_data[_offset + _stridden + idx] = 0xFF; + _page_going_bad = 0; // Do not corrupt the OOB data as well. + break; + } + idx = (idx + 1) % size; + } + } + } + // There is still the possibility where page_gone_bad, but all the data + // written was 0xFF. In that scenario all the data in the image is + // actually correct but we are still reporting -EIO. Probably not + // worth worrying about. + + _stridden += size; + return 0; +} + +static int +synth_writefinish(cyg_nand_device *dev, const void * spare, size_t spare_size) +{ + int result = 0; + int idx,i; + + CYG_ASSERTC((spare == NULL) || ((spare_size >= 0) && (spare_size <= SPARE_PER_PAGE))); + CYG_ASSERTC(_stridden || spare); + + if (log_write) { + int len = diag_sprintf(logfile_data, "wf %p %d\n", + spare, (int)spare_size); + logfile_write(len); + } + if (log_WRITE) { + if (spare) { + int len = diag_sprintf(logfile_data, "Wfo %p %d ", + spare, (int)spare_size); + len += addhex(&(logfile_data[len]), (unsigned char*)spare, (int)spare_size); + logfile_data[len++] = '\n'; + logfile_write(len); + } + } + + if (0 == result) { + if (spare && (spare_size > 0)) { + memcpy(&(image_data[_offset + PAGESIZE]), spare, spare_size); + if (_page_going_bad) { + idx = rand() % spare_size; + for (i = 0; i < spare_size; i++) { + if (image_data[_offset + PAGESIZE + idx] != 0x00FF) { + image_data[_offset + PAGESIZE + idx] = 0xFF; + break; + } + idx = (idx + 1) % spare_size; + } + } + } + } + + if (is_page_bad(_writepage)) { + result = -EIO; + } + + cyg_drv_mutex_unlock(&lock); + return result; +} + +static int +synth_eraseblock(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + int result = 0; + size_t offset; + int block_gone_bad = 0; + int counter; + + CYG_ASSERTC(image_fd >= 0); + CYG_ASSERTC(dev != NULL); + CYG_ASSERTC((blk >= 0) && (blk < BLOCK_COUNT)); + + cyg_drv_mutex_lock(&lock); + number_of_calls += 1; + number_of_erase_calls += 1; + offset = blk * PAGES_PER_BLOCK * (PAGESIZE + SPARE_PER_PAGE); + + if (log_erase) { + int len = diag_sprintf(logfile_data ,"E %d %d %d\n", + number_of_erase_calls, number_of_calls, blk); + logfile_write(len); + } + + if (is_block_bad(blk)) { + diag_printf("NAND synth_eraseblock: attempt to erase block %d which was previously marked bad.\n", blk); + result = -EIO; + } + if (0 == result) { + counter = CYG_BE32_TO_CPU(image_erase_counts[blk]); + counter += 1; + image_erase_counts[blk] = CYG_CPU_TO_BE32(counter); + } + if (0 == result) { + block_gone_bad = erase_check_injections(blk); + memset(&(image_data[offset]), 0x00FF, PAGES_PER_BLOCK * (PAGESIZE + SPARE_PER_PAGE)); + if (block_gone_bad) { + // Clear one bit in the block. It would be slightly better to find a bit + // that was cleared prior to the erase, but not worth worrying about. + int idx = rand() % (PAGES_PER_BLOCK * (PAGESIZE + SPARE_PER_PAGE)); + int bit = 0x01 << (rand() % 8); + image_data[offset + idx] &= ~bit; + } + } + if (is_block_bad(blk)) { + result = -EIO; + } + + cyg_drv_mutex_unlock(&lock); + return result; +} + +static int +synth_factorybad(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + int i; + int is_bad = 0; + CYG_ASSERTC(image_fd >= 0); + CYG_ASSERTC(dev != NULL); + CYG_ASSERTC((blk >= 0) && (blk < BLOCK_COUNT)); + + cyg_drv_mutex_lock(&lock); + number_of_calls += 1; + number_of_factory_bad_calls += 1; + + // Check the actual factory bad blocks in the nand image file, not the + // bad blocks from the user's .tdf or the dialog window. The latter + // only get used when creating a new nand image. + for (i = 0; i < MAX_FACTORY_BAD; i++) { + if (blk == CYG_BE32_TO_CPU(image_factory_bads[i])) { + is_bad = 1; + break; + } + } + + if (logging_enabled) { + int len = diag_sprintf(logfile_data, "F %d %d %d %d\n", + number_of_factory_bad_calls, number_of_calls, blk, is_bad); + logfile_write(len); + } + cyg_drv_mutex_unlock(&lock); + + return is_bad; +} + +static CYG_NAND_FUNS_V2(nand_synth_funs, synth_devinit, + synth_readbegin, synth_readstride, synth_readfinish, + synth_readpart, + synth_writebegin, synth_writestride, synth_writefinish, + synth_eraseblock, synth_factorybad); + +CYG_NAND_DEVICE(nand_synth, "synth", &nand_synth_funs, NULL, &mtd_ecc256_fast, 0); +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/tests/ar4prng.inl @@ -0,0 +1,80 @@ +//============================================================================= +// +// ar4prng.inl +// +// Inline providing ARC4-based PRNG +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#define _SWAP(_a,_b) do { int tmp = (_a); (_a) = (_b); (_b) = tmp; } while(0) + +typedef struct { + unsigned char S[256]; + int i,j; +} ar4ctx; + +void ar4prng_init(ar4ctx *c, unsigned char *seed, unsigned seedlen) +{ + int i,j=0; + for (i=0; i<256; i++) c->S[i] = i; + for (i=0; i<256; i++) { + j = (j + c->S[i] + seed[i%seedlen]) %256; + _SWAP(c->S[i], c->S[j]); + } + c->i = c->j = 0; +} + +unsigned char ar4prng_next(ar4ctx *c) +{ + c->i = (c->i + 1) %256; + c->j = (c->j + c->S[c->i]) %256; + _SWAP(c->S[c->i], c->S[c->j]); + return c->S[(c->S[c->i] + c->S[c->j])%256]; +} + +void ar4prng_many(ar4ctx *c, unsigned char *optr, unsigned len) +{ + while (len--) *(optr++) = ar4prng_next(c); +} + +#undef _SWAP +
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/tests/bbt.c @@ -0,0 +1,150 @@ +//============================================================================= +// +// bbt.c +// +// Simple tests of the Bad Block Table layer +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <pkgconf/system.h> +#if !defined(CYGPKG_MEMALLOC) || !defined(CYGPKG_LIBC_STDLIB) +externC void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA("Only usable with CYGPKG_MEMALLOC and CYGPKG_LIBC_STDLIB"); +} + +#else + +#include <string.h> +#include <stdlib.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/infra/diag.h> + +/* Forbidden knowledge: internal BBT functions */ +int cyg_nand_bbti_query(cyg_nand_device *dev, cyg_nand_block_addr blk); +int cyg_nand_bbti_markany(cyg_nand_device *dev, cyg_nand_block_addr blk, + cyg_nand_bbt_status_t st); + +/* Assert-like ... */ +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#define NBLOCKS(dev) (1<<(dev)->blockcount_bits) +#define MYBBTSIZE(dev) (1+NBLOCKS(dev)/8) + +void read_bbt(cyg_nand_device *dev, unsigned char *my_bbt) +{ + cyg_nand_block_addr blk; + memset(my_bbt, 0, MYBBTSIZE(dev)); + for (blk=0; blk < NBLOCKS(dev); blk++) { + int st = cyg_nand_bbti_query(dev, blk); + if (st != CYG_NAND_BBT_OK) + my_bbt[blk/8] |= 1<<(blk%8); + } +} + +unsigned char tmp[CYGNUM_NAND_PAGEBUFFER]; + +int cyg_user_start(void) +{ + cyg_nand_device *dev; + cyg_nand_partition *prt; + unsigned char *bbt1, *bbt2; + cyg_nand_block_addr rblk; + + CYG_TEST_INIT(); + diag_printf("Using NAND device %s\n", cyg_nanddevtab[0].devname); + MUST(0==cyg_nand_lookup(cyg_nanddevtab[0].devname, &dev)); + prt = cyg_nand_get_partition(dev, 0); + if (!prt) + CYG_TEST_NA("Need a plausible partition 0 on first nand device"); + + bbt1 = malloc(MYBBTSIZE(dev)); + read_bbt(dev, bbt1); + + /* We need a usable block to work with. */ + int lim = prt->last - prt->first; + if (lim < 5) + CYG_TEST_NA("nand partition 0 isn't big enough"); + + do { + rblk = (rand() % lim) + prt->first; + } while (cyg_nand_bbti_query(dev, rblk) != CYG_NAND_BBT_OK); + + cyg_nand_page_addr pg = rblk * NAND_PAGES_PER_BLOCK(dev); + MUST(0==cyg_nand_read_page(prt, pg, tmp, NAND_BYTES_PER_PAGE(dev), 0, 0)); + + /* Mark bad, check the table is as expected, ensure we can't read it */ + //MUST(0==cyg_nand_bbti_markbad(dev, rblk)); + //MUST(0==cyg_nand_bbt_markbad(prt, rblk)); + MUST(0==cyg_nand_bbt_markbad_pageaddr(prt, pg)); + + bbt2 = malloc(MYBBTSIZE(dev)); + read_bbt(dev, bbt2); + /* We expect it to match, save for one bit... */ + int differer = rblk/8; + int i; + for (i=0; i<MYBBTSIZE(dev); i++) { + if (i==differer) { + MUST(bbt1[i]!=bbt2[i]); + MUST( ( bbt1[i] | 1<<(rblk%8) ) == bbt2[i] ); + } else { + MUST(bbt1[i]==bbt2[i]); + } + } + MUST(0!=cyg_nand_read_page(prt, pg, tmp, NAND_BYTES_PER_PAGE(dev), 0, 0)); + + /* Now revert */ + MUST(0==cyg_nand_bbti_markany(dev, rblk, CYG_NAND_BBT_OK)); + read_bbt(dev, bbt2); + for (i=0; i<MYBBTSIZE(dev); i++) + MUST(bbt1[i]==bbt2[i]); + MUST(0==cyg_nand_read_page(prt, pg, tmp, NAND_BYTES_PER_PAGE(dev), 0, 0)); + + CYG_TEST_PASS_FINISH("NAND read/BBT functional check"); + return 0; +} + +#endif
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/tests/eccdamage.c @@ -0,0 +1,142 @@ +//============================================================================= +// +// eccdamage.c +// +// eCos NAND flash: ECC random-loss checks (on the synth device) +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <pkgconf/system.h> + +#ifdef CYGPKG_DEVS_NAND_SYNTH +#include <pkgconf/devs_nand_synth.h> +#endif + +#if !defined(CYGPKG_DEVS_NAND_SYNTH) || !defined(CYGSEM_NAND_SYNTH_RANDOMLY_LOSE) + +externC void cyg_start( void ) +{ + + CYG_TEST_INIT(); + CYG_TEST_NA("Requires CYGPKG_DEVS_NAND_SYNTH && CYGSEM_NAND_SYNTH_RANDOMLY_LOSE)"); +} + +#else + + +#include <cyg/infra/testcase.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/util.h> +#include <cyg/infra/diag.h> +#include <stdio.h> +#include <stdlib.h> + +/* slightly nasty: table defs are normally hidden */ +__externC struct _cyg_nand_device_t cyg_nanddevtab[]; +__externC struct _cyg_nand_device_t cyg_nanddevtab_end; + +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#include "ar4prng.inl" + +const char msg[] = "NAND damage loop test"; + +/* we'll use our text segment as seed to the prng; not crypto-secure but + * pretty good for running tests */ +extern unsigned char _stext[], _etext[]; + +externC unsigned cyg_nand_synth_get_losscount(void); // from nand_synth.c + +ar4ctx rnd; +cyg_nand_device *dev; +cyg_nand_partition *prt; +cyg_nand_block_addr blk; +cyg_nand_page_addr pg; + +#define datasize CYGNUM_NAND_PAGEBUFFER + +unsigned char buf[datasize], buf2[datasize]; +char msgbuf[256]; + +void cycle(void) +{ + ar4prng_many(&rnd, buf, datasize); + + MUST(0==cyg_nand_write_page(prt, pg, buf, datasize, 0, 0)); + MUST(0==cyg_nand_read_page (prt, pg, buf2,datasize, 0, 0)); + MUST(0==memcmp(buf, buf2, datasize)); + MUST(0==cyg_nand_erase_block(prt, blk)); +} + +int cyg_user_start(void) +{ + int i,seed; + + CYG_TEST_INIT(); + CYG_TEST_INFO(msg); + ar4prng_init(&rnd,(unsigned char*)msg,strlen(msg)); + ar4prng_many(&rnd, (void*)&seed, sizeof seed); + srand(seed); // for synth randomly_lose + + if (cyg_nanddevtab == &cyg_nanddevtab_end) + CYG_TEST_NA("No NAND devices found"); + + snprintf(msgbuf, sizeof(msgbuf)-1, "Using NAND device %s", cyg_nanddevtab->devname); + CYG_TEST_INFO(msgbuf); + CYG_TEST_CHECK(0==cyg_nand_lookup(cyg_nanddevtab->devname, &dev),"lookup failed"); + + prt = cyg_nand_get_partition(dev, 0); + + blk = prt->first; + pg = CYG_NAND_BLOCK2PAGEADDR(dev,blk); + + MUST(0==cyg_nand_erase_block(prt, blk)); + for(i=0; i<1000; i++) + cycle(); + + unsigned losses = cyg_nand_synth_get_losscount(); + printf("%u losses happened\n",losses); + CYG_TEST_PASS_FINISH(msg); +} + +#endif
new file mode 100644 --- /dev/null +++ b/packages/devs/nand/synth/current/tests/multipagebbt.c @@ -0,0 +1,162 @@ +//============================================================================= +// +// multipagebbt.c +// +// Multi-page BBT functional check (using the synth nand device) +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <pkgconf/system.h> +#if !defined(CYGPKG_DEVS_NAND_SYNTH) || !defined(CYGPKG_MEMALLOC) || !defined(CYGPKG_LIBC_STDLIB) + +externC void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA("Only usable with CYGPKG_DEVS_NAND_SYNTH, CYGPKG_MEMALLOC, CYGPKG_LIBC_STDLIB"); +} + +#else + +# include <pkgconf/devs_nand_synth.h> +# if (CYGNUM_NAND_SYNTH_BLOCK_COUNT <= (8*CYGNUM_NAND_SYNTH_PAGESIZE)) + +externC void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA("Requires: CYGNUM_NAND_SYNTH_BLOCK_COUNT > (8*CYGNUM_NAND_SYNTH_PAGESIZE)\n"); +} + +# else + +#include <string.h> +#include <stdlib.h> +#include <cyg/infra/diag.h> +#include <cyg/nand/nand.h> +#include <pkgconf/io_nand.h> + +/* Assert-like ... */ +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#define NBLOCKS(dev) (1<<(dev)->blockcount_bits) +#define MYBBTSIZE(dev) (1+NBLOCKS(dev)/8) + +/* Forbidden knowledge: functions declared in nand_bbt.h which isn't + * exposed. */ +int cyg_nand_bbti_markany(cyg_nand_device *dev, cyg_nand_block_addr blk, + cyg_nand_bbt_status_t st); + +unsigned char tmp[CYGNUM_NAND_PAGEBUFFER]; + +void read_bbt(cyg_nand_partition *prt, unsigned char *my_bbt) +{ + cyg_nand_device *dev = prt->dev; + cyg_nand_block_addr blk; + memset(my_bbt, 0, MYBBTSIZE(dev)); + for (blk=0; blk < NBLOCKS(dev); blk++) { + int st = cyg_nand_bbt_query(prt, blk); + if (st != CYG_NAND_BBT_OK) + my_bbt[blk/8] |= 1<<(blk%8); + } +} + +int cyg_user_start(void) +{ + cyg_nand_device *dev; + cyg_nand_partition *prt; + unsigned char *bbt1, *bbt2; + cyg_nand_block_addr rblk; + + CYG_TEST_INIT(); + MUST(0==cyg_nand_lookup("synth", &dev)); + prt = cyg_nand_get_partition(dev, 0); + if (!prt) + CYG_TEST_NA("Need a plausible partition 0 on synth nand"); + + bbt1 = malloc(MYBBTSIZE(dev)); + read_bbt(prt, bbt1); + + /* We need a usable block to work with. */ + rblk = prt->last; + do --rblk; + while (cyg_nand_bbt_query(prt, rblk) != CYG_NAND_BBT_OK); + diag_printf("got blk %d / %d\n", rblk, 8*NAND_BYTES_PER_PAGE(dev)); + if (rblk < (8 * NAND_BYTES_PER_PAGE(dev))) { + CYG_TEST_NA("Requires partition 0 to extend past the first BBT page; e.g. (CYGNUM_DEVS_NAND_SYNTH_PARTITION_0_BASE + CYGNUM_DEVS_NAND_SYNTH_PARTITION_0_SIZE) >= (8*CYGNUM_NAND_SYNTH_PAGESIZE)"); + } + + cyg_nand_page_addr pg = rblk * NAND_PAGES_PER_BLOCK(dev); + MUST(0==cyg_nand_read_page(prt, pg, tmp, NAND_BYTES_PER_PAGE(dev), 0, 0)); + + /* Mark bad, check the table is as expected, ensure we can't read it */ + MUST(0==cyg_nand_bbt_markbad(prt, rblk)); + + bbt2 = malloc(MYBBTSIZE(dev)); + read_bbt(prt, bbt2); + /* We expect it to match, save for one bit... */ + int differer = rblk/8; + int i; + for (i=0; i<MYBBTSIZE(dev); i++) { + if (i==differer) { + MUST(bbt1[i]!=bbt2[i]); + MUST( ( bbt1[i] | 1<<(rblk%8) ) == bbt2[i] ); + } else { + MUST(bbt1[i]==bbt2[i]); + } + } + MUST(0!=cyg_nand_read_page(prt, pg, tmp, NAND_BYTES_PER_PAGE(dev), 0, 0)); + + /* Now revert */ + MUST(0==cyg_nand_bbti_markany(dev, rblk, CYG_NAND_BBT_OK)); + read_bbt(prt, bbt2); + for (i=0; i<MYBBTSIZE(dev); i++) + MUST(bbt1[i]==bbt2[i]); + MUST(0==cyg_nand_read_page(prt, pg, tmp, NAND_BYTES_PER_PAGE(dev), 0, 0)); + + CYG_TEST_PASS_FINISH("NAND read/BBT functional check with big BBT"); + return 0; +} + +# endif +#endif
--- a/packages/ecos.db +++ b/packages/ecos.db @@ -4914,6 +4914,7 @@ target ea2468 { CYGPKG_IO_I2C CYGPKG_DEVS_I2C_ARM_LPC2XXX CYGPKG_DEVS_ADC_ARM_LPC24XX + CYGPKG_DEVS_NAND_SAMSUNG_K9 } description " The Embedded Artists LPC2468 HAL package provides the support @@ -5666,6 +5667,7 @@ target linux { CYGPKG_DEVS_WALLCLOCK_SYNTH CYGPKG_DEVS_FRAMEBUF_SYNTH CYGPKG_DEVS_ADC_SYNTH + CYGPKG_DEVS_NAND_SYNTH } description " The linux target provides the @@ -6906,10 +6908,50 @@ target stm3210e_eval { CYGPKG_IO_SPI CYGPKG_DEVS_SPI_CORTEXM_STM32 CYGPKG_DEVS_ADC_CORTEXM_STM32 + CYGPKG_DEVS_NAND_ST_NANDXXXX3A } description "The stm3210e_eval target provides the packages needed to run eCos on the STM3210E EVAL board." } # ========================================================================== +# NAND and YAFFS packages + +package CYGPKG_IO_NAND { + alias { "NAND flash memory support" nand io_nand } + directory io/nand + script nand.cdl + description " + This package provides the NAND flash access library. + Further platform-specific package(s) are required to implement + support for the specific devices present." +} + +package CYGPKG_DEVS_NAND_SAMSUNG_K9 { + alias { "Samsung K9 NAND chip family support" nand_samsung_k9 } + directory devs/nand/samsung_k9 + script k9fxx08x0a.cdl + description " + This package provides support for the Samsung K9Fxx08x0A family of NAND + flash devices." +} + +package CYGPKG_DEVS_NAND_SYNTH { + alias { "Synthetic NAND device" nand_synth } + directory devs/nand/synth + script nand_synth.cdl + description " + This package provides a synthetic NAND device, for testing purposes." +} + +package CYGPKG_DEVS_NAND_ST_NANDXXXX3A { + alias { "ST Microelectronics NANDxxxx3A chip family support" nand_st_nandxxxx3a } + directory devs/nand/st/nandxxxx3a + script nandxxxx3a.cdl + description " + This package provides support for the ST Microelectronics family of + NANDxxxx3A flash devices." +} + +# ========================================================================== # End of ecos.db
--- a/packages/hal/arm/lpc24xx/ea2468/current/ChangeLog +++ b/packages/hal/arm/lpc24xx/ea2468/current/ChangeLog @@ -1,3 +1,45 @@ +2009-11-10 Ross Younger <wry@ecoscentric.com> + + * ea_lpc2468_nand.c: Fix interrupt-mode brokenness when the debug + level was low. + Add heuristic to improve I/O throughput. + Tune the EMC timings to speed up NAND access. + +2009-11-06 Ross Younger <wry@ecoscentric.com> + + * ea_lpc2468_nand.c: Use mtd_ecc256_fast, not linux_mtd_ecc. + +2009-08-18 Ross Younger <wry@ecoscentric.com> + + * ea_lpc_2468_nand.c: Minor bugfix - attach on the interrupt handle, + not the interrupt object, even if it's currently inconsequential. + +2009-07-02 Ross Younger <wry@ecoscentric.com> + + * ea_lpc_2468_nand.c: Small optimisations: + + Condition-out poll-counting unless it's being reported. + + Properly defined initial-wait semantics for wait_ready_polled; + tweak callers to match. + + Don't bother with an interrupt-assisted sleep for a small + time (i.e. a page read). + +2009-06-05 Ross Younger <wry@ecoscentric.com> + + * ea_lpc_2468_nand.c: refactor for k9fxx08x0x changes; retab. + * * BBT per-chip + * * provide for locking though we don't use it on this board. + +2009-05-27 Ross Younger <wry@ecoscentric.com> + + * src/ea_lpc_2468_nand.c: Rip out eCosPro HAL ifdefs & partial rewrite + for clarity. + +2009-05-14 Ross Younger <wry@ecoscentric.com> + + * cdl/hal_arm_lpc24xx_ea2468.cdl: Add NAND support and options + * cdl/manual_partition.cdl: Created + * src/ea_lpc_2468_nand.c: Created + 2009-01-31 Bart Veer <bartv@ecoscentric.com> * cdl/hal_arm_lpc24xx_ea2468.cdl: update compiler flags for gcc 4.x
--- a/packages/hal/arm/lpc24xx/ea2468/current/cdl/hal_arm_lpc24xx_ea2468.cdl +++ b/packages/hal/arm/lpc24xx/ea2468/current/cdl/hal_arm_lpc24xx_ea2468.cdl @@ -321,7 +321,63 @@ cdl_package CYGPKG_HAL_ARM_LPC24XX_EA246 "<pkgconf/mlt_arm_lpc24xx_ea2468_rom.h>" } } } - + + cdl_component CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_NAND { + display "EA LPC2xxx NAND support" + parent CYGPKG_IO_NAND + active_if CYGPKG_IO_NAND + implements CYGHWR_IO_NAND_DEVICE + requires CYGPKG_DEVS_NAND_SAMSUNG_K9 + requires { (CYGPKG_REDBOOT && CYGPKG_FS_YAFFS) implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x20000) } + + compile -library=libextras.a ea_lpc2468_nand.c + description "This option enables support for the on-board Samsung + K9F1G08U0A NAND flash chip." + + cdl_option CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_USE_NAND_RDY { + display "Use NAND_RDY line" + flavor bool + default_value 0 + description "The EA OEM Base Board provides a jumper which + connects the NAND_RDY line with P2.12 on the CPU. + This option allows the driver to query that line. + You should not set this option if the jumper is not + connected; the results of interacting with the + chip will be undefined." + } + + cdl_option CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_NAND_RDY_USE_INTERRUPT { + display "Configure NAND_RDY line as an interrupt" + flavor bool + default_value CYGPKG_KERNEL + active_if (CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_USE_NAND_RDY && CYGPKG_KERNEL) + description "This option configures the CPU pin P2.12 + - to which the NAND_RDY line is assumed to be connected - + as an interrupt (EINT2). This is normally the preferred + configuration when the NAND_RDY line is connected, as + it allows a thread waiting for the + NAND device to sleep for exactly the right amount of time. + If this is disabled, the NAND_RDY line is polled in a + loop which consumes unnecessary CPU cycles." + } + + # Manual configuration of NAND partitions. + # We currently only provide manual config. + + + cdl_component CYGSEM_DEVS_NAND_EA_LPC2468_PARTITION_MANUAL_CONFIG { + display "Manual partition configuration" + flavor bool + default_value 1 + description " + Set in order to use CDL to manually configure the + partitions of the EA LPC2468 on-board NAND." + + set ::partition_device "EA_LPC2468" + script manual_partition.cdl + } + } + cdl_option CYGPKG_HAL_ARM_LPC24XX_EA2468_TESTS { display "Tests for LPC2468 OEM board HAL" flavor data
new file mode 100644 --- /dev/null +++ b/packages/hal/arm/lpc24xx/ea2468/current/cdl/manual_partition.cdl @@ -0,0 +1,124 @@ +# ==================================================================== +# +# manual_partition.cdl +# +# NAND device manual partition logic +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 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): wry +# Date: 2009-03-10 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +# This file can be used by drivers to implement manual CDL-driven +# partition config. +# +# To use, create a cdl_component with an appropriate name; +# make it boolean or otherwise selectable (you might for example want +# to turn it off, or pick partitioning strategy from a drop-down list), +# then choose and set a name-fragment for your device before including +# this script file along these lines: +# +# set ::partition_device "SYNTH" +# script manual_partition.cdl +# +# For a full example, see the synthetic NAND device. + + +####################################################### + +# Partition table support + +# Every NAND board driver has to decide how it will determine the +# NAND partition layout. In a simple case, there might be just +# a single partition covering the whole chip. Alternatively, +# the driver could read a partition table during _devinit, or +# the partition layout might be hard-wired (e.g. to inter-operate +# with some other fixed code). + +### +# Unfortunately, it is not currently possible within CDL to +# directly access the value of CYGNUM_NAND_MAX_PARTITIONS in a +# Tcl loop, so we cannot automatically have the second argument +# to this for loop be { $::part < CYGNUM_NAND_MAX_PARTITIONS } . +# The best we can do is pick an arbitrary number - we'll choose 4, +# because that's the same as the default CYGNUM_NAND_MAX_PARTITIONS, +# and put only that many in the loop. The current limitations of +# also mean that we have to manually check for each of the four +# partitions in C - so if you edit the number 4 below, be sure +# to tweak the corresponding macro use which makes use of it! +# +# (Four ought to be enough for everybody, shouldn't it?) +### + +for { set ::part 0 } { $::part < 4 } { incr ::part } { + cdl_option CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] { + active_if $::part < CYGNUM_NAND_MAX_PARTITIONS + display "Configure partition [set ::part]" + flavor bool + default_value [set ::part] == 0 + description " + Set in order to manually configure partition [set ::part] + in CDL." + } + + cdl_option CYGNUM_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part]_BASE { + display "Partition [set ::part] base block address" + active_if CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] == 1 + flavor data + legal_values 0 to 0x7fffffff + default_value 0 + description " + The address (number) of the eraseblock at which + partition [set ::part] begins." + } + + cdl_option CYGNUM_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part]_SIZE { + display "Partition [set ::part] size in blocks" + active_if CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] == 1 + flavor data + legal_values 0 to 0x7fffffff + default_value 0 + description " + The size of partition [set ::part], expressed + in eraseblocks. A value of 0 is special and + consumes all the remaining space on the device." + } +} +# / for loop for partitions.
new file mode 100644 --- /dev/null +++ b/packages/hal/arm/lpc24xx/ea2468/current/src/ea_lpc2468_nand.c @@ -0,0 +1,526 @@ +//============================================================================= +// +// ea_lpc2468_nand.c +// +// NAND flash support for the Embedded Artists LPC2468 OEM board. +// (This is the version for the eCos HAL for that board.) +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-03 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/hal_arm_lpc24xx_ea2468.h> + +#include <cyg/nand/nand_device.h> +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_diag.h> +#include <cyg/hal/drv_api.h> + +#include <cyg/devs/nand/k9fxx08x0x.h> + +/* Private structs. We need one k9_priv (and one of our privs) per + * instance of the chip. */ + +struct _mypriv { +#ifdef CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_NAND_RDY_USE_INTERRUPT + cyg_drv_mutex_t cvmux; // Protects CV + cyg_drv_cond_t cv; // Used to sleep on interrupt + cyg_handle_t inthdl; // interrupt handle + cyg_interrupt intr; // interrupt object + + volatile int ready; // Set when interrupt fires. Protected by DSR lock. +#else + char dummy; // shush, gcc +#endif +}; + +static struct _mypriv _ea_lpc2468_nand_priv; +static k9_priv _k9_ea_lpc2468_priv = { &_ea_lpc2468_nand_priv }; + +#define CAST_MYPRIV(x) ((struct _mypriv *) (x)) +#define CAST_K9PRIV(x) ((k9_priv *) (x)) +#define GET_MYPRIV(dev,var) struct _mypriv * var = CAST_MYPRIV(CAST_K9PRIV((dev)->priv)->plat_priv); + +/* We could use 'priv' to supply the NAND addresses. This might be + * useful if there were multiple chips on a board, but for simplicity + * we're going to hard-wire it meantime. */ +#define NAND_BASE 0x81000000 +#define NAND_CMD (NAND_BASE | (1<<20)) +#define NAND_ADDR (NAND_BASE | (1<<19)) + +static inline void tweak_pin_register(CYG_ADDRWORD reg, cyg_uint32 clearbits, cyg_uint32 setbits) +{ + cyg_uint32 val; + HAL_READ_UINT32(reg, val); + val &= ~clearbits; + val |= setbits; + HAL_WRITE_UINT32(reg, val); +} + +/* CHIP OPERATIONS ================================================= */ + +/* On this board, the memory controller is well set up, so we don't need + * to worry about timings for most operations. */ + +static inline void write_cmd(cyg_nand_device *ctx, unsigned char cmd) +{ + HAL_WRITE_UINT8(NAND_CMD,cmd); +} + +static inline void write_addrbytes(cyg_nand_device *ctx, CYG_BYTE *bytes, size_t n) +{ + HAL_WRITE_UINT8_VECTOR(NAND_ADDR, bytes, n, 0); +} + +static inline unsigned char read_data_1(cyg_nand_device *ctx) +{ + unsigned char b; + HAL_READ_UINT8(NAND_BASE, b); + return b; +} + +static inline void read_data_bulk(cyg_nand_device *ctx, unsigned char *dp, size_t n) +{ + // Most of the time, we expect to be dealing with word-aligned + // multiples of 4 bytes, so optimise for that case. + if ( ((CYG_ADDRWORD)dp&3)==0 && (n%4)==0) { + volatile cyg_uint8 const *a = (cyg_uint8*) NAND_BASE; + cyg_uint32 *ip = (cyg_uint32*) dp; + cyg_uint32 r; + n /= 4; +#if (CYGINT_HAL_ARM_BIGENDIAN == 1) +#define ONEWORD do { r = (*a) << 24; r |= (*a) << 16; r |= (*a) << 8; r |= *a; } while(0) +#else +#define ONEWORD do { r = *a; r |= (*a) << 8; r |= (*a) << 16; r |= (*a) << 24; } while(0) +#endif + while (n) { + ONEWORD; + *(ip++) = r; + --n; + } +#undef ONEWORD + } else + HAL_READ_UINT8_VECTOR(NAND_BASE, dp, n, 0); +} + +static inline void write_data_1(cyg_nand_device *ctx, unsigned char b) +{ + HAL_WRITE_UINT8(NAND_BASE,b); +} + +static inline void write_data_bulk(cyg_nand_device *ctx, const unsigned char *dp, size_t n) +{ + if ( ((CYG_ADDRWORD)dp&3)==0 && (n%4)==0) { + volatile cyg_uint8 *a = (cyg_uint8*) NAND_BASE; + cyg_uint32 *ip = (cyg_uint32*) dp; + cyg_uint32 r; + n /= 4; +#ifdef CYGHWR_HAL_ARM_BIGENDIAN +#define ONEWORD do { *a = (r>>24)&0xff; *a = (r>>16)&0xff; (*a) = (r>>8) & 0xff; (*a) = r & 0xff; } while(0) +#else +#define ONEWORD do { *a = r & 0xff; *a = (r>>8) & 0xff; *a = (r>>16)&0xff; *a = (r>>24)&0xff; } while(0) +#endif + while (n) { + r = *(ip++); + ONEWORD; + --n; + } +#undef ONEWORD + } else + HAL_WRITE_UINT8_VECTOR(NAND_BASE, dp, n, 0); +} + + +/* READY line handling and fallback ================================ */ + +// Forward defs: +/* Waits either for the !BUSY line to signal that the device is finished, + or for the prescribed amount of time. + * wait_init specifies the time in microseconds to wait to ensure that + BUSY is asserted. + * wait_fallback specifies the worst-case time to wait (from the spec + sheet; again in microseconds) for the operation to complete. */ +static void wait_ready_or_time(cyg_nand_device *ctx, + size_t wait_init, size_t wait_fallback); + +/* Waits either for the !BUSY line to signal that the device is finished, + * or (if not available) polls the chip by sending the Read Status command + * and waits for (response & mask) to be non-zero. */ +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask); + +#define POLL_INTERVAL 10 /* us */ + +#define POLLCOUNT_COUNTING_LEVEL 7 +#if defined(CYGSEM_IO_NAND_DEBUG_LEVEL) && (CYGSEM_IO_NAND_DEBUG_LEVEL >= POLLCOUNT_COUNTING_LEVEL) +#define REPORT_POLLS +#endif + +/* Case 1: The NAND_RDY line is not connected. ---------------------- */ +#ifndef CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_USE_NAND_RDY + +// fwd def from the k9 driver: +static inline CYG_BYTE read_status(cyg_nand_device *dev); + +static void wait_ready_or_time(cyg_nand_device *ctx, size_t initial, size_t fallback) +{ + NAND_CHATTER(8, ctx, "Waiting %d us for operation\n", initial+fallback); + HAL_DELAY_US(initial+fallback); +} + +static void wait_ready_or_status(cyg_nand_device *dev, CYG_BYTE mask) +{ + // The Ready line won't be ready for at least tWB (100ns), so out of + // paranoia we'll wait at least that long before reading Status. + + k9_WAIT_tWB(); // this (1us) is overkill + +#ifdef REPORT_POLLS + int polls=0; +#endif + int sta; + do { + sta = read_status(dev); + HAL_DELAY_US(POLL_INTERVAL); +#ifdef REPORT_POLLS + ++polls; +#endif + } while (!(sta & mask)); +#ifdef REPORT_POLLS + NAND_CHATTER(8, dev, "wait_status: pollcount %d\n",polls); +#endif +} + +#else // CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_USE_NAND_RDY +/* Case 2: The NAND_RDY line *is* connected. ------------------------ */ + +// Common code + +/* Polls the !BUSY line. Returns 1 if ready, 0 if busy. */ +static inline int is_chip_ready(cyg_nand_device *ctx) +{ + cyg_uint32 rv; + HAL_READ_UINT32( + CYGARC_HAL_LPC24XX_REG_FIO_BASE + CYGARC_HAL_LPC24XX_REG_FIO2PIN, + rv); + rv = rv & (1<<12); + return rv; +} + +static void wait_ready_polled(cyg_nand_device *ctx); + +# ifdef CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_NAND_RDY_USE_INTERRUPT +/* Case 2A: We are using sleep+interrupt wherever possible. */ + +# define NAND_RDY_VECTOR CYGNUM_HAL_INTERRUPT_EINT2 +# define NAND_RDY_PRIO 12 + +/* Sleeps until woken by interrupt on the READY/!BUSY line. + * Obviously, this doesn't work (in fact is illegal) if the scheduler + * isn't running, so we fall back to polling the READY line in that case + * (see wait_ready below). */ +static void wait_ready_interrupt(cyg_nand_device *ctx) +{ + GET_MYPRIV(ctx,priv); + cyg_drv_mutex_lock(&priv->cvmux); + cyg_drv_dsr_lock(); + priv->ready = 0; + NAND_CHATTER(8, ctx, "sleep for busy\n"); + cyg_drv_interrupt_unmask(NAND_RDY_VECTOR); + while (!priv->ready) + cyg_drv_cond_wait(&priv->cv); + cyg_drv_interrupt_mask(NAND_RDY_VECTOR); + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&priv->cvmux); +} + +static +cyg_uint32 nand_rdy_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + if (vector != NAND_RDY_VECTOR) return 0; + cyg_drv_interrupt_acknowledge(vector); + return CYG_ISR_HANDLED|CYG_ISR_CALL_DSR; +} + +static +void nand_rdy_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + struct _mypriv *priv = CAST_MYPRIV(data); + priv->ready=1; + cyg_drv_cond_broadcast(&priv->cv); +} + +static void wait_ready(cyg_nand_device *ctx) +{ + int scheduler_off= (cyg_thread_self() == cyg_thread_idle_thread()); + if (scheduler_off) { + NAND_CHATTER(7, ctx, "Polling as scheduler is off\n"); + k9_WAIT_tWB(); + wait_ready_polled(ctx); + } else { + wait_ready_interrupt(ctx); + } +} + +/* Interrupt mode has high overheads (several hundred us). + * For quick operations - page reading @ 25us and certain reset cases - + * it's not worth it on this board, so we just hang around for the + * prescribed time. + */ +#define WAIT_MIN_INTERRUPTMODE_THRESHOLD 400 /* useconds */ + +static void wait_ready_or_time(cyg_nand_device *ctx, + size_t wait_init, size_t wait_fallback) +{ + /* Page reading is very quick (25us), so it's not worth the + * overhead of interrupt mode. */ + if (wait_fallback > WAIT_MIN_INTERRUPTMODE_THRESHOLD) { + wait_ready(ctx); + } else { + HAL_DELAY_US(wait_init); + wait_ready_polled(ctx); + } +} + +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask) +{ + /* These ops are page programming (300-700us) block erase (2-3ms), + * so if interrupt mode is enabled, we'll use it. */ + wait_ready(ctx); +} + + +# define INITHOOK ea_plf_init_interrupt +static int ea_plf_init_interrupt(cyg_nand_device *ctx) +{ + GET_MYPRIV(ctx,priv); + + // Direction -> input + tweak_pin_register( + CYGARC_HAL_LPC24XX_REG_FIO_BASE + CYGARC_HAL_LPC24XX_REG_FIO2DIR, + 1 << 12, 0); + + // Function -> EINT2 + tweak_pin_register( + CYGARC_HAL_LPC24XX_REG_PIN_BASE + CYGARC_HAL_LPC24XX_REG_PINSEL4, + 3 << 24, 1 << 24); + + // Mask -> pin active + tweak_pin_register( + CYGARC_HAL_LPC24XX_REG_FIO_BASE + CYGARC_HAL_LPC24XX_REG_FIO2MASK, + 1 << 12, 0); + + cyg_drv_mutex_init(&priv->cvmux); + cyg_drv_cond_init(&priv->cv, &priv->cvmux); + + cyg_interrupt_configure(NAND_RDY_VECTOR, false /* edge triggered */, true /* high */); + cyg_drv_interrupt_create(NAND_RDY_VECTOR, NAND_RDY_PRIO, (cyg_addrword_t)priv, nand_rdy_ISR, nand_rdy_DSR, &priv->inthdl, &priv->intr); + cyg_drv_interrupt_attach(priv->inthdl); + cyg_drv_interrupt_mask(NAND_RDY_VECTOR); + return 0; +} + +# else +/* Case 2B: We are never using sleep+interrupt. */ + +static void wait_ready_or_time(cyg_nand_device *ctx, + size_t wait_init, size_t wait_fallback) +{ + HAL_DELAY_US(wait_init); + wait_ready_polled(ctx); +} + +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask) +{ + k9_WAIT_tWB(); + wait_ready_polled(ctx); +} + +# define INITHOOK ea_plf_init_nointerrupt +static inline int ea_plf_init_nointerrupt(cyg_nand_device *ctx) +{ + // Direction -> input + tweak_pin_register( + CYGARC_HAL_LPC24XX_REG_FIO_BASE + CYGARC_HAL_LPC24XX_REG_FIO2DIR, + 1<<12, 0); + + // Function -> GPIO + tweak_pin_register( + CYGARC_HAL_LPC24XX_REG_PIN_BASE + CYGARC_HAL_LPC24XX_REG_PINSEL4, + 3<<24, 0); + + // Mask -> pin active + tweak_pin_register( + CYGARC_HAL_LPC24XX_REG_FIO_BASE + CYGARC_HAL_LPC24XX_REG_FIO2MASK, + 1<<12, 0); + return 0; + (void)ctx; +} + +# endif + +/* Polling loop, does not return until the chip is READY. + * Callers should themselves wait for tWB or other initial time + * to ensure that READY is deasserted. */ +static void wait_ready_polled(cyg_nand_device *ctx) +{ +#ifdef REPORT_POLLS + int polls=0; +#endif +#ifdef CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_NAND_RDY_USE_INTERRUPT + cyg_drv_interrupt_unmask(NAND_RDY_VECTOR); +#endif + while (0==is_chip_ready(ctx)) { + HAL_DELAY_US(POLL_INTERVAL); +#ifdef REPORT_POLLS + ++polls; +#endif + } +#ifdef CYGHWR_HAL_ARM_LPC2XXX_EA_LPC2468_NAND_RDY_USE_INTERRUPT + cyg_drv_interrupt_mask(NAND_RDY_VECTOR); +#endif +#ifdef REPORT_POLLS + NAND_CHATTER(8, ctx, "!BUSY: pollcount %d\n",polls); +#endif +} + +#endif // USE_INTERRUPT ? + +static int k9_plf_init(cyg_nand_device *dev) +{ + //GET_MYPRIV(dev,priv); + + // Default platform EMC timings on this board are a bit off for + // efficient use of the NAND. + + unsigned ns_per_cclk = 1 + 1000000000 / CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED; + + // NB! These figures are interpreted from the K9 datasheet. + // WaitOEN: No delay required + HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_EMC_BASE + CYGARC_HAL_LPC24XX_REG_EMCS_WAITO_EN1, 0); + + // WaitRead: 25ns (EMC delays for CCLK * (1+n) ) + unsigned waitread = 25 / ns_per_cclk; // +1 to round up, -1 to account for the implicit CCLK + HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_EMC_BASE + CYGARC_HAL_LPC24XX_REG_EMCS_WAITRD1, waitread); + + // WaitWEN: No delay required, use the shortest that the EMC allows + HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_EMC_BASE + CYGARC_HAL_LPC24XX_REG_EMCS_WAITW_EN1, 0); + // WaitWrite: 25ns (EMC delays for CCLK * (2+n) ) + unsigned waitwrite = 25 / ns_per_cclk; // +1 to round up, -2 to account for the implicit 2CCLK, but don't underflow... + if (waitwrite != 0) --waitwrite; + HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_EMC_BASE + CYGARC_HAL_LPC24XX_REG_EMCS_WAITWR1, waitwrite); + + // WaitTurn: 10ns (EMC delays for CCLK * (1+n) ) + unsigned waitturn = 10 / ns_per_cclk; // +1 to round up, -1 to account for the implicit CCLK + HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_EMC_BASE + CYGARC_HAL_LPC24XX_REG_EMCS_WAITTURN1, waitturn); + + +#ifdef INITHOOK + return INITHOOK(dev); +#else + return 0; +#endif +} + +/* Partition support =================================================== + * Without Manual config, developer has to set up the partitions list + * by hand. */ +#ifdef CYGSEM_DEVS_NAND_EA_LPC2468_PARTITION_MANUAL_CONFIG + +static inline int ea_init_manual_partition(cyg_nand_device *dev) +{ +#define PARTITION(i) do { \ + cyg_nand_block_addr \ + base = CYGNUM_DEVS_NAND_EA_LPC2468_PARTITION_ ## i ## _BASE, \ + size = CYGNUM_DEVS_NAND_EA_LPC2468_PARTITION_ ## i ## _SIZE; \ + dev->partition[i].dev = dev; \ + dev->partition[i].first = base; \ + dev->partition[i].last = size ? \ + base + size - 1: (1<<dev->blockcount_bits)-1; \ +} while(0) + +#ifdef CYGPKG_DEVS_NAND_EA_LPC2468_PARTITION_0 + PARTITION(0); +#endif +#ifdef CYGPKG_DEVS_NAND_EA_LPC2468_PARTITION_1 + PARTITION(1); +#endif +#ifdef CYGPKG_DEVS_NAND_EA_LPC2468_PARTITION_2 + PARTITION(2); +#endif +#ifdef CYGPKG_DEVS_NAND_EA_LPC2468_PARTITION_3 + PARTITION(3); +#endif + /* Oh for the ability to write a for-loop in pre-processor, + or a more powerful libcdl ... */ + return 0; +} +#define PARTITIONHOOK ea_init_manual_partition + +#endif // CYGSEM_DEVS_NAND_EA_LPC2468_PARTITION_MANUAL_CONFIG + +static int k9_plf_partition_setup(cyg_nand_device *dev) +{ +#ifdef PARTITIONHOOK + return PARTITIONHOOK(dev); +#else + return 0; +#endif +} + +/* Concurrent access protection ======================================== */ + +// ... is not required on this platform. +// (On some boards, chips might share a chip-select line, CPLD or similar.) + +static inline void k9_devlock(cyg_nand_device *dev) +{ +} + +static inline void k9_devunlock(cyg_nand_device *dev) +{ +} + +/* Putting it all together ... ========================================= */ + +#include <cyg/devs/nand/k9fxx08x0x.inl> + +CYG_NAND_DEVICE(ea_nand, "onboard", &k9f8_funs, &_k9_ea_lpc2468_priv, + &mtd_ecc256_fast, &nand_mtd_oob_64); +
--- a/packages/hal/cortexm/stm32/stm3210e_eval/current/ChangeLog +++ b/packages/hal/cortexm/stm32/stm3210e_eval/current/ChangeLog @@ -1,3 +1,31 @@ +2009-11-13 Ross Younger <wry@ecoscentric.com> + + * src/stm3210e_eval_nand.c: Build fix for minimal configs. + +2009-11-12 Ross Younger <wry@ecoscentric.com> + + * src/stm3210e_eval_nand.c: Add i/o heuristic speed-up. + +2009-11-09 Ross Younger <wry@ecoscentric.com> + + * src/stm3210e_eval_nand.c: Update for nand interface changes. + * cdl/hal_cortexm_stm32_stm3210e_eval.cdl: Add + CYGPKG_HAL_CORTEXM_STM32_STM3210E_EVAL_CFLAGS_{ADD,REMOVE}, + default to -Werror. + +2009-10-28 Ross Younger <wry@ecoscentric.com> + + * src/stm3210e_eval_nand.c: Implement hardware ECC. + Create eccwalk test to test it. + Add a nop to work around an apparent timing issue in the + NAND-specific FSMC setup when optimised. + Implement CYGNUM_HAL_CORTEXM_STM3210E_EVAL_POLL_INTERVAL. + +2009-08-26 Ross Younger <wry@ecoscentric.com> + + * src/stm3210e_eval_nand.c: Added support for onboard NAND chip. + Based on work by Simon Kallweit. + 2009-02-04 Nick Garnett <nickg@ecoscentric.com> * include/pkgconf/mlt_cortexm_stm3210e_eval_rom.ldi:
--- a/packages/hal/cortexm/stm32/stm3210e_eval/current/cdl/hal_cortexm_stm32_stm3210e_eval.cdl +++ b/packages/hal/cortexm/stm32/stm3210e_eval/current/cdl/hal_cortexm_stm32_stm3210e_eval.cdl @@ -233,6 +233,36 @@ cdl_package CYGPKG_HAL_CORTEXM_STM32_STM } } + cdl_component CYGPKG_HAL_CORTEXM_STM32_STM3210E_EVAL_OPTIONS { + display "stm3210e HAL build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building this HAL." + + cdl_option CYGPKG_HAL_CORTEXM_STM32_STM3210E_EVAL_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "-Werror" } + description " + This option modifies the set of compiler flags + for building this HAL. These flags are used + in addition to the set of global flags." + } + cdl_option CYGPKG_HAL_CORTEXM_STM32_STM3210E_EVAL_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags + for building this HAL. These flags are + removed from the set of global flags if + present." + } + } + cdl_option CYGSEM_HAL_ROM_MONITOR { display "Behave as a ROM monitor" flavor bool @@ -328,4 +358,79 @@ cdl_package CYGPKG_HAL_CORTEXM_STM32_STM files." } + cdl_component CYGHWR_HAL_CORTEXM_STM3210E_EVAL_NAND { + display "STM3210E EVAL NAND support" + parent CYGPKG_IO_NAND + active_if CYGPKG_IO_NAND + implements CYGHWR_IO_NAND_DEVICE + requires CYGPKG_DEVS_NAND_ST_NANDXXXX3A + requires { (CYGPKG_REDBOOT && CYGPKG_FS_YAFFS) implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x20000) } + + compile -library=libextras.a stm3210e_eval_nand.c + description " + This option enables support for the on-board ST NAND flash chip." + + cdl_option CYGHWR_HAL_CORTEXM_STM3210E_EVAL_RB_ON_INT2 { + display "Use NAND_RB line" + flavor bool + default_value 0 + description " + The STM3210E board provides a jumper, JP7, which + routes the NAND ready/busy signal to either the + WAIT line (pins 1-2, the default as shipped), or to + FSMC_INT2 (pins 2-3). You must set + this option if the jumper is in the FSMC_INT2 position; + if you do not, the results are undefined. + (In WAIT mode, the FSMC automatically stalls further + accesses until the NAND signals it is ready: this is + code-size-efficient, but may cause problems with a + multi-threaded application.) + " + } + + cdl_option CYGNUM_HAL_CORTEXM_STM3210E_EVAL_POLL_INTERVAL { + display "Chip polling interval (us)" + flavor data + active_if CYGHWR_HAL_CORTEXM_STM3210E_EVAL_RB_ON_INT2 + default_value 10 + legal_values 1 to 1000 + description " + If the NAND_RB line is routed to INT2, the driver polls + that line whilst waiting for the chip to signal + that it has completed an operation. + This setting is the interval - in microseconds - the + NAND driver will sleep for during each wait cycle. + Lower values improve responsiveness slightly, at the cost + of stealing CPU time from any other threads which may be + running." + } + + # Manual configuration of NAND partitions. + # We currently only provide manual config. + + cdl_component CYGSEM_DEVS_NAND_STM3210E_EVAL_PARTITION_MANUAL_CONFIG { + display "Manual partition configuration" + flavor bool + default_value 1 + description " + Set in order to use CDL to manually configure the + partitions of the ST STM3210E EVAL on-board NAND." + + set ::partition_device "STM3210E_EVAL" + script manual_partition.cdl + } + } + + cdl_option CYGPKG_HAL_CORTEXM_STM32_STM3210E_EVAL_TESTS { + display "STM3210E tests" + flavor data + no_define + calculated { + ( CYGHWR_HAL_CORTEXM_STM3210E_EVAL_NAND ? "tests/eccwalk " : "") + } + + description " + This option specifies the set of tests for the STM3210E HAL." + } + }
new file mode 100644 --- /dev/null +++ b/packages/hal/cortexm/stm32/stm3210e_eval/current/cdl/manual_partition.cdl @@ -0,0 +1,124 @@ +# ==================================================================== +# +# manual_partition.cdl +# +# NAND device manual partition logic +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 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): wry +# Date: 2009-03-10 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +# This file can be used by drivers to implement manual CDL-driven +# partition config. +# +# To use, create a cdl_component with an appropriate name; +# make it boolean or otherwise selectable (you might for example want +# to turn it off, or pick partitioning strategy from a drop-down list), +# then choose and set a name-fragment for your device before including +# this script file along these lines: +# +# set ::partition_device "SYNTH" +# script manual_partition.cdl +# +# For a full example, see the synthetic NAND device. + + +####################################################### + +# Partition table support + +# Every NAND board driver has to decide how it will determine the +# NAND partition layout. In a simple case, there might be just +# a single partition covering the whole chip. Alternatively, +# the driver could read a partition table during _devinit, or +# the partition layout might be hard-wired (e.g. to inter-operate +# with some other fixed code). + +### +# Unfortunately, it is not currently possible within CDL to +# directly access the value of CYGNUM_NAND_MAX_PARTITIONS in a +# Tcl loop, so we cannot automatically have the second argument +# to this for loop be { $::part < CYGNUM_NAND_MAX_PARTITIONS } . +# The best we can do is pick an arbitrary number - we'll choose 4, +# because that's the same as the default CYGNUM_NAND_MAX_PARTITIONS, +# and put only that many in the loop. The current limitations of +# also mean that we have to manually check for each of the four +# partitions in C - so if you edit the number 4 below, be sure +# to tweak the corresponding macro use which makes use of it! +# +# (Four ought to be enough for everybody, shouldn't it?) +### + +for { set ::part 0 } { $::part < 4 } { incr ::part } { + cdl_option CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] { + active_if $::part < CYGNUM_NAND_MAX_PARTITIONS + display "Configure partition [set ::part]" + flavor bool + default_value [set ::part] == 0 + description " + Set in order to manually configure partition [set ::part] + in CDL." + } + + cdl_option CYGNUM_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part]_BASE { + display "Partition [set ::part] base block address" + active_if CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] == 1 + flavor data + legal_values 0 to 0x7fffffff + default_value 0 + description " + The address (number) of the eraseblock at which + partition [set ::part] begins." + } + + cdl_option CYGNUM_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part]_SIZE { + display "Partition [set ::part] size in blocks" + active_if CYGPKG_DEVS_NAND_[set ::partition_device]_PARTITION_[set ::part] == 1 + flavor data + legal_values 0 to 0x7fffffff + default_value 0 + description " + The size of partition [set ::part], expressed + in eraseblocks. A value of 0 is special and + consumes all the remaining space on the device." + } +} +# / for loop for partitions.
--- a/packages/hal/cortexm/stm32/stm3210e_eval/current/src/stm3210e_eval_misc.c +++ b/packages/hal/cortexm/stm32/stm3210e_eval/current/src/stm3210e_eval_misc.c @@ -94,7 +94,7 @@ CYGHWR_HAL_STM32_RCC_APB2ENR_IOPD | CYGHWR_HAL_STM32_RCC_APB2ENR_IOPE | CYGHWR_HAL_STM32_RCC_APB2ENR_IOPF | - CYGHWR_HAL_STM32_RCC_APB2ENR_IOPG ); + CYGHWR_HAL_STM32_RCC_APB2ENR_IOPG); // Set all unused GPIO lines to input with pull down to prevent // them floating and annoying any external hardware.
new file mode 100644 --- /dev/null +++ b/packages/hal/cortexm/stm32/stm3210e_eval/current/src/stm3210e_eval_nand.c @@ -0,0 +1,499 @@ +//============================================================================= +// +// stm3210e_eval_nand.c +// +// Cortex-M3 STM3210E EVAL NAND setup +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation +// +// 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): Simon Kallweit, Ross Younger +// Date: 2009-06-30 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/hal_cortexm_stm32_stm3210e_eval.h> + +#include <cyg/infra/cyg_ass.h> + +#include <cyg/nand/nand_device.h> +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/hal_diag.h> +#include <cyg/hal/drv_api.h> + +#include <cyg/devs/nand/nandxxxx3a.h> + +/* Private structs. We need one nandxxxx3a_priv (and one of our privs) per + * instance of the chip. */ + +struct _mypriv { + char dummy; // not currently used +}; + +static struct _mypriv _stm3210_nand_priv; + +#define CAST_MYPRIV(x) ((struct _mypriv *) (x)) +#define CAST_NANDPRIV(x) ((struct nandxxxx3a_priv *) (x)) +#define GET_MYPRIV(dev,var) struct _mypriv * var = CAST_MYPRIV(CAST_NANDPRIV((dev)->priv)->plat_priv); + +/* We could use 'priv' to supply the NAND addresses. This might be + * useful if there were multiple chips on a board, but for simplicity + * we're going to hard-wire it meantime. */ +#define NAND_BASE CYGHWR_HAL_STM32_FSMC_BANK2_BASE +#define NAND_CMD (NAND_BASE | CYGHWR_HAL_STM32_FSMC_BANK_CMD) +#define NAND_ADDR (NAND_BASE | CYGHWR_HAL_STM32_FSMC_BANK_ADDR) + +/* Where can we read the Ready/!Busy signal? */ +#ifdef CYGHWR_HAL_CORTEXM_STM3210E_EVAL_RB_ON_INT2 +# define GPIO_NAND_RB_PIN CYGHWR_HAL_STM32_GPIO(G, 6, IN, PULLUP) // if JP7 2-3 +#else +# define GPIO_NAND_RB_PIN CYGHWR_HAL_STM32_GPIO(D, 6, IN, PULLUP) // if JP7 1-2 +#endif + +/* CHIP OPERATIONS ================================================= */ + +/* On this board, the memory controller is well set up, so we don't need + * to worry about timings for most operations. */ + +static inline void write_cmd(cyg_nand_device *ctx, unsigned char cmd) +{ + HAL_WRITE_UINT8(NAND_CMD, cmd); +} + +static inline void write_addrbytes(cyg_nand_device *ctx, CYG_BYTE *bytes, size_t n) +{ + HAL_WRITE_UINT8_VECTOR(NAND_ADDR, bytes, n, 0); +} + +static inline unsigned char read_data_1(cyg_nand_device *ctx) +{ + unsigned char b; + HAL_READ_UINT8(NAND_BASE, b); + return b; +} + +static inline void read_data_bulk(cyg_nand_device *ctx, unsigned char *dp, size_t n) +{ + // Most of the time, we expect to be dealing with word-aligned + // multiples of 4 bytes, so optimise for that case. + if ( ((CYG_ADDRWORD)dp&3)==0 && (n%4)==0) { + volatile cyg_uint8 const *a = (cyg_uint8*) NAND_BASE; + cyg_uint32 *ip = (cyg_uint32*) dp; + cyg_uint32 r; + n /= 4; +#if (CYGINT_HAL_CORTEXM_BIGENDIAN == 1) +#define ONEWORD do { r = (*a) << 24; r |= (*a) << 16; r |= (*a) << 8; r |= *a; } while(0) +#else +#define ONEWORD do { r = *a; r |= (*a) << 8; r |= (*a) << 16; r |= (*a) << 24; } while(0) +#endif + while (n) { + ONEWORD; + *(ip++) = r; + --n; + } +#undef ONEWORD + } else + HAL_READ_UINT8_VECTOR(NAND_BASE, dp, n, 0); +} + +static inline void write_data_1(cyg_nand_device *ctx, unsigned char b) +{ + HAL_WRITE_UINT8(NAND_BASE,b); +} + +static inline void write_data_bulk(cyg_nand_device *ctx, const unsigned char *dp, size_t n) +{ + if ( ((CYG_ADDRWORD)dp&3)==0 && (n%4)==0) { + volatile cyg_uint8 *a = (cyg_uint8*) NAND_BASE; + cyg_uint32 *ip = (cyg_uint32*) dp; + cyg_uint32 r; + n /= 4; +#ifdef CYGHWR_HAL_ARM_BIGENDIAN +#define ONEWORD do { *a = (r>>24)&0xff; *a = (r>>16)&0xff; (*a) = (r>>8) & 0xff; (*a) = r & 0xff; } while(0) +#else +#define ONEWORD do { *a = r & 0xff; *a = (r>>8) & 0xff; *a = (r>>16)&0xff; *a = (r>>24)&0xff; } while(0) +#endif + while (n) { + r = *(ip++); + ONEWORD; + --n; + } +#undef ONEWORD + } else + HAL_WRITE_UINT8_VECTOR(NAND_BASE, dp, n, 0); +} + +/* READY line handling and fallback ================================ */ + +// Forward defs: +/* Waits either for the !BUSY line to signal that the device is finished, + or for the prescribed amount of time. + * wait_init specifies the time in microseconds to wait to ensure that + BUSY is asserted. + * wait_fallback specifies the worst-case time to wait (from the spec + sheet; again in microseconds) for the operation to complete. */ +static void wait_ready_or_time(cyg_nand_device *ctx, + size_t wait_init, size_t wait_fallback); + +/* Waits either for the !BUSY line to signal that the device is finished, + * or (if not available) polls the chip by sending the Read Status command + * and waits for (response & mask) to be non-zero. */ +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask); + +/* Case 1: The NAND_RDY line is not connected. ---------------------- */ +#ifndef CYGHWR_HAL_CORTEXM_STM3210E_EVAL_RB_ON_INT2 + +// fwd def from the chip driver: +static inline CYG_BYTE read_status(cyg_nand_device *dev); + +static void wait_ready_or_time(cyg_nand_device *ctx, size_t initial, size_t fallback) +{ + // With the jumper set to route the BUSY line to FSMC_WAIT, + // the FSMC will stall any attempted accesses to the NAND until the + // chip signals READY. + // On a read operation, the chip asserts BUSY tWHBL (100ns) or tWHALL + // (10ns) after we latch in the last address byte. + // Therefore we will wait the initial time (1us is overkill) to ensure + // it is asserted, but don't have to do anything further here. + cyg_int32 r; + + HAL_DELAY_US(initial); + + CYGHWR_HAL_STM32_GPIO_IN(GPIO_NAND_RB_PIN, &r); + CYG_ASSERTC(r==1); +} + +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask) +{ + // With the jumper set to route the BUSY line to FSMC_WAIT, + // the FSMC will stall any attempted accesses to the NAND until the + // chip signals READY. + // + // Therefore, we should just be able to read_status once and find + // that we stall until the operation has completed; IOW, `polls' + // should be 1 every time. This has been confirmed experimentally. + + st_nand_wait_for_BUSY(); // this (1us) is overkill + int polls=0; + int sta; + do { + sta = read_status(ctx); + HAL_DELAY_US(10); + ++polls; + } while (!(sta & mask)); + NAND_CHATTER(8, ctx, "wait_status: pollcount %d status 0x%02x\n", polls, sta); +} + +#else // CYGHWR_HAL_CORTEXM_STM3210E_EVAL_RB_ON_INT2 +/* Case 2: The RB line is connected to INT2. ------------------------ */ + +// Common code + +/* Polls the !BUSY line. Returns 1 if ready, 0 if busy. */ +static inline int is_chip_ready(struct _mypriv *ctx) +{ + cyg_int32 rv; + CYGHWR_HAL_STM32_GPIO_IN(GPIO_NAND_RB_PIN, &rv); + return rv; +} + +/* Polling loop, does not return until the chip is READY */ +static void wait_ready_polled(cyg_nand_device *ctx) +{ + int polls=0; + GET_MYPRIV(ctx, priv); + while (0==is_chip_ready(priv)) { + HAL_DELAY_US(CYGNUM_HAL_CORTEXM_STM3210E_EVAL_POLL_INTERVAL); + ++polls; + } + NAND_CHATTER(8, ctx, "!BUSY: pollcount %d\n",polls); +} + +/* TODO: Code to achieve interrupt-driven sleep, as opposed to polling, + * would go here, enabled by its own CDL option. + * At the time of writing we have been unable to get this to work + * properly; the interrupt controller doesn't seem to detect the + * movement of the NAND RB line. */ + +static void wait_ready_or_time(cyg_nand_device *ctx, + size_t wait_init, size_t wait_fallback) +{ + wait_ready_polled(ctx); +} + +static void wait_ready_or_status(cyg_nand_device *ctx, CYG_BYTE mask) +{ + wait_ready_polled(ctx); +} + +#endif // ..._RB_ON_INT2 + +static int nandxxxx3a_plf_init(cyg_nand_device *dev) +{ + CYG_ADDRESS base; + cyg_uint32 reg; + + // Setup CLE, ALE, D0..D3, NOE, NWE, NCE2 pins + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D, 0, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D, 1, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D, 4, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D, 5, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D, 7, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D,11, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D,12, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D,14, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(D,15, OUT_50MHZ, AOPP)); + + // Setup D4..D7 pins + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(E, 7, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(E, 8, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(E, 9, OUT_50MHZ, AOPP)); + CYGHWR_HAL_STM32_GPIO_SET(CYGHWR_HAL_STM32_GPIO(E,10, OUT_50MHZ, AOPP)); + + // Setup the relevant Ready/!Busy inputs as GPIO + CYGHWR_HAL_STM32_GPIO_SET(GPIO_NAND_RB_PIN); + + // Setup FSMC for NAND + base = CYGHWR_HAL_STM32_FSMC; + reg = 0x01020301; + //reg = 0x0f0f0f0f; + HAL_WRITE_UINT32(base + CYGHWR_HAL_STM32_FSMC_PMEM2, reg); + HAL_WRITE_UINT32(base + CYGHWR_HAL_STM32_FSMC_PATT2, reg); + reg = + CYGHWR_HAL_STM32_FSMC_PCR_PWAITEN | + CYGHWR_HAL_STM32_FSMC_PCR_PTYP_NAND | + CYGHWR_HAL_STM32_FSMC_PCR_PWID_8 | + CYGHWR_HAL_STM32_FSMC_PCR_TCLR(0) | + CYGHWR_HAL_STM32_FSMC_PCR_TAR(0) | + CYGHWR_HAL_STM32_FSMC_PCR_ECCPS_512; + HAL_WRITE_UINT32(base + CYGHWR_HAL_STM32_FSMC_PCR2, reg); + reg |= CYGHWR_HAL_STM32_FSMC_PCR_PBKEN; + HAL_WRITE_UINT32(base + CYGHWR_HAL_STM32_FSMC_PCR2, reg); + + /* Having just twiddled the FSMC, if we immediately try to talk to + * the NAND we sometimes (pretty reliably via certain code paths + * when compiled with -O2, it seems) die with a SIGBUS. + * This seemingly ineffectual talisman (which, incidentally, + * first manifested itself as "volatile int i = 42;" is all that's + * needed to perturb it away. */ + asm("nop"); + +#ifdef INITHOOK + INITHOOK(dev); +#endif + + return 0; +} + +/* Partition support =================================================== + * Without Manual config, developer has to set up the partitions list + * by hand. */ +#ifdef CYGSEM_DEVS_NAND_STM3210E_EVAL_PARTITION_MANUAL_CONFIG + +static inline int stm3210e_init_manual_partition(cyg_nand_device *dev) +{ +#define PARTITION(i) do { \ + cyg_nand_block_addr \ + base = CYGNUM_DEVS_NAND_STM3210E_EVAL_PARTITION_ ## i ## _BASE, \ + size = CYGNUM_DEVS_NAND_STM3210E_EVAL_PARTITION_ ## i ## _SIZE; \ + dev->partition[i].dev = dev; \ + dev->partition[i].first = base; \ + dev->partition[i].last = size ? \ + base + size - 1: (1<<dev->blockcount_bits)-1; \ +} while(0) + +#ifdef CYGPKG_DEVS_NAND_STM3210E_EVAL_PARTITION_0 + PARTITION(0); +#endif +#ifdef CYGPKG_DEVS_NAND_STM3210E_EVAL_PARTITION_1 + PARTITION(1); +#endif +#ifdef CYGPKG_DEVS_NAND_STM3210E_EVAL_PARTITION_2 + PARTITION(2); +#endif +#ifdef CYGPKG_DEVS_NAND_STM3210E_EVAL_PARTITION_3 + PARTITION(3); +#endif + /* Oh for the ability to write a for-loop in pre-processor, + or a more powerful libcdl ... */ + return 0; +} + +#endif // CYGSEM_DEVS_NAND_STM3210E_EVAL_PARTITION_MANUAL_CONFIG + +static int nandxxxx3a_plf_partition_setup(cyg_nand_device *dev) +{ +#ifdef CYGSEM_DEVS_NAND_STM3210E_EVAL_PARTITION_MANUAL_CONFIG + return stm3210e_init_manual_partition(dev); +#else + return 0; +#endif +} + +/* Concurrent access protection ======================================== */ + +// ... is not required on this platform. +// (On some boards, chips might share a chip-select line, CPLD or similar.) + +static inline void nandxxxx3a_devlock(cyg_nand_device *dev) +{ +} + +static inline void nandxxxx3a_devunlock(cyg_nand_device *dev) +{ +} + +/* Hardware ECC ======================================================== */ +// TODO This could live in the variant HAL? + +static void stm3210e_ecc_init(cyg_nand_device *dev) +{ + cyg_uint32 cur; + CYG_ADDRWORD reg = CYGHWR_HAL_STM32_FSMC + CYGHWR_HAL_STM32_FSMC_PCR2; + + HAL_READ_UINT32(reg, cur); + cur |= CYGHWR_HAL_STM32_FSMC_PCR_ECCEN; + HAL_WRITE_UINT32(reg, cur); +} + +static void stm3210e_ecc_calc(cyg_nand_device *dev, const CYG_BYTE *dat, CYG_BYTE *ecc) +{ + cyg_uint32 code,set; + CYG_ADDRWORD eccr= CYGHWR_HAL_STM32_FSMC + CYGHWR_HAL_STM32_FSMC_ECCR2, + ctrr= CYGHWR_HAL_STM32_FSMC + CYGHWR_HAL_STM32_FSMC_PCR2; + HAL_READ_UINT32(eccr, code); + code = ~code; // So an all-0xFF page has an ECC of 0xFF + + ecc[0] = code & 0xFF; + ecc[1] = (code >> 8) & 0xFF; + ecc[2] = (code >>16) & 0xFF; + // The resultant ordering is therefore: + // byte 0: P8, P4, P2, P1 pairs (P1 at LSB) + // byte 1: P128, P64, P32, P16 + // byte 2: P2048, P1024, P512, P256 + + HAL_READ_UINT32(ctrr, set); + set &= ~CYGHWR_HAL_STM32_FSMC_PCR_ECCEN; + HAL_WRITE_UINT32(ctrr, set); +} + +static int stm3210e_ecc_repair(cyg_nand_device *dev, + CYG_BYTE *dat, size_t nbytes, + CYG_BYTE *read_ecc, const CYG_BYTE *calc_ecc) +{ + unsigned d1, d2, d3; + + d1 = calc_ecc[0] ^ read_ecc[0]; + d2 = calc_ecc[1] ^ read_ecc[1]; + d3 = calc_ecc[2] ^ read_ecc[2]; + + if((d1|d2|d3) == 0) + return 0; // Nothing to do. + + // Can we fix it? 12 bits should be set, and as they're stored + // in adjacent pairs within each byte we can use this neat XOR + // trick to make sure that precisely one bit of each pair is set. + unsigned a, b, c; + a = (d1 ^ (d1 >> 1)) & 0x55; + b = (d2 ^ (d2 >> 1)) & 0x55; + c = (d3 ^ (d3 >> 1)) & 0x55; + + if ((a==b)&&(b==c)&&(c==0x55)) { + // Yes we can ! Figure out the offset. + unsigned byte, bit; + + bit = ( (d1 >> 1) & 1) | // P1 + ( (d1 >> 2) & 2) | // P2 + ( (d1 >> 3) & 4); // and P4. + + byte = ( (d1 >> 7) & 1) | // P8 + ( (d2 >> 0) & 2) | // P16 + ( (d2 >> 1) & 4) | // P32 + ( (d2 >> 2) & 8) | // P64 + ( (d2 >> 3) &16) | // P128 + ( (d3 << 4) &32) | // P256 + ( (d3 << 3) &64) | // P512 + ( (d3 << 2)&128) | // P1024 + ( (d3 << 1)&256); // P2048 + + if (byte < nbytes) + dat[byte] ^= (1<<bit); + + return 1; + } + + // No? Is it an ECC dropout? Count the bits... + unsigned i=0; + while (d1) { + if (d1 & 1) ++i; + d1 >>= 1; + } + while (d2) { + if (d2 & 1) ++i; + d2 >>= 1; + } + while (d3) { + if (d3 & 1) ++i; + d3 >>= 1; + } + if (i==1) { + read_ecc[0] = calc_ecc[0]; + read_ecc[1] = calc_ecc[1]; + read_ecc[2] = calc_ecc[2]; + return 2; + } + // Alas, it is uncorrectable. + return -1; +} + +static CYG_NAND_ECC_ALG_HW(stm3210e_ecc, 512, 3, stm3210e_ecc_init, stm3210e_ecc_calc, stm3210e_ecc_repair); + +// Need to use a slightly modified OOB layout to satisfy nand_lookup's paranoia checks +static const cyg_nand_oob_layout stm3210e_oob = { + .ecc_size = 3, + .ecc = { { .pos=0, .len=3 } }, + /* 3, 6, 7 would be ECC in the Linux MTD world. 4/5 are avoided. */ + .app_size = 8, + .app = { { .pos=3, .len=1 }, { .pos=6, .len=10} }, +}; + +/* Putting it all together ... ========================================= */ + +#include <cyg/devs/nand/nandxxxx3a.inl> + +NANDXXXX3A_DEVICE(stm3210e_nand, "onboard", 512, &_stm3210_nand_priv, + &stm3210e_ecc, &stm3210e_oob); +
new file mode 100644 --- /dev/null +++ b/packages/hal/cortexm/stm32/stm3210e_eval/current/tests/eccwalk.c @@ -0,0 +1,146 @@ +//============================================================================= +// +// eccwalk.c +// +// Walks some sample data through the NAND flash controller to +// check that the ECC computation and repair operate correctly. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-10-27 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/testcase.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/nand/util.h> +#include <cyg/infra/diag.h> +#include <stdio.h> +#include <string.h> + +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#define datasize 512 +unsigned char buf[datasize]; + +#define NAND_BASE CYGHWR_HAL_STM32_FSMC_BANK2_BASE + +void ecc(cyg_nand_device *dev, const char *msg, CYG_BYTE *out) +{ + dev->ecc->init(dev); + + // This is the sneaky bit: write data through the NAND controller + // so the ECC register updates, but not framed by NAND commands i.e. + // not actually affecting the chip. + // This is necessarily board-specific ... + HAL_WRITE_UINT8_VECTOR(NAND_BASE, buf, datasize, 0); + + dev->ecc->calc(dev, 0, 256, out); + diag_printf("%s: ecc=%02x%02x%02x\n", msg, out[0], out[1], out[2]); +} + +const char msg[]="ECC walker"; + +int cyg_user_start(void) +{ + cyg_nand_device *dev; + int i; + CYG_BYTE ecc1[3], ecc2[3]; + + CYG_TEST_INIT(); + CYG_TEST_INFO(msg); + + if (cyg_nanddevtab == &cyg_nanddevtab_end) + CYG_TEST_NA("No NAND devices found"); + + CYG_TEST_CHECK(0==cyg_nand_lookup("onboard", &dev),"lookup failed"); + + // Plan: Start with a buffer full of 0xFF; then, changing one bit + // at a time, compute a fresh ECC and check that the repair code + // does the right thing. + + for (i=0; i<datasize; i++) buf[i]=0xff; + ecc(dev, "all-ff", ecc1); + + + for (i=0; i<8; i++) { + int st; + char msg[] = "bit X"; + buf[0] ^= 1<<i; + msg[4] = '0' + i; + ecc(dev, msg, ecc2); + + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==1); + CYG_ASSERTC(buf[0] == 0xff); + + ecc(dev, msg, ecc2); + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==1); + } + for (i=0; i<9; i++) { + char msg[] = "bytelog X"; + int st; + msg[8] = '0' + i; + buf[1<<i] ^= 1; + ecc(dev, msg, ecc2); + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==1); + CYG_ASSERTC(buf[1<<i] == 0xff); + + ecc(dev, msg, ecc2); + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==1); + } + + int fail=0; + for (i=0; i<datasize; i++) { + if (buf[i] != 0xff) { + ++fail; + diag_printf("buf[%d] == %02x != 0xff\n", i, buf[i]); + } + } + + if (fail) + CYG_TEST_FAIL_FINISH(msg); + else + CYG_TEST_PASS_FINISH(msg); +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/ChangeLog @@ -0,0 +1,183 @@ +2009-11-19 Ross Younger <wry@eCosCentric.com> + + Significant interface change. + * nand.h: Application-facing functions now take partition-relative + addresses, not device-relative addresses. + Rename functions cyg_nand_* -> cyg_nandp_* to reflect this (change the + interface, change the name). + Create helper macros CYG_NAND_PARTITION_N{BLOCKS,PAGES}. + Rename NAND_* macros to CYG_NAND_*. + * tests, utils: Update to new semantics. + * nand.cdl: Declare CYGSEM_IO_NAND_APPINTERFACE_VERSION + - calculated, 2 - and add a tripwire to ensure YAFFS is updated. + * docs/nand.sgml: Updated to suit. + +2009-11-17 Ross Younger <wry@eCosCentric.com> + + * nand.c: Cosmetic messages fix + +2009-11-13 Ross Younger <wry@eCosCentric.com> + + * utils/erasenand.c: Fix fencepost error + * nand_device.h nand.c: Further refine CYGSEM_IO_NAND_USE_BBT, + drop the relevant parts of the struct when not enabled. + * utils/erase_bbt_dangerous.c: Build fix for non-default config + * nand_bbt.c: Fix logic error on initial scan + +2009-11-12 Ross Younger <wry@eCosCentric.com> + + * nand.c: Add timing instrumentation hooks. + * nand.cdl: Add CYGSEM_IO_NAND_INSTRUMENT_TIMING to mediate them. + * misc/timetag_to_csv.pl: Helper perl script for use with them. + +2009-11-09 Ross Younger <wry@eCosCentric.com> + + * nand.h: Rationalise interface: + * read_page: now only reads a whole page and/or its spare. + * read_part_page: Created. Allows part-pages and optionally + not checking ECC. + * write_page: now only writes a whole page and/or its spare. + + nand_ecc.h: Drop earlier attempt to support sub-page ECC. + * tests/readwrite.c: Test out cyg_nand_read_part_page(). + * tests: Update for interface tweak. + * nand_bbt.c: Rationalise BBT finding into one place and fix to + better cope with the situation where only one BBT block had + been written. Cure an internal race. + * nand_ecc_mtd_fast.c: Speed up checking phase. + +2009-11-06 Ross Younger <wry@eCosCentric.com> + + * nand_ecc_mtd_fast.c: Created. Complete rewrite of software + ECC for massive performance boost. In summary, use all 32 bits + of a register at once, and part-unroll the operation. (Also + rewrote the ecc repair function to drop the dependency on the + previous (imported) code. + * tests: Update to suit the above. + * tests/eccequiv.c: Created (used to test new ECC implementation). + +2009-10-28 Ross Younger <wry@eCosCentric.com> + + * nand.cdl, nand.c, nand_bbt.[ch]: CYGSEM_IO_NAND_USE_BBT + implemented (default on). Updated tests and utils to suit. + * nand.cdl: Add convenience options to build the utils as well + as the tests. + * tests/sweccwalk.c: Created (software ECC bit-walker and repair + consistency checks) + * nand.sgml: Updated for the above. Documented ECC algorithm + interface. + * tests/rwbenchmark.c: Have rwbenchmark use randomised test data + and check its work for better validity. + +2009-10-08 Ross Younger <wry@eCosCentric.com> + + * nand_ecc.h, nand.c, nand_ecc_mtd.c: Expand ECC interface + to better allow hardware assistance. + * nand_device.h, nand.cdl: Change function set ("v2"), add cdl marker + * nand.c: Implement v2 read/write, updated devinit + * nand.c, nand_bbt.h: Internally expose "raw" page read/write fns + * nand_oob.c, nand_oob.h: Create packed_{read,write} fns + * nand_bbt.c: Use raw page read/write fns, packed read/write fns + - and sanity test them on startup + * nand.sgml: Document driver interface change. + * rwbenchmark.c: Check that we read the requisite amount of data. + +2009-09-28 Ross Younger <wry@eCosCentric.com> + + * tests: Don't put large arrays on stack. + +2009-08-28 Ross Younger <wry@eCosCentric.com> + + * doc/nand.sgml: Update. Split entries for NAND device drivers out into + their individual driver packages. + * tests: Moved bbt.c and multipagebbt.c into devs/nand/synth/ + +2009-07-28 Ross Younger <wry@eCosCentric.com> + + * utils: Add erasenand.c; build fix erase_bbt_dangerous.c + +2009-07-21 Ross Younger <wry@eCosCentric.com> + + * nand_bbt.c: Fix BBT initialisation bug + +2009-07-17 Ross Younger <wry@eCosCentric.com> + + * nand.sgml: Prep for inclusion in docbuilds + +2009-07-09 Ross Younger <wry@eCosCentric.com> + + * nand_bbt.c: Fix corner case arising from a write failure on a BBT block. + +2009-07-02 Ross Younger <wry@eCosCentric.com> + + * tests: Add rwbenchmark.c + +2009-06-17 Ross Younger <wry@eCosCentric.com> + * Global: Create a per-device lock to remove this burden from drivers. + Retab for consistency with the rest of eCos. + * cdl: Create CYGNUM_NAND_PAGEBUFFER; NAND drivers must impose + requirements on this according to the largest device they support. + Add dependency on stdlib. + * nand.c, util.c: Add more assertions. + * nand_app.h: Renamed to nand.h for consistency with other packages + * nand_bbt.c: Refactor to use the pagebuffer to not be so stack-greedy. + Properly incorporate both on-chip BBTs in case we were interrupted + when writing out. Add more assertions. + * nand_bbt.h: Move BLOCK2PAGEADDR and PAGE2BLOCKADDR to util.h. + Header made internal. + * nand_ecc.h: Rename ECCPERPAGE to CYG_NAND_ECCPERPAGE. + * nand_oob.h: Rename NAND_APPLICATION_OOB to CYG_NAND_APPLICATION_OOB, + similarly for OOB_MAX_ECC_SLOTS and OOB_MAX_APP_SLOTS. + * doc: Linewrap for consistency + * tests: Tweak to make more likely to work in a minimal config. + Move mkvector.c and ar4test.c into misc/. + bbt doesn't mandate synth. + eccdamage moved to synth. + +2009-06-02 Ross Younger <wry@eCosCentric.com> + + * cyg_nand_init: Removed in toto, in favour of a static constructor. + * Global: Replaced all use of diag_printf with new NAND_ERROR macro. + +2009-06-01 Ross Younger <wry@eCosCentric.com> + + * src/util.c include/util.h: Created + +2009-03-02 Ross Younger <wry@eCosCentric.com> + + * New package. NAND flash access library. + +//=========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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#### +//=========================================================================== + +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/cdl/nand.cdl @@ -0,0 +1,287 @@ +# ==================================================================== +# +# nand.cdl +# +# eCos NAND flash library +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 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): wry +# Date: 2009-02-23 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + + +cdl_package CYGPKG_IO_NAND { + display "NAND Flash access library" + parent CYGPKG_IO + include_dir cyg/nand + doc ref/nand.html + description " + This package provides support for NAND flash devices. It provides + both an application and a device interface. Further + platform-specific package(s) are required to implement drivers for + the particular devices present." + + requires CYGINT_ISO_ERRNO_CODES + requires CYGPKG_ISOINFRA + requires CYGPKG_LIBC_STRING + requires CYGINT_ISO_STRING_MEMFUNCS + requires CYGPKG_LIBC_STDLIB + + # If YAFFS is loaded, ensure that is knows how to drive us. + requires ( CYGPKG_FS_YAFFS implies CYGSEM_FS_YAFFS_NAND_APPINTERFACE > 1) + + compile nand.c nand_bbt.c nand_oob.c util.c + compile nand_ecc_mtd.c + compile nand_ecc_mtd_fast.c + compile -library=libextras.a nandinit.cxx + + cdl_option CYGSEM_IO_NAND_APPINTERFACE_VERSION { + display "NAND application interface version" + flavor data + calculated 2 + description "The current version of the application + interface provided by + the NAND layer. As the NAND device interface evolves, this + version number will be incremented; applications may require + that the layer provide a certain level in order + to function correctly." + } + + cdl_option CYGSEM_IO_NAND_INTERFACE_VERSION { + display "NAND device interface version" + flavor data + calculated 2 + description "The current version of the device interface + provided by + the NAND layer. As the NAND device interface evolves, this + version number will be incremented; devices may require + that the infrastructure provide a certain level in order + to function correctly." + } + + cdl_component CYGPKG_IO_NAND_OPTIONS { + display "NAND library build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building the NAND library + flash driver." + + cdl_option CYGPKG_IO_NAND_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "-Werror" } + description " + This option modifies the set of compiler flags for + building the NAND flash library. These flags + are used in addition to the set of global flags." + } + cdl_option CYGPKG_IO_NAND_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the NAND flash library. These flags + are removed from the set of global flags if present." + } + } + + cdl_interface CYGHWR_IO_NAND_DEVICE { + display "Hardware NAND device drivers" + requires { CYGHWR_IO_NAND_DEVICE >= 1 } + description " + This calculated option shows the number of NAND devices on + the current platform. The generic NAND support is disabled + unless at least one device is present." + } + + cdl_component CYGSEM_IO_NAND_DEBUG { + display "NAND debug output" + default_value 1 + description " + The NAND library has the ability to report debugging information + by sending it to a printf-like function. + This option is the master switch for all such output. + " + + cdl_option CYGSEM_IO_NAND_DEBUG_FN_DEFAULT { + display "Global output function" + flavor data + default_value { "cyg_nand_defaultprintf" } + description " + This is the default function to use to send debugging output + from the NAND library. + (It may be overridden by individual device drivers.) + The default value is a wrapper to diag_printf. + " + } + + cdl_option CYGSEM_IO_NAND_DEBUG_LEVEL { + display "Debug chatter level" + flavor data + legal_values 0 to 9 + default_value 1 + description " + This option configures the degree to which the NAND code will + print status messages as various operations are undertaken. + Setting it to zero disables the status chatter altogether. + Messages, when enabled, are printed using the printf-like + function provided when the library is initialised. + (Note that serious problems are always reported via + the output function, regardless of this setting.)" + compile nand_chatter.c + } + } + + cdl_option CYGSEM_IO_NAND_READONLY { + display "NAND layer is read-only" + flavor bool + default_value 0 + description " + Selecting this option will globally disable all code which + writes to NAND devices." + } + + cdl_option CYGSEM_IO_NAND_USE_BBT { + display "NAND layer uses bad-block tables" + flavor bool + default_value 1 + description " + Select this option to instruct the NAND library to use + a Bad Block Table to keep track of blocks marked bad + at the factory and any bad blocks which may develop during + the life of the device. This is strongly recommended." + } + + cdl_option CYGNUM_NAND_PAGEBUFFER { + display "Largest page size to support" + flavor data + default_value 0 + description " + This package requires a certain amount of RAM to use as a + page buffer from time to time. This value is the + size of that buffer. You should not normally require to + edit this; it is affected by whichever NAND chip driver + packages are present." + } + + cdl_option CYGNUM_NAND_MAX_READ_RETRIES { + display "Automatic read retry limit" + flavor data + default_value 2 + description " + Typical NAND chips may exhibit occasional bit errors, + which may be transient. This library implements + an Error Correcting Code in order to detect and + automatically repair these. If you are unlucky, + a combination of errors may cause an indication of + an uncorrectable error, which would normally be returned to + the caller as EIO. This setting causes the library + to automatically retry a read, up to this many times, + in the hope that the error is transient; + set to 0 if you wish to disable this behaviour." + } + + cdl_option CYGNUM_NAND_MAX_PARTITIONS { + display "Maximum number of partitions on a NAND chip" + flavor data + default_value 4 + legal_values 1 to 0x7fffffff + description " + Within every NAND device there are one or more logical partitions, + akin to partitions on a hard drive. This setting is the + largest number of partitions that the NAND library and + drivers will support. The default, 4, should be enough for + most purposes. (Higher settings consume more RAM at runtime.) + + N.B. This setting does not configure how partitions are defined; + that is set up in the platform HAL." + } + + # We do not currently provide CDL options to switch the choice of + # ECC algorithm, OOB area layout and BBT semantics on and off. + # This could easily be added in future if there was a demand for it. + # Bear in mind that as well as conditioning the code in/out, each + # chip instance must select its own semantics individually (in case + # of multiple devices with different requirements), so there may + # well not be a need for a top-level switch. + + cdl_option CYGBLD_IO_NAND_BUILD_UTILS { + display "Build NAND library utilities" + default_value 0 + no_define + description "If set, builds the NAND library utilities at the + same time as the tests. Beware that misuse of these utilities + can seriously mess up your NAND chip; they should not be + played with lightly." + } + + cdl_option CYGSEM_IO_NAND_INSTRUMENT_TIMING { + display "Instrument NAND call timings" + default_value 0 + description "This option enables timing instrumentation within + the NAND library. It is intended only to assist driver + authors during development. + Normal users should not set this option." + } + + cdl_option CYGBLD_IO_NAND_UTILS { + display "The list of utilities to build." + flavor data + calculated { " utils/erasenand utils/erase_bbt_dangerous" } + no_define + } + + cdl_option CYGPKG_IO_NAND_TESTS { + display "NAND library tests" + flavor data + no_define + calculated { "tests/nandunit tests/readlimits tests/readwrite" + . " tests/rwbenchmark tests/sweccwalk tests/eccequiv" + . (CYGBLD_IO_NAND_BUILD_UTILS ? CYGBLD_IO_NAND_UTILS : "") + } + description "This special option specifies the set of NAND + library tests (and utilities, if enabled) to build." + } + +}
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/doc/.gitignore @@ -0,0 +1,11 @@ +*.html +io-nand-a4.aux +io-nand-a4.log +io-nand-a4.out +io-nand-a4.pdf +io-nand-a4.tex +io-nand-letter.aux +io-nand-letter.log +io-nand-letter.out +io-nand-letter.pdf +io-nand-letter.tex
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/doc/makefile @@ -0,0 +1,54 @@ +#============================================================================= +# +# makefile +# +# For building the synthetic target documentation. +# +#============================================================================= +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 1998, 1999, 2000, 2001, 2002 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 +# Date: 2001-01-11 +#####DESCRIPTIONEND#### +#============================================================================= + +TOPLEVEL := ../../../.. +MAIN_SGML := nand.sgml +MAIN_HTML := io-nand.html +MAIN_PDF := io-nand.pdf +OTHER_SGML := +PICTURES := + +include $(TOPLEVEL)/pkgconf/rules.doc
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/doc/nand.sgml @@ -0,0 +1,1290 @@ + +<!-- {{{ Banner --> + +<!-- =============================================================== --> +<!-- --> +<!-- nand.sgml --> +<!-- --> +<!-- Documentation for the eCos NAND flash access library. --> +<!-- --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> +<!-- =============================================================== --> +<!-- Copyright (C) 2009 eCosCentric Ltd. --> +<!-- This material may be distributed only subject to the terms --> +<!-- and conditions set forth in the Open Publication License, v1.0 --> +<!-- or later (the latest version is presently available at --> +<!-- http://www.opencontent.org/openpub/) --> +<!-- Distribution of the work or derivative of the work in any --> +<!-- standard (paper) book form is prohibited unless prior --> +<!-- permission obtained from the copyright holder --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTEND#### --> +<!-- =============================================================== --> +<!-- #####DESCRIPTIONBEGIN#### --> +<!-- --> +<!-- Author(s): wry --> +<!-- Date: 2009/04/17 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<!-- }}} --> + +<part id="io-nand-overview"> +<title>The eCos NAND Flash Library</title> +<titleabbrev id="io-nand-short">eCos NAND Flash Library</titleabbrev> + +<chapter id="nand-overview-c"> +<title>NAND Library Overview</title> + +<sect1 id="nand-overview1"><title>Description</title> +<para>This is a library which allows NAND flash devices to be accessed +by the eCos kernel and applications. It is analogous to the eCos FLASH +library, but for NAND devices. It exists as a separate library because of +the fundamental differences between the two types of flash memory.</para> + +<para>This library provides the following functionality: +<itemizedlist> +<listitem><para>Interrogation to confirm that the expected device is +present</para></listitem> +<listitem><para>Reading from and writing to flash pages</para></listitem> +<listitem><para>Erasing flash blocks</para></listitem> +<listitem><para>The ability to divide a single device into multiple +partitions, like those of a hard drive</para></listitem> +<listitem><para>Creation and maintenance of a Bad Block Table</para></listitem> +<listitem><para>Use of an Error Correcting Code to detect and correct +single-bit errors, and to detect multiple-bit errors</para></listitem> +<listitem><para>Packing of the ECC and application out-of-band data into +the spare area on the device</para></listitem> +</itemizedlist> +<note><para>The spare area, ECC and bad block table have been +deliberately created with the intention of compatibility with +current versions of the Linux MTD layer. For example, this would +allow a single NAND device to be accessed by RedBoot to load a Linux +kernel, which could then go on to use another partition as its root +filesystem.</para></note> </para> <tip><para>This library is also used +as glue to allow appropriate filesystems to use NAND devices. This +allows more useful higher-level access by applications and RedBoot via +the File I/O and POSIX interfaces. In other words, your application +may not need to invoke this library directly, though of course you +may still have to write a driver for your chip and/or board. +</para></tip> + +<sect2 id="nand-lib-structure"><title>Structure of the library</title> +<para>This library has two principal interfaces: one for +<emphasis>applications</emphasis> to call into it, and another to call +out to the chip-specific <emphasis>drivers</emphasis>. (The chip drivers +themselves then require support from the relevant platform HAL to allow +them to access the physical chip in an appropriate manner for the board - +such as the memory-mapped I/O range to use.)</para> + +<para>The following diagram illustrates the calls from two applications +all the way to an underlying NAND device. Application 1 uses the NAND +library directly, whereas application 2 is using a filesystem and the +eCos File I/O layer.</para> + +<mediaobject> +<imageobject> +<imagedata fileref="nandlib-layout.png" align=center scalefit=1 depth=600> +</imageobject> +<textobject> +<phrase>Library layout diagram</phrase> +</textobject> +</mediaobject> + +</sect2> +<sect2 id="nand-lib-devsupport"><title>Device support</title> +<para>Before this library can be used on a given board, an appropriate +device driver must be created. Each driver is for a particular NAND +part or family of parts; the HAL for each board then instantiates the +relevant driver(s) appropriately with board-specific glue such as the +memory-mapped I/O range to use. Full details on creating a driver are +presented in <xref linkend="nand-devs-writing">.</para> + +<para>There is also a <xref linkend="devs-nand-synth"> for testing purposes, +which is present on the <emphasis>synth</emphasis> target. +</para> +</sect2> +</sect1> +<SECT1 id="nand-danger"> +<TITLE>Danger, Will Robinson! Danger!</TITLE> + +<PARA>Unlike nearly every other aspect of embedded system programming, +getting it wrong with FLASH devices can render your target system +useless. Most targets have a boot loader in the FLASH. Without this +boot loader the target will obviously not boot. So before starting to +play with this library its worth investigating a few things. How do +you recover your target if you delete the boot loader? Do you have the +necessary JTAG cable? Or is specialist hardware needed? Is it even +possible to recover the target boards or must it be thrown into the +rubbish bin? How does killing the board affect your project schedule? +</PARA> + +</SECT1> + + +<sect1 id="nand-nor-diff"><title>Differences between NAND and NOR flash</title> +<para>Most flash devices supported by the eCos Flash library are +categorised as NOR flash. These are fundamentally different from NAND +flash devices, both in terms of the storage cells deep within the chip, +and how they are addressed and used by applications.</para> + +<informaltable frame=topbot pgwide=1> +<tgroup cols=3> +<colspec colname=what> +<colspec colname=nor> +<colspec colname=nand> +<thead> <row> +<entry> Attribute </entry> +<entry> NOR </entry> +<entry> NAND </entry> +</row> </thead> +<tbody> +<row> +<entry>Addressing of data</entry> +<entry>By byte address within the device. Usually expressed as +memory-mapped addresses.</entry> +<entry>By row (page) number. Pages are a power of two; commonly 512 or +2048 bytes. Optimised for reading and writing a page at a time. Sometimes +supports column (byte) addressing, but this library does not expose +such functionality.</entry> +</row> +<row> +<entry>Are direct reads and writes possible? <footnote><para>In +other words, can the application read flash directly as if it +was RAM, or does it have to invoke the driver to copy data in and +out?</para></footnote></entry> +<entry>Usually</entry> +<entry>Not in general, though a few special-case exceptions exist such +as OneNAND devices.</entry> +</row> +<row> +<entry>Erase block size</entry> +<entry>May vary across the chip</entry> +<entry>A fixed number of pages, typically 64</entry> +</row> +<row> +<entry>Out-of-band data </entry> +<entry>Not supported </entry> +<entry>A small number of bytes per page - typically 16 "spare" per 512 +"data" bytes - are usable by the application. They are read, written +and erased at the same time as the "real" page data. </entry> +</row> +<row> +<entry>May factory-bad regions <footnote><para>Regions which were found +during manufacture to be bad and marked in some way - usually by placing +a special code in the Out Of Band area.</para></footnote> exist on the +chip?</entry> +<entry>No </entry> +<entry>Typically up to 20 eraseblocks are marked as factory-bad in +their OOB area. The OS is expected to scan these to create a Bad Block +Table. <footnote><para>Once a BBT exists it can then be used to keep +track of any blocks which fail through wear during the lifetime of the +device.</para></footnote></entry> +</row> +<row> +<entry>May data be rewritten without being erased first?</entry> +<entry>Usually (but only by resetting 1-bits to 0) </entry> +<entry>Usually, on SLC NAND chips; not on MLC chips.</entry> +</row> +<row> +<entry>Error detection and correction</entry> +<entry>Not present</entry> +<entry>Usually automatic. Typically this involves an Error Correcting +Code, automatically calculated and stored in the OOB area, then checked +on read. +</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +<para> Since a NAND chip can in general only be read indirectly, its +contents must be copied to RAM before they can be executed. This means +that the caveats in the eCos FLASH library about disabling interrupts +whilst programming do not apply here, except in special cases such as +OneNAND devices.</para> +</sect1> + +<sect1 id="nand-deployment-notes"><title>Preparing for deployment</title> +<para> +It is generally not recommended to hard-code physical on-NAND locations +in case of factory bad blocks or block failures in the field. +<footnote><para>Usually the first block is guaranteed to be defect free +for a certain number of erase cycles. This tends to be necessary if +bootstrapping the CPU off NAND, and is an obvious exception to this +rule.</para></footnote> Instead it is preferable to set up +<emphasis>partitions</emphasis> on the chip with a generous safety +margin and to store data in a location-independent way. This is +commonly achieved by placing logical tags in the spare area of each +page, or using a log-structured filesystem such as YAFFS. Such +strategies remove the dependence on physical addressing, at the cost of +increased complexity.</para> + +<para>The upshot of this is that you cannot reliably create a simple +binary image to bulk-program in the factory. A more complicated +programming operation is required to take account of your chip +partitions, logical addressing strategy and any bad blocks which +may be encountered during write. +</para> +</sect1> + +</chapter> + +<chapter id="nand-using"> +<title>Using the NAND library</title> + +<para>The eCos NAND library exposes two principal APIs: one for +applications to use and the other to communicate with +device drivers.</para> + +<sect1 id="nand-app-config"><title>Configuring the NAND library</title> +<para>The following configuration options are provided. They affect the +library globally, i.e. across all drivers.</para> + +<variablelist> +<varlistentry><term><constant>CYGPKG_IO_NAND_CFLAGS_ADD</constant></term> +<term><constant>CYGPKG_IO_NAND_CFLAGS_REMOVE</constant></term> +<listitem><para> Allows specific build options to be added to or +removed from the CFLAGS list when building this library.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_IO_NAND_DEBUG</constant></term> +<listitem><para> +This is the master switch for all debug reporting from the library.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_IO_NAND_DEBUG_FN_DEFAULT</constant></term> +<listitem><para> +This is the default function that the library will use when sending +debugging output. It must behave like <function>printf</function>. +The default - <function>cyg_nand_defaultprintf</function> +- is a wrapper to <function>diag_printf</function>.</para> +<note><para>Individual drivers may override this setting in their +<function>devinit</function> routines by overwriting the pointer in +the device struct.</para></note></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_IO_NAND_DEBUG_LEVEL</constant></term> +<listitem><para> +Specifies the verbosity of the NAND library and device drivers. +Ranges from 0 (off) to 9 (incredibly verbose); the default setting is 1. +(Higher values are only likely to be of use during driver development, +if ever.) +When enabled, messages are printed using the per-device printf-like +function (see above).</para> +<note><para>Should a serious problem be encountered it will always +be reported the printf-like function, regardless of this +setting. Such messages may be suppressed altogether by turning +off <constant>CYGSEM_IO_NAND_DEBUG</constant>.</para></note></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_IO_NAND_READONLY</constant></term> +<listitem><para>Globally disables all code which writes to NAND devices. +This may be useful during driver development.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_NAND_MAX_PARTITIONS</constant></term> +<listitem><para>Sets a compile-time limit on the number of partitions +any NAND device may have. The default is 4, which should be enough for +most purposes; unnecessarily setting this higher wastes RAM.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_IO_NAND_USE_BBT</constant></term> +<listitem><para>Globally enables and disables the use of Bad Block Table. + <warning><para>This setting should not be disabled lightly! + It is strongly recommended that you leave this setting enabled unless + you have a very good reason to not use it. It is provided really as a + convenience for allowing developers to recover their NAND from a + confused state. </para></warning> +</para></listitem></varlistentry> +</variablelist> +</sect1> + +<sect1 id="nand-using-app-api"><title>The NAND Application API</title> +<para>All of the functions described here are declared in the header file +<filename><cyg/nand/nand.h></filename>, which should be included +by all users of the NAND library.</para> + +<note><para> Most of the functions in the library are declared +as returning <type>int</type>. <emphasis>Unless otherwise stated, +all functions return 0 for success, or a negative eCos error code if +something went wrong.</emphasis></para></note> + +<sect2 id="nand-app-lookup"><title>Device initialisation and lookup</title> +<para>NAND devices are identified to the library by name. In many cases +there will be only one, commonly named <emphasis>onboard</emphasis>, +but this flexibility allows for easy expansion later without cross-device +confusion.</para> +<note><para>The naming of NAND devices is set up by the code that +instantiates their drivers. Normally this is done by the platform HAL +port.</para></note> + +<programlisting> __externC int cyg_nand_lookup(const char *devname, cyg_nand_device **dev_o);</programlisting> +<para>On success, *dev_o will be set up to point to a +<type>cyg_nand_device</type> struct. On failure, it will not; a return +code of <constant>-ENOENT</constant> signifies that the requested device +name was not found.</para> + +<para> +Applications will hardly, if ever, need to access the +<type>cyg_nand_device</type> structs directly. The following members +and convenience macros are most likely to be of relevance: +<programlisting> +struct _cyg_nand_device_t { +... +cyg_nand_printf pf; // Diagnostic printf-like function for this device to use. May be changed at runtime. +... +size_t page_bits; // log2 of no of regular bytes per page +size_t spare_per_page; // OOB area size in bytes +size_t block_page_bits; // log2 of no of pages per eraseblock +size_t blockcount_bits; // log2 of number of blocks +size_t chipsize_log; // log2 of total chip size in BYTES. +... +}; + +#define CYG_NAND_BYTES_PER_PAGE(dev) (1<<(dev)->page_bits) +#define CYG_NAND_SPARE_PER_PAGE(dev) ((dev)->spare_per_page) +#define CYG_NAND_PAGES_PER_BLOCK(dev) (1<<(dev)->block_page_bits) +#define CYG_NAND_BLOCKCOUNT(dev) (1<<(dev)->blockcount_bits) +#define CYG_NAND_PAGECOUNT(dev) (NAND_BLOCKCOUNT(dev) * NAND_PAGES_PER_BLOCK(dev)) +#define CYG_NAND_CHIPSIZE(dev) (1<<(dev)->chipsize_log) +#define CYG_NAND_APPSPARE_PER_PAGE(dev) ((dev)->oob->app_size) + +</programlisting> +</para> +</sect2> + +<sect2 id="nand-app-addressing"><title>NAND device addressing</title> +<para>NAND devices are arranged as a series of <emphasis>pages</emphasis> +and <emphasis>eraseblocks</emphasis>. The eCos NAND library numbers +pages and eraseblocks sequentially, both starting at 0 and continuing +until the end of the chip. For example, eraseblock 0 might contain pages +0 through 63; eraseblock 1, pages 64 through 127; and so on.</para> +<caution><para>This numbering scheme is independent of the device's +addressing scheme. Take care, particularly when erasing blocks; some +devices and some applications effectively express the location to erase as +a page number (or, in NAND-speak, as the <emphasis>row address</emphasis> +to erase from).</para></caution> + +<warning><para>Most NAND chip manufacturers document restrictions on +the order in which pages may be written to their device. Typically, +individual pages within an eraseblock must be written in sequential +order starting from the first, and random-order writes are prohibited +or unspecified. The eCos NAND library does not attempt to police such +restrictions; if at all unsure, check the spec sheet for the part. You +have been warned! </para></warning> + +<para>NAND devices are widely considered to be arranged as one or +more <emphasis>partitions</emphasis>, and the eCos NAND library +supports this. However, there is no universal scheme for partition +sizes to be supplied to the driver, unlike hard drives which encode +a partition table into their first sector. Partition arrangements are +often implicitly hardcoded, such as by byte address within the device, +though they could be encoded in a "partition table", user-set, or even +variable under software control by some esoteric rules. Therefore, every +device driver is responsible for configuring its partition information +as appropriate for the device, and this might for example appear as CDL +options.</para> +<tip><para>Be sure to read the notes associated with the device driver +to understand how partitions are set up; if no notes are provided, +look in its <function>devinit</function> code.</para></tip> + +<sect3 id="nand-app-partitions"><title>NAND device partitions</title> +<para>After a NAND device has been initialised, its device struct contains +a list of partitions. These are numbered from 0 and may go up to +<constant>CYGNUM_NAND_MAX_PARTITIONS</constant>-1. Before an +application can use the NAND device, it must obtain a partition +context (pointer) with the following call: +<programlisting>__externC cyg_nand_partition* cyg_nand_get_partition(cyg_nand_device *dev, unsigned partno);</programlisting> +</para> + +<note><para>This call returns a pointer to the partition struct, not +an error code. If the given partition number is inactive or invalid, +it returns NULL.</para></note> +</sect3> + +<sect3 id="nand-app-addressing-spare"><title>About the spare area</title> +<para>Every page on the NAND array has a small number of "spare" bytes +associated with it. These are used by the NAND library to store the +page's ECC; whatever is left over may be used by the application for +whatever purposes may suit it.</para> + +<para>Every page has <function>CYG_NAND_APPSPARE_PER_PAGE(dev)</function> +bytes of spare area available to the application. (This amount is implicit +from the driver configuration and cannot change during the lifetime of +a device.) </para> + +<note><para>Application spare bytes are not subject to the ECC. When +reading the spare area data, you must be prepared to cope with the +consequences of the (unlikely) event of a bit drop-out or other +failure.</para></note> </sect3> + +</sect2> + +<sect2 id="nand-app-manipulating"><title>Manipulating the NAND array</title> +<para>Now, finally, given a <type>cyg_nand_partition*</type>, +your application can make use of the NAND array with the following +functions:</para> + +<sect3 id="nand-app-read"><title>Reading data</title> +<programlisting> +__externC int cyg_nand_read_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, void * dest, size_t size, void * spare, size_t spare_size); +</programlisting> + +<blockquote> +<para>Reads a single page and its spare area. The data read from the chip +will be automatically ECC-checked and repaired if necessary. Parameters +are as follows:</para> + +<glosslist> +<glossentry><glossterm><parameter>ctx</parameter></glossterm><glossdef><para>The +partition that data is to be read from.</para></glossdef></glossentry> +<glossentry><glossterm><parameter>page</parameter></glossterm><glossdef><para> +The page to be read, <emphasis>numbered from the start of the partition. +</emphasis>. As a double-check, the library will refuse the +operation with <constant>-ENOENT</constant> if this address is not within +partition <parameter>ctx</parameter>. + <note><para>This was changed in application interface v2; earlier page + and block addresses were device-relative.</para></note> +</para></glossdef></glossentry> +<glossentry><glossterm><parameter>dest</parameter></glossterm><glossdef><para> +Where to put the data. May be NULL, in which case the page data is not +read.</para></glossdef></glossentry> +<glossentry><glossterm><parameter>size</parameter></glossterm><glossdef><para> +The maximum amount of data to read. (In any event, no more than a single +page will be read, but if your application knows it doesn't need the +whole page, you can place a cap here.) </para></glossdef></glossentry> +<glossentry><glossterm><parameter>spare</parameter></glossterm><glossdef><para> +Where to store the application data read from the spare area. This may +be NULL if spare data is not required.</para></glossdef></glossentry> +<glossentry><glossterm><parameter>spare_size</parameter></glossterm><glossdef><para> +The maximum number of bytes to read from the spare area. This will +not be more than <function>CYG_NAND_APPSPARE_PER_PAGE(dev)</function> +bytes.</para></glossdef></glossentry> +</glosslist> + +<para>An error response of <constant>-EIO</constant> means that a +multiple-bit I/O error has occurred in the page data, which the ECC +could not repair. The library stores the data read from the device in +<parameter>*dest</parameter> and <parameter>*spare</parameter> on a +best-effort basis; it should not be relied upon. The application should +take steps to salvage what it can and erase the block as soon as possible.</para> + +</blockquote> +</sect3> + +<sect3 id="nand-app-writing"><title>Writing data</title> +<programlisting> +__externC int cyg_nand_write_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, const void * src, size_t size, const void * spare, size_t spare_size); +</programlisting> + +<blockquote> +<para>Writes a single page and its spare area. The ECC will be computed +and stored automatically. Parameters are as follows:</para> + +<glosslist> +<glossentry><glossterm><parameter>ctx</parameter></glossterm><glossdef><para>The +partition that data is to be written to.</para></glossdef></glossentry> +<glossentry><glossterm><parameter>page</parameter></glossterm><glossdef><para> +The page to be written, <emphasis>numbered from the start of +the partition</emphasis>. As a double-check, the +library will refuse the operation with <constant>-ENOENT</constant> +if this address is not within partition <parameter>ctx</parameter>. +</para></glossdef></glossentry> +<glossentry><glossterm><parameter>src</parameter></glossterm><glossdef><para> +Where to read the data from. May be NULL, in which case the page data +is not written.</para></glossdef></glossentry> +<glossentry><glossterm><parameter>size</parameter></glossterm><glossdef><para> +The amount of data to write. (In any event, no more than a single page +will be written.)</para></glossdef></glossentry> +<glossentry><glossterm><parameter>spare</parameter></glossterm><glossdef><para> +Where to read the data to go into the spare area; it will automatically +be packed around the ECC as necessary. Again, this may be NULL if spare +data is not required.</para></glossdef></glossentry> +<glossentry><glossterm><parameter>spare_size</parameter></glossterm><glossdef><para> +The number of bytes to write to the spare area. This should not be +larger than <function>CYG_NAND_APPSPARE_PER_PAGE(dev)</function>; if it is, +only that many bytes will be stored.</para></glossdef></glossentry> +</glosslist> + +<para> An error response of <constant>-EIO</constant> means that +the page write failed. The application should copy out any data +it wishes to keep from the rest of the eraseblock, then call +<function>cyg_nand_bbt_markbad()</function> to put the block beyond use.</para> +</blockquote></sect3> + +<sect3 id="nand-app-erasing"><title>Erasing blocks</title> + +<programlisting> +__externC int cyg_nand_erase_block(cyg_nand_partition *ctx, cyg_nand_block_addr blk); +</programlisting> + +<blockquote><glosslist> +<glossentry><glossterm><parameter>ctx</parameter></glossterm><glossdef><para>The +partition that data is to be erased from.</para></glossdef></glossentry> +<glossentry><glossterm><parameter>blk</parameter></glossterm><glossdef><para> +The block to be erased, <emphasis>numbered from the start of +the partition</emphasis>. As a double-check, the +library will refuse the operation with <constant>-ENOENT</constant> +if this address is not within partition <parameter>ctx</parameter>. +</para></glossdef></glossentry> +</glosslist> + +<para>An error response of <constant>-EIO</constant> means that the +block erase failed. In this case, the library automatically marks the +block as bad, and the application need take no further action.</para> + +</blockquote> +</sect3> + +<sect3 id="nand-app-manip-commonerrs"><title>Common error returns</title> +<para> The following common error returns may be encountered when +manipulating the NAND array using the above functions:</para> + +<glosslist> +<glossentry><glossterm><constant>-EIO</constant></glossterm><glossdef><para> +The operation could not be completed due to an I/O error. This may require +the application to take further action; check the details provided above +for the call you have just made.</para></glossdef></glossentry> +<glossentry><glossterm><constant>-ENOENT</constant></glossterm><glossdef><para> +The page or block address was not valid for the given +partition.</para></glossdef></glossentry> +<glossentry><glossterm><constant>-EINVAL</constant></glossterm><glossdef><para> +The page (block) address was (within) a block that is marked +bad.</para></glossdef></glossentry> +</glosslist> +</sect3> +</sect2> + +<sect2 id="nand-app-ancillary"><title>Ancillary NAND functions</title> +<para>The following functions are provided to allow applications to interact +with the Bad Block Table:</para> + +<programlisting> +typedef enum { +CYG_NAND_BBT_OK=0, +CYG_NAND_BBT_WORNBAD=1, +CYG_NAND_BBT_RESERVED=2, +CYG_NAND_BBT_FACTORY_BAD=3 +} cyg_nand_bbt_status_t; + +__externC int cyg_nand_bbt_query(cyg_nand_partition *ctx, cyg_nand_block_addr blk); + +__externC int cyg_nand_bbt_markbad(cyg_nand_partition *ctx, cyg_nand_block_addr blk); +</programlisting> + +<para>To determine the status of an eraseblock, use +<function>cyg_nand_bbt_query</function>; this returns an enum from +<type>cyg_nand_bbt_status_t</type> or a negative eCos error code. All +blocks which return a non-0 enum value are considered inaccessible by +applications.</para> + +<para>Occasionally, it is necessary for applications to mark a block +as bad. This most commonly happens when a write operation fails +(see <xref linkend="nand-app-writing"> above). To do this, call +<function>cyg_nand_bbt_markbad</function>; the return is 0 for success, +or a negative eCos error code. <emphasis>As with other calls, blocks +are numbered from 0 at the start of the partition, and internally +translated for the device as appropriate.</emphasis></para> + +<para>Both of these calls may foreseeably return +<constant>-ENOENT</constant> if the given block address was not valid, +or <constant>-EIO</constant> if something awful happened with the on-chip +bad block table. +</para> +</sect2> +</sect1> + +</chapter> + +<chapter id="nand-devs-writing"> +<title>Writing NAND device drivers</title> +<sect1 id="nand-devs-planning"><title>Planning a port</title> + +<para> Before you start, you will need to have sight of appropriate spec +sheets for both the NAND chip and the board into which it is connected, +and you need to know how the chip is to be partitioned.</para> + +<sect2 id="nand-devs-structure"><title>Driver structure and layout</title> +<para> +A typical NAND device driver falls into two parts:</para> +<itemizedlist> +<listitem><para>high-level operations specific to the NAND chip (page +reads and writes); and +</para></listitem> +<listitem><para>board-specific plumbing (sending commands and data to +the chip; reading data back from the chip). +</para></listitem> +</itemizedlist> + +<para> This distinction is important in the interests of code reuse; +the same part may appear on different boards, or indeed multiple times, +but connected differently. It need not be maintained if there are good +reasons not to.</para> + +<para> The <emphasis>NAND library device interface</emphasis> consists +of a C struct, <type>cyg_nand_device</type>, comprising a number of +data fields and function pointers. Each NAND chip to be made available +to the library requires exactly one instance of this struct.</para> + +<tip><para>The <type>cyg_nand_device</type> structure includes a +<structfield>void* priv</structfield> member which is treated +as opaque. The driver may use this member as it sees fit; it is +intended to provide an easy means to identify the NAND array, MMIO +addresses or function pointers to use and so on. Typically this is +used by the chip driver for its own purposes, and includes a further +opaque member for the use of the HAL port. +</para></tip> + +<para>The function pointers in the struct form the driver's high-level +functions; they make use of the low-level functions to talk to the +chip. We present the high-level functions first, although there is no +intrinsic reason to prefer either ordering during driver development.</para> + +<para> The high-level chip-specific functions +are traditionally laid out as an <emphasis>inline +file</emphasis> in an appropriate package in <filename +class=directory>devs/nand/<replaceable>CHIP</replaceable></filename>. +The board-specific functions should normally appear in the platform HAL +and #include the inline. +</para></sect2> + +<sect2 id="nand-devs-partitions"><title>Chip partitions</title> +<para>Before embarking on the port, you should determine how the +NAND array will be partitioned. This is necessarily a board-specific +question, and your layout must accommodate any other software users of +the array. You will need to know either the fixed layout - converted to +eraseblock addresses - or how to determine the layout at initialisation +time.</para> + +<tip><para>It may be worthwhile to set up partitioning by way of some +parameters in your platform's CDL, with sensible defaults, instead of +outright hard-coding the partition layout.</para></tip> + +</sect2> +<sect2 id="nand-devs-locking"><title>Locking against concurrent access</title> +<para> +The eCos NAND library provides per-device locking, to guard against +concurrent access during high-level operations. This support is fully +automatic; drivers need take no action to make use of it.</para> + +<para> This strategy may not be sufficient on all target boards: +sometimes, accessing a NAND chip requires mediation by CPLD or other +device, which must be shared with other NAND chips or even other +peripherals. <emphasis>If this applies, it is the responsibility +of the driver and platform port to provide further locking as +appropriate!</emphasis></para> + +<tip><para>When using mutexes in a driver, one should +use the <emphasis>driver API</emphasis> as defined in +<filename><cyg/hal/drv_api.h></filename> instead of the full kernel +API. This has the useful property that mutex operations are very cheaply +implemented when the eCos kernel is not present, such as when operating +in RedBoot. </para></tip> +</sect2> + +<sect2 id="nand-devs-cdl"> +<title>Required CDL declarations</title> + +<para> +An individual NAND chip driver must declare the largest page +size it supports by means of CDL. This is done with a statement like +the following in its cdl_package stanza:</para> + +<programlisting> +requires ( CYGNUM_NAND_PAGEBUFFER >= 2048 ) +</programlisting> + +<note><para> +This requirement is due to the internal workings of the eCos NAND +library: a buffer is required for certain operations which +manipulate up to a NAND page worth of data, internally to the library. +This is declared once as a global buffer for safety under low-memory +conditions; a page may be too big to use temporary storage on the C stack, +and the NAND library deliberately avoids the use of +<function>malloc</function>.</para> +</note> + +<para> +By convention, a driver package would declare +<constant>CYGPKG_IO_NAND</constant> as its <constant>parent</constant> and use +<filename>cyg/devs/nand</filename> as its <constant>include_dir</constant>, +but there is no intrinsic reason why this should be so.</para> +</sect2> +</sect1> + +<sect1 id="nand-devs-highlevel"> +<title>High-level (chip) functions</title> +<para> The high-level functions provided by the chip driver are +typically created as an <emphasis>inline file</emphasis> providing a +fully-populated <type>cyg_nand_dev_fns_v1</type> struct, instantiated +by the <type>CYG_NAND_FUNS</type> macro. The high-level driver should +not directly read or write to the hardware itself, but instead call into +functions in the low-level driver.</para> + +<para> The form the low-level functions should take is not prescribed; +typically functions will be required to write commands to the device, to +read and write data, and to query any status line which may be present. +The high-level driver should normally provide a header file containing +prototypes for the functions it requires from the low-level driver. +(The low-level source file would provide the low-level functions required, +include the high-level include, then instantiate the combined driver +using the <type>CYG_NAND_DEVICE</type> macro.)</para> + +<para> This source code layout is not intended as a prescription. It +would for example be entirely in order to store pointers to the low-level +functions in a struct and set <structfield>priv</structfield> to point +to that struct, which could be useful in some cases.</para> + +<note><para>The device driver must not call <function>malloc</function> +or otherwise allocate memory; all data should be in the stack or set +as globals. This is because the driver may be required to run within a +minimal eCos configuration.</para></note> + +<para> These functions should all return 0 on success, or a negative +eCos error code. In the event of an error, do <emphasis>not</emphasis> +call back into the NAND library; use the <type>NAND_CHATTER</type> +macro to report, in case a human is watching, and return an error +code. The library will take care of ensuring the correct response to +the application and updating the BBT as necessary.</para> + +<sect2 id="nand-devs-devinit"> +<title>Device initialisation</title> +<programlisting> +static int my_devinit (cyg_nand_device *dev); +</programlisting> + +<para> +The <function>devinit</function> function is the most complex, and +logically one to write first. It is responsible for:</para> +<itemizedlist> +<listitem><para>initialising the device, typically by sending a reset +command; +</para></listitem> +<listitem><para>interrogating the device to confirm its presence and +properties; +</para></listitem> +<listitem><para>setting up the partition table list (see +"Planning a port" above); +</para></listitem> +<listitem><para>setting up mutexes as necessary (see +"Locking against concurrent access" above); +</para></listitem> +<listitem><para>populating the other members of the +<type>cyg_nand_device</type> struct (see below). +</para></listitem> +</itemizedlist> + +<para> Interrogating the device is normally performed by sending a +<emphasis>Read ID</emphasis> command and examining the result, which +typically encodes some or all of the chip parameters.</para> + +<para> Given the similarity between many NAND parts, it may be possible +to write a generic driver to cover all of one or more manufacturer's +parts, or indeed for all ONFI-compliant parts. At the time of writing, +this has not yet been attempted.</para> + +<variablelist><title>The <function>devinit</function> function must set +up the following struct members:</title> +<varlistentry><term><structfield>page_bits</structfield></term><listitem><para>The +size of the regular (non-spare) part of a page, expressed as the logarithm +in base 2 of the number of bytes. For example, if pages are 2048 bytes +long, <structfield>page_bits</structfield> would be 11. Obviously, +the size of a page must be an exact power of two. +</para></listitem></varlistentry> +<varlistentry><term><structfield>spare_per_page</structfield></term><listitem><para>The +number of bytes of spare area available in each +page.</para></listitem></varlistentry> +<varlistentry><term><structfield>block_page_bits</structfield></term><listitem><para>The +base-2 log of the number of pages per +eraseblock.</para></listitem></varlistentry> +<varlistentry><term><structfield>blockcount_bits</structfield></term><listitem><para>The +total number of erase blocks in the device, expressed as a base-2 +log. </para></listitem></varlistentry> +<varlistentry><term><structfield>chipsize_log</structfield></term><listitem><para>The +total size of the chip, not counting the spare areas. This is required so +that the library can double-check that the given parameters make sense +by comparing with the preceding fields. Again, this field is itself a +base-2 logarithm.</para></listitem></varlistentry> +<varlistentry><term><structfield>bbt.data</structfield></term><listitem><para>Space +for the in-memory Bad Block Table for this device. +</para></listitem></varlistentry> +<varlistentry><term><structfield>bbt.datasize</structfield></term><listitem><para>This +is the size of <structfield>bbt.data</structfield>, in bytes. At present, +this should be two bits times the number of blocks in the device; in +other words, <varname>1<<(blockcount_bits-2)</varname> bytes. +</para></listitem></varlistentry> +</variablelist> + +<para>The <type>cyg_nand_device</type> struct has two further members +<structfield>ecc</structfield> and <structfield>oob</structfield> +which must be set up to point to the ECC and OOB descriptors to use for +the device. This is normally done by the <type>CYG_NAND_DEVICE</type> +low-level instantiation macro, so will be better described in that +section, but at this level you should be aware that it is also safe +to set up the descriptor block during <function>devinit</function>. +for example if multiple semantics might be you had included logic to +detect what semantics to use.</para> + +<para> The Bad Block Table itself is implemented in a way which intends +to be compatible with the Linux MTD layer. A full parameter struct is +not currently provided, though one may be in future.</para> +</sect2> + +<sect2 id="nand-devs-readwrite"> +<title>Reading, writing and erasing data</title> +<para>The read and write operations are divided into three phases, with the following flow:</para> +<itemizedlist> +<listitem><para>Begin. This is called once; the driver should lock any +platform-level mutex and send the command and address.</para></listitem> +<listitem><para>Stride. This is called one or more times to read the page +data from the device. <note><para>The reason for this is if the platform +provides a NAND controller with hardware ECC: it is often necessary to +read out the ECC registers every so often.</para></note></para></listitem> +<listitem><para>Finish. This is called once; it should read or write +the spare area, (on programming) send a "program confirm" command and +check its status, and unlock any platform-level mutex.</para></listitem> +</itemizedlist> + +<para>Erasing is a single-shot call which should lock any +platform-specific mutex, send the command, check its status and unlock +the mutex.</para> + +<programlisting> +static int my_read_begin(cyg_nand_device *dev, cyg_nand_page_addr page); +static int my_read_stride(cyg_nand_device *dev, void * dest, size_t size); +static int my_read_finish(cyg_nand_device *dev, void * spare, size_t spare_size); + +static int my_write_begin(cyg_nand_device *dev, cyg_nand_page_addr page); +static int my_write_stride(cyg_nand_device *dev, const void * src, size_t size); +static int my_write_finish(cyg_nand_device *dev, const void * spare, size_t spare_size); + +static int my_erase_block(cyg_nand_device *dev, cyg_nand_block_addr blk); +</programlisting> +</sect2> + +<sect2 id="nand-devs-isfactorybad"> +<title>Searching for factory-bad blocks</title> +<programlisting> +static int my_is_factory_bad(cyg_nand_device *dev, cyg_nand_block_addr blk); +</programlisting> + +<para> The very first time a NAND chip is used, the library has to +scan it to check for factory-bad eraseblocks and build up the Bad Block +Table. This function is called repeatedly to do so, one block at a time; +it should return 1 if the block is marked bad, or 0 if the block appears +to be OK.</para> + +<para>Typically this function will invoke <function>read_page</function>; +blocks are usually marked factory-bad by the presence of a particular +signature in the out-of-band area of the first or second page of that +block.</para> + +<warning><para> It is extremely important that you get this function +right; after an eraseblock has been written to, it is no longer possible +to reliably determine whether the block was factory-bad. It is never +safe to assume that the factory-bad signature for a chip is the same +as that of a similarly-sized chip or another by the same manufacturer; +<emphasis>always</emphasis> check the correct spec sheet for the actual +part or part-family in use! </para></warning> + +<tip><para> Because this function is critical and a subtle error could +cripple your application some time later in the field when it runs +across undetected factory-bad blocks, you might find it handy to have +a double-check before proceeding. If you enable CYGSEM_IO_NAND_READONLY +in your eCos configuration during early development, you can safely fire +up a test application (which calls <function>cyg_nand_lookup</function>) +whilst watching the chatter output: the scan will be performed, but no BBT +will be written. You can then compare the number of bad blocks reported +against the manufacturer's specification of the maximum. Double-check +that your <function>is_factory_bad</function> function is correct before +enabling read-write mode! </para></tip> +</sect2> + +<sect2 id="nand-devs-declaring-fun-set"> +<title>Declaring the function set</title> +<programlisting> +CYG_NAND_FUNS_V2(mydev_funs, my_devinit, + my_read_begin, my_read_stride, my_read_finish, + my_write_begin, my_write_stride, my_write_finish, + my_erase_block, my_is_factory_bad); +</programlisting> + +<para> This macro ties the above functions together into a struct whose +name is given as its first argument. The name of the resulting struct +must be quoted when the driver is formally instantiated, which is normally +done by the low-level functions.</para> +<note><para>Earlier versions of this library used a slightly different +device interface, keyed off the macro CYG_NAND_FUNS. This interface has +been retired.</para></note> +</sect2> +</sect1> + +<sect1 id="nand-devs-lowlevel"> +<title>Low-level (board) functions</title> +<para> The set and prototypes of the functions required here will +necessarily depend on the board and to a lesser extent on the NAND part +itself. The following functionality is typically required:</para> + +<itemizedlist> +<listitem><para>Very low-level hardware initialisation - for example, +GPIO pin direction and interrupt config - if this has not already been +done by the platform HAL</para></listitem> +<listitem><para>Set up the chip partition table (see below) </para></listitem> +<listitem><para>Runtime hardware config as required, such as commanding +an FPGA or CPLD to route lines to the NAND part </para></listitem> +<listitem><para>Write a command (byte) </para></listitem> +<listitem><para>Write an address (handful of bytes) </para></listitem> +<listitem><para>Write data, usually at the chip's full bus width +(typically 8 or 16 bits) </para></listitem> +<listitem><para>Read data at full bus width </para></listitem> +<listitem><para>Read data at 8-bit width (if the chip has a 16 bit +data bus, some commands - commonly ReadID - may return 8-bit data) +</para></listitem> +<listitem><para>Poll any status lines required or - if supported - +set them up as interrupts to allow sleeping-wait </para></listitem> +</itemizedlist> + +<sect2 id="nand-devs-accessing"> +<title>Talking to the chip</title> +<para> It is impossible to prescribe how to achieve this, as it depends +entirely on how the NAND part is wired up on the board.</para> + +<para> The ideal situation is that the NAND part is wired in via the +CPU's memory controller and that the controller is set up to do most of +the hard work for you. In that case, reading and writing the device is +as simple as accessing the correct memory-mapped I/O address; usually +different address ranges connect to the device's command, address and +data registers respectively.</para> + +<tip><para>The HAL provides a number of macros in +<filename><cyg/hal/hal_io.h></filename> to read and write +memory-mapped I/O. </para></tip> + +<note><para>On platforms with an MMU, MMIO may be rerouted to different +addresses to those on the board spec sheet. Check the MMU setup in the +platform HAL.</para></note> + +<para> On some platforms, you may have to invoke an FPGA or CPLD to be +able to talk to the NAND chip. This might typically take the form of a +handful of MMIO accesses, but should hopefully be fairly straightforward +once you've figured out how the components interrelate.</para> + +<para> The worst case is where you have no support from any sort of +controller hardware and have to bit-bang GPIO lines to talk to the chip. +This is a much more involved process; you have to take great care to get the +timings right with carefully tuned delays. The result is usually +quite CPU intensive, and could be clock speed sensitive too; you should +check for and take account of any CDL settings in the architecture and +variant HAL which allow the CPU clock frequency to be changed.</para> + +<tip><para> If your low-level functions take a +<type>cyg_nand_device</type> pointer as an argument, you can use its +<structfield>priv</structfield> member to hold or point to some relevant +data like the MMIO addresses to use, which is preferable to hard-coding +them. Indeed, if you wish your board port to support more than one chip, +you should use the <structfield>priv</structfield> member to distinguish +between them. +</para></tip> +</sect2> + +<sect2 id="nand-devs-partition"> +<title>Setting up the chip partition table</title> +<para> It is the responsibility of the high-level +<function>devinit</function> function to set up the device's partition +table. (It may be appropriate for it to invoke a low-level function to +do this.)</para> + +<para>The partition definition is an array of +<type>cyg_nand_partition</type> entries in the +<type>cyg_nand_device</type>.</para> + +<programlisting> +struct _cyg_nand_partition_t { +cyg_nand_device *dev; +cyg_nand_block_addr first; +cyg_nand_block_addr last; +}; +typedef struct _cyg_nand_partition_t cyg_nand_partition; + +struct _cyg_nand_device_t { +... +cyg_nand_partition partition[CYGNUM_NAND_MAX_PARTITIONS]; +... +}; +</programlisting> + +<para> +Application-visible partition numbers are simply indexes into this array.</para> + +<itemizedlist> +<listitem><para>On a live partition, <structfield>dev</structfield> +must point back to the <type>cyg_nand_device</type> containing it. If +<constant>NULL</constant>, the partition is inactive.</para></listitem> +<listitem><para><structfield>first</structfield> is the number of the +first block of the partition.</para></listitem> +<listitem><para><structfield>last</structfield> is the number of the last +block of the partition (<emphasis>not</emphasis> the number of blocks, +unless the partition starts at block 0).</para></listitem> +</itemizedlist> +</sect2> + +<sect2 id="nand-devs-lowlevel-putting-it-together"> +<title>Putting it all together...</title> +<para> Finally, with everything else in place, we turn to the +CYG_NAND_DEVICE macro to instantiate it.</para> + +<programlisting> +CYG_NAND_DEVICE(my_nand, "onboard", &mydev_funs, &my_priv_struct, &linux_mtd_ecc, &nand_mtd_oob_64); +</programlisting> + +<para>In order, the arguments to this macro are:</para> + +<itemizedlist> +<listitem><para>The name to give the resultant cyg_nand_device struct;</para></listitem> +<listitem><para>the device identifier string, application-visible to be used in <function>cyg_nand_lookup()</function> ;</para></listitem> +<listitem><para>a pointer to the device high-level function set to use, +normally set up by the CYG_NAND_FUNS macro;</para></listitem> +<listitem><para>the <structfield>priv</structfield> member to include +in the struct;</para></listitem> +<listitem><para>a pointer to the ECC semantics block to use. +<filename>linux_mtd_ecc</filename> provides software ECC compatible +with the Linux MTD layer, but it is strongly recommended to use +onboard hardware ecc support if this is present as it gives a huge +speed boost. See <xref linkend="nand-ecc"> for more details. +</para></listitem> +<listitem><para>a pointer to the OOB-area layout descriptor to use (see +<filename>nand_oob.h</filename> : nand_mtd_oob_16 and nand_mtd_oob_64 +are Linux-compatible layouts for devices with 16 and 64 bytes of spare +area per page respectively).</para></listitem> +</itemizedlist> + +<para>The macro invokes the appropriate linker magic to pull all the +compiled NAND device structs into one section so the NAND library can +find them.</para> + +</sect2> + +</sect1> + +<sect1 id="nand-ecc"><title>ECC implementation</title> + +<para> +The use of ECC is strongly recommended with NAND flash parts owing to their +tendency to occasionally bit-flip. This is usually done with a variant of +a Hamming code which calculates column and line parity. +The computed ECC is stored in the spare area of the page to which it relates. +</para> + +<para> +The NAND library automatically computes and stores the ECC of data as it +is written to the chip. On read, the code is calculated for the data +actually read; this is compared with the stored code and the data +repaired if necessary. +</para> + +<para> +The NAND library comes with a software ECC implementation named +<filename>linux_mtd_ecc</filename>. This is compatible with the +ECC used in the Linux MTD layer, hence its name. It calculates +a 3-byte ECC on a 256-byte data block. +This algorithm is adequate for most circumstances, but it is +strongly recommended to use any hardware ECC support which may +be available because of the performance gains it yields. +(In testing, we observed that up to two thirds of the time +taken by every page read and program call was used in computing +ECC in software.) + +</para> + +<sect2 id="nand-ecc-interface"><title>The ECC interface</title> +<para> +This library draws a semantic distinction between +<emphasis>hardware</emphasis> and +<emphasis>software</emphasis> +ECC implementations. +</para> + +<itemizedlist> +<listitem><para> +A software ECC implementation will typically not require an +initialisation step. The calculation function will always be +called with a pointer to the data bytes to compute. +</para></listitem> +<listitem><para> +A hardware implementation is assumed to read and act upon the data +<emphasis>as it goes past</emphasis>. +Therefore, it will not be passed a pointer to the data +when its <filename>calculate</filename> step is invoked. +</para></listitem> +</itemizedlist> + +<para> +An ECC is defined by the following parameters: +<itemizedlist> +<listitem><para>The size of data block it handles, in bytes. +</para></listitem> +<listitem><para>The size of ECC it calculates on those blocks, in bytes. +</para></listitem> +<listitem><para>Whether the algorithm is hardware or software. +</para></listitem> +</itemizedlist> +</para> + +<para>An ECC algorithm must provide the following functions: +</para> + +<programlisting> +/* Initialises an ECC computation. May be NULL if not required. */ +void my_ecc_init(struct _cyg_nand_device_t *dev); + + +/* Returns the ECC for the given data block. + * If IS_HARDWARE: + * - dat and nbytes are ignored + * If ! IS_HARDWARE: + * - dat and nbytes are required + * - if nbytes is less than the chunk size, the remainder are + * assumed to be 0xff. + */ +void my_ecc_calc(struct _cyg_nand_device_t *dev, + const CYG_BYTE *dat, size_t nbytes, CYG_BYTE *ecc); + + +/* Repairs the ECC for the given data block, if needed. + * Call this if your read-from-chip ECC doesn't match what you computed + * over the data block. Both *dat and *ecc_read may be corrected. + * + * `nbytes' is the number of bytes we're interested in; if a correction + * is indicated outside of that range, it will be ignored. + * + * Returns: + * 0 for no errors + * 1 for a corrected single bit error in the data + * 2 for a corrected single bit error in the ECC + * -1 for an uncorrectable error (more than one bit) + */ +int my_ecc_repair(struct _cyg_nand_device_t *dev, + CYG_BYTE *dat, size_t nbytes, + CYG_BYTE *ecc_read, const CYG_BYTE *ecc_calc); +</programlisting> + +<para>The algorithm parameters and functions are then tied together +with one of the following macros: +</para> + +<programlisting> +CYG_NAND_ECC_ALG_SW(my_ecc, _datasize, _eccsize, my_ecc_init, my_ecc_calc, my_ecc_repair); + +CYG_NAND_ECC_ALG_HW(my_ecc, _datasize, _eccsize, my_ecc_init, my_ecc_calc, my_ecc_repair); +</programlisting> + +<tip><para> +It's OK to use software ECC while getting things going, but if you do +then switch to a hardware implementation, you probably need to erase +your entire NAND chip including its Bad Block Table. The +<filename>nanderase</filename> utility may come in handy for this.) +</para></tip> + +<warning><para>You must be sure that your ECC repair algorithm is correct. +This can be quite tricky to test. +However, it is often possible to hoodwink the controller into computing +ECCs for you even if the data is not going to affect the data stored +on the NAND chip, for example if you send it data but haven't told it to +program a page. +A variant of the <filename>sweccwalk</filename> test may come in handy +for this purpose. +</para></warning> + +<para> +An example implementation, including an ECC calculation and repair test +named <filename>eccwalk</filename>, may be found in the STM3210E +evaluation board platform HAL, +<filename>packages/hal/cortexm/stm32/stm3210e_eval</filename>. +The chip NAND controller has on-board ECC calculation, but does not +undertake to repair data; a repair function was written specially. +</para> + +</sect2> +</sect1> + +</chapter> + +<chapter id="nand-tests-utils"> + +<title>Tests and utilities</title> + +<sect1 id="nand-tests"><title>Unit and functional tests</title> +<para> The NAND library includes a number of tests. The most useful to +driver writers are <filename>readwrite</filename>, +<filename>rwbenchmark</filename> +and +<filename>sweccwalk</filename>; +the others are only likely to be of interest to library maintainers.</para> + +<glosslist> +<glossentry><glossterm>readwrite</glossterm><glossdef><para>Performs a +read-write-erase cycle on the first NAND device it finds, checking that +its operations have had the expected effect on the device contents. This +is a potentially destructive test; do not run it on a device containing +data you care about! +</para></glossdef></glossentry> +<glossentry><glossterm>rwbenchmark</glossterm><glossdef><para> +A more involved version of <filename>readwrite</filename>, this is a +timing test which performs multiple reads, writes and erases and +applies statistical techniques to the results in the same way that +<filename>tm_basic</filename> instruments the speed of various eCos kernel functions. +<emphasis> +This is a potentially destructive test; do not run it on a device containing +data you care about!</emphasis> +</para></glossdef></glossentry> +<glossentry><glossterm>sweccwalk</glossterm><glossdef><para> +Repeatedly makes single-bit changes to a data buffer and checks that the +software ECC implementation correctly repairs them. +<tip><para> +This test can be adapted to test out hardware ECC implementations. +The test outputs the raw ECC codes as it goes, which is useful in +confirming that the bits in the computed ECC are what you think they are. +</para></tip> +</para></glossdef></glossentry> + +<glossentry><glossterm>nandunit</glossterm><glossdef><para>Some unit tests +which do not require any NAND device: ECC known answer vectors, and OOB +area packing/unpacking correctness. </para></glossdef></glossentry> +<glossentry><glossterm>readlimits</glossterm><glossdef><para>Attempts +to read a block outside of a partition, confirming that it doesn't +work.</para></glossdef></glossentry> +</glosslist> + +<para>There are some further tests of the library which +require the <link linkend="devs-nand-synth-tests">synthetic NAND device</link>. +</para> +</sect1> + +<sect1 id="nand-utils"> +<title>Ancillary NAND utilities</title> +<para> The following utilities are included with the NAND library. +They are standalone eCos applications; for convenience, you can set +<constant>CYGBLD_IO_NAND_BUILD_UTILS</constant> in your eCos configuration +and they will be built and placed into +<filename>install/tests/io/nand/current/utils</filename>. +</para> + +<glosslist> +<glossentry><glossterm>erasenand.c</glossterm><glossdef><para> +Loops over all the blocks of a partition, erasing all the blocks which are not +marked as bad. The device and partition to erase are set by #define. +<note><para>This will not normally erase the Bad Block Table. This is because +the BBT reports its own blocks as "Reserved" when queried via +<function>cyg_nand_bbt_query</function>, which makes them inaccessible +to applications. However, if +<constant>CYGSEM_IO_NAND_USE_BBT</constant> is turned off, then any BBT +present will not be detected and hence will be erased. +</para></note> +</para></glossdef></glossentry> +<glossentry><glossterm>erase_bbt_dangerous.c</glossterm><glossdef><para> +Erases the NAND blocks comprising the primary and mirror bad-block tables of a device. +The device to erase is set by #define. +(The tables are detected by the library in the usual way. If none are present, the +library will scan the device for factory-bad blocks to create such a table, then this +code will immediately erase it.) +<warning><para>It is particularly dangerous to run this utility +on a production device, as it is generally not possible to later +reconstruct the list of factory-bad blocks. It is intended only as an +aid to driver authors. </para></warning> +</para></glossdef></glossentry> +</glosslist> +</sect1> +</chapter> + +</part>
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/doc/nandlib-layout.svg @@ -0,0 +1,353 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docname="nandlib-layout.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Lend" + style="overflow:visible;"> + <path + id="path3844" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.8) rotate(180) translate(12.5,0)" /> + </marker> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.7647644" + inkscape:cx="141.8623" + inkscape:cy="214.74423" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:window-width="1319" + inkscape:window-height="965" + inkscape:window-x="508" + inkscape:window-y="140"> + <inkscape:grid + type="xygrid" + id="grid2379" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="g3219" + transform="translate(20,-158.15381)"> + <text + id="text2405" + y="801.22449" + x="50.444336" + style="font-size:14px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + xml:space="preserve"><tspan + style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + y="801.22449" + x="50.444336" + id="tspan2407" + sodipodi:role="line">Application 1</tspan></text> + <rect + y="782.36218" + x="-10" + height="30" + width="120" + id="rect3207" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + </g> + <g + id="g3251" + transform="translate(173.72461,-140)"> + <g + id="g3272"> + <text + id="text2409" + y="852.03113" + x="39.706055" + style="font-size:14px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + xml:space="preserve"><tspan + y="852.03113" + x="39.706055" + id="tspan2411" + sodipodi:role="line">File I/O</tspan></text> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect3217" + width="120" + height="30" + x="-20" + y="832.36218" /> + </g> + </g> + <g + id="g3246" + transform="translate(13.724609,-158.15381)"> + <text + id="text2417" + y="801.22449" + x="200.5708" + style="font-size:14px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + xml:space="preserve"><tspan + y="801.22449" + x="200.5708" + id="tspan2419" + sodipodi:role="line">Application 2</tspan></text> + <rect + y="782.36218" + x="140" + height="30" + width="120" + id="rect3224" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + </g> + <g + id="g3265" + transform="translate(173.72461,-118.80762)"> + <text + id="text2413" + y="881.1698" + x="39.917969" + style="font-size:14px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + xml:space="preserve"><tspan + y="881.1698" + x="39.917969" + id="tspan2415" + sodipodi:role="line">Filesystem</tspan></text> + <rect + y="862.36218" + x="-20" + height="30" + width="120" + id="rect3226" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + </g> + <path + inkscape:connection-end="#g3251" + inkscape:connection-start="#g3246" + inkscape:connector-type="polyline" + id="path6728" + d="M 213.72461,654.70837 L 213.72461,691.86218" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1" /> + <path + inkscape:connection-end="#g3265" + inkscape:connection-start="#g3251" + inkscape:connector-type="polyline" + id="path7245" + d="M 213.72461,722.86218 L 213.72461,743.05456" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1" /> + <path + inkscape:connection-end="#g3277" + inkscape:connection-start="#g3265" + inkscape:connector-type="polyline" + id="path7762" + d="M 204.70788,774.05456 L 161.66028,848.05456" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)" + d="M 75.709814,654.70837 L 146.93374,848.05456" + id="path8279" + inkscape:connector-type="polyline" + inkscape:connection-start="#g3219" + inkscape:connection-end="#g3277" /> + <g + id="g8837"> + <g + transform="translate(42.643554,-103.80762)" + id="g3277"> + <text + xml:space="preserve" + style="font-size:14px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + x="109.4873" + y="971.1698" + id="text2381"><tspan + sodipodi:role="line" + id="tspan2383" + x="109.4873" + y="971.1698">NAND library</tspan></text> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect3228" + width="120" + height="30" + x="50" + y="952.36218" /> + </g> + <g + transform="translate(42.643554,-53.665415)" + id="g3282"> + <text + xml:space="preserve" + style="font-size:12px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + x="109.47266" + y="1011.8358" + id="text2401"><tspan + sodipodi:role="line" + id="tspan2403" + x="109.47266" + y="1011.8358">NAND driver</tspan></text> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect3230" + width="120" + height="30" + x="50" + y="992.36218" /> + </g> + <rect + y="1021.0275" + x="92.643555" + height="30" + width="120" + id="rect3232" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:4, 2, 1, 2;stroke-dashoffset:0;stroke-opacity:1" /> + <text + id="text3234" + y="1040.8206" + x="152.53809" + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold" + xml:space="preserve"><tspan + y="1040.8206" + x="152.53809" + id="tspan3236" + sodipodi:role="line">NAND device</tspan></text> + <path + inkscape:connection-start="#g3282" + inkscape:connector-type="polyline" + id="path5662" + d="M 152.64355,969.19677 L 152.64355,1020.5276" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1" /> + <g + transform="translate(7.4418945e-6,10.093933)" + id="g6190"> + <rect + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 1;stroke-dashoffset:0;stroke-opacity:1" + id="rect3300" + width="110" + height="20" + x="97.643547" + y="972.26825" /> + <text + xml:space="preserve" + style="font-size:10px;font-style:italic;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + x="152.80713" + y="985.99628" + id="text3292"><tspan + sodipodi:role="line" + id="tspan3294" + x="152.80713" + y="985.99628">Platform HAL</tspan></text> + </g> + <path + inkscape:connection-end="#g3282" + inkscape:connection-start="#g3277" + inkscape:connector-type="polyline" + id="path6211" + d="M 152.64355,879.05456 L 152.64355,938.19677" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1" /> + <g + transform="translate(0,7.0070801)" + id="g8825"> + <rect + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.21734178;stroke-miterlimit:4;stroke-dasharray:3.6520253, 1.21734177;stroke-dashoffset:0;stroke-opacity:1" + id="rect6205" + width="109.78266" + height="29.697096" + x="97.752228" + y="883.0285" /> + <text + xml:space="preserve" + style="font-size:10px;font-style:italic;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + x="152.80713" + y="895.3551" + id="text6207"><tspan + sodipodi:role="line" + id="tspan6209" + x="152.80713" + y="895.3551">NAND Device</tspan><tspan + id="tspan8819" + sodipodi:role="line" + x="152.80713" + y="907.8551">interface</tspan></text> + </g> + <g + transform="translate(0,-10.385498)" + id="g8805"> + <rect + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.2289834;stroke-miterlimit:4;stroke-dasharray:3.68695011, 1.22898337;stroke-dashoffset:0;stroke-opacity:1" + id="rect6197" + width="109.77102" + height="30.271017" + x="97.758049" + y="807.47668" /> + <text + xml:space="preserve" + style="font-size:10;font-style:italic;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Sans" + x="152.80713" + y="820.5946" + id="text6199"><tspan + id="tspan8796" + sodipodi:role="line" + x="152.80713" + y="820.5946">NAND Application</tspan><tspan + sodipodi:role="line" + x="152.80713" + y="830.5946" + id="tspan8803">interface</tspan></text> + </g> + </g> + <flowRoot + xml:space="preserve" + id="flowRoot8811" + style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:Bitstream Vera Sans;font-style:italic;font-weight:bold;font-size:14;-inkscape-font-specification:Sans"><flowRegion + id="flowRegion8813"><rect + id="rect8815" + width="68.5" + height="17" + x="104" + y="798.86218" /></flowRegion><flowPara + id="flowPara8817"></flowPara></flowRoot> </g> +</svg>
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/include/nand.h @@ -0,0 +1,256 @@ +#ifndef CYGONCE_NAND_H +# define CYGONCE_NAND_H +//============================================================================= +// +// nand.h +// +// Application interface for the eCos NAND flash library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-02-23 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand_device.h> +#include <pkgconf/io_nand.h> + +/* + * Convenience diagnostic function. + * If debugging is enabled, this function is the default output sink. + * It sends all its output via diag_printf, prefixed with `NAND: '. + */ +__externC int cyg_nand_defaultprintf(const char *fmt, ...) CYGBLD_ATTRIB_PRINTF_FORMAT(1,2); + + +/* NAND device addressing and lookup ================================= */ + +/* NAND devices are addressed by name and, where appropriate, by + * a numeric partition within the device. + * + * To look up a device, you must know its name. Names are defined + * statically by the platform HAL along with the device's function + * pointers etc. + * + * To actually use a NAND device, you must address your requests to + * a partition on it. These can be retrieved, given the device struct, + * by cyg_nand_get_partition. (You are recommended not to directly + * access the partitions array within the device struct, in case the + * mechanism should change in future.) + * + * Note that partitions are numbered starting from 0, unlike + * traditional hard drive partitions. + */ + +/* Looks up a device, by name. If necessary, the device driver is + * initialised and the device interrogated as to its capabilities. + * + * On success, stores a pointer to the device struct in *dev_o (if non-null) + * and returns 0. + * Otherwise, returns a negative error code. + */ +__externC int cyg_nand_lookup(const char *devname, cyg_nand_device **dev_o); + +/* Obtaining information about the device ============================ */ + +/* Looks up the given partition number for the given nand device. + * Partition numbers start at 0 and may go up to CYGNUM_NAND_MAX_PARTITIONS. + * Returns the partition structure, or NULL if the partition is inactive + * or the requested number is invalid. + */ +__externC +cyg_nand_partition* cyg_nand_get_partition(cyg_nand_device *dev, unsigned partno); + +/* Device info helpers */ +#define CYG_NAND_BYTES_PER_PAGE(dev) (1<<(dev)->page_bits) +#define CYG_NAND_SPARE_PER_PAGE(dev) ((dev)->spare_per_page) +#define CYG_NAND_PAGES_PER_BLOCK(dev) (1<<(dev)->block_page_bits) +#define CYG_NAND_BLOCKCOUNT(dev) (1<<(dev)->blockcount_bits) +#define CYG_NAND_CHIPSIZE(dev) (1<<(dev)->chipsize_log) +#define CYG_NAND_APPSPARE_PER_PAGE(dev) ((dev)->oob->app_size) + +/* NAND access functions ============================================= */ + +/* + * Pages and blocks are numbered relative to the partition containing + * them, not to the whole device. In other words, the first page + * of every partition is considered to be number 0. + * + * (Note: This was changed in application interface v2, and the + * application-facing functions renamed. + * The library uses device-relative addressing internally. + * As an aide-memoire, if a function takes a cyg_nand_partition, + * it expects a partition-relative address; if it takes a + * cyg_nand_device, it expects a device-relative address.) + */ + +/* How big is your partition? */ +#define CYG_NAND_PARTITION_NBLOCKS(_p) ((_p)->last - (_p)->first) +#define CYG_NAND_PARTITION_NPAGES(_p) (CYG_NAND_PARTITION_NBLOCKS(_p) * CYG_NAND_PAGES_PER_BLOCK((_p)->dev)) + +/* Reads a single page and/or its spare area from the device. + * @page@ specifies the page to be read. + * If @dest@ is not NULL, it will be used to store the page contents. + * Exactly NAND_BYTES_PER_PAGE(dev) will be written to @dest@. + * If @spare@ is not NULL, it will be used to store the contents of the + * page's spare area (the lesser of @spare_size@ bytes and + * NAND_APPSPARE_PER_PAGE(dev)). + * + * If the page data is read from the chip, it will be ECC-checked + * and repaired if necessary. + * + * Returns 0 for success, otherwise a negative error code. + * -EIO : The block could not be successfully read due to an I/O error + * which the ECC (if configured) was not able to repair. + * *dest and *spare contain the best-effort data read from the chip + * but should not be relied upon; the application should take + * steps to save as much data as needed and erase the block as + * soon as possible. + * + * -ENOENT : The page address was not valid. + * -EINVAL : The page address is within a block that is marked bad. + * -EFBIG : You asked for more data from the spare-area than is present + * in the current chip layout. + */ +__externC +int cyg_nandp_read_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, + void * dest, void * spare, size_t spare_size); + +/* Reads a partial page from the device, to @dest@. + * @page@ specifies the page to be read, @offset@ the address within the + * page (the column address) to start from, and @length@ the number of + * bytes. + * + * If @check_ecc@ is zero, no attempt will be made to check or repair ECC; + * the caller accepts responsibility for error detection and correction! + * + * Where the device driver supports it, the underlying device may use + * relevant chip commands to avoid reading the whole page. However, + * this is not usually compatible with checking the ECC, which requires + * the whole page to be read; in other words, setting @check_ecc@ tends + * to not give you the speedup you might otherwise have hoped for by + * making a part-page read. + * + * Returns 0 for success, otherwise a negative error code. + * -EIO : You requested ECC checking, but an error was found which + * the ECC was not able to repair. + * *dest and *spare contain the best-effort data read from the chip + * but should not be relied upon; the application should take + * steps to save as much data as needed and erase the block as + * soon as possible. + * + * -ENOENT : The page address was not valid. + * -EINVAL : The page address is within a block that is marked bad. + * -EFBIG : You have asked for too much data: offset+length extends + * past the end of the page. + */ +__externC +int cyg_nandp_read_part_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, + void * dest, size_t offset, size_t length, int check_ecc); + +/* Writes a single page and/or its spare area to the device. + * ECC will be automatically computed and written. + * + * @page@ specifies the page to be written. + * If @src@ is not NULL, the page contents - a whole page - will be + * read from it. + * If @spare@ is not NULL, the spare area contents + * (the lesser of @spare_size@ bytes and NAND_APPSPARE_PER_PAGE(dev)) + * will be read from it. + * + * Returns 0 for success, otherwise a negative error code. + * -EIO : The page could not be successfully written due to an I/O error. + * In this case, the application should copy out data from the preceding + * pages of the eraseblock, then call cyg_nand_bbt_markbad() to mark the + * block as bad. + * + * -ENOENT : The page address was not valid. + * -EINVAL : The page address is within a block that is marked bad. + */ +__externC +int cyg_nandp_write_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, + const void * src, const void * spare, size_t spare_size); + +/* Erases an eraseblock. + * @blk@ specifies the block to be erased. + * + * Returns: + * 0 for success + * -EINVAL : the block was already known to be bad + * -EIO : the erase failed; the block has been marked as bad + * -ENOENT : the block address was not valid. + */ +__externC +int cyg_nandp_erase_block(cyg_nand_partition *ctx, cyg_nand_block_addr blk); + +/* Bad block table functions ======================================= */ + +typedef enum { + CYG_NAND_BBT_OK=0, + CYG_NAND_BBT_WORNBAD=1, + CYG_NAND_BBT_RESERVED=2, + CYG_NAND_BBT_FACTORY_BAD=3 +} cyg_nand_bbt_status_t; + +/* Queries the Bad Block Table for what it knows about a given eraseblock. + * Returns an enum from cyg_nand_bbt_status_t, or a negative errno value. + * -ENOENT : the block address was not valid. + * -EIO : something awful happened with the bad block table. + */ +__externC +int cyg_nandp_bbt_query(cyg_nand_partition *ctx, cyg_nand_block_addr blk); + +/* These functions mark a block as worn-bad in the Bad Block Table. + * (The only difference is in the addressing: markbad_pageaddr takes + * a page address and internally converts it to the correct block address.) + * If a page write fails, the application should salvage data from + * any still-needed pages in the failing block to another block, + * then call _markbad to put the block out of use. + * (If a block erase fails, the block is automatically marked bad.) + * After this has been called, attempts to use the block fail with -EPERM. + * Returns 0 on success or a negative errno value. + * -ENOENT : the block address was not valid. + * -EIO : something awful happened with the bad block table. + */ +__externC +int cyg_nandp_bbt_markbad(cyg_nand_partition *ctx, cyg_nand_block_addr blk); + +__externC +int cyg_nandp_bbt_markbad_pageaddr(cyg_nand_partition *ctx, cyg_nand_page_addr pg); + +#endif
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/include/nand_device.h @@ -0,0 +1,312 @@ +#ifndef CYGONCE_NAND_DEVICE_H +# define CYGONCE_NAND_DEVICE_H +//============================================================================= +// +// nand_device.h +// +// Device driver interface for the eCos NAND flash library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-02-23 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/io_nand.h> +#include <pkgconf/isoinfra.h> +#include <cyg/infra/cyg_type.h> +#include <cyg/hal/drv_api.h> // mutexes +#include <cyg/hal/hal_tables.h> +#include CYGBLD_ISO_ERRNO_CODES_HEADER +#include <cyg/nand/nand_ecc.h> +#include <cyg/nand/nand_oob.h> + +#if (defined CYGSEM_IO_NAND_DEBUG_LEVEL) && (CYGSEM_IO_NAND_DEBUG_LEVEL > 0) +// Usage: NAND_CHATTER(level, device, fmt, printf args..) +// Important messages should be level 1; inane drivel should be level 9. +#define NAND_CHATTER(_l_, _dev_, _fmt_, ...) \ + do { \ + if (_l_ <= CYGSEM_IO_NAND_DEBUG_LEVEL && *(_dev_)->pf) \ + (*(_dev_)->pf)((_fmt_), ## __VA_ARGS__); \ + } while(0) +#else +#define NAND_CHATTER(_l_, _dev_, _fmt_, ...) CYG_EMPTY_STATEMENT +#endif + +#ifdef CYGSEM_IO_NAND_DEBUG +#define NAND_ERROR(_dev_, _fmt_, ...) \ + do { \ + if (*(_dev_)->pf) \ + (*(_dev_)->pf)((_fmt_), ## __VA_ARGS__); \ + } while(0) +#else +#define NAND_ERROR(_dev_, _fmt_, ...) CYG_EMPTY_STATEMENT +#endif + + +typedef int (*cyg_nand_printf)(const char *fmt, ...) CYGBLD_ATTRIB_PRINTF_FORMAT(1,2); + +typedef cyg_uint32 cyg_nand_page_addr, cyg_nand_block_addr, cyg_nand_column_addr; + +/* ================================================================= */ + +/* Fwd def. A physical NAND device. */ +struct _cyg_nand_device_t; +typedef struct _cyg_nand_device_t cyg_nand_device; + +/* A partition of a NAND chip */ +struct _cyg_nand_partition_t { + cyg_nand_device *dev; /* The parent device. If NULL, this partition is inactive. */ + cyg_nand_block_addr first; + cyg_nand_block_addr last; +}; +typedef struct _cyg_nand_partition_t cyg_nand_partition; + + +/* A set of device functions. These are intended to be abstractable + * and transplantable amongst different boards using the same (or even + * only similar) chip by only changing the 'priv' struct. + * + * Notes about device functions: + * 1. The NAND library is responsible for checking that the input + * page/block address is valid; device drivers need not. Hence, the + * drivers are not given partition information. + * 2. These functions all return 0 on success (positive if a value + * is required), or a negative error code. + * 3. The read and write sequence from the library is strictly: + * (a) _begin + * (b) Call _stride a number of times, for (at most) a whole page + * (c) _finish + * (d) If another page is to be read, repeat from (a). + */ +struct cyg_nand_dev_fns_v2 { + /* Initialises the device, confirms its presence, + * interrogates it as necessary, + * sets up the in-memory partition array (if configured), + * and populates other members of the _cyg_nand_device_t. + * + * If the device requires any locking on top of the per-device mutex + * that this library provides, it should be set up by this call. + * + * Note that: + * 1. The driver MUST NOT malloc; the NAND layer may run without + * dynamic memory allocation, so anything the device requires should + * be set up as a static global. Implementers should use the + * driver API (cyg/hal/drv_api.h) as far as possible. + * 2. We do not define at which level mutexes should apply, as it + * may differ from device to device - they may need to lock out just + * a single device, or an entire bus, or something more esoteric. + */ + int (*devinit) (cyg_nand_device *dev); + + /* NOTE: read_page and write_page were replaced in interface v2 + * with the following stride-based functions. + * The "striding" interface allows easy interfacing with hardware + * ECC logic present in some NAND controllers. + */ + + /* Initialises a page read operation, but does not actually read any + * data. */ + int (*read_begin)(cyg_nand_device *dev, cyg_nand_page_addr page); + + /* Reads (up to) a stride of data from the chip. + * This call may wait for data to become available. + * + * The number of bytes to read - up to a stride - is given as `size'. + * Only that many bytes will be written to dest. + * + * The size of a stride is implicit from the ECC algorithm used. + */ + int (*read_stride)(cyg_nand_device *dev, void * dest, size_t size); + + /* Reads out the OOB and (if necessary) finalises the read. + * NOTE that this may be called without having read a whole page: + * if so, use the Change Read Column command as appropriate to get + * at the OOB area. If that proves impossible, return -ENOSYS. */ + int (*read_finish)(cyg_nand_device *dev, + void * spare, size_t spare_size); + + /* Sub-page reading. This is a strictly OPTIONAL operation and + * may be given as NULL in the device struct. + * If not present, the NAND layer will emulate it by reading the + * whole page into a temporary buffer and copying out to the client, + * which impacts on performance. + * + * @offset@ is in bytes relative to the start of the page; + * @length@ is the number of bytes to read. + * + * N.B. This is a "standalone" call, i.e. will NOT be punctuated + * by calls to read_begin and read_finish. + */ + int (*read_part_page)(cyg_nand_device *dev, void *dest, + cyg_nand_page_addr page, + size_t offset, size_t length); + + /* Initialises a write operation, but does not actually write any data. */ + int (*write_begin)(cyg_nand_device *dev, cyg_nand_page_addr page); + + /* Writes (up to) a stride of data from the chip. + * + * The number of bytes to written - up to a stride - is given as `size'. + * Only that many bytes will be written to the chip. + * + * The size of a stride is implicit from the ECC algorithm used. */ + int (*write_stride)(cyg_nand_device *dev, const void * src, size_t size); + + /* Sends the OOB data to the chip and finalises the write. + * NOTE that this may be called without having written a whole page: + * if so, use the Change Write Column command as appropriate to get + * at the OOB area. If that proves impossible, return -ENOSYS. */ + int (*write_finish)(cyg_nand_device *dev, + const void * spare, size_t spare_size); + + + /* Erases an eraseblock. See cyg_nand_erase_block(). */ + int (*erase_block)(cyg_nand_device *dev, cyg_nand_block_addr blk); + + /* Looks to see if a block contains the chip-specific factory-bad + * marker. Returns 1 if bad, 0 if OK, or a -ve error code if + * something went really wrong. */ + int (*is_factory_bad)(cyg_nand_device *dev, cyg_nand_block_addr blk); +}; + + +/* Context for a physical NAND device. + * Each device on the system should have its own. + */ +struct _cyg_nand_device_t { + int version; /* Indicates the compatibility level this device supports. */ + + cyg_drv_mutex_t devlock; // Device-level locking applied by this library. + + int is_inited; /* Managed by the NAND library. + If not set, only calls to devinit() are legal. */ + cyg_nand_printf pf; /* Diagnostic printf to use. The default + is configured by CDL, but a driver may + override it here if desired. */ + + const char *devname; /* Device name for use by applications, + e.g. "onboard" or "bus1". */ + + struct cyg_nand_dev_fns_v2 *fns; /* Access functions */ + void * priv; /* If required, points to private device-specific data. */ + + + /* Data about the device need not be defined statically. Indeed + * it is usually preferable to autodetect parameters when the chip + * is initialised. The details here need only be set at some point + * before fns->devinit() returns. */ + + cyg_nand_partition partition[CYGNUM_NAND_MAX_PARTITIONS]; + + size_t page_bits; /* log2 of no of regular bytes per page */ + size_t spare_per_page; /* OOB area size in bytes */ + size_t block_page_bits; /* log2 of no of pages per eraseblock */ + size_t blockcount_bits; /* log2 of number of blocks */ + size_t chipsize_log; /* log2 of total chip size in BYTES. */ + +#ifdef CYGSEM_IO_NAND_USE_BBT + struct { + cyg_nand_block_addr primary, mirror; // or 0xFFFFFFFF if not present + CYG_BYTE *data; /* in-RAM bad block table. See nand_bbt.c. + devinit must set up data: 2 bits * number of blocks. */ + size_t datasize; /* size of data in bytes, used to cross-check */ + CYG_BYTE version; /* _current_ version tag */ + } bbt; +#endif + + cyg_nand_ecc_t *ecc; + const cyg_nand_oob_layout *oob; + + /* Expansion fields go here. */ + +} CYG_HAL_TABLE_TYPE; + +#define CYG_NAND_FUNS ERROR_driver_function_update_to_v2_needed + +#define CYG_NAND_FUNS_V2(_funsv2_, _devinit_, \ + _rdbegin_, _rdstride_, _rdfin_, \ + _rdpart_, \ + _wrbegin_, _wrstride_, _wrfin_, \ + _erasebl_, _factorybad_ ) \ +struct cyg_nand_dev_fns_v2 _funsv2_ = { \ + .devinit = _devinit_, \ + .read_begin = _rdbegin_, \ + .read_stride = _rdstride_, \ + .read_finish = _rdfin_, \ + .read_part_page = _rdpart_, \ + .write_begin = _wrbegin_, \ + .write_stride = _wrstride_, \ + .write_finish = _wrfin_, \ + .erase_block = _erasebl_, \ + .is_factory_bad = _factorybad_, \ +} + +#define CYG_NAND_DEVICE(_structname_, _devname_, _funs_, _priv_, _ecc_, _oob_)\ +struct _cyg_nand_device_t _structname_ CYG_HAL_TABLE_ENTRY(cyg_nand_dev) = \ +{ \ + .version = 2, \ + .is_inited = 0, \ + .devname = _devname_, \ + .fns = _funs_, \ + .priv = _priv_, \ + .ecc = _ecc_, \ + .oob = _oob_, \ +} + +/* To declare a new NAND device, + * first provide its functions and tie them together with CYG_NAND_FUNCTIONS_V2, + * then instantiate it with CYG_NAND_DEVICE_V2. + * - You can optionally provide private data in 'priv' which will be passed + * to the driver functions (e.g. for register addresses or GPIO config). + * - You can use a static ECC param block, or pass it as NULL in the macro + * and set it up in devinit(). + * + * You also must decide on the partition layout for the device. + * This could be hard-coded, defined in CDL, read from a "partition table", + * user-supplied at runtime or something more esoteric. + * Whatever you do, the partition table in the nand_device struct has to + * be set up by the time devinit returns. + */ + +/* The HAL table itself lives in nand.c. */ +__externC cyg_nand_device cyg_nanddevtab[]; +__externC cyg_nand_device cyg_nanddevtab_end; + + +#endif
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/include/nand_devtab.h @@ -0,0 +1,53 @@ +#ifndef CYGONCE_NAND_DEVTAB_H +# define CYGONCE_NAND_DEVTAB_H +//============================================================================= +// +// nand_devtab.h +// +// eCos NAND flash library device table +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-06-02 +// +//####DESCRIPTIONEND#### +//============================================================================= + +extern cyg_nand_device cyg_nanddevtab[]; +extern cyg_nand_device cyg_nanddevtab_end; + +#endif
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/include/nand_ecc.h @@ -0,0 +1,157 @@ +#ifndef CYGONCE_NAND_ECC_H +# define CYGONCE_NAND_ECC_H +//============================================================================= +// +// nand_ecc.h +// +// ECC algorithm interface for the eCos NAND flash library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-13 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/cyg_type.h> + +struct _cyg_nand_device_t; + +/* A "software" ECC algorithm: + * - must read all its data from RAM + * - probably doesn't need an initialisation step + * + * A "hardware" algorithm: + * - updates its internal state as data goes by + * - probably does need an initialisation step (and locking, but the + * caller should take care of that) + */ + +typedef struct { + const unsigned flags; +#define NAND_ECC_FLAG_IS_HARDWARE (1<<0) /* Engages `hardware' semantics */ + + /* How many data bytes does this algorithm read? */ + const unsigned data_size; + /* How many ECC bytes does this algorithm use per data block? */ + const unsigned ecc_size; + /* Initialises an ECC computation. May be NULL if not required. */ + void (*init)(struct _cyg_nand_device_t *dev); + + /* Returns the ECC for the given data block. + * If IS_HARDWARE: + * - dat is ignored + * If ! IS_HARDWARE: + * - dat is required, and @data_size@ bytes will be read from it + */ + void (*calc)(struct _cyg_nand_device_t *dev, + const CYG_BYTE *dat, CYG_BYTE *ecc); + + /* Repairs the ECC for the given data block, if needed. + * Call this if your read-from-chip ECC doesn't match what you computed + * over the data block. Both *dat and *ecc_read may be corrected. + * + * `nbytes' is the number of bytes we're interested in; if a correction + * is indicated outside of that range, it will be ignored. + * + * Returns: + * 0 for no errors + * 1 for a corrected single bit error in the data + * 2 for a corrected single bit error in the ECC + * -1 for an uncorrectable error (more than one bit) + */ + int (*repair)(struct _cyg_nand_device_t *dev, + CYG_BYTE *dat, size_t nbytes, + CYG_BYTE *ecc_read, const CYG_BYTE *ecc_calc); +} cyg_nand_ecc_t; + +#define CYG_NAND_ECC_ALG(_name, _dataz, _eccz, _init, _calc, _repair, _flags) \ + cyg_nand_ecc_t _name = { \ + .data_size = _dataz, \ + .ecc_size = _eccz, \ + .init = _init, \ + .calc = _calc, \ + .repair = _repair, \ + .flags = _flags, \ + } + +#define CYG_NAND_ECC_ALG_SW(_name, _dataz, _eccz, _init, _calc, _repair) \ + CYG_NAND_ECC_ALG(_name, _dataz, _eccz, _init, _calc, _repair, 0) + +#define CYG_NAND_ECC_ALG_HW(_name, _dataz, _eccz, _init, _calc, _repair) \ + CYG_NAND_ECC_ALG(_name, _dataz, _eccz, _init, _calc, _repair, \ + NAND_ECC_FLAG_IS_HARDWARE) + +/* Useful code ==================================================== */ + +/* Quick & dirty calc: no of ECC bytes per page. + * Assumes that ecc->data_size will only ever be a power of two. */ +#define CYG_NAND_ECCPERPAGE(dev) ( (dev)->ecc->ecc_size * (1<<(dev)->page_bits) / (dev)->ecc->data_size ) + +/* Computes the ECC for a whole device page. + * 'page' points to the data; a whole page will necessarily be read. + * The computed ECC will be stored in 'ecc_o'; CYG_NAND_ECCPERPAGE(dev) + * bytes will be written. */ +void nand_ecci_calc_page(struct _cyg_nand_device_t *dev, + const CYG_BYTE *page, CYG_BYTE *ecc_o); + +/* Checks and (if necessary) repairs the ECC for (up to) a whole device page. + * 'page' points to the data; an error at position after @nbytes@ will not + * be corrected. + * Broadly the same semantics as for cyg_nand_ecc_t.repair; + * both ECCs are of size CYG_NAND_ECCPERPAGE(dev), and ecc_read may + * be corrected as well as the data. + * Returns: + * 0 for no errors + * 1 if there was at least one corrected data error + * 2 if there was at least one corrected ECC error + * 3 if there was at least one corrected error in both data and ECC + * -1 if there was an uncorrectable error (>1 bit in a single ECC block) + */ +int nand_ecci_repair_page(struct _cyg_nand_device_t *dev, + CYG_BYTE *page, size_t nbytes, + CYG_BYTE *ecc_read, const CYG_BYTE *ecc_calc); + +/* Implementations ================================================ */ +// TODO: Hide by CDL, when more than one is added. + +/* A compatible ECC algorithm with that used by the Linux MTD layer. + * See nand_ecc_mtd.c and nand_ecc_mtd_fast.c. */ +__externC cyg_nand_ecc_t linux_mtd_ecc; +__externC cyg_nand_ecc_t mtd_ecc256_fast; + +#endif
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/include/nand_oob.h @@ -0,0 +1,148 @@ +#ifndef CYGONCE_NAND_OOB_H +# define CYGONCE_NAND_OOB_H +//============================================================================= +// +// nand_oob.h +// +// eCos NAND flash library - Out Of Band (Spare) area layout defs +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-13 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/cyg_type.h> +#include <pkgconf/isoinfra.h> +#include CYGBLD_ISO_ERRNO_CODES_HEADER + +/* The Out Of Band ("spare") area on every page of a NAND array contains + * the following: + * * Somewhere to put the ECC data + * * Somewhere to put application data + * * (Maybe) a factory bad marker. + * + * To make matters more complicated, both the ECC and the application + * OOB data may be spread across non-contiguous regions. + * + * In theory, we can overwrite the position of the factory-bad marker as + * we've scanned the array to make our own bad-block table. + * However, should the array be reinitialised by some other OS with + * different BBT semantics, it is likely to rescan the array looking + * for factory bad markers. + * Therefore, we should avoid writing to the bad-marker location on + * general principles. The Linux MTD layer does this in its OOB layout + * definitions. + */ + +/* NOTE: For the sake of reducing code size, we currently use a byte + * to declare locations. This is fine, provided that a chip's OOB + * is less than 256 bytes per page. + * Well, chips with a 2k page size typically have 64 byte OOB area, + * so we might have to change this typedef if/when pages reach 8k. + */ + +typedef CYG_BYTE oobpos_t; + +/* Vector component. If 'len'==0, there are no more elements. */ +typedef struct { + const oobpos_t pos, len; +} oob_vector; + +/* Increase these maxima as necessary, but not excessively or you'll waste ROM space. */ +#define CYG_NAND_OOB_MAX_ECC_SLOTS 2 +#define CYG_NAND_OOB_MAX_APP_SLOTS 2 + +typedef struct { + const oobpos_t ecc_size; // total ECC _bytes_ + const oob_vector ecc[CYG_NAND_OOB_MAX_ECC_SLOTS]; + // CAUTION! Both ecc and app vectors MUST BE IN ORDER! + const oobpos_t app_size; // total bytes available for app data + const oob_vector app[CYG_NAND_OOB_MAX_APP_SLOTS]; +} cyg_nand_oob_layout; + +/* Packs 'app_size' bytes from 'app' (appdata) and layout->ecc_size bytes + * from 'ecc' into 'packed'. + * app_size must be <= layout->app_size and will be SILENTLY TRUNCATED + * if too big. + * Bytes not referenced by the layout are not touched; the caller should + * usually pre-initialise the buffer to 0xFF. + */ +__externC void nand_oob_pack(struct _cyg_nand_device_t *dev, + const CYG_BYTE *app, const unsigned app_size, + const CYG_BYTE *ecc, CYG_BYTE *packed); + +/* Unpacks data from 'packed' into 'ecc' (layout->ecc_size bytes) + * and 'app' (no more than 'app_max' bytes). + * It's up to the app to decide however many app bytes are useful to it. + * If unsure, you could always read out them all (layout->app_size). + */ +__externC void nand_oob_unpack( struct _cyg_nand_device_t *dev, + CYG_BYTE *app, const unsigned app_max, + CYG_BYTE *ecc, const CYG_BYTE *packed); + +/* Writes @len@ bytes of @data@ into an @oobbuf@ such that the data + * will end up at the given @rawpos@ in the packed layout. + * Returns 0 for success or -1 if it's not possible. */ +__externC int nand_oob_packed_write(struct _cyg_nand_device_t *dev, + size_t rawpos, size_t len, + CYG_BYTE *oobbuf, const CYG_BYTE *data); + +/* Opposite of nand_oob_packed_write. + * Reads @len@ bytes from an application @oobbuf@ such that they + * came from the given @rawpos@ in the packed layout; copies them + * to @data@. + * Returns 0 for success or -1 if it's not possible. */ +__externC int nand_oob_packed_read(struct _cyg_nand_device_t *dev, + size_t rawpos, size_t len, + const CYG_BYTE *oobbuf, CYG_BYTE *data); + +/* And now some layouts from the Linux MTD layer. */ + +extern const cyg_nand_oob_layout +#if 0 +/* Disabled for now - see comments in source */ + nand_mtd_oob_8, +#endif + nand_mtd_oob_16, + nand_mtd_oob_64; + +/* How much application-usable OOB spare is there per page? */ +#define CYG_NAND_APPLICATION_OOB(dev) (dev->oob->app_size) + +#endif
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/include/util.h @@ -0,0 +1,65 @@ +#ifndef CYGONCE_NAND_UTIL_H +#define CYGONCE_NAND_UTIL_H +//============================================================================= +// +// util.h +// +// eCos NAND flash library - sundry utilities +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-06-01 +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* Block address <--> page address conversion */ +#define CYG_NAND_PAGE2BLOCKADDR(dev,page) ( (page) >> (dev)->block_page_bits ) +#define CYG_NAND_BLOCK2PAGEADDR(dev,block) ( (block) << (dev)->block_page_bits ) + +/* Resolver from dev name (e.g. onboard/0) to device and partition structs + * if there's no /, we'll just look up the device name and - if part isn't + * NULL - set *part to NULL. + * Reasonably foreseeable returns: + * 0 - device (and partition if provided) successfully looked up + * -ENODEV - device name not found + * -ENOENT - device found, partition not found + */ +int cyg_nand_resolve_device(const char *dev, cyg_nand_device **nand, + cyg_nand_partition **part); + +#endif // CYGONCE_NAND_UTIL_H
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/misc/.gitignore @@ -0,0 +1,4 @@ +ar4test +mkvector +yaffs_ecc.c +yaffs_ecc.h
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/misc/ar4test.c @@ -0,0 +1,121 @@ +// ar4test.c +// +// Meta-test for the arc4 PRNG algorithm in ar4prng.inl +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* This is a rough and ready meta-test of the PRNG using the known-answer + * vectors found on http://en.wikipedia.org/wiki/RC4. + * + * This is NOT an eCos test case; it is intended to be run host-side. + * (Although there's no inherent reason why you couldn't run it on a board.) + * Compile with: gcc ar4test.c -g -o ar4test + */ + +#include "../tests/ar4prng.inl" + +#include <alloca.h> +#include <assert.h> +#include <stdio.h> +#include <string.h> + +typedef struct { + char *key; + char *plaintext; + char *ct_hex; +} vector; + +vector master[] = { + { "Key", "Plaintext", "BBF316E8D940AF0AD3" }, + { "Wiki", "pedia", "1021BF0420" }, + { "Secret", "Attack at dawn", "45A01F645FC35B383552544B9BF5" }, + { 0,0,0 } +}; + +// ascii nybble to binary +unsigned char N2B(char p) +{ + if (p>='0' && p<='9') + return p-'0'; + if (p>='A' && p<='F') + return 10+p-'A'; + if (p>='a' && p<='f') + return 10+p-'a'; + assert(0=="bad hex"); +} + +void test (vector *v) +{ + ar4ctx ctx; + int textlen = strlen(v->plaintext), i; + unsigned char *ct = alloca(textlen), + *ct_comp = alloca(textlen); + + for (i=0; i<textlen; i++) { + ct[i] = ( N2B(v->ct_hex[i*2]) << 4 ) + | N2B(v->ct_hex[i*2+1]); + } + + ar4prng_init(&ctx, v->key, strlen(v->key)); + ar4prng_many(&ctx, ct_comp, textlen); + for (i=0; i<textlen; i++) + ct_comp[i] ^= v->plaintext[i]; + + int pass = (0==memcmp(ct, ct_comp, textlen)); + printf("Test %s: result %s\n", v->key, pass ? "PASS" : "FAIL"); +#if 0 + for (i=0; i<textlen; i++) + printf("%02x", ct_comp[i]); + printf("\n"); +#endif +} + +int main(int argc, char**argv) +{ + vector *vv = master; + while (vv->key) { + test(vv); + ++vv; + } + return 0; +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/misc/mkvector.c @@ -0,0 +1,98 @@ +// mkvector.c +// +// Routine to create ECC known answer vectors for nandunit.c +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* This is a quick & dirty hostside harness to create known-answer ECC + * test vectors. + * It uses ar4prng.inl to generate its test data. + * The output is human-readable, intended to be turned into code; the + * results have been incorporated into nandunit.c. Each output is an + * arc4 input ("key") string, followed by the ECC output of each of the + * first eight 256-byte chunks from running arc4 on that key string. + * + * An ECC algorithm is required. In its current form, this code + * slightly nastily #includes Charles Manning's ECC implementation, + * but any ECC algorithm compatible with the Linux MTD ECC code should do. + * + * This is NOT an eCos test case; it is intended to be run host-side. + * (Although there's no inherent reason why you couldn't run it on a board.) + * + * To compile, first copy this source and ar4prng.inl, along with + * yaffs_ecc.c and yaffs_ecc.h from a recent yaffs2 tree, into a + * build directory; then: + * gcc mkvector.c -g -o mkvector + */ + + +#include <stdio.h> +#include <string.h> +#include "ar4prng.inl" +#include "yaffs_ecc.c" + +#define CHUNKSIZE 2048 +void doit(char *key) +{ + ar4ctx ctx; + unsigned char chunk[CHUNKSIZE]; + unsigned char ecc[3*CHUNKSIZE/256]; + int i; + + ar4prng_init(&ctx, key, strlen(key)); + ar4prng_many(&ctx, chunk, CHUNKSIZE); + + for (i=0; i< (CHUNKSIZE/256); i++) + yaffs_ECCCalculate(&chunk[256*i], &ecc[3*i]); + + printf ("Key: %s\nECC: ", key); + for (i=0; i<sizeof(ecc); i++) + printf("%02x", ecc[i]); + printf("\n\n"); +} + +int main(int argc, char**argv) +{ + doit("key1"); + doit("key2"); + return 0; +}
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/misc/timetag_to_csv.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl -ln +# +# timetag_to_csv.pl +# Reformats some timetags as output from gdb ("p tagslist") as CSV +# for easy import into your analysis tool of choice. +# +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 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): wry +# Date: 2009-11-10 +# +# ###DESCRIPTIONEND#### +# + +# input (stdin or filename): paste from gdb ("p tagslist") +# output (stdout): csv + +BEGIN { my $state=0; my @data = (); } + +$state = 1 if s/.*{//; + +my $nextstate = $state; +$nextstate = 0 if s/}.*//; + +s/^\s+//; +s/\s+$//; +if ($state == 1) { + push @data, split /,\s*/; +} +$state = $nextstate; + +END { + while (@data) { + $a = shift @data; + $b = shift @data; + $c = shift @data; + print "$a, $b, $c"; + } +}
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nand.c @@ -0,0 +1,817 @@ +//============================================================================= +// +// nand.c +// +// Main application interface for the eCos NAND flash library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-02 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/hal/drv_api.h> // mutexes +#include <cyg/infra/diag.h> +#include <cyg/infra/cyg_ass.h> + +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_device.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/nand/util.h> +#include "nand_bbt.h" +#include CYGBLD_ISO_ERRNO_CODES_HEADER +#include <string.h> + +/* ============================================================ */ +// Timing instrumentation hooks; or "where is all the time going?" +// timetag_to_csv.pl will turn gdb output ("p tagslist") into CSV, +// for ease of analysis. + +#ifdef CYGSEM_IO_NAND_INSTRUMENT_TIMING +# ifndef HAL_CLOCK_READ +# error HAL_CLOCK_READ required +# endif +# define TAGSIZE 1024 +cyg_uint32 tagslist[TAGSIZE]; +cyg_uint32 tags_next; +static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; +static cyg_int64 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; + +# define TAG(_x) do { \ + tagslist[tags_next++] = _x; \ + if (tags_next >= TAGSIZE) tags_next = 0; \ +} while(0) + +# define TIMETAG() do { \ + cyg_uint64 tick; \ + cyg_uint32 haltick; \ + tick=cyg_current_time();\ + HAL_CLOCK_READ(&haltick);\ + TAG(__LINE__); \ + TAG(tick&0xFFFFFFFF); \ + TAG(haltick); \ +} while(0) + +# define TIMETAG_INIT() do { \ + int _i; \ + for (_i=0; _i<TAGSIZE; _i++) \ + tagslist[_i]=0; \ + tags_next = 0; \ + cyg_uint32 _tt, _tu; \ + HAL_CLOCK_READ(&_tt); \ + _tu = _tt; \ + while (_tt == _tu) \ + HAL_CLOCK_READ(&_tu); \ + TIMETAG(); \ + (void) rtc_period; \ + (void) rtc_resolution; \ +} while(0) + +#else // ! CYGSEM_IO_NAND_INSTRUMENT_TIMING + +# define TIMETAG_INIT() CYG_EMPTY_STATEMENT +# define TIMETAG() CYG_EMPTY_STATEMENT + +#endif + +/* ============================================================ */ + +/* We have a global ("devinit") lock, protects the nanddevtab and all + * writes to device->isInited. + * + * Each device also has its own lock, which protects the rest of + * the structure, and the hardware itself. + * + * Rules: + * 1. Nothing can use a device until it has been fully initialised + * (i.e. they must check dev->isInited, which is not set until + * initialisation is complete); + * 2. All calls to a device which has been initialised must acquire + * the device's lock, to prevent multiple access; + * 3. A repeated call to initialise a device is a safe no-op (under the + * global lock, see that isInited is set, so do nothing); + * 4. It is not possible for multiple threads to simultaneously + * initialise the same device [via the lookup function] + * (they are protected by the global lock - the second blocks + * until the first has completed, at which point the second thread + * sees that the device has been inited and falls out into a no-op). + * + * Therefore, an operation in devinit which uses the chip need not + * assert the per-device lock, as nothing else can use the chip until + * it has completed and set isInited to 1. + */ + +static cyg_drv_mutex_t devinit_lock; + +#define LOCK_devinit() cyg_drv_mutex_lock(&devinit_lock) +#define UNLOCK_devinit() cyg_drv_mutex_unlock(&devinit_lock) + +/* Per-device lock. + * NB that if multiple devices might interact (e.g. sharing a CPLD), + * their drivers must act in concert to prevent this, usually at the + * platform level. */ +#define LOCK_DEV(dev) cyg_drv_mutex_lock(&dev->devlock) +#define UNLOCK_DEV(dev) cyg_drv_mutex_unlock(&dev->devlock) + +/* ============================================================ */ +/* Initialisation and lookup */ + +__externC void cyg_nand_bbt_initx(void); +static cyg_nand_printf nand_default_pf; + +// This is called only by the C++ static constructor. Applications +// never need to call this themselves. +__externC void cyg_nand_initx(cyg_nand_printf pf) +{ + if (pf) CYG_CHECK_FUNC_PTRC(pf); + cyg_drv_mutex_init(&devinit_lock); + cyg_nand_bbt_initx(); + nand_default_pf = pf; +} + +__externC +cyg_nand_partition* cyg_nand_get_partition(cyg_nand_device *dev, unsigned partno) +{ + if ((partno < 0) || (partno >= CYGNUM_NAND_MAX_PARTITIONS)) + return NULL; + LOCK_DEV(dev); + cyg_nand_partition *rv = &(dev->partition[partno]); + UNLOCK_DEV(dev); + if (!rv->dev) return NULL; /* partition inactive */ + return rv; +} + +__externC +int cyg_nand_lookup(const char *devname, cyg_nand_device **dev_o) +{ + int rv = -ENOENT; + if (dev_o) { + CYG_CHECK_DATA_PTRC(dev_o); + *dev_o = 0; + } + if (!devname) return -EINVAL; + + LOCK_devinit(); // ++++++++++++++++++++++++++++++++++++++++++++ + cyg_nand_device *dev; + for (dev = &cyg_nanddevtab[0]; dev != &cyg_nanddevtab_end; dev++) { + if (0==strcmp(devname, dev->devname)) { + rv = 0; + break; + } + } + if (!rv) { + if (!dev->is_inited) { + int i; + + if (dev->version != 2) { + NAND_ERROR(dev, "Device %s declares incompatible version %d (expected 2)", devname, dev->version); + goto done; + } + CYG_CHECK_DATA_PTRC(dev->fns); + CYG_CHECK_FUNC_PTRC(dev->fns->devinit); + + dev->pf = nand_default_pf; + for (i=0; i<CYGNUM_NAND_MAX_PARTITIONS; i++) + dev->partition[i].dev = 0; +#ifdef CYGSEM_IO_NAND_USE_BBT + dev->bbt.data = 0; // Paranoia, ensure devinit sets up +#endif + + rv = dev->fns->devinit(dev); + + if (rv) { + NAND_ERROR(dev,"Could not initialise NAND device \"%s\": code %d\n", devname, rv); + goto done; + } + + // Now check that we have everything we need + CYG_CHECK_FUNC_PTRC(dev->fns->read_begin); + CYG_CHECK_FUNC_PTRC(dev->fns->read_stride); + CYG_CHECK_FUNC_PTRC(dev->fns->read_finish); + CYG_CHECK_FUNC_PTRC(dev->fns->write_begin); + CYG_CHECK_FUNC_PTRC(dev->fns->write_stride); + CYG_CHECK_FUNC_PTRC(dev->fns->write_finish); + + CYG_CHECK_FUNC_PTRC(dev->fns->erase_block); + CYG_CHECK_FUNC_PTRC(dev->fns->is_factory_bad); + +#ifdef CYGSEM_IO_NAND_USE_BBT + CYG_CHECK_DATA_PTRC(dev->bbt.data); +#endif + CYG_CHECK_DATA_PTRC(dev->ecc); + CYG_CHECK_DATA_PTRC(dev->oob); + if (!dev->chipsize_log || + !dev->blockcount_bits || + !dev->block_page_bits || + !dev->spare_per_page || + !dev->page_bits || +#ifdef CYGSEM_IO_NAND_USE_BBT + !dev->bbt.data || +#endif + !dev->ecc || + !dev->oob) { + NAND_ERROR(dev,"BUG: NAND driver devinit did not fill in all required fields - disabling device\n"); + rv = -ENOSYS; + goto done; + } + +#ifdef CYGSEM_IO_NAND_USE_BBT + if (dev->bbt.datasize < (1 << (dev->blockcount_bits-2)) ) { + NAND_ERROR(dev,"BUG: NAND driver declared bbt.data_size isn't big enough (got %lu, want %u) - disabling device\n", (unsigned long) dev->bbt.datasize, (1 << (dev->blockcount_bits-2))); + rv = -ENOSYS; + goto done; + } +#endif + + if ( dev->oob->ecc_size != CYG_NAND_ECCPERPAGE(dev) ) { + NAND_ERROR(dev,"BUG: NAND driver has inconsistent ECC size declaration (oob says %d, ecc says %d) - disabling device\n", dev->oob->ecc_size, CYG_NAND_ECCPERPAGE(dev)); + rv = -ENOSYS; + goto done; + } + + // NOW we are ready to read from the device ! + +#ifdef CYGSEM_IO_NAND_USE_BBT + rv = cyg_nand_bbti_find_tables(dev); + if (rv == -ENOENT) { + NAND_CHATTER(1,dev, "Creating initial bad block table on device %s\n", devname); + rv = cyg_nand_bbti_build_tables(dev); + } + if (rv != 0) { + NAND_ERROR(dev,"Cannot find or build BBT (%d)\n", -rv); + goto done; + } +#endif + + cyg_drv_mutex_init(&dev->devlock); + dev->is_inited = 1; + + int live_partitions = 0; + for (i=0; i<CYGNUM_NAND_MAX_PARTITIONS; i++) + if (dev->partition[i].dev) ++live_partitions; + if (live_partitions) + NAND_CHATTER(1,dev, "%s devinit complete, %u partition%c configured\n", devname, live_partitions, live_partitions==1 ? ' ' : 's' ); + else + NAND_CHATTER(1,dev, "%s devinit complete, NO partitions configured!\n", devname); // hope they know what they're doing. + } + if (dev_o) *dev_o = dev; + } +done: + UNLOCK_devinit(); // ------------------------------------------ + return rv; +} + +/* ============================================================ */ +/* Device access */ + +#define DEV_INIT_CHECK(dev) do { if (!dev->is_inited) return -ENXIO; } while(0) +#define PARTITION_CHECK(p) do { if (!p->dev) return -ENXIO; } while(0) + +// Partition-to-Device and Device-to-Partition address xlation +#define BLOCK_P_TO_D(_part,_block) ((_block) + (_part)->first) +#define BLOCK_D_TO_P(_part,_block) ((_block) - (_part)->first) + +#define PAGE_P_TO_D(_part,_page) ((_page) + (_part)->first * CYG_NAND_PAGES_PER_BLOCK((_part)->dev) ) +#define PAGE_D_TO_P(_part,_page) ((_page) - (_part)->first * CYG_NAND_PAGES_PER_BLOCK((_part)->dev) ) + +/* Sanity check helpers: these take a partition and a DEVICE address */ +static inline int valid_block_addr(cyg_nand_partition *part, cyg_nand_block_addr block) +{ + return ( (block < part->first) || (block > part->last) ) ? -ENOENT : 0; +} + +static int valid_page_addr(cyg_nand_partition *part, cyg_nand_page_addr page) +{ + cyg_nand_block_addr block = CYG_NAND_PAGE2BLOCKADDR(part->dev,page); + int rv = valid_block_addr(part, block); + if (rv != 0) + NAND_CHATTER(1,part->dev, "Invalid attempted access to page %d\n", page); + return rv; +} + +#define EG(what) do { rv = (what); if (rv != 0) goto err_exit; } while(0) + +__externC +int cyg_nandp_read_page(cyg_nand_partition *prt, cyg_nand_page_addr ppage, + void * dest, void * spare, size_t spare_size) +{ + int rv, locked=0; + TIMETAG_INIT(); + PARTITION_CHECK(prt); + cyg_nand_device *dev = prt->dev; + DEV_INIT_CHECK(dev); + cyg_nand_page_addr page = PAGE_P_TO_D(prt,ppage); + + if (spare_size > dev->spare_per_page) return -EFBIG; + + EG(valid_page_addr(prt, page)); + +#ifdef CYGSEM_IO_NAND_USE_BBT + cyg_nand_block_addr blk = CYG_NAND_PAGE2BLOCKADDR(dev,page); + if (cyg_nand_bbti_query(dev, blk) != CYG_NAND_BBT_OK) { + NAND_CHATTER(1,dev,"Asked to read page %u in bad block %u\n", page, blk); + EG(-EINVAL); + } +#endif + + LOCK_DEV(dev); + locked = 1; + EG(nandi_read_whole_page_raw(dev, page, dest, spare, spare_size, 1)); + +err_exit: + if (locked) UNLOCK_DEV(dev); + TIMETAG(); + return rv; +} + + + +__externC +int cyg_nandp_read_part_page(cyg_nand_partition *prt, cyg_nand_page_addr ppage, + void * dest, size_t offset, size_t length, int check_ecc) + +{ + int rv; + PARTITION_CHECK(prt); + cyg_nand_device *dev = prt->dev; + DEV_INIT_CHECK(dev); + cyg_nand_page_addr page = PAGE_P_TO_D(prt,ppage); + CYG_BYTE *pagebuffer; + int got_pagebuf = 0, locked = 0; + + if (offset + length > CYG_NAND_BYTES_PER_PAGE(dev)) return -EFBIG; + + EG(valid_page_addr(prt, page)); + +#ifdef CYGSEM_IO_NAND_USE_BBT + cyg_nand_block_addr blk = CYG_NAND_PAGE2BLOCKADDR(dev,page); + if (cyg_nand_bbti_query(dev, blk) != CYG_NAND_BBT_OK) { + NAND_CHATTER(1,dev,"Asked to read page %u in bad block %u\n", page, blk); + EG(-EINVAL); + } +#endif + + LOCK_DEV(dev); + locked = 1; + + if (dev->fns->read_part_page && !check_ecc) { + EG(dev->fns->read_part_page(dev, dest, page, offset, length)); + } else { + pagebuffer = nandi_grab_pagebuf(); + got_pagebuf = 1; + EG(nandi_read_whole_page_raw(dev, page, pagebuffer, 0, 0, check_ecc)); + if (dest) + memcpy(dest, &pagebuffer[offset], length); + } + +err_exit: + if (got_pagebuf) nandi_release_pagebuf(); + if (locked) UNLOCK_DEV(dev); + return rv; +} + + +/* Internal, mostly-unchecked interface to read a page. + * Takes a DEVICE address. + * Caller must hold the devlock! */ +int nandi_read_whole_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page, + CYG_BYTE * dest, CYG_BYTE * spare, size_t spare_size, + int check_ecc) +{ + CYG_BYTE ecc_read[CYG_NAND_ECCPERPAGE(dev)], + ecc_calc[CYG_NAND_ECCPERPAGE(dev)]; + CYG_BYTE *ecc_calc_p, *ecc_read_p; + + CYG_BYTE oob_buf[dev->spare_per_page]; + int rv=0,tries=0; + size_t remain; + const int do_hw_ecc = (dev->ecc->flags & NAND_ECC_FLAG_IS_HARDWARE) && check_ecc; + + // Stride for reading from device: + const unsigned read_data_stride = do_hw_ecc ? dev->ecc->data_size : CYG_NAND_BYTES_PER_PAGE(dev); + // Stride for calculating/checking/repairing ECC: + const unsigned ecc_data_stride = dev->ecc->data_size; + // Stride within the ECC data + const unsigned ecc_stride = dev->ecc->ecc_size; + + if (dest) CYG_CHECK_DATA_PTRC(dest); + if (spare) CYG_CHECK_DATA_PTRC(spare); + + CYG_ASSERTC(CYG_NAND_BYTES_PER_PAGE(dev) % ecc_data_stride == 0); + + do { + CYG_BYTE *data_dest = dest; + CYG_BYTE *ecc_dest = ecc_calc; + + ++tries; + remain = CYG_NAND_BYTES_PER_PAGE(dev); + + TIMETAG(); + EG(dev->fns->read_begin(dev, page)); + TIMETAG(); + + if (dest) { + int step; + while (remain) { + step = read_data_stride; + CYG_ASSERTC(remain >= read_data_stride); + + TIMETAG(); + if (do_hw_ecc && dev->ecc->init) dev->ecc->init(dev); + EG(dev->fns->read_stride(dev, data_dest, read_data_stride)); + TIMETAG(); + + if (do_hw_ecc) { + dev->ecc->calc(dev, 0, ecc_dest); + ecc_dest += ecc_stride; + TIMETAG(); + } + + data_dest += read_data_stride; + remain -= read_data_stride; + } + + TIMETAG(); + EG(dev->fns->read_finish(dev, oob_buf, dev->spare_per_page)); + TIMETAG(); + nand_oob_unpack(dev, spare, spare_size, ecc_read, oob_buf); + + if (check_ecc) { + TIMETAG(); + if (!do_hw_ecc) { + // Calculate software ECC in one go to try and take + // advantage of the cache. + data_dest = dest; + remain = CYG_NAND_BYTES_PER_PAGE(dev); + ecc_calc_p = ecc_calc; + + while (remain) { + if (dev->ecc->init) dev->ecc->init(dev); + dev->ecc->calc(dev, data_dest, ecc_calc_p); + + remain -= ecc_data_stride; + data_dest += ecc_data_stride; + ecc_calc_p += ecc_stride; + } + } + + // Now repair ... + rv = 0; + int step_rv; + remain = CYG_NAND_BYTES_PER_PAGE(dev); + data_dest = dest; + + ecc_calc_p = ecc_calc; + ecc_read_p = ecc_read; + + while (remain) { + CYG_ASSERTC(remain >= ecc_data_stride); + + step_rv = dev->ecc->repair(dev,data_dest,ecc_data_stride,ecc_read_p,ecc_calc_p); + if (step_rv == -1) { + rv = -1; + break; + } + rv |= step_rv; + + data_dest += ecc_data_stride; + ecc_read_p += ecc_stride; + ecc_calc_p += ecc_stride; + remain -= ecc_data_stride; + } + TIMETAG(); + } + } else { // !dest: very simple case + TIMETAG(); + EG(dev->fns->read_finish(dev, oob_buf, dev->spare_per_page)); + TIMETAG(); + rv = 0; + nand_oob_unpack(dev, spare, spare_size, ecc_read, oob_buf); + } + + if (rv==-1 && (tries < CYGNUM_NAND_MAX_READ_RETRIES) ) { + NAND_CHATTER(4, dev, "ECC uncorrectable error on read, retrying\n"); + } + } while (rv==-1 && (tries < CYGNUM_NAND_MAX_READ_RETRIES) ); + + switch (rv) { + case 0: + NAND_CHATTER(8,dev,"Read page %u OK\n", page); + break; + case 1: + case 2: + case 3: + NAND_CHATTER(2,dev, "Page %u ECC correction, type %d\n", page,rv); + rv=0; + break; + case -1: + default: + NAND_ERROR(dev,"Page %u read gave ECC uncorrectable error\n", page); + rv=-EIO; + break; + } +err_exit: + return rv; +} + +__externC +int cyg_nandp_write_page(cyg_nand_partition *prt, cyg_nand_page_addr ppage, + const void * src, const void * spare, size_t spare_size) +{ + int rv, locked = 0; + TIMETAG_INIT(); + PARTITION_CHECK(prt); + cyg_nand_device *dev = prt->dev; + DEV_INIT_CHECK(dev); + cyg_nand_page_addr page = PAGE_P_TO_D(prt,ppage); + + EG(valid_page_addr(prt, page)); + +#ifdef CYGSEM_IO_NAND_USE_BBT + cyg_nand_block_addr blk = CYG_NAND_PAGE2BLOCKADDR(dev,page); + if (cyg_nand_bbti_query(dev, blk) != CYG_NAND_BBT_OK) { + NAND_CHATTER(1,dev,"Asked to write page %u in bad block %u\n", page, blk); + EG(-EINVAL); + } +#endif + LOCK_DEV(dev); + locked = 1; + EG(nandi_write_page_raw(dev, page, src, spare, spare_size)); + +err_exit: + if (locked) UNLOCK_DEV(dev); + TIMETAG(); + return rv; +} + +/* Internal, mostly-unchecked interface to write a page. + * Takes a DEVICE address. */ +__externC +int nandi_write_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page, + const CYG_BYTE * src, const CYG_BYTE * spare, size_t spare_size) +{ +#ifdef CYGSEM_IO_NAND_READONLY + return -EROFS; +#else + int rv; + CYG_BYTE oob_packed[dev->spare_per_page]; + CYG_BYTE ecc[CYG_NAND_ECCPERPAGE(dev)]; + + const int do_hw_ecc = (dev->ecc->flags & NAND_ECC_FLAG_IS_HARDWARE); + const unsigned write_data_stride = do_hw_ecc ? dev->ecc->data_size : CYG_NAND_BYTES_PER_PAGE(dev); + const unsigned ecc_data_stride = dev->ecc->data_size; + const unsigned ecc_stride = dev->ecc->ecc_size; + size_t remain; + CYG_BYTE *ecc_dest = ecc; + + memset(ecc, 0xff, CYG_NAND_ECCPERPAGE(dev)); + + if (src) CYG_CHECK_DATA_PTRC(src); + if (spare) CYG_CHECK_DATA_PTRC(spare); + CYG_ASSERTC(CYG_NAND_BYTES_PER_PAGE(dev) % ecc_data_stride == 0); + + TIMETAG(); + // If we're doing software ECC, do it all in one go now. + if (src && !do_hw_ecc) { + const CYG_BYTE *data_src = src; + remain = CYG_NAND_BYTES_PER_PAGE(dev); + + while (remain) { + CYG_ASSERTC(remain >= ecc_data_stride); + if (dev->ecc->init) dev->ecc->init(dev); + dev->ecc->calc(dev, data_src, ecc_dest); + + remain -= ecc_data_stride; + data_src += ecc_data_stride; + ecc_dest += ecc_stride; + } + } + TIMETAG(); + + EG(dev->fns->write_begin(dev, page)); + TIMETAG(); + if (src) { + remain = CYG_NAND_BYTES_PER_PAGE(dev); + while (remain) { + CYG_ASSERTC(remain >= write_data_stride); + TIMETAG(); + if (do_hw_ecc && dev->ecc->init) dev->ecc->init(dev); + EG(dev->fns->write_stride(dev, src, write_data_stride)); + TIMETAG(); + if (do_hw_ecc) { + dev->ecc->calc(dev, 0, ecc_dest); + ecc_dest += ecc_stride; + } + src += write_data_stride; + remain -= write_data_stride; + } + } + TIMETAG(); + + nand_oob_pack(dev, spare, spare_size, ecc, oob_packed); + NAND_CHATTER(8,dev,"Write page %u\n", page); + EG(dev->fns->write_finish(dev, oob_packed, dev->spare_per_page)); + TIMETAG(); + + /* N.B. We don't read-back to verify; drivers may do so themselves if + * they wish. Typically the spec sheet says that a read-back test + * is unnecessary if the device reports a successful program, and + * if ECC is being used. */ + +err_exit: + return rv; +#endif +} + +__externC +int cyg_nandp_erase_block(cyg_nand_partition *prt, cyg_nand_block_addr pblk) +{ +#ifdef CYGSEM_IO_NAND_READONLY + return -EROFS; +#else + PARTITION_CHECK(prt); + cyg_nand_device *dev = prt->dev; + int rv; + DEV_INIT_CHECK(dev); + cyg_nand_block_addr blk = BLOCK_P_TO_D(prt, pblk); + + TIMETAG(); + LOCK_DEV(dev); + TIMETAG(); + + EG(valid_block_addr(prt, blk)); +#ifdef CYGSEM_IO_NAND_USE_BBT + if (cyg_nand_bbti_query(dev, blk) != CYG_NAND_BBT_OK) { + NAND_CHATTER(1,dev,"Asked to erase bad block %u\n", blk); + EG(-EINVAL); + } +#endif + NAND_CHATTER(8,dev,"Erasing block %u\n", blk); + rv = dev->fns->erase_block(dev, blk); + if (rv==-EIO) { +#ifdef CYGSEM_IO_NAND_USE_BBT + cyg_nand_bbti_markbad(dev, blk); // deliberate ignore +#endif + EG(rv); + } +err_exit: + TIMETAG(); + UNLOCK_DEV(dev); + TIMETAG(); + return rv; +#endif +} + +__externC +int cyg_nandp_bbt_query(cyg_nand_partition *prt, cyg_nand_block_addr pblk) +{ +#ifdef CYGSEM_IO_NAND_USE_BBT + int rv; + PARTITION_CHECK(prt); + cyg_nand_device *dev = prt->dev; + DEV_INIT_CHECK(dev); + cyg_nand_block_addr blk = BLOCK_P_TO_D(prt, pblk); + LOCK_DEV(dev); + EG(valid_block_addr(prt, blk)); + rv = cyg_nand_bbti_query(dev, blk); +err_exit: + UNLOCK_DEV(dev); + return rv; +#else + return -ENOSYS; +#endif +} + +__externC +int cyg_nandp_bbt_markbad(cyg_nand_partition *prt, cyg_nand_block_addr pblk) +{ +#ifdef CYGSEM_IO_NAND_USE_BBT + int rv; + PARTITION_CHECK(prt); + cyg_nand_device *dev = prt->dev; + DEV_INIT_CHECK(dev); + cyg_nand_block_addr blk = BLOCK_P_TO_D(prt, pblk); + LOCK_DEV(dev); + EG(valid_block_addr(prt, blk)); + EG(cyg_nand_bbti_markbad(dev, blk)); +err_exit: + UNLOCK_DEV(dev); + return rv; +#else + return -ENOSYS; +#endif +} + +__externC +int cyg_nand_bbt_markbad_pageaddr(cyg_nand_partition *prt, cyg_nand_page_addr ppg) +{ +#ifdef CYGSEM_IO_NAND_USE_BBT + int rv; + PARTITION_CHECK(prt); + cyg_nand_device *dev = prt->dev; + DEV_INIT_CHECK(dev); + cyg_nand_block_addr pblk = CYG_NAND_PAGE2BLOCKADDR(dev, ppg); + cyg_nand_block_addr blk = BLOCK_P_TO_D(prt, pblk); + EG(valid_block_addr(prt, blk)); + LOCK_DEV(dev); + EG(cyg_nand_bbti_markbad(dev, blk)); +err_exit: + UNLOCK_DEV(dev); + return rv; +#else + return -ENOSYS; +#endif +} + +/* Computes the ECC for a whole device page. + * 'page' points to the data; a whole page will necessarily be read. + * The computed ECC will be stored in 'ecc_o'; CYG_NAND_ECCPERPAGE(dev) + * bytes will be written. */ +void nand_ecci_calc_page(cyg_nand_device *dev, const CYG_BYTE *page, CYG_BYTE *ecc_o) +{ + int i; + const int nblocks = (1<<dev->page_bits) / dev->ecc->data_size; + + CYG_CHECK_DATA_PTRC(page); + CYG_CHECK_DATA_PTRC(ecc_o); + + for (i=0; i<nblocks; i++) { + if (dev->ecc->init) + dev->ecc->init(dev); + dev->ecc->calc(dev,page,ecc_o); + page += dev->ecc->data_size; + ecc_o += dev->ecc->ecc_size; + } +} + +/* Checks and (if necessary) repairs the ECC for (up to) a whole device page. + * 'page' points to the data; an error at position after @nbytes@ will not + * be corrected. + * Broadly the same semantics as for cyg_nand_ecc_t.repair; + * both ECCs are of size CYG_NAND_ECCPERPAGE(dev), and ecc_read may + * be corrected as well as the data. + * Returns: + * 0 for no errors + * 1 if there was at least one corrected data error + * 2 if there was at least one corrected ECC error + * 3 if there was at least one corrected error in both data and ECC + * -1 if there was an uncorrectable error (>1 bit in a single ECC block) + */ +int nand_ecci_repair_page(cyg_nand_device *dev, CYG_BYTE *page, size_t remain, + CYG_BYTE *ecc_read, const CYG_BYTE *ecc_calc) +{ + int i, page_rv=0; + const int nblocks = (1<<dev->page_bits) / dev->ecc->data_size; + CYG_CHECK_DATA_PTRC(page); + CYG_CHECK_DATA_PTRC(ecc_read); + CYG_CHECK_DATA_PTRC(ecc_calc); + + for (i=0; i<nblocks; i++) { + int stride = dev->ecc->data_size; + if (stride > remain) stride = remain; + int chunk_rv = dev->ecc->repair(dev,page,stride,ecc_read,ecc_calc); + if (chunk_rv < 0) return chunk_rv; + page_rv |= chunk_rv; + page += dev->ecc->data_size; + remain -= dev->ecc->data_size; + ecc_read += dev->ecc->ecc_size; + ecc_calc += dev->ecc->ecc_size; + } + return page_rv; +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nand_bbt.c @@ -0,0 +1,702 @@ +//============================================================================= +// +// nand_bbt.c +// +// eCos NAND flash library - bad block table +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-11 +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* This source is intended to be on-chip compatible with the Linux MTD layer. + * TODO: Multi-chip devices are not yet implemented. + * ASSUMPTION: 1<<blockcount_bits will fit in an int. + */ + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/util.h> +#include "nand_bbt.h" +#include CYGBLD_ISO_ERRNO_CODES_HEADER +#include <string.h> +#include <stdlib.h> + +/* ============================================================ */ +// We need a global page buffer so we can manipulate the +// Bad Block Table. This has to be big enough for the largest +// sized page we will handle, so each driver has to declare +// it with a _requires_ statement in its CDL. + +#if CYGNUM_NAND_PAGEBUFFER == 0 +#error CYGNUM_NAND_PAGEBUFFER not set +/* If you've tripped over this error, it means that either there are + * no NAND drivers present in your config, or they don't correctly + * impose a requirement on CYGNUM_NAND_PAGEBUFFER and therefore + * the logic that uses the global pagebuffer (in nand_bbt.c) could + * not possibly work correctly. + */ +#endif + +static unsigned char bbt_pagebuf[CYGNUM_NAND_PAGEBUFFER]; + + +cyg_drv_mutex_t nand_bbt_pagebuf_lock; + +__externC void cyg_nand_bbt_initx(void) +{ + cyg_drv_mutex_init(&nand_bbt_pagebuf_lock); +} + +#define LOCK_PAGEBUF() do { \ + cyg_drv_mutex_lock(&nand_bbt_pagebuf_lock); \ + i_locked = 1; \ +} while(0) + +#define UNLOCK_PAGEBUF() do { \ + cyg_drv_mutex_unlock(&nand_bbt_pagebuf_lock); \ + i_locked = 0; \ +} while(0) + +CYG_BYTE* nandi_grab_pagebuf(void) +{ + cyg_drv_mutex_lock(&nand_bbt_pagebuf_lock); + return &bbt_pagebuf[0]; +} + +void nandi_release_pagebuf(void) +{ + cyg_drv_mutex_unlock(&nand_bbt_pagebuf_lock); +} + +#ifdef CYGSEM_IO_NAND_USE_BBT + +#ifndef CYGSEM_IO_NAND_READONLY +static int cyg_nand_bbti_write_tables(cyg_nand_device *dev, int is_initial); +#endif + +/* Mapping between on-chip and in-ram statuses ===================== */ +static inline cyg_nand_bbt_status_t chip_2_ram(nand_bbti_onchip_status_t in) +{ + switch(in) { + case BBTI_FACTORY_BAD: return CYG_NAND_BBT_FACTORY_BAD; + case BBTI_WORNBAD_1: return CYG_NAND_BBT_WORNBAD; + case BBTI_WORNBAD_2: return CYG_NAND_BBT_WORNBAD; + case BBTI_OK: return CYG_NAND_BBT_OK; + } + CYG_FAIL("Invalid input to chip_2_ram"); + return CYG_NAND_BBT_FACTORY_BAD; +} + +static inline nand_bbti_onchip_status_t ram_2_chip(cyg_nand_bbt_status_t in) +{ + switch(in) { + case CYG_NAND_BBT_FACTORY_BAD: return BBTI_FACTORY_BAD; + case CYG_NAND_BBT_WORNBAD: return BBTI_WORNBAD_1; + case CYG_NAND_BBT_RESERVED: return BBTI_OK; + case CYG_NAND_BBT_OK: return BBTI_OK; + } + CYG_FAIL("Invalid input to ram_2_chip"); + return BBTI_FACTORY_BAD; +} + +/* ============================================================= */ + +/* Update the in-RAM table, but do _not_ write it out. Unchecked! */ +static void bbti_mark_raw(cyg_nand_device *dev, cyg_nand_block_addr blk, + cyg_nand_bbt_status_t st) +{ + unsigned offset = blk >> 2; + unsigned byteshift = (blk & 3) * 2; + dev->bbt.data[offset] = + (dev->bbt.data[offset] &~ (3 << byteshift)) | (st << byteshift); +} + +int cyg_nand_bbti_query(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + CYG_ASSERT(blk >= 0 && blk <= CYG_NAND_BLOCKCOUNT(dev), "valid block"); + unsigned offset = blk >> 2; + unsigned byteshift = (blk & 3) * 2; + return ( dev->bbt.data[offset] >> byteshift ) & 3; +} + +int cyg_nand_bbti_markany(cyg_nand_device *dev, cyg_nand_block_addr blk, + cyg_nand_bbt_status_t st) +{ + CYG_ASSERT(blk >= 0 && blk <= CYG_NAND_BLOCKCOUNT(dev), "valid block"); + bbti_mark_raw(dev, blk, st); +#ifdef CYGSEM_IO_NAND_READONLY + NAND_CHATTER(2,dev,"ignoring mark request on read-only config\n"); + return -ENOSYS; +#else + int rv = cyg_nand_bbti_write_tables(dev,0); + if (rv) + NAND_ERROR(dev,"nand_bbti_mark %d as %d: %d (%s)\n", blk, st, -rv, strerror(-rv)); + return rv; +#endif +} + +int cyg_nand_bbti_markbad(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + CYG_ASSERT(blk >= 0 && blk <= CYG_NAND_BLOCKCOUNT(dev), "valid block"); + return cyg_nand_bbti_markany(dev, blk, CYG_NAND_BBT_WORNBAD); +} + + +/* Search for, and read in, the BBTs. + * + * Algorithm: Start at the last block, work backwards (up to 4 blocks) + * looking for the signature. + * DEVICE MUST BE LOCKED. + * Table descriptor patterns are 'Bbt0' primary / '1tbB' mirror. + * Descriptors are located at offset 8 of the OOB area of the first + * page of the block, length 4 bytes. + * Table version tags are ON by default. + * Version tag is a _single byte_ at offset 12 within the OOB area of + * the first page of the block. A freshly created table has version 1; + * it is incremented whenever the table is updated. + * (FIXME: What happens after version 255 is not defined.) + * If both tables are the same version, either may be used. + * If their versions differ, the higher version is used. + */ + +static CYG_BYTE nand_pattern_primary[] = { 'B','b','t','0' }; +static CYG_BYTE nand_pattern_mirror [] = { '1','t','b','B' }; +#define NAND_PATTERN_OFFSET 8 +#define NAND_PATTERN_SIZE 4 +#define NAND_VERSION_OFFSET 12 +#define NAND_VERSION_SIZE 1 + +#define EG(x) do { rv = (x); if (rv != 0) goto err_exit; } while(0) + +/* Of these two block states, which is worst? + * "current" is a CYG_NAND_BBT_ (in-RAM) state. + * "onchip" is a BBTI_ state (on-chip!) + * Output is in-RAM format (CYG_NAND_BBT_). + * */ +static inline CYG_BYTE worst_of_the_two(CYG_BYTE current, CYG_BYTE onchip) +{ + CYG_ASSERT( (current == (current&3)) && (onchip == (onchip&3)), "invalid input to w_o_t_t"); + /* + * OnChip | OK WornBad Reserved FactoryBad < Current + * | 00 01 10 11 + * +--------------------------------------- + * FB 00 | FB 11 FB 11 FB 11 FB 11 { + * | + * WB 01 | WB 01 WB 01 WB 01 FB 11 { Output + * or 10 | + * | + * OK 11 | OK 00 WB 01 Res 10 FB 11 { + * + * ('Reserved' never appears on chip.) + */ + // Let the compiler take the strain, lookup tables are vv cheap + switch ( (onchip << 2) | current) { + // I would have used '0b0000' syntax, but gcc 3 doesn't support it + case 0: case 1: case 2: case 3: + return 3; + + case 4: case 8: + case 5: case 9: + case 6: case 10: + return 1; + case 7: case 11: + return 3; + + case 12: return 0; + case 13: return 1; + case 14: return 2; + case 15: return 3; + } + /* should never get here, indicates bad input and asserts disabled */ + return current; // least bad alternative if asserts disabled +} + +static int bbti_incorporate_one(cyg_nand_device *dev, cyg_nand_block_addr blk, CYG_BYTE version) +{ + int rv = 0, i_locked = 0; + LOCK_PAGEBUF(); + + cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(dev,blk); + unsigned char *optr = dev->bbt.data; + + if (version > dev->bbt.version) dev->bbt.version = version; + + int blks_to_read = 1 << dev->blockcount_bits; + while (blks_to_read>0) { + rv = nandi_read_whole_page_raw(dev, pg, bbt_pagebuf, 0, 0, 1); + // read_page_raw does the ecc for us, and we don't care about the OOB here as we already know it's one of ours. + if (rv<0) { + // This is bad. + int is_primary = blk == dev->bbt.primary; + NAND_CHATTER(1,dev, "Reading BBT %s (page %u): uncorrectable error\n", is_primary ? "primary" : "mirror", pg); + (void) is_primary; + EG(rv); + } + if (rv>0) { + NAND_CHATTER(2,dev,"Reading BBT page %u: ECC repaired, code %d\n", pg, rv); + rv=0; + } + + unsigned char *iptr = bbt_pagebuf; + int data = blks_to_read / 4; /* one byte per 4 blocks on-chip */ + if (data > (1<<dev->page_bits)) + data = (1<<dev->page_bits); + + while (data) { + unsigned char inp = *iptr; + unsigned char cur = *optr; + unsigned char out = 0; + int j; + + // Each byte tells us about four blocks; so does each output byte + // NB: Currently hard-coded to 2 bits both in RAM and on chip! + for (j=0; j<8; j+=2) { + unsigned char newchip = (inp >> j) & 3; + //unsigned char new_ram = chip_2_ram(newchip); + unsigned char curstat = (cur >> j) & 3; + + unsigned char new_ram = worst_of_the_two(curstat, newchip); + + // MTD does it in this order too. + out |= new_ram << j; + } + *optr = out; + ++iptr; ++optr; --data; blks_to_read -= 4; + } // inner while(data) + ++pg; + } // outer while(blks_to_read>0) +err_exit: + if (i_locked) UNLOCK_PAGEBUF(); + return rv; +} + +/* ============================================================= */ + +static int nandi_bbt_packing_test(cyg_nand_device *dev) +{ + // Startup sanity check: Can we pack the BBT marker and version into the app spare area, do they appear in the right place, and can we extract them? + CYG_BYTE appspare[CYG_NAND_APPSPARE_PER_PAGE(dev)], + packed[CYG_NAND_SPARE_PER_PAGE(dev)], + testdata[NAND_PATTERN_SIZE > NAND_VERSION_SIZE ? NAND_PATTERN_SIZE : NAND_VERSION_SIZE], + ecc[CYG_NAND_ECCPERPAGE(dev)]; + int i, rv, fail = 0; + +#define MAGIC 42 + memset(ecc, 0xff, sizeof ecc); + memset(testdata, 0, sizeof testdata); + for (i=0; i<NAND_PATTERN_SIZE; i++) + testdata[i] = i+MAGIC; + + i = nand_oob_packed_write(dev, NAND_PATTERN_OFFSET, NAND_PATTERN_SIZE, appspare, testdata); + if (i == 0) + i = nand_oob_packed_write(dev, NAND_VERSION_OFFSET, NAND_VERSION_SIZE, appspare, testdata); + + if (i != 0) { + NAND_ERROR(dev,"BUG: BBT ident/version offset will not fit into this device's spare area\n"); + /* Read the warning in nand_oob.c by nand_mtd_oob_8. + * To make that work, you have to teach this layer how to find + * the BBT on such a device. */ + EG(-ENOSYS); + } + + nand_oob_pack(dev, appspare, sizeof appspare, ecc, packed); + for (i=0; i<NAND_PATTERN_SIZE; i++) + if (packed[NAND_PATTERN_OFFSET + i] != i + MAGIC) + ++fail; + for (i=0; i<NAND_VERSION_SIZE; i++) + if (packed[NAND_PATTERN_OFFSET + i] != i + MAGIC) + ++fail; + + if (fail) { + NAND_ERROR(dev, "BUG: NAND BBT tag pack did not work"); + EG(-ENOSYS); + } + + memset(appspare, 0xff, sizeof appspare); + nand_oob_unpack(dev, appspare, sizeof appspare, ecc, packed); + + memset(testdata, 0, sizeof testdata); + i = nand_oob_packed_read(dev, NAND_PATTERN_OFFSET, NAND_PATTERN_SIZE, appspare, testdata); + for (i=0; i<NAND_PATTERN_SIZE; i++) + if (testdata[i] != i + MAGIC) + ++fail; + + memset(testdata, 0, sizeof testdata); + i = nand_oob_packed_read(dev, NAND_VERSION_OFFSET, NAND_VERSION_SIZE, appspare, testdata); + for (i=0; i<NAND_VERSION_SIZE; i++) + if (testdata[i] != i + MAGIC) + ++fail; + + for (i=0; i < sizeof ecc; i++) + if (ecc[i] != 0xff) + ++fail; + + if (fail) { + NAND_ERROR(dev, "BUG: NAND BBT tag unpack did not work"); + EG(-ENOSYS); + } + + rv = 0; +err_exit: + return rv; +} + +/* ============================================================= */ + +#if (NAND_VERSION_SIZE != 1) +#error CT_ASSERT: BBT version handling needs recoded +#endif + +/* Looks for the BBT copies, or for plausible places to put them. + * If @find_only@: outputs are set to 0xFFFFFFFF where the respective + * ident patterns are not found. + * Else: outputs are set to plausible-looking places to write BBTs; + * where the ident patterns are found, those block IDs are used. + * Only if there is nowhere plausible to go (blocks marked bad) then + * the relevant output(s) are set to 0xFFFFFFFF. + * If live BBTs were found, their version identifiers will be stored + * in *pri_ver and *mir_ver. If not, they will be untouched. + */ +static int nandi_find_bbt_locations(cyg_nand_device *dev, + cyg_nand_block_addr *pri_o, CYG_BYTE*pri_ver, + cyg_nand_block_addr *mir_o, CYG_BYTE*mir_ver, int find_only) +{ + cyg_nand_block_addr start = (1<<dev->blockcount_bits) - 1; + CYG_BYTE oobbuf[CYG_NAND_APPSPARE_PER_PAGE(dev)]; + CYG_BYTE patternbuf[NAND_PATTERN_SIZE]; + CYG_BYTE versionbuf[NAND_VERSION_SIZE]; + int i, rv=0; + cyg_nand_block_addr pri, mir, maybepri, maybemir; + pri = mir = maybepri = maybemir = 0xFFFFFFFF; + + for (i=0; i<4; i++) { + cyg_nand_block_addr blk = start-i; + cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(dev,blk); + +#define BAD(b) ((cyg_nand_bbti_query(dev,b) != CYG_NAND_BBT_OK) && (cyg_nand_bbti_query(dev,b) != CYG_NAND_BBT_RESERVED)) + if (BAD(blk)) continue; + + // look for the pattern + memset(oobbuf, 0xff, sizeof oobbuf); + rv = nandi_read_whole_page_raw(dev, pg, 0, oobbuf, sizeof oobbuf, 1); + if (rv<0) { + NAND_CHATTER(1,dev, "find_bbt_locations: Error %d reading OOB of page %u (block %u)\n", -rv, pg, blk); + EG(-EIO); + } + + rv = nand_oob_packed_read(dev, NAND_PATTERN_OFFSET, NAND_PATTERN_SIZE, oobbuf, patternbuf); + if (rv != 0) EG(-EIO); // should never fail given the sanity check above + rv = nand_oob_packed_read(dev, NAND_VERSION_OFFSET, NAND_VERSION_SIZE, oobbuf, versionbuf); + if (rv != 0) EG(-EIO); // should never fail given the sanity check above + + if (0==memcmp(patternbuf, nand_pattern_primary, NAND_PATTERN_SIZE)) { + CYG_BYTE found_ver = *versionbuf; + if (found_ver > *pri_ver) { + *pri_ver = found_ver; + pri = blk; + continue; + } + } + if (0==memcmp(patternbuf, nand_pattern_mirror, NAND_PATTERN_SIZE)) { + CYG_BYTE found_ver = *versionbuf; + if (found_ver > *mir_ver) { + *mir_ver = found_ver; + mir = blk; + continue; + } + } + if (find_only) continue; + + // It's not an existing table, and it's not bad, so it might be + // a plausible place to put one. + + if (maybepri == 0xFFFFFFFF) { + maybepri = blk; + continue; + } + + if (maybemir == 0xFFFFFFFF) { + maybemir = blk; + continue; + } +#undef BAD + } + *pri_o = (pri == 0xFFFFFFFF) ? maybepri : pri; + *mir_o = (mir == 0xFFFFFFFF) ? maybemir : mir; + +err_exit: + return rv; +} + + +int cyg_nand_bbti_find_tables(cyg_nand_device *dev) +{ + int rv = 0, got = 0; + CYG_BYTE pri_ver = 0, mir_ver = 0; + + NAND_CHATTER(3,dev, "Looking for bad-block table:\n"); + /* TODO: What happens if a BBT block goes bad? Can we put it beyond use? + * - erasing it _should_ clear the descriptor pattern. + * Obviously, we should look for further instances of the BBT patterns + * with fresher version tag(s). */ + + EG(nandi_bbt_packing_test(dev)); + EG(nandi_find_bbt_locations(dev, &dev->bbt.primary, &pri_ver, &dev->bbt.mirror, &mir_ver, 1)); + + /* OK, we found one or both, so read them in. + * We must read both, if available, and OR them together. */ + + // TODO: Default pattern hard-coded for now. +#define all_ok_pattern ( CYG_NAND_BBT_OK | (CYG_NAND_BBT_OK << 2) | \ + (CYG_NAND_BBT_OK << 4) | (CYG_NAND_BBT_OK << 6) ) + memset(dev->bbt.data, all_ok_pattern, dev->bbt.datasize); + + if (dev->bbt.primary != 0xFFFFFFFF) { + ++got; + NAND_CHATTER(3,dev, "Found primary BBT in block %u\n", dev->bbt.primary); + rv = bbti_incorporate_one(dev, dev->bbt.primary, pri_ver); + bbti_mark_raw(dev, dev->bbt.primary, CYG_NAND_BBT_RESERVED); + } + + int rv2 = 0; + if (dev->bbt.mirror != 0xFFFFFFFF) { + ++got; + NAND_CHATTER(3,dev, "Found mirror BBT in block %u\n", dev->bbt.mirror); + rv2 = bbti_incorporate_one(dev, dev->bbt.mirror, mir_ver); + bbti_mark_raw(dev, dev->bbt.mirror, CYG_NAND_BBT_RESERVED); + } + + if (!got) { + NAND_CHATTER(3,dev,"Found no BBTs on chip\n"); + EG(-ENOENT); + } + + if ( (rv < 0) && (rv2 < 0) ) { + NAND_ERROR(dev, "No BBT usable - disabling device\n"); + EG(-EIO); + } + + /* TODO: The choice of BBT location and behaviour (BBT versioning; + * on-chip format) could in future be affected by CDL options or by + * device-specific settings. + * The Linux MTD layer has some examples of this. */ +err_exit: + return rv; +} + +/* Creates the initial BBTs by running a scan for factory bad blocks. + * Returns: 0 if OK, else a -ve error code. + */ +int cyg_nand_bbti_build_tables(cyg_nand_device *dev) +{ + cyg_nand_block_addr blk, max = (1<<dev->blockcount_bits); + + NAND_CHATTER(1, dev, "Scanning for factory-bad blocks:\n"); + + for (blk=0; blk < max; blk++) { + int rv = dev->fns->is_factory_bad(dev, blk); + if (rv<0) { + NAND_ERROR(dev,"NAND factory-bad scan failed on block %u (%u: %s)\n", blk, -rv, strerror(-rv)); + return rv; + } + if (rv) { + bbti_mark_raw(dev, blk, CYG_NAND_BBT_FACTORY_BAD); + NAND_CHATTER(2, dev, "bad: %u\n", blk); + } + } + NAND_CHATTER(2, dev, "... done\n"); + +#ifdef CYGSEM_IO_NAND_READONLY + NAND_CHATTER(1,dev, "Read-only config: not writing out BBT\n"); + return 0; +#else + /* This is a virgin device, so we have free choice. + * write_tables() takes care of choosing where. + */ + + dev->bbt.version = 0; /* write_tables() will bump to 1, which is correct */ + + int rv = cyg_nand_bbti_write_tables(dev, 1); + if (rv<0) + NAND_ERROR(dev,"Error %d writing out initial BBT: %s\n", -rv, strerror(-rv)); + else + NAND_CHATTER(3,dev, "Chosen BBT locations: primary %u, mirror %u\n", dev->bbt.primary, dev->bbt.mirror); + + if (dev->bbt.primary != 0xFFFFFFFF) + bbti_mark_raw(dev, dev->bbt.primary, CYG_NAND_BBT_RESERVED); + if (dev->bbt.mirror != 0xFFFFFFFF) + bbti_mark_raw(dev, dev->bbt.mirror, CYG_NAND_BBT_RESERVED); + + return rv; +#endif +} + +#ifndef CYGSEM_IO_NAND_READONLY +/* Erases and writes out a single copy of the BBT. + * If an error occurred, returns appropriately; if -EIO, there was + * evidently a write error in writing out the BBT and we need to restart + * the write loop... */ +static int bbti_write_one_table(cyg_nand_device *dev, + cyg_nand_block_addr blk, CYG_BYTE *pattern) +{ + const unsigned pagesize = 1 << dev->page_bits; + size_t bbt_disk_size = (1<<dev->blockcount_bits)/4; + + int st = cyg_nand_bbti_query(dev, blk); + if (st == CYG_NAND_BBT_WORNBAD) { + NAND_ERROR(dev, "BBT block %u is worn-bad, not updating\n", blk); + return 0; + } + + int rv = dev->fns->erase_block(dev, blk); + if (rv<0) { + /* We can't arbitrarily pick another block for the BBT, + * because we might trample on application data. + * All the Linux MTD layer does is warn and error out, + * so that's good enough for us. */ + NAND_ERROR(dev,"Erase BBT block %u failed; cannot update table!\n", blk); + return rv; + } + + cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(dev,blk); + + CYG_BYTE *iptr = dev->bbt.data; + int to_write = bbt_disk_size; // on-chip size, number of bytes + int i_locked = 0; + + LOCK_PAGEBUF(); + + while (to_write) { + CYG_BYTE *optr = bbt_pagebuf; + int this_write = to_write; + if (this_write >= pagesize) + this_write = pagesize; + else + memset(bbt_pagebuf, 0xff, sizeof(bbt_pagebuf)); + + /* Hard-coded 2-bit conversion for now. */ + while (this_write) { + CYG_BYTE d = *iptr, + out = 0; + int j; + for (j=0; j<8; j+=2) { + CYG_BYTE inp = (d >> j) & 3; + out |= ram_2_chip(inp) << j; + } + *optr = out; + --to_write; --this_write; ++iptr; ++optr; + } + + /* Prep ECC & OOB, then send */ + CYG_BYTE appspare[CYG_NAND_APPSPARE_PER_PAGE(dev)]; + memset(appspare, 0xff, sizeof appspare); + + rv = nand_oob_packed_write(dev, NAND_PATTERN_OFFSET, NAND_PATTERN_SIZE, appspare, pattern); + if (rv != 0) EG(-EIO); // Should never fail, we've passed the startup sanity check. + rv = nand_oob_packed_write(dev, NAND_VERSION_OFFSET, NAND_VERSION_SIZE, appspare, &dev->bbt.version); + if (rv != 0) EG(-EIO); // Should never fail, we've passed the startup sanity check. + + rv = nandi_write_page_raw(dev, pg, bbt_pagebuf, appspare, sizeof appspare); + if (rv==-EIO) { + /* Ouch. Our BBT block has failed. We cannot write another, + * as we might trample app data. We'll mark bad, and hope + * that the other copy is still usable. */ + bbti_mark_raw(dev, blk, CYG_NAND_BBT_WORNBAD); + NAND_ERROR(dev, "Write error on BBT block %u, marking bad\n", blk); + goto err_exit; + } + if (rv<0) { + /* As with an erase fail, we can't do very much here. */ + NAND_ERROR(dev,"Unexpected error writing to BBT block %u; cannot update table!\n", blk); + goto err_exit; + } + ++pg; + } + +err_exit: + UNLOCK_PAGEBUF(); + return rv; +} + + +/* Increments the BBT version, then writes out _both_ tables. + * Caller must have the devlock. */ +static int cyg_nand_bbti_write_tables(cyg_nand_device *dev, int is_initial) +{ + int rv, retries=-1; + +top: + ++retries; + + if (dev->bbt.version == 255) + NAND_ERROR(dev,"Warning! NAND BBT version would overflow, doing the best we can\n"); + else + dev->bbt.version ++; + + CYG_BYTE pri_ver, mir_ver; + rv = nandi_find_bbt_locations(dev, &dev->bbt.primary, &pri_ver, + &dev->bbt.mirror, &mir_ver, is_initial ? 0 : 1); + +#define RETRY_LIMIT 3 + + if (dev->bbt.primary == 0xFFFFFFFF) { + NAND_ERROR(dev,"Cannot find a location to write primary BBT!\n"); + return -EIO; + } else { + rv = bbti_write_one_table(dev, dev->bbt.primary, nand_pattern_primary); + if (rv == -EIO && retries < RETRY_LIMIT) goto top; + } + if (dev->bbt.mirror == 0xFFFFFFFF) { + NAND_ERROR(dev,"Cannot find a location to write mirror BBT!\n"); + return -EIO; + } else { + rv = bbti_write_one_table(dev, dev->bbt.mirror, nand_pattern_mirror); + if (rv == -EIO && retries < RETRY_LIMIT) goto top; + } + + if (retries >= RETRY_LIMIT) + NAND_ERROR(dev, "Warning! Retry limit on BBT writes reached, this shouldn't happen...\n"); + + return 0; +} +#endif + +#endif
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nand_bbt.h @@ -0,0 +1,142 @@ +#ifndef CYGONCE_NAND_BBT_H +# define CYGONCE_NAND_BBT_H +//============================================================================= +// +// nand_bbt.h +// +// Bad Block Table interface for the eCos NAND flash library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-11 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand_device.h> +#include <cyg/nand/nand.h> +#include <pkgconf/io_nand.h> + +/* BEWARE! + * + * Applications should not include this file. + * The functions within do NOT perform device locking. + * All the contents are internal interfaces and subject to + * change without notice. + */ + +/* Bad block table =================================================== */ +#ifdef CYGSEM_IO_NAND_USE_BBT + +/* On-chip values (in a 2-bit wide field). + * Each byte on-chip maps its _least_ significant bits to the _first_ + * block it relates to. (i.e. read with a shifting mask, starting with 0 shift) + * + * Each byte in RAM will be stored in the same way, but with values from + * cyg_nand_bbt_status_t. + */ +typedef enum { + BBTI_FACTORY_BAD=0, + BBTI_WORNBAD_1=1, + BBTI_WORNBAD_2=2, + BBTI_OK=3, +} nand_bbti_onchip_status_t; + +/* Raw unchecked query. Returns a cyg_nand_bbt_status_t enum, + * or -ve error code. */ +int cyg_nand_bbti_query(cyg_nand_device *dev, cyg_nand_block_addr blk); + +/* Marks a block as bad. Returns 0 for success, or -ve error code. + * Caller must have locked the devlock. */ +int cyg_nand_bbti_markbad(cyg_nand_device *dev, cyg_nand_block_addr blk); + +/* Marks a block arbitrarily. Normal applications should never use this. + * Returns 0 for success, or -ve error code. + * Caller must have locked the devlock. */ +int cyg_nand_bbti_markany(cyg_nand_device *dev, cyg_nand_block_addr blk, + cyg_nand_bbt_status_t st); + +/* Looks to find the bad block table(s) on the chip and read them in. + * Updates dev->bbt.* as appropriate. + * Caller must have locked the devlock or (more likely) the device not + * be accessible to callers yet (as we're running from nand_lookup). + * + * Returns: 0 if either or both were found; + * -ENOENT if neither; + * something else (-ve error code) if something awful happened. + */ +int cyg_nand_bbti_find_tables(cyg_nand_device *dev); + +/* Creates the initial BBTs by running a scan for factory bad blocks. + * Returns: 0 if OK, else a -ve error code. + * Caller must have locked the devlock or (more likely) the device not + * be accessible to callers yet (as we're running from nand_lookup). + */ +int cyg_nand_bbti_build_tables(cyg_nand_device *dev); + +/* TODO: Make BBT search parameterisable to support non-default behaviour. + * This is probably required in order to support devices with only 8 + * OOB bytes per page. + * + * At present we have hard-coded the default parameters from the Linux MTD + * layer: that the BBT and its mirror can be in one of the last four + * eraseblocks on the device, their signatures 'Bbt0' and '1ttB', the + * offsets of the signature and version byte within the OOB area of the + * first page of the eraseblock. + */ +#endif + +/* Raw unchecked NAND access, for use by the BBT ===================== */ + +/* Takes a DEVICE address. Caller must hold the devlock! */ +int nandi_read_whole_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page, + CYG_BYTE * dest, + CYG_BYTE * spare, size_t spare_size, + int check_ecc); + +/* Takes a DEVICE address. Caller must hold the devlock! */ +int nandi_write_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page, + const CYG_BYTE * src, + const CYG_BYTE * spare, size_t spare_size); + +/* Code outside of the BBT can use the pagebuffer ==================== */ +CYG_BYTE* nandi_grab_pagebuf(void); +void nandi_release_pagebuf(void); + +/* =================================================================== */ + +#endif
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nand_chatter.c @@ -0,0 +1,62 @@ +//============================================================================= +// +// nand_chatter.c +// +// Helper functions for the eCos NAND flash library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-05 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand_device.h> +#include <cyg/infra/diag.h> +#include <stdarg.h> + +__externC int cyg_nand_defaultprintf(const char *fmt, ...) +{ + int rv = 6; + diag_write_string("NAND: "); + va_list va; + va_start(va, fmt); + rv += diag_vprintf(fmt, va); + va_end(va); + return rv; +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nand_ecc_mtd.c @@ -0,0 +1,265 @@ +//============================================================================= +// +// nand_ecc_mtd.c +// +// ECC algorithm from the Linux MTD layer for the eCos NAND flash library +// +//============================================================================= +// +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Steven J. Hill +// Contributors: wry, to patch into eCos NAND library. +// Note: See copyright comment and original boilerplate below. +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* Copyright note: + * I downloaded this file from + * http://git.infradead.org/mtd-cvs.git?a=blob_plain;f=drivers/mtd/nand/nand_ecc.c;hb=e58fa2ce1b32fbc93511b92259c2473e89c463ea + * To confirm its copyright status, check its history: + * http://git.infradead.org/mtd-cvs.git?a=history;f=drivers/mtd/nand/nand_ecc.c + * Note that the commit changing this file (in this incarnation) to + * GPL+Library Exception was made by sjhill, its original author. + * + * - wry, 2009-03-13 + */ + +/* + * This file contains an ECC algorithm from Toshiba that detects and + * corrects 1 bit errors in a 256 byte block of data. + * + * drivers/mtd/nand/nand_ecc.c + * + * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) + * Toshiba America Electronics Components, Inc. + * + * $Id: nand_ecc.c,v 1.11 2004/05/05 14:19:42 sjhill Exp $ + * + * This file 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 file 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 file; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or use + * macros or inline functions from these files, or you compile these + * files and link them with other works to produce a work based on these + * files, these files do not by themselves cause the resulting work to be + * covered by the GNU General Public License. However the source code for + * these files must still be made available in accordance with section (3) + * of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + */ + +#include <cyg/infra/cyg_type.h> +#include <cyg/nand/nand_ecc.h> +typedef CYG_BYTE u_char; + +/* + * Pre-calculated 256-way 1 byte column parity + */ +static const u_char nand_ecc_precalc_table[] = { + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 +}; + + +/* + * Creates non-inverted ECC code from line parity + */ +void nand_trans_result(u_char reg2, u_char reg3, + u_char *ecc_code) +{ + u_char a, b, i, tmp1, tmp2; + + /* Initialize variables */ + a = b = 0x80; + tmp1 = tmp2 = 0; + + /* Calculate first ECC byte */ + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + a >>= 1; + } + + /* Calculate second ECC byte */ + b = 0x80; + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + a >>= 1; + } + + /* Store two of the ECC bytes */ + ecc_code[0] = tmp1; + ecc_code[1] = tmp2; +} + +/* + * Calculate 3 byte ECC code for 256 byte block + */ +static void mtd_calculate_ecc(struct _cyg_nand_device_t *dev, + const u_char *dat, u_char *ecc_code) +{ + u_char idx, reg1, reg2, reg3; + int j; + + /* Initialize variables */ + reg1 = reg2 = reg3 = 0; + ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; + + /* Build up column parity */ + for(j = 0; j < 256; j++) { + u_char d = dat[j]; + + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[d]; + reg1 ^= (idx & 0x3f); + + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (u_char) j; + reg2 ^= ~((u_char) j); + } + } + + /* Create non-inverted ECC code from line parity */ + nand_trans_result(reg2, reg3, ecc_code); + + /* Calculate final ECC code */ + ecc_code[0] = ~ecc_code[0]; + ecc_code[1] = ~ecc_code[1]; + ecc_code[2] = ((~reg1) << 2) | 0x03; +} + +/* + * Detect and correct a 1 bit error for 256 byte block + */ +static int mtd_correct_data(struct _cyg_nand_device_t *dev, + u_char *dat, size_t nbytes, u_char *read_ecc, const u_char *calc_ecc) +{ + u_char a, b, c, d1, d2, d3, add, bit, i; + + /* Do error detection */ + d1 = calc_ecc[0] ^ read_ecc[0]; + d2 = calc_ecc[1] ^ read_ecc[1]; + d3 = calc_ecc[2] ^ read_ecc[2]; + + if ((d1 | d2 | d3) == 0) { + /* No errors */ + return 0; + } + else { + a = (d1 ^ (d1 >> 1)) & 0x55; + b = (d2 ^ (d2 >> 1)) & 0x55; + c = (d3 ^ (d3 >> 1)) & 0x54; + + /* Found and will correct single bit error in the data */ + if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { + c = 0x80; + add = 0; + a = 0x80; + for (i=0; i<4; i++) { + if (d1 & c) + add |= a; + c >>= 2; + a >>= 1; + } + c = 0x80; + for (i=0; i<4; i++) { + if (d2 & c) + add |= a; + c >>= 2; + a >>= 1; + } + bit = 0; + b = 0x04; + c = 0x80; + for (i=0; i<3; i++) { + if (d3 & c) + bit |= b; + c >>= 2; + b >>= 1; + } + b = 0x01; + + if (add < nbytes) { + a = dat[add]; + a ^= (b << bit); + dat[add] = a; + } + return 1; + } + else { + i = 0; + while (d1) { + if (d1 & 0x01) + ++i; + d1 >>= 1; + } + while (d2) { + if (d2 & 0x01) + ++i; + d2 >>= 1; + } + while (d3) { + if (d3 & 0x01) + ++i; + d3 >>= 1; + } + if (i == 1) { + /* ECC Code Error Correction */ + read_ecc[0] = calc_ecc[0]; + read_ecc[1] = calc_ecc[1]; + read_ecc[2] = calc_ecc[2]; + return 2; + } + else { + /* Uncorrectable Error */ + return -1; + } + } + } + + /* Should never happen */ + return -1; +} + +CYG_NAND_ECC_ALG_SW(linux_mtd_ecc, 256, 3, NULL, mtd_calculate_ecc, mtd_correct_data); +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nand_ecc_mtd_fast.c @@ -0,0 +1,238 @@ +//============================================================================= +// +// nand_ecc_mtd_fast.c +// +// ECC algorithm compatible with the Linux MTD layer +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-11-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* Note on development: + * + * Inspired by the useful discussion of Frans Meulenbroeks' efforts to speed + * up software ECC[0], I set about rewriting our code from scratch. + * I have not referred to his source (drivers/mtd/nand/nand_ecc.c) which + * is GPL. + * - wry + * + * [0] Recently committed to the Linux MTD tree. See + * http://git.infradead.org/mtd-2.6.git/blob/HEAD:/Documentation/mtd/nand_ecc.txt + */ + +#include <cyg/infra/cyg_type.h> +#include <cyg/nand/nand_ecc.h> + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +/* This is a precomputed inverse-parity table for single bytes. + * If your camel's back is broken, you could push it into RAM + * and precompute it at boot time, or even fall back to software + * parity calculation. + * You might find Sean Eron Anderson's collection of "Bit Twiddling Hacks" + * useful - see http://graphics.stanford.edu/~seander/bithacks.html . + * That's where this (public domain) macro to generate the table comes from. + */ + +static const CYG_BYTE ParityTable256[256] = +{ +# define P2(n) n, n^1, n^1, n +# define P4(n) P2(n), P2(n^1), P2(n^1), P2(n) +# define P6(n) P4(n), P4(n^1), P4(n^1), P4(n) + P6(1), P6(0), P6(0), P6(1) +}; +#define BYTEPAR(i) ParityTable256[(unsigned char)(i)] + +static void ecc256_fast(struct _cyg_nand_device_t *dev, const CYG_BYTE *data, + CYG_BYTE *ecc) +{ + cyg_uint32 c; // current data word + cyg_uint32 cp,tp; // column and loop-temporary accumulators + // row accumulators + cyg_uint32 p8, p16, p32, p64, p128, p256, p512, p1024; + // alternate-row results holders + cyg_uint32 p8p, p16p, p32p, p64p, p128p, p256p, p512p, p1024p; + unsigned i; + cyg_uint32 *d = (cyg_uint32*)data; + + cp=p8=p16=p32=p64=p128=p256=p512=p1024=0; + + for (i=0; i<8; i++) { +#define NEXT() (c=*(d++)) // do as a macro so we can endian fix later if need be + + tp = NEXT(); + tp^= NEXT(); p32 ^= c; + tp^= NEXT(); p64 ^= c; + tp^= NEXT(); p32 ^= c; p64 ^= c; + p128 ^= tp; + + tp^= NEXT(); + tp^= NEXT(); p32 ^= c; + tp^= NEXT(); p64 ^= c; + tp^= NEXT(); p32 ^= c; p64 ^= c; + p128 ^= tp; // (0--3) (+) (0--7) = (4--7) : saves a couple more XORs :-) + + switch(i) { + case 7: + p256 ^= tp; + case 6: + p512 ^= tp; + case 4: + p1024^= tp; + break; + case 5: + p1024^= tp; + case 1: + p256 ^= tp; + break; + case 3: + p256 ^= tp; + case 2: + p512 ^= tp; + case 0: ; + } + cp^= tp; + } +#define DOALL(M) do { M(32); M(64); M(128); M(256); M(512); M(1024); } while(0) + + // de-bitslice p32 through p1024 +#define SQUASH1(vv) { vv ^= (vv>>16); vv = (vv ^ (vv>>8)) & 0xff; } +#define SQUASH(n) do { SQUASH1(p##n) } while(0) + DOALL(SQUASH); + + // de-bitslice p16, p8 and column parity + p16 = (cp >> 16) & 0xffff; + p16 = (p16 ^ (p16 >>8))& 0xff; + + cp ^= cp>>16; + p8 = cp>>8; + + cp ^= cp>>8; + + // Now, finally, we can work out p8' through p1024' ... +#define COMPUTE(n) do { p##n##p = cp ^ p##n; } while(0) + DOALL(COMPUTE); + COMPUTE(16); + COMPUTE(8); + + ecc[0] = BYTEPAR(p1024) << 7 + | BYTEPAR(p1024p)<< 6 + | BYTEPAR(p512) << 5 + | BYTEPAR(p512p) << 4 + | BYTEPAR(p256) << 3 + | BYTEPAR(p256p) << 2 + | BYTEPAR(p128) << 1 + | BYTEPAR(p128p); + + ecc[1] = BYTEPAR(p64) << 7 + | BYTEPAR(p64p) << 6 + | BYTEPAR(p32) << 5 + | BYTEPAR(p32p) << 4 + | BYTEPAR(p16) << 3 + | BYTEPAR(p16p) << 2 + | BYTEPAR(p8) << 1 + | BYTEPAR(p8p); + + ecc[2] = BYTEPAR(cp & 0xf0) << 7 // p4 + | BYTEPAR(cp & 0x0f) << 6 // p4' + | BYTEPAR(cp & 0xcc) << 5 // p2 + | BYTEPAR(cp & 0x33) << 4 // p2' + | BYTEPAR(cp & 0xaa) << 3 // p1 + | BYTEPAR(cp & 0x55) << 2 // p1' + | 3; +} + +static int ecc256_repair(struct _cyg_nand_device_t *dev, + CYG_BYTE *dat, size_t nbytes, + CYG_BYTE *read_ecc, const CYG_BYTE *calc_ecc) +{ + cyg_uint32 x = (calc_ecc[0] << 16) | (calc_ecc[1] << 8) | calc_ecc[2]; + cyg_uint32 y = (read_ecc[0] << 16) | (read_ecc[1] << 8) | read_ecc[2]; + + x ^= y; + if (x == 0) return 0; // Nothing to do + + // Can we fix it? 11 bits should be set, and as they're stored + // in adjacent pairs within each byte we can use this neat XOR + // trick to make sure that precisely one bit of each pair is set. + + if (( (x ^ (x>>1)) & 0x555554 ) == 0x555554 ) { + // Yes we can ! Figure out the offset. + unsigned byte, bit; + + byte = ( (x >>16) & 0x80) | // P1024 = 0x80 byte addr + ( (x >>15) & 0x40) | + ( (x >>14) & 0x20) | + ( (x >>13) & 0x10) | + ( (x >>12) & 8) | + ( (x >>11) & 4) | + ( (x >>10) & 2) | + ( (x >> 9) & 1); // ... P8 + + bit = ( (x >> 3) & 1) | // P4 + ( (x >> 4) & 2) | // P2 + ( (x >> 5) & 4); // and P1. + + if (byte < nbytes) + dat[byte] ^= (1<<bit); + + return 1; + } + + // No? Is it an ECC dropout? Count the bits... + unsigned i=0; + while (x) { + if (x & 1) ++i; + x >>= 1; + } + if (i==1) { + read_ecc[0] = calc_ecc[0]; + read_ecc[1] = calc_ecc[1]; + read_ecc[2] = calc_ecc[2]; + return 2; + } + // Alas, it is uncorrectable. + return -1; +} + +CYG_NAND_ECC_ALG_SW(mtd_ecc256_fast, 256, 3, 0, ecc256_fast, ecc256_repair); +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nand_oob.c @@ -0,0 +1,201 @@ +//============================================================================= +// +// nand_oob.c +// +// eCos NAND flash library - Out Of Band (spare) area pack/unpack/defs +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-13 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <string.h> +#include <cyg/nand/nand_device.h> +#include <cyg/nand/nand_oob.h> +#include CYGBLD_ISO_ERRNO_CODES_HEADER + +static +void pack(const oob_vector *v, int n_v, const CYG_BYTE *data, int n_data, CYG_BYTE *oob) +{ + int i; + for (i=0; i<n_v; i++) { + int stride = v[i].len; + if (stride > n_data) stride = n_data; + if (!stride) break; + memcpy(&oob[v[i].pos], data, stride); + data += stride; + n_data -= stride; + } +} + +static +void unpack(const oob_vector *v, int n_v, CYG_BYTE *data_o, int data_max, const CYG_BYTE *oob) +{ + int i; + for (i=0; i<n_v; i++) { + int stride = v[i].len; + if (stride > data_max) stride = data_max; + if (!stride) break; + memcpy(data_o, &oob[v[i].pos], stride); + data_o += stride; + data_max -= stride; + } +} + +__externC +void nand_oob_pack( struct _cyg_nand_device_t *dev, + const CYG_BYTE *app, const unsigned app_size, + const CYG_BYTE *ecc, CYG_BYTE *oob_o) +{ + const cyg_nand_oob_layout *layout = dev->oob; + unsigned real_size = app_size; + if(real_size > layout->app_size) real_size = layout->app_size; + pack(layout->ecc, CYG_NAND_OOB_MAX_ECC_SLOTS, ecc, ecc? layout->ecc_size : 0, oob_o); + pack(layout->app, CYG_NAND_OOB_MAX_APP_SLOTS, app, app_size, oob_o); +} + +__externC +void nand_oob_unpack(struct _cyg_nand_device_t *dev, + CYG_BYTE *app_o, const unsigned app_max, + CYG_BYTE *ecc, const CYG_BYTE *oob) +{ + const cyg_nand_oob_layout *layout = dev->oob; + unpack(layout->ecc, CYG_NAND_OOB_MAX_ECC_SLOTS, ecc, ecc? layout->ecc_size : 0, oob); + unpack(layout->app, CYG_NAND_OOB_MAX_APP_SLOTS, app_o, app_max, oob); +} + +/* Writes @len@ bytes of @data@ into an @oobbuf@ such that the data + * will end up at the given @rawpos@ in the packed layout. + * Returns 0 for success or -1 if it's not possible. */ +__externC +int nand_oob_packed_write(struct _cyg_nand_device_t *dev, + size_t rawpos, size_t len, + CYG_BYTE *oobbuf, const CYG_BYTE *data) +{ + const cyg_nand_oob_layout *layout = dev->oob; + int i; + + for (i=0; i<CYG_NAND_OOB_MAX_APP_SLOTS; i++) { + const oob_vector *v = &layout->app[i]; + int offset = rawpos - v->pos; // offset within this vector element (and lower fencepost check) + if (offset >= 0) { + int avail = v->len - offset; // how many bytes can we put in this element, starting at offset? This gives us an upper fencepost check. + if (avail > 0) { + // OK, we can do something here. + if (avail > len) avail = len; + memcpy(&oobbuf[offset], data, len); + len -= avail; + data += avail; + if (!len) return 0; + } + } + oobbuf += v->len; + } + return -1; // it didn't work... +} + +/* Opposite of nand_oob_packed_write. + * Reads @len@ bytes from an application @oobbuf@ such that they + * came from the given @rawpos@ in the packed layout; copies them + * to @data@. + * Returns 0 for success or -1 if it's not possible. */ +__externC +int nand_oob_packed_read(struct _cyg_nand_device_t *dev, + size_t rawpos, size_t len, + const CYG_BYTE *oobbuf, CYG_BYTE *data) +{ + const cyg_nand_oob_layout *layout = dev->oob; + int i; + + for (i=0; i<CYG_NAND_OOB_MAX_APP_SLOTS; i++) { + const oob_vector *v = &layout->app[i]; + int offset = rawpos - v->pos; // offset within this vector element (and lower fencepost check) + if (offset >= 0) { + int avail = v->len - offset; // how many bytes can we put in this element, starting at offset? This gives us an upper fencepost check. + if (avail > 0) { + // OK, we can do something here. + if (avail > len) avail = len; + memcpy(data, &oobbuf[offset], len); + len -= avail; + data += avail; + if (!len) return 0; + } + } + oobbuf += v->len; + } + return -1; // it didn't work... + +} + +// FIXME TODO: create a test case / add to unit test: does it cross boundaries correctly? + +/* Layouts from the Linux MTD layer. */ + +#if 0 +/* + * WARNING: 8 spare bytes per page WILL NOT WORK without further work on + * the BBT layer. (This is because the standard location for the BBT + * identity pattern is at offset 8.) Before enabling this, + * ensure that the BBT layer has an alternative way of determining the + * location of the on-chip BBT, if there is one, or other alternative + * bad-block logic. + */ +const cyg_nand_oob_layout nand_mtd_oob_8 = { + .ecc_size = 3, + .ecc = { { .pos=0, .len=3 } }, + .app_size = 4, + .app = { { .pos=3, .len=2 }, { .pos=6, .len=2} }, +}; +#endif + +const cyg_nand_oob_layout nand_mtd_oob_16 = { + .ecc_size = 6, + .ecc = { { .pos=0, .len=4 }, { .pos=6, .len=2 } }, + .app_size = 8, + .app = { { .pos=8, .len=8} }, +}; + + +const cyg_nand_oob_layout nand_mtd_oob_64 = { + .ecc_size = 24, + .ecc = { { .pos=40, .len=24 } }, + .app_size = 38, + .app = { { .pos=2, .len=38} }, +}; +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/nandinit.cxx @@ -0,0 +1,75 @@ +//============================================================================= +// +// nandinit.cxx +// +// eCos NAND flash library - auto-init magic +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-06-02 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> + +// This is a dummy class so we can execute the NAND package initialiser +// automatically at the right priority. + +__externC void cyg_nand_initx(cyg_nand_printf pf); + +class cyg_nand_init_class { + public: + cyg_nand_init_class(void) { +#if defined(CYGSEM_IO_NAND_DEBUG_FN_DEFAULT) + cyg_nand_initx(CYGSEM_IO_NAND_DEBUG_FN_DEFAULT); +#else + cyg_nand_initx(NULL); +#endif + } +}; + +// And here's an instance of it so that it fires: + +static cyg_nand_init_class _cyg_nand_init CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO); + +/* Device HAL table goes here, in libextras */ + +CYG_HAL_TABLE_BEGIN(cyg_nanddevtab, cyg_nand_dev); +CYG_HAL_TABLE_END(cyg_nanddevtab_end, cyg_nand_dev); +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/src/util.c @@ -0,0 +1,95 @@ +//============================================================================= +// +// util.c +// +// eCos NAND flash library - sundry utilities +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-06-01 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_device.h> +#include CYGBLD_ISO_ERRNO_CODES_HEADER +#include <stdlib.h> +#include <string.h> + +#include <cyg/nand/util.h> + +/* Resolver from dev name (e.g. onboard/0) to device and partition structs + * if there's no /, we'll just look up the device name and - if part isn't + * NULL - set *part to NULL. + * Reasonably foreseeable returns: + * 0 - device (and partition if provided) successfully looked up + * -ENODEV - device name not found + * -ENOENT - device found, partition not found + */ +int cyg_nand_resolve_device(const char *dev, cyg_nand_device **nand, + cyg_nand_partition **part) +{ + if (!dev) return -EINVAL; + CYG_CHECK_DATA_PTRC(dev); + const char *sepa = strchr(dev, '/'); + cyg_nand_device *nandx; + + if (sepa) { // Split it out ... + int len = sepa - dev; + char devalone[1+len]; + strncpy(devalone, dev, len); + devalone[len]=0; + cyg_nand_lookup(devalone, &nandx); + } else { + cyg_nand_lookup(dev, &nandx); + } + + if (nand) *nand = nandx; + if (part) *part = 0; + if (!nandx) return -ENODEV; + + if (!sepa) return 0; // All done + + long partno = strtol(sepa+1, 0, 10); + cyg_nand_partition *partx = cyg_nand_get_partition(nandx, partno); + + if (part) *part = partx; + if (!partx) return -ENOENT; + return 0; +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/.gitignore @@ -0,0 +1,4 @@ +ar4test +mkvector +yaffs_ecc.c +yaffs_ecc.h
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/ar4prng.inl @@ -0,0 +1,80 @@ +//============================================================================= +// +// ar4prng.inl +// +// Inline providing ARC4-based PRNG +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#define _SWAP(_a,_b) do { int tmp = (_a); (_a) = (_b); (_b) = tmp; } while(0) + +typedef struct { + unsigned char S[256]; + int i,j; +} ar4ctx; + +void ar4prng_init(ar4ctx *c, unsigned char *seed, unsigned seedlen) +{ + int i,j=0; + for (i=0; i<256; i++) c->S[i] = i; + for (i=0; i<256; i++) { + j = (j + c->S[i] + seed[i%seedlen]) %256; + _SWAP(c->S[i], c->S[j]); + } + c->i = c->j = 0; +} + +unsigned char ar4prng_next(ar4ctx *c) +{ + c->i = (c->i + 1) %256; + c->j = (c->j + c->S[c->i]) %256; + _SWAP(c->S[c->i], c->S[c->j]); + return c->S[(c->S[c->i] + c->S[c->j])%256]; +} + +void ar4prng_many(ar4ctx *c, unsigned char *optr, unsigned len) +{ + while (len--) *(optr++) = ar4prng_next(c); +} + +#undef _SWAP +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/eccequiv.c @@ -0,0 +1,136 @@ +//============================================================================= +// +// eccequiv.c +// +// Given two software ECC algorithms, confirms their equivalence. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-11-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/testcase.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/nand/util.h> +#include <cyg/infra/diag.h> +#include <stdio.h> +#include <string.h> +#include "ar4prng.inl" + +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +__externC cyg_nand_ecc_t linux_mtd_ecc; + +static CYG_NAND_DEVICE(fakenand, 0, 0, 0, &linux_mtd_ecc, 0); +static CYG_NAND_DEVICE(fakenand2, 0, 0, 0, &mtd_ecc256_fast, 0); + +void init_fakenand(void) +{ + if (fakenand.is_inited) + return; + + fakenand.is_inited = 1; + fakenand.pf = diag_printf; + fakenand.page_bits = 11; // 2048 byte test pattern. + fakenand.oob = &nand_mtd_oob_64; + + fakenand2.is_inited = 1; + fakenand2.pf = diag_printf; + fakenand2.page_bits = 11; // 2048 byte test pattern. + fakenand2.oob = &nand_mtd_oob_64; +} + + +void ecc(cyg_nand_device *dev, const CYG_BYTE *data, CYG_BYTE *out) +{ + if (dev->ecc->init) + dev->ecc->init(dev); + dev->ecc->calc(dev, data, out); +} + +const char msg[]="ECC equivalence check"; + +#define ECC_BUFFER_SIZE 10 +CYG_BYTE buf[CYGNUM_NAND_PAGEBUFFER]; +CYG_BYTE ecc1[ECC_BUFFER_SIZE], ecc2[ECC_BUFFER_SIZE]; + +ar4ctx rng; +extern unsigned char _stext[], _etext[]; + +int cyg_user_start(void) +{ + cyg_nand_device *dev = &fakenand, *dev2 = &fakenand2; + int i, fails=0; + + CYG_TEST_INIT(); + CYG_TEST_INFO(msg); + +#define datasize (fakenand.ecc->data_size) +#define eccsize (fakenand.ecc->ecc_size) + + CYG_ASSERTC(fakenand.ecc->data_size == fakenand2.ecc->data_size); + CYG_ASSERTC(fakenand.ecc->ecc_size == fakenand2.ecc->ecc_size); + + CYG_ASSERTC(datasize <= CYGNUM_NAND_PAGEBUFFER); + CYG_ASSERTC(eccsize <= ECC_BUFFER_SIZE); + + diag_printf("ECC sizes: data %d, ecc %d\n", datasize, eccsize); + + ar4prng_init(&rng,_stext, _etext-_stext); + +#define N_RUNS 10000 + + for (i=0; i<N_RUNS; i++) { + ar4prng_many(&rng, buf, datasize); + ecc(dev, buf, ecc1); + ecc(dev2, buf, ecc2); + if (0 != memcmp(ecc1, ecc2, eccsize)) { + ++fails; + } + } + + if (fails) { + diag_printf("FAIL: %d mismatches\n", fails); + CYG_TEST_FAIL_FINISH(msg); + } else + CYG_TEST_PASS_FINISH(msg); +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/nandunit.c @@ -0,0 +1,221 @@ +//============================================================================= +// +// nandunit.c +// +// Sundry unit tests for various parts of the NAND library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-03-18 +// +//####DESCRIPTIONEND#### +//============================================================================= + +//#define CYG_COMPOUND_TEST +#include <cyg/infra/testcase.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_oob.h> +#include <cyg/infra/diag.h> +#include <string.h> +#include <stdio.h> + +/* This one's a bit sneaky, this unit test is independent of + * any NAND device. So we'll construct a fake plastic cyg_nand_device + * out of whole cloth. */ + +static CYG_NAND_DEVICE(fakenand, 0, 0, 0, &mtd_ecc256_fast, 0); +void init_fakenand(void) +{ + if (fakenand.is_inited) + return; + + fakenand.is_inited = 1; + fakenand.pf = diag_printf; + fakenand.page_bits = 11; // 2048 byte test pattern. + fakenand.oob = &nand_mtd_oob_64; +} + +/* OOB packing =================================================== */ + +#define CANARY 0xaa +#define canary_subcheck(buf,x,y) do { \ + int i; \ + for (i=x; i<y; i++) \ + if (buf[i] != CANARY) \ + CYG_TEST_FAIL_FINISH("canary died"); \ +} while(0) + +#define canary_check(buf) do { \ + canary_subcheck(buf,0,32); \ + canary_subcheck(buf,96,128); \ +} while(0) + +int xcanary_check(CYG_BYTE *buf) +{ + int i; + for (i=0; i<32; i++) { + if (buf[i] != CANARY) + CYG_TEST_FAIL_FINISH("canary died"); + } + for (i=96; i<128; i++) { + if (buf[i] != CANARY) + CYG_TEST_FAIL_FINISH("canary died"); + } + return 1; +} + +CYG_BYTE oob_buf[128]; +CYG_BYTE testpattern[64], recvbuf[128]; + +int oob_packing(void) +{ + /* We are testing the mechanism, not the specifics of any given layout. + * We are interested in whether the application data is correctly + * stored and unpacked, without overrunning anything. */ + init_fakenand(); + CYG_BYTE *oob = &oob_buf[32]; + memset(oob_buf, CANARY, sizeof oob_buf); // To act as a simple canary + canary_check(oob_buf); + + CYG_BYTE *rcv = &recvbuf[32]; + memset(recvbuf, CANARY, sizeof recvbuf); + int i; + for (i=0; i<64; i++) + testpattern[i] = i^0xf4; + + canary_check(oob_buf); + nand_oob_pack(&fakenand, testpattern, sizeof testpattern, testpattern/*ecc*/, oob); + canary_check(oob_buf); + + canary_check(recvbuf); + nand_oob_unpack(&fakenand, rcv, 64, 0/*ecc*/, oob); + + //recvbuf[96] = 0; // uncomment to test the canary mechanism.. + canary_check(oob_buf); + canary_check(recvbuf); + + if (0 == memcmp(rcv, testpattern, fakenand.oob->app_size)) + CYG_TEST_PASS("oob pack/unpack unit test"); + else + CYG_TEST_FAIL_FINISH("oob pack/unpack unit test mismatch"); + + return 1; +} + +/* ECC known answer tests ======================================== */ + +/* An arc4 PRNG gives us known-answer tests. We'll take + * a few 2048 byte chunks from it and compute their ECCs + * with an independent implementation. */ + +#include "ar4prng.inl" + +#define CHUNKSIZE 2048 +#define ECCSIZE 3*(CHUNKSIZE/256) + +typedef struct { + char *seed; + unsigned char ecc[ECCSIZE]; +} eccvector; + +/* These vectors were independently computed using Charles Manning's + * ECC implementation. See mkvector.c. */ +eccvector vec[] = +{ + { "key1", { 0xa5, 0x65, 0xab, 0xff, 0x00, 0xcf, 0xf0, 0xf3, + 0x0f, 0xcc, 0xcc, 0xf3, 0xa9, 0x55, 0x57, 0x30, + 0x0f, 0xcf, 0x30, 0xc3, 0xf3, 0x30, 0xcf, 0xc3, } }, + { "key2", { 0x96, 0x9a, 0x57, 0x55, 0x66, 0xa7, 0x55, 0xa5, + 0x6b, 0xcc, 0x0f, 0xcf, 0x30, 0x03, 0x33, 0x96, + 0x9a, 0x5b, 0xa5, 0x69, 0x6b, 0x0c, 0x00, 0x33, } }, + { 0 } +}; + +unsigned char chunk[CHUNKSIZE], + ecc[ECCSIZE]; + +ar4ctx ctx; + +int do_ecc_known_answer(eccvector *v) +{ + ar4prng_init(&ctx, (unsigned char*)v->seed, strlen(v->seed)); + ar4prng_many(&ctx, chunk, CHUNKSIZE); + + nand_ecci_calc_page(&fakenand, chunk, ecc); + + int pass = (0 == memcmp(ecc, v->ecc, ECCSIZE)); + if (!pass) + diag_printf("Test with key %s mismatched\n", v->seed); +#if 0 + printf("Test key %s:\nECC: ",v->seed); + int i; + for (i=0; i<ECCSIZE; i++) + printf("%02x", ecc[i]); + printf("\n"); +#endif + + return pass; +} + +int ecc_known_answers(void) +{ + init_fakenand(); + eccvector *v = vec; + int fails = 0; + while (v->seed) { + if (1 != do_ecc_known_answer(v)) + ++fails; + ++v; + } + if (fails) CYG_TEST_FAIL_FINISH("ECC known answer check"); + else CYG_TEST_PASS("ECC known answer check"); + + return 0; +} + + +int cyg_user_start(void) +{ + CYG_TEST_INIT(); + CYG_TEST_INFO("NAND unit tests"); + + oob_packing(); + ecc_known_answers(); + + CYG_TEST_FINISH("Run complete."); + return 0; +}
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/readlimits.c @@ -0,0 +1,143 @@ +//============================================================================= +// +// readlimits.c +// +// eCos NAND flash: Read and partition limit tests +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/nand/util.h> +#include <cyg/infra/diag.h> +#include "nand_bbt.h" +#include <stdio.h> + +/* Functional check of reading data (not that it's sensible!); + * quasi-unit-test that partition limits work. + * + * Requires a NAND device. The first one found will be used. + */ + +/* Have we had an over-limit check? */ +int tried_bad = 0, passes = 0, fails = 0; +#define TRYREAD(p,g,s) do { \ + int _r = tryread(p,g,s); \ + if (!_r) ++passes; \ + else { \ + ++fails; \ + CYG_TEST_FAIL("partition limiter check"); \ + } \ +} while(0) + +unsigned char buf[CYGNUM_NAND_PAGEBUFFER]; + +/* Try to read a page. + * Pass 1 if you expect it to work, 0 if you don't. + * Returns 0 for test pass (i.e. it worked as well as it was supposed to), + * -1 for test fail (it didn't). */ +int tryread(cyg_nand_partition *prt, cyg_nand_page_addr pg, int shouldwork) +{ +#if 0 + printf("Trying %d...\n",pg); +#endif + int rv = cyg_nandp_read_page(prt, pg, buf, NULL, 0); + + if (!shouldwork) ++tried_bad; + if (rv==0) + return shouldwork ? 0 : -1; + else + return shouldwork ? -1 : 0; +} + +const char msg[] = "NAND partition limit read testing"; + +int cyg_user_start(void) +{ + cyg_nand_device *dev; + cyg_nand_partition *prt; + cyg_nand_page_addr pg; + CYG_TEST_INIT(); + CYG_TEST_INFO(msg); + + if (cyg_nanddevtab == &cyg_nanddevtab_end) + CYG_TEST_NA("No NAND devices found"); + + diag_printf("Using NAND device %s\n", cyg_nanddevtab->devname); + CYG_TEST_CHECK(0==cyg_nand_lookup(cyg_nanddevtab->devname, &dev),"lookup failed"); + + prt = cyg_nand_get_partition(dev, 0); + + /* Check we can read the first page of the partition, and the page + * before it (which might be off the start of the device) */ + TRYREAD(prt, 0, 1); + TRYREAD(prt, -1, 0); + + /* Check we can read the last page of the partition (allowing for + * the BBT perhaps getting in the way) */ + cyg_nand_block_addr blk = prt->last; +#ifdef CYGSEM_IO_NAND_USE_BBT + while (cyg_nand_bbti_query(dev, blk) != CYG_NAND_BBT_OK) + blk--; +#else + CYG_TEST_INFO("Caution, CYGSEM_IO_NAND_USE_BBT disabled - this may go wrong if we hit a bad block."); +#endif + cyg_nand_block_addr pblk = blk - prt->first; + pg = CYG_NAND_BLOCK2PAGEADDR(dev, pblk+1) - 1; + TRYREAD(prt, pg, 1); + + /* Try and read the page after the last page (which might be off + * the end of the device) */ + pg = CYG_NAND_PARTITION_NPAGES(prt); + TRYREAD(prt, pg, 0); + + if (!fails) { + if (!tried_bad) + CYG_TEST_NA("No expected failure cases; try again with a different partition setup"); + + else + CYG_TEST_PASS_FINISH(msg); + } else CYG_TEST_FAIL_FINISH(msg); + +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/readwrite.c @@ -0,0 +1,189 @@ +//============================================================================= +// +// readwrite.c +// +// eCos NAND flash: Read/write tests +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/testcase.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/nand/util.h> +#include <cyg/infra/diag.h> +#include <stdio.h> +#include <string.h> + +/* Functional test of reading, writing and erasing data. + * Requires a NAND device. The first one found will be used. + * This test is a bit stack-greedy, so don't expect it to work in a + * minimal configuration. + * + * WARNING: This test will WRITE TO and ERASE data on a partition. + * Do NOT run it on a device containing live data that you care about! + */ + +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#include "ar4prng.inl" + +const char msg[] = "NAND read/write testing"; + +#if defined(CYGSEM_IO_NAND_READONLY) +externC void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_INFO(msg); + CYG_TEST_NA("Not useful if CYGSEM_IO_NAND_READONLY"); +} + +#else + +/* we'll use our text segment as seed to the prng; not crypto-secure but + * pretty good for running tests */ +extern unsigned char _stext[], _etext[]; + +#define datasize CYGNUM_NAND_PAGEBUFFER +unsigned char buf[datasize], buf2[datasize]; +ar4ctx rnd; + +int cyg_user_start(void) +{ + cyg_nand_device *dev; + cyg_nand_partition *prt; + cyg_nand_block_addr blk; + cyg_nand_page_addr pg; + int i; + + CYG_TEST_INIT(); + CYG_TEST_INFO(msg); + ar4prng_init(&rnd,_stext, _etext-_stext); + + if (cyg_nanddevtab == &cyg_nanddevtab_end) + CYG_TEST_NA("No NAND devices found"); + + CYG_TEST_INFO("readwrite NAND test: using device: "); + CYG_TEST_INFO(cyg_nanddevtab->devname); + CYG_TEST_CHECK(0==cyg_nand_lookup(cyg_nanddevtab->devname, &dev),"lookup failed"); + + prt = cyg_nand_get_partition(dev, 0); + + /* Now select a usable block in the partition to base ourselves around. */ + blk = 0; +#ifdef CYGSEM_IO_NAND_USE_BBT + while ( (cyg_nandp_bbt_query(prt, blk) != CYG_NAND_BBT_OK) + && (cyg_nandp_bbt_query(prt, blk+1) != CYG_NAND_BBT_OK) ) { + blk++; + if (blk > CYG_NAND_PARTITION_NBLOCKS(prt)) + CYG_TEST_FAIL_FINISH("Cannot find a usable block to test"); + } +#else + CYG_TEST_INFO("Caution, CYGSEM_IO_NAND_USE_BBT disabled - this may go wrong if we hit a bad block."); +#endif + pg = CYG_NAND_BLOCK2PAGEADDR(dev,blk); + + diag_printf("Erasing block %d\n", blk); + MUST(0==cyg_nandp_erase_block(prt, blk)); + + CYG_ASSERTC(CYG_NAND_BYTES_PER_PAGE(dev) <= CYGNUM_NAND_PAGEBUFFER); + ar4prng_many(&rnd, buf, datasize); + + diag_printf("Read/write to page %d (block %d)\n", pg, blk); + MUST(0==cyg_nandp_write_page(prt, pg, buf, 0, 0)); + MUST(0==cyg_nandp_read_page (prt, pg, buf2, 0, 0)); + MUST(0==memcmp(buf, buf2, datasize)); + + diag_printf("Partial-reads of page %d (block %d)\n", pg, blk); +#define TEST(_m,_n,_ecc) do { \ + memset(buf2, 0, sizeof buf2); \ + MUST(0==cyg_nandp_read_part_page(prt, pg, buf2, _m, _n, _ecc)); \ + MUST(0==memcmp(&buf[_m], buf2, _n)); \ +} while(0) +#define TESTFAIL(_m,_n,_ecc) do { \ + MUST(0!=cyg_nandp_read_part_page(prt, pg, buf2, _m, _n, _ecc)); \ +} while(0) + // Ordinary whole-page reads: + TEST(0, CYG_NAND_BYTES_PER_PAGE(dev), 0); + TEST(0, CYG_NAND_BYTES_PER_PAGE(dev), 1); + // Partial reads: + TEST(0, 99, 0); + TEST(0, 99, 1); + TEST(42, 99, 0); + TEST(42, 99, 1); + // make sure we can address the upper half of small-page devices: + TEST(258, 99, 1); + TEST(258, 99, 0); + // Read right up to the end: + TEST(43, CYG_NAND_BYTES_PER_PAGE(dev)-43, 0); + TEST(43, CYG_NAND_BYTES_PER_PAGE(dev)-43, 1); + TEST(258, CYG_NAND_BYTES_PER_PAGE(dev)-258, 0); + TEST(258, CYG_NAND_BYTES_PER_PAGE(dev)-258, 1); + // ... but we should not be able to read off the end of the page: + TESTFAIL(0, CYG_NAND_BYTES_PER_PAGE(dev)+1, 0); + TESTFAIL(43, CYG_NAND_BYTES_PER_PAGE(dev)-42, 1); + // Zero-length reads should work: + TEST(0, 0, 0); + TEST(0, 0, 1); + // Silly offsets should fail: + TESTFAIL(CYG_NAND_BYTES_PER_PAGE(dev)+1, 1, 0); + TESTFAIL(CYG_NAND_BYTES_PER_PAGE(dev)+1, 0, 1); + + diag_printf("Erasing adjacent block %d\n", blk+1); + MUST(0==cyg_nandp_erase_block(prt, blk+1)); + diag_printf("Re-read check..\n"); + MUST(0==cyg_nandp_read_page (prt, pg, buf2, 0, 0)); + MUST(0==memcmp(buf, buf2, datasize)); + + diag_printf("Re-erase %d\n", blk); + MUST(0==cyg_nandp_erase_block(prt, blk)); + diag_printf("Read-back page %d to confirm erase\n", pg); + MUST(0==cyg_nandp_read_page (prt, pg, buf2, 0, 0)); + for (i=0; i<datasize; i++) + MUST(buf2[i]==0xff); + + CYG_TEST_PASS_FINISH(msg); +} + +#endif +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/rwbenchmark.c @@ -0,0 +1,560 @@ +//============================================================================= +// +// mounttime.c +// +// Mount timings exerciser, use on a filesystem filled by `makefiles' +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 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): wry +// Date: 2009-07-02 +// Description: Read, write and erase timing benchmark. +// Some timing code borrowed from mmfs tests. +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> +#include <cyg/infra/cyg_ass.h> +#include <pkgconf/system.h> +#include <pkgconf/hal.h> +#include <cyg/hal/hal_intr.h> + +#ifndef HAL_CLOCK_READ +# error "HAL_CLOCK_READ not defined!" +#endif + +#if !defined(CYGPKG_LIBC_TIME) || !defined(CYGPKG_ERROR) || !defined(CYGPKG_LIBC_STDIO) || !defined(CYGPKG_KERNEL) + +void cyg_user_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL, CYGPKG_LIBC_TIME, CYGPKG_ERROR and CYGPKG_LIBC_STDIO"); +} + +#else + +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_device.h> +#include <cyg/nand/util.h> + +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <stdlib.h> + +#include <cyg/kernel/kapi.h> + +#include "ar4prng.inl" +ar4ctx rnd; +/* we'll use our text segment as seed to the prng; not crypto-secure but + * pretty good for running tests */ +extern unsigned char _stext[], _etext[]; + + +#ifdef CYGPKG_DEVS_NAND_SYNTH +#define DEVICE "synth" +#else +#define DEVICE "onboard" +#endif + +#define PARTITION 0 + +#define MUST(what) do { \ + if (0 != what) { \ + perror(#what); \ + CYG_TEST_FAIL(#what); \ + cyg_test_exit(); \ + } \ +} while(0) + +#define min(a,b) ( (a) > (b) ? (b) : (a) ) + +// -------------------------------------------------------------- +// Timing code cribbed from pvr5.c + +typedef struct +{ + cyg_int64 ticks; + cyg_uint32 halticks; +} timestamp; + +typedef struct +{ + timestamp start; + timestamp end; + cyg_int64 interval; // In HAL ticks + cyg_int64 us_interval; // Interval in microseconds +} timing; + +static cyg_int64 ticks_overhead = 0; +static cyg_int32 us_per_haltick = 0; +static cyg_int32 halticks_per_us = 0; + +static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; +static cyg_int64 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; + +static void wait_for_tick( void ) +{ + cyg_tick_count_t now = cyg_current_time(); + + while( cyg_current_time() == now ) + continue; +} + +static void get_timestamp( timestamp *ts ) +{ + ts->ticks = cyg_current_time(); + HAL_CLOCK_READ( &ts->halticks ); +} + +static cyg_int64 ticks_to_us( cyg_int64 ticks ) +{ + cyg_int64 us; + + if( us_per_haltick != 0 ) + us = ticks * us_per_haltick; + else + us = ticks / halticks_per_us; + + return us; +} + +static void calculate_interval( timing *t ) +{ + t->interval = t->end.halticks - t->start.halticks; + + t->interval += (t->end.ticks - t->start.ticks) * rtc_period; + + t->interval -= ticks_overhead; + + t->us_interval = ticks_to_us( t->interval ); +} + +static void init_timing( void ) +{ + timing t; + + cyg_thread_delay(2); // ensure clock running - asserts if not + + us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]); + halticks_per_us = (rtc_period * rtc_resolution[1])/1000000; + + wait_for_tick(); + + get_timestamp( &t.start ); + get_timestamp( &t.end ); + + calculate_interval( &t ); + + ticks_overhead = t.interval; + + diag_printf("Timing overhead %lld ticks (%lluus), this will be factored out of all other measurements\n", ticks_overhead, t.us_interval ); +} + +#define disable_clock_latency_measurement() +#define enable_clock_latency_measurement() + +// -------------------------------------------------------------- + +void +show_times_hdr(void) +{ + disable_clock_latency_measurement(); + diag_printf("\n"); +#ifdef _TM_BASIC_HAL_CLOCK_READ_UNDEFINED + diag_printf("HAL_CLOCK_READ() is not supported on this platform.\n"); + diag_printf("Timing results are meaningless.\n"); +#endif + diag_printf("All times are in microseconds\n"); + diag_printf("\n"); + diag_printf(" Confidence\n"); + diag_printf(" Ave Min Max Var Ave Min Function\n"); + diag_printf(" ====== ====== ====== ====== ========== ========\n"); + enable_clock_latency_measurement(); +} + +// Display a time result +void +show_ns(cyg_uint64 ns) +{ + ns += 5; // for rounding to .01us + diag_printf("%6d.%02d", (int)(ns/1000), (int)((ns%1000)/10)); +} + +void +show_times_detail(timing ft[], int nsamples, char *title, bool ignore_first) +{ + int i; + int start_sample, total_samples; + cyg_uint64 delta, total, ave, min, max, ave_dev; + /* we measure in ticks, convert to us, but store as ns for good precision */ + cyg_int32 con_ave, con_min; + + if (ignore_first) { + start_sample = 1; + total_samples = nsamples-1; + } else { + start_sample = 0; + total_samples = nsamples; + } + + total = 0; + min = 0xFFFFffffFFFFffffULL; + max = 0; + for (i = start_sample; i < nsamples; i++) { + calculate_interval(&ft[i]); + delta = ft[i].us_interval * 1000; + total += delta; + if (delta < min) min = delta; + if (delta > max) max = delta; + } + ave = total / total_samples; + + ave_dev = 0; + for (i = start_sample; i < nsamples; i++) { + delta = ft[i].us_interval * 1000; + if (delta > ave) + delta = delta - ave; + else + delta = ave - delta; + ave_dev += delta; + } + ave_dev /= total_samples; + + con_ave = 0; + con_min = 0; + for (i = start_sample; i < nsamples; i++) { + delta = ft[i].us_interval * 1000; + if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++; + if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++; + } + con_ave = (con_ave * 100) / total_samples; + con_min = (con_min * 100) / total_samples; + + disable_clock_latency_measurement(); + show_ns(ave); + show_ns(min); + show_ns(max); + show_ns(ave_dev); + diag_printf(" %3d%% %3d%%", con_ave, con_min); + diag_printf(" %s\n", title); + + CYG_ASSERT( ave <= max, "ave < max" ); + + enable_clock_latency_measurement(); +} + +void +show_times(timing ft[], int nsamples, char *title) +{ + show_times_detail(ft, nsamples, title, false); +#ifdef STATS_WITHOUT_FIRST_SAMPLE + show_times_detail(ft, nsamples, "", true); +#endif +} + +// -------------------------------------------------------------- + +#define WORKDIR MOUNTPOINT "/" "test" + +#define NREADS 100 +#define NWRITES 30 /* TODO */ +#define NERASES 30 + +void show_test_parameters(void) +{ + disable_clock_latency_measurement(); + diag_printf("\nTesting parameters:\n"); + diag_printf(" NAND reads: %5d\n", NREADS); + if (NWRITES) + diag_printf(" NAND writes: %5d\n", NWRITES); + if (NERASES) + diag_printf(" NAND erases: %5d\n", NERASES); + enable_clock_latency_measurement(); +} + +cyg_nand_block_addr find_spare_block(cyg_nand_partition *part) +{ + const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); + unsigned char oob[oobz]; + int i,rv; + cyg_nand_block_addr b; + + for (b=CYG_NAND_PARTITION_NBLOCKS(part)-1; b>=0; b--) { + cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, b); + rv = cyg_nandp_read_page(part, pg, 0, oob, oobz); + if (rv != 0) continue; // bad block? + + for (i=0; i<oobz; i++) + if (oob[i] != 0xff) + goto next; + + // oob all FF: take it! + return b; +next: + ; + } + + CYG_TEST_FAIL_EXIT("can't find an untagged block"); +} + +CYG_BYTE databuf[CYGNUM_NAND_PAGEBUFFER], testbuf[CYGNUM_NAND_PAGEBUFFER]; +timing ft_read[NREADS]; +timing ft_write[NWRITES]; +timing ft_erase[NERASES]; + +int fails = 0; + +void test_reads(cyg_nand_partition *part, cyg_nand_block_addr b) +{ + cyg_nand_page_addr pgstart = CYG_NAND_BLOCK2PAGEADDR(part->dev, b), + pgend = CYG_NAND_BLOCK2PAGEADDR(part->dev, b+1)-1, + pg = pgstart; + int i, rv; + const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); + unsigned char oob[oobz]; +#define ft ft_read + + /* First, set up the block the way we want it ... */ + cyg_nandp_erase_block(part, b); + memcpy(oob, databuf, oobz); + for (i=pgstart; i <= pgend; i++) { + rv = cyg_nandp_write_page(part, i, databuf, oob, oobz); + switch (rv) { + case 0: break; + case -EIO: + cyg_nandp_bbt_markbad(part, b); + CYG_TEST_FAIL_FINISH("Write failed; block now marked as bad. This run can't continue but should be OK to repeat."); + + default: + diag_printf("Unexpected write failure: %d\n", rv); + CYG_TEST_FAIL_FINISH("Pre-write failed"); + } + } + +#define CLEARDATA() memset(testbuf, 0, sizeof testbuf) +#define CHECKDATA() do { if (0 != memcmp(testbuf, databuf, sizeof testbuf)) { \ + CYG_TEST_FAIL("readback check failed"); \ + ++fails; \ + break; \ +} } while(0) + +#define CLEAROOB() memset(oob, 0, oobz) +#define CHECKOOB() do { if (0 != memcmp(oob, databuf, oobz)) { \ + CYG_TEST_FAIL("readback OOB check failed"); \ + ++fails; \ + break; \ +} } while(0) + + + for (i=0; i < NREADS; i++) { + CLEARDATA(); + wait_for_tick(); + get_timestamp(&ft[i].start); + cyg_nandp_read_page(part, pg, testbuf, 0, 0); + get_timestamp(&ft[i].end); + CHECKDATA(); + ++pg; + if (pg > pgend) pg = pgstart; + } + show_times(ft, NREADS, "NAND page reads (page data only)"); + + for (i=0; i < NREADS; i++) { + CLEAROOB(); + wait_for_tick(); + get_timestamp(&ft[i].start); + cyg_nandp_read_page(part, pg, 0, oob, oobz); + get_timestamp(&ft[i].end); + CHECKOOB(); + ++pg; + if (pg > pgend) pg = pgstart; + } + show_times(ft, NREADS, "NAND page reads (OOB only)"); + + for (i=0; i < NREADS; i++) { + CLEARDATA(); + CLEAROOB(); + wait_for_tick(); + get_timestamp(&ft[i].start); + cyg_nandp_read_page(part, pg, testbuf, oob, oobz); + get_timestamp(&ft[i].end); + CHECKDATA(); + CHECKOOB(); + ++pg; + if (pg > pgend) pg = pgstart; + } + cyg_nandp_erase_block(part, b); + show_times(ft, NREADS, "NAND page reads (page + OOB)"); +#undef ft +} + + +void test_writes(cyg_nand_partition *part, cyg_nand_block_addr b) +{ + cyg_nand_page_addr pgstart = CYG_NAND_BLOCK2PAGEADDR(part->dev, b), + pgend = CYG_NAND_BLOCK2PAGEADDR(part->dev, b+1)-1, + pg = pgstart; + int i; + const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); + unsigned char oob[oobz]; +#define ft ft_write + + cyg_nandp_erase_block(part, b); + for (i=0; i < NWRITES; i++) { + wait_for_tick(); + get_timestamp(&ft[i].start); + cyg_nandp_write_page(part, pg, databuf, databuf, oobz); + get_timestamp(&ft[i].end); + + // Read it back to confirm + CLEARDATA(); + CLEAROOB(); + cyg_nandp_read_page(part, pg, testbuf, oob, oobz); + CHECKDATA(); + CHECKOOB(); + + ++pg; + if (pg > pgend) { + cyg_nandp_erase_block(part, b); + pg = pgstart; + } + } + cyg_nandp_erase_block(part, b); + show_times(ft, NWRITES, "NAND full-page writes"); +#undef ft +} + + +void test_erases(cyg_nand_partition *part, cyg_nand_block_addr b) +{ + int i; +#define ft ft_erase + + for (i=0; i < NERASES; i++) { + wait_for_tick(); + get_timestamp(&ft[i].start); + cyg_nandp_erase_block(part, b); + get_timestamp(&ft[i].end); + + if (i==0) { + cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, b); + const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); + unsigned char oob[oobz]; + int j; + // TODO: It only makes sense to check the one, unless we want + // to try writing out more dummy data each time. + CLEARDATA(); + CLEAROOB(); + cyg_nandp_read_page(part, pg, testbuf, oob, oobz); + for (j=0; j < sizeof testbuf; j++) { + if (testbuf[j] != 0xff) { + CYG_TEST_FAIL("readback check failed"); + ++fails; + break; + } + } + for (j=0; j < oobz; j++) { + if (oob[j] != 0xff) { + CYG_TEST_FAIL("readback OOB check failed"); + ++fails; + break; + } + } + } + } + show_times(ft, NERASES, "NAND block erases"); +#undef ft +} + + + +void rwbenchmark_main(void) +{ + cyg_nand_device *dev; + cyg_nand_partition *part; + cyg_nand_block_addr block; + + cyg_nand_lookup(DEVICE, &dev); + if (!dev) + CYG_TEST_FAIL_EXIT("can't get device "DEVICE); + part = cyg_nand_get_partition(dev, PARTITION); + if (!part) + CYG_TEST_FAIL_EXIT("can't get partition"); + + block = find_spare_block(part); + diag_printf("Using block %d\n",block); + + show_test_parameters(); + show_times_hdr(); + + // TODO: For speed, refactor test_reads and test_writes into each other. + test_reads(part, block); + + // Freshen our test data for the second phase + ar4prng_many(&rnd, databuf, sizeof databuf); + test_writes(part,block); + + test_erases(part,block); + +} + +int main(void) +{ + CYG_TEST_INIT(); + init_timing(); + + ar4prng_init(&rnd,_stext, _etext-_stext); + ar4prng_many(&rnd, databuf, sizeof databuf); + + +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) || defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) + CYG_TEST_INFO("WARNING: Clock or DSR latency instrumentation can mess with the results, recommend you turn it off."); +#endif + + + rwbenchmark_main(); + + if (fails) + CYG_TEST_FAIL_FINISH("something went wrong, THESE RESULTS ARE INVALID"); + + CYG_TEST_EXIT("Run complete"); +} + +#endif +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/tests/sweccwalk.c @@ -0,0 +1,176 @@ +//============================================================================= +// +// sweccwalk.c +// +// Walks some sample data through the software ECC algorithm to +// check that computation and repair operate correctly. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-10-27 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/testcase.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/nand/util.h> +#include <cyg/infra/diag.h> +#include <stdio.h> +#include <string.h> + +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +static CYG_NAND_DEVICE(fakenand, 0, 0, 0, &mtd_ecc256_fast, 0); + +void init_fakenand(void) +{ + if (fakenand.is_inited) + return; + + fakenand.is_inited = 1; + fakenand.pf = diag_printf; + fakenand.page_bits = 11; // 2048 byte test pattern. + fakenand.oob = &nand_mtd_oob_64; +} + + +void ecc(cyg_nand_device *dev, const CYG_BYTE *data, const char *msg, CYG_BYTE *out) +{ + if (dev->ecc->init) + dev->ecc->init(dev); + dev->ecc->calc(dev, data, out); + diag_printf("%s: ecc=%02x%02x%02x\n", msg, out[0], out[1], out[2]); + // TODO adapt this display for ECCs longer than 3 bytes +} + +const char msg[]="software ECC walker"; + +#define ECC_BUFFER_SIZE 10 +CYG_BYTE buf[CYGNUM_NAND_PAGEBUFFER]; +CYG_BYTE ecc1[ECC_BUFFER_SIZE], ecc2[ECC_BUFFER_SIZE]; + +int cyg_user_start(void) +{ + cyg_nand_device *dev = &fakenand; + int i; + + CYG_TEST_INIT(); + CYG_TEST_INFO(msg); + +#if 0 + // This code can be adapted to test a hardware ECC algorithm but + // this usually requires some cunning in ecc() to cause the test + // data to pass through the hardware. + if (cyg_nanddevtab == &cyg_nanddevtab_end) + CYG_TEST_NA("No NAND devices found"); + + CYG_TEST_CHECK(0==cyg_nand_lookup("onboard", &dev),"lookup failed"); +#endif + +#define datasize (fakenand.ecc->data_size) +#define eccsize (fakenand.ecc->ecc_size) + + CYG_ASSERTC(datasize <= CYGNUM_NAND_PAGEBUFFER); + CYG_ASSERTC(eccsize <= ECC_BUFFER_SIZE); + + diag_printf("ECC sizes: data %d, ecc %d\n", datasize, eccsize); + + // Plan: Start with a buffer full of 0xFF; then, changing one bit + // at a time, compute a fresh ECC and check that the repair code + // does the right thing. This code can also be used to help work + // out what's going on with an unclearly-documented ECC algorithm. + + memset(buf, 255, sizeof(buf)); + ecc(dev, buf, "all-ff", ecc1); + + for (i=0; i<8; i++) { + int st; + char msg[] = "bit X"; + buf[0] ^= 1<<i; + msg[4] = '0' + i; + ecc(dev, buf, msg, ecc2); + + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==1); + CYG_ASSERTC(buf[0] == 0xff); + + ecc(dev, buf, msg, ecc2); + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==0); + } + int max; + switch(datasize) { + case 256: max = 8; break; + case 512: max = 9; break; + // Add further cases here for different ECC data sizes. + default: + diag_printf("Unhandled case datasize=%d\n",datasize); + CYG_TEST_FAIL_EXIT("Unhandled case!"); + } + for (i=0; i<max; i++) { + char msg[256]; + int st; + diag_snprintf(msg, sizeof msg, "bytelog %d", i); + + buf[1<<i] ^= 1; + ecc(dev, buf, msg, ecc2); + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==1); + CYG_ASSERTC(buf[1<<i] == 0xff); + + ecc(dev, buf, msg, ecc2); + st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2); + CYG_ASSERTC(st==0); + } + + int fail=0; + for (i=0; i<datasize; i++) { + if (buf[i] != 0xff) { + ++fail; + diag_printf("buf[%d] == %02x != 0xff\n", i, buf[i]); + } + } + + if (fail) + CYG_TEST_FAIL_FINISH(msg); + else + CYG_TEST_PASS_FINISH(msg); +} +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/utils/erase_bbt_dangerous.c @@ -0,0 +1,92 @@ +//============================================================================= +// +// erase_bbt_dangerous.c +// +// eCos NAND flash: BBT erase utility. +// This program is DANGEROUS and must NEVER be run unless you +// are fully aware of and understand the effect it will have. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-04-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#define DEVICE "onboard" + +#include <cyg/nand/nand.h> +#include <cyg/infra/diag.h> +#include <cyg/infra/testcase.h> +#include <stdio.h> +#include <pkgconf/isoinfra.h> +#include CYGBLD_ISO_STRERROR_HEADER + +/* Utility code to erase the BBT on a device. + * This is DANGEROUS, do not run unless you understand the consequences! + */ + +#ifdef CYGSEM_IO_NAND_USE_BBT +void rawerase(cyg_nand_device *dev, cyg_nand_block_addr blk) +{ + diag_printf("Erasing block %d on %s\n", blk, dev->devname); + int rv = dev->fns->erase_block(dev, blk); + if (rv != 0) { + diag_printf("Error erasing: %s (%d)\n", strerror(-rv), rv); + } +} + +#define MUST(a,b) do { if (!(a)) { diag_printf(b); return; } } while(0) + +void cyg_user_start(void) +{ + cyg_nand_device *dev; + MUST(0==cyg_nand_lookup(DEVICE, &dev),"lookup failed\n"); + if (dev->bbt.primary != 0xFFFFFFFF) + rawerase(dev,dev->bbt.primary); + if (dev->bbt.mirror != 0xFFFFFFFF) + rawerase(dev,dev->bbt.mirror); + diag_printf("BBT should now be erased.\n"); +} + +#else +void cyg_user_start(void) +{ + diag_printf("This utility doesn't make sense unless the BBT is enabled.\n"); +} +#endif +
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/utils/erasenand.c @@ -0,0 +1,116 @@ +//============================================================================= +// +// erasenand.c +// +// eCos NAND flash: NAND erase utility. +// This program is DANGEROUS and must NEVER be run unless you +// are fully aware of and understand the effect it will have. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-07-28 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_devtab.h> +#include <cyg/nand/util.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> +#include <stdio.h> +#include <string.h> + +/* NAND device erase. + * WARNING: This test will WRITE TO and ERASE data on a partition. + * Do NOT run it on a device containing live data that you care about! + */ + +// Set the device and partition to be erased here. +#define DEVICE "onboard" +#define PARTITION 0 + +void cyg_user_start(void) +{ + cyg_nand_device *dev; + cyg_nand_partition *prt; + cyg_nand_block_addr blk; + int rv; + + cyg_nand_lookup(DEVICE, &dev); + CYG_ASSERT(0!=dev,"device lookup failed"); + prt = cyg_nand_get_partition(dev, 0); + CYG_ASSERT(0!=prt, "partition lookup failed"); + + diag_printf("Erasing NAND device %s/%d...\n", DEVICE, PARTITION); + + int progmod = (prt->last - prt->first + 1) / 73 + 1; + + for (blk=0; blk <= CYG_NAND_PARTITION_NBLOCKS(prt); blk++) { +#ifdef CYGSEM_IO_NAND_USE_BBT + int st = cyg_nandp_bbt_query(prt, blk); + if (st<0) { + diag_printf("Block %d BBTI error %d\n", blk, -st); + } +#else + int st = 0; +#endif + const char *msg = 0; + switch(st) { + case CYG_NAND_BBT_OK: + rv = cyg_nandp_erase_block(prt, blk); + if (rv != 0) + diag_printf("Block %d: error %d\n", blk, -rv); + break; + case CYG_NAND_BBT_WORNBAD: + msg="worn bad"; break; + case CYG_NAND_BBT_FACTORY_BAD: + msg="factory bad"; break; + + case CYG_NAND_BBT_RESERVED: + // Skip quietly + break; + } + if (msg) + diag_printf("Skipping block %d (%s)\n", blk, msg); + + if (0==(blk % progmod)) + diag_printf("."); + } + diag_printf("\nErase complete.\n"); +} +
--- a/packages/redboot/current/ChangeLog +++ b/packages/redboot/current/ChangeLog @@ -4,6 +4,26 @@ 2010-04-23 John Dallaway <john@dallawa avoid possible invalid memory access. Issue reported by Kirill Berezin. +2009-11-19 Ross Younger <wry@ecoscentric.com> + * src/nand.c: Update to application interface v2. + Requires CYGSEM_IO_NAND_INTERFACE_VERSION > 1. + +2009-11-17 Ross Younger <wry@ecoscentric.com> + + * src/nand.c: Add "nand badblocks" subcommand and nested + subsubcmds: summarise or list bad blocks, and manually + change the state of a block's marking. + * cdl/redboot.cdl: Add CYGSEM_REDBOOT_NAND_BADBLOCKS_CMD and + CYGSEM_REDBOOT_NAND_BADBLOCKS_MARK_CMD. + +2009-06-26 Ross Younger <wry@ecoscentric.com> + + * src/nand.c: Created for NAND utilities + * cdl/redboot.cdl: Build nand.c if it's appropriate. + CYGMEM_REDBOOT_WORKSPACE_HEAP defaults on where active. + * fs/fileio.c: Try to be more helpful if mount failed. + * main.c: If mallinfo exists, report on it. + 2009-06-24 Nick Garnett <nickg@ecoscentric.com> * cdl/redboot.cdl:
--- a/packages/redboot/current/cdl/redboot.cdl +++ b/packages/redboot/current/cdl/redboot.cdl @@ -1290,7 +1290,7 @@ cdl_package CYGPKG_REDBOOT { flavor bool active_if CYGPKG_MEMALLOC active_if CYGPKG_MEMALLOC_MALLOC_ALLOCATORS - default_value 0 + default_value 1 description " If the MEMALLOC package is present, it usually allocates the whole of memory not used by the program to the heap. @@ -1320,6 +1320,61 @@ cdl_package CYGPKG_REDBOOT { The size of this buffer can have a big impart on load speed." } + cdl_component CYGPKG_REDBOOT_NAND { + display "Include NAND utilities in RedBoot" + flavor bool + default_value 1 + active_if CYGPKG_IO_NAND + requires CYGPKG_IO_NAND + requires ( CYGSEM_IO_NAND_INTERFACE_VERSION > 1 ) + description " + If this option is enabled then RedBoot will provide commands + to interrogate and manage NAND storage chips at a low level. + (Note that files are normally stored on a NAND chip + via a filesystem. To enable that, you need to add the + relevant package to the configuration and check that + CYGPKG_REDBOOT_FILEIO is enabled.)" + compile -library=libextras.a nand.c + + cdl_option CYGSEM_REDBOOT_NAND_ERASE_CMD { + display "Include support for nand erase command" + flavor bool + default_value 1 + active_if CYGPKG_REDBOOT_NAND + description " + This option provides a helper command to erase + a partition of a NAND device. It may be useful to + turn off if (for example) you don't want to provide + your users with this ability. + " + } + + cdl_option CYGSEM_REDBOOT_NAND_BADBLOCKS_CMD { + display "Include support for nand badblocks command" + flavor bool + default_value 1 + active_if CYGPKG_REDBOOT_NAND + description " + This option provides a helper command to query + and (optionally) change the state of bad blocks + in the NAND device's Bad Blocks Table. + " + } + + cdl_option CYGSEM_REDBOOT_NAND_BADBLOCKS_MARK_CMD { + display "Can nand badblocks change block states" + flavor bool + default_value 1 + active_if CYGSEM_REDBOOT_NAND_BADBLOCKS_CMD + description " + This option enables the `badblocks mark' subcommand, + which allows the user to manually change the state + of blocks in the Bad Block Table. It is potentially + dangerous if misused, so you may not wish to + enable this." + } + } + } }
--- a/packages/redboot/current/src/fs/fileio.c +++ b/packages/redboot/current/src/fs/fileio.c @@ -233,7 +233,12 @@ do_mount(int argc, char *argv[]) if (err) { - err_printf("fs mount: mount(%s,%s,%s) failed %d\n", dev_str, mp_str, type_str, errno); + const char *msg = ""; + switch(errno) { + case ENOENT: msg="(No such entity)"; break; + case ENODEV: msg="(No such device)"; break; + } + err_printf("fs mount: mount(%s,%s,%s) failed %d %s\n", dev_str, mp_str, type_str, errno, msg); mounts[m].mp_str[0] = '\0'; // mount failed so don't let it appear mounted } else
--- a/packages/redboot/current/src/main.c +++ b/packages/redboot/current/src/main.c @@ -53,6 +53,7 @@ #define DEFINE_VARS #include <redboot.h> +#include <stdlib.h> #include <cyg/hal/hal_arch.h> #include <cyg/hal/hal_intr.h> #include <cyg/hal/hal_if.h> @@ -76,6 +77,11 @@ extern void breakpoint(void); #endif +#if defined(CYGMEM_REDBOOT_WORKSPACE_HEAP) +# include <stdlib.h> +static unsigned char* heap_base; +#endif + // Builtin Self Test (BIST) externC void bist(void); @@ -170,6 +176,9 @@ do_version(int argc, char *argv[]) #ifdef CYGPKG_REDBOOT_FLASH externC void _flash_info(void); #endif +#ifdef CYGPKG_REDBOOT_NAND + externC void _nand_info(void); +#endif char *version = CYGACC_CALL_IF_MONITOR_VERSION(); diag_printf(version); @@ -196,9 +205,16 @@ do_version(int argc, char *argv[]) } } #endif +#ifdef CYGMEM_REDBOOT_WORKSPACE_HEAP + struct mallinfo mi = mallinfo(); + diag_printf(" Arena: base 0x%x, size 0x%x, %u%% free, maxfree 0x%x\n", heap_base, mi.arena, (unsigned)(100 * ((double)mi.fordblks / mi.arena)), mi.maxfree); +#endif #ifdef CYGPKG_REDBOOT_FLASH _flash_info(); #endif +#ifdef CYGPKG_REDBOOT_NAND + _nand_info(); +#endif } // @@ -306,6 +322,7 @@ cyg_start(void) extern cyg_bool cyg_memalloc_heap_reinit( cyg_uint8 *base, cyg_uint32 size ); workspace_end -= CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE; + heap_base = workspace_end; if( !cyg_memalloc_heap_reinit( (cyg_uint8 *)workspace_end, CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE ) ) diag_printf("Heap reinitialization failed\n");
new file mode 100644 --- /dev/null +++ b/packages/redboot/current/src/nand.c @@ -0,0 +1,603 @@ +//========================================================================== +// +// nand.c +// +// RedBoot - NAND library support +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 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): wry +// Date: 2009-05-29 +// Purpose: +// Description: +// +// This code is part of RedBoot (tm). +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <redboot.h> +#include <pkgconf/system.h> +#ifdef CYGPKG_IO_FILEIO +# include <cyg/fileio/fileio.h> +#endif +#include <cyg/nand/nand.h> +#include <cyg/nand/nand_device.h> +#include <cyg/nand/util.h> + +CYG_HAL_TABLE_BEGIN( __NAND_cmds_TAB__, NAND_cmds); +CYG_HAL_TABLE_END( __NAND_cmds_TAB_END__, NAND_cmds); + +extern struct cmd __NAND_cmds_TAB__[], __NAND_cmds_TAB_END__; + +#ifdef CYGSEM_REDBOOT_NAND_BADBLOCKS_CMD +static unsigned count_nand_devices(void) +{ + unsigned n = 0; + cyg_nand_device *nand; + for (nand = &cyg_nanddevtab[0]; nand != &cyg_nanddevtab_end; nand++,n++); + return n; +} +#endif + +//========================================================================== + +static void +nand_usage(char *why) +{ + diag_printf("*** invalid 'nand' command: %s\n", why); + cmd_usage(__NAND_cmds_TAB__, &__NAND_cmds_TAB_END__, "nand "); +} + +static void +do_nand(int argc, char *argv[]) +{ + struct cmd *cmd; + + if (argc < 2) { + nand_usage("too few arguments"); + return; + } + if ((cmd = cmd_search(__NAND_cmds_TAB__, &__NAND_cmds_TAB_END__, + argv[1])) != (struct cmd *)0) { + (cmd->fun)(argc-1, argv+1); + return; + } + nand_usage("unrecognized command"); +} + +RedBoot_nested_cmd("nand", "Manage NAND arrays", "{cmds}", do_nand, + __NAND_cmds_TAB__, &__NAND_cmds_TAB_END__); + +//========================================================================== +// nand list - enumerates the available devices + +static void nand_list_guts(const char *banner, const char *eachdev, + const char *donefound, const char *donenone) +{ + cyg_bool found=false; + cyg_nand_device *nand; + for (nand = &cyg_nanddevtab[0]; nand != &cyg_nanddevtab_end; nand++) { + if (!found) { + diag_printf(banner); + found=true; + } + diag_printf(eachdev, nand->devname); + } + if (found) { + if (donefound) + diag_printf(donefound); + } else { + if (donenone) + diag_printf(donenone); + } +} + +static void nand_list(int argc, char*argv[]) +{ + nand_list_guts("NAND devices available:\n", "\t%s\n", + 0, "No NAND devices available.\n"); +} + +// Startup banner is suspiciously similar.. +void _nand_info(void) +{ + nand_list_guts("NAND:", " %s", "\n", 0); + // We could do more here, maybe interrogate each device like nand_info, + // but we'd have to be certain that calling each device's devinit + // wouldn't risk an unrecoverable crash in case of trouble. +} + +local_cmd_entry("list", "Lists available NAND devices", "", nand_list, NAND_cmds); + +//========================================================================== +// nand info DEVICE - list chip info, partitions & sizes + +static void pretty_print(unsigned log) { + char si = ' '; + if (log>30) { + si='G'; log -= 30; + } else if (log>20) { + si='M'; log -= 20; + } else if (log>10) { + si='k'; log -= 10; + } + diag_printf("%u %cB", 1<<log, si); +} + +static void do_info(cyg_nand_device *nand) +{ + // Dev must be initialised. + diag_printf("NAND device `%s':\n" + " %u bytes/page, %u pages/block, " + "capacity %u blocks x ", + nand->devname, + 1 << nand->page_bits, + 1 << nand->block_page_bits, + 1 << nand->blockcount_bits); + pretty_print(nand->page_bits + nand->block_page_bits); + diag_printf(" = "); + pretty_print(nand->chipsize_log); + diag_printf("\n"); + + cyg_bool found = false; + int p; + for (p=0; p < CYGNUM_NAND_MAX_PARTITIONS; p++) { + if (nand->partition[p].dev) { + if (!found) { + found=true; + diag_printf(" Partition Start Blocks\n"); + } + diag_printf(" %6u %4u %5u\n", + p, + nand->partition[p].first, + 1 + nand->partition[p].last - nand->partition[p].first); + } + } + if (!found) + diag_printf(" (No partitions defined.)\n"); +} + +static void nand_info(int argc, char*argv[]) +{ + cyg_nand_device *nand; + + int arg = 1; + while (arg < argc) { + const char *dev = argv[arg]; + if (0==cyg_nand_lookup(dev, &nand)) + do_info(nand); + else + diag_printf("No such NAND device `%s'\n", dev); + ++arg; + } + + // However, if they've not provided an arg ... + if (argc == 1) { + for (nand = &cyg_nanddevtab[0]; nand != &cyg_nanddevtab_end; nand++) { + cyg_nand_lookup(nand->devname,0); + do_info(nand); + } + } +} + +local_cmd_entry("info", "Displays information about one or more NAND devices", "[<device>] [<device>...]", nand_info, NAND_cmds); + +//========================================================================== +#ifdef CYGSEM_REDBOOT_NAND_BADBLOCKS_CMD +// nand badblocks [-d <device>] SUBCOMMAND - bad block info and management +// Shared handling allows -d device to default to the single present device. + +CYG_HAL_TABLE_BEGIN( __NAND_badblocks_cmds_TAB__, NAND_badblocks_cmds); +CYG_HAL_TABLE_END( __NAND_badblocks_cmds_TAB_END__, NAND_badblocks_cmds); + +extern struct cmd __NAND_badblocks_cmds_TAB__[], + __NAND_badblocks_cmds_TAB_END__; + +static cmd_fun do_nand_badblocks; +static cmd_fun nbb_subcommand; + +#define nbb_cmd(_w, _h, _u) \ + static struct cmd _cmd_tab_nbb_subcommand_##_w CYG_HAL_TABLE_QUALIFIED_ENTRY(NAND_badblocks_cmds,nbb_subcommand) = { #_w, _h, "[-d <device>] " _u, nbb_subcommand, 0, 0 } + +struct cmd _cmd_tag_do_nand_badblocks CYG_HAL_TABLE_QUALIFIED_ENTRY(NAND_cmds, do_nand_badblocks) = { + "badblocks", "Interrogates and manages the device bad block table", + "<subcommand> [-d <device>] [<subcommand args>...]", + do_nand_badblocks, + __NAND_badblocks_cmds_TAB__, &__NAND_badblocks_cmds_TAB_END__ +}; + +static void nbb_usage(const char *why) +{ + diag_printf("*** invalid `nand badblocks' subcommand: %s\n", why); + cmd_usage(__NAND_badblocks_cmds_TAB__, + &__NAND_badblocks_cmds_TAB_END__, "nand badblocks "); +} + +static void do_nand_badblocks(int argc, char**argv) +{ + struct cmd *cmd; + if (argc<2) { + // defaulting behaviour + nbb_subcommand(argc,argv); + return; + } + if ((cmd = cmd_search(__NAND_badblocks_cmds_TAB__, + &__NAND_badblocks_cmds_TAB_END__, argv[1])) + != (struct cmd *)0) { + (cmd->fun)(argc, argv); + return; + } + nbb_usage("unrecognized command"); +} + +static void nbb_help(int argc, char**argv) +{ + cmd_usage(__NAND_badblocks_cmds_TAB__, + &__NAND_badblocks_cmds_TAB_END__, "nand badblocks "); +} + +local_cmd_entry("help", "Explains the available commands", "", nbb_help, NAND_badblocks_cmds); + +static struct { + cyg_nand_bbt_status_t state; + const char *msg; +} states[5] = { + { CYG_NAND_BBT_OK, "OK" }, + { CYG_NAND_BBT_WORNBAD, "worn bad" }, + { CYG_NAND_BBT_RESERVED, "reserved" }, + { CYG_NAND_BBT_FACTORY_BAD, "factory bad" }, + { 0,0 } +}; + +static void nbb_states(int argc, char**argv) +{ + int i = 0; + diag_printf("The possible block states are:\n"); + while (states[i].msg) { + diag_printf("\t%u : %s\n", states[i].state, states[i].msg); + ++i; + } +} + +local_cmd_entry("states", "Lists the valid states in the BBT", "", nbb_states, NAND_badblocks_cmds); + +// ......................... + +// nand badblocks SUMMARY and nand badblocks LIST: +// count the number of blocks of a given type and (in list mode) dump them out. + +// Forbidden knowledge: +extern int cyg_nand_bbti_query(cyg_nand_device *dev, cyg_nand_block_addr blk); + +static void do_summary(cyg_nand_device *nand) +{ + // count the bad blocks + cyg_nand_block_addr i = 0; + unsigned state[1+CYG_NAND_BBT_FACTORY_BAD]; + int rv; + memset(state, 0, sizeof(state)); + for (i=0; i < CYG_NAND_BLOCKCOUNT(nand); i++) { + rv = cyg_nand_bbti_query(nand,i); + if (rv>=CYG_NAND_BBT_OK && rv <= CYG_NAND_BBT_FACTORY_BAD) + ++state[rv]; + } + + diag_printf("Device `%s' has %u blocks", nand->devname, CYG_NAND_BLOCKCOUNT(nand)); + + int counted=0; +#define REPORT(_s,_msg) do { \ + if (state[_s] != 0) { \ + if (counted) \ + diag_printf(", %u %s", state[_s], _msg); \ + else \ + diag_printf(", of which %u are %s", state[_s], _msg); \ + counted += state[_s]; \ + } \ +} while(0) + + // Report in sensible order, not enum order. + REPORT(CYG_NAND_BBT_FACTORY_BAD, "factory bad"); + REPORT(CYG_NAND_BBT_WORNBAD, "worn bad"); + REPORT(CYG_NAND_BBT_RESERVED, "reserved"); + + int pct = 100 * (CYG_NAND_BLOCKCOUNT(nand) - counted) / CYG_NAND_BLOCKCOUNT(nand); + diag_printf(". %u blocks (%d%%) are OK.\n", CYG_NAND_BLOCKCOUNT(nand) - counted, pct); +} + +nbb_cmd(summary, "Summarises the bad blocks table", ""); + +// ......................... + +static void do_sublist(cyg_nand_device *nand, cyg_nand_bbt_status_t st, const char *msg) +{ + cyg_nand_block_addr i = 0; + int rv; + unsigned found = 0; + + diag_printf("%s: ", msg); + for (i=0; i < CYG_NAND_BLOCKCOUNT(nand); i++) { + rv = cyg_nand_bbti_query(nand,i); + if (rv == st) { + diag_printf("%s%d", (found ? ", " : ""), i); + ++found; + } + } + + if (found) + diag_printf(". (count: %d blocks)\n", found); + else + diag_printf("no blocks\n"); +} + +static void do_list(cyg_nand_device *nand) { + do_sublist(nand, CYG_NAND_BBT_FACTORY_BAD, "factory bad"); + do_sublist(nand, CYG_NAND_BBT_WORNBAD, "worn bad"); + do_sublist(nand, CYG_NAND_BBT_RESERVED, "reserved"); +} + +nbb_cmd(list, "Lists the contents of the bad blocks table", ""); + +// ......................... + +// nand badblocks mark -d device -b block -s state +// Manually marks a block in the BBT. Use with caution! +#ifdef CYGSEM_REDBOOT_NAND_BADBLOCKS_MARK_CMD +// more forbidden knowledge: +extern int cyg_nand_bbti_markany(cyg_nand_device *dev, cyg_nand_block_addr blk, cyg_nand_bbt_status_t st); + +static void nbb_mark_usage(void) { + diag_printf("Usage: nand badblocks mark [-d device] -b block -s state\n The valid states are shown by `nand badblocks states'.\n"); +} + +static void do_mark(cyg_nand_device *nand, int markblock, int markstate) +{ + int bail=0; + if (markblock < 0 || markblock > CYG_NAND_BLOCKCOUNT(nand)) { + diag_printf("Invalid block number.\n"); + bail=1; + } + if (markstate < CYG_NAND_BBT_OK || markstate > CYG_NAND_BBT_FACTORY_BAD) { + diag_printf("Invalid state.\n"); + bail=1; + } + if (markstate == CYG_NAND_BBT_RESERVED) { + diag_printf("State `reserved' is for the BBT itself and cannot be written to flash.\n"); + bail=1; + } + if (bail) { + nbb_mark_usage(); + return; + } + + + // We don't need to take the devlock as RedBoot is single-threaded. + int rv = cyg_nand_bbti_markany(nand, markblock, markstate); + if (rv != 0) + diag_printf("mark operation failed with status %d\n", rv); + else + diag_printf("OK\n"); +} + +nbb_cmd(mark, "Manually marks a block in the BBT", "-b block -s state"); + +#endif + +// ......................... + +static void nbb_subcommand(int argc, char*argv[]) +{ + cyg_nand_device *nand = 0; + const char *subcmd = argv[1]; + char *dev; + cyg_bool got_dev = false; +#define MAXOPTS 4 + struct option_info opts[MAXOPTS]; + enum { + unset=0, + dodefault, + summary, + list, + mark + } mode = unset; + int markblock = -1, markstate = -1; + + // we know that we _have_ a valid subcommand at this point, just not _which_. + int n_opts = 0; +#define OPTION(_f, _a, _t, _p, _got, _arg) init_opts(&opts[n_opts++], _f, _a, _t, _p, _got, _arg) + OPTION('d', true, OPTION_ARG_TYPE_STR, (void*)&dev, &got_dev, "device"); + + if (subcmd) { + int sclen = strlen(subcmd); + if (0==strncmp(subcmd, "summary", sclen)) + mode = summary; + else if (0==strncmp(subcmd, "list", sclen)) + mode = list; + else if (0==strncmp(subcmd, "mark", sclen)) { + mode = mark; + OPTION('s', true, OPTION_ARG_TYPE_NUM, (void*) &markstate, 0, "state"); + OPTION('b', true, OPTION_ARG_TYPE_NUM, (void*) &markblock, 0, "block"); + } + + // Caution! If you are adding a new subsubcommand with options, make sure that n_opts can't become bigger than MAXOPTS ! + } + else + mode = dodefault; + + if (n_opts > MAXOPTS) { + diag_printf("BUG: Too many options at %s:%d\n",__FILE__,__LINE__); + return; + } + + if (!scan_opts(argc, argv, 2, opts, n_opts, 0, 0, "")) + return; + + if (got_dev) { + cyg_nand_lookup(dev, &nand); + if (!nand) + diag_printf("Device %s not found.\n", dev); + } else { + if (count_nand_devices()==1) + cyg_nand_lookup(cyg_nanddevtab[0].devname, &nand); + else + diag_printf("More than one NAND device present, please specify with -d <device>\n"); + } + if (!nand) return; + + switch(mode) { + case dodefault: + diag_printf("(You didn't specify a subcommand, so I'm defaulting to `summary.'\n `nand badblocks help' lists all known subcommands.)\n"); + // FALLTHROUGH + case summary: + do_summary(nand); + return; + case list: + do_list(nand); + return; +#ifdef CYGSEM_REDBOOT_NAND_BADBLOCKS_MARK_CMD + case mark: + if (markblock==-1 || markstate==-1) { + nbb_mark_usage(); + } else + do_mark(nand, markblock, markstate); + return; +#endif + case unset: + diag_printf("can't happen at %s %d\n", __FILE__, __LINE__); + return; + } +} + +#endif // CYGSEM_REDBOOT_NAND_BADBLOCKS_CMD + +//========================================================================== +// nand erase - erases a nand partition. (Who'd have thunk?) + +#ifdef CYGSEM_REDBOOT_NAND_ERASE_CMD + +#ifdef CYGPKG_IO_FILEIO +__externC cyg_mtab_entry cyg_mtab[]; +__externC cyg_mtab_entry cyg_mtab_end; + +static cyg_mtab_entry * find_mounted_nand(const char *dev) +{ + cyg_mtab_entry *m; + for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ ) { + if( m->name == NULL || !m->valid ) continue; + if (0==strcmp(m->devname, dev)) { + return m; + } + } + return NULL; +} +#endif + +static void nand_erase(int argc, char*argv[]) +{ + char *part_str=0; + int rv; + + if (!scan_opts(argc, argv, 1, NULL, 0, &part_str, OPTION_ARG_TYPE_STR, "NAND partition, e.g. mynand/0")) + return; + + if (!part_str) { + err_printf("nand erase: partition required\n"); + return; + } + + cyg_nand_device *nand=0; + cyg_nand_partition *part=0; + cyg_nand_resolve_device(part_str, &nand, &part); + if (!nand) { + err_printf("nand erase: device not found\n"); + return; + } + if (!part) { + err_printf("nand erase: partition not found\n"); + return; + } + +#ifdef CYGPKG_IO_FILEIO + cyg_mtab_entry *mte = find_mounted_nand(part_str); + if (mte) { + err_printf("nand erase: device %s is mounted on %s, must unmount first\n", part_str, mte->name); + return; + } +#endif + + diag_printf("Erasing device %s blocks %u to %u...\n", nand->devname, part->first, part->last); + cyg_nand_block_addr blk; + // Compute a modulus to print out about 72 x `.' as we go by + int progmod = (1 + CYG_NAND_PARTITION_NBLOCKS(part)) / 73 + 1; + + for (blk = part->first; blk <= part->last; blk++) { + int st = cyg_nandp_bbt_query(part, blk); + if (st<0) { + diag_printf("Block %d BBTI error %d\n", blk, -st); + } + const char *msg = 0; + switch(st) { + case CYG_NAND_BBT_OK: + rv = cyg_nandp_erase_block(part, blk); + if (rv != 0) + diag_printf("Block %d: error %d\n", blk, -rv); + break; + case CYG_NAND_BBT_WORNBAD: + msg="worn bad"; break; + case CYG_NAND_BBT_FACTORY_BAD: + msg="factory bad"; break; + + case CYG_NAND_BBT_RESERVED: + // Skip quietly + break; + } + if (msg) + diag_printf("Skipping block %d (%s)\n", blk, msg); + + if (0==(blk % progmod)) + diag_printf("."); + } + diag_printf("\nErase complete.\n"); +} + +local_cmd_entry("erase", "Erases a NAND partition", "<partition> (e.g. mynand/0)", nand_erase, NAND_cmds); + +#endif // CYGSEM_REDBOOT_NAND_ERASE_CMD + +//========================================================================== + +// end nand.c
