Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/bitsy/devflash.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname bitsy/devflash.c 2000/1031
## diff -e /dev/null /n/emeliedump/2000/1031/sys/src/9/bitsy/devflash.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"

/* flash partitions */
typedef struct FlashPart FlashPart;
struct FlashPart
{
	QLock;
	char	name[NAMELEN];
	ulong	start;		/* byte offsets */
	ulong	end;
};
.
## diffname bitsy/devflash.c 2000/1107
## diff -e /n/emeliedump/2000/1031/sys/src/9/bitsy/devflash.c /n/emeliedump/2000/1107/sys/src/9/bitsy/devflash.c
17a

static ulong *flash = (ulong*)FLASHZERO;

/*
 *  on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit
 *  accesses, one to the low half of the chip and the other to the high
 *  half.  Therefore for all command accesses, ushort indices in the
 *  manuals turn into ulong indices in our code.  Also, by copying all
 *  16 bit commands to both halves of a 32 bit command, we erase 2
 *  sectors for each request erase request.
 */

/*
 *  common flash memory interface
 */
enum
{
	CFIidoff=	0x10,
	CFIsysoff=	0x1B,
	CFIgeomoff=	0x27,
};

struct CFIid
{
	ulong	q;
	ulong	r;
	ulong	y;
	ulong	cmd_set;
	ulong	vendor_alg;
	ulong	ext_alg_addr[2];
	ulong	alt_cmd_set;
	ulong	alt_vendor_alg;
	ulong	alt_ext_ald_addr[2];
	
};

struct CFIsys
{
	ulong 	vcc_min;	/* 100 mv */
	ulong	vcc_max;
	ulong	vpp_min;
	ulong	vpp_max;
	ulong	word_wr_to;		/* 2**n µs */
	ulong	buf_wr_to;		/* 2**n µs */
	ulong	block_erase_to;		/* 2**n ms */
	ulong	chip_erase_to;		/* 2**n ms */
	ulong	max_word_wr_to;		/* 2**n µs */
	ulong	max_buf_wr_to;		/* 2**n µs */
	ulong	max_block_erase_to;	/* 2**n ms */
	ulong	max_chip_erase_to;	/* 2**n ms */
};

struct CFIgeom
{
	ulong	size;		/* 2**n bytes */
	ulong	
};
.
## diffname bitsy/devflash.c 2000/1111
## diff -e /n/emeliedump/2000/1107/sys/src/9/bitsy/devflash.c /n/emeliedump/2000/1111/sys/src/9/bitsy/devflash.c
73c
	ulong	dev_code;	/* ??? */
	ulong	max_multi;	/* max bytes in a multibyte write */
	ulong	nregion;	/* number of erase regions */
	ulong	region[1];	/* erase region info */
};

#define mirror(x) (((x)<<16)|(x))

void
cfiquery(void)
{
	struct CFIid *id;

	flash[0x55] = mirror(0x98);
	id = (struct CFIid*)&flash[0x10];
	if(id.q != 'q' || id.r != 'r' || id.y != 'y')
		print("CFI not supported by flash\n");
	
	flash[0x55] = mirror(0xFF);
}

void
cfigeom(void)
{
}

/*
 *  flash device interface
 */

enum
{
	Qf0=1,
	Qf1,
	Qf2,
	Qf3,
};

Dirtab flashdir[]={
	"f0",		{ Qf0, 0 },	0,	0664,
	"f1",		{ Qf1, 0 },	0,	0664,
	"f2",		{ Qf2, 0 },	0,	0664,
	"f3",		{ Qf3, 0 },	0,	0664,
};

void
flashinit(void)
{
	cfiquery();
	cfigeom();
}

static Chan*
flashattach(char* spec)
{
	return devattach('r', spec);
}

static int	 
flashwalk(Chan* c, char* name)
{
	return devwalk(c, name, flashdir, nelem(flashdir), devgen);
}

static void	 
flashstat(Chan* c, char* dp)
{
	devstat(c, dp, flashdir, nelem(flashdir), devgen);
}

static Chan*
flashopen(Chan* c, int omode)
{
	omode = openmode(omode);
	if(strcmp(up->user, eve)!=0)
		error(Eperm);
	return devopen(c, omode, flashdir, nelem(flashdir), devgen);
}

static void	 
flashclose(Chan*)
{
}

static long	 
flashread(Chan* c, void* a, long n, vlong off)
{
	USED(c, a, off);
	error("UUO");
	return n;
}

static long	 
flashwrite(Chan* c, void* a, long n, vlong)
{
	USED(c, a, off);
	error("UUO");
	return n;
}

Dev flashdevtab = {
	'F',
	"flash",

	devreset,
	flashinit,
	flashattach,
	devclone,
	flashwalk,
	flashstat,
	flashopen,
	devcreate,
	flashclose,
	flashread,
	devbread,
	flashwrite,
	devbwrite,
	devremove,
	devwstat,
.
33,39d
## diffname bitsy/devflash.c 2000/1117
## diff -e /n/emeliedump/2000/1111/sys/src/9/bitsy/devflash.c /n/emeliedump/2000/1117/sys/src/9/bitsy/devflash.c
185a


/* intel/sharp extended command set */
static void
ise_reset(void)
{
	flash.p[0x55] = mirror(0xff);	/* reset */
}
static void
ise_id(void)
{
	ise_reset();
	flash.p[0x555] = mirror(0x90);	/* uncover vendor info */
	flash.manid = flash.p[00];
	flash.devid = flash.p[01];
	ise_reset();
}
static void
ise_clearerror(void)
{
	flash.p[0x100] = mirror(0x50);

}
static void
ise_error(int bank, ulong status)
{
	char err[ERRLEN];

	if(status & (1<<3)){
		sprint(err, "flash%d: low prog voltage", bank);
		error(err);
	}
	if(status & (1<<1)){
		sprint(err, "flash%d: block locked", bank);
		error(err);
	}
	if(status & (1<<5)){
		sprint(err, "flash%d: i/o error", bank);
		error(err);
	}
}
static void
ise_erase(ulong addr)
{
	ulong start;
	ulong x;

	addr >>= 2;	/* convert to ulong offset */

	flashprogpower(1);
	flash.p[addr] = mirror(0x20);
	flash.p[addr] = mirror(0xd0);
	start = m->ticks;
	do {
		x = flash.p[addr];
		if((x & mirror(1<<7)) == mirror(1<<7))
			break;
	} while(TK2MS(m->ticks-start) < 1500);
	flashprogpower(0);

	ise_clearerror();
	ise_error(0, x);
	ise_error(1, x>>16);

	ise_reset();
}
/*
 *  flash writing goes about 16 times faster if we use
 *  the write buffer.  We fill the write buffer and then
 *  issue the write request.  After the write request,
 *  subsequent reads will yield the status register or,
 *  since error bits are sticky, another write buffer can
 *  be filled and written.
 *
 *  On timeout, we issue a read status register request so
 *  that the status register can be read no matter how we
 *  exit.
 */
static int
ise_wbwrite(ulong *p, int n, ulong off)
{
	ulong start;
	int i;

	/* copy out of user space to avoid faults later */
	memmove(flash.wb, p, n*4);
	p = flash.wb;

	/* put flash into write buffer mode */
	start = m->ticks;
	for(;;) {
		/* request write buffer mode */
		flash.p[off] = mirror(0xe8);

		/* look at extended status reg for status */
		if((flash.p[off] & mirror(1<<7)) == mirror(1<<7))
			break;

		/* didn't work, keep trying for 2 secs */
		if(TK2MS(m->ticks-start) > 2000){
			/* set up to read status */
			flash.p[off] = mirror(0x70);
			return -1;
		}
	}

	/* fill write buffer */
	flash.p[off] = mirror(n-1);
	for(i = 0; i < n; i++)
		flash.p[off+i] = *p++;

	/* program from buffer */
	flash.p[off] = mirror(0xd0);

	/* subsequent reads will return status about the write */

	return n;
}
static void
ise_write(void *a, long n, ulong off)
{
	ulong *p, *end;
	int i, wbsize;
	ulong x, start, ooff;

	/* everything in terms of ulongs */
	wbsize = flash.wbsize>>2;
	off >>= 2;
	n >>= 2;
	p = a;
	ooff = off;

	/* first see if write will succeed */
	for(i = 0; i < n; i++)
		if((p[i] & flash.p[off+i]) != p[i])
			error("flash needs erase");

	if(waserror()){
		ise_reset();
		flashprogpower(0);
		nexterror();
	}
	flashprogpower(1);

	/*
	 *  use the first write to reach
 	 *  a write buffer boundary.  the intel maunal
	 *  says writes startng at wb boundaries
	 *  maximize speed.
	 */
	i = wbsize - (off & (wbsize-1));
	for(end = p + n; p < end;){
		if(i > end - p)
			i = end - p;

		if(ise_wbwrite(p, i, off) != i)
			break;

		off += i;
		p += i;
		i = wbsize;
	}

	/* wait till the programming is done */
	start = m->ticks;
	do {
		x = flash.p[ooff];
		if((x & mirror(1<<7)) == mirror(1<<7))
			break;
	} while(TK2MS(m->ticks-start) < 1000);

	ise_clearerror();
	ise_error(0, x);
	ise_error(1, x>>16);

	ise_reset();
	flashprogpower(0);
	poperror();
}

/* amd/fujitsu standard command set
 *	I don't have an amd chipset to work with
 *	so I'm loathe to write this yet.  If someone
 *	else does, please send it to me and I'll
 *	incorporate it -- [email protected]
 */
static void
afs_reset(void)
{
	flash.p[0x55] = mirror(0xf0);	/* reset */
}
static void
afs_id(void)
{
	afs_reset();
	flash.p[0x55] = mirror(0xf0);	/* reset */
	flash.p[0x555] = mirror(0xaa);	/* query vendor block */
	flash.p[0x2aa] = mirror(0x55);
	flash.p[0x555] = mirror(0x90);
	flash.manid = flash.p[00];
	afs_reset();
	flash.p[0x555] = mirror(0xaa);	/* query vendor block */
	flash.p[0x2aa] = mirror(0x55);
	flash.p[0x555] = mirror(0x90);
	flash.devid = flash.p[01];
	afs_reset();
}
static void
afs_erase(ulong)
{
	error("amd/fujistsu erase not implemented");
}
static void
afs_write(void*, long, ulong)
{
	error("amd/fujistsu write not implemented");
}
.
161,162c
	if(c->qid.path & CHDIR)
		error(Eperm);

	if(!iseve())
		error(Eperm);

	switch(c->qid.path){
	default:
		panic("flashwrite");
	case Qfctl:
		return flashctlwrite(a, n);
	case Qfdata:
		return flashdatawrite(a, n, off);
	}
.
159c
flashwrite(Chan* c, void* a, long n, vlong off)
.
157a
static void
bootprotect(ulong addr)
{
	FlashRegion *r;

	if(flash.bootprotect == 0)
		return;
	if(flash.nr == 0)
		error("writing over boot loader disallowed");
	r = flash.r;
	if(addr >= r->addr && addr < r->addr + r->size)
		error("writing over boot loader disallowed");
}

ulong
blockstart(ulong addr)
{
	FlashRegion *r, *e;
	ulong x;

	r = flash.r;
	for(e = &flash.r[flash.nr]; r < e; r++)
		if(addr >= r->addr && addr < r->end){
			x = addr - r->addr;
			x /= r->size;
			return r->addr + x*r->size;
		}
			
	return (ulong)-1;
}

ulong
blockend(ulong addr)
{
	FlashRegion *r, *e;
	ulong x;

	r = flash.r;
	for(e = &flash.r[flash.nr]; r < e; r++)
		if(addr >= r->addr && addr < r->end){
			x = addr - r->addr;
			x /= r->size;
			return r->addr + (x+1)*r->size;
		}
			
	return (ulong)-1;
}

static long
flashctlwrite(char *p, long n)
{
	Cmdbuf *cmd;
	ulong addr;

	cmd = parsecmd(p, n);
	wlock(&flash);
	if(waserror()){
		wunlock(&flash);
		nexterror();
	}
	if(strcmp(cmd->f[0], "erase") == 0){
		if(cmd->nf != 2)
			error(Ebadarg);
		addr = atoi(cmd->f[1]);
		if(addr != blockstart(addr))
			error("erase must be a block boundary");
		bootprotect(addr);
		(*flash.alg->erase)(addr);
	} else if(strcmp(cmd->f[0], "protectboot") == 0){
		if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
			flash.bootprotect = 1;
		else
			flash.bootprotect = 0;
	} else
		error(Ebadarg);
	poperror();
	wunlock(&flash);
	free(cmd);

	return n;
}

static long
flashdatawrite(uchar *p, long n, long off)
{
	uchar *end;
	int m;
	long ooff = off;
	uchar *op = p;

	if((off & 0x3) || (n & 0x3))
		error("only quad writes");
	if(off >= flash.size || off+n > flash.size || n <= 0)
		error(Ebadarg);

	wlock(&flash);
	if(waserror()){
		wunlock(&flash);
		nexterror();
	}

	/* make sure we're not writing the boot sector */
	bootprotect(off);

	/* (*flash.alg->write) can't cross blocks */
	for(end = p + n; p < end; p += m){
		m = blockend(off) - off;
		if(m > end - p)
			m = end - p;
		(*flash.alg->write)(p, m, off);
		off += m;
	}

	/* make sure write succeeded */
	if(memcmp(op, &flash.p[ooff>>2], n) != 0)
		error("written bytes don't match");

	wunlock(&flash);
	poperror();

	return n;
}

.
153,154c
	char *buf, *p, *e;
	int i;

	if(c->qid.path&CHDIR)
		return devdirread(c, a, n, flashdir, nelem(flashdir), devgen);
	switch(c->qid.path){
	default:
		error(Eperm);
	case Qfctl:
		buf = smalloc(1024);
		e = buf + 1024;
		p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9lux\n", flash.size,
			flash.wbsize, flash.manid, flash.devid);
		for(i = 0; i < flash.nr; i++)
			p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", flash.r[i].addr,
				flash.r[i].n, flash.r[i].size);
		n = readstr(off, a, n, buf);
		free(buf);
		break;
	case Qfdata:
		if(!iseve())
			error(Eperm);
		if(off >= flash.size)
			return 0;
		if(off + n > flash.size)
			n = flash.size - off;
		rlock(&flash);
		if(waserror()){
			runlock(&flash);
			nexterror();
		}
		memmove(a, ((uchar*)FLASHZERO)+off, n);
		runlock(&flash);
		poperror();
		break;
	}
.
121c
	return devattach('F', spec);
.
115c
	for(i = 0; i < nelem(falg); i++)
		if(flash.algid == falg[i].id){
			flash.alg = &falg[i];
			(*flash.alg->identify)();
			break;
		}
	flash.bootprotect = 1;
.
113a
	int i;

	flash.p = (ulong*)FLASHZERO;
.
105,108c
	"flashctl",		{ Qfctl, 0 },	0,	0664,
	"flashdata",		{ Qfdata, 0 },	0,	0660,
.
98,101c
	Qfctl=1,
	Qfdata,
.
91a
static ulong
cfigetl(int off)
{
	return (cfigetc(off+3)<<24)|(cfigetc(off+2)<<16)|
		(cfigetc(off+1)<<8)|cfigetc(off);
}

static void
cfiquery(void)
{
	uchar q, r, y;
	ulong x, addr;

	q = cfigetc(0x10);
	r = cfigetc(0x11);
	y = cfigetc(0x12);
	if(q != 'Q' || r != 'R' || y != 'Y'){
		print("cfi query failed: %ux %ux %ux\n", q, r, y);
		return;
	}
	flash.algid = cfigetc(0x13);
	flash.size = 1<<(cfigetc(0x27)+1);
	flash.wbsize = 1<<(cfigetc(0x2a)+1);
	flash.nr = cfigetc(0x2c);
	if(flash.nr > nelem(flash.r)){
		print("cfi reports > %d regions\n", nelem(flash.r));
		flash.nr = nelem(flash.r);
	}
	addr = 0;
	for(q = 0; q < flash.nr; q++){
		x = cfigetl(q+0x2d);
		flash.r[q].size = 2*256*(x>>16);
		flash.r[q].n = (x&0xffff)+1;
		flash.r[q].addr = addr;
		addr += flash.r[q].size*flash.r[q].n;
		flash.r[q].end = addr;
	}
	flash.wb = malloc(flash.wbsize);
}

.
89a
	return (cfigetc(off+1)<<8)|cfigetc(off);
.
87,88c
static ushort
cfigets(int off)
.
79,84c
	flash.p[0x55] = mirror(0x98);
	rv = flash.p[off];
	flash.p[0x55] = mirror(0xFF);
	return rv;
.
77c
	uchar rv;
.
74,75c
/*
 *  common flash interface
 */
static uchar
cfigetc(int off)
.
72c
struct
{
	RWlock;
	ulong		*p;
	ushort		algid;		/* access algorithm */
	FlashAlg	*alg;
	ushort		manid;		/* manufacturer id */
	ushort		devid;		/* device id */
	ulong		size;		/* size in bytes */
	int		wbsize;		/* size of write buffer */ 
	ulong		nr;		/* number of regions */
	uchar		bootprotect;
	FlashRegion	r[32];
	ulong		*wb;		/* staging area for write buffer */
} flash;
.
65,69c
	{ 1,	"Intel/Sharp Extended",	ise_id, ise_erase, ise_write	},
	{ 2,	"AMD/Fujitsu Standard",	afs_id, afs_erase, afs_write	},
.
63c
static void	ise_id(void);
static void	ise_erase(ulong);
static void	ise_write(void*, long, ulong);

static void	afs_id(void);
static void	afs_erase(ulong);
static void	afs_write(void*, long, ulong);

FlashAlg falg[] =
.
49,60c
	int	id;
	char	*name;
	void	(*identify)(void);	/* identify device */
	void	(*erase)(ulong);	/* erase a region */
	void	(*write)(void*, long, ulong);	/* write a region */
.
47c
/* this defines a particular access algorithm */
typedef struct FlashAlg FlashAlg;
struct FlashAlg
.
35,44c
	ulong	addr;		/* start of region */
	ulong	end;		/* end of region + 1 */
	ulong	n;		/* number of blocks */
	ulong	size;		/* size of each block */
.
30,33c
#define mirror(x) (((x)<<16)|(x))

/* this defines a contiguous set of erase blocks of one size */
typedef struct FlashRegion FlashRegion;
struct FlashRegion
.
9,20d
## diffname bitsy/devflash.c 2000/1207
## diff -e /n/emeliedump/2000/1117/sys/src/9/bitsy/devflash.c /n/emeliedump/2000/1207/sys/src/9/bitsy/devflash.c
373,374c
	case Qfpart:
		return flashdatawrite(c, a, n, off);
.
368c
	switch(FTYPE(c->qid.path)){
.
340a
	ooff = off;
.
336a
	if(fp->name[0] == 0)
		error("partition vanished");
	if(!iseve())
		error(Eperm);

	if((off & 0x3) || (n & 0x3))
		error("only quad writes");
	off += fp->start;
	if(off >= fp->end || off+n > fp->end || n <= 0)
		error(Ebadarg);

.
326,329c
	fp = FPART(c->qid.path);
.
324a
	FPart *fp;
.
323c
	long ooff;
.
319c
flashdatawrite(Chan *c, uchar *p, long n, long off)
.
299,303c
		rempart(cmd->f[1]);
.
296a
		if(cmd->nf < 2)
			error(Ebadarg);
		fp = findpart(cmd->f[1]);
		if(fp == nil)
			error("no such partition");

		switch(cmd->nf){
		case 3:
			/* erase a single block */
			off = atoi(cmd->f[2]);
			off += fp->start;
			if(off >= fp->end)
				error("region not in partition");
			if(off != blockstart(off))
				error("erase must be a block boundary");
			bootprotect(off);
			(*flash.alg->erase)(off);
			break;
		case 2:
			/* erase the whole partition */
			bootprotect(fp->start);
			for(off = fp->start; off < fp->end; off = blockend(off))
				(*flash.alg->erase)(off);
			break;
		default:
			error(Ebadarg);
		}
	} else if(strcmp(cmd->f[0], "add") == 0){
		if(cmd->nf != 4)
			error(Ebadarg);
		addpart(cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
	} else if(strcmp(cmd->f[0], "remove") == 0){
.
288c
	ulong off;
	FPart *fp;
.
267c
static ulong
.
250c
static ulong
.
228c
		if(fp->name[0] == 0)
			error("partition vanished");
		if(!iseve())
			error(Eperm);
		off += fp->start;
		if(off >= fp->end)
			n = 0;
		if(off+n >= fp->end)
			n = fp->end - off;
		if(n > 0)
			memmove(a, ((uchar*)FLASHZERO)+off, n);
.
216,222c
	case Qfpart:
		fp = FPART(c->qid.path);
.
201,202c
		return devdirread(c, a, n, nil, 0, gen);
	switch(FTYPE(c->qid.path)){
.
198a
	FPart *fp;
.
186c
	return devopen(c, omode, nil, 0, gen);
.
177c
	devstat(c, dp, nil, 0, gen);
.
171c
	return devwalk(c, name, nil, 0, gen);
.
159a

	addpart("whole", 0, flash.size);
.
145a
#define FQID(p,q)	((p)<<8|(q))
#define FTYPE(q)	((q) & 0xff)
#define FPART(q)	(&part[(q) >>8])

static int
gen(Chan *c, Dirtab*, int, int i, Dir *dp)
{
	Qid q;
	char buf[32];
	FPart *fp;

	q.vers = 0;

	/* top level directory contains the name of the network */
	if(c->qid.path == CHDIR){
		switch(i){
		case DEVDOTDOT:
			q.path = CHDIR;
			devdir(c, q, ".", 0, eve, CHDIR|0555, dp);
			break;
		case 0:
			q.path = CHDIR | Q2nddir;
			strcpy(buf, "flash");
			devdir(c, q, buf, 0, eve, CHDIR|0555, dp);
			break;
		default:
			return -1;
		}
		return 1;
	}

	/* second level contains ctl plus all partitions */
	switch(i) {
	case DEVDOTDOT:
		q.path = CHDIR;
		devdir(c, q, "#F", 0, eve, CHDIR|0555, dp);
		break;
	case 0:
		q.path = Qfctl;
		devdir(c, q, "ctl", 0, eve, 0666, dp);
		break;
	default:
		i -= 1;
		if(i >= Maxpart)
			return -1;
		fp = &part[i];
		if(fp->name[0] == 0)
			return 0;
		q.path = FQID(i, Qfpart);
		devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
		break;
	}
	return 1;
}

static FPart*
findpart(char *name)
{
	int i;

	for(i = 0; i < Maxpart; i++)
		if(strcmp(name, part[i].name) == 0)
			break;
	if(i >= Maxpart)
		return nil;
	return &part[i];
}

static void
addpart(char *name, ulong start, ulong end)
{
	int i;
	FPart *fp;

	if(start >= flash.size || end > flash.size)
		error(Ebadarg);
	if(blockstart(start) != start)
		error("must start on erase boundary");
	if(blockstart(end) != end && end != flash.size)
		error("must end on erase boundary");
	fp = findpart(name);
	if(fp != nil)
		error(Eexist);
	for(i = 0; i < Maxpart; i++)
		if(part[i].name[0] == 0)
			break;
	if(i == Maxpart)
		error("no more partitions");
	fp = &part[i];
	strncpy(fp->name, name, sizeof(fp->name)-1);
	fp->start = start;
	fp->end = end;
}

static void
rempart(char *name)
{
	FPart *fp;

	/* can't remove the total partition */
	fp = findpart(name);
	if(fp != nil)
		fp->name[0] = 0;
}

.
144a
static FPart	part[Maxpart];
.
141,143c

typedef struct FPart FPart;
struct FPart
{
	char	name[NAMELEN];
	ulong	start;
	ulong	end;
.
137,138c
	Qtopdir,
	Q2nddir,
	Qfctl,
	Qfpart,

	Maxpart= 8,
.
48a
static ulong	blockstart(ulong);
static ulong	blockend(ulong);

.
## diffname bitsy/devflash.c 2000/1209
## diff -e /n/emeliedump/2000/1207/sys/src/9/bitsy/devflash.c /n/emeliedump/2000/1209/sys/src/9/bitsy/devflash.c
725,732d
718c
		if(ise_wbwrite(p, i, off, baddr, &x) < 0)
.
693c
	baddr >>= 2;
.
689a
	baddr = blockstart(off);
.
686c
	ulong x, baddr;
.
677c
	/* wait till the programming is done */
	start = m->ticks;
	for(;;) {
		x = *status = flash.p[baddr];	/* read status register */
		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
			break;
		if(TK2MS(m->ticks-start) > 2000){
			pprint("read status timed out\n");
			return -1;
		}
	}
	if(x & mirror(ISEs_err))
		return -1;
.
675c
	flash.p[baddr] = mirror(0xd0);
	splx(s);
.
670c
	flash.p[baddr] = mirror(n-1);
.
664c
			flash.p[baddr] = mirror(0x70);
			*status = flash.p[baddr];
			pprint("write buffered cmd timed out\n");
.
659a
		splx(s);
.
658c
		if((flash.p[baddr] & mirror(1<<7)) == mirror(1<<7))
.
655c
		flash.p[baddr] = mirror(0xe8);
.
653a
		s = splhi();
.
647,650d
645a
	int s;
.
644c
	ulong x, start;
.
641,642c
static ulong
ise_wbwrite(ulong *p, int n, ulong off, ulong baddr, ulong *status)
.
639a
 *
 *  returns the status.
.
630c
 *  the flash spec claimes writing goes faster if we use
.
618c
		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
.
599,600c
	if(status & (ISEs_progerr|ISEs_eraseerr)){
		sprint(err, "flash%d: i/o error %lux", bank, status);
.
595,596c
	if(status & (ISEs_powererr)){
		sprint(err, "flash%d: low prog voltage %lux", bank, status);
.
591,592c
	if(status & (ISEs_lockerr)){
		sprint(err, "flash%d: block locked %lux", bank, status);
.
564a
	/* extended status register */
	ISExs_bufavail=		1<<7,
};



.
563a
enum
{
	/* status register */
	ISEs_lockerr=		1<<1,
	ISEs_powererr=		1<<3,
	ISEs_progerr=		1<<4,
	ISEs_eraseerr=		1<<5,
	ISEs_ready=		1<<7,
	ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
.
509c
		if(m > Maxwchunk)
			m = Maxwchunk;
		memmove(flash.wb, p, m);
		(*flash.alg->write)(flash.wb, m, off);
.
131c
	flash.wb = malloc(flash.wbsize>1024 ? flash.wbsize : 1024);
.
73a
enum
{
	Maxwchunk=	1024,	/* maximum chunk written by one call to falg->write */
};

.
## diffname bitsy/devflash.c 2000/1211
## diff -e /n/emeliedump/2000/1209/sys/src/9/bitsy/devflash.c /n/emeliedump/2000/1211/sys/src/9/bitsy/devflash.c
664c
 *  NOTE: I tried starting back to back buffered writes
 *	without reading the status in between, as the
 *	flowchart in the intel data sheet suggests.
 *	However, it always responded with an illegal
 *	command sequence, so I must be missing something.
 *	If someone learns better, please email me, though
 *	I doubt it will be much faster. -  [email protected]
.
660,662c
 *  returns the status, even on timeouts.
.
656,658c
 *  subsequent reads will yield the status register.
.
## diffname bitsy/devflash.c 2000/1213
## diff -e /n/emeliedump/2000/1211/sys/src/9/bitsy/devflash.c /n/emeliedump/2000/1213/sys/src/9/bitsy/devflash.c
544,546c
		n = flashctlwrite(FPART(c->qid.path), a, n);
		break;
	case Qfdata:
		n = flashdatawrite(FPART(c->qid.path), a, n, off);
		break;
.
528c
	return on;
.
525a
	free(buf);
.
522c
	if(memcmp(buf, &flash.p[ooff>>2], n) != 0)
.
516,517c
		(*flash.alg->write)(p, m, off);
.
509a
	p = buf;
.
507a
	on = n;

	/*
	 *  get the data into kernel memory to avoid faults during writing.
	 *  if write is not on a quad boundary or not a multiple of 4 bytes,
	 *  extend with data already in flash.
	 */
	buf = smalloc(n+8);
	m = off & 3;
	if(m){
		*(ulong*)buf = flash.p[(off)>>2];
		n += m;
		off -= m;
	}
	if(n & 3){
		n -= n & 3;
		*(ulong*)(&buf[n]) = flash.p[(off+n)>>2];
		n += 4;
	}
	memmove(&buf[m], p, on);

.
499,500c
	/* can't cross partition boundaries */
.
490a
		if(buf != nil)
			free(buf);
.
487a
	buf = nil;
.
486c
	if(fp == nil)
		panic("flashctlwrite");
.
483,484c
	uchar *buf;
.
481a
	int on;
.
478c
flashdatawrite(FPart *fp, uchar *p, long n, long off)
.
460,462c
		rempart(fp);
.
458c
		addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
.
446c
		case 1:
.
435,437c
		case 2:
			/* erase a single block in the partition */
			off = atoi(cmd->f[1]);
.
428,433d
420a
	if(fp == nil)
		panic("flashctlwrite");

.
419d
415c
flashctlwrite(FPart *fp, char *p, long n)
.
341,360c
	case Qfdata:
		n = flashdataread(FPART(c->qid.path), a, n, off);
.
331,339c
		n = flashctlread(FPART(c->qid.path), a, n, off);
.
324a
	buf = smalloc(1024);
	e = buf + 1024;
	p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9lux\n", fp->end-fp->start,
		flash.wbsize, flash.manid, flash.devid);
	addr = fp->start;
	for(i = 0; i < flash.nr && addr < fp->end; i++)
		if(flash.r[i].addr <= addr && flash.r[i].end > addr){
			if(fp->end <= flash.r[i].end)
				end = fp->end;
			else
				end = flash.r[i].end;
			p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,
				(end-addr)/flash.r[i].size, flash.r[i].size);
			addr = end;
		}
	n = readstr(off, a, n, buf);
	free(buf);
	return n;
}

static long
flashdataread(FPart *fp, void* a, long n, vlong off)
{
	rlock(&flash);
	if(waserror()){
		runlock(&flash);
		nexterror();
	}
	if(fp->name[0] == 0)
		error("partition vanished");
	if(!iseve())
		error(Eperm);
	off += fp->start;
	if(off >= fp->end)
		n = 0;
	if(off+n >= fp->end)
		n = fp->end - off;
	if(n > 0)
		memmove(a, ((uchar*)FLASHZERO)+off, n);
	runlock(&flash);
	poperror();

	return n;
}

static long	 
flashread(Chan* c, void* a, long n, vlong off)
{
.
323c
	ulong addr, end;
.
318,319c
static long
flashctlread(FPart *fp, void* a, long n, vlong off)
.
283c
	addpart(nil, "flash", 0, flash.size);
.
260,265c
	fp->name[0] = 0;
.
258c
rempart(FPart *fp)
.
242a

.
237,238c
	if(strlen(name) > NAMELEN-3)
		error("name too long");
	if(fp == nil){
		if(start >= flash.size || end > flash.size)
			error(Ebadarg);
	} else {
		start += fp->start;
		end += fp->start;
		if(start >= fp->end || end > fp->end)
			error(Ebadarg);
	}
.
235d
232c
addpart(FPart *fp, char *name, ulong start, ulong end)
.
211,212c
		if(i & 1){
			q.path = FQID(i>>1, Qfdata);
			devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
		} else {
			snprint(buf, sizeof(buf), "%sctl", fp->name);
			q.path = FQID(i>>1, Qfctl);
			devdir(c, q, buf, 0, eve, 0660, dp);
		}
.
208c
		fp = &part[i>>1];
.
205,206c
		if(i >= 2*Maxpart)
.
200,203d
194c
	/* second level contains all partitions and their control files */
.
171c
	char buf[NAMELEN];
.
157c
	char	name[NAMELEN-4];
.
148c
	Qfdata,
.
136d
71d
## diffname bitsy/devflash.c 2001/0529
## diff -e /n/emeliedump/2000/1213/sys/src/9/bitsy/devflash.c /n/emeliedump/2001/0529/sys/src/9/bitsy/devflash.c
658c
	char err[64];
.
604d
584c
	t = FTYPE(c->qid.path);
	switch(t){
.
578c
	int t;

	if(c->qid.type == QTDIR)
.
517c
	if(fp->name == nil)
.
378c
	t = FTYPE(c->qid.path);
	switch(t){
.
376c
	int t;

	if(c->qid.type == QTDIR)
.
356c
	if(fp->name == nil)
.
304c
	return devstat(c, db, n, nil, 0, gen);
.
301,302c
static int	 
flashstat(Chan *c, uchar *db, int n)
.
298c
	return devwalk(c, nc, name, nname, nil, 0, gen);
.
295,296c
static Walkqid*
flashwalk(Chan *c, Chan *nc, char **name, int nname)
.
268c
	char *p;

	p = fp->name;
	fp->name = nil;
	free(p);
.
260c
	kstrdup(&fp->name, name);
.
235,236d
209a
			q.type = QTFILE;
.
205a
			q.type = QTFILE;
.
202c
		if(fp->name == nil)
.
195,196c
		q.path = Qtopdir;
		q.type = QTDIR;
		devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
.
182,184c
			q.path = Q2nddir;
			q.type = QTDIR;
			devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
.
178,179c
			q.path = Qtopdir;
			q.type = QTDIR;
			devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
.
175c
	if(c->qid.path == Qtopdir){
.
169c
	char buf[KNAMELEN];
.
166c
gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
.
155c
	char	*name;
.
## diffname bitsy/devflash.c 2001/0605
## diff -e /n/emeliedump/2001/0529/sys/src/9/bitsy/devflash.c /n/emeliedump/2001/0605/sys/src/9/bitsy/devflash.c
257c
		if(part[i].name == nil)
.
227c
		if(part[i].name != nil && strcmp(name, part[i].name) == 0)
.
## diffname bitsy/devflash.c 2001/0614
## diff -e /n/emeliedump/2001/0605/sys/src/9/bitsy/devflash.c /n/emeliedump/2001/0614/sys/src/9/bitsy/devflash.c
274a
	free(cp);
.
273a
	cp = fp->ctlname;
	fp->ctlname = nil;
.
270c
	char *p, *cp;
.
262a
	snprint(ctlname, sizeof ctlname, "%sctl", name);
	kstrdup(&fp->ctlname, ctlname);
.
237a
	char ctlname[64];
.
214c
			devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
.
211d
169d
155a
	char	*ctlname;
.
## diffname bitsy/devflash.c 2002/0109
## diff -e /n/emeliedump/2001/0614/sys/src/9/bitsy/devflash.c /n/emeliedump/2002/0109/sys/src/9/bitsy/devflash.c
619a
	devshutdown,
.
## diffname bitsy/devflash.c 2002/0404
## diff -e /n/emeliedump/2002/0109/sys/src/9/bitsy/devflash.c /n/emeliedump/2002/0404/sys/src/9/bitsy/devflash.c
341c
	p = seprint(buf, e, "0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n", fp->end-fp->start,
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].