view loadtools/flutil.c @ 407:19e5a3e2f9c0

fcup-settime: moved time() retrieval a little closer to the output A fundamental problem with all simple time transfer tools is that there is always some delay between the time retrieval on the source system and that transmitted time being set on the destination, and the resulting time on the destination system is off by that delay amount. This delay cannot be fully eliminated when working in a simple environment like ours, but we should make our best effort to minimize it. In the present case, moving the atinterf_init() call before the time() retrieval should make a teensy-tiny improvement.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 11 Aug 2018 21:52:17 +0000
parents e7502631a0f9
children 7bf0d909c87e
line wrap: on
line source

/*
 * 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);
}