xref: /plan9/sys/src/9/ppc/devflash.c (revision 2cca75a1b2b8c6083390679d69d5c50cf66d9a01)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 enum {
9 	Nflash = 2,
10 	Maxwchunk=	1024,	/* maximum chunk written by one call to falg->write */
11 };
12 
13 
14 /*
15  *  Flashes are either 8 or 16 bits wide.  On some installations (e.g., the
16  *  bitsy, they are interleaved: address 0 is in the first chip, address 2
17  *  on the second, address 4 on the first, etc.
18  *  We define Funit as the unit that matches the width of a single flash chip,
19  *  so Funit is either `uchar' or `ushort' (I haven't seen 32-bit wide flashes),
20  *  and we define Fword as the unit that matches a set of interleaved Funits.
21  *  We access interleaved flashes simultaneously, by doing single reads and
22  *  writes to both.  The macro `mirror' takes a command and replicates it for
23  *  this purpose.
24  *  The Blast board has a non-interleaved 16-bit wide flash.  When doing
25  *  writes to it, we must swap bytes.
26  */
27 
28 typedef struct FlashAlg FlashAlg;
29 typedef struct Flash Flash;
30 typedef struct FlashRegion FlashRegion;
31 
32 #ifdef WIDTH8
33 	typedef		uchar		Funit;		/* Width of the flash (uchar or ushort) */
34 #	define		toendian(x)	(x)			/* Little or big endianness */
35 #	define		fromendian(x)	(x)
36 #	define		reg(x)		((x)<<1)
37 #	ifdef INTERLEAVED
38 #		define	mirror(x)		((x)<<8|(x))	/* Double query for interleaved flashes */
39 		typedef	ushort		Fword;		/* Width after interleaving */
40 #		define	Wshift		1
41 #	else
42 #		define 	mirror(x)		(x)
43 		typedef	uchar		Fword;
44 #		define	Wshift		0
45 #	endif
46 #else
47 	typedef		ushort		Funit;
48 #	define		toendian(x)	((x)<<8)
49 #	define		fromendian(x)	((x)>>8)
50 #	define		reg(x)		(x)
51 #	ifdef INTERLEAVED
52 #		define	mirror(x)		(toendian(x)<<16|toendian(x))
53 		typedef	ulong		Fword;
54 #		define	Wshift		2
55 #	else
56 #		define mirror(x)		toendian(x)
57 		typedef	ushort		Fword;
58 #		define	Wshift		1
59 #	endif
60 #endif
61 
62 /* this defines a contiguous set of erase blocks of one size */
63 struct FlashRegion
64 {
65 	ulong	addr;	/* start of region */
66 	ulong	end;		/* end of region + 1 */
67 	ulong	n;		/* number of blocks */
68 	ulong	size;		/* size of each block */
69 };
70 
71 struct Flash
72 {
73 	ISAConf;					/* contains size */
74 	RWlock;
75 	Fword		*p;
76 	ushort		algid;		/* access algorithm */
77 	FlashAlg		*alg;
78 	ushort		manid;		/* manufacturer id */
79 	ushort		devid;		/* device id */
80 	int			wbsize;		/* size of write buffer */
81 	ulong		nr;			/* number of regions */
82 	uchar		bootprotect;
83 	ulong		offset;		/* beginning offset of this flash */
84 	FlashRegion	r[32];
85 };
86 
87 /* this defines a particular access algorithm */
88 struct FlashAlg
89 {
90 	int	id;
91 	char	*name;
92 	void	(*identify)(Flash*);	/* identify device */
93 	void	(*erase)(Flash*, ulong);	/* erase a region */
94 	void	(*write)(Flash*, void*, long, ulong);	/* write a region */
95 };
96 
97 static void	ise_id(Flash*);
98 static void	ise_erase(Flash*, ulong);
99 static void	ise_write(Flash*, void*, long, ulong);
100 
101 static void	afs_id(Flash*);
102 static void	afs_erase(Flash*, ulong);
103 static void	afs_write(Flash*, void*, long, ulong);
104 
105 static ulong	blockstart(Flash*, ulong);
106 static ulong	blockend(Flash*, ulong);
107 
108 FlashAlg falg[] =
109 {
110 	{ 1,	"Intel/Sharp Extended",	ise_id, ise_erase, ise_write	},
111 	{ 2,	"AMD/Fujitsu Standard",	afs_id, afs_erase, afs_write	},
112 };
113 
114 Flash flashes[Nflash];
115 
116 /*
117  *  common flash interface
118  */
119 static uchar
cfigetc(Flash * flash,int off)120 cfigetc(Flash *flash, int off)
121 {
122 	uchar rv;
123 
124 	flash->p[reg(0x55)] = mirror(0x98);
125 	rv = fromendian(flash->p[reg(off)]);
126 	flash->p[reg(0x55)] = mirror(0xFF);
127 	return rv;
128 }
129 
130 static ushort
cfigets(Flash * flash,int off)131 cfigets(Flash *flash, int off)
132 {
133 	return (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
134 }
135 
136 static ulong
cfigetl(Flash * flash,int off)137 cfigetl(Flash *flash, int off)
138 {
139 	return (cfigetc(flash, off+3)<<24)|(cfigetc(flash, off+2)<<16)|
140 		(cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
141 }
142 
143 static void
cfiquery(Flash * flash)144 cfiquery(Flash *flash)
145 {
146 	uchar q, r, y;
147 	ulong x, addr;
148 
149 	q = cfigetc(flash, 0x10);
150 	r = cfigetc(flash, 0x11);
151 	y = cfigetc(flash, 0x12);
152 	if(q != 'Q' || r != 'R' || y != 'Y'){
153 		print("cfi query failed: %ux %ux %ux\n", q, r, y);
154 		return;
155 	}
156 	flash->algid = cfigetc(flash, 0x13);
157 	flash->size = (sizeof(Fword)/sizeof(Funit)) * (1<<(cfigetc(flash, 0x27)));
158 	flash->wbsize = (sizeof(Fword)/sizeof(Funit)) * (1<<(cfigetc(flash, 0x2a)));
159 	flash->nr = cfigetc(flash, 0x2c);
160 	if(flash->nr > nelem(flash->r)){
161 		print("cfi reports > %d regions\n", nelem(flash->r));
162 		flash->nr = nelem(flash->r);
163 	}
164 	addr = 0;
165 	for(q = 0; q < flash->nr; q++){
166 		x = cfigetl(flash, q+0x2d);
167 		flash->r[q].size = (sizeof(Fword)/sizeof(Funit)) * 256 * (x>>16);
168 		flash->r[q].n = (x&0xffff)+1;
169 		flash->r[q].addr = addr;
170 		addr += flash->r[q].size*flash->r[q].n;
171 		flash->r[q].end = addr;
172 	}
173 }
174 
175 /*
176  *  flash device interface
177  */
178 
179 enum
180 {
181 	Qtopdir,
182 	Q2nddir,
183 	Qfctl,
184 	Qfdata,
185 
186 	Maxpart= 8,
187 };
188 
189 
190 typedef struct FPart FPart;
191 struct FPart
192 {
193 	Flash	*flash;
194 	char		*name;
195 	char		*ctlname;
196 	ulong	start;
197 	ulong	end;
198 };
199 static FPart	part[Maxpart];
200 
201 #define FQID(p,q)	((p)<<8|(q))
202 #define FTYPE(q)	((q) & 0xff)
203 #define FPART(q)	(&part[(q) >>8])
204 
205 static int
gen(Chan * c,char *,Dirtab *,int,int i,Dir * dp)206 gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
207 {
208 	Qid q;
209 	FPart *fp;
210 
211 	q.vers = 0;
212 
213 	/* top level directory contains the name of the network */
214 	if(c->qid.path == Qtopdir){
215 		switch(i){
216 		case DEVDOTDOT:
217 			q.path = Qtopdir;
218 			q.type = QTDIR;
219 			devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
220 			break;
221 		case 0:
222 			q.path = Q2nddir;
223 			q.type = QTDIR;
224 			devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
225 			break;
226 		default:
227 			return -1;
228 		}
229 		return 1;
230 	}
231 
232 	/* second level contains all partitions and their control files */
233 	switch(i) {
234 	case DEVDOTDOT:
235 		q.path = Qtopdir;
236 		q.type = QTDIR;
237 		devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
238 		break;
239 	default:
240 		if(i >= 2*Maxpart)
241 			return -1;
242 		fp = &part[i>>1];
243 		if(fp->name == nil)
244 			return 0;
245 		if(i & 1){
246 			q.path = FQID(i>>1, Qfdata);
247 			q.type = QTFILE;
248 			devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
249 		} else {
250 			q.path = FQID(i>>1, Qfctl);
251 			q.type = QTFILE;
252 			devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
253 		}
254 		break;
255 	}
256 	return 1;
257 }
258 
259 static Flash *
findflash(ulong addr)260 findflash(ulong addr)
261 {
262 	Flash *flash;
263 
264 	for (flash = flashes; flash < flashes + Nflash; flash++)
265 		if(addr >= flash->offset && addr < flash->offset + flash->size)
266 			return flash;
267 	return nil;
268 }
269 
270 static FPart*
findpart(char * name)271 findpart(char *name)
272 {
273 	int i;
274 
275 	for(i = 0; i < Maxpart; i++)
276 		if(part[i].name != nil && strcmp(name, part[i].name) == 0)
277 			break;
278 	if(i >= Maxpart)
279 		return nil;
280 	return &part[i];
281 }
282 
283 static void
addpart(FPart * fp,char * name,ulong start,ulong end)284 addpart(FPart *fp, char *name, ulong start, ulong end)
285 {
286 	int i;
287 	char ctlname[64];
288 	Flash *flash;
289 	if (start > end)
290 		error(Ebadarg);
291 	if(fp == nil){
292 		flash = findflash(start);
293 		if (flash == nil || end > flash->offset + flash->size)
294 			error(Ebadarg);
295 		start -= flash->offset;
296 		end -= flash->offset;
297 	} else {
298 		start += fp->start;
299 		end += fp->start;
300 		if(start >= fp->end || end > fp->end){
301 			error(Ebadarg);
302 		}
303 		flash = fp->flash;
304 	}
305 	if(blockstart(flash, start) != start)
306 		error("must start on erase boundary");
307 	if(blockstart(flash, end) != end && end != flash->size)
308 		error("must end on erase boundary");
309 
310 	fp = findpart(name);
311 	if(fp != nil)
312 		error(Eexist);
313 	for(i = 0; i < Maxpart; i++)
314 		if(part[i].name == nil)
315 			break;
316 	if(i == Maxpart)
317 		error("no more partitions");
318 	fp = &part[i];
319 	kstrdup(&fp->name, name);
320 	snprint(ctlname, sizeof ctlname, "%sctl", name);
321 	kstrdup(&fp->ctlname, ctlname);
322 	fp->flash = flash;
323 	fp->start = start;
324 	fp->end = end;
325 }
326 
327 static void
rempart(FPart * fp)328 rempart(FPart *fp)
329 {
330 	char *p, *cp;
331 
332 	p = fp->name;
333 	fp->name = nil;
334 	cp = fp->ctlname;
335 	fp->ctlname = nil;
336 	free(p);
337 	free(cp);
338 }
339 
340 void
flashinit(void)341 flashinit(void)
342 {
343 	int i, ctlrno;
344 	char *fname;
345 	ulong offset;
346 	Flash *flash;
347 
348 	offset = 0;
349 	for (ctlrno = 0; ctlrno < Nflash; ctlrno++){
350 		flash = flashes + ctlrno;
351 		if(isaconfig("flash", ctlrno, flash) == 0)
352 			continue;
353 		flash->p = (Fword*)flash->mem;
354 		cfiquery(flash);
355 		for(i = 0; i < nelem(falg); i++)
356 			if(flash->algid == falg[i].id){
357 				flash->alg = &falg[i];
358 				(*flash->alg->identify)(flash);
359 				break;
360 			}
361 		flash->bootprotect = 1;
362 		flash->offset = offset;
363 		fname = malloc(8);
364 		sprint(fname, "flash%d", ctlrno);
365 		addpart(nil, fname, offset, offset + flash->size);
366 		offset += flash->size;
367 	}
368 }
369 
370 static Chan*
flashattach(char * spec)371 flashattach(char* spec)
372 {
373 	return devattach('F', spec);
374 }
375 
376 static Walkqid*
flashwalk(Chan * c,Chan * nc,char ** name,int nname)377 flashwalk(Chan *c, Chan *nc, char **name, int nname)
378 {
379 	return devwalk(c, nc, name, nname, nil, 0, gen);
380 }
381 
382 static int
flashstat(Chan * c,uchar * db,int n)383 flashstat(Chan *c, uchar *db, int n)
384 {
385 	return devstat(c, db, n, nil, 0, gen);
386 }
387 
388 static Chan*
flashopen(Chan * c,int omode)389 flashopen(Chan* c, int omode)
390 {
391 	omode = openmode(omode);
392 	if(strcmp(up->user, eve)!=0)
393 		error(Eperm);
394 	return devopen(c, omode, nil, 0, gen);
395 }
396 
397 static void
flashclose(Chan *)398 flashclose(Chan*)
399 {
400 }
401 
402 static long
flashctlread(FPart * fp,void * a,long n,vlong off)403 flashctlread(FPart *fp, void* a, long n, vlong off)
404 {
405 	char *buf, *p, *e;
406 	int i;
407 	ulong addr, end;
408 	Flash *flash;
409 
410 	flash = fp->flash;
411 	buf = smalloc(1024);
412 	e = buf + 1024;
413 	p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n",
414 		flash->offset, fp->start, fp->end-fp->start, flash->wbsize, flash->manid, flash->devid);
415 	addr = fp->start;
416 	for(i = 0; i < flash->nr && addr < fp->end; i++)
417 		if(flash->r[i].addr <= addr && flash->r[i].end > addr){
418 			if(fp->end <= flash->r[i].end)
419 				end = fp->end;
420 			else
421 				end = flash->r[i].end;
422 			p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,
423 				(end-addr)/flash->r[i].size, flash->r[i].size);
424 			addr = end;
425 		}
426 	n = readstr(off, a, n, buf);
427 	free(buf);
428 	return n;
429 }
430 
431 static long
flashdataread(FPart * fp,void * a,long n,vlong off)432 flashdataread(FPart *fp, void* a, long n, vlong off)
433 {
434 	Flash *flash;
435 
436 	flash = fp->flash;
437 	rlock(flash);
438 	if(waserror()){
439 		runlock(flash);
440 		nexterror();
441 	}
442 	if(fp->name == nil)
443 		error("partition vanished");
444 	if(!iseve())
445 		error(Eperm);
446 	off += fp->start;
447 	if(off >= fp->end)
448 		n = 0;
449 	if(off+n >= fp->end)
450 		n = fp->end - off;
451 	if(n > 0)
452 		memmove(a, ((uchar*)flash->mem)+off, n);
453 	runlock(flash);
454 	poperror();
455 
456 	return n;
457 }
458 
459 static long
flashread(Chan * c,void * a,long n,vlong off)460 flashread(Chan* c, void* a, long n, vlong off)
461 {
462 	int t;
463 
464 	if(c->qid.type == QTDIR)
465 		return devdirread(c, a, n, nil, 0, gen);
466 	t = FTYPE(c->qid.path);
467 	switch(t){
468 	default:
469 		error(Eperm);
470 	case Qfctl:
471 		n = flashctlread(FPART(c->qid.path), a, n, off);
472 		break;
473 	case Qfdata:
474 		n = flashdataread(FPART(c->qid.path), a, n, off);
475 		break;
476 	}
477 	return n;
478 }
479 
480 static void
bootprotect(ulong addr)481 bootprotect(ulong addr)
482 {
483 	FlashRegion *r;
484 	Flash *flash;
485 
486 	flash = findflash(addr);
487 	if (flash == nil)
488 		error(Ebadarg);
489 	if(flash->bootprotect == 0)
490 		return;
491 	if(flash->nr == 0)
492 		error("writing over boot loader disallowed");
493 	r = flash->r;
494 	if(addr >= r->addr && addr < r->addr + r->size)
495 		error("writing over boot loader disallowed");
496 }
497 
498 static ulong
blockstart(Flash * flash,ulong addr)499 blockstart(Flash *flash, ulong addr)
500 {
501 	FlashRegion *r, *e;
502 	ulong x;
503 
504 	r = flash->r;
505 	for(e = &flash->r[flash->nr]; r < e; r++){
506 		if(addr >= r->addr && addr < r->end){
507 			x = addr - r->addr;
508 			x /= r->size;
509 			return r->addr + x*r->size;
510 		}
511 	}
512 
513 	return (ulong)-1;
514 }
515 
516 static ulong
blockend(Flash * flash,ulong addr)517 blockend(Flash *flash, ulong addr)
518 {
519 	FlashRegion *r, *e;
520 	ulong x;
521 
522 	r = flash->r;
523 	for(e = &flash->r[flash->nr]; r < e; r++)
524 		if(addr >= r->addr && addr < r->end){
525 			x = addr - r->addr;
526 			x /= r->size;
527 			return r->addr + (x+1)*r->size;
528 		}
529 
530 	return (ulong)-1;
531 }
532 
533 static long
flashctlwrite(FPart * fp,char * p,long n)534 flashctlwrite(FPart *fp, char *p, long n)
535 {
536 	Cmdbuf *cmd;
537 	ulong off;
538 	Flash *flash;
539 
540 	if(fp == nil)
541 		panic("flashctlwrite");
542 
543 	flash = fp->flash;
544 	cmd = parsecmd(p, n);
545 	wlock(flash);
546 	if(waserror()){
547 		wunlock(flash);
548 		nexterror();
549 	}
550 	if(strcmp(cmd->f[0], "erase") == 0){
551 		switch(cmd->nf){
552 		case 2:
553 			/* erase a single block in the partition */
554 			off = atoi(cmd->f[1]);
555 			off += fp->start;
556 			if(off >= fp->end)
557 				error("region not in partition");
558 			if(off != blockstart(flash, off))
559 				error("erase must be a block boundary");
560 			bootprotect(off);
561 			(*flash->alg->erase)(flash, off);
562 			break;
563 		case 1:
564 			/* erase the whole partition */
565 			bootprotect(fp->start);
566 			for(off = fp->start; off < fp->end; off = blockend(flash, off))
567 				(*flash->alg->erase)(flash, off);
568 			break;
569 		default:
570 			error(Ebadarg);
571 		}
572 	} else if(strcmp(cmd->f[0], "add") == 0){
573 		if(cmd->nf != 4)
574 			error(Ebadarg);
575 		addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
576 	} else if(strcmp(cmd->f[0], "remove") == 0){
577 		rempart(fp);
578 	} else if(strcmp(cmd->f[0], "protectboot") == 0){
579 		if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
580 			flash->bootprotect = 1;
581 		else
582 			flash->bootprotect = 0;
583 	} else
584 		error(Ebadarg);
585 	poperror();
586 	wunlock(flash);
587 	free(cmd);
588 
589 	return n;
590 }
591 
592 static long
flashdatawrite(FPart * fp,uchar * p,long n,long off)593 flashdatawrite(FPart *fp, uchar *p, long n, long off)
594 {
595 	uchar *end;
596 	int m;
597 	int on;
598 	long ooff;
599 	uchar *buf;
600 	Flash *flash;
601 
602 	if(fp == nil)
603 		panic("flashdatawrite");
604 
605 	flash = fp->flash;
606 	buf = nil;
607 	wlock(flash);
608 	if(waserror()){
609 		wunlock(flash);
610 		if(buf != nil)
611 			free(buf);
612 		nexterror();
613 	}
614 
615 	if(fp->name == nil)
616 		error("partition vanished");
617 	if(!iseve())
618 		error(Eperm);
619 
620 	/* can't cross partition boundaries */
621 	off += fp->start;
622 	if(off >= fp->end || off+n > fp->end || n <= 0)
623 		error(Ebadarg);
624 
625 	/* make sure we're not writing the boot sector */
626 	bootprotect(off);
627 
628 	on = n;
629 
630 	/*
631 	 *  get the data into kernel memory to avoid faults during writing.
632 	 *  if write is not on a quad boundary or not a multiple of 4 bytes,
633 	 *  extend with data already in flash.
634 	 */
635 	buf = smalloc(n+8);
636 	m = off & 3;
637 	if(m){
638 		*(ulong*)buf = flash->p[off>>Wshift];
639 		n += m;
640 		off -= m;
641 	}
642 	if(n & 3){
643 		n -= n & 3;
644 		*(ulong*)(&buf[n]) = flash->p[(off+n)>>Wshift];
645 		n += 4;
646 	}
647 	memmove(&buf[m], p, on);
648 
649 	/* (*flash->alg->write) can't cross blocks */
650 	ooff = off;
651 	p = buf;
652 	for(end = p + n; p < end; p += m){
653 		m = blockend(flash, off) - off;
654 		if(m > end - p)
655 			m = end - p;
656 		if(m > Maxwchunk)
657 			m = Maxwchunk;
658 		(*flash->alg->write)(flash, p, m, off);
659 		off += m;
660 	}
661 
662 	/* make sure write succeeded */
663 	if(memcmp(buf, &flash->p[ooff>>Wshift], n) != 0)
664 		error("written bytes don't match");
665 
666 	wunlock(flash);
667 	free(buf);
668 	poperror();
669 
670 	return on;
671 }
672 
673 static long
flashwrite(Chan * c,void * a,long n,vlong off)674 flashwrite(Chan* c, void* a, long n, vlong off)
675 {
676 	int t;
677 
678 	if(c->qid.type == QTDIR)
679 		error(Eperm);
680 
681 	if(!iseve())
682 		error(Eperm);
683 
684 	t = FTYPE(c->qid.path);
685 	switch(t){
686 	default:
687 		panic("flashwrite");
688 	case Qfctl:
689 		n = flashctlwrite(FPART(c->qid.path), a, n);
690 		break;
691 	case Qfdata:
692 		n = flashdatawrite(FPART(c->qid.path), a, n, off);
693 		break;
694 	}
695 	return n;
696 }
697 
698 Dev flashdevtab = {
699 	'F',
700 	"flash",
701 
702 	devreset,
703 	flashinit,
704 	devshutdown,
705 	flashattach,
706 	flashwalk,
707 	flashstat,
708 	flashopen,
709 	devcreate,
710 	flashclose,
711 	flashread,
712 	devbread,
713 	flashwrite,
714 	devbwrite,
715 	devremove,
716 	devwstat,
717 };
718 
719 enum
720 {
721 	/* status register */
722 	ISEs_lockerr=		1<<1,
723 	ISEs_powererr=		1<<3,
724 	ISEs_progerr=		1<<4,
725 	ISEs_eraseerr=		1<<5,
726 	ISEs_ready=		1<<7,
727 	ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
728 
729 	/* extended status register */
730 	ISExs_bufavail=		1<<7,
731 };
732 
733 /* intel/sharp extended command set */
734 static void
ise_reset(Flash * flash)735 ise_reset(Flash* flash)
736 {
737 	flash->p[reg(0xaa)] = mirror(0xff);	/* reset */
738 }
739 
740 static void
ise_id(Flash * flash)741 ise_id(Flash* flash)
742 {
743 	ise_reset(flash);
744 	flash->p[reg(0xaaa)] = mirror(0x90);	/* uncover vendor info */
745 	flash->manid = fromendian(flash->p[reg(0x0)]);
746 	flash->devid = fromendian(flash->p[reg(0x1)]);
747 	ise_reset(flash);
748 }
749 
750 static void
ise_clearerror(Flash * flash)751 ise_clearerror(Flash* flash)
752 {
753 	flash->p[reg(0x200)] = mirror(0x50);
754 
755 }
756 
757 static void
ise_error(int bank,ulong status)758 ise_error(int bank, ulong status)
759 {
760 	char err[64];
761 
762 	if(status & (ISEs_lockerr)){
763 		sprint(err, "flash%d: block locked %lux", bank, status);
764 		error(err);
765 	}
766 	if(status & (ISEs_powererr)){
767 		sprint(err, "flash%d: low prog voltage %lux", bank, status);
768 		error(err);
769 	}
770 	if(status & (ISEs_progerr|ISEs_eraseerr)){
771 		sprint(err, "flash%d: i/o error %lux", bank, status);
772 		error(err);
773 	}
774 }
775 static void
ise_erase(Flash * flash,ulong addr)776 ise_erase(Flash *flash, ulong addr)
777 {
778 	ulong start;
779 	ulong x;
780 
781 	addr >>= Wshift;
782 
783 	flashprogpower(1);
784 	flash->p[addr] = mirror(0x20);
785 	flash->p[addr] = mirror(0xd0);
786 	start = m->ticks;
787 	do {
788 		x = fromendian(flash->p[addr]);
789 		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
790 			break;
791 	} while(TK2MS(m->ticks-start) < 1500);
792 	flashprogpower(0);
793 
794 	ise_clearerror(flash);
795 	ise_error(0, x);
796 	ise_error(1, x>>16);
797 
798 	ise_reset(flash);
799 }
800 /*
801  *  the flash spec claimes writing goes faster if we use
802  *  the write buffer.  We fill the write buffer and then
803  *  issue the write request.  After the write request,
804  *  subsequent reads will yield the status register.
805  *
806  *  returns the status, even on timeouts.
807  *
808  *  NOTE: I tried starting back to back buffered writes
809  *	without reading the status in between, as the
810  *	flowchart in the intel data sheet suggests.
811  *	However, it always responded with an illegal
812  *	command sequence, so I must be missing something.
813  *	If someone learns better, please email me, though
814  *	I doubt it will be much faster. -  presotto@bell-labs.com
815  */
816 static long
ise_wbwrite(Flash * flash,Fword * p,int n,ulong off,ulong baddr,ulong * status)817 ise_wbwrite(Flash *flash, Fword *p, int n, ulong off, ulong baddr, ulong *status)
818 {
819 	Fword x;
820 	ulong start;
821 	int i;
822 	int s;
823 
824 	/* put flash into write buffer mode */
825 	start = m->ticks;
826 	for(;;) {
827 		s = splhi();
828 		/* request write buffer mode */
829 		flash->p[baddr] = mirror(0xe8);
830 
831 		/* look at extended status reg for status */
832 		if((flash->p[baddr] & mirror(1<<7)) == mirror(1<<7))
833 			break;
834 		splx(s);
835 
836 		/* didn't work, keep trying for 2 secs */
837 		if(TK2MS(m->ticks-start) > 2000){
838 			/* set up to read status */
839 			flash->p[baddr] = mirror(0x70);
840 			*status = fromendian(flash->p[baddr]);
841 			pprint("write buffered cmd timed out\n");
842 			return -1;
843 		}
844 	}
845 
846 	/* fill write buffer */
847 	flash->p[baddr] = mirror(n-1);
848 	for(i = 0; i < n; i++)
849 		flash->p[off+i] = *p++;
850 
851 	/* program from buffer */
852 	flash->p[baddr] = mirror(0xd0);
853 	splx(s);
854 
855 	/* wait till the programming is done */
856 	start = m->ticks;
857 	for(;;) {
858 		x = flash->p[baddr];	/* read status register */
859 		*status = fromendian(x);
860 		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
861 			break;
862 		if(TK2MS(m->ticks-start) > 2000){
863 			pprint("read status timed out\n");
864 			return -1;
865 		}
866 	}
867 	if(x & mirror(ISEs_err))
868 		return -1;
869 
870 	return n;
871 }
872 
873 static void
ise_write(Flash * flash,void * a,long n,ulong off)874 ise_write(Flash *flash, void *a, long n, ulong off)
875 {
876 	Fword *p, *end;
877 	int i, wbsize;
878 	ulong x, baddr;
879 
880  	/* everything in terms of Fwords */
881 	wbsize = flash->wbsize >> Wshift;
882 	baddr = blockstart(flash, off) >> Wshift;
883 	off >>= Wshift;
884 	n >>= Wshift;
885 	p = a;
886 
887 	/* first see if write will succeed */
888 	for(i = 0; i < n; i++)
889 		if((p[i] & flash->p[off+i]) != p[i])
890 			error("flash needs erase");
891 
892 	if(waserror()){
893 		ise_reset(flash);
894 		flashprogpower(0);
895 		nexterror();
896 	}
897 	flashprogpower(1);
898 
899 	/*
900 	 *  use the first write to reach
901  	 *  a write buffer boundary.  the intel maunal
902 	 *  says writes starting at wb boundaries
903 	 *  maximize speed.
904 	 */
905 	i = wbsize - (off & (wbsize-1));
906 	for(end = p + n; p < end;){
907 		if(i > end - p)
908 			i = end - p;
909 
910 		if(ise_wbwrite(flash, p, i, off, baddr, &x) < 0)
911 			break;
912 
913 		off += i;
914 		p += i;
915 		i = wbsize;
916 	}
917 
918 	ise_clearerror(flash);
919 	ise_error(0, x);
920 	ise_error(1, x>>16);
921 
922 	ise_reset(flash);
923 	flashprogpower(0);
924 	poperror();
925 }
926 
927 /* amd/fujitsu standard command set
928  *	I don't have an amd chipset to work with
929  *	so I'm loathe to write this yet.  If someone
930  *	else does, please send it to me and I'll
931  *	incorporate it -- presotto@bell-labs.com
932  */
933 static void
afs_reset(Flash * flash)934 afs_reset(Flash *flash)
935 {
936 	flash->p[reg(0xaa)] = mirror(0xf0);	/* reset */
937 }
938 static void
afs_id(Flash * flash)939 afs_id(Flash *flash)
940 {
941 	afs_reset(flash);
942 	flash->p[reg(0xaa)] = mirror(0xf0);	/* reset */
943 	flash->p[reg(0xaaa)] = mirror(0xaa);	/* query vendor block */
944 	flash->p[reg(0x554)] = mirror(0x55);
945 	flash->p[reg(0xaaa)] = mirror(0x90);
946 	flash->manid = fromendian(flash->p[reg(0x00)]);
947 	afs_reset(flash);
948 	flash->p[reg(0xaaa)] = mirror(0xaa);	/* query vendor block */
949 	flash->p[reg(0x554)] = mirror(0x55);
950 	flash->p[reg(0xaaa)] = mirror(0x90);
951 	flash->devid = fromendian(flash->p[reg(0x02)]);
952 	afs_reset(flash);
953 }
954 static void
afs_erase(Flash *,ulong)955 afs_erase(Flash*, ulong)
956 {
957 	error("amd/fujistsu erase not implemented");
958 }
959 static void
afs_write(Flash *,void *,long,ulong)960 afs_write(Flash*, void*, long, ulong)
961 {
962 	error("amd/fujistsu write not implemented");
963 }
964