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