📄 nandlib.c
字号:
/*************nand flash***********
* by lht
**************************/
#include "2410lib.h"
#include "2410addr.h"
#define U32 unsigned int
#define U16 unsigned short
#define U8 unsigned char
static U16 NandAddr;
static U16 support;
extern U32 downloadFileSize;
extern U32 downloadAddress;
#define EnNandFlash() (rNFCONF |= 0x8000)
#define DsNandFlash() (rNFCONF &= ~0x8000)
#define InitEcc() (rNFCONF |= 0x1000)
#define NoEcc() (rNFCONF &= ~0x1000)
#define NFChipEn() (rNFCONF &= ~0x800)
#define NFChipDs() (rNFCONF |= 0x800)
#define WrNFCmd(cmd) (rNFCMD = (cmd))
#define WrNFAddr(addr) (rNFADDR = (addr))
#define WrNFDat(dat) (rNFDATA = (dat))
#define RdNFDat() (rNFDATA)
#define RdNFStat() (rNFSTAT)
#define NFIsBusy() (!(rNFSTAT&1))
#define NFIsReady() (rNFSTAT&1)
//#define WIAT_BUSY_HARD 1
//#define ER_BAD_BLK_TEST
//#define WR_BAD_BLK_TEST
#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 RdIDCMD 0x90
static U16 NandAddr;
static U32 StartPage, BlockCnt;
struct Partition{
U32 offset;
U32 size;
char *name;
};
static struct Partition NandPart[] = {
{0, 0x00040000, "bootloader"}, //256K
{0x00040000, 0x001c0000, "zImage"},
{0x00200000, 0x01e00000, "cramfs"}, //30M
{0x02000000, 0x02000000, "yaffs"}, //32M
{0, 0 , 0}
};
#define BLK_IDXL 8
#define BLK_IDXH 9
#define FMT_TAG 15
char format_tags[] = "Formatted For NAND FLASH Driver"; //must be less than 32
#define u_char U8
static U8 eccpos[6] = {0, 1, 2, 3, 6, 7};
static const u_char nand_ecc_precalc_table[] = {
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
};
static U32 ReadChipId(void)
{
U32 id;
NFChipEn();
WrNFCmd(RdIDCMD);
WrNFAddr(0);
while(NFIsBusy());
id = RdNFDat()<<8;
id |= RdNFDat();
NFChipDs();
return id;
}
static void InitNandCfg(void)
{
//enable nand flash control, initilize ecc, chip disable,
rNFCONF = (1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7);
}
void InitNandFlash(void)
{
U32 i;
InitNandCfg();
i = ReadChipId();
// uart_printf("Read chip id = %x\n", i);
if((i==0x9873)||(i==0xec75))
NandAddr = 0;
else if(i==0xec76)
{
support=1;
NandAddr = 1;
}
else {
// puts("Chip id error!!!\n");
uart_printf("Chip id error!!!\n");
return;
}
//*/ printf("Nand flash status = %x\n", ReadStatus()); */
}
static int NandSelPart(char *info)
{
U16 i, max_sel;
struct Partition *ptr = NandPart;
uart_printf("Please select which region to %s : Esc to abort\n", info);
for(i=0; ptr->size!=0; i++, ptr++)
uart_printf("%d : offset 0x%-8x, size 0x%-8x [%s]\n", i, ptr->offset, ptr->size, ptr->name);
max_sel = i;
while(1) {
i = uart_getch();
if(i==0x1b) //esc
return -1;
if((i>='0')&&(i<(max_sel+'0'))) {
i -= '0';
StartPage = NandPart[i].offset>>9;
BlockCnt = NandPart[i].size>>14;
return i;
}
}
}
#ifdef WIAT_BUSY_HARD
#define WaitNFBusy() while(NFIsBusy())
#else
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 EraseBlock(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%x %s\n", addr, stat?"fail":"ok");
uart_printf (".");
return stat;
}
void Nand_Erase()
{
int i, err = 0;
InitNandFlash(); //初始化nand,并获取id
i = NandSelPart("erase");
if(i<0)
return;
uart_printf("Are you sure to erase nand flash from page 0x%x, block count 0x%x ? [y/n]\n", StartPage, BlockCnt);
while(1) {
char c;
c = uart_getch();
if((c=='y')||(c=='Y'))
break;
if((c=='n')||(c=='N'))
return;
}
for(i=0; BlockCnt; BlockCnt--, i+=32) {
if(EraseBlock(i+StartPage)) {
err ++;
uart_printf("Press any key to continue...\n");
uart_getch();
}
}
DsNandFlash(); //disable nand flash interface
uart_printf("Erase Nand partition completed ");
if(err)
uart_printf("with %d bad block(s)\n", err);
else
uart_printf("success\n");
// NandErase ();
//nn();
// uart_printf("in Nand_Erase\n" );
}
static int CheckBadBlk(U32 addr)
{
U8 dat;
addr &= ~0x1f;
NFChipEn();
WrNFCmd(READCMD2); //point to area c
WrNFAddr(5); //mark offset 4,5,6,7
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
WaitNFBusy(); //by lht
// while(NFIsBusy());
WrNFCmd(READCMD0); //point to area a
dat = RdNFDat();
NFChipDs();
return (dat!=0xff);
}
static void MarkBadBlk(U32 addr)
{
int i;
addr &= ~0x1f;
NFChipEn();
WrNFCmd(READCMD2); //point to area c
WrNFCmd(PROGCMD0);
WrNFAddr(4); //mark offset 4,5,6,7
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
for(i=0; i<16; i++)
WrNFDat(0); //mark with 0
WrNFCmd(PROGCMD1);
WaitNFBusy(); //needn't check return status
WrNFCmd(READCMD0); //point to area a
NFChipDs();
}
/**
* nand_trans_result - [GENERIC] create non-inverted ECC
* @reg2: line parity reg 2
* @reg3: line parity reg 3
* @ecc_code: ecc
*
* Creates non-inverted ECC code from line parity
*/
static void nand_trans_result(u_char reg2, u_char reg3,
u_char *ecc_code)
{
u_char a, b, i, tmp1, tmp2;
/* Initialize variables */
a = b = 0x80;
tmp1 = tmp2 = 0;
/* Calculate first ECC byte */
for (i = 0; i < 4; i++) {
if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
tmp1 |= b;
b >>= 1;
if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
tmp1 |= b;
b >>= 1;
a >>= 1;
}
/* Calculate second ECC byte */
b = 0x80;
for (i = 0; i < 4; i++) {
if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
tmp2 |= b;
b >>= 1;
if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
tmp2 |= b;
b >>= 1;
a >>= 1;
}
/* Store two of the ECC bytes */
ecc_code[0] = tmp1;
ecc_code[1] = tmp2;
}
int nand_calculate_ecc(const u_char *dat, u_char *ecc_code)
{
U8 idx, reg1, reg2, reg3;
int j;
/* Initialize variables */
reg1 = reg2 = reg3 = 0;
ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
/* Build up column parity */
for(j = 0; j < 256; j++) {
/* Get CP0 - CP5 from table */
idx = nand_ecc_precalc_table[dat[j]];
reg1 ^= (idx & 0x3f);
/* All bit XOR = 1 ? */
if (idx & 0x40) {
reg3 ^= (u_char) j;
reg2 ^= ~((u_char) j);
}
}
/* Create non-inverted ECC code from line parity */
nand_trans_result(reg2, reg3, ecc_code);
/* Calculate final ECC code */
ecc_code[0] = ~ecc_code[0];
ecc_code[1] = ~ecc_code[1];
ecc_code[2] = ((~reg1) << 2) | 0x03;
return 0;
}
static void ReadPage(U32 addr, U8 *buf)
{
U16 i;
NFChipEn();
WrNFCmd(READCMD0);
WrNFAddr(0);
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
InitEcc();
WaitNFBusy();
WrNFCmd(READCMD0);//add
for(i=0; i<512; i++)
buf[i] = RdNFDat();
NFChipDs();
}
static U32 WritePage(U32 addr, U8 *buf, U16 blk_idx)
{
U16 i;
U8 stat;
U8 ecc_code[3];
U8 oob_info[16];
for(i=0; i<sizeof(oob_info); i++)
oob_info[i] = 0xff;
nand_calculate_ecc(buf, ecc_code);
oob_info[eccpos[0]] = ecc_code[0];
oob_info[eccpos[1]] = ecc_code[1];
oob_info[eccpos[2]] = ecc_code[2];
nand_calculate_ecc(buf+256, ecc_code);
oob_info[eccpos[3]] = ecc_code[0];
oob_info[eccpos[4]] = ecc_code[1];
oob_info[eccpos[5]] = ecc_code[2];
oob_info[BLK_IDXL] = blk_idx;
oob_info[BLK_IDXH] = blk_idx>>8;
oob_info[FMT_TAG] = format_tags[addr&0x1f];
NFChipEn();
WrNFCmd(READCMD0);//add
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');
} else {
for(i=0; i<sizeof(oob_info); i++)
WrNFDat(oob_info[i]);
}
/* tmp[0] = rNFECC0;
tmp[1] = rNFECC1;
tmp[2] = rNFECC2;
WrNFDat(tmp[0]);
WrNFDat(tmp[1]);
WrNFDat(tmp[2]);
*/
WrNFCmd(PROGCMD1);
stat = WaitNFBusy();
WrNFCmd(READCMD0);//add
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];
ReadPage(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 WrFileToNF(void)
{
int nf_part, i ,size, skip_blks;
U32 ram_addr;
U8 *ram_addr_ecc;
nf_part = NandSelPart("write");
if(nf_part<0)
return;
if(downloadFileSize>NandPart[nf_part].size) {
uart_printf("Download file size is more large than selected partition size!!!\n");
// return;
}
uart_printf("Now write nand flash page 0x%x from ram address 0x%x, filesize = %d\n", StartPage, downloadAddress, downloadFileSize);
uart_printf("Are you sure? [y/n]\n");
while(1) {
char c = uart_getch();
if((c=='y')||(c=='Y'))
break;
if((c=='n')||(c=='N'))
return;
}
skip_blks = 0;
ram_addr = downloadAddress;
ram_addr_ecc = (U8 *)downloadAddress;
size = downloadFileSize;
for(i=0; size>0; ) {
if(!(i&0x1f)) {
if(EraseBlock(i+StartPage)) {
NandPart[nf_part].size -= 32<<9; //partition available size - 1 block size
if(downloadFileSize>NandPart[nf_part].size) {
uart_printf("Program nand flash fail\n");
return;
}
MarkBadBlk(i+StartPage);
skip_blks++;
i += 32;
continue;
goto WrFileToNFErr;
}
}
if(WritePage(i+StartPage, (U8 *)ram_addr, ((U32)ram_addr_ecc-downloadAddress)>>14 )) {
ram_addr -= (i&0x1f)<<9;
size += (i&0x1f)<<9;
i &= ~0x1f;
WrFileToNFErr:
NandPart[nf_part].size -= 32<<9; //partition available size - 1 block size
if(downloadFileSize>NandPart[nf_part].size) {
uart_printf("Program nand flash fail\n");
return;
}
MarkBadBlk(i+StartPage);
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);
}
void NandWrite(void)
{
InitNandFlash();
WrFileToNF();
DsNandFlash(); //disable nand flash interface
}
void NandRunSystem(void)
{
int size;
U32 i, ram_addr, buf = 0x31000000;
InitNandFlash();
/*
NFSearchParams((char *)&Env);
if(Env.Os_Auto_Flag==2)
NandLoadRunW();
else
NandLoadRun(); */
StartPage = NandPart[1].offset>>9;
size = NandPart[1].size;
//uart_printf("in NandRunSystem\n");
ram_addr = buf;
for(i=0; size>0; ) {
if(!(i&0x1f)) {
if(CheckBadBlk(i+StartPage)) {
uart_printf("Skipped bad block at 0x%x\n", i+StartPage);
i += 32;
size -= 32<<9;
continue;
}
}
// uart_printf("in NandRunSystem2\n");
ReadPage((i+StartPage), (U8 *)ram_addr);
i++;
size -= 512;
ram_addr += 512;
}
DsNandFlash();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -