[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

etrax100boot - cleanup + support for Amtel Flash (AT49BV1614T)



Hi,

We had a hard time to get a AT49BV1614T flash to work in the current
etrax100boot.

Why?

because:
a) Device id clash with incompatible device :-(
=> use both manufacturer and device id to determine specific information
[use the AT49BV1614AT if you have to choose!
 Note the A - it is not only speed...]
(note: FID macro might need to change to uniquely "hash" this values)
b) it does not like 2AA and 555 as unlock addresses (it requires 2AAA and 
5555)
=> I changed this to AAAA and 5555 since unused highbits are ignored
c) it is not CFI compatible, and has strange layout (30 + 2 + 8)
=> Removed the special boot_sector handling, all is now sector_count & 
sector_size
d) while erasing you have to repeat the full command over and over...
=> implemented
e) checking that erase for a sector is ready must be made on the same plane 
(~= address) as you erased
=> implemented

unrelated bug(?):
In CFI code ADDResses are shifted with offset_shift, but the Enter CFI mode 
does not... bug or not? I do not know - If I only had a CFI device...

 	/* Enter CFI mode */
-	wide_cmd(flash, CMD_CFI_QUERY_DATA, ADDR_CFI_QUERY);
+	wide_cmd(flash, CMD_CFI_QUERY_DATA, ADDR_CFI_QUERY << offset_shift);

cleanup:
f) fixed some Warnings too...

Result:
- We can erase and flash our device => it boots! :-)
- Probably this saves some bytes too :-)
  Previously we allocated 8*sizeof(int) for the table + some other variables,
  now I allocate 4*(1 + sizeof(int))
- Erasing other (modern) devices will probably slow down since it can not
  erase several sectors at once, but this can be handled too (in just a few
  lines of code)

I include a not working (write fails) version for patch of Linux kernels 
amd_flash.c too..

Enjoy!

/RogerL

-- 
Roger Larsson
Optronic dp AB
Skellefteċ
Sweden
--- flash.c.orig	Fri Dec 14 10:46:23 2001
+++ flash.c	Fri Dec 14 14:08:44 2001
@@ -122,8 +122,8 @@
 
 enum {
 	/* Addresses */
-	ADDR_UNLOCK_1			= 0x0555,
-	ADDR_UNLOCK_2			= 0x02AA,
+	ADDR_UNLOCK_1			= 0x5555, /* AT49BV1614T requires 0555 ! */
+	ADDR_UNLOCK_2			= 0xAAAA, /* AT49BV1614T requires 2AAA ! */
 	ADDR_MANUFACTURER		= 0x0000,
 	ADDR_DEVICE_ID			= 0x0001,
 	ADDR_CFI_QUERY			= 0x0055,
@@ -150,6 +150,7 @@
 	MANUFACTURER_SST		= 0xBF,
 	MANUFACTURER_ST			= 0x20,
 	MANUFACTURER_TOSHIBA		= 0x98,
+	MANUFACTURER_ATMEL		= 0x1F,
 
 	/* AMD devices */
 	AM29F800BB			= 0x2258,
@@ -176,23 +177,26 @@
 	TC58FVB160			= 0x0043,
 	TC58FVT800			= 0x004F,
 
+	/* ATMEL devices */
+	AT49BV1614T			= 0x00C2,  /* Note: same id as AM29LV160BT, but not identical */
+
 	/* Toggle bit mask */
 	D6_MASK				= 0x40
 };
 
-
+/* make a unique id from flash manufacturer and device id */
+#define FID(m,d) (m+d)
 
 typedef struct flash_type {
 	volatile unsigned char *base;
 	udword type;
 	byte interleave;
 	byte buswidth;
-	volatile unsigned char *boot_sector;
 	udword mfr;
 	udword dev_id;
 	unsigned int size;
-	unsigned int sector_size;
-	unsigned int boot_sector_size[8];
+        unsigned char sector_count[4];
+	unsigned int sector_size[4];
 } flash_t;
 
 
@@ -295,7 +299,16 @@
 		(wide_read(flash, offset) & D6_MASK));
 }
 
+static int inline umul(unsigned int a, unsigned int b)
+{
+	unsigned int result = 0;
+	/* Can't use multiplication (we have no lib). */
+	while (a--) {
+		result += b;
+	}
 
+	return result;
+}
 
 static int 
 try_cfi(flash_t *flash)
@@ -307,7 +320,7 @@
 	}
 
 	/* Enter CFI mode */
-	wide_cmd(flash, CMD_CFI_QUERY_DATA, ADDR_CFI_QUERY);
+	wide_cmd(flash, CMD_CFI_QUERY_DATA, ADDR_CFI_QUERY << offset_shift);
 
 	/* Check if flash responds correctly */
 	if ((byte)wide_read(flash, (OFFSET_CFI_ID+0) << offset_shift) == 'Q' &&
@@ -315,7 +328,6 @@
 	    (byte)wide_read(flash, (OFFSET_CFI_ID+2) << offset_shift) == 'Y') {
 		int block;            /* Current block */
 		int block_count;      /* Number of blocks */ 
-		char boot_sector = 0; /* Current boot sector */
 		int offset = 0;       /* Offset into flash */
 		int reverse = 0;      /* Reverse block table */
 		int primary;          /* Offset to vendor specific table */
@@ -374,32 +386,12 @@
 			    		      offset_shift) << 8)
 			    ) + 1;
 			    
-			if (sector_count > 8) {
-				/* Not boot sectors */	
-				int temp;
-				
-				flash->sector_size = sector_size;
-
-				/* Can't use multiplication (we have no lib). */
-				for (temp = 0 ; temp < sector_count ; temp++) {
-					offset += sector_size;
-                                }
-			} else {
-				/* Boot sectors */
-				if (boot_sector == 0) {
-					/* Set boot sector start */
-					flash->boot_sector =
-						flash->base + offset;
-				}
-        
-				for (; sector_count > 0; sector_count--) {
-					flash->boot_sector_size[
-						(udword)(boot_sector++)
-					] = sector_size;
-                                        offset += sector_size;
-				}
-			}
-                        
+			flash->sector_count[block] = sector_count;
+			flash->sector_size[block] = sector_size;
+
+			offset += umul(sector_count, sector_size);
+
+
                         /* Some flashes (SST) store information about alternate
 			 * block sizes. Ignore those by breaking when the sum
 			 * of the sector sizes == flash size.
@@ -463,21 +455,25 @@
 
 	/* check device type and fill in correct size */
 
-	flash->sector_size = 0x10000;
-
-	switch(flash->dev_id) {
-		case AM29LV160BT:
-		case TC58FVT160:
-		// case MBM29LV160TE: /* This is same id as AM29LV160BT */
+	switch(FID(flash->mfr, flash->dev_id)) {
+	        case FID(MANUFACTURER_AMD, AM29LV160BT):
+		case FID(MANUFACTURER_TOSHIBA, TC58FVT160):
+		case FID(MANUFACTURER_FUJITSU, MBM29LV160TE):
 			message = "16Mb TB";
 			flash->size = 0x00200000;
-			flash->boot_sector = flash->base + flash->size -
-					    flash->sector_size;
-			flash->boot_sector_size[0] = 0x8000;
-			flash->boot_sector_size[1] = 0x2000;
-			flash->boot_sector_size[2] = 0x2000;
-			flash->boot_sector_size[3] = 0x4000;
+			flash->sector_count[0] = 31; flash->sector_size[0] = 0x10000;
+			flash->sector_count[1] =  1; flash->sector_size[1] = 0x08000;
+			flash->sector_count[2] =  2; flash->sector_size[2] = 0x02000;
+			flash->sector_count[3] =  1; flash->sector_size[3] = 0x04000;
+			break;
+	        case FID(MANUFACTURER_ATMEL, AT49BV1614T):
+			message = "16Mb TB";
+			flash->size = 0x00200000;
+			flash->sector_count[0] = 30; flash->sector_size[0] = 0x10000;
+			flash->sector_count[1] =  2; flash->sector_size[1] = 0x08000;
+			flash->sector_count[2] =  8; flash->sector_size[2] = 0x02000;
 			break;
+/*
 		// case AM29LV160BB:
 		case TC58FVB160:
 		case MBM29LV160BE:
@@ -513,7 +509,7 @@
 			flash->boot_sector_size[3] = 0x4000;
 			break;
 		// case AM29LV800BB:
-
+*/
 		default:
 			if (flash->interleave == 1) {
 				safe_printk(
@@ -522,7 +518,10 @@
 				safe_printk(
 					"No interleaved x16 at "); 
 			}
-			send_serial_hex((udword)flash->base, NL);
+
+			send_serial_hex((udword)flash->base, ' ');
+			send_serial_hex((udword)flash->mfr, ':');
+			send_serial_hex((udword)flash->dev_id, NL);
 
 			return 0;
 	}
@@ -533,13 +532,10 @@
 	}
 	if (flash->interleave == 2) {
 		flash->size <<= 1;
-		flash->sector_size <<= 1;
-		flash->boot_sector =  flash->base +
-			((flash->boot_sector - flash->base) << 1);
-		flash->boot_sector_size[0] <<= 1;
-		flash->boot_sector_size[1] <<= 1;
-		flash->boot_sector_size[2] <<= 1;
-		flash->boot_sector_size[3] <<= 1;
+		flash->sector_size[0] <<= 1;
+		flash->sector_size[1] <<= 1;
+		flash->sector_size[2] <<= 1;
+		flash->sector_size[3] <<= 1;
 		safe_printk("2");
 	}
 	safe_printk(" x ");
@@ -556,7 +552,7 @@
 flash_erase(flash_t *flash, unsigned char *ptr, unsigned int size)
 {
 	unsigned int erased_size = 0;
-	int boot_sector_counter = 0;
+	int sector_counter = 0;
 	unsigned char *verify_ptr, *end_ptr;
 	udword cmd;
 
@@ -584,36 +580,43 @@
 	send_serial_hex((udword)ptr, 0);
 	safe_printk(": Erasing ");
 	send_serial_hex(size, 0);
-	safe_printk(" bytes...");
-
-	/* Init erasing of the number of sectors needed. */
-	flash_unlock(flash);
-	wide_cmd(flash, CMD_SECTOR_ERASE_UNLOCK_DATA_1, ADDR_UNLOCK_1);
-	flash_unlock(flash);
+	safe_printk(" bytes");
 
 	while(erased_size < size) {
-		if (flash->interleave == 2) {
-			*(udword *)ptr = cmd;
-		} else {
-			*(uword *)ptr = cmd;
-		}
+	        int sectors = flash->sector_count[sector_counter];
+		const unsigned int sector_size = flash->sector_size[sector_counter];
+		sector_counter++;
+		safe_printk(":");
 
-		if (ptr < flash->boot_sector || 
-		    ptr >= (flash->boot_sector + flash->sector_size)) {
-			erased_size += flash->sector_size;
-			ptr += flash->sector_size;
-		} else {
-			erased_size +=
-				flash->boot_sector_size[boot_sector_counter];
-			ptr += flash->boot_sector_size[boot_sector_counter++];
-		}
-	}
+		while (sectors-- > 0) {
+			/* Init erasing of the number of sectors needed. */
+			flash_unlock(flash);
+			wide_cmd(flash, CMD_SECTOR_ERASE_UNLOCK_DATA_1, ADDR_UNLOCK_1);
+			flash_unlock(flash);
 
-	/* give time for busy signal to be ready */
-	nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
+			/* the erase command */
+			if (flash->interleave == 2) {
+				*(udword *)ptr = cmd;
+			} else {
+				*(uword *)ptr = cmd;
+			}
+
+			/* give time for busy signal to be ready */
+			nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
+			nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
  
-	while(flash_is_busy(flash, 0))
-		/* nothing */;
+			if (flash_is_busy(flash, erased_size))
+			    safe_printk(".");
+			else
+			    safe_printk("?");
+
+			while(flash_is_busy(flash, erased_size)) /* same plane! */
+				/* nothing */;
+
+			erased_size += sector_size;
+			ptr += sector_size;
+		}
+	}
 
 	safe_printk("done, verifying...");
 	for (; verify_ptr < end_ptr && *verify_ptr == 0xff; verify_ptr++) {
@@ -633,12 +636,11 @@
 int
 flash_write_part(flash_t *flash, const unsigned char *source, unsigned int offset, unsigned int size)
 {
-	char retry_number[2] = "";
 	unsigned int end_offset = offset + size;
 
 	/* do the writing */
 
-	send_serial_hex(flash->base + offset, 0);
+	send_serial_hex((unsigned int)flash->base + offset, 0);
 	safe_printk(": Writing ");
 	send_serial_hex(size, 0);
 	safe_printk(" bytes...");
--- svinto_boot.h.orig	Mon Feb 19 14:53:03 2001
+++ svinto_boot.h	Fri Dec 14 11:34:33 2001
@@ -504,7 +504,7 @@
 
 #define NETWORK_HEADER_LENGTH sizeof(struct packet_header_T)
 
-void flash_write(const unsigned char *source, unsigned char *dest, unsigned int size);
+void flash_write(const unsigned char *source, unsigned int offset, unsigned int size);
 void            memory_dump(udword *from, udword *to);
 byte 		crc_correct();
 int        	read_data(void);
--- amd_flash.c.orig	Fri Nov  2 09:50:27 2001
+++ amd_flash.c	Thu Dec 13 17:15:33 2001
@@ -32,8 +32,8 @@
 /* Addresses */
 #define ADDR_MANUFACTURER		0x0000
 #define ADDR_DEVICE_ID			0x0001
-#define ADDR_UNLOCK_1			0x0555
-#define ADDR_UNLOCK_2			0x02AA
+#define ADDR_UNLOCK_1			0x5555
+#define ADDR_UNLOCK_2			0x2AAA
 
 /* Commands */
 #define CMD_UNLOCK_DATA_1		0x00AA
@@ -51,6 +51,7 @@
 #define MANUFACTURER_ST		0x0020
 #define MANUFACTURER_SST	0x00BF
 #define MANUFACTURER_TOSHIBA	0x0098
+#define MANUFACTURER_ATMEL      0x001F
 
 /* AMD */
 #define AM29F800BB	0x2258
@@ -77,6 +78,9 @@
 #define TC58FVT160	0x00C2
 #define TC58FVB160	0x0043
 
+/* ATMEL devices */
+#define AT49BV1614T     0x00C2
+
 #define D6_MASK	0x40
 
 struct amd_flash_private {
@@ -451,6 +455,28 @@
 			{ offset: 0x0F0000, erasesize: 0x08000, numblocks:  1 },
 			{ offset: 0x0F8000, erasesize: 0x02000, numblocks:  2 },
 			{ offset: 0x0FC000, erasesize: 0x04000, numblocks:  1 }
+		}	}, {
+		mfr_id: MANUFACTURER_ST,
+		dev_id: M29W160DT,
+		name: "ST M29W160DT",
+		size: 0x00200000,
+		numeraseregions: 4,
+		regions: {
+			{ offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
+			{ offset: 0x1F0000, erasesize: 0x08000, numblocks:  1 },
+			{ offset: 0x1F8000, erasesize: 0x02000, numblocks:  2 },
+			{ offset: 0x1FC000, erasesize: 0x04000, numblocks:  1 }
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV1614T,
+		name: "ATMEL AT49BV1614T",
+		size: 0x00200000,
+		numeraseregions: 3,
+		regions: {
+			{ offset: 0x000000, erasesize: 0x10000, numblocks: 30 },
+			{ offset: 0x1E0000, erasesize: 0x08000, numblocks:  2 },
+			{ offset: 0x1F0000, erasesize: 0x02000, numblocks:  8 },
 		}
 	}, {
 		mfr_id: MANUFACTURER_ST,