📄 nand.c
字号:
/*
create by hzh, support 512/page NAND Flash only
*/
#include <string.h>
#include "def.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "Nand.h"
#include "Lcd.h"
//suppport boot params
#define GLOBAL_PARAMS
#include "bootpara.h"
#define puts Uart_Printf
#define printf Uart_Printf
#define getch Uart_Getch
#define putch Uart_SendByte
#define EnNandFlash() (rNFCONT |= 1)
#define DsNandFlash() (rNFCONT &= ~1)
#define NFChipEn() (rNFCONT &= ~(1<<1))
#define NFChipDs() (rNFCONT |= (1<<1))
#define InitEcc() (rNFCONT |= (1<<4))
#define MEccUnlock() (rNFCONT &= ~(1<<5))
#define MEccLock() (rNFCONT |= (1<<5))
#define SEccUnlock() (rNFCONT &= ~(1<<6))
#define SEccLock() (rNFCONT |= (1<<6))
#define WrNFDat8(dat) (rNFDATA8 = (dat))
#define WrNFDat32(dat) (rNFDATA = (dat))
#define RdNFDat8() (rNFDATA8) //byte access
#define RdNFDat32() (rNFDATA) //word access
#define WrNFCmd(cmd) (rNFCMD = (cmd))
#define WrNFAddr(addr) (rNFADDR = (addr))
#define WrNFDat(dat) WrNFDat8(dat)
#define RdNFDat() RdNFDat8() //for 8 bit nand flash, use byte access
#define RdNFMEcc() (rNFMECC0) //for 8 bit nand flash, only use NFMECC0
#define RdNFSEcc() (rNFSECC) //for 8 bit nand flash, only use low 16 bits
#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;
// HCLK=100Mhz
#define TACLS 1//7 // 1-clk(0ns)
#define TWRPH0 4//7 // 3-clk(25ns)
#define TWRPH1 1//7 // 1-clk(10ns) //TACLS+TWRPH0+TWRPH1>=50ns
extern int jffs2;
static void InitNandCfg(void)
{
// for S3C2440
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
// TACLS [14:12] CLE&ALE duration = HCLK*TACLS.
// TWRPH0 [10:8] TWRPH0 duration = HCLK*(TWRPH0+1)
// TWRPH1 [6:4] TWRPH1 duration = HCLK*(TWRPH1+1)
// AdvFlash(R) [3] Advanced NAND, 0:256/512, 1:1024/2048
// PageSize(R) [2] NAND memory page size
// when [3]==0, 0:256, 1:512 bytes/page.
// when [3]==1, 0:1024, 1:2048 bytes/page.
// AddrCycle(R) [1] NAND flash addr size
// when [3]==0, 0:3-addr, 1:4-addr.
// when [3]==1, 0:4-addr, 1:5-addr.
// BusWidth(R/W) [0] NAND bus width. 0:8-bit, 1:16-bit.
rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
// Lock-tight [13] 0:Disable lock, 1:Enable lock.
// Soft Lock [12] 0:Disable lock, 1:Enable lock.
// EnablillegalAcINT[10] Illegal access interupt control. 0:Disable, 1:Enable
// EnbRnBINT [9] RnB interrupt. 0:Disable, 1:Enable
// RnB_TrandMode[8] RnB transition detection config. 0:Low to High, 1:High to Low
// SpareECCLock [6] 0:Unlock, 1:Lock
// MainECCLock [5] 0:Unlock, 1:Lock
// InitECC(W) [4] 1:Init ECC decoder/encoder.
// Reg_nCE [1] 0:nFCE=0, 1:nFCE=1.
// NANDC Enable [0] operating mode. 0:Disable, 1:Enable.
// rNFSTAT = 0;
// Nand_Reset();
}
#ifdef WIAT_BUSY_HARD
#define WaitNFBusy() while(NFIsBusy())
#else
static U32 WaitNFBusy(void) // R/B 未接好?
{
U8 stat;
WrNFCmd(QUERYCMD);
do {
stat = RdNFDat();
//printf("%x\n", stat);
}while(!(stat&0x40));
WrNFCmd(READCMD0);
return stat&1;
}
#endif
static U32 ReadChipId(void)
{
U32 id;
NFChipEn();
WrNFCmd(RdIDCMD);
WrNFAddr(0);
while(NFIsBusy());
id = RdNFDat()<<8;
id |= RdNFDat();
NFChipDs();
return id;
}
static U16 ReadStatus(void)
{
U16 stat;
NFChipEn();
WrNFCmd(QUERYCMD);
stat = RdNFDat();
NFChipDs();
return stat;
}
static U32 WriteOOB(U32 addr)
{
U32 i, mecc;
U8 stat, jtmp[8];
U32 oobaddr = addr + 512 + 8;
NFChipEn();
WrNFCmd(PROGCMD0);
WrNFAddr(0);
WrNFAddr(oobaddr);
WrNFAddr(oobaddr>>8);
if(NandAddr)
WrNFAddr(oobaddr>>16);
jtmp[0] = 0x85;
jtmp[1] = 0x19;
jtmp[2] = 0x03;
jtmp[3] = 0x20;
jtmp[4] = 0x08;
jtmp[5] = 0x00;
jtmp[6] = 0x00;
jtmp[7] = 0x00;
for(i=0;i<8;i++)
WrNFDat(jtmp[i]);
WrNFCmd(PROGCMD1);
stat = WaitNFBusy();
NFChipDs();
return stat;
}
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
/*
if(jffs2){
int ret;
ret = WriteOOB(addr);
if(ret)
printf("oob write error,addr:0x%x\n", addr);
}
*/
putch('.');
//printf("Erase block 0x%x %s\n", addr, stat?"fail":"ok");
return stat;
}
//addr = page address
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();
for(i=0; i<512; i++)
buf[i] = RdNFDat();
NFChipDs();
}
#define u_char U8
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 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)
{
u_char 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);
nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, 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 int nand_calculate_ecc(const u_char *dat, u_char *ecc_code)
{
u_char idx, reg1, reg2, reg3, tmp1, tmp2;
int i;
/* Initialize variables */
reg1 = reg2 = reg3 = 0;
/* Build up column parity */
for(i = 0; i < 256; i++) {
/* Get CP0 - CP5 from table */
idx = nand_ecc_precalc_table[*dat++];
reg1 ^= (idx & 0x3f);
/* All bit XOR = 1 ? */
if (idx & 0x40) {
reg3 ^= (u_char) i;
reg2 ^= ~((u_char) i);
}
}
// Create non-inverted ECC code from line parity
tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */
tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */
tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
/* Calculate final ECC code */
#ifdef CONFIG_NAND_ECC_SMC
ecc_code[0] = ~tmp2;
ecc_code[1] = ~tmp1;
#else
ecc_code[0] = ~tmp1;
ecc_code[1] = ~tmp2;
#endif
ecc_code[2] = ((~reg1) << 2) | 0x03;
return 0;
}
static void SoftEcc(const u_char *dat, u_char *oob_buf)
{
int eccsteps = 2;
int eccidx = 0;
int datidx = 0;
int i = 0;
U8 ecc_code[3];
U8 oob_config[] = {0, 1, 2, 3, 6, 7};
/*
for (; eccsteps; eccsteps--) {
nand_calculate_ecc(&dat[datidx], ecc_code);//计算出一页的ecc数据
for (i = 0; i < 3; i++, eccidx++)
oob_buf[oob_config[eccidx]] = ecc_code[i];//存放到ecc_code数组中
datidx += 256;
}
*/
nand_calculate_ecc(&dat[0], ecc_code);
oob_buf[0] = ecc_code[0];
oob_buf[1] = ecc_code[1];
oob_buf[2] = ecc_code[2];
nand_calculate_ecc(&dat[256], ecc_code);
oob_buf[3] = ecc_code[0];
oob_buf[6] = ecc_code[1];
oob_buf[7] = ecc_code[2];
/*
printf("ecc:");
for(i=0;i<6;i++)
printf("eccidx:%d,0x%x ",oob_config[i],oob_buf[oob_config[i]]);
printf("\n");
printf("ecc:");
for(i=0;i<8;i++)
printf("0x%x ",oob_buf[i]);
printf("\n");
*/
}
static U32 WritePage(U32 addr, U8 *buf)
{
U32 i, mecc;
U8 stat, tmp[8];
NFChipEn();
WrNFCmd(PROGCMD0);
WrNFAddr(0);
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
InitEcc(); //reset mecc and secc
MEccUnlock();
for(i=0; i<512; i++)
WrNFDat(buf[i]);
MEccLock();
mecc = RdNFMEcc();
if(!jffs2){
tmp[0] = mecc&0xff;
tmp[1] = (mecc>>8)&0xff;
tmp[2] = (mecc>>16)&0xff;
tmp[3] = (mecc>>24)&0xff;
tmp[5] = 0xff; //mark good block
SEccUnlock();
WrNFDat(tmp[0]);
WrNFDat(tmp[1]);
WrNFDat(tmp[2]);
WrNFDat(tmp[3]);
SEccLock();
WrNFDat(tmp[4]);
WrNFDat(tmp[5]);
}
else{
SoftEcc(buf, tmp);
tmp[4] = 0x0;
tmp[5] = 0xff; //mark good block
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -