diff loadtools/flutil.c @ 403:7602443edf0d

fc-loadtool flash: CFI query code implemented, compiles
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 15 Jun 2014 22:06:46 +0000
parents f027c6fbe37e
children a212b4968b29
line wrap: on
line diff
--- a/loadtools/flutil.c	Sun Jun 15 20:38:18 2014 +0000
+++ b/loadtools/flutil.c	Sun Jun 15 22:06:46 2014 +0000
@@ -10,15 +10,161 @@
 
 extern struct flash_bank_info flash_bank_info[2];
 
+static int
+cfi_read_byte(bi, off, ret16p)
+	struct flash_bank_info *bi;
+	int off;
+	uint16_t *ret16p;
+{
+	return do_r16(bi->base_addr + (off << 1), ret16p);
+}
+
+static int
+cfi_read_twobyte(bi, off, retptr)
+	struct flash_bank_info *bi;
+	int off;
+	uint16_t *retptr;
+{
+	uint16_t lo, hi;
+
+	if (cfi_read_byte(bi, off, &lo) < 0)
+		return(-1);
+	lo &= 0xFF;
+	if (cfi_read_byte(bi, off + 1, &hi) < 0)
+		return(-1);
+	hi &= 0xFF;
+	*retptr = (hi << 8) | lo;
+	return(0);
+}
+
+static int
+cfi_id_return_to_read_mode(bi)
+	struct flash_bank_info *bi;
+{
+	if (do_w16(bi->base_addr + 0xAAA, 0xF0)) {
+		fprintf(stderr,
+	"unexpected response to w16 when resetting flash to read mode!\n");
+		return(-1);
+	}
+	return(0);
+}
+
 flash_get_cfi(bank)
 {
 	struct flash_bank_info *bi;
+	struct cfi_info *cfi;
+	struct flash_region_desc *reg;
+	int nr;
+	uint16_t rdval;
+	uint32_t size_check;
 
 	bi = flash_bank_info + bank;
 	if (bi->cfi)
 		return(0);
-	printf("Error: CFI info retrieval not implemented yet\n");
-	return(-1);
+	printf("Performing CFI query\n");
+	if (do_w16(bi->base_addr + 0xAA, 0x98)) {
+		fprintf(stderr, "unexpected response to w16 - aborting\n");
+		return(-1);
+	}
+	/* if do_r16() returns -1, error msg has already been printed */
+	if (cfi_read_byte(bi, 0x10, &rdval) < 0)
+		return(-1);
+	if (rdval != 'Q') {
+noqry:		fprintf(stderr, "error: no QRY response from flash\n");
+		cfi_id_return_to_read_mode(bi);
+		return(-1);
+	}
+	if (cfi_read_byte(bi, 0x11, &rdval) < 0)
+		return(-1);
+	if (rdval != 'R')
+		goto noqry;
+	if (cfi_read_byte(bi, 0x12, &rdval) < 0)
+		return(-1);
+	if (rdval != 'Y')
+		goto noqry;
+	cfi = malloc(sizeof(struct cfi_info));
+	if (!cfi) {
+		fprintf(stderr,
+		"unable to malloc buffer for flash bank %d CFI structure\n",
+			bank);
+		cfi_id_return_to_read_mode(bi);
+		return(-1);
+	}
+	if (cfi_read_twobyte(bi, 0x13, &cfi->cmdset_style) < 0) {
+free_and_immed_out:
+		free(cfi);
+		return(-1);
+	}
+	/* total device size */
+	if (cfi_read_byte(bi, 0x27, &rdval) < 0)
+		goto free_and_immed_out;
+	if (rdval < 20 || rdval > 24) {
+		fprintf(stderr,
+			"error: CFI reports unreasonable device size\n");
+free_and_clean_out:
+		free(cfi);
+		cfi_id_return_to_read_mode(bi);
+		return(-1);
+	}
+	cfi->total_size = 1 << rdval;
+	if (cfi->total_size > bi->bank_desc->align_size) {
+		fprintf(stderr,
+	"error: CFI device size 0x%lx exceeds configured maximum 0x%lx\n",
+			(u_long) cfi->total_size, bi->bank_desc->align_size);
+		goto free_and_clean_out;
+	}
+	if (cfi_read_byte(bi, 0x2C, &rdval) < 0)
+		goto free_and_immed_out;
+	if (rdval < 1 || rdval > CFI_MAX_REGIONS) {
+		fprintf(stderr,
+			"error: CFI reports unreasonable # of erase regions\n");
+		goto free_and_clean_out;
+	}
+	cfi->nregions = rdval;
+	cfi->total_sectors = 0;
+	size_check = 0;
+	for (nr = 0; nr < cfi->nregions; nr++) {
+		reg = cfi->regions + nr;
+		if (cfi_read_twobyte(bi, 0x2D + nr*4, &rdval) < 0)
+			goto free_and_immed_out;
+		if (rdval > 255) {
+			fprintf(stderr,
+		"error: CFI reports unreasonable # of sectors in region %d\n",
+				nr);
+			goto free_and_clean_out;
+		}
+		reg->nsectors = rdval + 1;
+		cfi->total_sectors += reg->nsectors;
+		if (cfi_read_twobyte(bi, 0x2F + nr*4, &rdval) < 0)
+			goto free_and_immed_out;
+		if (rdval < 0x20 || rdval > 0x400) {
+			fprintf(stderr,
+		"error: CFI reports unreasonable sector size in region %d\n",
+				nr);
+			goto free_and_clean_out;
+		}
+		reg->sector_size = rdval << 8;
+		size_check += reg->sector_size * reg->nsectors;
+	}
+	if (cfi_id_return_to_read_mode(bi) < 0) {
+		/* error msg already printed */
+		free(cfi);
+		return(-1);
+	}
+	if (size_check != cfi->total_size) {
+		fprintf(stderr,
+"CFI error: added size of erase regions (%lx) != reported devive size (%lx)\n",
+			(u_long) size_check, (u_long) cfi->total_size);
+		free(cfi);
+		return(-1);
+	}
+	/* all checks passed */
+	bi->cfi = cfi;
+	printf(
+"CFI query successful: total size %lx, %u sectors, command set style %04X\n\n",
+		(u_long) cfi->total_size, cfi->total_sectors,
+		cfi->cmdset_style);
+	return(1);
 }
 
 get_flash_sector_table(bank)