📄 nand.c
字号:
/*
create by hzh, support 512/page NAND Flash only
*/
#ifndef BOOT_NAND
#include <string.h>
#include "2440addr.h"
/*#include "bootrom.h"*/
#define U32 unsigned int
#define U16 unsigned short
#define S32 int
#define S16 short int
#define U8 unsigned char
#define S8 char
#define TRUE 1
#define FALSE 0
#define OK 1
#define FAIL 0
#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)
#define RdNFDat32() (rNFDATA)
#define WrNFCmd(cmd) (rNFCMD = (cmd))
#define WrNFAddr(addr) (rNFADDR = (addr))
#define WrNFDat(dat) WrNFDat8(dat)
#define RdNFDat() RdNFDat8()
#define RdNFMEcc() (rNFMECC0)
#define RdNFSEcc() (rNFSECC)
#define RdNFStat() (rNFSTAT)
#define NFIsBusy() (!(rNFSTAT&1))
#define NFIsReady() (rNFSTAT&1)
#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;
#define TACLS 1
#define TWRPH0 4
#define TWRPH1 0
static void InitNandCfg(void)
{
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
#if 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.
#endif
rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
#if 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();
#endif
}
#ifdef WIAT_BUSY_HARD
#define WaitNFBusy() while(NFIsBusy())
#else
static U32 WaitNFBusy(void)
{
U8 stat;
WrNFCmd(QUERYCMD);
do {
stat = RdNFDat();
}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;
}
U16 ReadStatus(void)
{
U16 stat;
NFChipEn();
WrNFCmd(QUERYCMD);
stat = RdNFDat();
NFChipDs();
return stat;
}
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;
#endif
printf("Erase block 0x%x %s\n", addr, stat?"fail":"ok");
return stat;
}
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();
}
U32 WritePage(U32 addr, U8 *buf)
{
U32 i, mecc;
U8 stat, tmp[7];
NFChipEn();
WrNFCmd(PROGCMD0);
WrNFAddr(0);
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
InitEcc();
MEccUnlock();
for(i=0; i<512; i++)
WrNFDat(buf[i]);
MEccLock();
mecc = RdNFMEcc();
tmp[0] = mecc&0xff;
tmp[1] = (mecc>>8)&0xff;
tmp[2] = (mecc>>16)&0xff;
tmp[3] = (mecc>>24)&0xff;
tmp[5] = 0xff;
SEccUnlock();
WrNFDat(tmp[0]);
WrNFDat(tmp[1]);
WrNFDat(tmp[2]);
WrNFDat(tmp[3]);
SEccLock();
WrNFDat(tmp[4]);
WrNFDat(tmp[5]);
WrNFCmd(PROGCMD1);
stat = WaitNFBusy();
NFChipDs();
#ifdef WR_BAD_BLK_TEST
if((addr&0xff)==0x17) stat = 1;
#endif
if(stat)
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]) {
printf("Check data at page 0x%x, offset 0x%x fail\n", addr, i);
stat = 1;
break;
}
}
return stat;
}
static void MarkBadBlk(U32 addr)
{
addr &= ~0x1f;
NFChipEn();
WrNFCmd(READCMD2);
WrNFCmd(PROGCMD0);
WrNFAddr(4);
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
WrNFDat(0);
WrNFDat(0);
WrNFDat(0);
WrNFDat(0);
WrNFCmd(PROGCMD1);
WaitNFBusy();/*needn't check return status*/
WrNFCmd(READCMD0);
NFChipDs();
}
static int CheckBadBlk(U32 addr)
{
U8 dat;
addr &= ~0x1f;
NFChipEn();
WrNFCmd(READCMD2);
WrNFAddr(5);
WrNFAddr(addr);
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
WaitNFBusy();
dat = RdNFDat();
WrNFCmd(READCMD0);
NFChipDs();
return (dat!=0xff);
}
/************************************************************/
struct Partition{
U32 offset;
U32 size;
char *name;
};
/*
static struct Partition NandPart[] = {
{0, 0x00030000, "boot"}, //256K
{0x00030000, 0x001d0000, "kernel"},
{0x00200000, 0x02000000, "rootfs"}, //30M
{0x02000000, 0x02000000, "ext-fs1"}, //32M
{0, 0 , 0}
};
*/
static struct Partition NandPart[] = {
{0, 0x00030000, "boot"},
{0x00030000, 0x001d0000, "kernel"},
{0x00200000, 0x01600000, "rootfs"},
{0x01800000, 0x02200000, "ext-fs1"},
{0, 0 , 0}
};
/*
static void TestFunc(void)
{
U32 i;
U8 buf[512];
if(EraseBlock(0x180))
return;
for(i=0; i<512; i++)
buf[i] = i;
WritePage(0x180, buf);
for(i=0; i<512; i++)
buf[i] = 0;
ReadPage(0x180, buf);
for(i=0; i<512; i++)
printf("%4x", buf[i]);
}
*/
static U32 StartPage, BlockCnt;
U32 downloadAddress;
U32 downloadFileSize;
static int NandSelPart(char *info)
{
U16 i, max_sel;
struct Partition *ptr = NandPart;
printf("Please select which region to %s : Esc to abort\n", info);
for(i=0; ptr->size!=0; i++, ptr++)
printf("%d : offset 0x%-8x, size 0x%-8x [%s]\n", i, ptr->offset, ptr->size, ptr->name);
max_sel = i;
while(1) {
i = getchar();
if(i==0x1b)
return -1;
if((i>='0')&&(i<(max_sel+'0'))) {
i -= '0';
StartPage = NandPart[i].offset>>9;
BlockCnt = NandPart[i].size>>14;
return i;
}
}
}
static void WrFileToNF(void)
{
int nf_part, i ,size, skip_blks;
U32 ram_addr;
nf_part = NandSelPart("write");
if(nf_part<0)
return;
if(downloadFileSize>NandPart[nf_part].size) {
printf("Download file size is more large than selected partition size!!!\n");
}
printf("Now write nand flash page 0x%x from ram address 0x%x, filesize = %d\n", StartPage, downloadAddress, downloadFileSize);
printf("Are you sure? [y/n]\n");
while(1) {
char c = getchar();
if((c=='y')||(c=='Y'))
break;
if((c=='n')||(c=='N'))
return;
}
skip_blks = 0;
ram_addr = 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) {
puts("Program nand flash fail\n");
return;
}
MarkBadBlk(i+StartPage);
skip_blks++;
i += 32;
continue;
*/
goto WrFileToNFErr;
}
}
if(WritePage(i+StartPage, (U8 *)ram_addr)) {
ram_addr -= (i&0x1f)<<9;
size += (i&0x1f)<<9;
i &= ~0x1f;
WrFileToNFErr:
NandPart[nf_part].size -= 32<<9;
if(downloadFileSize>NandPart[nf_part].size) {
printf("Program nand flash fail\n");
}
MarkBadBlk(i+StartPage);
skip_blks++;
i += 32;
continue;
}
ram_addr += 512;
size -= 512;
i++;
}
printf("Program nand flash partition success\n");
if(skip_blks)
printf("Skiped %d bad block(s)\n", skip_blks);
}
#define LINUX_PAGE_SHIFT 12
#define LINUX_PAGE_SIZE (1<<LINUX_PAGE_SHIFT)
#define COMMAND_LINE_SIZE 1024;
/*************************************************************/
extern int sprintf(char * /*s*/, const char * /*format*/, ...);
/************************************************************/
void InitNandFlash(int info)
{
U32 i;
InitNandCfg();
i = ReadChipId();
if(info)
printf("Read chip id = %x\n", i);
if((i==0x9873)||(i==0xec75))
NandAddr = 0;
else if(i==0xec76)
NandAddr = 1;
else {
printf("Chip id error!!!\n");
return;
}
if(info)
printf("Nand flash status = %x\n", ReadStatus());
}
void NandErase(void)
{
int i, err = 0;
InitNandFlash(1);
i = NandSelPart("erase");
if(i<0)
return;
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 = getchar();
if((c=='y')||(c=='Y'))
break;
if((c=='n')||(c=='N'))
return;
}
for(i=0; BlockCnt; BlockCnt--, i+=32) {
if(EraseBlock(i+StartPage)) {
err ++;
printf("Press any key to continue...\n");
getchar();
}
}
DsNandFlash();
printf("Erase Nand partition completed ");
if(err)
printf("with %d bad block(s)\n", err);
else
printf("success\n");
}
void NandWrite(void)
{
InitNandFlash(1);
WrFileToNF();
DsNandFlash();
}
void PrintBuffer(U8 *pData, U32 len)
{
U32 i;
char buf[80];
for(i = 0; i < len; i++)
{
if(0 == (i % 16))
{
if(0 != i)
{
buf[59] = '\r';
buf[60] = '\n';
buf[61] = '\0';
printf(buf);
}
sprintf(buf, "0x%08x:", (unsigned int)pData + i);
}
sprintf(buf + (i % 16) * 3 + 11, " %02x", (unsigned char)pData[i]);
}
}
void WriteBootrom(void)
{
unsigned long i, rom_adr,rom_len,blk_num,page_num;
rom_adr = (unsigned long)0x33e00000;
rom_len = 0x100000;
InitNandFlash(1);
blk_num = rom_len / 0x4000;
if(0 != (rom_len % 0x4000))
blk_num++;
page_num = blk_num*32;
printf("Bootrom length is 0x%x, block number is %d.\n",rom_len,blk_num);
printf("Erasing block:");
for(i = 0; i < page_num; i++)
{
EraseBlock(i);
}
printf("Write data:");
for(i = 0; i < page_num; i++)
{
WritePage(i, (U8*)(rom_adr + 512*i));
}
printf("Write data finished.\n");
}
void ReadBootrom(int cmplen)
{
unsigned long i, rom_adr,rom_len,blk_num,page_num,error_cnt=0;
U8 buf[512];
rom_adr = (unsigned long)0x33f00000;
rom_len = 0x100000;
InitNandFlash(1);
blk_num = rom_len / 0x4000;
if(0 != (rom_len % 0x4000))
blk_num++;
page_num = blk_num*32;
for(i = 0; i < page_num; i++)
{
printf("Reading page %d....:\n", i);
ReadPage(i, (U8*)(rom_adr + i*512));
}
for(i = 0; i < cmplen; i++)
{
if(*(unsigned char*)(0x33f00000 + i) != *(unsigned char*)(0x33e00000 + i))
{
error_cnt++;
}
}
printf("Compare length is 0x%x.\n", cmplen);
printf("Error count is 0x%x.\n", error_cnt);
}
void testnand(void)
{
U8 buf[512];
InitNandFlash(1);
EraseBlock(0);
printf("Reading page 0 after erase:\n");
ReadPage(0, (U8*)buf);
PrintBuffer(buf, 512);
printf("Write page 0:\n");
WritePage(0,(U8*)0x33e00000);
printf("Reading page 0 after write:\n");
ReadPage(0, (U8*)buf);
PrintBuffer(buf, 512);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -