Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
131
cfigets(Flash *flash, int off)
132
{
133
	return (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
134
}
135
 
136
static ulong
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
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
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 *
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*
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
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
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
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*
371
flashattach(char* spec)
372
{
373
	return devattach('F', spec);
374
}
375
 
376
static Walkqid*
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	 
383
flashstat(Chan *c, uchar *db, int n)
384
{
385
	return devstat(c, db, n, nil, 0, gen);
386
}
387
 
388
static Chan*
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	 
398
flashclose(Chan*)
399
{
400
}
401
 
402
static long
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
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	 
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
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
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
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
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
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	 
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
735
ise_reset(Flash* flash)
736
{
737
	flash->p[reg(0xaa)] = mirror(0xff);	/* reset */
738
}
739
 
740
static void
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
751
ise_clearerror(Flash* flash)
752
{
753
	flash->p[reg(0x200)] = mirror(0x50);
754
 
755
}
756
 
757
static void
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
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
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
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
934
afs_reset(Flash *flash)
935
{
936
	flash->p[reg(0xaa)] = mirror(0xf0);	/* reset */
937
}
938
static void
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
955
afs_erase(Flash*, ulong)
956
{
957
	error("amd/fujistsu erase not implemented");
958
}
959
static void
960
afs_write(Flash*, void*, long, ulong)
961
{
962
	error("amd/fujistsu write not implemented");
963
}