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