view target-utils/loadagent/amdflash.c @ 733:bed7981ac8ca

doc/Compal-FFS: update for IMEI found in OTP cells
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 28 Aug 2020 15:58:46 +0000
parents b34384991094
children
line wrap: on
line source

/*
 * This module implements the AMFB and AMFW commands for programming
 * AMD-style flash memories.  Syntax:
 *
 * AMFB <baseaddr>	-- sets the base address for subsequent AMFW commands
 * AMFW <offset> <hexstring>	-- the actual flash write operation
 *
 * The flash memory is assumed to be 16 bits wide.  The hex string
 * argument to the AMFW command is just data, with no header, address,
 * length, checksum or other additions.  The number of hex digits in the
 * string must be a multiple of 4, and the byte order is the same as
 * that of TI's *.m0 files: we interpret the string as consisting of
 * 16-bit words rather than bytes.
 *
 * The address to which each flash write is directed is the sum of the
 * base given to AMFB and the offset given to AMFW.  The fixed offsets
 * of 0xAAA and 0x554 (0x555 and 0x2AA in words) prescribed for the flash
 * programming command sequence are also made from the base set with AMFB.
 */

#include <sys/types.h>
#include "types.h"

static u32 base_addr;

void
cmd_AMFB(argbulk)
	char *argbulk;
{
	char *argv[2];
	u_long addr;

	if (parse_args(argbulk, 1, 1, argv, 0) < 0)
		return;
	if (parse_hexarg(argv[0], 8, &addr) < 0) {
		printf("ERROR: argument must be a valid 32-bit hex address\n");
		return;
	}
	if (addr & 1) {
		printf("ERROR: odd address\n");
		return;
	}
	base_addr = addr;
}

void
cmd_AMFW(argbulk)
	char *argbulk;
{
	char *argv[3], *s;
	u_long offset;
	volatile u16 *flashptr;
	u32 datum;	/* needs to be u32 for decode_hex_digits() */
	int i;

	if (parse_args(argbulk, 2, 2, argv, 0) < 0)
		return;
	if (parse_hexarg(argv[0], 8, &offset) < 0) {
	    printf("ERROR: offset argument must a valid 32-bit hex value\n");
		return;
	}
	if (offset & 1) {
		printf("ERROR: odd offset argument\n");
		return;
	}
	flashptr = (volatile u16 *)(base_addr + offset);
	for (s = argv[1]; *s; flashptr++, s += 4) {
		if (decode_hex_digits(s, 4, &datum) < 0) {
			printf("ERROR: bad AMFW hex string argument\n");
			return;
		}
		if (*flashptr != 0xFFFF) {
			printf("ERROR: flash not blank at %08X\n",
				(u_long) flashptr);
			return;
		}
		*(volatile u16 *)(base_addr + 0xAAA) = 0xAA;
		*(volatile u16 *)(base_addr + 0x554) = 0x55;
		*(volatile u16 *)(base_addr + 0xAAA) = 0xA0;
		*flashptr = datum;
		for (i = 10000; i; i--)
			if (*flashptr == datum)
				break;
		if (!i) {
			printf("ERROR: flash write timeout at %08X\n",
				(u_long) flashptr);
			return;
		}
	}
}

amdflash_binary_prog(offset, nwords, data)
	u32 offset;
	unsigned nwords;
	u16 *data;
{
	volatile u16 *flashptr;
	int i;

	flashptr = (volatile u16 *)(base_addr + offset);
	while (nwords) {
		if (*flashptr != 0xFFFF) {
			serial_out(0x15);	/* NAK */
			printf("ERROR: flash not blank at %08X\n",
				(u_long) flashptr);
			return(-1);
		}
		*(volatile u16 *)(base_addr + 0xAAA) = 0xAA;
		*(volatile u16 *)(base_addr + 0x554) = 0x55;
		*(volatile u16 *)(base_addr + 0xAAA) = 0xA0;
		*flashptr = *data;
		for (i = 10000; i; i--)
			if (*flashptr == *data)
				break;
		if (!i) {
			serial_out(0x15);	/* NAK */
			printf("ERROR: flash write timeout at %08X\n",
				(u_long) flashptr);
			return(-1);
		}
		flashptr++;
		data++;
		nwords--;
	}
	return(0);
}

void
cmd_AMFWB()
{
	binary_flash_prog_main(amdflash_binary_prog);
}