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

📄 nand.c

📁 YL9200开发板的测试代码,详细请下载后细看
💻 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( "Sure to write nand flash from 0x%x to 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 NandFlash  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:\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 completed " );
	if ( err )
		printf( "with %d bad block(s)\n" , err );
	else
		puts( "ok\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 + -