diff options
Diffstat (limited to 'os/pc/flashzpc.c')
| -rw-r--r-- | os/pc/flashzpc.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/os/pc/flashzpc.c b/os/pc/flashzpc.c new file mode 100644 index 00000000..c360f7bf --- /dev/null +++ b/os/pc/flashzpc.c @@ -0,0 +1,371 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#include "flashif.h" + +#define FLASHMEM 0xfff80000 +#define FLASHPGSZ 0x40000 +#define FLASHBKSZ (FLASHPGSZ>>2) +#define LOG2FPGSZ 18 +#define FLASHEND (FLASHMEM+FLASHPGSZ) +#define SYSREG0 0x78 +#define SYSREG1 0x878 + +/* Intel28F016SA flash memory family (8SA and (DD)32SA as well) in byte mode */ + +/* + * word mode does not work - a 2 byte write to a location results in the lower address + * byte being unchanged (4 byte writes are even stranger) and no indication of error. + * Perhaps the bridge is interfering with the address lines. + * Looks like the BIOS code doesn't use it either but that's not certain. + */ + +/* + * When port 0x78 bit 2 is set to 1 (flash device 1) + * 0xfff80000-0xfffbffff seems to be free but has dos block headers + * 0xfffc0000-0xfffdffff seems to be the DOS P: drive + * 0xfffe0000-0xffffffff is the BIOS + * When port 0x78 bit 2 is set to 0 (flash device 0) + * 0xfff80000-0xffffffff is a mixture of used and unused DOS blocks and apparently + * many copies of the BIOS + * + * In the absence of information from Ziatech and to preserve the BIOS and DOS sections, + * this driver only uses the first range for a total of 8 x 0x40000 = 2Mb + */ + +enum { + DQ7 = 0x80, + DQ6 = 0x40, + DQ5 = 0x20, + DQ4 = 0x10, + DQ3 = 0x08, + DQ2 = 0x04, + DQ1 = 0x02, + DQ0 = 0x01, +}; + +enum { + FLRDM = 0xFF, /* read */ + FLWTM = 0x10, /* write/program */ + FLCLR = 0x50, /* clear SR */ + FLBE1 = 0x20, /* block erase */ + FLBE2 = 0xD0, /* block erase */ + FLRSR = 0x70, /* read SR */ + FLDID = 0x90, /* read id */ +}; + +#define DPRINT if(0)print +#define EPRINT if(1)print + +static int +zpcwait(uchar *p, ulong ticks) +{ + uchar csr; + + ticks += m->ticks+1; + while((*p & DQ7) != DQ7){ + sched(); + if(m->ticks >= ticks){ + EPRINT("flash: timed out: %8.8lux\n", (ulong)*p); + return -1; + } + } + csr = *p; + if(csr & (DQ5|DQ4|DQ3)){ + EPRINT("flash: DQ5 error: %8.8lux %8.8lux\n", p, (ulong)csr); + return 0; + } + return 1; +} + +static int +eraseall(Flash *f) +{ + uchar r; + uchar *p; + int i, j, s; + + DPRINT("flash: erase all\n"); + for (i = 0; i < 8; i++) { /* page */ + /* set page */ + r = inb(SYSREG0); + r &= 0x8f; + r |= i<<4; + outb(SYSREG0, r); + p = (uchar *)f->addr; + for (j = 0; j < 4; j++) { /* block within page */ + DPRINT("erasing page %d block %d addr %lux\n", i, j, p); + s = splhi(); + *p = FLBE1; + *p = FLBE2; + splx(s); + if(zpcwait(p, MS2TK(16*1000)) <= 0){ + *p = FLCLR; /* clr SR */ + *p = FLRDM; /* read mode */ + f->unusable = ~0; + return -1; + } + *p = FLCLR; + *p = FLRDM; + p += FLASHPGSZ>>2; + } + } + return 0; +} + +static int +erasezone(Flash *f, int zone) +{ + uchar r; + uchar *p; + int s, pg, blk; + + DPRINT("flash: erase zone %d\n", zone); + if(zone & ~31) { + EPRINT("flash: bad erasezone %d\n", zone); + return -1; /* bad zone */ + } + pg = zone>>2; + blk = zone&3; + /* set page */ + r = inb(SYSREG0); + r &= 0x8f; + r |= pg<<4; + outb(SYSREG0, r); + p = (uchar *)f->addr + blk*(FLASHPGSZ>>2); + DPRINT("erasing zone %d pg %d blk %d addr %lux\n", zone, pg, blk, p); + s = splhi(); + *p = FLBE1; + *p = FLBE2; + splx(s); + if(zpcwait(p, MS2TK(8*1000)) <= 0){ + *p = FLCLR; + *p = FLRDM; /* reset */ + f->unusable |= 1<<zone; + return -1; + } + *p = FLCLR; + *p = FLRDM; + return 0; +} + +static int +readx(Flash *f, ulong offset, void *buf, long n) +{ + uchar r; + ulong pg, o; + long m; + uchar *p = buf; + + pg = offset>>LOG2FPGSZ; + o = offset&(FLASHPGSZ-1); + while (n > 0) { + if (pg < 0 || pg > 7) { + EPRINT("flash: bad read %ld %ld\n", offset, n); + return -1; + } + /* set page */ + r = inb(SYSREG0); + r &= 0x8f; + r |= pg<<4; + outb(SYSREG0, r); + if (o+n > FLASHPGSZ) + m = FLASHPGSZ-o; + else + m = n; + DPRINT("flash: read page %ld offset %lux buf %lux n %ld\n", pg, o, p-(uchar*)buf, m); + memmove(p, (uchar *)f->addr + o, m); + p += m; + n -= m; + pg++; + o = 0; + } + return 0; +} + +static int +writex(Flash *f, ulong offset, void *buf, long n) +{ + int i, s; + uchar r; + ulong pg, o; + long m; + uchar *a, *v = buf; + + DPRINT("flash: writex\n"); + pg = offset>>LOG2FPGSZ; + o = offset&(FLASHPGSZ-1); + while (n > 0) { + if (pg < 0 || pg > 7) { + EPRINT("flash: bad write %ld %ld\n", offset, n); + return -1; + } + /* set page */ + r = inb(SYSREG0); + r &= 0x8f; + r |= pg<<4; + outb(SYSREG0, r); + if (o+n > FLASHPGSZ) + m = FLASHPGSZ-o; + else + m = n; + a = (uchar *)f->addr + o; + DPRINT("flash: write page %ld offset %lux buf %lux n %ld\n", pg, o, v-(uchar*)buf, m); + for (i = 0; i < m; i++, v++, a++) { + if (~*a & *v) { + EPRINT("flash: bad write: %lux %lux -> %lux\n", (ulong)a, (ulong)*a, (ulong)*v); + return -1; + } + if (*a == *v) + continue; + s = splhi(); + *a = FLWTM; /* program */ + *a = *v; + splx(s); + microdelay(8); + if(zpcwait(a, 5) <= 0){ + *a = FLCLR; /* clr SR */ + *a = FLRDM; /* read mode */ + f->unusable = ~0; + return -1; + } + *a = FLCLR; + *a = FLRDM; + if (*a != *v) { + EPRINT("flash: write %lux %lux -> %lux failed\n", (ulong)a, (ulong)*a, (ulong)*v); + return -1; + } + } + n -= m; + pg++; + o = 0; + } + return 0; +} + +#ifdef ZERO +/* search the whole of flash */ +static void +flashsearch(Flash *f) +{ + int d, m, p, b, n, i; + uchar r, buf[64]; + + for (d = 0; d < 2; d++) { /* flash device */ + r = inb(SYSREG0); + r &= 0xfb; + r |= (d<<2); + outb(SYSREG0, r); + for (m = 0; m < 2; m++) { /* lower/upper mem */ + if (m == 0) + f->addr = (void *)FLASHMEM; + else + f->addr = (void *)FLASHEND; + for (p = 0; p < 8; p++) { /* page */ + for (b = 0; b < 4; b++) { /* block */ + n = readx(f, (4*p+b)*FLASHBKSZ, buf, 64); + if (n != 0) { + print("bad read in search %d\n", n); + goto end; + } + print("%d %d %d %d : ", d, m, p, b); + if (buf[0] == 0x5a && buf[1] == 0x54) { /* DOS block */ + n = 0; + for (i = 0; i < 64; i++) { + if (buf[i] == 0xff) + n++; + } + if (n == 64-28) + print("un"); + print("used dos\n"); + } + else if (buf[0] == 0x55 && buf[1] == 0xaa) + print("bios start\n"); + else + print("bios ?\n"); + } + } + } + } +end: + r = inb(SYSREG0); + r |= 4; + outb(SYSREG0, r); + f->addr = (void *)FLASHMEM; +} +#endif + +static int +reset(Flash *f) +{ + uchar r; + int s; + ulong pa; + Pcidev *bridge; + + /* get bridge device */ + bridge = pcimatch(nil, 0x8086, 0x7000); /* Intel PIIX3 ISA bridge device */ + if (bridge == nil) { + EPRINT("flash : failed to find bridge device\n"); + return 1; + } + /* enable extended BIOS and read/write */ + s = splhi(); + r = pcicfgr8(bridge, 0x4e); + r |= 0x84; + pcicfgw8(bridge, 0x4e, r); + splx(s); + /* set system register bits */ + r = inb(SYSREG0); + r |= 0x86; /* chip enable, non-BIOS part, set r/w */ + outb(SYSREG0, r); + /* + * might have to grab memory starting at PADDR(FLASHMEM) ie 0x7ff80000 + * because if this is mapped via virtual address FLASHMEM we would get a + * a kernel panic in mmukmap(). + * va = 0xfff80000 pa = 0xfff80000 for flash + * va = 0xfff80000 pa = 0x7ff80000 if lower memory grabbed by anything + */ + /* + * upafree(FLASHMEM, FLASHPGSZ); + * pa = upamalloc(FLASHMEM, FLASHPGSZ, 0); + * if (pa != FLASHMEM) + * error + */ + pa = mmukmap(FLASHMEM, FLASHMEM, FLASHPGSZ); + if (pa != FLASHEND) { + EPRINT("failed to map flash memory"); + return 1; + } +/* + pa = mmukmap(FLASHEND, FLASHEND, FLASHPGSZ); + if (pa != 0) { + EPRINT("failed to map flash memory"); + return 1; + } +*/ + f->id = 0x0089; /* can't use autoselect: might be running in flash */ + f->devid = 0x66a0; + f->read = readx; + f->write = writex; + f->eraseall = eraseall; + f->erasezone = erasezone; + f->suspend = nil; + f->resume = nil; + f->width = 1; /* must be 1 since devflash.c must not read directly */ + f->erasesize = 64*1024; + *(uchar*)f->addr = FLCLR; /* clear status registers */ + *(uchar*)f->addr = FLRDM; /* reset to read mode */ + return 0; +} + +void +flashzpclink(void) +{ + addflashcard("DD28F032SA", reset); +} |
