diff -Nur anon-hg/packages/hal/arm/lpc24xx/ea2468/current/cdl/hal_arm_lpc24xx_ea2468.cdl anon+nand/packages/hal/arm/lpc24xx/ea2468/current/cdl/hal_arm_lpc24xx_ea2468.cdl
--- anon-hg/packages/hal/arm/lpc24xx/ea2468/current/cdl/hal_arm_lpc24xx_ea2468.cdl	2009-10-28 11:10:41.000000000 +0000
+++ anon+nand/packages/hal/arm/lpc24xx/ea2468/current/cdl/hal_arm_lpc24xx_ea2468.cdl	2009-11-12 11:47:25.000000000 +0000
@@ -321,7 +321,63 @@
                              "<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
diff -Nur anon-hg/packages/hal/arm/lpc24xx/ea2468/current/cdl/manual_partition.cdl anon+nand/packages/hal/arm/lpc24xx/ea2468/current/cdl/manual_partition.cdl
--- anon-hg/packages/hal/arm/lpc24xx/ea2468/current/cdl/manual_partition.cdl	1970-01-01 01:00:00.000000000 +0100
+++ anon+nand/packages/hal/arm/lpc24xx/ea2468/current/cdl/manual_partition.cdl	2009-11-12 11:47:25.000000000 +0000
@@ -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.
diff -Nur anon-hg/packages/hal/arm/lpc24xx/ea2468/current/ChangeLog anon+nand/packages/hal/arm/lpc24xx/ea2468/current/ChangeLog
--- anon-hg/packages/hal/arm/lpc24xx/ea2468/current/ChangeLog	2009-10-28 11:10:41.000000000 +0000
+++ anon+nand/packages/hal/arm/lpc24xx/ea2468/current/ChangeLog	2009-11-12 15:06:57.000000000 +0000
@@ -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
diff -Nur anon-hg/packages/hal/arm/lpc24xx/ea2468/current/src/ea_lpc2468_nand.c anon+nand/packages/hal/arm/lpc24xx/ea2468/current/src/ea_lpc2468_nand.c
--- anon-hg/packages/hal/arm/lpc24xx/ea2468/current/src/ea_lpc2468_nand.c	1970-01-01 01:00:00.000000000 +0100
+++ anon+nand/packages/hal/arm/lpc24xx/ea2468/current/src/ea_lpc2468_nand.c	2009-11-13 10:36:21.000000000 +0000
@@ -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);
+
