?? nand.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 + -