/************************************************************* * File: lib/nvram.c * Purpose: Part of C runtime library * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970304 Start of revision history * 970311 Added flush_cache(DCACHE) for 4010 copy-back * 970605 Added writeFlash * 970620 Cygnus requires Uchar in flash29. * 970910 Added support for Am29F080. * 971124 Don't create msg for famcode=0000. * 971125 Added code to writeFlash for 4011 copy from boot eprom * 980114 Added delay to start of nvType for GHS+4011. * 980120 Replaced outb() macro with a function. Fixes prob w * nvType check on 4011. Removed delay. * 980324 Fixed problem with outb. It wasn't doing the right thing. * 980508 Added needcpy. * 980508 Flush D before I in nvCheck. * 980509 Discovered that for needcpy=1 outb MUST be a macro. * 980509 The new outb macro works on 4011 but fails on 4101. * 980510 Reverted to old outb macro until real fix is found. * 980602 Delay shrc execution until after the powerup banner. * Do this by setting shrc_needed. * 980715 Modified do_shrc and shrc to support 2 separate init * blocks. Before p2 is executed before the banner. After * p2 is executed after the banner. Only commands that * were specified in the "set nvram" command are located * after the p2. */ /************************************************************* * Performance data: * 3 secs to erase one sector * 128 secs/MB for writes */ #include #include #include #include #define inb(x) (*(volatile Uchar *)(x)) #if 0 #define outb(a,v) *((Uchar *)(a))=((Uchar)(v)) #else /************************************************************* * outb(a,v) * store byte with write buffer flush. * For 4011 you MUST use Kseg1 addresses for tmp1 and tmp2. * 980324 Added & for wbflushtmpX and volatile for wbftX. */ #define outb(a,v) \ { \ volatile int *wbft1,*wbft2; \ \ *((Uchar *)(a))=((Uchar)(v)); \ wbft1 = (int *)(((Ulong)&wbflushtmp1)|K1BASE); \ wbft2 = (int *)(((Ulong)&wbflushtmp2)|K1BASE); \ *wbft1 = 0; \ *wbft2 = *wbft1; \ } #endif int nvType(),nvType_end(); int flash28(),flash28end(); int flash29(),flash29end(); int xl28(),xl28end(); NvType nvTypes[] = { {0x01a2,"Am28F010",0, 128*1024,flash28,flash28end}, {0x01a7,"Am28F010",0, 128*1024,flash28,flash28end}, {0x89b4,"i28F010", 0, 128*1024,flash28,flash28end}, {0x89bd,"i28F020", 0, 256*1024,flash28,flash28end}, {0x0120,"Am29F010",16*1024,128*1024,flash29,flash29end}, {0x01a4,"Am29F040",64*1024,512*1024,flash29,flash29end}, {0xc0a4,"Am29F040",64*1024,512*1024,flash29,flash29end}, {0x01d5,"Am29F080",64*1024,1024*1024,flash29,flash29end}, {0x1f5b,"AT29F040",64*1024,512*1024,flash29,flash29end}, /* atmel */ {0x5010,"XL28C64", 1, 1024,xl28,xl28end}, {0}}; NvInfo nvInfo; #define SPC_BITMSK (3<<21) #define SPC_8BIT (1<<21) #define SPC_16BIT (2<<21) #define SPC_32BIT (3<<21) int machtype; volatile int wbflushtmp1; volatile int wbflushtmp2; int shrc_needed; #ifdef TEST /************************************************************* * main() */ main(argc,argv) int argc; char *argv[]; { int n,i,j,c; char nvtype[40]; machtype = getmachtype(); if (!nvCheck(nvtype)) printf("nvCheck FAILED\n");; printf("nvram: %s\n",nvtype); printf("reading: "); for (i=0;;i++) { c = nvRead(i); if (c == 0 || c == 0xff) break; putchar(c); } putchar('\n'); if (argc == 1) return; for (j=1,i=0;j0;i++) wbflushtmp1 = 0; /* 10us delay */ outb(X,0xc0); /* prog verify */ for (i=300;i>0;i++) wbflushtmp1 = 0; /* 6us delay */ pvd = inb(X); if (val == pvd) break; } printf("pvd=%02x plscnt=%d\n",pvd,plscnt); /* outb(X,0xff); outb(X,0xff); outb(X,0x00); /* reset-rd */ if (plscnt >= 25) return(0); return(1); case NV_ERASE : printf("flash28e: NOT IMPLEMENTED\n"); break; case NV_SERASE : printf("flash28se: NOT supported by device\n"); break; } } flash28end() {} #define P29MAX 10 /* max polling count for 29F devices */ int diagcnt; /************************************************************* * flash29(op,adr,val) */ flash29(op,adr,val) int op; Ulong adr; Uchar val; { Ulong adrA,adrB,adr0,adr1; Uchar epd; int sh,cnt,i; switch (op) { case NV_WRITE : sh = nvInfo.width/2; adrA = ((adr&~(0x1ffff<= XL28_TIMEOUT) return(0); break; case NV_ERASE : case NV_SERASE : /* clear nvram */ val = 0xff; for (n=0;n= XL28_TIMEOUT) return(0); } } break; } } xl28end() {} /************************************************************* * do_shrc() */ do_shrc() { int c,n; char ch,buf[80]; c = 'n'; ioctl(STDIN,FIONREAD,&n); if (n != 0) { for (;;) { ioctl(STDIN,FIONREAD,&n); if (n == 0) break; read(STDIN,&ch,1); } for (;;) { printf("Skip NVRAM read? (y/n)? >"); gets(buf); c = *buf; if (c == 'n' || c == 'y') break; if (c == 'N' || c == 'Y') break; } } if (c == 'Y' || c == 'y') return; shrc(0); shrc_needed = 1; } /************************************************************* * shrc(n) * n=0 do part1 * n=1 do part2 */ shrc(n) int n; { int c; char buf[LINESZ]; unsigned long adr; adr = 0; for (;;) { c = getln(&adr,buf); if (c == 0) break; if (strequ(buf,"p2")) { if (n == 0) break; if (n == 1) n++; } else if (n == 2 || n == 0) do_cmd(buf); } } /************************************************************* * getln(adr,p) */ getln(adr,p) unsigned long *adr; unsigned char *p; { unsigned int c = 0; long addr; addr = *adr; for (;;) { c = nvRead(addr); if (c == 0xff) c = 0; if (c == 0) break; addr++; if (c == '\n') break; *p++ = c; } *adr = addr; *p = 0; return(c); } /************************************************************* * writeFlash(adr,val) * This is used by self-updating flashes (xflash.c) */ writeFlash(adr,val) Ulong adr; Uchar val; { int se,width; Ulong msk; char nvtype[20]; if (!nvInfo.type) return(0); se = nvInfo.type->se; width = nvInfo.width; msk = ((se*width)-1) & ~(width-1); if ((adr&msk) == 0) (* nvInfo.driver)(NV_SERASE,adr); (* nvInfo.driver)(NV_WRITE,adr,val); return(0); } #if 0 /************************************************************* */ printNvInfo() { printf("name=%s start=%08x width=%d size=0x%x gap=%d nvbase=%08x driver=%08x\n", nvInfo.name, nvInfo.start, nvInfo.width, nvInfo.size, nvInfo.gap, nvInfo.nvbase,nvInfo.driver); if (nvInfo.type) printf("famcode=%04x name=%s se=0x%x size=0x%x driver=%08x\n", nvInfo.type->famcode, nvInfo.type->name, nvInfo.type->se, nvInfo.type->size,nvInfo.type->driver); } #endif