I'm so !@&#$^*& close I can taste it.

I can erase the part.
I can write the the part.
I properly avoid the EC code.  No bricks yet.

What I can't do is write anything other than a zero. :(

For whatever reason my writes into the SPIDAT (0xfeab) register don't
work.  I've verified this in both the olpcflash.c and in my own little
utilites that just read and write EC registers.

I can write to each of the registers before and after SPIDAT and I can
read from SPIDAT just fine after a READ command.  But write to SPIDAT
and then do a read and you just get zero.

The attached olpcflash.c will erase your SPI flash from 0x10000 to
0xfffff. And then it trys to write 256 bytes from the file you give it

olpcflash -w <filename>

After it tries to put the data to write into the SPIDAT register it
will read it back print it out issue the write and then try to verify
the byte.

Fails every time.

olpcflash -r dump
hd dump | less

You will see a file that is entirely 0xff except for the fist 2 bytes
which are zero.  Why 2 and not 1?  I don't know yet.  But this shows I
wrote to the part with exactly what was in the register.

Also attached are 2 small utilites that allow you to read and write EC
registers.
inreg and outreg.

You can do the following:

outreg 0xfeab 0xaa
inreg 0xfeab
will print '00'

Do the same with 0xfeaa or 0xfeac and it works.

Ray???

--
Richard A. Smith
/*
 * flash_rom.c: Flash programming utility
 *
 * Copyright 2000 Silicon Integrated System Corporation
 * Copyright 2004 Tyan Corp
 *	yhlu [EMAIL PROTECTED] add exclude start and end option
 * Copyright 2005-2006 coresystems GmbH 
 *      Stefan Reinauer <[EMAIL PROTECTED]> added rom layout
 *      support, and checking for suitable rom image, various fixes
 *      support for flashing the Technologic Systems 5300.
 * 
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/io.h>

#define printf_debug(x...) { if(verbose) printf(x); }
#define printf_super_debug(x...) { if(verbose > 1) printf(x); }

#define LINUXBIOS_START 0x10000
enum {
	GPIO5 = 0xfc2a,
	SPIA0 = 0xfea8, 
	SPIA1, 
	SPIA2, 
	SPIDAT,
	SPICMD, 
	SPICFG,
	SPIDATR
};

enum {
	WRITESTATUS = 1,
	BYTEPROGRAM, 
	READ,
	WRITEDISABLE,
	READSTATUS,	
	WRITEENABLE,
	HIGHSPEEDREAD = 0xb,
	SECTORERASESST = 0x20, 
	ENABLEWRITESTATUSSST = 0x50,
	BLOCKERASESST = 0x52,
	CHIPERASESST = 0x60,
	CHIPERASEPCM = 0xc7, /* also nexflash */
	SECTORERASEPCM = 0xd7,
	BLOCKERASEPCM = 0xd8, /* also nexflash, and spansion */
};

enum {
	SPIBUSY = 2, 
	SPICMDWE = 8,
	SPIFLASHREADCE = 1 <<6
};

enum {
	WIP = 1 << 0
};

char *chip_to_probe = NULL;

int exclude_start_page, exclude_end_page;
int force=0, verbose=0;

/* this is the default hardware base address. 
  * 0x2d is the MSB, 0x2e is the LSB, 0x2f is the data
  */

unsigned short iobase = 0x381;

// count to a billion. Time it. If it's < 1 sec, count to 10B, etc.
unsigned long micro = 1;

void myusec_delay(int time)
{
	volatile unsigned long i;
	for (i = 0; i < time * micro; i++);
}

void myusec_calibrate_delay()
{
	int count = 1000;
	unsigned long timeusec;
	struct timeval start, end;
	int ok = 0;

	printf_debug("Setting up microsecond timing loop\n");
	while (!ok) {
		gettimeofday(&start, 0);
		myusec_delay(count);
		gettimeofday(&end, 0);
		timeusec = 1000000 * (end.tv_sec - start.tv_sec) +
		    (end.tv_usec - start.tv_usec);
		count *= 2;
		if (timeusec < 1000000 / 4)
			continue;
		ok = 1;
	}

	// compute one microsecond. That will be count / time
	micro = count / timeusec;

	printf_debug("%ldM loops per second\n", (unsigned long) micro);
}


void
setecindex(unsigned short index){
	unsigned char hi = index>>8;
	unsigned char lo = index;

	outb(hi, iobase);
	outb(lo, iobase+1);
	printf_super_debug("%s: set 0x%x to 0x%x, 0x%x to 0x%x\n", __FUNCTION__, 
		iobase, hi, iobase+1, lo);
}

unsigned char 
getecdata(void){
	unsigned char data;
	data = inb(iobase+2);
	printf_super_debug("%s: read 0x%x from 0x%x\n", __FUNCTION__, data, iobase+2);
	return data;
}

void
putecdata(unsigned char data){
	outb(data, iobase+2);
	printf_super_debug("%s: wrote 0x%x to 0x%x\n", __FUNCTION__, data, iobase+2);
}

unsigned char 
readecdata(unsigned short index){
	setecindex(index);
	return getecdata();
}

void
writeecdata(unsigned short index, unsigned char data){
	setecindex(index);
	putecdata(data);
}

void setaddr(unsigned long addr){
	unsigned char data;
	data = addr;
	writeecdata(SPIA0, data);
	data = addr >> 8;
	writeecdata(SPIA1, data);
	data = addr >> 16;
	writeecdata(SPIA2, data);
}

unsigned char 
rdata(){
	unsigned char data;
	data = readecdata(SPIDAT);
	return data;
}

void
wdata(unsigned char data){
	writeecdata(SPIDAT, data);
}

unsigned char
cmd(void){
	return readecdata(SPICMD);
}

void
docmd(unsigned char cmd){
	writeecdata(SPICMD, cmd);
	printf_super_debug("docmd: cmd 0x%x\n", cmd);
}

void
wait_cmd_sent(void){
	int trycount = 0;
	myusec_delay(10);
//	docmd(READSTATUS);
//	myusec_delay(1000);

	while (readecdata(SPICFG) & SPIBUSY){
		trycount++;
		myusec_delay(10);
		if (trycount > 100000){ /* 1 second! */
			printf("wait_sent: Err: waited for > 1 second\n");
			trycount = 0;
		}
	}
}	

// You must do the prior to _every_ command that
// writes data to the part.  The write enable
// latch resets after write commands complete.
void
send_write_enable(void) {
	docmd(WRITEENABLE);
	wait_cmd_sent();
	printf_debug("enabled flash write\n");
}

void
enable_flash_cmd(void){
	writeecdata(SPICFG, SPICMDWE|readecdata(SPICFG));
}

void 
enable_flash_write_protect(void){
	unsigned char val;
	val = readecdata(GPIO5);
	val &= ~0x80;
	writeecdata(GPIO5,val);
}

void 
disable_flash_write_protect(void){
	unsigned char val;
	val = readecdata(GPIO5);
	val |= 0x80;
	writeecdata(GPIO5,val);
}

/*
	This appears to be necessary.  If you watch the lines with 
	scope you will see that there is constant activity on the SPI
	bus to the part.  Trying to write to the port while all that
	is going on is sure to muck things up.
	Putting this into reset stops all that 
	activity.

	Plus Ray Tseng said so.

	It appears to work in read mode without this though.
*/
void put_kbc_in_reset(void){
	unsigned char val;
	unsigned long timeout = 500000;

	outb(0xd8,0x66);
	while((inb(0x66) & 0x02) & timeout>0) {
		timeout--;
	}
	val = readecdata(0xff14);
	val |= 0x01;
	writeecdata(0xff14,val);
}

void restore_kbc_run_mode(void){
	unsigned char val;

	val = readecdata(0xff14);
	val &= ~0x01;
	writeecdata(0xff14,val);
}

unsigned char read_status_register(void)
{
	unsigned char data=0;
	docmd(READSTATUS);
	wait_cmd_sent();
	data =  rdata();
	return data;
}

// Staus reg writes; erases and programs all need to 
// check this status bit.
int wait_write_done(void)
{
	int trycount = 0;
	myusec_delay(10);
//	docmd(READSTATUS);
//	myusec_delay(1000);

	while (read_status_register() & WIP){
		trycount++;
		myusec_delay(10);
		// The only thing that takes longer than 500mS is 
		// bulk erase and we don't ever want to use that
		// command
		if (trycount > 100000){ /* 1 second! */
			printf("wait_write_done: Err: waited for > 1 second\n");
			trycount = 0;
			return -1;
		}
	}
}	
 
int erase_sector(unsigned long addr) {
	send_write_enable();
	wait_cmd_sent();
	setaddr(addr);
	docmd(BLOCKERASEPCM);
	wait_cmd_sent();
	return wait_write_done();
}

/*
 Erase from sectors 0x10000 to 0xf0000
*/
int erase_linuxbios_area(void) {
	unsigned long addr;

	for (addr = 0x10000;addr < 0xfffff;addr+=0x10000) {
		printf("Erasing Sector: 0x%08x\r\n",addr);
		erase_sector(addr);
	}
	return 0;
}

int erase_flash(void)
{
	erase_linuxbios_area();
}

unsigned char 
read_flash_byte(unsigned long addr) {
	unsigned char data;

	setaddr(addr);
	docmd(READ);
	wait_cmd_sent();
	data =  rdata();
	printf_debug("read [EMAIL PROTECTED]", data, addr);
	return data;
}

int
read_flash(unsigned char *buf, unsigned long start, unsigned long stop){
	unsigned long i;

	for (i = start; i <= stop; i++) {
		if ((i % 0x10000) == 0)
			printf("Sector 0x%08x\r\n", i);
		*buf = read_flash_byte(i);
		buf++;
	}
	return 0;
}

int
write_flash_byte(unsigned long addr, unsigned char data) {
	unsigned char verify;
	
	send_write_enable();
	wait_cmd_sent();
	setaddr(addr);
	wdata(data);
	verify = rdata();
	printf("data = %x\r\n",verify);
	docmd(BYTEPROGRAM);
	wait_cmd_sent();
	wait_write_done();

	verify =  read_flash_byte(addr);
	if (verify != data) {
		printf("addr 0x%x, want 0x%x, got 0x%x\n", 
				addr, data, verify);
		return -1;
	}

	return 0;
}

int
write_flash(unsigned char *buf, unsigned long start, unsigned long end){
	unsigned long i;

	end = 0x100ff;
	printf("Writing...\r\n"); 
	for(i = start; i <= end; i++){
		if ((i % 0x10000) == 0)
			printf("Sector 0x%08x\r\n", i);
		if (write_flash_byte(i, *buf)) {
			return -1;
		}
		buf++;
	}

	return 0;
}

int verify_flash(unsigned char *buf)
{
	unsigned long idx;
	int total_size = 1024*1024;

	printf("Verifying flash ");
	
	if(verbose) printf("address: 0x00000000\b\b\b\b\b\b\b\b\b\b");
	
	for (idx = 0x10000; idx < total_size; idx++) {
		if (verbose && ( (idx & 0xfff) == 0xfff ))
			printf("0x%08x", idx);

		if (read_flash_byte(idx) != *(buf)) {
			if (verbose) {
				printf("0x%08x ", idx);
			}
			printf("- FAILED\n");
			return 1;
		}
		buf++;

		if (verbose && ( (idx & 0xfff) == 0xfff ))
			printf("\b\b\b\b\b\b\b\b\b\b");
	}
	if (verbose) 
		printf("\b\b\b\b\b\b\b\b\b\b ");
	
	printf("- VERIFIED         \n");
	return 0;
}


void usage(const char *name)
{
	printf("usage: %s [-rwvE] [-V] [-c chipname] [-s exclude_start] [-e exclude_end] [file]\n", name);
	printf("   -r | --read:   read flash and save into file\n"
	       "   -w | --write:  write file into flash (default when file is specified)\n"
	       "   -v | --verify: verify flash against file\n"
	       "   -E | --erase: Erase flash device\n"
	       "   -V | --verbose: more verbose output\n\n"
	       "   -c | --chip <chipname>: probe only for specified flash chip\n"
	       "   -s | --estart <addr>: exclude start position\n"
	       "   -e | --eend <addr>: exclude end postion\n"
	       "   -m | --mainboard <vendor:part>: override mainboard settings\n"
	       "   -f | --force: force write without checking image\n"
	       "   -l | --layout <file.layout>: read rom layout from file\n"
	       "   -i | --image <name>: only flash image name from flash layout\n"
	       "\n"
	       " If no file is specified, then all that happens\n"
	       " is that flash info is dumped\n\n");
	exit(1);
}

int main(int argc, char *argv[])
{
	unsigned char *buf;
	unsigned long size;
	FILE *image;
	int opt;
	int option_index = 0;
	int read_it = 0, 
	    write_it = 0, 
	    erase_it = 0, 
	    verify_it = 0;
	int ret = 0;
	static char flashimage[1048576];

	static struct option long_options[]= {
		{ "read", 0, 0, 'r' },
		{ "write", 0, 0, 'w' },
		{ "erase", 0, 0, 'E' },
		{ "verify", 0, 0, 'v' },
		{ "estart", 1, 0, 's' },
		{ "eend", 1, 0, 'e' },
		{ "iobase", 1, 0, 'i' },
		{ "verbose", 0, 0, 'V' },
		{ "help", 0, 0, 'h' },
		{ 0, 0, 0, 0 }
	};
	
	char *filename = NULL;
    unsigned int exclude_start_position=0, exclude_end_position=0; // [x,y)
	char *tempstr=NULL, *tempstr2=NULL;

	if (iopl(3) < 0){
		perror("iop(3)");
		exit(1);
	}

	setbuf(stdout, NULL);
	while ((opt = getopt_long(argc, argv, "rwvVEfc:s:e:m:l:i:h", long_options,
					&option_index)) != EOF) {
		switch (opt) {
		case 'r':
			read_it = 1;
			break;
		case 'w':
			write_it = 1;
			break;
		case 'v':
			verify_it = 1;
			break;
		case 'V':
			verbose++;
			break;
		case 'E':
			erase_it = 1;
			break;
		case 's':
			tempstr = strdup(optarg);
			sscanf(tempstr,"%x",&exclude_start_position);
			break;
		case 'i':
			tempstr = strdup(optarg);
			sscanf(tempstr,"%x",&iobase);
			break;
		case 'e':
			tempstr = strdup(optarg);
			sscanf(tempstr,"%x",&exclude_end_position);
			break;
		case 'h':
		default:
			usage(argv[0]);
			break;
		}
	}

	if (argc > 1) {
		/* Yes, print them. */
		int i;
		printf_debug ("The arguments are:\n");
		for (i = 1; i < argc; ++i)
			printf_debug ("%s\n", argv[i]);
	}

	if (read_it && write_it) {
		printf("-r and -w are mutually exclusive\n");
		usage(argv[0]);
	}

	if (optind < argc)
		filename = argv[optind++];

	printf("Calibrating delay loop... ");
	myusec_calibrate_delay();
	printf("ok\n");

	/* We look at the lbtable first to see if we need a
	 * mainboard specific flash enable sequence.
	 *
	linuxbios_init();
	*/
	enable_flash_cmd();

	if (!filename && !erase_it) {
		// FIXME: Do we really want this feature implicitly?
		printf("OK, only ENABLING flash write, but NOT FLASHING.\n");
		return 0;
	}

	size = (1024*1024) - (64*1024);
	buf = (unsigned char *) calloc(size, sizeof(char));
	
	if (erase_it) {
		erase_flash();
		exit(0);		
	} else if (read_it) {
		if ((image = fopen(filename, "w")) == NULL) {
			perror(filename);
			exit(1);
		}
		printf("Reading Flash...\r\n");
		read_flash(buf,LINUXBIOS_START,LINUXBIOS_START+size);

/*
		if (exclude_end_position - exclude_start_position > 0)
			memset(buf+exclude_start_position, 0,
			       exclude_end_position-exclude_start_position);
*/
		fwrite(buf, sizeof(char), size, image);
		fclose(image);
		printf("done\n");
	} else {
		if ((image = fopen(filename, "r")) == NULL) {
			perror(filename);
			exit(1);
		}
		printf("Loading 0x%x bytes from %s\r\n",size,filename);
		fread(buf, sizeof(char), size, image);
//		show_id(buf, size);
		fclose(image);
	}

	if (write_it) {
		put_kbc_in_reset();
		disable_flash_write_protect();
		erase_linuxbios_area();
		write_flash(buf,LINUXBIOS_START, LINUXBIOS_START+size-1);
		enable_flash_write_protect();
//		restore_kbc_run_mode();
	}

	if (verify_it)
		ret |= verify_flash(buf);

	if (buf) {
		free(buf);
	}
	return ret;
}



#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/io.h>

#define printf_debug(x...) { if(verbose) printf(x); }
#define printf_super_debug(x...) { if(verbose > 1) printf(x); }

int verbose=0;

/* this is the default hardware base address. 
  * 0x2d is the MSB, 0x2e is the LSB, 0x2f is the data
  */
unsigned short iobase = 0x381;

void
setecindex(unsigned short index){
	unsigned char hi = index>>8;
	unsigned char lo = index;

	outb(hi, iobase);
	outb(lo, iobase+1);
	printf_super_debug("%s: set 0x%x to 0x%x, 0x%x to 0x%x\n", __FUNCTION__, 
		iobase, hi, iobase+1, lo);
}

unsigned char 
getecdata(void){
	unsigned char data;
	data = inb(iobase+2);
	printf_super_debug("%s: read 0x%x from 0x%x\n", __FUNCTION__, data, iobase+2);
	return data;
}

void
putecdata(unsigned char data){
	outb(data, iobase+2);
	printf_super_debug("%s: wrote 0x%x to 0x%x\n", __FUNCTION__, data, iobase+2);
}

unsigned char 
readecdata(unsigned short index){
	setecindex(index);
	return getecdata();
}

void
writeecdata(unsigned short index, unsigned char data){
	setecindex(index);
	putecdata(data);
}

main(int argc, char *argv[]){
	unsigned char x;

	iopl(3);
	if (argc < 2) {
		printf("inreg <reg>\n");
		exit(1);
	}

	x = readecdata(strtoul(argv[1], 0, 0));
	printf("0x%02x\n", x);
}




#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/io.h>

#define printf_debug(x...) { if(verbose) printf(x); }
#define printf_super_debug(x...) { if(verbose > 1) printf(x); }

int verbose=0;

/* this is the default hardware base address. 
  * 0x2d is the MSB, 0x2e is the LSB, 0x2f is the data
  */
unsigned short iobase = 0x381;

void
setecindex(unsigned short index){
	unsigned char hi = index>>8;
	unsigned char lo = index;

	outb(hi, iobase);
	outb(lo, iobase+1);
	printf_super_debug("%s: set 0x%x to 0x%x, 0x%x to 0x%x\n", __FUNCTION__, 
		iobase, hi, iobase+1, lo);
}

unsigned char 
getecdata(void){
	unsigned char data;
	data = inb(iobase+2);
	printf_super_debug("%s: read 0x%x from 0x%x\n", __FUNCTION__, data, iobase+2);
	return data;
}

void
putecdata(unsigned char data){
	outb(data, iobase+2);
	printf_super_debug("%s: wrote 0x%x to 0x%x\n", __FUNCTION__, data, iobase+2);
}

unsigned char 
readecdata(unsigned short index){
	setecindex(index);
	return getecdata();
}

void
writeecdata(unsigned short index, unsigned char data){
	setecindex(index);
	putecdata(data);
}

main(int argc, char *argv[]){
	unsigned char x;

	iopl(3);
	if (argc < 3) {
		printf("outreg <reg> <data>\n");
		exit(1);
	}

	writeecdata(strtoul(argv[1], 0, 0),strtoul(argv[2], 0, 0));
}


_______________________________________________
Devel mailing list
[email protected]
http://mailman.laptop.org/mailman/listinfo/devel

Reply via email to