Patch by Yuli Barcohen, 09 Jun 2004:
Add support for 8MB flash SIMM and JFFS2 file system on
Motorola FADS board and its derivatives (MPC86xADS, MPC885ADS).
diff --git a/board/fads/flash.c b/board/fads/flash.c
index d2a46b2..f0fb621 100644
--- a/board/fads/flash.c
+++ b/board/fads/flash.c
@@ -24,7 +24,7 @@
 #include <common.h>
 #include <mpc8xx.h>
 
-flash_info_t flash_info[CFG_MAX_FLASH_BANKS];	/* info for FLASH chips        */
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];	/* info for FLASH chips */
 
 #if defined(CFG_ENV_IS_IN_FLASH)
 # ifndef  CFG_ENV_ADDR
@@ -38,124 +38,103 @@
 # endif
 #endif
 
+#define QUAD_ID(id)	((((ulong)(id) & 0xFF) << 24) | \
+			 (((ulong)(id) & 0xFF) << 16) | \
+			 (((ulong)(id) & 0xFF) << 8)  | \
+			 (((ulong)(id) & 0xFF) << 0)    \
+			)
+
 /*-----------------------------------------------------------------------
  * Functions
  */
 static ulong flash_get_size (vu_long * addr, flash_info_t * info);
 static int write_word (flash_info_t * info, ulong dest, ulong data);
-static void flash_get_offsets (ulong base, flash_info_t * info);
 
 /*-----------------------------------------------------------------------
  */
-
 unsigned long flash_init (void)
 {
 	volatile immap_t *immap = (immap_t *) CFG_IMMR;
 	volatile memctl8xx_t *memctl = &immap->im_memctl;
-	unsigned long total_size;
-	unsigned long size_b0, size_b1;
+	vu_long *bcsr = (vu_long *)BCSR_ADDR;
+	unsigned long pd_size, total_size, bsize, or_am;
 	int i;
 
 	/* Init: no FLASHes known */
 	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
 		flash_info[i].flash_id = FLASH_UNKNOWN;
+		flash_info[i].size = 0;
+		flash_info[i].sector_count = 0;
+		flash_info[i].start[0] = 0xFFFFFFFF; /* For TFTP */
 	}
 
-	total_size = 0;
-	size_b0 = 0xffffffff;
+	switch ((bcsr[2] & BCSR2_FLASH_PD_MASK) >> BCSR2_FLASH_PD_SHIFT) {
+	case 2:
+	case 4:
+	case 6:
+		pd_size = 0x800000;
+		or_am = 0xFF800000;
+		break;
 
-	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
-		size_b1 =
-			flash_get_size ((vu_long *) (CFG_FLASH_BASE +
-						     total_size),
-					&flash_info[i]);
+	case 5:
+	case 7:
+		pd_size = 0x400000;
+		or_am = 0xFFC00000;
+		break;
 
-		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
-			printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", i, size_b1, size_b1 >> 20);
-		}
+	case 8:
+		pd_size = 0x200000;
+		or_am = 0xFFE00000;
+		break;
 
-		/* Is this really needed ? - LP */
-		if (size_b1 > size_b0) {
-			printf ("## ERROR: Bank %d (0x%08lx = %ld MB) > Bank %d (0x%08lx = %ld MB)\n", i, size_b1, size_b1 >> 20, i - 1, size_b0, size_b0 >> 20);
-			goto out_error;
-		}
-		size_b0 = size_b1;
-		total_size += size_b1;
+	default:
+		pd_size = 0;
+		or_am = 0xFFE00000;
+		printf("## Unsupported flash detected by BCSR: 0x%08X\n", bcsr[2]);
 	}
 
-	/* Compute the Address Mask */
-	for (i = 0; (total_size >> i) != 0; ++i) {
+	total_size = 0;
+	for (i = 0; i < CFG_MAX_FLASH_BANKS && total_size < pd_size; ++i) {
+		bsize = flash_get_size((vu_long *)(CFG_FLASH_BASE + total_size),
+				       &flash_info[i]);
+
+		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
+			printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
+				i, bsize, bsize >> 20);
+		}
+
+		total_size += bsize;
 	}
-	i--;
 
-	if (total_size != (1 << i)) {
-		printf ("## WARNING: Total FLASH size (0x%08lx = %ld MB) is not a power of 2\n", total_size, total_size >> 20);
+	if (total_size != pd_size) {
+		printf("## Detected flash size %lu conflicts with PD data %lu\n",
+		       total_size, pd_size);
 	}
 
 	/* Remap FLASH according to real size */
-	memctl->memc_or0 =
-		((((unsigned long) ~0) << i) & OR_AM_MSK) |
-		CFG_OR_TIMING_FLASH;
-	memctl->memc_br0 = CFG_BR0_PRELIM;
-
-	total_size = 0;
+	memctl->memc_or0 = or_am | CFG_OR_TIMING_FLASH;
 
 	for (i = 0; i < CFG_MAX_FLASH_BANKS && flash_info[i].size != 0; ++i) {
-		/* Re-do sizing to get full correct info */
-		/* Why ? - LP */
-		size_b1 =
-			flash_get_size ((vu_long *) (CFG_FLASH_BASE +
-						     total_size),
-					&flash_info[i]);
-
-		/* This is done by flash_get_size - LP */
-		/* flash_get_offsets (CFG_FLASH_BASE + total_size, &flash_info[i]); */
-
 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
 		/* monitor protection ON by default */
-		flash_protect (FLAG_PROTECT_SET,
-			       CFG_MONITOR_BASE,
-			       CFG_MONITOR_BASE + monitor_flash_len - 1,
-			       &flash_info[i]);
+		if (CFG_MONITOR_BASE >= flash_info[i].start[0])
+			flash_protect (FLAG_PROTECT_SET,
+				       CFG_MONITOR_BASE,
+				       CFG_MONITOR_BASE + monitor_flash_len - 1,
+				       &flash_info[i]);
 #endif
 
 #ifdef	CFG_ENV_IS_IN_FLASH
 		/* ENV protection ON by default */
-		flash_protect (FLAG_PROTECT_SET,
-			       CFG_ENV_ADDR,
-			       CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
-			       &flash_info[i]);
+		if (CFG_ENV_ADDR >= flash_info[i].start[0])
+			flash_protect (FLAG_PROTECT_SET,
+				       CFG_ENV_ADDR,
+				       CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+				       &flash_info[i]);
 #endif
-
-		total_size += size_b1;
 	}
 
-	return (total_size);
-
-      out_error:
-	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
-		flash_info[i].flash_id = FLASH_UNKNOWN;
-		flash_info[i].sector_count = -1;
-		flash_info[i].size = 0;
-	}
-
-	return (0);
-}
-
-/*-----------------------------------------------------------------------
- */
-static void flash_get_offsets (ulong base, flash_info_t * info)
-{
-	int i;
-
-	/* set up sector start address table */
-	if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040
-	    || (info->flash_id & FLASH_TYPEMASK) == FLASH_AM080) {
-		/* set sector offsets for uniform sector type   */
-		for (i = 0; i < info->sector_count; i++) {
-			info->start[i] = base + (i * 0x00040000);
-		}
-	}
+	return total_size;
 }
 
 /*-----------------------------------------------------------------------
@@ -235,48 +214,26 @@
 	}
 
 	printf ("\n");
-	return;
 }
 
 /*-----------------------------------------------------------------------
- */
-
-
-/*-----------------------------------------------------------------------
- */
-
-/*
- * The following code cannot be run from FLASH!
+ * The following code can not run from flash!
  */
-
 static ulong flash_get_size (vu_long * addr, flash_info_t * info)
 {
 	short i;
 
-#if 0
-	ulong base = (ulong) addr;
-#endif
-	uchar value;
-
 	/* Write auto select command: read Manufacturer ID */
-#if 0
-	addr[0x0555] = 0x00AA00AA;
-	addr[0x02AA] = 0x00550055;
-	addr[0x0555] = 0x00900090;
-#else
 	addr[0x0555] = 0xAAAAAAAA;
 	addr[0x02AA] = 0x55555555;
 	addr[0x0555] = 0x90909090;
-#endif
-
-	value = addr[0];
 
-	switch (value + (value << 16)) {
-	case AMD_MANUFACT:
+	switch (addr[0]) {
+	case QUAD_ID(AMD_MANUFACT):
 		info->flash_id = FLASH_MAN_AMD;
 		break;
 
-	case FUJ_MANUFACT:
+	case QUAD_ID(FUJ_MANUFACT):
 		info->flash_id = FLASH_MAN_FUJ;
 		break;
 
@@ -287,21 +244,20 @@
 		break;
 	}
 
-	value = addr[1];	/* device ID            */
-
-	switch (value) {
-	case AMD_ID_F040B:
+	switch (addr[1]) {	/* device ID            */
+	case QUAD_ID(AMD_ID_F040B):
+	case QUAD_ID(AMD_ID_LV040B):
 		info->flash_id += FLASH_AM040;
 		info->sector_count = 8;
 		info->size = 0x00200000;
 		break;		/* => 2 MB              */
 
-	case AMD_ID_F080B:
+	case QUAD_ID(AMD_ID_F080B):
 		info->flash_id += FLASH_AM080;
 		info->sector_count = 16;
 		info->size = 0x00400000;
 		break;		/* => 4 MB              */
-
+#if 0
 	case AMD_ID_LV400T:
 		info->flash_id += FLASH_AM400T;
 		info->sector_count = 11;
@@ -337,7 +293,7 @@
 		info->sector_count = 35;
 		info->size = 0x00400000;
 		break;		/* => 4 MB              */
-#if 0				/* enable when device IDs are available */
+
 	case AMD_ID_LV320T:
 		info->flash_id += FLASH_AM320T;
 		info->sector_count = 67;
@@ -349,11 +305,10 @@
 		info->sector_count = 67;
 		info->size = 0x00800000;
 		break;		/* => 8 MB              */
-#endif
+#endif /* 0 */
 	default:
 		info->flash_id = FLASH_UNKNOWN;
 		return (0);	/* => no or unknown flash */
-
 	}
 
 #if 0
@@ -378,7 +333,9 @@
 		}
 	}
 #else
-	flash_get_offsets ((ulong) addr, info);
+	/* set sector offsets for uniform sector type */
+	for (i = 0; i < info->sector_count; i++)
+		info->start[i] = (ulong)addr + (i * 0x00040000);
 #endif
 
 	/* check for protected sectors */
@@ -389,25 +346,16 @@
 		info->protect[i] = addr[2] & 1;
 	}
 
-	/*
-	 * Prevent writes to uninitialized FLASH.
-	 */
 	if (info->flash_id != FLASH_UNKNOWN) {
 		addr = (volatile unsigned long *) info->start[0];
-#if 0
-		*addr = 0x00F000F0;	/* reset bank */
-#else
 		*addr = 0xF0F0F0F0;	/* reset bank */
-#endif
 	}
 
 	return (info->size);
 }
 
-
 /*-----------------------------------------------------------------------
  */
-
 int flash_erase (flash_info_t * info, int s_first, int s_last)
 {
 	vu_long *addr = (vu_long *) (info->start[0]);
@@ -420,13 +368,13 @@
 		} else {
 			printf ("- no sectors to erase\n");
 		}
-		return 1;
+		return ERR_INVAL;
 	}
 
 	if ((info->flash_id == FLASH_UNKNOWN) ||
 	    (info->flash_id > FLASH_AMD_COMP)) {
 		printf ("Can't erase unknown flash type - aborted\n");
-		return 1;
+		return ERR_UNKNOWN_FLASH_TYPE;
 	}
 
 	prot = 0;
@@ -447,29 +395,17 @@
 	/* Disable interrupts which might cause a timeout here */
 	flag = disable_interrupts ();
 
-#if 0
-	addr[0x0555] = 0x00AA00AA;
-	addr[0x02AA] = 0x00550055;
-	addr[0x0555] = 0x00800080;
-	addr[0x0555] = 0x00AA00AA;
-	addr[0x02AA] = 0x00550055;
-#else
 	addr[0x0555] = 0xAAAAAAAA;
 	addr[0x02AA] = 0x55555555;
 	addr[0x0555] = 0x80808080;
 	addr[0x0555] = 0xAAAAAAAA;
 	addr[0x02AA] = 0x55555555;
-#endif
 
 	/* Start erase on unprotected sectors */
 	for (sect = s_first; sect <= s_last; sect++) {
 		if (info->protect[sect] == 0) {	/* not protected */
 			addr = (vu_long *) (info->start[sect]);
-#if 0
-			addr[0] = 0x00300030;
-#else
 			addr[0] = 0x30303030;
-#endif
 			l_sect = sect;
 		}
 	}
@@ -490,15 +426,11 @@
 	start = get_timer (0);
 	last = start;
 	addr = (vu_long *) (info->start[l_sect]);
-#if 0
-	while ((addr[0] & 0x00800080) != 0x00800080)
-#else
 	while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
-#endif
 	{
 		if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
 			printf ("Timeout\n");
-			return 1;
+			return ERR_TIMOUT;
 		}
 		/* show that we're waiting */
 		if ((now - last) > 1000) {	/* every second */
@@ -510,13 +442,10 @@
       DONE:
 	/* reset to read mode */
 	addr = (volatile unsigned long *) info->start[0];
-#if 0
-	addr[0] = 0x00F000F0;	/* reset bank */
-#else
 	addr[0] = 0xF0F0F0F0;	/* reset bank */
-#endif
 
 	printf (" done\n");
+
 	return 0;
 }
 
@@ -526,7 +455,6 @@
  * 1 - write timeout
  * 2 - Flash not erased
  */
-
 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 {
 	ulong cp, wp, data;
@@ -605,20 +533,14 @@
 
 	/* Check if Flash is (sufficiently) erased */
 	if ((*((vu_long *) dest) & data) != data) {
-		return (2);
+		return ERR_NOT_ERASED;
 	}
 	/* Disable interrupts which might cause a timeout here */
 	flag = disable_interrupts ();
 
-#if 0
-	addr[0x0555] = 0x00AA00AA;
-	addr[0x02AA] = 0x00550055;
-	addr[0x0555] = 0x00A000A0;
-#else
 	addr[0x0555] = 0xAAAAAAAA;
 	addr[0x02AA] = 0x55555555;
 	addr[0x0555] = 0xA0A0A0A0;
-#endif
 
 	*((vu_long *) dest) = data;
 
@@ -628,18 +550,11 @@
 
 	/* data polling for D7 */
 	start = get_timer (0);
-#if 0
-	while ((*((vu_long *) dest) & 0x00800080) != (data & 0x00800080))
-#else
 	while ((*((vu_long *) dest) & 0x80808080) != (data & 0x80808080))
-#endif
 	{
 		if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
-			return (1);
+			return ERR_TIMOUT;
 		}
 	}
 	return (0);
 }
-
-/*-----------------------------------------------------------------------
- */