?? nand.c
字號:
#include "..\inc\def.h"
#include "..\inc\44b.h"
#include "..\inc\44blib.h"
#include "..\pro\nand.h"
#define NAND_SUPPORT
#ifdef NAND_SUPPORT
#define LINUX_KERNEL_ADDR 0x0c000000
#define INITRD_START 0x0c200000
#define BOOT_PORG_ADDR 0x0c400000
struct NFChipInfo {
U32 id;
U32 size;
}static NandFlashChip[4] = {
{0xec73, SIZE_16M},
{0xec75, SIZE_32M},
{0xec76, SIZE_64M},
{0, 0},
};
struct Partition{
U32 offset;
U32 size;
char *name;
};
struct Partition NandPartition[6] = {
{0x00000000, 0x00200000, "boot"},
{0x00200000, 0x00200000, "kernel"},
{0x00400000, 0x00200000, "rootfs"},
{0x00600000, 0x00200000, "ext-fs1"},
{0x00800000, 0x00200000, "ext-fs2"},
{0x00000000, 0x00000000, 0}
};
/*
EQU R/B(READY/BUSY) PC0
EQU /CEB(CHIP_ENABLE) PC1
EQU CLE(COMMAND) PC2
EQU ALE(ADDRESS) PC3
WEB SMCWE NGCS1 0X02000000
REB SWCOE NGCS1 0X02000000
EQU WPB VDD
EQU SEB GND
*/
U32 NandFlashSize;
static U16 NandAddr;
static U16 HaveNandChip;
#define NAND_DAT 0x02000000
#define NAND_CLE(t) (t?(rPDATC |= 1<<2):(rPDATC &= ~(1<<2)))
#define NAND_ALE(t) (t?(rPDATC |= 1<<3):(rPDATC &= ~(1<<3)))
#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() (rPDATC &= ~(1<<1))
#define NFChipDs() (rPDATC |= 1<<1)
#define NFIsBusy() (!(rPDATC&(1)))
#define WrNFDat(dat) *(volatile U8 *)NAND_DAT = (dat)
#define RdNFDat() *(volatile U8 *)NAND_DAT
//#define WIAT_BUSY_HARD 0
//#define ER_BAD_BLK_TEST 0
//#define WR_BAD_BLK_TEST 0
#ifdef WIAT_BUSY_HARD
#define WaitNFBusy() while(NFIsBusy())
#else
void WrNFCmd(cmd)
{
NAND_CLE(1);
*(volatile U8 *)NAND_DAT = (cmd);
NAND_CLE(0);
}
void WrNFAddr(addr)
{
NAND_ALE(1);
*(volatile U8 *)NAND_DAT = (addr);
NAND_ALE(0);
}
static U32 WaitNFBusy(void)
{
U8 stat;
WrNFCmd(QUERYCMD);
do {
stat = RdNFDat();
//Uart_Printf("%x\n", stat);
}while(!(stat&0x40));
WrNFCmd(READCMD0);
return stat&1;
}
#endif
static U32 NFReadID(void)
{
U32 id, loop = 0;
NFChipEn();
WrNFCmd(READIDCMD);
WrNFAddr(0);
while(NFIsBusy()&&(loop<10000)) loop++;
if(loop>=10000)
return 0;
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=1;
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
Uart_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();
// WrNFCmd(READCMD1);
// WrNFAddr(0);
// WrNFAddr(addr);
// WrNFAddr(addr>>8);
// if(NandAddr)
// WrNFAddr(addr>>16);
// InitEcc();
// WaitNFBusy();
// for(i=256; 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(READCMD0);
WrNFCmd(PROGCMD0);
WrNFAddr(0);
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
// InitEcc();
for(i=0; i<512; i++)
WrNFDat(buf[i]);
/* tmp[0] = rNFECC0;
tmp[1] = rNFECC1;
tmp[2] = rNFECC2;
WrNFDat(tmp[0]);
WrNFDat(tmp[1]);
WrNFDat(tmp[2]);*/
WrNFCmd(PROGCMD1);
stat = WaitNFBusy();
/* WrNFCmd(READCMD1);
WrNFCmd(PROGCMD0);
WrNFAddr(0);
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
// InitEcc();
for(i=0; i<256; i++)
WrNFDat(buf[i]);
/* 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)
Uart_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]) {
Uart_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(6); //mark offset 6,7
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(6); //mark offset 6,7
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;
Uart_Printf("Please select Nand flash region to %s, Esc to abort\n", info);
for(i=0; NandPartition[i].size; i++)
Uart_Printf("%d : start 0x%08x, size 0x%08x\t[part%d]\n", i,
NandPartition[i].offset, NandPartition[i].size, i/*NandPartition[i].name*/);
max_sel = i;
while(1) {
char c = Uart_Getch();
if(c==0x1b) //"enter" key
return 0;
if((c>='0')&&(c<(max_sel+'0')))
return &(NandPartition[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)) {
Uart_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 */
int getyorn()
{
while(1)
{
char c = Uart_Getch();
if((c=='y')||(c=='Y'))
return 0;
if((c=='n')||(c=='N'))
return 1;
}
}
/******************************************************/
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) {
Uart_Printf("File size is too long!\n");
return;
}
start_page = part->offset>>9;
Uart_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) {
Uart_Printf("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) {
Uart_Printf("Program nand flash fail\n");
return;
}
NFMarkBadBlk(i+start_page);
skip_blks++;
i += 32;
continue;
}
ram_addr += 512;
size -= 512;
i++;
}
Uart_Printf("Program nand flash partition success\n");
if(skip_blks)
Uart_Printf("Skiped %d bad block(s)\n", skip_blks);
#endif /* NAND_SUPPORT */
}
static U32 downloadAddress;
//void start_kernel(U32, U32);
void RdFileFrNF(U32 FileAddr, U32 FileSize)
{
#ifdef NAND_SUPPORT
U32 initrd, bootpart;
void (*fp)(void);
if(!HaveNandChip)
return;
Uart_Printf("Select which program to run?\n");
Uart_Printf("1: Kernel without initrd\n");
Uart_Printf("2: Kernel with initrd\n");
Uart_Printf("3: NAND-BOOT\n");
Uart_Printf("ESC : exit\n");
while(1) {
char c = Uart_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;
}
}
Uart_Printf("Loading...\n");
NFReadPart(&NandPartition[bootpart], (U8 *)downloadAddress);
if(initrd)
NFReadPart(&NandPartition[2], (U8 *)initrd);
Uart_Printf("end\n");
fp = (void (*)(void))downloadAddress;
(*fp)();
// 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;
Uart_Printf("Are you sure to erase nand flash from page 0x%x, block count 0x%x ?\n", start_page, blk_cnt);
if(getyorn())
return;
for(i=0; blk_cnt; blk_cnt--, i+=32) {
if(NFEraseBlock(i+start_page)) {
err ++;
Uart_Printf("Press any key to continue...\n");
Uart_Getch();
}
}
Uart_Printf("Erase Nand partition completed \n");
if(err)
Uart_Printf("with %d bad block(s)\n", err);
else
Uart_Printf("success\n");
#endif /* NAND_SUPPORT */
}
void GetNandFlashChip(void)
{
#ifdef NAND_SUPPORT
int i;
U32 id;
HaveNandChip = 0;
id = NFReadID();
//Uart_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) {
//Uart_Printf("This nand flash size = %dM\n",NandFlashChip[i].size>>20);
NandFlashSize = NandFlashChip[i].size;
HaveNandChip = 1;
if(!NandPartition[0].size) {
NandPartition[0].offset = 0;
NandPartition[0].size = NandFlashSize;
NandPartition[1].size = 0;
}
return;
}
Uart_Printf("No supported Nand Flash Found!\n");
#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;
NandAddr = 0;
Uart_Printf("Erase Block 0x%x...\n", blk);
NFEraseBlock(blk);
Uart_Printf("status = %x\n", NFReadStat());
// Uart_Printf("Write nand flash\n");
for(i=0; i<512; i++)
dat[i] = ~(i&0xff);
// for(i=0; i<512; i++)
// Uart_Printf("%4x,", dat[i]);
NFWritePage(blk, dat);
// Uart_Printf("Read nand flash\n");
// for(i=0; i<512; i++)
// dat[i] = 0;
// NFReadPage(blk, dat);
// for(i=0; i<512; i++)
// Uart_Printf("%4x,", dat[i]);
//#endif
//#endif /* NAND_SUPPORT */
}
void Nand_Arm_Set()
{
rPDATC = 0xff02;
rPCONC = 0x0ff0ff54;
rPUPC = 0x30f0; //PULL UP RESISTOR should be enabled to I/O
}
void Nand_Work()
{
Nand_Arm_Set();
GetNandFlashChip();
TestNandFlash(0, 0);
while(1)
{
Uart_Printf("Are you sure to erase nand flash?\n");
if(!getyorn())
EraseNandPart(0,0);
else
break;
}
Uart_Printf("Erase nand flash finish.\n");
Uart_Getch();
}
void NandInit()
{
Nand_Arm_Set();
GetNandFlashChip();
}
void ReadMap(U8 *mapa,int num) //
{
U32 i;
U32 page;
int number;
if(!HaveNandChip)
return;
NandAddr = 0;
number = MAPNUMBER / 512;
page = num * number;
for(i=0;i<number;i++)
NFReadPage(page+i,(mapa+512*i)); // page: offset page number of the current picture
// Uart_Printf("Read nand flash\n");
// for(i=0; i<MAPNUMBER; i++)
// Uart_Printf("%4x,", mapa[i]);
}
void WriteMap(U8 *mapa,int num) //*mapa:picture point, num :picture number
{
U32 i,j;
U32 blk,page;
int number;
if(!HaveNandChip)
return;
NandAddr = 0;
number = MAPNUMBER / 512;
page = num * number;
for(i=0;i<number;i++)
{
if(((page+i) % 32)==0) // erase before program.
NFEraseBlock(page+i);
NFWritePage(page+i,(mapa+512*i));
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -