changeset 400:f027c6fbe37e

fc-loadtool flash: first round of refactoring for CFI
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 15 Jun 2014 20:05:54 +0000
parents d26a9e3de626
children 7ceeec049be4
files loadtools/flash.h loadtools/flerase.c loadtools/flprogbin.c loadtools/flprogsrec.c loadtools/flutil.c loadtools/ltflash.c
diffstat 6 files changed, 119 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/loadtools/flash.h	Sun Jun 15 00:47:06 2014 +0000
+++ b/loadtools/flash.h	Sun Jun 15 20:05:54 2014 +0000
@@ -12,16 +12,27 @@
 	unsigned	nsectors;
 };
 
+#define	CFI_MAX_REGIONS		4
+
+/* The info in struct cfi_info can be either gathered from CFI or hard-coded. */
+struct cfi_info {
+	uint16_t			cmdset_style;
+	uint32_t			total_size;
+	unsigned			nregions;
+	struct flash_region_desc	regions[CFI_MAX_REGIONS];
+	unsigned			total_sectors;
+};
+
 struct flash_idcheck {
 	uint16_t	offset;
 	uint16_t	expect_val;
 };
 
 struct flash_bank_desc {
-	struct flash_region_desc	*regions;
-	uint32_t			prog_base_mask;
-	struct flash_idcheck		*idcheck_table;
-	unsigned			idcheck_num;
+	uint32_t		align_size;
+	struct cfi_info		*hard_cfi;
+	struct flash_idcheck	*idcheck_table;
+	unsigned		idcheck_num;
 };
 
 struct flash_device_desc {
@@ -39,9 +50,8 @@
 
 struct flash_bank_info {
 	uint32_t		base_addr;
-	uint32_t		total_size;
 	struct flash_bank_desc	*bank_desc;
+	struct cfi_info		*cfi;
 	struct sector_info	*sectors;
-	unsigned		nsectors;
 	int			idcheck_done;
 };
--- a/loadtools/flerase.c	Sun Jun 15 00:47:06 2014 +0000
+++ b/loadtools/flerase.c	Sun Jun 15 20:05:54 2014 +0000
@@ -72,20 +72,27 @@
 	offset = strtoul(argv[2], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
 	bi = flash_bank_info + bank;
-	if (offset >= bi->total_size) {
+	if (bi->cfi->cmdset_style != 2) {
+		fprintf(stderr,
+"error: this command is currently only implemented for AMD-style flash\n");
+		return(-1);
+	}
+	if (offset >= bi->cfi->total_size) {
 		fprintf(stderr,
 		"error: specified offset exceeds flash bank size (0x%lx)\n",
-			(u_long) bi->total_size);
+			(u_long) bi->cfi->total_size);
 		return(-1);
 	}
 	len = strtoul(argv[3], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
-	if (len > bi->total_size - offset) {
+	if (len > bi->cfi->total_size - offset) {
 		fprintf(stderr,
 	"error: specified offset+length exceed flash bank size (0x%lx)\n",
-			(u_long) bi->total_size);
+			(u_long) bi->cfi->total_size);
 		return(-1);
 	}
 	if (!len) {
--- a/loadtools/flprogbin.c	Sun Jun 15 00:47:06 2014 +0000
+++ b/loadtools/flprogbin.c	Sun Jun 15 20:05:54 2014 +0000
@@ -35,11 +35,18 @@
 	flashoff = strtoul(argv[2], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
 	bi = flash_bank_info + bank;
-	if (flashoff >= bi->total_size) {
+	if (bi->cfi->cmdset_style != 2) {
+		fprintf(stderr,
+"error: this command is currently only implemented for AMD-style flash\n");
+		return(-1);
+	}
+	if (flashoff >= bi->cfi->total_size) {
 		fprintf(stderr,
 		"error: specified flash offset exceeds bank size (0x%lx)\n",
-			(u_long) bi->total_size);
+			(u_long) bi->cfi->total_size);
 		return(-1);
 	}
 	if (flashoff & 1) {
@@ -90,10 +97,10 @@
 		fclose(binf);
 		return(0);
 	}
-	if (len > bi->total_size - flashoff) {
+	if (len > bi->cfi->total_size - flashoff) {
 		fprintf(stderr,
 	"error: specified flash offset+length exceed bank size (0x%lx)\n",
-			(u_long) bi->total_size);
+			(u_long) bi->cfi->total_size);
 		fclose(binf);
 		return(-1);
 	}
--- a/loadtools/flprogsrec.c	Sun Jun 15 00:47:06 2014 +0000
+++ b/loadtools/flprogsrec.c	Sun Jun 15 20:05:54 2014 +0000
@@ -22,6 +22,14 @@
 	int resp;
 	unsigned long rec_count;
 
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
+	bi = flash_bank_info + bank;
+	if (bi->cfi->cmdset_style != 2) {
+		fprintf(stderr,
+"error: this command is currently only implemented for AMD-style flash\n");
+		return(-1);
+	}
 	srr.filename = imgfile;
 	resp = open_srec_file(&srr);
 	if (resp < 0)
@@ -31,7 +39,6 @@
 		fclose(srr.openfile);
 		return(resp);
 	}
-	bi = flash_bank_info + bank;
 	sprintf(shortarg, "%lx", (u_long) bi->base_addr);
 	targv[0] = "AMFB";
 	targv[1] = shortarg;
@@ -91,8 +98,8 @@
 			fclose(srr.openfile);
 			return(-1);
 		}
-		srr.addr &= bi->total_size - 1;
-		if (srr.addr + srr.datalen > bi->total_size) {
+		srr.addr &= bi->cfi->total_size - 1;
+		if (srr.addr + srr.datalen > bi->cfi->total_size) {
 			fprintf(stderr,
 			"%s line %d: goes past the end of the flash bank\n",
 				srr.filename, srr.lineno);
--- a/loadtools/flutil.c	Sun Jun 15 00:47:06 2014 +0000
+++ b/loadtools/flutil.c	Sun Jun 15 20:05:54 2014 +0000
@@ -10,42 +10,35 @@
 
 extern struct flash_bank_info flash_bank_info[2];
 
-compute_flash_totsize_nsecs(bank)
+flash_get_cfi(bank)
 {
 	struct flash_bank_info *bi;
-	struct flash_region_desc *reg;
 
 	bi = flash_bank_info + bank;
-	for (reg = bi->bank_desc->regions; reg->nsectors; reg++) {
-		bi->nsectors += reg->nsectors;
-		bi->total_size += reg->sector_size * reg->nsectors;
-	}
-}
-
-/* the following function is used to verify that total_size is a power of 2 */
-count_ones(word)
-	uint32_t word;
-{
-	int count;
-
-	for (count = 0; word; word >>= 1)
-		count += word & 1;
-	return count;
+	if (bi->cfi)
+		return(0);
+	printf("Error: CFI info retrieval not implemented yet\n");
+	return(-1);
 }
 
 get_flash_sector_table(bank)
 {
 	struct flash_bank_info *bi;
+	struct cfi_info *cfi;
 	struct flash_region_desc *reg;
 	struct sector_info *sp;
 	uint32_t offset;
-	int i;
+	int nr, i;
 
 	bi = flash_bank_info + bank;
 	if (bi->sectors)
 		return(0);
+	i = flash_get_cfi(bank);
+	if (i < 0)
+		return(i);
+	cfi = bi->cfi;
 	sp = (struct sector_info *) malloc(sizeof(struct sector_info)
-						* (bi->nsectors + 1));
+						* (cfi->total_sectors + 1));
 	if (!sp) {
 		fprintf(stderr,
 		"unable to malloc buffer for flash bank %d sector table\n",
@@ -55,7 +48,8 @@
 	bi->sectors = sp;
 	/* now fill it */
 	offset = 0;
-	for (reg = bi->bank_desc->regions; reg->nsectors; reg++) {
+	for (nr = 0; nr < cfi->nregions; nr++) {
+		reg = cfi->regions + nr;
 		for (i = 0; i < reg->nsectors; i++) {
 			sp->start = offset;
 			sp->size = reg->sector_size;
@@ -64,12 +58,12 @@
 		}
 	}
 	/* sanity checks */
-	if (sp - bi->sectors != bi->nsectors) {
+	if (sp - bi->sectors != cfi->total_sectors) {
 		fprintf(stderr,
 	"BUG in get_flash_sector_table(): wrong # of sectors at the end\n");
 		abort();
 	}
-	if (offset != bi->total_size) {
+	if (offset != cfi->total_size) {
 		fprintf(stderr,
 		"BUG in get_flash_sector_table(): wrong offset at the end\n");
 		abort();
@@ -93,7 +87,7 @@
 	if (get_flash_sector_table(bank) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
-	printf("%u sectors in flash bank %d:\n", bi->nsectors, bank);
+	printf("%u sectors in flash bank %d:\n", bi->cfi->total_sectors, bank);
 	printf("Offset    Size\n");
 	for (sp = bi->sectors; sp->size; sp++)
 		printf("%08lX  %lx\n", (u_long) sp->start, (u_long) sp->size);
@@ -160,6 +154,9 @@
 	bi = flash_bank_info + bank;
 	if (bi->idcheck_done && !repeat)
 		return(0);
+	bd = bi->bank_desc;
+	if (!bd->idcheck_table || !bd->idcheck_num)
+		return(0);
 	printf("Performing flash ID check\n");
 	stat = do_w16(bi->base_addr + 0xAAA, 0xAA);
 	if (stat) {
@@ -173,7 +170,6 @@
 	stat = do_w16(bi->base_addr + 0xAAA, 0x90);
 	if (stat)
 		goto bad_w16;
-	bd = bi->bank_desc;
 	id = bd->idcheck_table;
 	fail = 0;
 	for (cnt = 0; cnt < bd->idcheck_num; cnt++) {
--- a/loadtools/ltflash.c	Sun Jun 15 00:47:06 2014 +0000
+++ b/loadtools/ltflash.c	Sun Jun 15 20:05:54 2014 +0000
@@ -1,6 +1,6 @@
 /*
- * In this module we are going to implement the flash operation commands
- * of fc-loadtool.
+ * This module contains the "core" of fc-loadtool flash operations;
+ * fl*.c modules contain the rest.
  */
 
 #include <sys/types.h>
@@ -13,11 +13,12 @@
 
 /* K5A32xx device description */
 
-static struct flash_region_desc k5a32xx_topboot_regions[] = {
-	/* 4 MiB total, 64 KiB sectors except for the boot block of 8x 8 KiB */
-	{0x10000, 63},
-	{0x2000, 8},
-	{0, 0}		/* array terminator */
+static struct cfi_info k5a32xx_topboot_hardcfi = {
+	.cmdset_style	= 2,
+	.total_size	= 0x400000,
+	.nregions	= 2,
+	.regions	= {0x10000, 63, 0x2000, 8},
+	.total_sectors	= 71
 };
 
 static struct flash_idcheck k5a32xx_topboot_idcheck[2] = {
@@ -26,23 +27,25 @@
 };
 
 static struct flash_bank_desc k5a32xx_topboot_bankdesc = {
-	k5a32xx_topboot_regions, 0xFFF00000, k5a32xx_topboot_idcheck, 2
+	0x400000, &k5a32xx_topboot_hardcfi, k5a32xx_topboot_idcheck, 2
 };
 
 /* S{29,71}PL129N device description */
 
-static struct flash_region_desc pl129n_ce1_regions[] = {
-	/* 4 sectors of 64 KiB each at the beginning, then 256 KiB sectors */
-	{0x10000, 4},
-	{0x40000, 31},
-	{0, 0}		/* array terminator */
+static struct cfi_info pl129n_ce1_hardcfi = {
+	.cmdset_style	= 2,
+	.total_size	= 0x800000,
+	.nregions	= 2,
+	.regions	= {0x10000, 4, 0x40000, 31},
+	.total_sectors	= 35
 };
 
-static struct flash_region_desc pl129n_ce2_regions[] = {
-	/* the other way around now */
-	{0x40000, 31},
-	{0x10000, 4},
-	{0, 0}		/* array terminator */
+static struct cfi_info pl129n_ce2_hardcfi = {
+	.cmdset_style	= 2,
+	.total_size	= 0x800000,
+	.nregions	= 2,
+	.regions	= {0x40000, 31, 0x10000, 4},
+	.total_sectors	= 35
 };
 
 static struct flash_idcheck pl129n_idcheck[4] = {
@@ -53,8 +56,8 @@
 };
 
 static struct flash_bank_desc pl129n_banks[2] = {
-	{pl129n_ce1_regions, 0xFFFC0000, pl129n_idcheck, 4},
-	{pl129n_ce2_regions, 0xFFFC0000, pl129n_idcheck, 4}
+	{0x800000, &pl129n_ce1_hardcfi, pl129n_idcheck, 4},
+	{0x800000, &pl129n_ce2_hardcfi, pl129n_idcheck, 4}
 };
 
 /* list of supported flash devices */
@@ -130,20 +133,14 @@
 		}
 		/* the rest comes from the flash device type */
 		bi->bank_desc = selected_flash_device->bank_desc + bank;
-		compute_flash_totsize_nsecs(bank);
-		if (count_ones(bi->total_size) != 1) {
-			fprintf(stderr,
-"fc-loadtool internal bug: flash bank %d size for %s is not a power of 2\n",
-				bank, selected_flash_device->name);
-			exit(1);
-		}
-		if (bi->base_addr & (bi->total_size - 1)) {
+		if (bi->base_addr & (bi->bank_desc->align_size - 1)) {
 			fprintf(stderr,
 "%s line %d: flash bank %d base addr is not aligned to the bank size (0x%lx)\n",
 				filename_for_errs, lineno_for_errs, bank,
-				(u_long) bi->total_size);
+				(u_long) bi->bank_desc->align_size);
 			exit(1);
 		}
+		bi->cfi = bi->bank_desc->hard_cfi;
 	}
 	while (isspace(*cp))
 		cp++;
@@ -171,20 +168,22 @@
 	offset = strtoul(argv[2], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
 	bi = flash_bank_info + bank;
-	if (offset >= bi->total_size) {
+	if (offset >= bi->cfi->total_size) {
 		fprintf(stderr,
 		"error: specified offset exceeds flash bank size (0x%lx)\n",
-			(u_long) bi->total_size);
+			(u_long) bi->cfi->total_size);
 		return(-1);
 	}
 	len = strtoul(argv[3], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
-	if (len > bi->total_size - offset) {
+	if (len > bi->cfi->total_size - offset) {
 		fprintf(stderr,
 	"error: specified offset+length exceed flash bank size (0x%lx)\n",
-			(u_long) bi->total_size);
+			(u_long) bi->cfi->total_size);
 		return(-1);
 	}
 	sprintf(targ_start, "%lx", (u_long) bi->base_addr + offset);
@@ -212,20 +211,22 @@
 			argv[0], argv[1]);
 		return(-1);
 	}
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
 	bi = flash_bank_info + bank;
 	if (argc >= 4) {
 		offset = strtoul(argv[3], &strtoul_endp, 16);
 		if (*strtoul_endp)
 			goto inv;
-		if (offset >= bi->total_size) {
+		if (offset >= bi->cfi->total_size) {
 			fprintf(stderr,
 		"error: specified offset exceeds flash bank size (0x%lx)\n",
-				(u_long) bi->total_size);
+				(u_long) bi->cfi->total_size);
 			return(-1);
 		}
 	} else
 		offset = 0;
-	maxlen = bi->total_size - offset;
+	maxlen = bi->cfi->total_size - offset;
 	if (argc >= 5) {
 		dumplen = strtoul(argv[4], &strtoul_endp, 16);
 		if (*strtoul_endp)
@@ -233,7 +234,7 @@
 		if (dumplen > maxlen) {
 			fprintf(stderr,
 	"error: specified offset+length exceed flash bank size (0x%lx)\n",
-				(u_long) bi->total_size);
+				(u_long) bi->cfi->total_size);
 			return(-1);
 		}
 	} else
@@ -271,8 +272,11 @@
 	bi = flash_bank_info + bank;
 	printf("Flash device type: %s\n", selected_flash_device->name);
 	printf("Bank %d base address: %08lX\n", bank, (u_long) bi->base_addr);
-	printf("Bank %d total size: %lx\n", bank, (u_long) bi->total_size);
-	printf("Sectors in bank %d: %u\n", bank, bi->nsectors);
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
+	printf("Bank %d total size: %lx\n", bank, (u_long) bi->cfi->total_size);
+	printf("Sectors in bank %d: %u (%u regions)\n", bank,
+		bi->cfi->total_sectors, bi->cfi->nregions);
 	flash_id_check(bank, 1);
 	if (selected_flash_device->nbanks == 2 && !bank)
 	    printf("\nFlash device has 2 banks; flash2 command available\n");
@@ -285,8 +289,15 @@
 	char *targv[4], targ_base[10];
 	int stat;
 
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
+	if (flash_bank_info[bank].cfi->cmdset_style != 2) {
+		fprintf(stderr,
+"error: this command is currently only implemented for AMD-style flash\n");
+		return(-1);
+	}
 	if (argc != 4) {
-inv:		fprintf(stderr, "usage: %s %s hex-offset hex-data-string\n",
+		fprintf(stderr, "usage: %s %s hex-offset hex-data-string\n",
 			argv[0], argv[1]);
 		return(-1);
 	}