view loadtools/flashops.c @ 805:a43c5dc251dc

doc/User-phone-tools: new sms-pdu-decode backslash escapes
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 25 Mar 2021 05:10:43 +0000
parents 44cdfc4fed4c
children
line wrap: on
line source

/*
 * This module implements those flash operations which are dependent
 * on the AMD vs. Intel command set style.
 */

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

/* common stub functions */

static
noop()
{
	return(0);
}

static
amd_invalid()
{
	fprintf(stderr,
		"This operation is not applicable to AMD-style flash\n");
	return(-1);
}

/* AMD flash functions */

amd_reset_cmd(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);
}

amd_sector_erase(bi, sp)
	struct flash_bank_info *bi;
	struct sector_info *sp;
{
	int stat;
	uint16_t flstat;
	time_t start_time, curtime;

	stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0xAA);
	if (stat) {
bad_w16:	fprintf(stderr,
	"unexpected response to w16 in erase cmd sequence - aborting\n");
		return(-1);
	}
	stat = do_w16(bi->base_addr + sp->start + 0x554, 0x55);
	if (stat)
		goto bad_w16;
	stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0x80);
	if (stat)
		goto bad_w16;
	stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0xAA);
	if (stat)
		goto bad_w16;
	stat = do_w16(bi->base_addr + sp->start + 0x554, 0x55);
	if (stat)
		goto bad_w16;
	stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0x30);
	if (stat)
		goto bad_w16;
	start_time = time(0);
	for (;;) {
		stat = do_r16(bi->base_addr + sp->start, &flstat);
		if (stat)
			return(stat);	/* error msg already printed */
		if (flstat == 0xFFFF)
			return(0);
		curtime = time(0);
		if (curtime >= start_time + 20) {
			fprintf(stderr, "erase timeout, aborting\n");
			return(-1);
		}
	}
}

struct flash_cmdset flash_cmdset_amd = {
	.cmdset_name		= "AMD",
	.reset_cmd		= amd_reset_cmd,
	.status_cmd		= amd_invalid,
	.unlock_sector		= amd_invalid,
	.erase_sector		= amd_sector_erase,
	.prep_for_program	= noop,
	.read_prot_reg		= amd_invalid,
	.loadagent_setbase_cmd	= "AMFB",
	.loadagent_program_cmd	= "AMFW",
	.loadagent_binmode_cmd	= "AMFWB",
	.needs_unlock		= 0,
};

/* Intel flash functions */

intel_reset_cmd(bi)
	struct flash_bank_info *bi;
{
	if (do_w16(bi->base_addr, 0xFF)) {
		fprintf(stderr,
	"unexpected response to w16 when resetting flash to read mode!\n");
		return(-1);
	}
	return(0);
}

intel_w30_reset_cmd(bi)
	struct flash_bank_info *bi;
{
	uint32_t part;

	for (part = 0; part < bi->geom->total_size; part += 0x80000) {
		if (do_w16(bi->base_addr + part, 0xFF)) {
			fprintf(stderr,
	"unexpected response to w16 when resetting flash to read mode!\n");
			return(-1);
		}
	}
	return(0);
}

intel_status_cmd(bi)
	struct flash_bank_info *bi;
{
	int stat;
	uint16_t sr;

	/* issue Read SR command */
	stat = do_w16(bi->base_addr, 0x70);
	if (stat) {
		fprintf(stderr,
			"unexpected response to w16 for Read SR command\n");
		return(-1);
	}
	stat = do_r16(bi->base_addr, &sr);
	if (stat)
		return(stat);	/* error msg already printed */
	sr &= 0xFF;
	printf("Status Register: %02X\n", sr);
	return(0);
}

intel_w30_status_cmd(bi)
	struct flash_bank_info *bi;
{
	uint32_t part;
	int stat;
	uint16_t sr;

	for (part = 0; part < bi->geom->total_size; part += 0x80000) {
		/* issue Read SR command */
		stat = do_w16(bi->base_addr + part, 0x70);
		if (stat) {
			fprintf(stderr,
			"unexpected response to w16 for Read SR command\n");
			return(-1);
		}
		stat = do_r16(bi->base_addr + part, &sr);
		if (stat)
			return(stat);	/* error msg already printed */
		sr &= 0xFF;
		printf("Status Register for partition %08lX: %02X\n",
			(u_long) part, sr);
	}
	return(0);
}

intel_sector_unlock(bi, sp)
	struct flash_bank_info *bi;
	struct sector_info *sp;
{
	int stat;

	stat = do_w16(bi->base_addr + sp->start, 0x60);
	if (stat) {
bad_w16:	fprintf(stderr,
	"unexpected response to w16 in block unlock cmd sequence - aborting\n");
		return(-1);
	}
	stat = do_w16(bi->base_addr + sp->start, 0xD0);
	if (stat)
		goto bad_w16;
	return(0);
}

intel_sector_erase(bi, sp)
	struct flash_bank_info *bi;
	struct sector_info *sp;
{
	int stat;
	uint16_t flstat;
	time_t start_time, curtime;

	stat = intel_sector_unlock(bi, sp);
	if (stat)
		return(stat);	/* error msg already printed */
	/* clear SR */
	stat = do_w16(bi->base_addr + sp->start, 0x50);
	if (stat) {
bad_w16:	fprintf(stderr,
	"unexpected response to w16 in erase cmd sequence - aborting\n");
		return(-1);
	}
	/* send the actual block erase command */
	stat = do_w16(bi->base_addr + sp->start, 0x20);
	if (stat)
		goto bad_w16;
	stat = do_w16(bi->base_addr + sp->start, 0xD0);
	if (stat)
		goto bad_w16;
	/* wait for completion */
	start_time = time(0);
	for (;;) {
		stat = do_r16(bi->base_addr + sp->start, &flstat);
		if (stat)
			return(stat);	/* error msg already printed */
		if (flstat & 0x80)
			break;
		curtime = time(0);
		if (curtime >= start_time + 20) {
			fprintf(stderr, "erase timeout, aborting\n");
			return(-1);
		}
	}
	if (flstat & 0x20) {
		fprintf(stderr, "block erase failed!\n");
		return(-1);
	} else
		return(0);
}

intel_clear_sr(bi)
	struct flash_bank_info *bi;
{
	printf("Clearing Intel flash SR\n");
	if (do_w16(bi->base_addr, 0x50)) {
		fprintf(stderr,
			"unexpected response to w16 for Clear SR command\n");
		return(-1);
	}
	return(0);
}

intel_w30_clear_sr(bi)
	struct flash_bank_info *bi;
{
	uint32_t part;

	printf("Clearing Intel flash SR\n");
	for (part = 0; part < bi->geom->total_size; part += 0x80000) {
		if (do_w16(bi->base_addr + part, 0x50)) {
			fprintf(stderr,
			"unexpected response to w16 for Clear SR command\n");
			return(-1);
		}
	}
	return(0);
}

intel_read_prot_reg(bi, data)
	struct flash_bank_info *bi;
	uint16_t *data;
{
	int stat, i;

	if (do_w16(bi->base_addr, 0x90)) {
		fprintf(stderr,
			"unexpected response to w16 for Read ID command\n");
		return(-1);
	}
	for (i = 0; i < 9; i++) {
		stat = do_r16(bi->base_addr + 0x100 + i * 2, data + i);
		if (stat)
			return(stat);	/* error msg already printed */
	}
	return(0);
}

struct flash_cmdset flash_cmdset_intel = {
	.cmdset_name		= "Intel",
	.reset_cmd		= intel_reset_cmd,
	.status_cmd		= intel_status_cmd,
	.unlock_sector		= intel_sector_unlock,
	.erase_sector		= intel_sector_erase,
	.prep_for_program	= intel_clear_sr,
	.read_prot_reg		= intel_read_prot_reg,
	.loadagent_setbase_cmd	= "INFB",
	.loadagent_program_cmd	= "INFW",
	.loadagent_binmode_cmd	= "INFWB",
	.needs_unlock		= 1,
};

struct flash_cmdset flash_cmdset_intel_w30 = {
	.cmdset_name		= "Intel",
	.reset_cmd		= intel_w30_reset_cmd,
	.status_cmd		= intel_w30_status_cmd,
	.unlock_sector		= intel_sector_unlock,
	.erase_sector		= intel_sector_erase,
	.prep_for_program	= intel_w30_clear_sr,
	.read_prot_reg		= intel_read_prot_reg,
	.loadagent_setbase_cmd	= "INFB",
	.loadagent_program_cmd	= "INFW",
	.loadagent_binmode_cmd	= "INFWB",
	.needs_unlock		= 1,
};