Patches by Josef Wagner, 29 Oct 2004:
- Add support for MicroSys CPU87 board
- Add support for MicroSys PM854 board
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index af3c674..6057dd1 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -3,6 +3,9 @@
  * borrowed heavily from:
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Added 16-bit nand support
+ * (C) 2004 Texas Instruments
  */
 
 #include <common.h>
@@ -20,10 +23,6 @@
 
 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
 
-#ifdef CONFIG_AT91RM9200DK
-#include <asm/arch/hardware.h>
-#endif
-
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ids.h>
 #include <jffs2/jffs2.h>
@@ -399,10 +398,11 @@
  *		not marked bad, or no bad mark position is specified
  * returns 1 if marked bad or otherwise invalid
  */
-int check_block(struct nand_chip* nand, unsigned long pos)
+int check_block (struct nand_chip *nand, unsigned long pos)
 {
 	int retlen;
 	uint8_t oob_data;
+	uint16_t oob_data16[6];
 	int page0 = pos & (-nand->erasesize);
 	int page1 = page0 + nand->oobblock;
 	int badpos = oob_config.badblock_pos;
@@ -413,12 +413,21 @@
 	if (badpos < 0)
 		return 0;	/* no way to check, assume OK */
 
-	/* Note - bad block marker can be on first or second page */
-	if (nand_read_oob(nand, page0 + badpos, 1, &retlen, &oob_data) ||
-	    oob_data != 0xff ||
-	    nand_read_oob(nand, page1 + badpos, 1, &retlen, &oob_data) ||
-	    oob_data != 0xff)
-		return 1;
+	if (nand->bus16) {
+		if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16)
+		    || (oob_data16[2] & 0xff00) != 0xff00)
+			return 1;
+		if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16)
+		    || (oob_data16[2] & 0xff00) != 0xff00)
+			return 1;
+	} else {
+		/* Note - bad block marker can be on first or second page */
+		if (nand_read_oob(nand, page0 + badpos, 1, &retlen, &oob_data)
+		    || oob_data != 0xff
+		    || nand_read_oob (nand, page1 + badpos, 1, &retlen, &oob_data)
+		    || oob_data != 0xff)
+			return 1;
+	}
 
 	return 0;
 }
@@ -469,17 +478,14 @@
 						--len;
 					}
 					continue;
-				}
-				else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
+				} else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
 					start += erasesize;
 					continue;
-				}
-				else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
+				} else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
 					/* skip bad block */
 					start += erasesize;
 					continue;
-				}
-				else {
+				} else {
 					ret = 1;
 					break;
 				}
@@ -491,14 +497,15 @@
 		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)
+		if (cmd & NANDRW_READ) {
 			ret = nand_read_ecc(nand, start,
 					   min(len, eblk + erasesize - start),
 					   &n, (u_char*)buf, eccbuf);
-		else
+		} else {
 			ret = nand_write_ecc(nand, start,
 					    min(len, eblk + erasesize - start),
 					    &n, (u_char*)buf, eccbuf);
+		}
 
 		if (ret)
 			break;
@@ -568,7 +575,7 @@
 	if(command == NAND_CMD_RESET){
 		u_char ret_val;
 		NanD_Command(nand, NAND_CMD_STATUS);
-		do{
+		do {
 			ret_val = READ_NAND(nandptr);/* wait till ready */
 		} while((ret_val & 0x40) != 0x40);
 	}
@@ -605,9 +612,11 @@
 
 	ofs = ofs >> nand->page_shift;
 
-	if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE)
-		for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8)
+	if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+		for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) {
 			WRITE_NAND_ADDRESS(ofs, nandptr);
+		}
+	}
 
 	/* Lower the ALE line */
 	NAND_CTL_CLRALE(nandptr);
@@ -674,11 +683,12 @@
 	 * contain _one_ type of flash part, although that's not a
 	 * hardware restriction. */
 	if (nand->mfr) {
-		if (nand->mfr == mfr && nand->id == id)
+		if (nand->mfr == mfr && nand->id == id) {
 			return 1;	/* This is another the same the first */
-		else
+		} else {
 			printf("Flash chip at floor %d, chip %d is different:\n",
 			       floor, chip);
+		}
 	}
 
 	/* Print and store the manufacturer and ID codes. */
@@ -706,13 +716,11 @@
 					nand->oobsize = 16;
 					nand->page_shift = 9;
 				}
-				nand->pageadrlen =
-				    nand_flash_ids[i].pageadrlen;
-				nand->erasesize =
-				    nand_flash_ids[i].erasesize;
-				nand->chips_name =
-				    nand_flash_ids[i].name;
-				return 1;
+				nand->pageadrlen = nand_flash_ids[i].pageadrlen;
+				nand->erasesize  = nand_flash_ids[i].erasesize;
+				nand->chips_name = nand_flash_ids[i].name;
+				nand->bus16	 = nand_flash_ids[i].bus16;
+ 				return 1;
 			}
 			return 0;
 		}
@@ -795,33 +803,74 @@
 }
 
 /* we need to be fast here, 1 us per read translates to 1 second per meg */
-static void NanD_ReadBuf(struct nand_chip *nand, u_char *data_buf, int cntr)
+static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr)
 {
 	unsigned long nandptr = nand->IO_ADDR;
 
-	while (cntr >= 16) {
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		*data_buf++ = READ_NAND(nandptr);
-		cntr -= 16;
-	}
+	NanD_Command (nand, NAND_CMD_READ0);
 
-	while (cntr > 0) {
-		*data_buf++ = READ_NAND(nandptr);
-		cntr--;
+	if (nand->bus16) {
+		u16 val;
+
+		while (cntr >= 16) {
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			cntr -= 16;
+		}
+
+		while (cntr > 0) {
+			val = READ_NAND (nandptr);
+			*data_buf++ = val & 0xff;
+			*data_buf++ = val >> 8;
+			cntr -= 2;
+		}
+	} else {
+		while (cntr >= 16) {
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			*data_buf++ = READ_NAND (nandptr);
+			cntr -= 16;
+		}
+
+		while (cntr > 0) {
+			*data_buf++ = READ_NAND (nandptr);
+			cntr--;
+		}
 	}
 }
 
@@ -842,7 +891,8 @@
 
 	/* Do not allow reads past end of device */
 	if ((start + len) > nand->totlen) {
-		printf ("%s: Attempt read beyond end of device %x %x %x\n", __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen);
+		printf ("%s: Attempt read beyond end of device %x %x %x\n",
+			__FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen);
 		*retlen = 0;
 		return -1;
 	}
@@ -863,25 +913,33 @@
 	/* Loop until all data read */
 	while (*retlen < len) {
 
-
 #ifdef CONFIG_MTD_NAND_ECC
-
 		/* Do we have this page in cache ? */
 		if (nand->cache_page == page)
 			goto readdata;
 		/* Send the read command */
 		NanD_Command(nand, NAND_CMD_READ0);
-		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);
+		if (nand->bus16) {
+ 			NanD_Address(nand, ADDR_COLUMN_PAGE,
+				     (page << nand->page_shift) + (col >> 1));
+		} else {
+ 			NanD_Address(nand, ADDR_COLUMN_PAGE,
+				     (page << nand->page_shift) + col);
+		}
+
 		/* Read in a page + oob data */
 		NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize);
 
 		/* copy data into cache, for read out of cache and if ecc fails */
-		if (nand->data_cache)
-			memcpy (nand->data_cache, nand->data_buf, nand->oobblock + nand->oobsize);
+		if (nand->data_cache) {
+			memcpy (nand->data_cache, nand->data_buf,
+				nand->oobblock + nand->oobsize);
+		}
 
 		/* Pick the ECC bytes out of the oob data */
-		for (j = 0; j < 6; j++)
+		for (j = 0; j < 6; j++) {
 			ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])];
+		}
 
 		/* Calculate the ECC and verify it */
 		/* If block was not written with ECC, skip ECC */
@@ -938,7 +996,14 @@
 #else
 		/* Send the read command */
 		NanD_Command(nand, NAND_CMD_READ0);
-		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);
+		if (nand->bus16) {
+			NanD_Address(nand, ADDR_COLUMN_PAGE,
+				     (page << nand->page_shift) + (col >> 1));
+		} else {
+			NanD_Address(nand, ADDR_COLUMN_PAGE,
+				     (page << nand->page_shift) + col);
+		}
+
 		/* Read the data directly into the return buffer */
 		if ((*retlen + (nand->oobblock - col)) >= len) {
 			NanD_ReadBuf(nand, buf + *retlen, len - *retlen);
@@ -976,6 +1041,7 @@
 
 	int i;
 	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;
@@ -992,28 +1058,53 @@
 
 	/* Read back previous written data, if col > 0 */
 	if (col) {
-		NanD_Command(nand, NAND_CMD_READ0);
-		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);
-		for (i = 0; i < col; i++)
-			nand->data_buf[i] = READ_NAND (nandptr);
+		NanD_Command (nand, NAND_CMD_READ0);
+		if (nand->bus16) {
+			NanD_Address (nand, ADDR_COLUMN_PAGE,
+				      (page << nand->page_shift) + (col >> 1));
+		} else {
+			NanD_Address (nand, ADDR_COLUMN_PAGE,
+				      (page << nand->page_shift) + col);
+		}
+
+		if (nand->bus16) {
+			u16 val;
+
+			for (i = 0; i < col; i += 2) {
+				val = READ_NAND (nandptr);
+				nand->data_buf[i] = val & 0xff;
+				nand->data_buf[i + 1] = val >> 8;
+			}
+		} else {
+			for (i = 0; i < col; i++)
+				nand->data_buf[i] = READ_NAND (nandptr);
+		}
 	}
 
 	/* Calculate and write the ECC if we have enough data */
 	if ((col < nand->eccsize) && (last >= nand->eccsize)) {
 		nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0]));
-		for (i = 0; i < 3; i++)
-			nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i];
-		if (oob_config.eccvalid_pos != -1)
-			nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] = 0xf0;
+		for (i = 0; i < 3; i++) {
+			nand->data_buf[(nand->oobblock +
+					oob_config.ecc_pos[i])] = ecc_code[i];
+		}
+		if (oob_config.eccvalid_pos != -1) {
+			nand->data_buf[nand->oobblock +
+				       oob_config.eccvalid_pos] = 0xf0;
+		}
 	}
 
 	/* Calculate and write the second ECC if we have enough data */
 	if ((nand->oobblock == 512) && (last == nand->oobblock)) {
 		nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3]));
-		for (i = 3; i < 6; i++)
-			nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i];
-		if (oob_config.eccvalid_pos != -1)
-			nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] &= 0x0f;
+		for (i = 3; i < 6; i++) {
+			nand->data_buf[(nand->oobblock +
+					oob_config.ecc_pos[i])] = ecc_code[i];
+		}
+		if (oob_config.eccvalid_pos != -1) {
+			nand->data_buf[nand->oobblock +
+				       oob_config.eccvalid_pos] &= 0x0f;
+		}
 	}
 #endif
 	/* Prepad for partial page programming !!! */
@@ -1025,31 +1116,46 @@
 		nand->data_buf[i] = 0xff;
 
 	/* Send command to begin auto page programming */
-	NanD_Command(nand, NAND_CMD_READ0);
-	NanD_Command(nand, NAND_CMD_SEQIN);
-	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);
+	NanD_Command (nand, NAND_CMD_READ0);
+	NanD_Command (nand, NAND_CMD_SEQIN);
+	if (nand->bus16) {
+		NanD_Address (nand, ADDR_COLUMN_PAGE,
+			      (page << nand->page_shift) + (col >> 1));
+	} else {
+		NanD_Address (nand, ADDR_COLUMN_PAGE,
+			      (page << nand->page_shift) + col);
+	}
 
 	/* Write out complete page of data */
-	for (i = 0; i < (nand->oobblock + nand->oobsize); i++)
-		WRITE_NAND(nand->data_buf[i], nand->IO_ADDR);
+	if (nand->bus16) {
+		for (i = 0; i < (nand->oobblock + nand->oobsize); i += 2) {
+			WRITE_NAND (nand->data_buf[i] +
+				    (nand->data_buf[i + 1] << 8),
+				    nand->IO_ADDR);
+		}
+	} else {
+		for (i = 0; i < (nand->oobblock + nand->oobsize); i++)
+			WRITE_NAND (nand->data_buf[i], nand->IO_ADDR);
+	}
 
 	/* Send command to actually program the data */
-	NanD_Command(nand, NAND_CMD_PAGEPROG);
-	NanD_Command(nand, NAND_CMD_STATUS);
+	NanD_Command (nand, NAND_CMD_PAGEPROG);
+	NanD_Command (nand, NAND_CMD_STATUS);
 #ifdef NAND_NO_RB
-	{ u_char ret_val;
+	{
+		u_char ret_val;
 
-	  do{
-		ret_val = READ_NAND(nandptr);	/* wait till ready */
-	  } while((ret_val & 0x40) != 0x40);
+		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);
+	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
@@ -1066,16 +1172,34 @@
 
 	/* Send command to read back the page */
 	if (col < nand->eccsize)
-		NanD_Command(nand, NAND_CMD_READ0);
+		NanD_Command (nand, NAND_CMD_READ0);
 	else
-		NanD_Command(nand, NAND_CMD_READ1);
-	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);
+		NanD_Command (nand, NAND_CMD_READ1);
+	if (nand->bus16) {
+		NanD_Address (nand, ADDR_COLUMN_PAGE,
+			      (page << nand->page_shift) + (col >> 1));
+	} else {
+		NanD_Address (nand, ADDR_COLUMN_PAGE,
+			      (page << nand->page_shift) + col);
+	}
 
 	/* Loop through and verify the data */
-	for (i = col; i < last; i++) {
-		if (nand->data_buf[i] != readb (nand->IO_ADDR)) {
-			printf ("%s: Failed write verify, page 0x%08x ", __FUNCTION__, page);
-			return -1;
+	if (nand->bus16) {
+		for (i = col; i < last; i = +2) {
+			if ((nand->data_buf[i] +
+			     (nand->data_buf[i + 1] << 8)) != READ_NAND (nand->IO_ADDR)) {
+				printf ("%s: Failed write verify, page 0x%08x ",
+					__FUNCTION__, page);
+				return -1;
+			}
+		}
+	} else {
+		for (i = col; i < last; i++) {
+			if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) {
+				printf ("%s: Failed write verify, page 0x%08x ",
+					__FUNCTION__, page);
+				return -1;
+			}
 		}
 	}
 
@@ -1084,19 +1208,36 @@
 	 * We also want to check that the ECC bytes wrote
 	 * correctly for the same reasons stated above.
 	 */
-	NanD_Command(nand, NAND_CMD_READOOB);
-	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);
-	for (i = 0; i < nand->oobsize; i++)
-		nand->data_buf[i] = readb (nand->IO_ADDR);
+	NanD_Command (nand, NAND_CMD_READOOB);
+	if (nand->bus16) {
+		NanD_Address (nand, ADDR_COLUMN_PAGE,
+			      (page << nand->page_shift) + (col >> 1));
+	} else {
+		NanD_Address (nand, ADDR_COLUMN_PAGE,
+			      (page << nand->page_shift) + col);
+	}
+	if (nand->bus16) {
+		for (i = 0; i < nand->oobsize; i += 2) {
+			val = READ_NAND (nand->IO_ADDR);
+			nand->data_buf[i] = val & 0xff;
+			nand->data_buf[i + 1] = val >> 8;
+		}
+	} else {
+		for (i = 0; i < nand->oobsize; i++) {
+			nand->data_buf[i] = READ_NAND (nand->IO_ADDR);
+		}
+	}
 	for (i = 0; i < ecc_bytes; i++) {
 		if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) {
 			printf ("%s: Failed ECC write "
-			       "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
+				"verify, page 0x%08x, "
+				"%6i bytes were succesful\n",
+				__FUNCTION__, page, i);
 			return -1;
 		}
 	}
-#endif
-#endif
+#endif	/* CONFIG_MTD_NAND_ECC */
+#endif	/* CONFIG_MTD_NAND_VERIFY_WRITE */
 	return 0;
 }
 
@@ -1124,6 +1265,10 @@
 #ifdef CONFIG_OMAP1510
 	archflashwp(0,0);
 #endif
+#ifdef CFG_NAND_WP
+	NAND_WP_OFF();
+#endif
+
     	NAND_ENABLE_CE(nand);  /* set pin low */
 
 	/* Check the WP bit */
@@ -1141,12 +1286,15 @@
 			nand->cache_page = -1;
 
 		/* Write data into buffer */
-		if ((col + len) >= nand->oobblock)
-			for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++)
+		if ((col + len) >= nand->oobblock) {
+			for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) {
 				nand->data_buf[i] = buf[(*retlen + cnt)];
-		else
-			for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++)
+			}
+		} else {
+			for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) {
 				nand->data_buf[i] = buf[(*retlen + cnt)];
+			}
+		}
 		/* We use the same function for write and writev !) */
 		ret = nand_write_page (nand, page, col, i, ecc_code);
 		if (ret)
@@ -1171,6 +1319,10 @@
 #ifdef CONFIG_OMAP1510
     	archflashwp(0,1);
 #endif
+#ifdef CFG_NAND_WP
+	NAND_WP_ON();
+#endif
+
 	return ret;
 }
 
@@ -1197,7 +1349,13 @@
 
 	NAND_ENABLE_CE(nand);  /* set pin low */
 	NanD_Command(nand, NAND_CMD_READOOB);
-	NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+	if (nand->bus16) {
+ 		NanD_Address(nand, ADDR_COLUMN_PAGE,
+			     ((ofs >> nand->page_shift) << nand->page_shift) +
+ 				((ofs & (nand->oobblock - 1)) >> 1));
+	} else {
+		NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+	}
 
 	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
 	/* Note: datasheet says it should automaticaly wrap to the */
@@ -1247,7 +1405,13 @@
 
 	/* issue the Read2 command to set the pointer to the Spare Data Area. */
 	NanD_Command(nand, NAND_CMD_READOOB);
-	NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+	if (nand->bus16) {
+ 		NanD_Address(nand, ADDR_COLUMN_PAGE,
+			     ((ofs >> nand->page_shift) << nand->page_shift) +
+ 				((ofs & (nand->oobblock - 1)) >> 1));
+	} else {
+ 		NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+	}
 
 	/* update address for 2M x 8bit devices. OOB starts on the second */
 	/* page to maintain compatibility with nand_read_ecc. */
@@ -1260,7 +1424,13 @@
 
 	/* issue the Serial Data In command to initial the Page Program process */
 	NanD_Command(nand, NAND_CMD_SEQIN);
-	NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+	if (nand->bus16) {
+ 		NanD_Address(nand, ADDR_COLUMN_PAGE,
+			     ((ofs >> nand->page_shift) << nand->page_shift) +
+ 				((ofs & (nand->oobblock - 1)) >> 1));
+	} else {
+ 		NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+	}
 
 	/* treat crossing 8-byte OOB data for 2M x 8bit devices */
 	/* Note: datasheet says it should automaticaly wrap to the */
@@ -1274,9 +1444,9 @@
 		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);
+			do {
+				ret_val = READ_NAND(nandptr); /* wait till ready */
+			} while ((ret_val & 0x40) != 0x40);
 		}
 #endif
 		if (READ_NAND(nandptr) & 1) {
@@ -1290,16 +1460,22 @@
 		NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
 	}
 
-	for (i = len256; i < len; i++)
-		WRITE_NAND(buf[i], nandptr);
+	if (nand->bus16) {
+		for (i = len256; i < len; i += 2) {
+			WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr);
+		}
+	} else {
+		for (i = len256; i < len; i++)
+			WRITE_NAND(buf[i], nandptr);
+	}
 
 	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);
+	{	u_char ret_val;
+		do {
+			ret_val = READ_NAND(nandptr); /* wait till ready */
+		} while ((ret_val & 0x40) != 0x40);
 	}
 #endif
 	if (READ_NAND(nandptr) & 1) {
@@ -1342,6 +1518,9 @@
 #ifdef CONFIG_OMAP1510
 	archflashwp(0,0);
 #endif
+#ifdef CFG_NAND_WP
+	NAND_WP_OFF();
+#endif
     NAND_ENABLE_CE(nand);  /* set pin low */
 
 	/* Check the WP bit */
@@ -1379,10 +1558,10 @@
 			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);
+			{	u_char ret_val;
+				do {
+					ret_val = READ_NAND(nandptr); /* wait till ready */
+				} while ((ret_val & 0x40) != 0x40);
 			}
 #endif
 			if (READ_NAND(nandptr) & 1) {
@@ -1403,8 +1582,7 @@
 				if (nand->page256) {
 					p = NAND_JFFS2_OOB8_FSDAPOS;
 					l = NAND_JFFS2_OOB8_FSDALEN;
-				}
-				else {
+				} else {
 					p = NAND_JFFS2_OOB16_FSDAPOS;
 					l = NAND_JFFS2_OOB16_FSDALEN;
 				}
@@ -1426,6 +1604,10 @@
 #ifdef CONFIG_OMAP1510
     	archflashwp(0,1);
 #endif
+#ifdef CFG_NAND_WP
+	NAND_WP_ON();
+#endif
+
 	return ret;
 }
 
@@ -1498,22 +1680,38 @@
  * 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
+	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
 };
 
 
@@ -1606,8 +1804,7 @@
 	if ((d1 | d2 | d3) == 0) {
 		/* No errors */
 		return 0;
-	}
-	else {
+	} else {
 		a = (d1 ^ (d1 >> 1)) & 0x55;
 		b = (d2 ^ (d2 >> 1)) & 0x55;
 		c = (d3 ^ (d3 >> 1)) & 0x54;