* Patch by Nicolas Lacressonniere, 11 Jun 2003:
  Modifications for Atmel AT91RM9200DK ARM920T based development kit
  - Add Atmel DataFlash support for reading and writing.
  - Add possibility to boot a Linux from DataFlash with BOOTM command.
  - Add Flash detection on Atmel AT91RM9200DK
    (between Atmel AT49BV1614 and AT49BV1614A flashes)
  - Replace old Ethernet PHY layer functions
  - Change link address

* Patch by Frank Smith, 9 Jun 2003:
  use CRIT_EXCEPTION for machine check on 4xx

* Patch by Detlev Zundel, 13 Jun 2003:
  added implementation of the "carinfo" command in cmd_immap.c
diff --git a/board/at91rm9200dk/flash.c b/board/at91rm9200dk/flash.c
index 6497f11..4d4524f 100644
--- a/board/at91rm9200dk/flash.c
+++ b/board/at91rm9200dk/flash.c
@@ -31,11 +31,40 @@
 ulong myflush(void);
 
 
+/* Flash Organization Structure */
+typedef struct OrgDef
+{
+	unsigned int sector_number;
+	unsigned int sector_size;
+} OrgDef;
+
+
+/* Flash Organizations */
+OrgDef OrgAT49BV16x4[] =
+{
+	{ 8, 8*1024 }, /* 8 * 8kBytes sectors */
+	{ 2, 32*1024 }, /* 2 * 32kBytes sectors */	
+	{ 30, 64*1024 } /* 30 * 64kBytes sectors */	
+};
+
+OrgDef OrgAT49BV16x4A[] =
+{
+	{ 8, 8*1024 }, /* 8 * 8kBytes sectors */	
+	{ 31, 64*1024 } /* 31 * 64kBytes sectors */	
+};
+
+
 #define FLASH_BANK_SIZE 0x200000	/* 2 MB */
 #define MAIN_SECT_SIZE  0x10000		/* 64 KB */
 
 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
 
+/* AT49BV1614A Codes */
+#define FLASH_CODE1		0xAA
+#define FLASH_CODE2		0x55
+#define ID_IN_CODE		0x90
+#define ID_OUT_CODE		0xF0
+
 
 #define CMD_READ_ARRAY		0x00F0
 #define CMD_UNLOCK1		0x00AA
@@ -48,6 +77,9 @@
 #define MEM_FLASH_ADDR1		(*(volatile u16 *)(CFG_FLASH_BASE + (0x00005555<<1)))
 #define MEM_FLASH_ADDR2		(*(volatile u16 *)(CFG_FLASH_BASE + (0x00002AAA<<1)))
 
+#define IDENT_FLASH_ADDR1	(*(volatile u16 *)(CFG_FLASH_BASE + (0x0000555<<1)))
+#define IDENT_FLASH_ADDR2	(*(volatile u16 *)(CFG_FLASH_BASE + (0x0000AAA<<1)))
+
 #define BIT_ERASE_DONE		0x0080
 #define BIT_RDY_MASK		0x0080
 #define BIT_PROGRAM_ERROR	0x0020
@@ -59,339 +91,375 @@
 
 /*-----------------------------------------------------------------------
  */
-
-ulong flash_init(void)
+void flash_identification (flash_info_t * info)
 {
-    int i, j;
-    ulong size = 0;
+	volatile u16 manuf_code, device_code, add_device_code;
 
-    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
-    {
-	ulong flashbase = 0;
-	flash_info[i].flash_id =
-	  (ATM_MANUFACT & FLASH_VENDMASK) |
-	  (ATM_ID_BV1614 & FLASH_TYPEMASK);
-	flash_info[i].size = FLASH_BANK_SIZE;
-	flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
-	memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
-	if (i == 0)
-	  flashbase = PHYS_FLASH_1;
-	else
-	  panic("configured to many flash banks!\n");
-	for (j = 0; j < flash_info[i].sector_count; j++)
-	{
+	IDENT_FLASH_ADDR1 = FLASH_CODE1;
+	IDENT_FLASH_ADDR2 = FLASH_CODE2;
+	IDENT_FLASH_ADDR1 = ID_IN_CODE;
 
-	    if (j <= 9)
-	    {
-		/* 1st to 8th are 8 KB */
-		if (j <= 7)
-		{
-		    flash_info[i].start[j] = flashbase + j*0x2000;
+	manuf_code = *(volatile u16 *) CFG_FLASH_BASE;
+	device_code = *(volatile u16 *) (CFG_FLASH_BASE + 2);
+	add_device_code = *(volatile u16 *) (CFG_FLASH_BASE + (3 << 1));
+
+	IDENT_FLASH_ADDR1 = FLASH_CODE1;
+	IDENT_FLASH_ADDR2 = FLASH_CODE2;
+	IDENT_FLASH_ADDR1 = ID_OUT_CODE;
+
+	/* Vendor type */
+	info->flash_id = ATM_MANUFACT & FLASH_VENDMASK;
+	printf ("Atmel: ");
+
+	if ((device_code & FLASH_TYPEMASK) == (ATM_ID_BV1614 & FLASH_TYPEMASK)) {
+
+		if ((add_device_code & FLASH_TYPEMASK) ==
+			(ATM_ID_BV1614A & FLASH_TYPEMASK)) {
+			info->flash_id |= ATM_ID_BV1614A & FLASH_TYPEMASK;
+			printf ("AT49BV1614A (16Mbit)\n");
 		}
 
-		/* 9th and 10th are both 32 KB */
-		if ((j == 8) || (j == 9))
-		{
-			flash_info[i].start[j] = flashbase + 0x10000 + (j-8)*0x8000;
-		}
-	    }
-	    else
-	    {
-		flash_info[i].start[j] = flashbase + (j-8)*MAIN_SECT_SIZE;
-	    }
+	} else {				/* AT49BV1614 Flash */
+		info->flash_id |= ATM_ID_BV1614 & FLASH_TYPEMASK;
+		printf ("AT49BV1614 (16Mbit)\n");
 	}
-	size += flash_info[i].size;
-    }
+}
 
-    flash_protect(FLAG_PROTECT_SET,
-		  CFG_FLASH_BASE,
-		  CFG_ENV_ADDR - 1,
-		  &flash_info[0]);
 
-    flash_protect(FLAG_PROTECT_SET,
-		  CFG_ENV_ADDR,
-		  CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
-		  &flash_info[0]);
+ulong flash_init (void)
+{
+	int i, j, k;
+	unsigned int flash_nb_blocks, sector;
+	unsigned int start_address;
+	OrgDef *pOrgDef;
 
-    return size;
+	ulong size = 0;
+
+	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+		ulong flashbase = 0;
+
+		flash_identification (&flash_info[i]);
+
+		flash_info[i].size = FLASH_BANK_SIZE;
+
+		if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
+			(ATM_ID_BV1614 & FLASH_TYPEMASK)) {
+			flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
+			memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
+
+			pOrgDef = OrgAT49BV16x4;
+			flash_nb_blocks = sizeof (OrgAT49BV16x4) / sizeof (OrgDef);
+		} else {			/* AT49BV1614A Flash */
+			flash_info[i].sector_count = CFG_MAX_FLASH_SECT - 1;
+			memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT - 1);
+
+			pOrgDef = OrgAT49BV16x4A;
+			flash_nb_blocks = sizeof (OrgAT49BV16x4A) / sizeof (OrgDef);
+		}
+
+		if (i == 0)
+			flashbase = PHYS_FLASH_1;
+		else
+			panic ("configured to many flash banks!\n");
+
+		sector = 0;
+		start_address = flashbase;
+
+		for (j = 0; j < flash_nb_blocks; j++) {
+			for (k = 0; k < pOrgDef[j].sector_number; k++) {
+				flash_info[i].start[sector++] = start_address;
+				start_address += pOrgDef[j].sector_size;
+			}
+		}
+
+		size += flash_info[i].size;
+	}
+
+	/* Protect binary boot image */
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_FLASH_BASE,
+		       CFG_FLASH_BASE + CFG_BOOT_SIZE - 1, &flash_info[0]);
+
+	/* Protect environment variables */
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_ENV_ADDR,
+		       CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
+
+	/* Protect U-Boot gzipped image */
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_U_BOOT_BASE,
+		       CFG_U_BOOT_BASE + CFG_U_BOOT_SIZE - 1, &flash_info[0]);
+
+	return size;
 }
 
 /*-----------------------------------------------------------------------
  */
-void flash_print_info  (flash_info_t *info)
+void flash_print_info (flash_info_t * info)
 {
-    int i;
+	int i;
 
-    switch (info->flash_id & FLASH_VENDMASK)
-    {
-    case (ATM_MANUFACT & FLASH_VENDMASK):
-	printf("Atmel: ");
-	break;
-    default:
-	printf("Unknown Vendor ");
-	break;
-    }
-
-    switch (info->flash_id & FLASH_TYPEMASK)
-    {
-    case (ATM_ID_BV1614 & FLASH_TYPEMASK):
-	printf("AT49BV1614 (16Mbit)\n");
-	break;
-    default:
-	printf("Unknown Chip Type\n");
-	goto Done;
-	break;
-    }
-
-    printf("  Size: %ld MB in %d Sectors\n",
-	   info->size >> 20, info->sector_count);
-
-    printf("  Sector Start Addresses:");
-    for (i = 0; i < info->sector_count; i++)
-    {
-	if ((i % 5) == 0)
-	{
-	    printf ("\n   ");
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case (ATM_MANUFACT & FLASH_VENDMASK):
+		printf ("Atmel: ");
+		break;
+	default:
+		printf ("Unknown Vendor ");
+		break;
 	}
-	printf (" %08lX%s", info->start[i],
-		info->protect[i] ? " (RO)" : "     ");
-    }
-    printf ("\n");
 
-Done:
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case (ATM_ID_BV1614 & FLASH_TYPEMASK):
+		printf ("AT49BV1614 (16Mbit)\n");
+		break;
+	case (ATM_ID_BV1614A & FLASH_TYPEMASK):
+		printf ("AT49BV1614A (16Mbit)\n");
+		break;
+	default:
+		printf ("Unknown Chip Type\n");
+		goto Done;
+		break;
+	}
+
+	printf ("  Size: %ld MB in %d Sectors\n",
+		info->size >> 20, info->sector_count);
+
+	printf ("  Sector Start Addresses:");
+	for (i = 0; i < info->sector_count; i++) {
+		if ((i % 5) == 0) {
+			printf ("\n   ");
+		}
+		printf (" %08lX%s", info->start[i],
+			info->protect[i] ? " (RO)" : "     ");
+	}
+	printf ("\n");
+
+  Done:
 }
 
 /*-----------------------------------------------------------------------
  */
 
-int	flash_erase (flash_info_t *info, int s_first, int s_last)
+int flash_erase (flash_info_t * info, int s_first, int s_last)
 {
-    ulong result;
-    int iflag, cflag, prot, sect;
-    int rc = ERR_OK;
-    int chip1;
+	ulong result;
+	int iflag, cflag, prot, sect;
+	int rc = ERR_OK;
+	int chip1;
 
-    /* first look for protection bits */
+	/* first look for protection bits */
 
-    if (info->flash_id == FLASH_UNKNOWN)
-	return ERR_UNKNOWN_FLASH_TYPE;
+	if (info->flash_id == FLASH_UNKNOWN)
+		return ERR_UNKNOWN_FLASH_TYPE;
 
-    if ((s_first < 0) || (s_first > s_last)) {
-	return ERR_INVAL;
-    }
-
-    if ((info->flash_id & FLASH_VENDMASK) !=
-	(ATM_MANUFACT & FLASH_VENDMASK)) {
-	return ERR_UNKNOWN_FLASH_VENDOR;
-    }
-
-    prot = 0;
-    for (sect=s_first; sect<=s_last; ++sect) {
-	if (info->protect[sect]) {
-	    prot++;
+	if ((s_first < 0) || (s_first > s_last)) {
+		return ERR_INVAL;
 	}
-    }
-    if (prot)
-	return ERR_PROTECTED;
 
-    /*
-     * Disable interrupts which might cause a timeout
-     * here. Remember that our exception vectors are
-     * at address 0 in the flash, and we don't want a
-     * (ticker) exception to happen while the flash
-     * chip is in programming mode.
-     */
-    cflag = icache_status();
-    icache_disable();
-    iflag = disable_interrupts();
+	if ((info->flash_id & FLASH_VENDMASK) !=
+		(ATM_MANUFACT & FLASH_VENDMASK)) {
+		return ERR_UNKNOWN_FLASH_VENDOR;
+	}
 
-    /* Start erase on unprotected sectors */
-    for (sect = s_first; sect<=s_last && !ctrlc(); sect++)
-    {
-	printf("Erasing sector %2d ... ", sect);
-
-	/* arm simple, non interrupt dependent timer */
-	reset_timer_masked();
-
-	if (info->protect[sect] == 0)
-	{	/* not protected */
-	    volatile u16 *addr = (volatile u16 *)(info->start[sect]);
-
-	    MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-	    MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-	    MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
-
-	    MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-	    MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-	    *addr = CMD_ERASE_CONFIRM;
-
-	    /* wait until flash is ready */
-	    chip1 = 0;
-
-	    do
-	    {
-		result = *addr;
-
-		/* check timeout */
-		if (get_timer_masked() > CFG_FLASH_ERASE_TOUT)
-		{
-		    MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
-		    chip1 = TMO;
-		    break;
+	prot = 0;
+	for (sect = s_first; sect <= s_last; ++sect) {
+		if (info->protect[sect]) {
+			prot++;
 		}
-
-		if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
-			chip1 = READY;
-
-	    }  while (!chip1);
-
-	    MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
-
-	    if (chip1 == ERR)
-	    {
-		rc = ERR_PROG_ERROR;
-		goto outahere;
-	    }
-	    if (chip1 == TMO)
-	    {
-		rc = ERR_TIMOUT;
-		goto outahere;
-	    }
-
-	    printf("ok.\n");
 	}
-	else /* it was protected */
-	{
-	    printf("protected!\n");
-	}
-    }
+	if (prot)
+		return ERR_PROTECTED;
 
-    if (ctrlc())
-      printf("User Interrupt!\n");
+	/*
+	 * Disable interrupts which might cause a timeout
+	 * here. Remember that our exception vectors are
+	 * at address 0 in the flash, and we don't want a
+	 * (ticker) exception to happen while the flash
+	 * chip is in programming mode.
+	 */
+	cflag = icache_status ();
+	icache_disable ();
+	iflag = disable_interrupts ();
+
+	/* Start erase on unprotected sectors */
+	for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
+		printf ("Erasing sector %2d ... ", sect);
+
+		/* arm simple, non interrupt dependent timer */
+		reset_timer_masked ();
+
+		if (info->protect[sect] == 0) {	/* not protected */
+			volatile u16 *addr = (volatile u16 *) (info->start[sect]);
+
+			MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+			MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+			MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
+
+			MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+			MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+			*addr = CMD_ERASE_CONFIRM;
+
+			/* wait until flash is ready */
+			chip1 = 0;
+
+			do {
+				result = *addr;
+
+				/* check timeout */
+				if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
+					MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
+					chip1 = TMO;
+					break;
+				}
+
+				if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
+					chip1 = READY;
+
+			} while (!chip1);
+
+			MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
+
+			if (chip1 == ERR) {
+				rc = ERR_PROG_ERROR;
+				goto outahere;
+			}
+			if (chip1 == TMO) {
+				rc = ERR_TIMOUT;
+				goto outahere;
+			}
+
+			printf ("ok.\n");
+		} else {			/* it was protected */
+			printf ("protected!\n");
+		}
+	}
+
+	if (ctrlc ())
+		printf ("User Interrupt!\n");
 
 outahere:
-    /* allow flash to settle - wait 10 ms */
-    udelay_masked(10000);
+	/* allow flash to settle - wait 10 ms */
+	udelay_masked (10000);
 
-    if (iflag)
-      enable_interrupts();
+	if (iflag)
+		enable_interrupts ();
 
-    if (cflag)
-      icache_enable();
+	if (cflag)
+		icache_enable ();
 
-    return rc;
+	return rc;
 }
 
 /*-----------------------------------------------------------------------
  * Copy memory to flash
  */
 
-volatile static int write_word (flash_info_t *info, ulong dest, ulong data)
+volatile static int write_word (flash_info_t * info, ulong dest,
+								ulong data)
 {
-    volatile u16 *addr = (volatile u16 *)dest;
-    ulong result;
-    int rc = ERR_OK;
-    int cflag, iflag;
-    int chip1;
+	volatile u16 *addr = (volatile u16 *) dest;
+	ulong result;
+	int rc = ERR_OK;
+	int cflag, iflag;
+	int chip1;
 
-    /*
-     * Check if Flash is (sufficiently) erased
-     */
-    result = *addr;
-    if ((result & data) != data)
-        return ERR_NOT_ERASED;
-
-
-    /*
-     * Disable interrupts which might cause a timeout
-     * here. Remember that our exception vectors are
-     * at address 0 in the flash, and we don't want a
-     * (ticker) exception to happen while the flash
-     * chip is in programming mode.
-     */
-    cflag = icache_status();
-    icache_disable();
-    iflag = disable_interrupts();
-
-    MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-    MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-    MEM_FLASH_ADDR1 = CMD_PROGRAM;
-    *addr = data;
-
-    /* arm simple, non interrupt dependent timer */
-    reset_timer_masked();
-
-    /* wait until flash is ready */
-    chip1 = 0;
-    do
-    {
+	/*
+	 * Check if Flash is (sufficiently) erased
+	 */
 	result = *addr;
+	if ((result & data) != data)
+		return ERR_NOT_ERASED;
 
-	/* check timeout */
-	if (get_timer_masked() > CFG_FLASH_ERASE_TOUT)
-	{
-	    chip1 = ERR | TMO;
-	    break;
-	}
-	if (!chip1 && ((result & 0x80) == (data & 0x80)))
-		chip1 = READY;
 
-    }  while (!chip1);
+	/*
+	 * Disable interrupts which might cause a timeout
+	 * here. Remember that our exception vectors are
+	 * at address 0 in the flash, and we don't want a
+	 * (ticker) exception to happen while the flash
+	 * chip is in programming mode.
+	 */
+	cflag = icache_status ();
+	icache_disable ();
+	iflag = disable_interrupts ();
 
-    *addr = CMD_READ_ARRAY;
+	MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+	MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+	MEM_FLASH_ADDR1 = CMD_PROGRAM;
+	*addr = data;
 
-    if (chip1 == ERR || *addr != data)
-        rc = ERR_PROG_ERROR;
+	/* arm simple, non interrupt dependent timer */
+	reset_timer_masked ();
 
-    if (iflag)
-      enable_interrupts();
+	/* wait until flash is ready */
+	chip1 = 0;
+	do {
+		result = *addr;
 
-    if (cflag)
-      icache_enable();
+		/* check timeout */
+		if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
+			chip1 = ERR | TMO;
+			break;
+		}
+		if (!chip1 && ((result & 0x80) == (data & 0x80)))
+			chip1 = READY;
 
-    return rc;
+	} while (!chip1);
+
+	*addr = CMD_READ_ARRAY;
+
+	if (chip1 == ERR || *addr != data)
+		rc = ERR_PROG_ERROR;
+
+	if (iflag)
+		enable_interrupts ();
+
+	if (cflag)
+		icache_enable ();
+
+	return rc;
 }
 
 /*-----------------------------------------------------------------------
  * Copy memory to flash.
  */
 
-int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 {
-    ulong wp, data;
-    int rc;
+	ulong wp, data;
+	int rc;
 
-    if(addr & 1) {
-      printf("unaligned destination not supported\n");
-      return ERR_ALIGN;
-    };
+	if (addr & 1) {
+		printf ("unaligned destination not supported\n");
+		return ERR_ALIGN;
+	};
 
-    if((int)src & 1) {
-      printf("unaligned source not supported\n");
-      return ERR_ALIGN;
-    };
+	if ((int) src & 1) {
+		printf ("unaligned source not supported\n");
+		return ERR_ALIGN;
+	};
 
-    wp = addr;
+	wp = addr;
 
-    while (cnt >= 2) {
-	data = *((volatile u16*)src);
-	if ((rc = write_word(info, wp, data)) != 0) {
-	    return (rc);
+	while (cnt >= 2) {
+		data = *((volatile u16 *) src);
+		if ((rc = write_word (info, wp, data)) != 0) {
+			return (rc);
+		}
+		src += 2;
+		wp += 2;
+		cnt -= 2;
 	}
-	src += 2;
-	wp  += 2;
-	cnt -= 2;
-    }
 
-    if(cnt == 1) {
-      data =  (*((volatile u8*)src)) | (*((volatile u8*)(wp+1)) << 8);
-	if ((rc = write_word(info, wp, data)) != 0) {
-	    return (rc);
-	}
-	src += 1;
-	wp  += 1;
-	cnt -= 1;
-    };
+	if (cnt == 1) {
+		data = (*((volatile u8 *) src)) | (*((volatile u8 *) (wp + 1)) <<
+										   8);
+		if ((rc = write_word (info, wp, data)) != 0) {
+			return (rc);
+		}
+		src += 1;
+		wp += 1;
+		cnt -= 1;
+	};
 
-    return ERR_OK;
+	return ERR_OK;
 }