2 #include "../port/lib.h"
6 #include "../port/error.h"
10 Maxwchunk= 1024, /* maximum chunk written by one call to falg->write */
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
24 * The Blast board has a non-interleaved 16-bit wide flash. When doing
25 * writes to it, we must swap bytes.
28 typedef struct FlashAlg FlashAlg;
29 typedef struct Flash Flash;
30 typedef struct FlashRegion FlashRegion;
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)
38 # define mirror(x) ((x)<<8|(x)) /* Double query for interleaved flashes */
39 typedef ushort Fword; /* Width after interleaving */
42 # define mirror(x) (x)
48 # define toendian(x) ((x)<<8)
49 # define fromendian(x) ((x)>>8)
52 # define mirror(x) (toendian(x)<<16|toendian(x))
56 # define mirror(x) toendian(x)
62 /* this defines a contiguous set of erase blocks of one size */
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 */
73 ISAConf; /* contains size */
76 ushort algid; /* access algorithm */
78 ushort manid; /* manufacturer id */
79 ushort devid; /* device id */
80 int wbsize; /* size of write buffer */
81 ulong nr; /* number of regions */
83 ulong offset; /* beginning offset of this flash */
87 /* this defines a particular access algorithm */
92 void (*identify)(Flash*); /* identify device */
93 void (*erase)(Flash*, ulong); /* erase a region */
94 void (*write)(Flash*, void*, long, ulong); /* write a region */
97 static void ise_id(Flash*);
98 static void ise_erase(Flash*, ulong);
99 static void ise_write(Flash*, void*, long, ulong);
101 static void afs_id(Flash*);
102 static void afs_erase(Flash*, ulong);
103 static void afs_write(Flash*, void*, long, ulong);
105 static ulong blockstart(Flash*, ulong);
106 static ulong blockend(Flash*, ulong);
110 { 1, "Intel/Sharp Extended", ise_id, ise_erase, ise_write },
111 { 2, "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write },
114 Flash flashes[Nflash];
117 * common flash interface
120 cfigetc(Flash *flash, int off)
124 flash->p[reg(0x55)] = mirror(0x98);
125 rv = fromendian(flash->p[reg(off)]);
126 flash->p[reg(0x55)] = mirror(0xFF);
131 cfigets(Flash *flash, int off)
133 return (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
137 cfigetl(Flash *flash, int off)
139 return (cfigetc(flash, off+3)<<24)|(cfigetc(flash, off+2)<<16)|
140 (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
144 cfiquery(Flash *flash)
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);
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);
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;
176 * flash device interface
190 typedef struct FPart FPart;
199 static FPart part[Maxpart];
201 #define FQID(p,q) ((p)<<8|(q))
202 #define FTYPE(q) ((q) & 0xff)
203 #define FPART(q) (&part[(q) >>8])
206 gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
213 /* top level directory contains the name of the network */
214 if(c->qid.path == Qtopdir){
219 devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
224 devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
232 /* second level contains all partitions and their control files */
237 devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
246 q.path = FQID(i>>1, Qfdata);
248 devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
250 q.path = FQID(i>>1, Qfctl);
252 devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
260 findflash(ulong addr)
264 for (flash = flashes; flash < flashes + Nflash; flash++)
265 if(addr >= flash->offset && addr < flash->offset + flash->size)
275 for(i = 0; i < Maxpart; i++)
276 if(part[i].name != nil && strcmp(name, part[i].name) == 0)
284 addpart(FPart *fp, char *name, ulong start, ulong end)
292 flash = findflash(start);
293 if (flash == nil || end > flash->offset + flash->size)
295 start -= flash->offset;
296 end -= flash->offset;
300 if(start >= fp->end || end > fp->end){
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");
313 for(i = 0; i < Maxpart; i++)
314 if(part[i].name == nil)
317 error("no more partitions");
319 kstrdup(&fp->name, name);
320 snprint(ctlname, sizeof ctlname, "%sctl", name);
321 kstrdup(&fp->ctlname, ctlname);
349 for (ctlrno = 0; ctlrno < Nflash; ctlrno++){
350 flash = flashes + ctlrno;
351 if(isaconfig("flash", ctlrno, flash) == 0)
353 flash->p = (Fword*)flash->mem;
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);
361 flash->bootprotect = 1;
362 flash->offset = offset;
364 sprint(fname, "flash%d", ctlrno);
365 addpart(nil, fname, offset, offset + flash->size);
366 offset += flash->size;
371 flashattach(char* spec)
373 return devattach('F', spec);
377 flashwalk(Chan *c, Chan *nc, char **name, int nname)
379 return devwalk(c, nc, name, nname, nil, 0, gen);
383 flashstat(Chan *c, uchar *db, int n)
385 return devstat(c, db, n, nil, 0, gen);
389 flashopen(Chan* c, int omode)
391 omode = openmode(omode);
392 if(strcmp(up->user, eve)!=0)
394 return devopen(c, omode, nil, 0, gen);
403 flashctlread(FPart *fp, void* a, long n, vlong off)
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);
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)
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);
426 n = readstr(off, a, n, buf);
432 flashdataread(FPart *fp, void* a, long n, vlong off)
443 error("partition vanished");
452 memmove(a, ((uchar*)flash->mem)+off, n);
460 flashread(Chan* c, void* a, long n, vlong off)
464 if(c->qid.type == QTDIR)
465 return devdirread(c, a, n, nil, 0, gen);
466 t = FTYPE(c->qid.path);
471 n = flashctlread(FPART(c->qid.path), a, n, off);
474 n = flashdataread(FPART(c->qid.path), a, n, off);
481 bootprotect(ulong addr)
486 flash = findflash(addr);
489 if(flash->bootprotect == 0)
492 error("writing over boot loader disallowed");
494 if(addr >= r->addr && addr < r->addr + r->size)
495 error("writing over boot loader disallowed");
499 blockstart(Flash *flash, ulong addr)
505 for(e = &flash->r[flash->nr]; r < e; r++){
506 if(addr >= r->addr && addr < r->end){
509 return r->addr + x*r->size;
517 blockend(Flash *flash, ulong addr)
523 for(e = &flash->r[flash->nr]; r < e; r++)
524 if(addr >= r->addr && addr < r->end){
527 return r->addr + (x+1)*r->size;
534 flashctlwrite(FPart *fp, char *p, long n)
541 panic("flashctlwrite");
544 cmd = parsecmd(p, n);
550 if(strcmp(cmd->f[0], "erase") == 0){
553 /* erase a single block in the partition */
554 off = atoi(cmd->f[1]);
557 error("region not in partition");
558 if(off != blockstart(flash, off))
559 error("erase must be a block boundary");
561 (*flash->alg->erase)(flash, off);
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);
572 } else if(strcmp(cmd->f[0], "add") == 0){
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){
578 } else if(strcmp(cmd->f[0], "protectboot") == 0){
579 if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
580 flash->bootprotect = 1;
582 flash->bootprotect = 0;
593 flashdatawrite(FPart *fp, uchar *p, long n, long off)
603 panic("flashdatawrite");
616 error("partition vanished");
620 /* can't cross partition boundaries */
622 if(off >= fp->end || off+n > fp->end || n <= 0)
625 /* make sure we're not writing the boot sector */
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.
638 *(ulong*)buf = flash->p[off>>Wshift];
644 *(ulong*)(&buf[n]) = flash->p[(off+n)>>Wshift];
647 memmove(&buf[m], p, on);
649 /* (*flash->alg->write) can't cross blocks */
652 for(end = p + n; p < end; p += m){
653 m = blockend(flash, off) - off;
658 (*flash->alg->write)(flash, p, m, off);
662 /* make sure write succeeded */
663 if(memcmp(buf, &flash->p[ooff>>Wshift], n) != 0)
664 error("written bytes don't match");
674 flashwrite(Chan* c, void* a, long n, vlong off)
678 if(c->qid.type == QTDIR)
684 t = FTYPE(c->qid.path);
689 n = flashctlwrite(FPART(c->qid.path), a, n);
692 n = flashdatawrite(FPART(c->qid.path), a, n, off);
721 /* status register */
727 ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
729 /* extended status register */
730 ISExs_bufavail= 1<<7,
733 /* intel/sharp extended command set */
735 ise_reset(Flash* flash)
737 flash->p[reg(0xaa)] = mirror(0xff); /* reset */
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)]);
751 ise_clearerror(Flash* flash)
753 flash->p[reg(0x200)] = mirror(0x50);
758 ise_error(int bank, ulong status)
762 if(status & (ISEs_lockerr)){
763 sprint(err, "flash%d: block locked %lux", bank, status);
766 if(status & (ISEs_powererr)){
767 sprint(err, "flash%d: low prog voltage %lux", bank, status);
770 if(status & (ISEs_progerr|ISEs_eraseerr)){
771 sprint(err, "flash%d: i/o error %lux", bank, status);
776 ise_erase(Flash *flash, ulong addr)
784 flash->p[addr] = mirror(0x20);
785 flash->p[addr] = mirror(0xd0);
788 x = fromendian(flash->p[addr]);
789 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
791 } while(TK2MS(m->ticks-start) < 1500);
794 ise_clearerror(flash);
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.
806 * returns the status, even on timeouts.
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
817 ise_wbwrite(Flash *flash, Fword *p, int n, ulong off, ulong baddr, ulong *status)
824 /* put flash into write buffer mode */
828 /* request write buffer mode */
829 flash->p[baddr] = mirror(0xe8);
831 /* look at extended status reg for status */
832 if((flash->p[baddr] & mirror(1<<7)) == mirror(1<<7))
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");
846 /* fill write buffer */
847 flash->p[baddr] = mirror(n-1);
848 for(i = 0; i < n; i++)
849 flash->p[off+i] = *p++;
851 /* program from buffer */
852 flash->p[baddr] = mirror(0xd0);
855 /* wait till the programming is done */
858 x = flash->p[baddr]; /* read status register */
859 *status = fromendian(x);
860 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
862 if(TK2MS(m->ticks-start) > 2000){
863 pprint("read status timed out\n");
867 if(x & mirror(ISEs_err))
874 ise_write(Flash *flash, void *a, long n, ulong off)
880 /* everything in terms of Fwords */
881 wbsize = flash->wbsize >> Wshift;
882 baddr = blockstart(flash, off) >> Wshift;
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");
900 * use the first write to reach
901 * a write buffer boundary. the intel maunal
902 * says writes starting at wb boundaries
905 i = wbsize - (off & (wbsize-1));
906 for(end = p + n; p < end;){
910 if(ise_wbwrite(flash, p, i, off, baddr, &x) < 0)
918 ise_clearerror(flash);
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
934 afs_reset(Flash *flash)
936 flash->p[reg(0xaa)] = mirror(0xf0); /* reset */
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)]);
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)]);
955 afs_erase(Flash*, ulong)
957 error("amd/fujistsu erase not implemented");
960 afs_write(Flash*, void*, long, ulong)
962 error("amd/fujistsu write not implemented");