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

📄 nand.c

📁 at91rm9200 bios v1.1 源码
💻 C
字号:
#include "AT91RM9200.h"
#include "lib_AT91RM9200.h"
#include "def.h"
#include "config.h"
#include "console.h"
#include "params.h"

#ifdef	NAND_SUPPORT

struct NFChipInfo {
	U32 id;
	U32 size;
}

static NandFlashChip[] = {
	{0xec73, SIZE_16M},
	{0xec75, SIZE_32M},
	{0xec76, SIZE_64M},
	{0, 0},
};

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

static struct Partition NandPart[] = {
	{0x00000000, 0x00030000, "boot"},
	{0x00030000, 0x001d0000, "kernel"},
	{0x00200000, 0x00600000, "rootfs"},
	{0x00800000, 0x00800000, "ext-fs1"},
	{0x01000000, 0x01000000, "ext-fs2"},
	{0x00000000, 0x00000000, 0}
};

static U16 NandAddr;
static U16 HaveNandChip;

#define	NAND_DAT	0x40000000
#define	NAND_ALE	0x40000040
#define	NAND_CLE	0x40400080

#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	READIDCMD	0x90

#define	NFChipEn()	AT91F_PIO_ClearOutput(AT91C_BASE_PIOC, AT91C_PIO_PC15)
#define	NFChipDs()	AT91F_PIO_SetOutput(AT91C_BASE_PIOC, AT91C_PIO_PC15)

#define	NFIsBusy()	(!(AT91F_PIO_GetInput(AT91C_BASE_PIOC)&AT91C_PIO_PC14))

#define	WrNFCmd(cmd)	*(volatile U8 *)NAND_CLE = (cmd)
#define	WrNFAddr(addr)	*(volatile U8 *)NAND_ALE = (addr)
#define	WrNFDat(dat)	*(volatile U8 *)NAND_DAT = (dat)
#define	RdNFDat()		*(volatile U8 *)NAND_DAT

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

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

static U32 NFReadID(void)
{
	U32 id;

	NFChipEn();
	WrNFCmd(READIDCMD);
	WrNFAddr(0);
	while(NFIsBusy());
	id  = RdNFDat()<<8;
	id |= RdNFDat();
	NFChipDs();
	
	return id;
}

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

static U32 NFEraseBlock(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%08x %s\n", addr, stat?"fail":"ok");
	
	return stat;
}

//addr = page address
static void NFReadPage(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();
}

//addr = page address
static U32 NFWritePage(U32 addr, U8 *buf)
{
	U16 i, stat;
//	U8 tmp[3];
	
	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]);
	
	if(!addr) {
		WrNFDat('b');
		WrNFDat('o');
		WrNFDat('o');
		WrNFDat('t');		
	}
		
/*	tmp[0] = rNFECC0;
    tmp[1] = rNFECC1;
    tmp[2] = rNFECC2;
    	
	WrNFDat(tmp[0]);
    WrNFDat(tmp[1]);
    WrNFDat(tmp[2]);*/
    	
	WrNFCmd(PROGCMD1);
	stat = WaitNFBusy();
	NFChipDs();
	
#ifdef	WR_BAD_BLK_TEST
	if((addr&0xff)==0x17) stat = 1;	//just for test bad block
#endif
	
	if(stat)
		printf("Write nand flash 0x%x fail\n", addr);
	else {	
		U8 RdDat[512];
		
		NFReadPage(addr, RdDat);
		for(i=0; i<512; i++)
			if(RdDat[i]!=buf[i]) {
				printf("Check data at page 0x%x, offset 0x%x fail\n", addr, i);
				stat = 1;
				break;
			}
	}
		
	return stat;	
}

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

static int NFChkBadBlk(U32 addr)
{
	U8 dat;
	
	addr &= ~0x1f;
	
	NFChipEn();
	
	WrNFCmd(READCMD2);	//point to area c
	WrNFAddr(5);		//mark offset 4,5
	WrNFAddr(addr);
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);
	WaitNFBusy();
	dat = RdNFDat();
	
	WrNFCmd(READCMD0);	//point to area a
	
	NFChipDs();

	return (dat!=0xff);
}



static struct Partition *NandPartSel(char *info)
{
	int i, max_sel;

	printf("Please select Nand flash region to %s, Esc to abort\n", info);
	
	for(i=0; NandPart[i].size; i++)
		printf("%d : start 0x%08x, size 0x%08x\t[%s]\n", i, NandPart[i].offset, NandPart[i].size, NandPart[i].name);

	max_sel = i;	
	
	while(1) {
		char c = getch();
		
		if(c==0x1b)
			return 0;
		if((c>='0')&&(c<(max_sel+'0')))
			return &(NandPart[c-'0']);
	}	
}

static void NFReadPart(struct Partition *part, U8 *buf)
{
	U32 i, start_page;
	U8 *ram_addr;
	int size;
	
	start_page = part->offset>>9;
	size = part->size;
	ram_addr = buf;
	
	for(i=0; size>0; ) {
		if(!(i&0x1f)) {
			if(NFChkBadBlk(i+start_page)) {
				printf("Skipped bad block at 0x%08x\n", i+start_page);
				i += 32;
				size -= 32<<9;
				continue;
			}
		}
		NFReadPage((i+start_page), ram_addr);
		i++;
		size -= 512;
		ram_addr += 512;
	}
}

#endif	/* NAND_SUPPORT */

/******************************************************/
void WrFileToNF(U32 FileAddr, U32 FileSize)
{
#ifdef	NAND_SUPPORT
	struct Partition *part;
	U32 start_page, i, skip_blks;
	U8 *ram_addr;
	int size;	//must be int
	
	if(!HaveNandChip)
		return;
		
	part = NandPartSel("write");
	if(!part)
		return;
	
	if(FileSize>part->size) {
		puts("File size is too long!\n");
		return;
	}

	start_page = part->offset>>9;
	
	printf("Are you sure to write nand flash from 0x%x with ram address 0x%x, size %d ?\n", part->offset, FileAddr, FileSize);
	if(!getyorn())
		return;
		
	skip_blks = 0;
	ram_addr = (U8 *)FileAddr;
	size = FileSize;
	for(i=0; size>0; )	{
		if(!(i&0x1f)) {
			if(NFEraseBlock(i+start_page)) {
/*				part->size -= 32<<9;	//fail, partition available size - 1 block size
				if(FileSize>part->size) {
					puts("Program nand flash fail\n");
					return;
				}
				NFMarkBadBlk(i+start_page);
				skip_blks++;
				i += 32;			
				continue;*/
				goto WrFileToNFErr;
			}
		}
		if(NFWritePage(i+start_page, ram_addr)) {
			ram_addr -= (i&0x1f)<<9;
			size += (i&0x1f)<<9;
			i &= ~0x1f;
WrFileToNFErr:			
			part->size -= 32<<9;	//partition available size - 1 block size
			if(FileSize>part->size) {
				puts("Program nand flash fail\n");
				return;
			}			
			NFMarkBadBlk(i+start_page);
			skip_blks++;			
			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);
	
#endif	/* NAND_SUPPORT */
}

extern U32 downloadAddress;
void start_kernel(U32, U32);

void RdFileFrNF(U32 FileAddr, U32 FileSize)
{
#ifdef	NAND_SUPPORT
	U32 initrd, bootpart;
	if(!HaveNandChip)
		return;
		
	puts("Select which program to run?\n");
	puts("1: Kernel without initrd\n");
	puts("2: Kernel with initrd\n");
	puts("3: NAND-BOOT\n");
	puts("ESC : exit\n");
	
	while(1) {
		char c = getch();
		
		if(c==0x1b)
			return;

		if((c=='1')||(c=='2')) {
			downloadAddress = LINUX_KERNEL_ADDR;
			bootpart = 1;
			initrd = (c=='1')?0:INITRD_START;
			break;
		}
		if(c=='3') {			
			downloadAddress = BOOT_PORG_ADDR;
			bootpart = 0;
			initrd = 0;
			break;
		}
	}

	puts("Loading...\n");
	
	NFReadPart(&NandPart[bootpart], (U8 *)downloadAddress);
	if(initrd)
		NFReadPart(&NandPart[2], (U8 *)initrd);

	start_kernel(downloadAddress, initrd);
	
#endif	/* NAND_SUPPORT */
}

void EraseNandPart(U32 a1, U32 a2)
{
#ifdef	NAND_SUPPORT
	struct Partition *part;
	U32 start_page, blk_cnt;
	int i, err = 0;	

	if(!HaveNandChip)
		return;
		
	part = NandPartSel("erase");
	if(!part)
		return;

	start_page = part->offset>>9;
	blk_cnt  = part->size>>14;

	printf("Are you sure to erase nand flash from page 0x%x, block count 0x%x ?", start_page, blk_cnt);
	if(!getyorn())
		return;
	
	for(i=0; blk_cnt; blk_cnt--, i+=32) {
		if(NFEraseBlock(i+start_page)) {
			err ++;
			puts("Press any key to continue...\n");
			getch();
		}
	}
	
	puts("Erase Nand partition completed ");
	if(err)
		printf("with %d bad block(s)\n", err);
	else
		puts("success\n");
		
#endif	/* NAND_SUPPORT */
}

#ifdef	NAND_SUPPORT
static __inline void FindNandBoot(void)
{
	NFChipEn();
	WrNFCmd(READCMD2);
	WrNFAddr(0);
	WrNFAddr(0);
	WrNFAddr(0);
	if(NandAddr)
		WrNFAddr(0);
	WaitNFBusy();
	
	if(RdNFDat()=='b')
		if(RdNFDat()=='o')
			if(RdNFDat()=='o')
				if(RdNFDat()=='t') {
					void (*fp)(void);
					
					NFChipDs();
					printf("boot\n");
					fp = (void (*)(void))0x20008000;
					NFReadPart(NandPart, (U8 *)fp);
					(*fp)();
				}
				
	NFChipDs();
}
#endif

void GetNandFlashChip(void)
{
#ifdef	NAND_SUPPORT
	int i;
	U32 id;
	
	HaveNandChip = 0;
	id = NFReadID();
	printf("Nand Flash ID = 0x%x, status = 0x%x\n", id, NFReadStat());
	
	for(i=0; NandFlashChip[i].id!=0; i++)
		if(NandFlashChip[i].id==id) {
			printf("This nand flash chip size = %dM\n", NandFlashChip[i].size>>20);
			HaveNandChip = 1;
			NandAddr = (NandFlashChip[i].size>SIZE_32M)?1:0;
			FindNandBoot();
			return;
		}
		
#endif	/* NAND_SUPPORT */
}

void TestNandFlash(U32 a1, U32 a2)
{
#ifdef	NAND_SUPPORT
#ifdef	NAND_TEST
	U32 i;
	U32 blk;
	U8 dat[512];
	
	if(!HaveNandChip)
		return;
	
	blk = 0x180;	//page number
//	printf("Erase Block 0x%x...\n", blk);
//	NFEraseBlock(blk);
//	printf("status = %x\n", NFReadStat());
	for(i=0; i<512; i++)
		dat[i] = ~(i&0xff);
//	NFWritePage(blk, dat);
	for(i=0; i<512; i++)
		dat[i] = 0;
	
	NFReadPage(blk, dat);
	for(i=0; i<512; i++)
		printf("%4x,", dat[i]);
#endif
#endif	/* NAND_SUPPORT */
}

⌨️ 快捷键说明

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