📄 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("Are you sure to write nand flash from 0x%x with 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 nand flash partition 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 which program to run?\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 Nand partition completed ");
if(err)
printf("with %d bad block(s)\n", err);
else
puts("success\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 + -