From 43a2b0e76a56995f17e1b7628c192ebafe6051ee Mon Sep 17 00:00:00 2001
From: Stefan Roese <sr@denx.de>
Date: Fri, 20 Oct 2006 14:28:52 +0200
Subject: [PATCH] Add board/cpu specific NAND chip select function to 440 NDFC
 Based on idea and implementation from Jeff Mann Patch by Stefan Roese, 20 Oct
 2006

---
 CHANGELOG                 |  4 ++++
 common/cmd_nand.c         |  8 ++++++++
 cpu/ppc4xx/ndfc.c         | 39 ++++++++++++++++++++++++++-------------
 drivers/nand/nand.c       |  9 ++++++++-
 include/configs/sequoia.h | 15 ++++++++-------
 include/nand.h            |  4 ++++
 6 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 71096e875f..6ff1f9b37e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,10 @@ Changes since U-Boot 1.1.4:
 
 * Add (preliminary) support for V38B board
 
+* Add board/cpu specific NAND chip select function to 440 NDFC
+  Based on idea and implementation from Jeff Mann
+  Patch by Stefan Roese, 20 Oct 2006
+
 * PPC405EP: Add support for board configuration of CPC0_PCI register
   This is needed to be able to configure PerWE*/PCI_INT* pin as PerWE*
   Patch by Tolunay Orkun, 07 Apr 2006
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 7042a9c226..4fb3b65960 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -178,6 +178,14 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 		printf("Device %d: %s", dev, nand_info[dev].name);
 		puts("... is now current device\n");
 		nand_curr_device = dev;
+
+#ifdef CFG_NAND_SELECT_DEVICE
+		/*
+		 * Select the chip in the board/cpu specific driver
+		 */
+		board_nand_select_device(nand_info[dev].priv, dev);
+#endif
+
 		return 0;
 	}
 
diff --git a/cpu/ppc4xx/ndfc.c b/cpu/ppc4xx/ndfc.c
index 183ab5ef16..2c44111da6 100644
--- a/cpu/ppc4xx/ndfc.c
+++ b/cpu/ppc4xx/ndfc.c
@@ -66,7 +66,7 @@ static void ndfc_hwcontrol(struct mtd_info *mtdinfo, int cmd)
 static void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte)
 {
 	struct nand_chip *this = mtdinfo->priv;
-	ulong base = (ulong) this->IO_ADDR_W;
+	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
 
 	if (hwctl & 0x1)
 		out8(base + NDFC_CMD, byte);
@@ -79,7 +79,7 @@ static void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte)
 static u_char ndfc_read_byte(struct mtd_info *mtdinfo)
 {
 	struct nand_chip *this = mtdinfo->priv;
-	ulong base = (ulong) this->IO_ADDR_W;
+	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
 
 	return (in8(base + NDFC_DATA));
 }
@@ -87,7 +87,7 @@ static u_char ndfc_read_byte(struct mtd_info *mtdinfo)
 static int ndfc_dev_ready(struct mtd_info *mtdinfo)
 {
 	struct nand_chip *this = mtdinfo->priv;
-	ulong base = (ulong) this->IO_ADDR_W;
+	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
 
 	while (!(in32(base + NDFC_STAT) & NDFC_STAT_IS_READY))
 		;
@@ -111,30 +111,30 @@ static int ndfc_dev_ready(struct mtd_info *mtdinfo)
 static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
 {
 	struct nand_chip *this = mtdinfo->priv;
-	ulong base = (ulong) this->IO_ADDR_W;
+	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
 	uint32_t *p = (uint32_t *) buf;
 
-	for(;len > 0; len -= 4)
+	for (;len > 0; len -= 4)
 		*p++ = in32(base + NDFC_DATA);
 }
 
 static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
 {
 	struct nand_chip *this = mtdinfo->priv;
-	ulong base = (ulong) this->IO_ADDR_W;
+	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
 	uint32_t *p = (uint32_t *) buf;
 
-	for(; len > 0; len -= 4)
+	for (; len > 0; len -= 4)
 		out32(base + NDFC_DATA, *p++);
 }
 
 static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
 {
 	struct nand_chip *this = mtdinfo->priv;
-	ulong base = (ulong) this->IO_ADDR_W;
+	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;
 	uint32_t *p = (uint32_t *) buf;
 
-	for(; len > 0; len -= 4)
+	for (; len > 0; len -= 4)
 		if (*p++ != in32(base + NDFC_DATA))
 			return -1;
 
@@ -142,8 +142,20 @@ static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len
 }
 #endif /* #ifndef CONFIG_NAND_SPL */
 
+void board_nand_select_device(struct nand_chip *nand, int chip)
+{
+	ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
+
+	/* Set NandFlash Core Configuration Register */
+	/* 1col x 2 rows */
+	out32(base + NDFC_CCR, 0x00000000 | (chip << 24));
+}
+
 void board_nand_init(struct nand_chip *nand)
 {
+	int chip = (ulong)nand->IO_ADDR_W & 0x00000003;
+	ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
+
 	nand->eccmode = NAND_ECC_SOFT;
 
 	nand->hwcontrol  = ndfc_hwcontrol;
@@ -166,10 +178,11 @@ void board_nand_init(struct nand_chip *nand)
 	mtebc(pb0ap, CFG_EBC_PB0AP);
 #endif
 
-	/* Set NandFlash Core Configuration Register */
-	/* Chip select 3, 1col x 2 rows */
-	out32(CFG_NAND_BASE + NDFC_CCR, 0x00000000 | (CFG_NAND_CS << 24));
-	out32(CFG_NAND_BASE + NDFC_BCFG0 + (CFG_NAND_CS << 2), 0x80002222);
+	/*
+	 * Select required NAND chip in NDFC
+	 */
+	board_nand_select_device(nand, chip);
+	out32(base + NDFC_BCFG0 + (chip << 2), 0x80002222);
 }
 
 #endif
diff --git a/drivers/nand/nand.c b/drivers/nand/nand.c
index e1781fcbbf..3899045a72 100644
--- a/drivers/nand/nand.c
+++ b/drivers/nand/nand.c
@@ -66,8 +66,15 @@ void nand_init(void)
 		size += nand_info[i].size;
 		if (nand_curr_device == -1)
 			nand_curr_device = i;
-}
+	}
 	printf("%lu MiB\n", size / (1024 * 1024));
+
+#ifdef CFG_NAND_SELECT_DEVICE
+	/*
+	 * Select the chip in the board/cpu specific driver
+	 */
+	board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
+#endif
 }
 
 #endif
diff --git a/include/configs/sequoia.h b/include/configs/sequoia.h
index f67fd9163d..3a76315b44 100644
--- a/include/configs/sequoia.h
+++ b/include/configs/sequoia.h
@@ -134,13 +134,6 @@
 #define CFG_ENV_SIZE_REDUND	(CFG_ENV_SIZE)
 #endif
 
-/*-----------------------------------------------------------------------
- * NAND FLASH
- *----------------------------------------------------------------------*/
-#define CFG_MAX_NAND_DEVICE	1
-#define NAND_MAX_CHIPS		1
-#define CFG_NAND_BASE		CFG_NAND_ADDR
-
 /*
  * IPL (Initial Program Loader, integrated inside CPU)
  * Will load first 4k from NAND (SPL) into cache and execute it from there.
@@ -405,6 +398,14 @@
 #define CFG_EBC_PB2AP		0x24814580
 #define CFG_EBC_PB2CR		(CFG_CPLD | 0x38000)
 
+/*-----------------------------------------------------------------------
+ * NAND FLASH
+ *----------------------------------------------------------------------*/
+#define CFG_MAX_NAND_DEVICE	1
+#define NAND_MAX_CHIPS		1
+#define CFG_NAND_BASE		(CFG_NAND_ADDR + CFG_NAND_CS)
+#define CFG_NAND_SELECT_DEVICE  1	/* nand driver supports mutipl. chips	*/
+
 /*-----------------------------------------------------------------------
  * Cache Configuration
  *----------------------------------------------------------------------*/
diff --git a/include/nand.h b/include/nand.h
index 5c7311fd50..23493f7e98 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -117,4 +117,8 @@ int nand_lock( nand_info_t *meminfo, int tight );
 int nand_unlock( nand_info_t *meminfo, ulong start, ulong length );
 int nand_get_lock_status(nand_info_t *meminfo, ulong offset);
 
+#ifdef CFG_NAND_SELECT_DEVICE
+void board_nand_select_device(struct nand_chip *nand, int chip);
+#endif
+
 #endif
-- 
2.39.5