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

📄 nand.c

📁 LPC2292 bios测试程序 说明:YL_LPC229X_BIOS_Data的目录说明
💻 C
字号:
#include "def.h"
#include "config.h"
#include "board.h"
#include "utils.h"
#include "option.h"
#include "nandflash.h"

#ifdef	NAND_FLASH_SUPPORT

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;

U32 NandFlashSize;

static U16 NandAddr;
static U16 support;

//#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

void NFChipSel( U32 );
int NFIsReady( void );
void NFWrCmd( int );
void NFWrAddr( int );
void NFWrDat( int );
U8 NFRdDat( void );

#define	NFChipEn()	NandFlash_Chip_Enable
#define	NFChipDs()	NandFlash_Chip_Disable
#define	NFIsBusy()	NandFlash_ReadyBusy

#define	NFWrCmd(cmd)	*(volatile U8 *)NandFlash_CLE = (cmd)
#define	NFWrAddr(addr)	*(volatile U8 *)NandFlash_ALE = (addr)
#define	NFWrDat(dat)	*(volatile U8 *)NandFlash_DATA = (dat)
#define	NFRdDat()		*(volatile U8 *)NandFlash_DATA

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

#ifdef	WIAT_BUSY_HARD
#define	NFWaitBusy()	while( !NFIsBusy() )
#else
static U32 NFWaitBusy( void )
{
	U8 stat;

	NandFlash_WR_CLE = 0x70 ;
	do
	{
		stat = NandFlash_WR_DATA;
	}
	while ( !( stat & 0x40 ) ) ;

	NandFlash_WR_CLE = 0x00 ;
	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;
}

static U32 NFEraseBlock( U32 addr )
{
	U8 stat;

	addr &= ~0x1f;

	NFChipEn();	
	NFWrCmd( ERASECMD0 );		
	NFWrAddr( addr );
	NFWrAddr( addr >> 8 );
	if ( NandAddr )
		NFWrAddr( addr >> 16 );
	NFWrCmd( ERASECMD1 );		
	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;
}

/********************************************************/
/*功能:擦除FLASH的一个Block(对应文件系统为一个Cluster) 		 */
/*     每一个簇(或块)为16KB,因此K9F2808共有1024个簇(或块)  	 */
/*输入:unsigned int cluster/block(需要擦除的Block Number)*/
/*返回:OK或FAIL										 */
/********************************************************/
unsigned char nferaseblock( unsigned int cluster )
{
	unsigned int blockPage; 
	unsigned char i;

	blockPage = cluster;
	NandFlash_Chip_Enable ;
	NandFlash_WR_CLE = 0x60;  			//Erase Setup command(60h).
	NandFlash_WR_ALE = ( U8 ) ( blockPage & 0xff ) ; //去掉高位
	NandFlash_WR_ALE = ( U8 ) ( ( blockPage >> 8 ) & 0xff ) ;
	if ( NandAddr )
		NandFlash_WR_ALE = ( U8 ) ( ( blockPage >> 16 ) & 0xff ) ;

	NandFlash_WR_CLE = 0xd0;	 			//The Erase Confirm command(D0h) following the block address loading initiates the internal erasing process.
	for ( i = 0 ; i < 10; i++ )
		;
	while ( !NFIsBusy() ) ;							//wait max 3ms
	for ( i = 0 ; i < 10; i++ )
		;

	NandFlash_WR_CLE = 0x70;
	i = NFWaitBusy() ;
	NandFlash_Chip_Disable ;

	if ( i > 0 )
		return FALSE;
	else
		return TRUE;
}

//addr = page address
static void NFReadPage( U32 addr , U8* buf )
{
	U16 i;

	NFChipEn();
	NFWrCmd( READCMD0 );
	NFWrAddr( 0 );
	NFWrAddr( addr );
	NFWrAddr( addr >> 8 );
	if ( NandAddr )
		NFWrAddr( addr >> 16 );
	//	InitEcc();
	NFWaitBusy();		
	for ( i = 0; i < 512; i++ )
		buf[i] = NFRdDat();		
	NFChipDs();
}

/*****************************************************************/
/*功能:读取FLASH的任意的1page数据  							 */
/*  	在文件系统中,有如下对应关系:  						  */
/*  	Page =Sector					*/
/*输入:存放数据的地址)*/
/*****************************************************************/
void nfreadpage( unsigned short pageWord , unsigned char* buf )
{
	int i;
	
	NandFlash_Chip_Enable ;
	NandFlash_WR_CLE = 0x00; 		//命令
	NandFlash_WR_ALE = 0;
	NandFlash_WR_ALE = pageWord & 0xff;
	NandFlash_WR_ALE = ( pageWord >> 8 ) & 0xff;
	if ( NandAddr )
		NandFlash_WR_ALE = ( U8 ) ( ( pageWord >> 16 ) & 0xff ) ;

	NFWaitBusy();		//random access ,wait max. 10us 
	for ( i = 0; i < 512; i++ )
	{
		*buf++ = ( unsigned char ) ( NandFlash_WR_DATA & 0xff );
	}
	NandFlash_Chip_Disable ;
}

//addr = page address
static U32 NFWritePage( U32 addr , U8* buf )
{
	U16 i, stat;
	//	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;
}


/******************************************************************************
【功能说明】
******************************************************************************/
unsigned char nfwritepage( unsigned short pageWord , unsigned char* buf )
{
	U32 i;
	U16 stat ;
	
	NandFlash_Chip_Enable ;
	NandFlash_WR_CLE = 0x80;
	NandFlash_WR_ALE = 0;
	NandFlash_WR_ALE = pageWord & 0xff;		//ADDR9--ADDR16
	NandFlash_WR_ALE = ( pageWord >> 8 ) & 0xff;		//ADDR17--ADDR23
	if ( NandAddr )
		NandFlash_WR_ALE = ( U8 ) ( ( pageWord >> 16 ) & 0xff ) ;

	for ( i = 0; i < 512; i++ )
	{
		NandFlash_WR_DATA = buf[i];
	}   	  //data input->as the same as _WrPage528()

	NandFlash_WR_CLE = 0x10;
	for ( i = 0; i < 10; i++ )
		;  //twb=100ns. why is it 10? spec is false?  
	while ( !NFIsBusy() );	//wait max 500us;
	stat = NFWaitBusy() ;
	NandFlash_Chip_Disable ;

	if ( stat )
		printf( "Write nand flash 0x%x fail\n" , pageWord );
#if( NF_WRITE_PAGE_VERIFY )		
	else
	{
		U8 RdDat[512];

		nfreadpage( pageWord , RdDat );
		for ( i = 0; i < 512; i++ )
			if ( RdDat[i] != buf[i] )
			{
				printf( "Check data at page 0x%x, offset 0x%x fail, expect %d but %d\n" ,
					pageWord , i , buf[i] , RdDat[i] );
				stat = 1;
				break;
			}
	}
#endif

	if ( stat > 0 )
		return FALSE;
	else
		return TRUE;
}

static 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();
}

static int NFChkBadBlk( U32 addr )
{
	U8 dat;

	addr &= ~0x1f;

	NFChipEn();

	NFWrCmd( READCMD2 );	//point to area c
	NFWrAddr( 5 );		//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: %x, Size = %dM, Status = 0x%x\n" ,
			NandFlashChip[nand_id].id , NandFlashChip[nand_id].size >> 20 ,
			NFReadStat() );
	}
	else
	{
		printf( "Nand Flash ID is: %x," , nand_id ) ;
		printf( " No supported Nand Flash Found!\n" ) ;
	}
}


void NandFlash_Test( void )
{
	U16 m, n ;
	U8 d[36] ;

	NandFlashInit() ;

	NandFlashStatusRep() ;

	//  NandFlash_Test() ;
	//   擦除NandFlash
	printf( "\nNand Flash Erase Block!\n" ) ;
	for ( m = 0 ; m < 0x60 ; m += 0x20 )
		NFEraseBlock( m ) ;

	//给要写入nandflash的数组赋值
	for ( m = 0 ; m < 36 ; m++ )
		d[m] = m ;

	//页写方式将数组依次写入nandflash,一次写入512字节
	printf( "\nNand Flash Write Page!\n" ) ;

	for ( m = 0; m < 3; m++ )
	{
		printf( " " );
		for ( n = 0; n < 12; n++ )
			printf( "%02x " , d[m * 12 + n] ) ;
		printf( "\n" );
	}

	NFWritePage( 0 , d ) ;

	//将数组全部清零
	for ( m = 0 ; m < 36 ; m++ )
		d[m] = 0 ;

	//页读方式将nandflash的0地址数据读出并写到数组
	printf( "\nNand Flash Read Page!\n" ) ;
	NFReadPage( 0 , d ) ;

	//将数组里面的数据依次打印出来,验证写入与读出是否相符

	for ( m = 0; m < 3; m++ )
	{
		printf( " " );
		for ( n = 0; n < 12; n++ )
			printf( "%02x " , d[m * 12 + n] ) ;
		printf( "\n" );
	}

	printf( "\nPress ESC key to exit\n" );
	while ( getkey() != ESC_KEY );
}

#endif	/* NAND_SUPPORT */

⌨️ 快捷键说明

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