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

📄 nand.c

📁 QX44B0的BIOS源代码
💻 C
字号:
#include "..\inc\DataType.h"
#include "44b.h"
#include "console.h"
#include "Nand.h"

struct NFChipInfo {
	U32 id;
	U32 size;
}

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

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

extern struct Partition *pNandPart;

static EnvParams Env;

struct Partition *pNandPart = Env.NandPartition;

U32 NandFlashSize;

static U16 NandAddr;
static U16 support;

//#define BAD_CHECK

#define	NAND_DAT	0x02000000
#define	NAND_ALE	0x02000004
#define	NAND_CLE	0x02000002

#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
int NFChkBadBlk(U32 addr);
void NFMarkBadBlk(U32 addr);
void NFChipSel(U32);
int  NFIsReady(void);
void NFWrCmd(int);
void NFWrAddr(int);
void NFWrDat(int);
U8   NFRdDat(void);

#define	NFChipEn()	NFChipSel(1)
#define	NFChipDs()	NFChipSel(0)
#define	NFIsBusy()	(!NFIsReady())

//#define	NFWrCmd(cmd)	*(volatile U8 *)NAND_CLE = (cmd)
//#define	NFWrAddr(addr)	*(volatile U8 *)NAND_ALE = (addr)
//#define	NFWrDat(dat)	*(volatile U8 *)NAND_DAT = (dat)
//#define	NFRdDat()		*(volatile U8 *)NAND_DAT

//#define	WIAT_BUSY_HARD
//#define	ER_BAD_BLK_TEST
//#define	WR_BAD_BLK_TEST
void NFChipSel(U32 sel)
{
	if(sel)
		rPDATC &= ~(1<<9);
	else
		rPDATC |= 1<<9;
}

int NFIsReady(void)
{
	while(!(rPDATC&(1<<8)))
	{}
	return rPDATC&(1<<8);
}

void NFWrCmd(int cmd)
{
	*(volatile U8 *)NAND_CLE = cmd;
}

void NFWrAddr(int addr)
{
	*(volatile U8 *)NAND_ALE = addr;
}

void NFWrDat(int dat)
{
	*(volatile U8 *)NAND_DAT = dat;
}

U8 NFRdDat(void)
{
	return *(volatile U8 *)NAND_DAT;
}


#ifdef	WIAT_BUSY_HARD
#define	NFWaitBusy()	NFIsBusy()
#else
static U32 NFWaitBusy(void)
{
	U8 stat;
	
	NFWrCmd(QUERYCMD);
	do {
		stat = NFRdDat();
	}while(!(stat&0x40));
	NFWrCmd(READCMD0);
	return stat&1;
}
#endif

static U32 NFReadID(void)
{
	U32 id, loop = 0;

	NFChipEn();
	NFWrCmd(READIDCMD);
	NFWrAddr(0);
    while(NFIsBusy()&&(loop<10000)) loop++;
	if(loop>=10000)
		return 0;
	id  = NFRdDat()<<8;
	id |= NFRdDat();
	NFChipDs();
	
	return id;
}

static U16 NFReadStat(void)
{
	U16 stat;
	
	NFChipEn();	
	NFWrCmd(QUERYCMD);
	stat = NFRdDat();	
	NFChipDs();
	
	return stat;
}

void Nand_Read(U32 blockD,U8 *Save_Address,U32 ReadSize)
{
	  U32  i,k,BlockSize;
	  U32  blockPage;
      U8  *read_addr;

	  blockD = blockD & 0x7ff;
	  read_addr = Save_Address;
	  BlockSize = (ReadSize>>14) + 1;
      for(i=0;i<BlockSize;i++)
	  {
	      for(k=0;k<32;k++)    // Read 32 page
		  {
              blockPage=((blockD+i)<<5)+k;
              NFReadPage(blockPage,read_addr);   // Read one page
			  read_addr +=  512; 
              if((U32)read_addr>=((U32)Save_Address+ReadSize)) // Check end of buffer
                break;  // Exit for loop
		  }
	  }
      printf("NandFlas read completed\n");
}
void Nand_Program(U32 targetBlock,U8 *downloadAddress,U32 targetSize)
{
    int i;
    int programError=0;
    U8 *srcPt,*saveSrcPt;
	U32  blockPage;
    U32 blockIndex;

    //NF_Init();

    srcPt=downloadAddress;
    blockIndex=targetBlock & 0x7ff;
    while(1)
    {
        saveSrcPt=srcPt;    
        #ifdef BAD_CHECK       //检查坏块,
            if(NFChkBadBlk(blockIndex<<5))   // 1:bad 0:good
            {
                blockIndex++;   // for next block
                continue;
            }
        #endif
	
        if(NFEraseBlock(blockIndex<<5))    //擦除块。
        {
            NFMarkBadBlk(blockIndex<<5);
            blockIndex++;   // for next block
            continue;
        }
          


        for(i=0;i<32;i++)    //  1 Block = 32 Page;
        {
            printf("p");
            blockPage=(blockIndex<<5)+i;
            if(NFWritePage(blockPage,srcPt))// block num, page num, buffer
            {
                NFMarkBadBlk(blockIndex<<5);
                programError=1;
                break;
            }    
            srcPt+=512; // Increase buffer addr one pase size
            if((U32)srcPt>=((U32)downloadAddress+targetSize)) // Check end of buffer
                break;  // Exit for loop
        }
        if(programError==1)
        {
            blockIndex++;
            srcPt=saveSrcPt;
            programError=0;
            continue;
        }
        if((U32)srcPt>=((U32)downloadAddress+targetSize))
            break;  // Exit while loop
        blockIndex++;
    }
   printf("\nNandFlas Program completed\n");
}


U32 NFEraseBlock(U32 addr)
{
	U8 stat=0;
	U16 i;
	addr &= ~0x1f;
		
	NFChipEn();	
	NFWrCmd(ERASECMD0);		
	NFWrAddr(addr);
	NFWrAddr(addr>>8);
	if(NandAddr)
		NFWrAddr(addr>>16);
	NFWrCmd(ERASECMD1);
	for(i=0;i<10;i++); //wait tWB(100ns)
	stat = NFWaitBusy();
	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
void NFReadPage(U32 addr, U8 *buf)
{
	U16 i;
	
	NFChipEn();
	NFWrCmd(READCMD0);
	NFWrAddr(0);
	NFWrAddr(addr);
	NFWrAddr(addr>>8);
	if(NandAddr)
		NFWrAddr(addr>>16);
//	InitEcc();
    for(i=0;i<10;i++); //wait tWB(100ns)
	NFWaitBusy();		
	for(i=0; i<512; i++)
		buf[i] = NFRdDat();		
	NFChipDs();
}

//addr = page address
U32 NFWritePage(U32 addr, U8 *buf)
{
	U16 i, stat=0;
//	U8 tmp[3];
	
	NFChipEn();
	NFWrCmd(PROGCMD0);
	NFWrAddr(0);
	NFWrAddr(addr);
	NFWrAddr(addr>>8);
	if(NandAddr)
		NFWrAddr(addr>>16);
//	InitEcc();	
	for(i=0; i<512; i++)
		NFWrDat(buf[i]);
		
	if(!addr) {
		NFWrDat('b');
		NFWrDat('o');
		NFWrDat('o');
		NFWrDat('t');		
	}
		
/*	tmp[0] = rNFECC0;
    tmp[1] = rNFECC1;
    tmp[2] = rNFECC2;
    	
	NFWrDat(tmp[0]);
    NFWrDat(tmp[1]);
    NFWrDat(tmp[2]);*/
    	
	NFWrCmd(PROGCMD1);
	stat = NFWaitBusy();
	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;	
}
void NFMarkBadBlk(U32 addr)
{
	int i;
	addr &= ~0x1f;
	
	NFChipEn();
	
	NFWrCmd(READCMD2);	//point to area c
	
	NFWrCmd(PROGCMD0);
	NFWrAddr(0);		//mark offset 0~15
	NFWrAddr(addr);
	NFWrAddr(addr>>8);
	if(NandAddr)
		NFWrAddr(addr>>16);
	for(i=0; i<16; i++)
		NFWrDat(0);		//mark with 0	
	NFWrCmd(PROGCMD1);
	NFWaitBusy();		//needn't check return status
	
	NFWrCmd(READCMD0);	//point to area a
		
	NFChipDs();
}

int NFChkBadBlk(U32 addr)
{
	U8 dat;
	
	addr &= ~0x1f;
	
	NFChipEn();
	
	NFWrCmd(READCMD2);	//point to area c
	NFWrAddr(517&0xf);		//mark offset 5
	NFWrAddr(addr);
	NFWrAddr(addr>>8);
	if(NandAddr)
		NFWrAddr(addr>>16);
	NFWaitBusy();
	dat = NFRdDat();
	
	NFWrCmd(READCMD0);	//point to area a
	
	NFChipDs();
    return(dat!=0xff);
}



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

	//printf("Please select Nand flash region to %s, Esc to abort\n", info);
	
	for(i=0; pNandPart[i].size; i++)
		//printf("%d : start 0x%08x, size 0x%08x\t[part%d]\n", i, pNandPart[i].offset, pNandPart[i].size, i/*pNandPart[i].name*/);
    {}
	max_sel = i;	
	
	while(1) {
		//char c = getch();
		/*
		if(c==0x1b)
			return 0;
		if((c>='0')&&(c<(max_sel+'0')))
			return &(pNandPart[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);
//			printf("Read page %d\n", i);
		i++;
		size -= 512;
		ram_addr += 512;
	}
}

/******************************************************/
int WrFileToNF(U32 src_addr, U32 w_size)
{
	struct Partition *part;
	U32 start_page, i, skip_blks;
	U8 *ram_addr;
	int size;	//must be int
	
	if(!support)
		return -1;
		
	part = NFSelPart("write");
	if(!part)
		return -1;
	
	if(w_size>part->size) {
		//puts("File size is too long!\n");
		return -1;
	}

	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, src_addr, w_size);
	//if(!getyorn())
		//return -1;
		
	skip_blks = 0;
	ram_addr = (U8 *)src_addr;
	size = w_size;
	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(w_size>part->size) {
				puts("Program nand flash fail\n");
				return -1;
			}			
			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);
		
	return 0;	
}

int RdFileFrNF(U32 dst_addr, U32 load_part)
{
	U32 i;
	struct Partition *part;
	
	if(!support)
		return -1;

	for(i=0; pNandPart[i].size; i++);
	if(i>load_part)
		part = pNandPart+load_part;
	else {
		part = NFSelPart("read");
		if(!part)
			return -1;
	}
	
	puts("Loading...\n");
	
	NFReadPart(part, (U8 *)dst_addr);
	
	puts("end\n");
	
	return 0;
}

int EraseNandPart(void)
{
	struct Partition *part;
	U32 start_page, blk_cnt;
	int i, err = 0;	

	if(!support)
		return -1;
		
	part = NFSelPart("erase");
	if(!part)
		return -1;

	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 -1;
	
	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");
	
	return 0;
}

#ifdef	SAVE_ENV_IN_NAND
U32 NFSaveParams(char *pEnv)
{
	char dat[512];
	U32 addr;
	
	if(support) {
		memcpy(dat, pEnv, sizeof(EnvParams));
		for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) {
			NFEraseBlock(addr);
			if(!NFWritePage(addr, (U8 *)dat))
				return 0;
		}
	}
	return -1;
}

U32 NFSearchParams(char *pEnv)
{
	char dat[512];
	U32 addr;
	
	if(support) {
		for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) {
			NFReadPage(addr, (U8 *)dat);		
			if(!strncmp(dat, "params", 7)) {
				memcpy(pEnv, dat, sizeof(EnvParams));			
				return 0;
			}
		}
	}
	return -1;	
}
#endif

static U32 nand_id;

void NandFlashInit(void)
{
	int i;	
	
	support = 0;
	nand_id = NFReadID();
	
	for(i=0; NandFlashChip[i].id!=0; i++)
		if(NandFlashChip[i].id==nand_id) {			
			nand_id = i;
			NandFlashSize = NandFlashChip[i].size;
			support  = 1;
			NandAddr = NandFlashSize>SIZE_32M;
			if(!pNandPart[0].size) {
				pNandPart[0].offset = 0;
				pNandPart[0].size   = NandFlashSize;
				pNandPart[1].size   = 0;				
			}			
			return;
		}
	
}

void NandFlashStatusRep(void)
{
	if(support) {
		printf("Nand Flash ID is 0x%x, Size = %dM, Status = 0x%x\n", NandFlashChip[nand_id].id, NandFlashChip[nand_id].size>>20, NFReadStat());
	} else {
		printf("No supported Nand Flash Found!\n");
	}
}

⌨️ 快捷键说明

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