⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nvram.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
字号:
/*************************************************************
 * 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 <stdio.h>
#include <mips.h>
#include <termio.h>
#include <mon.h>


#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;j<argc;j++) {
	if (argv[j][0] == '-') {
		if (argv[j][1] == 'c') nvClear();
		else if (argv[j][1] == 'v') {
			j++;
			for (i=0;j<argc;j++) {
				for (p=argv[j];*p;p++) nvWrite(i++,*p);
				nvWrite(i++,' ');
				}
			}
		else {
			printf("%s: bad option\n",argv[j][1]);
			printf("usage: [-c] [-v msg]\n");
			exit(1);
			}
		}
	else {
		printf("%s: bad argument\n",argv[j]);
		printf("usage: [-c] [-v msg]\n");
		exit(1);
		}
	}

printf("reading: ");
for (i=0;;i++) {
	c = nvRead(i);
	if (c == 0 || c == 0xff) break;
	putchar(c);
	}
putchar('\n');
}
#endif

/*************************************************************
*  int nvCheck(char *msg)
*/
nvCheck(msg)
char *msg;
{
Ulong r;
int len,i,famcode;
Func *f;
int needcpy;

*msg = 0;
if (nvInfo.nvbase) return(1);

#if 0
/* check to see if I am executing out of flash */
/* do this by checking if I am in the same 8MB as nvInfo.start */
/* if so, I must copy some routines to RAM before executing them */
if ((((Ulong)nvCheck)&~(0x800000-1)) == nvInfo.start&~(0x800000-1)) needcpy=1;
else needcpy = 0;
#else
needcpy=1;
#endif

/* first, find out what nvType we have */
if (needcpy) {
	len = ((Ulong)nvType_end)-((Ulong)nvType);
	f = (Func *)malloc(len + jalBytes(nvType,len/4));
	if (!f) {
		strcpy(msg,"malloc failure 1");
		return(0);
		}
	codecpy(f,nvType,len/4);
	flush_cache(DCACHE);
	flush_cache(ICACHE);
	famcode = (* f)();
	free(f);
	}
else famcode = nvType();

/* look up the famcode in the nvTypes table */
for (i=0;nvTypes[i].driver;i++) {
	if (nvTypes[i].famcode == famcode) break;
	}
if (!nvTypes[i].driver) { /* famcode not found */
	nvInfo.nvbase = 0;
	if (msg && famcode != 0) sprintf(msg,"%04x: Bad flashcode",famcode);
	return(0);
	}
nvInfo.name = nvTypes[i].name;

/* now, install the correct driver */
if (needcpy) {
	len = ((Ulong)nvTypes[i].edriver)-((Ulong)nvTypes[i].driver);
	f = (Func *)malloc(len + jalBytes(nvTypes[i].driver,len/4));
	if (!f) {
		strcpy(msg,"malloc failure 2");
		return(0);
		}
	codecpy(f,nvTypes[i].driver,len/4);
	flush_cache(DCACHE);
	flush_cache(ICACHE);
	nvInfo.driver = f;
	}
else nvInfo.driver = nvTypes[i].driver;

nvInfo.size = nvTypes[i].size;
nvInfo.type = &nvTypes[i];

/* return if this device doesn't support sector erase */
if (!nvTypes[i].se) {
	nvInfo.nvbase = 0;
	if (msg) strcpy(msg,"Function not supported");
	return(0);
	}

/* calculate the correct value for nvbase */
if (nvInfo.nvbase == 0) {
	len = nvInfo.size*nvInfo.width;
	len -= nvTypes[i].se*nvInfo.width;
#if 0 /* we aught to check if there's enough room */
	if (len <= PMONsize) {
		nvInfo.nvbase = 0;
		if (msg) strcpy(msg,"Insufficient space");
		return(0);
		}
#endif
	nvInfo.nvbase = nvInfo.start + len;
	len -= nvTypes[i].se*nvInfo.width;
	nvInfo.dvrsa = nvInfo.start + len;
	}
/*printf("famcode=%04x ",famcode); /*  */
if (msg) strcpy(msg,nvInfo.name);
return(1);
}

/*************************************************************
*  nvWrite(adr,val)
*/
nvWrite(adr,val)
Ulong adr;
int val;
{
if (!nvInfo.nvbase) return;
if (adr == 0) nvClear();
(* nvInfo.driver)(NV_WRITE,nvInfo.nvbase+(adr*nvInfo.gap),val);
}

/*************************************************************
*  nvRead(adr)
*/
nvRead(adr)
Ulong adr;
{
if (!nvInfo.nvbase) return(0);
return inb(nvInfo.nvbase+(adr*nvInfo.gap));
}

/*************************************************************
*  nvClear()
*/
nvClear()
{
int i;

if (!nvInfo.nvbase) return;
if (nvInfo.start == nvInfo.nvbase) (* nvInfo.driver)(NV_ERASE,nvInfo.start);
else {
	for (i=0;i<nvInfo.width;i++) {
		(* nvInfo.driver)(NV_SERASE,nvInfo.nvbase+i);
		}
	}
}

/*************************************************************
*  nvType()
*	determine family code
*	what we do know at start:
*		start address of device
*		gap
*		width
*/
nvType()
{
Ulong adrA,adrB,adr0,adr1;
Ulong msk;
int sh,b1,b2,h0,h1;

sh = nvInfo.width/2;
adrA = (nvInfo.start|(0x5555<<sh));
adrB = (nvInfo.start|(0x2aaa<<sh));
adr0 = (nvInfo.start|(0x0000<<sh));
adr1 = (nvInfo.start|(0x0001<<sh));
b1 = inb(adr0);
b2 = inb(adr1);
h0 =  (b1<<8)|b2; /* read the existing value */

outb(adrA,0xaa); outb(adrB,0x55); outb(adrA,0x90); 
b1 = inb(adr0);
b2 = inb(adr1);
outb(adrA,0xaa); outb(adrB,0x55); outb(adrA,0xf0); 
h1 =  (b1<<8)|b2; /* read the famcode */

if (h0 == h1) return(0); /* must be eprom */
return(h1);
}
nvType_end() {}

/*************************************************************
*  flash28(op,adr,val) 
*/
flash28(op,adr,val) 
int op,val;
Ulong adr;
{
Uchar pvd;
Ulong X,cs;
int plscnt,dev,sh,i;
		 
printf("flash28: op=%d adr=%08x val=%02x\n",op,adr,val&0xff);
switch (op) {
	case NV_WRITE : 
		printf("flash28w: NOT TESTED\n");
		cs = nvInfo.nvbase&~3;
		sh = nvInfo.width/2;
		dev = adr&((1<<sh)-1);
		X = cs|dev; /* any address within the device */
		printf("nvbase=%08x X=%08x\n",nvInfo.nvbase,X);
		for (plscnt=0;plscnt<25;plscnt++) {
			outb(X,0x40); /* prog */
			outb(adr,val);
			for (i=500;i>0;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<<sh))|(0x5555<<sh));
		adrB = ((adr&~(0x1ffff<<sh))|(0x2aaa<<sh));
#if 0
		printf("flash29w: adr=%08x val=%02x adrA=%08x adrB=%08x\n",
			adr,val,adrA,adrB);
#endif
		outb(adrA,0xaa); outb(adrB,0x55); outb(adrA,0xa0); 
		outb(adr,val);
		for (i=0;i<3000;i++) wbflushtmp1 = 0; /* min 100us delay */
		for (cnt=0;;cnt++) {
			epd = inb(adr);
			if ((epd&0x80) == (val&0x80) && epd == val) break; 
			if (epd&(1<<5)) break;
			}
#if 0
		if (epd != val) printf("flash29w: ## TIMEOUT\n");
#endif
		if (epd != val) return(0);
		return(1);
		break;
	case NV_SERASE : 
		sh = nvInfo.width/2;
		adrA = ((adr&~(0x1ffff<<sh))|(0x5555<<sh));
		adrB = ((adr&~(0x1ffff<<sh))|(0x2aaa<<sh));
#if 0
		printf("flash29se: adr=%08x adrA=%08x adrB=%08x\n",
			adr,adrA,adrB);
#endif
		/* unlock, setup */
		outb(adrA,0xaa); outb(adrB,0x55); outb(adrA,0x80); 
		/* unlock, sectEra */
		outb(adrA,0xaa); outb(adrB,0x55); outb(adr,0x30); 
		for (i=0;i<3000;i++) wbflushtmp1 = 0; /* min 100us delay */
		val = 0xff;
		for (cnt=0;cnt<5000000;cnt++) { /* cnt=1.3M is normal */
			epd = inb(adr);
			if ((epd&0x80) == (val&0x80) && epd == val) break; 
			if (epd&(1<<5)) break;
			}
#if 0
		if (epd != val) printf("flash29se: ## TIMEOUT\n");
		printf("flash29se: epd=%02x cnt=%d\n",epd,cnt);
#endif
		if (epd != val) return(0);
		return(1);
		break;
	case NV_ERASE :
		printf("flash29e: NOT IMPLEMENTED\n");
		break;
	default: printf("flash29: %d: bad opcode\n",op);
	}
}
flash29end() {}

#define XL28_TIMEOUT 100000

/*************************************************************
*  xl28(op,adr,val) 
*/
xl28(op,adr,val) 
int op,val;
Ulong adr;
{
int i,n;
Ulong a;

switch (op) {
	case NV_WRITE :
		outb(adr,val);
		for (i=0;i<XL28_TIMEOUT && inb(adr) != val;i++) wbflushtmp1=0;
		if (i >= XL28_TIMEOUT) return(0);
		break;
	case NV_ERASE :
	case NV_SERASE :
		/* clear nvram */
		val = 0xff;
		for (n=0;n<nvInfo.size;n++) {
			if (nvRead(n) != val) {
				a = nvInfo.nvbase+(n*nvInfo.gap);
				outb(a,val);
				for (i=0;i<XL28_TIMEOUT && inb(adr) != val;i++) 
					wbflushtmp1=0;
				if (i >= 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -