FreeBSD/Linux Kernel Cross Reference
sys/ppc/devflash.c
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 }
Cache object: 5cccb5f70bce46959f00af6259bcb311
|