diff loadtools/flutil.c @ 0:e7502631a0f9

initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 11 Jun 2016 00:13:35 +0000
parents
children 7bf0d909c87e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/flutil.c	Sat Jun 11 00:13:35 2016 +0000
@@ -0,0 +1,350 @@
+/*
+ * Miscellaneous utility functions for flash support
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "flash.h"
+
+extern struct flash_bank_info flash_bank_info[2];
+extern struct flash_cmdset flash_cmdset_amd;
+extern struct flash_cmdset flash_cmdset_intel;
+
+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);
+}
+
+flash_get_cfi(bank)
+{
+	struct flash_bank_info *bi;
+	struct flash_geom *geom;
+	struct flash_region_desc *reg;
+	int nr;
+	uint16_t rdval, cmdset_id;
+	uint32_t size_check;
+
+	bi = flash_bank_info + bank;
+	if (bi->geom)
+		return(0);
+	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");
+		amd_reset_cmd(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;
+	if (cfi_read_twobyte(bi, 0x13, &cmdset_id) < 0)
+		return(-1);
+	if (!bi->ops) {
+		switch (cmdset_id) {
+		case 2:
+			bi->ops = &flash_cmdset_amd;
+			break;
+		case 3:
+			bi->ops = &flash_cmdset_intel;
+			break;
+		default:
+			fprintf(stderr, "error: command set %04X unsupported\n",
+				cmdset_id);
+			amd_reset_cmd(bi);
+			return(-1);
+		}
+	}
+	geom = malloc(sizeof(struct flash_geom));
+	if (!geom) {
+		fprintf(stderr,
+	"unable to malloc buffer for flash bank %d CFI geometry structure\n",
+			bank);
+		bi->ops->reset_cmd(bi);
+		return(-1);
+	}
+	/* total device size */
+	if (cfi_read_byte(bi, 0x27, &rdval) < 0) {
+free_and_immed_out:
+		free(geom);
+		return(-1);
+	}
+	if (rdval < 20 || rdval > 24) {
+		fprintf(stderr,
+			"error: CFI reports unreasonable device size\n");
+free_and_clean_out:
+		free(geom);
+		bi->ops->reset_cmd(bi);
+		return(-1);
+	}
+	geom->total_size = 1 << rdval;
+	if (geom->total_size > bi->bank_desc->align_size) {
+		fprintf(stderr,
+	"error: CFI device size 0x%lx exceeds configured maximum 0x%lx\n",
+			(u_long) geom->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;
+	}
+	geom->nregions = rdval;
+	geom->total_sectors = 0;
+	size_check = 0;
+	for (nr = 0; nr < geom->nregions; nr++) {
+		reg = geom->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;
+		geom->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 (bi->ops->reset_cmd(bi) < 0) {
+		/* error msg already printed */
+		free(geom);
+		return(-1);
+	}
+	if (size_check != geom->total_size) {
+		fprintf(stderr,
+"CFI error: added size of erase regions (%lx) != reported devive size (%lx)\n",
+			(u_long) size_check, (u_long) geom->total_size);
+		free(geom);
+		return(-1);
+	}
+	/* all checks passed */
+	bi->geom = geom;
+	printf(
+"CFI query successful: total size %lx, %u sectors, command set style %04X\n",
+		(u_long) geom->total_size, geom->total_sectors, cmdset_id);
+	return(1);
+}
+
+get_flash_sector_table(bank)
+{
+	struct flash_bank_info *bi;
+	struct flash_geom *geom;
+	struct flash_region_desc *reg;
+	struct sector_info *sp;
+	uint32_t offset;
+	int nr, i;
+
+	bi = flash_bank_info + bank;
+	if (bi->sectors)
+		return(0);
+	i = flash_get_cfi(bank);
+	if (i < 0)
+		return(i);
+	geom = bi->geom;
+	sp = (struct sector_info *) malloc(sizeof(struct sector_info)
+						* (geom->total_sectors + 1));
+	if (!sp) {
+		fprintf(stderr,
+		"unable to malloc buffer for flash bank %d sector table\n",
+			bank);
+		return(-1);
+	}
+	bi->sectors = sp;
+	/* now fill it */
+	offset = 0;
+	for (nr = 0; nr < geom->nregions; nr++) {
+		reg = geom->regions + nr;
+		for (i = 0; i < reg->nsectors; i++) {
+			sp->start = offset;
+			sp->size = reg->sector_size;
+			sp++;
+			offset += reg->sector_size;
+		}
+	}
+	/* sanity checks */
+	if (sp - bi->sectors != geom->total_sectors) {
+		fprintf(stderr,
+	"BUG in get_flash_sector_table(): wrong # of sectors at the end\n");
+		abort();
+	}
+	if (offset != geom->total_size) {
+		fprintf(stderr,
+		"BUG in get_flash_sector_table(): wrong offset at the end\n");
+		abort();
+	}
+	/* finish */
+	sp->start = 0;
+	sp->size = 0;
+	return(0);
+}
+
+flashcmd_sectors(argc, argv, bank)
+	char **argv;
+{
+	struct flash_bank_info *bi;
+	struct sector_info *sp;
+
+	if (argc > 2) {
+		fprintf(stderr, "error: too many arguments\n");
+		return(-1);
+	}
+	if (get_flash_sector_table(bank) < 0)
+		return(-1);
+	bi = flash_bank_info + bank;
+	printf("%u sectors in flash bank %d:\n", bi->geom->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);
+	return(0);
+}
+
+get_flash_sector_range(bi, useroff, userlen, startp, endp)
+	struct flash_bank_info *bi;
+	u_long useroff, userlen;
+	struct sector_info **startp, **endp;
+{
+	struct sector_info *sp;
+	uint32_t remlen;
+
+	for (sp = bi->sectors; sp->size; sp++)
+		if (sp->start == useroff)
+			break;
+	if (!sp->size) {
+		fprintf(stderr,
+	"error: specified offset not aligned to a flash sector boundary\n");
+		return(-1);
+	}
+	*startp = sp;
+	for (remlen = userlen; remlen; ) {
+		if (remlen < sp->size) {
+			fprintf(stderr,
+	"error: specified length not aligned to a flash sector boundary\n");
+			return(-1);
+		}
+		remlen -= sp->size;
+		sp++;
+	}
+	*endp = sp;
+	return(0);
+}
+
+build_flashw_hex_string(bin, strbuf, nwords, m0src)
+	u_char *bin;
+	char *strbuf;
+	int nwords, m0src;
+{
+	int i;
+	u_char *dp;
+	char *s;
+
+	for (dp = bin, s = strbuf, i = 0; i < nwords; dp += 2, s += 4, i++) {
+		if (m0src)
+			sprintf(s, "%02X%02X", dp[0], dp[1]);
+		else
+			sprintf(s, "%02X%02X", dp[1], dp[0]);
+	}
+	*s = '\0';
+}
+
+flash_id_check(bank, repeat)
+{
+	struct flash_bank_info *bi;
+	struct flash_bank_desc *bd;
+	struct flash_idcheck *id;
+	int stat, fail;
+	uint16_t rdval;
+	unsigned cnt;
+
+	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) {
+bad_w16:	fprintf(stderr,
+	"unexpected response to w16 in read ID cmd sequence - aborting\n");
+		return(-1);
+	}
+	stat = do_w16(bi->base_addr + 0x554, 0x55);
+	if (stat)
+		goto bad_w16;
+	stat = do_w16(bi->base_addr + 0xAAA, 0x90);
+	if (stat)
+		goto bad_w16;
+	id = bd->idcheck_table;
+	fail = 0;
+	for (cnt = 0; cnt < bd->idcheck_num; cnt++) {
+		stat = do_r16(bi->base_addr + id->offset, &rdval);
+		if (stat)
+			return(stat);	/* error msg already printed */
+		printf("offset %02X: %04X -- ", (int)id->offset, (int)rdval);
+		if (rdval == id->expect_val)
+			printf("PASS\n");
+		else {
+			printf("FAIL: expected %04X\n", (int)id->expect_val);
+			fail = 1;
+			break;
+		}
+		id++;
+	}
+	/* reset flash to read mode */
+	stat = do_w16(bi->base_addr + 0xAAA, 0xF0);
+	if (stat) {
+		fprintf(stderr,
+	"unexpected response to w16 when resetting flash to read mode!\n");
+		return(-1);
+	}
+	if (fail)
+		return(-1);
+	bi->idcheck_done = 1;
+	return(0);
+}