* Patch by Scott McNutt, 21 Jul 2003:
  Add support for LynuxWorks Kernel Downloadable Images (KDIs).
  Both LynxOS and BlueCat linux KDIs are supported.

* Patch by Richard Woodruff, 25 Jul 2003:
  use more reliable reset for OMAP/925T

* Patch by Nye Liu, 25 Jul 2003:
  fix typo in mpc8xx.h

* Patch by Richard Woodruff, 24 Jul 2003:
  Fixes for cmd_nand.c:
  - Fixed null dereferece which could result in incorrect ECC values.
  - Added support for devices with no Ready/Busy signal hooked up.
  - Added OMAP1510 read/write protect handling.
  - Fixed nand.h's ECCPOS. A conflict existed with POS5 and badblock
    for non-JFFS2.
  - Switched default ECC to be JFFS2.
diff --git a/common/Makefile b/common/Makefile
index d144bef..f640cda 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -44,7 +44,7 @@
 	  environment.o env_common.o \
 	  env_flash.o env_eeprom.o env_nvram.o env_nowhere.o exports.o \
 	  flash.o fpga.o \
-	  hush.o kgdb.o lists.o miiphybb.o miiphyutil.o \
+	  hush.o kgdb.o lists.o lynxkdi.o miiphybb.o miiphyutil.o \
 	  s_record.o soft_i2c.o soft_spi.o spartan2.o \
 	  usb.o usb_kbd.o usb_storage.o \
 	  virtex2.o xilinx.o
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 1343659..794f0de 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -127,6 +127,10 @@
 #if defined(CONFIG_ARTOS) && defined(CONFIG_PPC)
 static boot_os_Fcn do_bootm_artos;
 #endif
+#ifdef CONFIG_LYNXKDI
+static boot_os_Fcn do_bootm_lynxkdi;
+extern void lynxkdi_boot( image_header_t * );
+#endif
 
 image_header_t header;
 
@@ -357,6 +361,13 @@
 			     addr, len_ptr, verify);
 	    break;
 
+#ifdef CONFIG_LYNXKDI
+	case IH_OS_LYNXOS:
+	    do_bootm_lynxkdi (cmdtp, flag, argc, argv,
+			     addr, len_ptr, verify);
+	    break;
+#endif
+
 	case IH_OS_RTEMS:
 	    do_bootm_rtems (cmdtp, flag, argc, argv,
 			     addr, len_ptr, verify);
@@ -1069,6 +1080,9 @@
 #ifdef CONFIG_ARTOS
 	case IH_OS_ARTOS:	os = "ARTOS";			break;
 #endif
+#ifdef CONFIG_LYNXKDI
+	case IH_OS_LYNXOS:	os = "LynxOS";			break;
+#endif
 	default:		os = "Unknown OS";		break;
 	}
 
@@ -1242,3 +1256,17 @@
 	do_bootelf(cmdtp, 0, 2, local_args);
 }
 #endif /* CFG_CMD_ELF */
+
+#ifdef CONFIG_LYNXKDI
+static void
+do_bootm_lynxkdi (cmd_tbl_t *cmdtp, int flag,
+		 int	argc, char *argv[],
+		 ulong	addr,
+		 ulong	*len_ptr,
+		 int	verify)
+{
+	lynxkdi_boot( &header );
+}
+
+#endif /* CONFIG_LYNXKDI */
+
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 137f34f..ec76aa3 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -3,7 +3,6 @@
  * borrowed heavily from:
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
- *
  */
 
 #include <common.h>
@@ -24,6 +23,12 @@
 #include <linux/mtd/nand_ids.h>
 #include <jffs2/jffs2.h>
 
+#ifdef CONFIG_OMAP1510
+void archflashwp(void *archdata, int wp);
+#endif
+
+#define ROUND_DOWN(value,boundary)      ((value) & (~((boundary)-1)))
+
 /*
  * Definition of the out of band configuration structure
  */
@@ -52,7 +57,7 @@
 #define	 ALLOW_ERASE_BAD_DEBUG 0
 
 #define CONFIG_MTD_NAND_ECC  /* enable ECC */
-/* #define CONFIG_MTD_NAND_ECC_JFFS2 */
+#define CONFIG_MTD_NAND_ECC_JFFS2
 
 /* bits for nand_rw() `cmd'; or together as needed */
 #define NANDRW_READ	0x01
@@ -76,6 +81,7 @@
 		 size_t * retlen, u_char * buf);
 static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
 		 size_t * retlen, const u_char * buf);
+static int NanD_WaitReady(struct nand_chip *nand, int ale_wait);
 #ifdef CONFIG_MTD_NAND_ECC
 static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
 static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
@@ -218,7 +224,7 @@
 		ret = nand_rw(nand_dev_desc + curr_device, cmd, off, size,
 			     &total, (u_char*)addr);
 
-		printf ("%d bytes %s: %s\n", total,
+		printf (" %d bytes %s: %s\n", total,
 			(cmd & NANDRW_READ) ? "read" : "write",
 			ret ? "ERROR" : "OK");
 
@@ -419,7 +425,7 @@
 	    size_t start, size_t len,
 	    size_t * retlen, u_char * buf)
 {
-	int noecc, ret = 0, n, total = 0;
+	int ret = 0, n, total = 0;
 	char eccbuf[6];
 	/* eblk (once set) is the start of the erase block containing the
 	 * data being processed.
@@ -457,17 +463,18 @@
 		}
 		/* The ECC will not be calculated correctly if
 		   less than 512 is written or read */
-		noecc = (start != (start | 0x1ff) + 1) ||	(len < 0x200);
+		/* Is request at least 512 bytes AND it starts on a proper boundry */
+		if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200))
+			printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n");
+
 		if (cmd & NANDRW_READ)
 			ret = nand_read_ecc(nand, start,
 					   min(len, eblk + erasesize - start),
-					   &n, (u_char*)buf,
-					   noecc ? NULL : eccbuf);
+					   &n, (u_char*)buf, eccbuf);
 		else
 			ret = nand_write_ecc(nand, start,
 					    min(len, eblk + erasesize - start),
-					    &n, (u_char*)buf,
-					    noecc ? NULL : eccbuf);
+					    &n, (u_char*)buf, eccbuf);
 
 		if (ret)
 			break;
@@ -502,19 +509,19 @@
 
 /* ------------------------------------------------------------------------- */
 
-/* This function is needed to avoid calls of the __ashrdi3 function. */
-#if 0
-static int shr(int val, int shift)
-{
-	return val >> shift;
-}
-#endif
-static int NanD_WaitReady(struct nand_chip *nand)
+static int NanD_WaitReady(struct nand_chip *nand, int ale_wait)
 {
 	/* This is inline, to optimise the common case, where it's ready instantly */
 	int ret = 0;
-	NAND_WAIT_READY(nand);
 
+#ifdef NAND_NO_RB	/* in config file, shorter delays currently wrap accesses */
+	if(ale_wait)
+		NAND_WAIT_READY(nand);	/* do the worst case 25us wait */
+	else
+		udelay(10);
+#else	/* has functional r/b signal */
+    NAND_WAIT_READY(nand);
+#endif
 	return ret;
 }
 
@@ -533,7 +540,16 @@
 	/* Lower the CLE line */
 	NAND_CTL_CLRCLE(nandptr);
 
-	return NanD_WaitReady(nand);
+#ifdef NAND_NO_RB
+	if(command == NAND_CMD_RESET){
+		u_char ret_val;
+		NanD_Command(nand, NAND_CMD_STATUS);
+		do{
+			ret_val = READ_NAND(nandptr);/* wait till ready */
+		} while((ret_val & 0x40) != 0x40);
+	}
+#endif
+	return NanD_WaitReady(nand, 0);
 }
 
 /* NanD_Address: Set the current address for the flash chip */
@@ -573,7 +589,7 @@
 	NAND_CTL_CLRALE(nandptr);
 
 	/* Wait for the chip to respond */
-	return NanD_WaitReady(nand);
+	return NanD_WaitReady(nand, 1);
 }
 
 /* NanD_SelectChip: Select a given flash chip within the current floor */
@@ -581,7 +597,7 @@
 static inline int NanD_SelectChip(struct nand_chip *nand, int chip)
 {
 	/* Wait for it to be ready */
-	return NanD_WaitReady(nand);
+	return NanD_WaitReady(nand, 0);
 }
 
 /* NanD_IdentChip: Identify a given NAND chip given {floor,chip} */
@@ -931,8 +947,8 @@
 {
 
 	int i;
-#ifdef CONFIG_MTD_NAND_ECC
 	unsigned long nandptr = nand->IO_ADDR;
+#ifdef CONFIG_MTD_NAND_ECC
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
 	int ecc_bytes = (nand->oobblock == 512) ? 6 : 3;
 #endif
@@ -992,12 +1008,20 @@
 	/* Send command to actually program the data */
 	NanD_Command(nand, NAND_CMD_PAGEPROG);
 	NanD_Command(nand, NAND_CMD_STATUS);
+#ifdef NAND_NO_RB
+	{ u_char ret_val;
 
+	  do{
+		ret_val = READ_NAND(nandptr);	/* wait till ready */
+	  } while((ret_val & 0x40) != 0x40);
+	}
+#endif
 	/* See if device thinks it succeeded */
 	if (READ_NAND(nand->IO_ADDR) & 0x01) {
 		printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, page);
 		return -1;
 	}
+
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
 	/*
 	 * The NAND device assumes that it is always writing to
@@ -1069,7 +1093,10 @@
 	*retlen = 0;
 
 	/* Select the NAND device */
-	NAND_ENABLE_CE(nand);  /* set pin low */
+#ifdef CONFIG_OMAP1510
+	archflashwp(0,0);
+#endif
+    	NAND_ENABLE_CE(nand);  /* set pin low */
 
 	/* Check the WP bit */
 	NanD_Command(nand, NAND_CMD_STATUS);
@@ -1113,7 +1140,9 @@
 out:
 	/* De-select the NAND device */
 	NAND_DISABLE_CE(nand);  /* set pin high */
-
+#ifdef CONFIG_OMAP1510
+    	archflashwp(0,1);
+#endif
 	return ret;
 }
 
@@ -1160,7 +1189,7 @@
 	 * causing the flash device to go into busy mode, so we need
 	 * to wait until ready 11.4.1 and Toshiba TC58256FT nands */
 
-	ret = NanD_WaitReady(nand);
+	ret = NanD_WaitReady(nand, 1);
 	NAND_DISABLE_CE(nand);  /* set pin high */
 
 	return ret;
@@ -1215,8 +1244,13 @@
 
 		NanD_Command(nand, NAND_CMD_PAGEPROG);
 		NanD_Command(nand, NAND_CMD_STATUS);
-		/* NanD_WaitReady() is implicit in NanD_Command */
-
+#ifdef NAND_NO_RB
+   		{ u_char ret_val;
+    		  do{
+		  	ret_val = READ_NAND(nandptr); /* wait till ready */
+    		  }while((ret_val & 0x40) != 0x40);
+		}
+#endif
 		if (READ_NAND(nandptr) & 1) {
 			puts ("Error programming oob data\n");
 			/* There was an error */
@@ -1233,8 +1267,13 @@
 
 	NanD_Command(nand, NAND_CMD_PAGEPROG);
 	NanD_Command(nand, NAND_CMD_STATUS);
-	/* NanD_WaitReady() is implicit in NanD_Command */
-
+#ifdef NAND_NO_RB
+	{ u_char ret_val;
+	  do{
+		ret_val = READ_NAND(nandptr); /* wait till ready */
+	  } while((ret_val & 0x40) != 0x40);
+	}
+#endif
 	if (READ_NAND(nandptr) & 1) {
 		puts ("Error programming oob data\n");
 		/* There was an error */
@@ -1272,7 +1311,10 @@
 	nandptr = nand->IO_ADDR;
 
 	/* Select the NAND device */
-	NAND_ENABLE_CE(nand);  /* set pin low */
+#ifdef CONFIG_OMAP1510
+	archflashwp(0,0);
+#endif
+    NAND_ENABLE_CE(nand);  /* set pin low */
 
 	/* Check the WP bit */
 	NanD_Command(nand, NAND_CMD_STATUS);
@@ -1308,6 +1350,13 @@
 
 			NanD_Command(nand, NAND_CMD_STATUS);
 
+#ifdef NAND_NO_RB
+			{ u_char ret_val;
+			  do{
+				ret_val = READ_NAND(nandptr); /* wait till ready */
+			  } while((ret_val & 0x40) != 0x40);
+			}
+#endif
 			if (READ_NAND(nandptr) & 1) {
 				printf ("%s: Error erasing at 0x%lx\n",
 					__FUNCTION__, (long)ofs);
@@ -1346,7 +1395,9 @@
 out:
 	/* De-select the NAND device */
 	NAND_DISABLE_CE(nand);  /* set pin high */
-
+#ifdef CONFIG_OMAP1510
+    	archflashwp(0,1);
+#endif
 	return ret;
 }
 
@@ -1596,5 +1647,6 @@
 	/* Should never happen */
 	return -1;
 }
+
 #endif
 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
diff --git a/common/lynxkdi.c b/common/lynxkdi.c
new file mode 100644
index 0000000..95df955
--- /dev/null
+++ b/common/lynxkdi.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) Orbacom Systems, Inc <www.orbacom.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <image.h>
+
+#if defined(CONFIG_LYNXKDI)
+#include <lynxkdi.h>
+
+#if defined(CONFIG_MPC8260)
+void lynxkdi_boot ( image_header_t *hdr )
+{
+	void (*lynxkdi)(void) = (void(*)(void))hdr->ih_ep;
+	lynxos_bootparms_t *parms = (lynxos_bootparms_t *)0x0020;
+	bd_t *kbd;
+	DECLARE_GLOBAL_DATA_PTR;
+	u32 *psz = (u32 *)(hdr->ih_load + 0x0204);
+
+	memset( parms, 0, sizeof(*parms));
+	kbd = gd->bd;
+	parms->clock_ref = kbd->bi_busfreq;
+	parms->dramsz = kbd->bi_memsize;
+	memcpy(parms->ethaddr, kbd->bi_enetaddr, 6);
+	mtspr(SPRN_SPRG2, 0x0020);
+
+	/* Do a simple check for Bluecat so we can pass the
+	 * kernel command line parameters.
+	 */
+	if( le32_to_cpu(*psz) == hdr->ih_size ){
+	    char *args;
+	    char *cmdline = (char *)(hdr->ih_load + 0x020c);
+	    int len;
+
+	    printf("Booting Bluecat KDI ...\n");
+	    udelay(200*1000); /* Allow serial port to flush */
+	    if ((args = getenv("bootargs")) == NULL)
+		    args = "";
+	    /* Prepend the cmdline */
+	    len = strlen(args);
+	    if( len && (len + strlen(cmdline) + 2 < (0x0400 - 0x020c))) {
+		memmove( cmdline + strlen(args) + 1, cmdline, strlen(cmdline) );
+		strcpy( cmdline, args );
+		cmdline[len] = ' ';
+	    }
+	}
+	else {
+	    printf("Booting LynxOS KDI ...\n");
+	}
+
+	lynxkdi();
+}
+#else
+#error "Lynx KDI support not implemented for configured CPU"
+#endif
+
+#endif	/* CONFIG_LYNXKDI */
+