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

📄 nand.c

📁 s3c2410 bios程序 可引导wince linux vxworks
💻 C
字号:
#include "def.h"
#include "2410addr.h"
#include "2410lib.h"
#include "ecc.h"

#define	EnNandFlash()	(rNFCONF |= 0x8000)
#define	DsNandFlash()	(rNFCONF &= ~0x8000)
#define	InitEcc()		(rNFCONF |= 0x1000)
#define	NoEcc()			(rNFCONF &= ~0x1000)
#define	NFChipEn()		(rNFCONF &= ~0x800)
#define	NFChipDs()		(rNFCONF |= 0x800)

#define	WrNFCmd(cmd)	(rNFCMD = (cmd))
#define	WrNFAddr(addr)	(rNFADDR = (addr))
#define	WrNFDat(dat)	(rNFDATA = (dat))
#define	RdNFDat()		(rNFDATA)
#define	RdNFStat()		(rNFSTAT)
#define	NFIsBusy()		(!(rNFSTAT&1))
#define	NFIsReady()		(rNFSTAT&1)

//#define	WIAT_BUSY_HARD	1
//#define	ER_BAD_BLK_TEST
//#define	WR_BAD_BLK_TEST

#define	READCMD0	0
#define	READCMD1	1
#define	READCMD2	0x50
#define	ERASECMD0	0x60
#define	ERASECMD1	0xd0
#define	PROGCMD0	0x80
#define	PROGCMD1	0x10
#define	QUERYCMD	0x70
#define	RdIDCMD		0x90

static U16 NandAddr;

int Write_partition_table(void);

static void InitNandCfg(void)
{
	//enable nand flash control, initilize ecc, chip disable,
	rNFCONF = (1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7);	
}

#ifdef	WIAT_BUSY_HARD
#define	WaitNFBusy()	while(NFIsBusy())
#else
static U32 WaitNFBusy(void)	// R/B 未接好?
{
	U8 stat;
	
	WrNFCmd(QUERYCMD);
	do {
		stat = RdNFDat();
		//printf("%x\n", stat);
	}while(!(stat&0x40));
	WrNFCmd(READCMD0);
	return stat&1;
}
#endif

static U32 ReadChipId(void)
{
	U32 id;
	
	NFChipEn();	
	WrNFCmd(RdIDCMD);
	WrNFAddr(0);
	while(NFIsBusy());	
	id  = RdNFDat()<<8;
	id |= RdNFDat();		
	NFChipDs();		
	
	return id;
}

static U16 ReadStatus(void)
{
	U16 stat;
	
	NFChipEn();	
	WrNFCmd(QUERYCMD);		
	stat = RdNFDat();	
	NFChipDs();
	
	return stat;
}

static U32 EraseBlock(U32 addr)
{
	U8 stat;

	addr &= ~0x1f;
		
	NFChipEn();	
	WrNFCmd(ERASECMD0);		
	WrNFAddr(addr);
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);
	WrNFCmd(ERASECMD1);		
	stat = WaitNFBusy();
	NFChipDs();
	
#ifdef	ER_BAD_BLK_TEST
	if(!((addr+0xe0)&0xff)) stat = 1;	//just for test bad block
#endif
	
	//printf("Erase block 0x%x %s\n", addr, stat?"fail":"ok");
	putch('.');
	return stat;
}

//addr = page address
static void ReadPage(U32 addr, U8 *buf)
{
	U16 i;
	
	NFChipEn();
	WrNFCmd(READCMD0);
	WrNFAddr(0);
	WrNFAddr(addr);
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);
	InitEcc();
	WaitNFBusy();
	for(i=0; i<512; i++)
		buf[i] = RdNFDat();
	NFChipDs();
}

static U32 WritePage(U32 addr, U8 *buf, U8 Ecc_type)
{
	U16 i;
	U8 ecc[3];
	U8 oob_buf[16];
	
	NFChipEn();
	WrNFCmd(PROGCMD0);
	WrNFAddr(0);
	WrNFAddr(addr);
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);
	InitEcc();	
	for(i=0; i<512; i++)
		WrNFDat(buf[i]);
		
	for(i=0; i<16; i++)
		oob_buf[i] = 0xff;
	
	if(Ecc_type) 
	{
		nand_calculate_ecc(buf, ecc);
		oob_buf[8] = ecc[0];
		oob_buf[9] = ecc[1];		
		oob_buf[10] =ecc[2];
	
		nand_calculate_ecc(buf+256, ecc);
		oob_buf[11] = ecc[0];
		oob_buf[12] = ecc[1];		
		oob_buf[13] = ecc[2];
	}
	else
	{
		oob_buf[0] = rNFECC0;
		oob_buf[1] = rNFECC0;
		oob_buf[2] = rNFECC0;
	}
		

    for(i=0;i<16;i++)
    	WrNFDat(oob_buf[i]);	// Write spare array(ECC and Mark)

    WrNFCmd(PROGCMD1);   // Write 2nd command
    
	if(WaitNFBusy())    //wait tPROG 200~500us;
	{
		NFChipDs();
		printf("write page error!\n");
		return 1;
	}
		
	NFChipDs();	
	
  	return 0;
  	
}

static void MarkBadBlk(U32 addr)
{
	addr &= ~0x1f;
	
	NFChipEn();
	
	WrNFCmd(READCMD2);	//point to area c
	
	WrNFCmd(PROGCMD0);
	WrNFAddr(4);		//mark offset 4,5,6,7
	WrNFAddr(addr); 
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);
	WrNFDat(0);			//mark with 0
	WrNFDat(0);
	WrNFDat(0);			//mark with 0
	WrNFDat(0);
	WrNFCmd(PROGCMD1);
	WaitNFBusy();		//needn't check return status
	
	WrNFCmd(READCMD0);	//point to area a
		
	NFChipDs();
}

static int CheckBadBlk(U32 addr)
{
	U8 dat1; //, dat2;
	
	addr &= ~0x1f;
	
	NFChipEn();
	
	WrNFCmd(READCMD2);	//point to area c
	WrNFAddr(5);		//mark offset 4,5,6,7
	WrNFAddr(addr);		//the first page
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);
	WaitNFBusy();
	dat1 = RdNFDat();
/*	
	WrNFCmd(READCMD2);	//point to area c
	WrNFAddr(5);		//mark offset 4,5,6,7
	WrNFAddr(addr+1);	//the second page
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);
	WaitNFBusy();
	dat2 = RdNFDat();
*/
	WrNFCmd(READCMD0);	//point to area a
	
	NFChipDs();

	return (dat1!= 0xff); // || (dat2 != 0xff));
}

/************************************************************/
struct Partition{
	U32 offset;
	U32 size;
	char *name;
};

static struct Partition NandPart[] = {
	{0, 		 0x00030000, "boot"},		//192K
	{0x00030000, 0x00030000, "ucos-ii"},	//192K
	{0x00060000, 0x001a0000, "linux kernel"}, 
	{0x00200000, 0x01e00000, "rootfs"},		//30M
	//{0x02000000, 0x01ffc000, "wince"},	//32M - 16k
	{0x02000000, 0x00800000, "wince"},	//31M
	{0,			 0         , 0}
};

U32 rootfs_num_badblock;
U32 rootfs_badblock[20];



static U32 StartPage, BlockCnt;
extern U32 downloadAddress; 
extern U32 downloadFileSize;


static int NandSelPart(char *info)
{
	U16 i, max_sel;
	struct Partition *ptr = NandPart;
	
	printf("Please select which region to %s : Esc to abort\n", info);
	
	for(i=0; ptr->size!=0; i++, ptr++)
		printf("%d : offset 0x%-8x, size 0x%-8x [%s]\n", i, ptr->offset, ptr->size, ptr->name);
		
	max_sel = i;
	
	while(1) {
		i = getch();
		if(i==0x1b)
			return -1;
		if((i>='0')&&(i<(max_sel+'0'))) {
			i -= '0';
			StartPage = NandPart[i].offset>>9;
			BlockCnt  = NandPart[i].size>>14;
			return i;
		}
	}	
}

static void WrFileToNF(void)
{
	int nf_part, i ,size, skip_blks;
	U32 ram_addr;
	
	nf_part = NandSelPart("write");
	if(nf_part<0)
		return;	
	
	if(downloadFileSize>NandPart[nf_part].size) {
		puts("Download file size is more large than selected partition size!!!\n");
//		return;
	}
	
	printf("Now write nand flash page 0x%x from ram address 0x%x, filesize = %d\n", StartPage, downloadAddress, downloadFileSize);
	puts("Are you sure? [y/n]\n");
	while(1) {
		char c = getch();
		if((c=='y')||(c=='Y'))
			break;
		if((c=='n')||(c=='N'))			
			return;
	}
	
	skip_blks = 0;
	ram_addr = downloadAddress;
	size = downloadFileSize;
	if(nf_part == 3)			//初始化文件系统分区的bad block数目
		rootfs_num_badblock = 0;
	for(i=0; size>0; )	{	
		if(!(i&0x1f)) {				
			if(EraseBlock(i+StartPage)) {
				MarkBadBlk(i+StartPage);
				skip_blks++;
				if(nf_part == 3){
					//printf("Skiped  bad block %x!\n", i >> 5);	
					rootfs_badblock[rootfs_num_badblock] = i >> 5;
					rootfs_num_badblock++;				
				}
				i += 32;				
				continue;
			}
			if(CheckBadBlk(i+StartPage)){
				MarkBadBlk(i+StartPage);
				skip_blks++;
				if(nf_part == 3){
					//printf("Skiped  bad block %x!!\n", i >> 5);	
					rootfs_badblock[rootfs_num_badblock] = i >> 5;
					rootfs_num_badblock++;				
				}
				i += 32;				
				continue;
			}
		}
		if(WritePage(i+StartPage, (U8 *)ram_addr, nf_part)) {
			ram_addr -= (i&0x1f)<<9;
			size += (i&0x1f)<<9;
			i &= ~0x1f;
			NandPart[nf_part].size -= 32<<9;	
			MarkBadBlk(i+StartPage);
			skip_blks++;
			if(nf_part == 3){
				printf("Skiped  bad block %x\n", (i+StartPage) >> 5);	
				rootfs_badblock[rootfs_num_badblock] = (i+StartPage) >> 5;
				rootfs_num_badblock++;					
			}
			i += 32;			
			continue;
		}
		ram_addr += 512;
		size -= 512;
		i++;
	}

	puts("Program nand flash partition success\n");
	if(skip_blks)
		printf("Skiped %d bad block(s)\n", skip_blks);	
	if(nf_part == 3)				//if root fs partition, write partition table
		Write_partition_table();
}

#define LINUX_PAGE_SHIFT	12
#define LINUX_PAGE_SIZE		(1<<LINUX_PAGE_SHIFT)
#define COMMAND_LINE_SIZE 	1024

struct param_struct {
    union {
	struct {
	    unsigned long page_size;			/*  0 */
	    unsigned long nr_pages;				/*  4 */
	    unsigned long ramdisk_size;			/*  8 */
	    unsigned long flags;				/* 12 */
#define FLAG_READONLY	1
#define FLAG_RDLOAD		4
#define FLAG_RDPROMPT	8
	    unsigned long rootdev;				/* 16 */
	    unsigned long video_num_cols;		/* 20 */
	    unsigned long video_num_rows;		/* 24 */
	    unsigned long video_x;				/* 28 */
	    unsigned long video_y;				/* 32 */
	    unsigned long memc_control_reg;		/* 36 */
	    unsigned char sounddefault;			/* 40 */
	    unsigned char adfsdrives;			/* 41 */
	    unsigned char bytes_per_char_h;		/* 42 */
	    unsigned char bytes_per_char_v;		/* 43 */
	    unsigned long pages_in_bank[4];		/* 44 */
	    unsigned long pages_in_vram;		/* 60 */
	    unsigned long initrd_start;			/* 64 */
	    unsigned long initrd_size;			/* 68 */
	    unsigned long rd_start;				/* 72 */
	    unsigned long system_rev;			/* 76 */
	    unsigned long system_serial_low;	/* 80 */
	    unsigned long system_serial_high;	/* 84 */
	    unsigned long mem_fclk_21285;       /* 88 */
	} s;
	char unused[256];
  } u1;
    union {
	char paths[8][128];
	struct {
	    unsigned long magic;
	    char n[1024 - sizeof(unsigned long)];
	} s;
    } u2;
    char commandline[COMMAND_LINE_SIZE];
};

extern char boot_params[];
extern void  call_linux(U32 a0, U32 a1, U32 a2);

static void LoadRun(int part_sel)
{
	U32 i, ram_addr, buf = 0x30200000;
	struct param_struct *params = (struct param_struct *)0x30000100;
	int size;

	//copy kernel image
	StartPage = NandPart[part_sel].offset>>9;
	size = NandPart[part_sel].size;
	ram_addr = buf;	
			
	for(i=0; size>0; ) {
		if(!(i&0x1f)) {
			puts(".");
			if(CheckBadBlk(i+StartPage)) {
				printf("Skipped bad block at 0x%x\n", i+StartPage);
				i += 32;
				size -= 32<<9;
				continue;
			}
		}
		ReadPage((i+StartPage), (U8 *)ram_addr);
		i++;
		size -= 512;
		ram_addr += 512;
	}
	DsNandFlash();

	if(part_sel == 2)
	{
		for(i=0; i<(sizeof(struct param_struct)>>2); i++)
			((U32 *)params)[i] = 0;
		params->u1.s.page_size = LINUX_PAGE_SIZE;
		params->u1.s.nr_pages = (0x04000000 >> LINUX_PAGE_SHIFT);
		for(i=0; boot_params[i]; i++)
			params->commandline[i] = boot_params[i];
		puts("\nImage Load Succefull!\n");
		puts("\nboot params = ");
		puts(boot_params);
		putch('\n');
	}
	else
		puts("\nImage Load Succefull!\n");
	call_linux(0, 193, buf);
}

/************************************************************/
static int support=0;
static void InitNandFlash(void)
{	
	U32 i;
	
	InitNandCfg();
	i = ReadChipId();
	printf("Read chip id = %x\n", i);	
	if((i==0x9873)||(i==0xec75))	
		NandAddr = 0;
	else if(i==0xec76)
	{	
		support=1;	//by chang
		NandAddr = 1;
	}
	else {	
		puts("Chip id error!!!\n");
		return;
	}
	printf("Nand flash status = %x\n", ReadStatus());
}

void NandErase(void)
{
	int i, err = 0;
	
	InitNandFlash();
	
	i = NandSelPart("erase");
	if(i<0)
		return;	
	
	printf("Are you sure to erase nand flash from page 0x%x, block count 0x%x ? [y/n]\n", StartPage, BlockCnt);
	while(1) {
		char c;
		
		c = getch();
		if((c=='y')||(c=='Y'))
			break;
		if((c=='n')||(c=='N'))
			return;
	}	
	
	for(i=0; BlockCnt; BlockCnt--, i+=32) {
		if(EraseBlock(i+StartPage)) {
			err ++;
			puts("Press any key to continue...\n");
			getch();
		}
	}	
		
	DsNandFlash();		//disable nand flash interface
	puts("Erase Nand partition completed ");
	if(err)
		printf("with %d bad block(s)\n", err);
	else
		puts("success\n");
}

void NandWrite(void)
{
	InitNandFlash();
	WrFileToNF();
	DsNandFlash();		//disable nand flash interface
}

void NandLoadRun(int Auto_Run)
{
	InitNandFlash();
	if(Auto_Run == 1)
	{
		puts("Now Boot Linux!\n");
		LoadRun(2);
	}
	else if(Auto_Run == 2)
	{
		printf("Now boot Wince\n");
		LoadRun(4);
	}
	else if(Auto_Run == 3)
	{
		printf("Now boot ucos-ii\n");
		LoadRun(1);
	}
	else
		return;	
}

void memcpy(void *s1, const void *s2, int n)
{
	int i;

	for (i = 0; i < n; i++)
		((char *)(s1))[i] = ((const char *)(s2))[i];
}

int strncmp(const char *s1, const char *s2, int maxlen)
{
	int i;

	for(i = 0; i < maxlen; i++) {
		if(s1[i] != s2[i])
			return ((int) s1[i]) - ((int) s2[i]);
		if(s1[i] == 0)
			return 0;
	}

	return 0;
}


#define MAX_TRY_TIME  5

int Write_partition_table()
{
	U32  buf[128];
	int i,k;
	int j=3;
	int partition_page;
	int try_time;
	
	for(i=0; ; i++)
	{
		if(NandPart[i].size == 0)
			break;
		else
		{
			buf[j++] = NandPart[i].offset;
			buf[j++] = NandPart[i].size;
			buf[j++] = 0x0; 			//flag
		}
	}

	buf[j++] = 0x0; 					//number of bad blocks for partition 0
	buf[j++] = 0x0;						//partition 1
	buf[j++] = 0x0;						//partition 2
	buf[j++] = rootfs_num_badblock;		//partition 3
	for(k=0; k<rootfs_num_badblock; k++)
	buf[j++] = rootfs_badblock[k];	
	buf[j++] = 0x0;						//partition 4
	

	
	for(; j<128; j++)
		buf[j] = 0xffffffff;
	
	buf[2] = i;
	buf[1] = 0x495a00;
	buf[0] = 0x4900004d;
	
	if(NandAddr)
		partition_page = 4095 * 32;
	else
		partition_page = 2047 * 32;
	
	for(try_time=0; try_time<MAX_TRY_TIME; try_time++){		
		if(EraseBlock(partition_page)) {
			MarkBadBlk(partition_page);
			partition_page -= 32;
			continue;
		}
		else if(WritePage(partition_page, (U8 *)buf, 0)){
			MarkBadBlk(partition_page);
			partition_page -= 32;
			continue;
		}
		else{
		//	printf("partition table write successful at page 0x%x!\n", partition_page);
			return 0;	
		}
	}	

	puts("Write partition table fail!\n");
	return 1;
}

#define SAVE_ENV_IN_NAND
#ifdef	SAVE_ENV_IN_NAND

U32 NFSaveParams(char *pEnv)
{	
	char dat[512];
	U32 addr;
	InitNandFlash();
	if(support) {
		memcpy(dat, pEnv, sizeof(EnvParams));
		for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) {
			 EraseBlock(addr);
			 if(!WritePage(addr, (U8 *)dat, 1))
			 {
				//printf("wite succes\n");
				return 0;
			 }
		}
	}
	return -1;
	
}


U32 NFSearchParams(char *pEnv)
{
	char dat[512];
	U32 addr;
	InitNandFlash();
	if(support) {
		for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) {
			ReadPage(addr, (U8 *)dat);		
			memcpy(pEnv, dat, sizeof(EnvParams));			
			return 0;	
		}
	}
	return -1;	
}

#endif
/********************** add by chang *********************************/

⌨️ 快捷键说明

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