2 #include "../port/lib.h"
7 #include "../port/error.h"
10 * on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit
11 * accesses, one to the low half of the chip and the other to the high
12 * half. Therefore for all command accesses, ushort indices in the
13 * manuals turn into ulong indices in our code. Also, by copying all
14 * 16 bit commands to both halves of a 32 bit command, we erase 2
15 * sectors for each request erase request.
18 #define mirror(x) (((x)<<16)|(x))
20 /* this defines a contiguous set of erase blocks of one size */
21 typedef struct FlashRegion FlashRegion;
24 ulong addr; /* start of region */
25 ulong end; /* end of region + 1 */
26 ulong n; /* number of blocks */
27 ulong size; /* size of each block */
30 /* this defines a particular access algorithm */
31 typedef struct FlashAlg FlashAlg;
36 void (*identify)(void); /* identify device */
37 void (*erase)(ulong); /* erase a region */
38 void (*write)(void*, long, ulong); /* write a region */
41 static void ise_id(void);
42 static void ise_erase(ulong);
43 static void ise_write(void*, long, ulong);
45 static void afs_id(void);
46 static void afs_erase(ulong);
47 static void afs_write(void*, long, ulong);
49 static ulong blockstart(ulong);
50 static ulong blockend(ulong);
54 { 1, "Intel/Sharp Extended", ise_id, ise_erase, ise_write },
55 { 2, "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write },
62 ushort algid; /* access algorithm */
64 ushort manid; /* manufacturer id */
65 ushort devid; /* device id */
66 ulong size; /* size in bytes */
67 int wbsize; /* size of write buffer */
68 ulong nr; /* number of regions */
75 Maxwchunk= 1024, /* maximum chunk written by one call to falg->write */
79 * common flash interface
86 flash.p[0x55] = mirror(0x98);
88 flash.p[0x55] = mirror(0xFF);
95 return (cfigetc(off+1)<<8)|cfigetc(off);
101 return (cfigetc(off+3)<<24)|(cfigetc(off+2)<<16)|
102 (cfigetc(off+1)<<8)|cfigetc(off);
114 if(q != 'Q' || r != 'R' || y != 'Y'){
115 print("cfi query failed: %ux %ux %ux\n", q, r, y);
118 flash.algid = cfigetc(0x13);
119 flash.size = 1<<(cfigetc(0x27)+1);
120 flash.wbsize = 1<<(cfigetc(0x2a)+1);
121 flash.nr = cfigetc(0x2c);
122 if(flash.nr > nelem(flash.r)){
123 print("cfi reports > %d regions\n", nelem(flash.r));
124 flash.nr = nelem(flash.r);
127 for(q = 0; q < flash.nr; q++){
129 flash.r[q].size = 2*256*(x>>16);
130 flash.r[q].n = (x&0xffff)+1;
131 flash.r[q].addr = addr;
132 addr += flash.r[q].size*flash.r[q].n;
133 flash.r[q].end = addr;
138 * flash device interface
152 typedef struct FPart FPart;
160 static FPart part[Maxpart];
162 #define FQID(p,q) ((p)<<8|(q))
163 #define FTYPE(q) ((q) & 0xff)
164 #define FPART(q) (&part[(q) >>8])
167 gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
174 /* top level directory contains the name of the network */
175 if(c->qid.path == Qtopdir){
180 devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
185 devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
193 /* second level contains all partitions and their control files */
198 devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
207 q.path = FQID(i>>1, Qfdata);
209 devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
211 q.path = FQID(i>>1, Qfctl);
213 devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
225 for(i = 0; i < Maxpart; i++)
226 if(part[i].name != nil && strcmp(name, part[i].name) == 0)
234 addpart(FPart *fp, char *name, ulong start, ulong end)
240 if(start >= flash.size || end > flash.size)
245 if(start >= fp->end || end > fp->end)
248 if(blockstart(start) != start)
249 error("must start on erase boundary");
250 if(blockstart(end) != end && end != flash.size)
251 error("must end on erase boundary");
256 for(i = 0; i < Maxpart; i++)
257 if(part[i].name == nil)
260 error("no more partitions");
262 kstrdup(&fp->name, name);
263 snprint(ctlname, sizeof ctlname, "%sctl", name);
264 kstrdup(&fp->ctlname, ctlname);
287 flash.p = (ulong*)FLASHZERO;
289 for(i = 0; i < nelem(falg); i++)
290 if(flash.algid == falg[i].id){
291 flash.alg = &falg[i];
292 (*flash.alg->identify)();
295 flash.bootprotect = 1;
297 addpart(nil, "flash", 0, flash.size);
301 flashattach(char* spec)
303 return devattach('F', spec);
307 flashwalk(Chan *c, Chan *nc, char **name, int nname)
309 return devwalk(c, nc, name, nname, nil, 0, gen);
313 flashstat(Chan *c, uchar *db, int n)
315 return devstat(c, db, n, nil, 0, gen);
319 flashopen(Chan* c, int omode)
321 omode = openmode(omode);
322 if(strcmp(up->user, eve)!=0)
324 return devopen(c, omode, nil, 0, gen);
333 flashctlread(FPart *fp, void* a, long n, vlong off)
341 p = seprint(buf, e, "0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n", fp->end-fp->start,
342 flash.wbsize, flash.manid, flash.devid);
344 for(i = 0; i < flash.nr && addr < fp->end; i++)
345 if(flash.r[i].addr <= addr && flash.r[i].end > addr){
346 if(fp->end <= flash.r[i].end)
349 end = flash.r[i].end;
350 p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,
351 (end-addr)/flash.r[i].size, flash.r[i].size);
354 n = readstr(off, a, n, buf);
360 flashdataread(FPart *fp, void* a, long n, vlong off)
368 error("partition vanished");
377 memmove(a, ((uchar*)FLASHZERO)+off, n);
385 flashread(Chan* c, void* a, long n, vlong off)
389 if(c->qid.type == QTDIR)
390 return devdirread(c, a, n, nil, 0, gen);
391 t = FTYPE(c->qid.path);
396 n = flashctlread(FPART(c->qid.path), a, n, off);
399 n = flashdataread(FPART(c->qid.path), a, n, off);
406 bootprotect(ulong addr)
410 if(flash.bootprotect == 0)
413 error("writing over boot loader disallowed");
415 if(addr >= r->addr && addr < r->addr + r->size)
416 error("writing over boot loader disallowed");
420 blockstart(ulong addr)
426 for(e = &flash.r[flash.nr]; r < e; r++)
427 if(addr >= r->addr && addr < r->end){
430 return r->addr + x*r->size;
443 for(e = &flash.r[flash.nr]; r < e; r++)
444 if(addr >= r->addr && addr < r->end){
447 return r->addr + (x+1)*r->size;
454 flashctlwrite(FPart *fp, char *p, long n)
460 panic("flashctlwrite");
462 cmd = parsecmd(p, n);
468 if(strcmp(cmd->f[0], "erase") == 0){
471 /* erase a single block in the partition */
472 off = atoi(cmd->f[1]);
475 error("region not in partition");
476 if(off != blockstart(off))
477 error("erase must be a block boundary");
479 (*flash.alg->erase)(off);
482 /* erase the whole partition */
483 bootprotect(fp->start);
484 for(off = fp->start; off < fp->end; off = blockend(off))
485 (*flash.alg->erase)(off);
490 } else if(strcmp(cmd->f[0], "add") == 0){
493 addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
494 } else if(strcmp(cmd->f[0], "remove") == 0){
496 } else if(strcmp(cmd->f[0], "protectboot") == 0){
497 if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
498 flash.bootprotect = 1;
500 flash.bootprotect = 0;
511 flashdatawrite(FPart *fp, uchar *p, long n, long off)
520 panic("flashctlwrite");
532 error("partition vanished");
536 /* can't cross partition boundaries */
538 if(off >= fp->end || off+n > fp->end || n <= 0)
541 /* make sure we're not writing the boot sector */
547 * get the data into kernel memory to avoid faults during writing.
548 * if write is not on a quad boundary or not a multiple of 4 bytes,
549 * extend with data already in flash.
554 *(ulong*)buf = flash.p[(off)>>2];
560 *(ulong*)(&buf[n]) = flash.p[(off+n)>>2];
563 memmove(&buf[m], p, on);
565 /* (*flash.alg->write) can't cross blocks */
568 for(end = p + n; p < end; p += m){
569 m = blockend(off) - off;
574 (*flash.alg->write)(p, m, off);
578 /* make sure write succeeded */
579 if(memcmp(buf, &flash.p[ooff>>2], n) != 0)
580 error("written bytes don't match");
590 flashwrite(Chan* c, void* a, long n, vlong off)
594 if(c->qid.type == QTDIR)
600 t = FTYPE(c->qid.path);
605 n = flashctlwrite(FPART(c->qid.path), a, n);
608 n = flashdatawrite(FPART(c->qid.path), a, n, off);
637 /* status register */
643 ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
645 /* extended status register */
646 ISExs_bufavail= 1<<7,
651 /* intel/sharp extended command set */
655 flash.p[0x55] = mirror(0xff); /* reset */
661 flash.p[0x555] = mirror(0x90); /* uncover vendor info */
662 flash.manid = flash.p[00];
663 flash.devid = flash.p[01];
669 flash.p[0x100] = mirror(0x50);
673 ise_error(int bank, ulong status)
677 if(status & (ISEs_lockerr)){
678 sprint(err, "flash%d: block locked %lux", bank, status);
681 if(status & (ISEs_powererr)){
682 sprint(err, "flash%d: low prog voltage %lux", bank, status);
685 if(status & (ISEs_progerr|ISEs_eraseerr)){
686 sprint(err, "flash%d: i/o error %lux", bank, status);
691 ise_erase(ulong addr)
696 addr >>= 2; /* convert to ulong offset */
699 flash.p[addr] = mirror(0x20);
700 flash.p[addr] = mirror(0xd0);
704 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
706 } while(TK2MS(m->ticks-start) < 1500);
716 * the flash spec claimes writing goes faster if we use
717 * the write buffer. We fill the write buffer and then
718 * issue the write request. After the write request,
719 * subsequent reads will yield the status register.
721 * returns the status, even on timeouts.
723 * NOTE: I tried starting back to back buffered writes
724 * without reading the status in between, as the
725 * flowchart in the intel data sheet suggests.
726 * However, it always responded with an illegal
727 * command sequence, so I must be missing something.
728 * If someone learns better, please email me, though
729 * I doubt it will be much faster. - presotto@bell-labs.com
732 ise_wbwrite(ulong *p, int n, ulong off, ulong baddr, ulong *status)
738 /* put flash into write buffer mode */
742 /* request write buffer mode */
743 flash.p[baddr] = mirror(0xe8);
745 /* look at extended status reg for status */
746 if((flash.p[baddr] & mirror(1<<7)) == mirror(1<<7))
750 /* didn't work, keep trying for 2 secs */
751 if(TK2MS(m->ticks-start) > 2000){
752 /* set up to read status */
753 flash.p[baddr] = mirror(0x70);
754 *status = flash.p[baddr];
755 pprint("write buffered cmd timed out\n");
760 /* fill write buffer */
761 flash.p[baddr] = mirror(n-1);
762 for(i = 0; i < n; i++)
763 flash.p[off+i] = *p++;
765 /* program from buffer */
766 flash.p[baddr] = mirror(0xd0);
769 /* wait till the programming is done */
772 x = *status = flash.p[baddr]; /* read status register */
773 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
775 if(TK2MS(m->ticks-start) > 2000){
776 pprint("read status timed out\n");
780 if(x & mirror(ISEs_err))
786 ise_write(void *a, long n, ulong off)
792 /* everything in terms of ulongs */
793 wbsize = flash.wbsize>>2;
794 baddr = blockstart(off);
800 /* first see if write will succeed */
801 for(i = 0; i < n; i++)
802 if((p[i] & flash.p[off+i]) != p[i])
803 error("flash needs erase");
813 * use the first write to reach
814 * a write buffer boundary. the intel maunal
815 * says writes startng at wb boundaries
818 i = wbsize - (off & (wbsize-1));
819 for(end = p + n; p < end;){
823 if(ise_wbwrite(p, i, off, baddr, &x) < 0)
840 /* amd/fujitsu standard command set
841 * I don't have an amd chipset to work with
842 * so I'm loathe to write this yet. If someone
843 * else does, please send it to me and I'll
844 * incorporate it -- presotto@bell-labs.com
849 flash.p[0x55] = mirror(0xf0); /* reset */
855 flash.p[0x55] = mirror(0xf0); /* reset */
856 flash.p[0x555] = mirror(0xaa); /* query vendor block */
857 flash.p[0x2aa] = mirror(0x55);
858 flash.p[0x555] = mirror(0x90);
859 flash.manid = flash.p[00];
861 flash.p[0x555] = mirror(0xaa); /* query vendor block */
862 flash.p[0x2aa] = mirror(0x55);
863 flash.p[0x555] = mirror(0x90);
864 flash.devid = flash.p[01];
870 error("amd/fujistsu erase not implemented");
873 afs_write(void*, long, ulong)
875 error("amd/fujistsu write not implemented");