view loadtools/ltflash.c @ 401:7ceeec049be4

fc-loadtool flash: bank configurations for CFI
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 15 Jun 2014 20:24:51 +0000
parents f027c6fbe37e
children
line wrap: on
line source

/*
 * This module contains the "core" of fc-loadtool flash operations;
 * fl*.c modules contain the rest.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include "flash.h"

/* K5A32xx device description */

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] = {
	{0x00, 0x00EC},
	{0x02, 0x22A0}
};

static struct flash_bank_desc k5a32xx_topboot_bankdesc = {
	0x400000, &k5a32xx_topboot_hardcfi, k5a32xx_topboot_idcheck, 2
};

/* S{29,71}PL129N device description */

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 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] = {
	{0x00, 0x0001},
	{0x02, 0x227E},
	{0x1C, 0x2221},
	{0x1E, 0x2200}
};

static struct flash_bank_desc pl129n_banks[2] = {
	{0x800000, &pl129n_ce1_hardcfi, pl129n_idcheck, 4},
	{0x800000, &pl129n_ce2_hardcfi, pl129n_idcheck, 4}
};

/* bank configurations for CFI */

static struct flash_bank_desc cfi_4M_bankdesc = {
	0x400000, 0, 0, 0
};

static struct flash_bank_desc cfi_8M_bankdesc = {
	0x800000, 0, 0, 0
};

/* list of supported flash devices */

struct flash_device_desc flash_device_list[] = {
	{"cfi-4M", &cfi_4M_bankdesc, 1},
	{"cfi-8M", &cfi_8M_bankdesc, 1},
	{"k5a32xx_t", &k5a32xx_topboot_bankdesc, 1},
	{"pl129n", pl129n_banks, 2},
	{0, 0, 0}	/* array terminator */
};

/* the following variables describe our selected flash device */

struct flash_device_desc *selected_flash_device;
struct flash_bank_info flash_bank_info[2];

/* called from hwparam.c config file parser */
void
set_flash_device(arg, filename_for_errs, lineno_for_errs)
	char *arg;
	char *filename_for_errs;
	int lineno_for_errs;
{
	char *cp, *np, *ep;
	struct flash_device_desc *tp;
	int bank;
	struct flash_bank_info *bi;

	if (selected_flash_device) {
		fprintf(stderr, "%s line %d: duplicate flash setting\n",
			filename_for_errs, lineno_for_errs);
		exit(1);
	}
	for (cp = arg; isspace(*cp); cp++)
		;
	if (!*cp || *cp == '#') {
too_few_arg:	fprintf(stderr,
			"%s line %d: flash setting: too few arguments\n",
			filename_for_errs, lineno_for_errs);
		exit(1);
	}
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	for (tp = flash_device_list; tp->name; tp++)
		if (!strcmp(tp->name, np))
			break;
	if (!tp->name) {
		fprintf(stderr,
			"%s line %d: unknown flash device \"%s\"\n",
			filename_for_errs, lineno_for_errs, np);
		exit(1);
	}
	selected_flash_device = tp;

	/* now initialize flash_bank_info */
	for (bank = 0; bank < selected_flash_device->nbanks; bank++) {
		while (isspace(*cp))
			cp++;
		if (!*cp || *cp == '#')
			goto too_few_arg;
		for (np = cp; *cp && !isspace(*cp); cp++)
			;
		if (*cp)
			*cp++ = '\0';
		bi = flash_bank_info + bank;
		bi->base_addr = strtoul(np, &ep, 16);
		if (*ep) {
			fprintf(stderr,
"%s line %d: syntax error (base addr expected after flash device type)\n",
				filename_for_errs, lineno_for_errs);
			exit(1);
		}
		/* the rest comes from the flash device type */
		bi->bank_desc = selected_flash_device->bank_desc + bank;
		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->bank_desc->align_size);
			exit(1);
		}
		bi->cfi = bi->bank_desc->hard_cfi;
	}
	while (isspace(*cp))
		cp++;
	if (*cp && *cp != '#') {
		fprintf(stderr,
			"%s line %d: flash setting: too many arguments\n",
			filename_for_errs, lineno_for_errs);
		exit(1);
	}
}

flashcmd_blankchk(argc, argv, bank)
	char **argv;
{
	struct flash_bank_info *bi;
	u_long offset, len;
	char *strtoul_endp;
	char *targv[4], targ_start[10], targ_len[10];

	if (argc != 4) {
inv:		fprintf(stderr, "usage: %s %s hex-start-offset hex-length\n",
			argv[0], argv[1]);
		return(-1);
	}
	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->cfi->total_size) {
		fprintf(stderr,
		"error: specified offset exceeds flash bank size (0x%lx)\n",
			(u_long) bi->cfi->total_size);
		return(-1);
	}
	len = strtoul(argv[3], &strtoul_endp, 16);
	if (*strtoul_endp)
		goto inv;
	if (len > bi->cfi->total_size - offset) {
		fprintf(stderr,
	"error: specified offset+length exceed flash bank size (0x%lx)\n",
			(u_long) bi->cfi->total_size);
		return(-1);
	}
	sprintf(targ_start, "%lx", (u_long) bi->base_addr + offset);
	sprintf(targ_len, "%lx", len);
	targv[0] = "blankchk";
	targv[1] = targ_start;
	targv[2] = targ_len;
	targv[3] = 0;
	tpinterf_make_cmd(targv);
	if (tpinterf_send_cmd() < 0)
		return(-1);
	return tpinterf_pass_output(10);	/* 10 s timeout */
}

flashcmd_dump2file(argc, argv, bank)
	char **argv;
{
	struct flash_bank_info *bi;
	u_long offset, dumplen, maxlen;
	char *strtoul_endp;
	int format;

	if (argc < 3 || argc > 5) {
inv:		fprintf(stderr, "usage: %s %s outfile [offset [length]]\n",
			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->cfi->total_size) {
			fprintf(stderr,
		"error: specified offset exceeds flash bank size (0x%lx)\n",
				(u_long) bi->cfi->total_size);
			return(-1);
		}
	} else
		offset = 0;
	maxlen = bi->cfi->total_size - offset;
	if (argc >= 5) {
		dumplen = strtoul(argv[4], &strtoul_endp, 16);
		if (*strtoul_endp)
			goto inv;
		if (dumplen > maxlen) {
			fprintf(stderr,
	"error: specified offset+length exceed flash bank size (0x%lx)\n",
				(u_long) bi->cfi->total_size);
			return(-1);
		}
	} else
		dumplen = maxlen;
	switch (argv[1][5]) {
	case 'b':
		format = 0;
		break;
	case 's':
		format = 1;
		break;
	default:
		fprintf(stderr,
			"internal bug: bad format in flashcmd_dump2file()\n");
		return(-1);
	}
	return loadtool_memdump(bi->base_addr + offset, dumplen, argv[2],
				format);
}

flashcmd_help()
{
	return loadtool_help("flash");
}

flashcmd_info(argc, argv, bank)
	char **argv;
{
	struct flash_bank_info *bi;

	if (argc > 2) {
		fprintf(stderr, "error: too many arguments\n");
		return(-1);
	}
	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);
	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);
	printf("Command set style: %04X\n", bi->cfi->cmdset_style);
	flash_id_check(bank, 1);
	if (selected_flash_device->nbanks == 2 && !bank)
	    printf("\nFlash device has 2 banks; flash2 command available\n");
	return(0);
}

flashcmd_quickprog(argc, argv, bank)
	char **argv;
{
	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) {
		fprintf(stderr, "usage: %s %s hex-offset hex-data-string\n",
			argv[0], argv[1]);
		return(-1);
	}
	sprintf(targ_base, "%lx", (u_long) flash_bank_info[bank].base_addr);
	targv[0] = "AMFB";
	targv[1] = targ_base;
	targv[2] = 0;
	tpinterf_make_cmd(targv);
	if (tpinterf_send_cmd() < 0)
		return(-1);
	stat = tpinterf_pass_output(1);
	if (stat)
		return(stat);
	targv[0] = "AMFW";
	targv[1] = argv[2];
	targv[2] = argv[3];
	targv[3] = 0;
	if (tpinterf_make_cmd(targv) < 0) {
		fprintf(stderr, "error: unable to form AMFW target command\n");
		return(-1);
	}
	if (tpinterf_send_cmd() < 0)
		return(-1);
	return tpinterf_pass_output(1);
}

extern int flashcmd_erase();
extern int flashcmd_progbin();
extern int flashcmd_program_m0();
extern int flashcmd_program_srec();
extern int flashcmd_sectors();

static struct cmdtab {
	char *cmd;
	int (*func)();
} cmdtab[] = {
	{"blankchk", flashcmd_blankchk},
	{"dump2bin", flashcmd_dump2file},
	{"dump2srec", flashcmd_dump2file},
	{"erase", flashcmd_erase},
	{"help", flashcmd_help},
	{"info", flashcmd_info},
	{"program-bin", flashcmd_progbin},
	{"program-m0", flashcmd_program_m0},
	{"program-srec", flashcmd_program_srec},
	{"quickprog", flashcmd_quickprog},
	{"sectors", flashcmd_sectors},
	{0, 0}
};

cmd_flash(argc, argv)
	char **argv;
{
	int bank;
	struct cmdtab *tp;

	if (!selected_flash_device) {
		fprintf(stderr, "No flash configuration defined\n");
		return(-1);
	}
	if (argv[0][5] == '2') {
		if (selected_flash_device->nbanks < 2) {
			fprintf(stderr, "Flash device %s has only one bank\n",
				selected_flash_device->name);
			return(-1);
		}
		bank = 1;
	} else
		bank = 0;
	for (tp = cmdtab; tp->cmd; tp++)
		if (!strcmp(tp->cmd, argv[1]))
			break;
	if (!tp->func) {
		fprintf(stderr, "%s %s: unknown/unimplemented subcommand\n",
			argv[0], argv[1]);
		return(-1);
	}
	return tp->func(argc, argv, bank);
}