📄 nand.c
字号:
#include "def.h"
#include "2410addr.h"
#include "2410lib.h"
#include "ecc.h"
#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;
int Write_partition_table(void);
static void InitNandCfg(void)
{
//enable nand flash control, initilize ecc, chip disable,
rNFCONF = (1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7);
}
#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 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");
putch('.');
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();
}
static U32 WritePage(U32 addr, U8 *buf, U8 Ecc_type)
{
U16 i;
U8 ecc[3];
U8 oob_buf[16];
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]);
for(i=0; i<16; i++)
oob_buf[i] = 0xff;
if(Ecc_type)
{
nand_calculate_ecc(buf, ecc);
oob_buf[8] = ecc[0];
oob_buf[9] = ecc[1];
oob_buf[10] =ecc[2];
nand_calculate_ecc(buf+256, ecc);
oob_buf[11] = ecc[0];
oob_buf[12] = ecc[1];
oob_buf[13] = ecc[2];
}
else
{
oob_buf[0] = rNFECC0;
oob_buf[1] = rNFECC0;
oob_buf[2] = rNFECC0;
}
for(i=0;i<16;i++)
WrNFDat(oob_buf[i]); // Write spare array(ECC and Mark)
WrNFCmd(PROGCMD1); // Write 2nd command
if(WaitNFBusy()) //wait tPROG 200~500us;
{
NFChipDs();
printf("write page error!\n");
return 1;
}
NFChipDs();
return 0;
}
static void MarkBadBlk(U32 addr)
{
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);
WrNFDat(0); //mark with 0
WrNFDat(0);
WrNFDat(0); //mark with 0
WrNFDat(0);
WrNFCmd(PROGCMD1);
WaitNFBusy(); //needn't check return status
WrNFCmd(READCMD0); //point to area a
NFChipDs();
}
static int CheckBadBlk(U32 addr)
{
U8 dat1; //, dat2;
addr &= ~0x1f;
NFChipEn();
WrNFCmd(READCMD2); //point to area c
WrNFAddr(5); //mark offset 4,5,6,7
WrNFAddr(addr); //the first page
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
WaitNFBusy();
dat1 = RdNFDat();
/*
WrNFCmd(READCMD2); //point to area c
WrNFAddr(5); //mark offset 4,5,6,7
WrNFAddr(addr+1); //the second page
WrNFAddr(addr>>8);
if(NandAddr)
WrNFAddr(addr>>16);
WaitNFBusy();
dat2 = RdNFDat();
*/
WrNFCmd(READCMD0); //point to area a
NFChipDs();
return (dat1!= 0xff); // || (dat2 != 0xff));
}
/************************************************************/
struct Partition{
U32 offset;
U32 size;
char *name;
};
static struct Partition NandPart[] = {
{0, 0x00030000, "boot"}, //192K
{0x00030000, 0x00030000, "ucos-ii"}, //192K
{0x00060000, 0x001a0000, "linux kernel"},
{0x00200000, 0x01e00000, "rootfs"}, //30M
//{0x02000000, 0x01ffc000, "wince"}, //32M - 16k
{0x02000000, 0x00800000, "wince"}, //31M
{0, 0 , 0}
};
U32 rootfs_num_badblock;
U32 rootfs_badblock[20];
static U32 StartPage, BlockCnt;
extern U32 downloadAddress;
extern 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 = getch();
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) {
puts("Download file size is more large than selected partition size!!!\n");
// return;
}
printf("Now write nand flash page 0x%x from ram address 0x%x, filesize = %d\n", StartPage, downloadAddress, downloadFileSize);
puts("Are you sure? [y/n]\n");
while(1) {
char c = getch();
if((c=='y')||(c=='Y'))
break;
if((c=='n')||(c=='N'))
return;
}
skip_blks = 0;
ram_addr = downloadAddress;
size = downloadFileSize;
if(nf_part == 3) //初始化文件系统分区的bad block数目
rootfs_num_badblock = 0;
for(i=0; size>0; ) {
if(!(i&0x1f)) {
if(EraseBlock(i+StartPage)) {
MarkBadBlk(i+StartPage);
skip_blks++;
if(nf_part == 3){
//printf("Skiped bad block %x!\n", i >> 5);
rootfs_badblock[rootfs_num_badblock] = i >> 5;
rootfs_num_badblock++;
}
i += 32;
continue;
}
if(CheckBadBlk(i+StartPage)){
MarkBadBlk(i+StartPage);
skip_blks++;
if(nf_part == 3){
//printf("Skiped bad block %x!!\n", i >> 5);
rootfs_badblock[rootfs_num_badblock] = i >> 5;
rootfs_num_badblock++;
}
i += 32;
continue;
}
}
if(WritePage(i+StartPage, (U8 *)ram_addr, nf_part)) {
ram_addr -= (i&0x1f)<<9;
size += (i&0x1f)<<9;
i &= ~0x1f;
NandPart[nf_part].size -= 32<<9;
MarkBadBlk(i+StartPage);
skip_blks++;
if(nf_part == 3){
printf("Skiped bad block %x\n", (i+StartPage) >> 5);
rootfs_badblock[rootfs_num_badblock] = (i+StartPage) >> 5;
rootfs_num_badblock++;
}
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);
if(nf_part == 3) //if root fs partition, write partition table
Write_partition_table();
}
#define LINUX_PAGE_SHIFT 12
#define LINUX_PAGE_SIZE (1<<LINUX_PAGE_SHIFT)
#define COMMAND_LINE_SIZE 1024
struct param_struct {
union {
struct {
unsigned long page_size; /* 0 */
unsigned long nr_pages; /* 4 */
unsigned long ramdisk_size; /* 8 */
unsigned long flags; /* 12 */
#define FLAG_READONLY 1
#define FLAG_RDLOAD 4
#define FLAG_RDPROMPT 8
unsigned long rootdev; /* 16 */
unsigned long video_num_cols; /* 20 */
unsigned long video_num_rows; /* 24 */
unsigned long video_x; /* 28 */
unsigned long video_y; /* 32 */
unsigned long memc_control_reg; /* 36 */
unsigned char sounddefault; /* 40 */
unsigned char adfsdrives; /* 41 */
unsigned char bytes_per_char_h; /* 42 */
unsigned char bytes_per_char_v; /* 43 */
unsigned long pages_in_bank[4]; /* 44 */
unsigned long pages_in_vram; /* 60 */
unsigned long initrd_start; /* 64 */
unsigned long initrd_size; /* 68 */
unsigned long rd_start; /* 72 */
unsigned long system_rev; /* 76 */
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
} u1;
union {
char paths[8][128];
struct {
unsigned long magic;
char n[1024 - sizeof(unsigned long)];
} s;
} u2;
char commandline[COMMAND_LINE_SIZE];
};
extern char boot_params[];
extern void call_linux(U32 a0, U32 a1, U32 a2);
static void LoadRun(int part_sel)
{
U32 i, ram_addr, buf = 0x30200000;
struct param_struct *params = (struct param_struct *)0x30000100;
int size;
//copy kernel image
StartPage = NandPart[part_sel].offset>>9;
size = NandPart[part_sel].size;
ram_addr = buf;
for(i=0; size>0; ) {
if(!(i&0x1f)) {
puts(".");
if(CheckBadBlk(i+StartPage)) {
printf("Skipped bad block at 0x%x\n", i+StartPage);
i += 32;
size -= 32<<9;
continue;
}
}
ReadPage((i+StartPage), (U8 *)ram_addr);
i++;
size -= 512;
ram_addr += 512;
}
DsNandFlash();
if(part_sel == 2)
{
for(i=0; i<(sizeof(struct param_struct)>>2); i++)
((U32 *)params)[i] = 0;
params->u1.s.page_size = LINUX_PAGE_SIZE;
params->u1.s.nr_pages = (0x04000000 >> LINUX_PAGE_SHIFT);
for(i=0; boot_params[i]; i++)
params->commandline[i] = boot_params[i];
puts("\nImage Load Succefull!\n");
puts("\nboot params = ");
puts(boot_params);
putch('\n');
}
else
puts("\nImage Load Succefull!\n");
call_linux(0, 193, buf);
}
/************************************************************/
static int support=0;
static void InitNandFlash(void)
{
U32 i;
InitNandCfg();
i = ReadChipId();
printf("Read chip id = %x\n", i);
if((i==0x9873)||(i==0xec75))
NandAddr = 0;
else if(i==0xec76)
{
support=1; //by chang
NandAddr = 1;
}
else {
puts("Chip id error!!!\n");
return;
}
printf("Nand flash status = %x\n", ReadStatus());
}
void NandErase(void)
{
int i, err = 0;
InitNandFlash();
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 = 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 ++;
puts("Press any key to continue...\n");
getch();
}
}
DsNandFlash(); //disable nand flash interface
puts("Erase Nand partition completed ");
if(err)
printf("with %d bad block(s)\n", err);
else
puts("success\n");
}
void NandWrite(void)
{
InitNandFlash();
WrFileToNF();
DsNandFlash(); //disable nand flash interface
}
void NandLoadRun(int Auto_Run)
{
InitNandFlash();
if(Auto_Run == 1)
{
puts("Now Boot Linux!\n");
LoadRun(2);
}
else if(Auto_Run == 2)
{
printf("Now boot Wince\n");
LoadRun(4);
}
else if(Auto_Run == 3)
{
printf("Now boot ucos-ii\n");
LoadRun(1);
}
else
return;
}
void memcpy(void *s1, const void *s2, int n)
{
int i;
for (i = 0; i < n; i++)
((char *)(s1))[i] = ((const char *)(s2))[i];
}
int strncmp(const char *s1, const char *s2, int maxlen)
{
int i;
for(i = 0; i < maxlen; i++) {
if(s1[i] != s2[i])
return ((int) s1[i]) - ((int) s2[i]);
if(s1[i] == 0)
return 0;
}
return 0;
}
#define MAX_TRY_TIME 5
int Write_partition_table()
{
U32 buf[128];
int i,k;
int j=3;
int partition_page;
int try_time;
for(i=0; ; i++)
{
if(NandPart[i].size == 0)
break;
else
{
buf[j++] = NandPart[i].offset;
buf[j++] = NandPart[i].size;
buf[j++] = 0x0; //flag
}
}
buf[j++] = 0x0; //number of bad blocks for partition 0
buf[j++] = 0x0; //partition 1
buf[j++] = 0x0; //partition 2
buf[j++] = rootfs_num_badblock; //partition 3
for(k=0; k<rootfs_num_badblock; k++)
buf[j++] = rootfs_badblock[k];
buf[j++] = 0x0; //partition 4
for(; j<128; j++)
buf[j] = 0xffffffff;
buf[2] = i;
buf[1] = 0x495a00;
buf[0] = 0x4900004d;
if(NandAddr)
partition_page = 4095 * 32;
else
partition_page = 2047 * 32;
for(try_time=0; try_time<MAX_TRY_TIME; try_time++){
if(EraseBlock(partition_page)) {
MarkBadBlk(partition_page);
partition_page -= 32;
continue;
}
else if(WritePage(partition_page, (U8 *)buf, 0)){
MarkBadBlk(partition_page);
partition_page -= 32;
continue;
}
else{
// printf("partition table write successful at page 0x%x!\n", partition_page);
return 0;
}
}
puts("Write partition table fail!\n");
return 1;
}
#define SAVE_ENV_IN_NAND
#ifdef SAVE_ENV_IN_NAND
U32 NFSaveParams(char *pEnv)
{
char dat[512];
U32 addr;
InitNandFlash();
if(support) {
memcpy(dat, pEnv, sizeof(EnvParams));
for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) {
EraseBlock(addr);
if(!WritePage(addr, (U8 *)dat, 1))
{
//printf("wite succes\n");
return 0;
}
}
}
return -1;
}
U32 NFSearchParams(char *pEnv)
{
char dat[512];
U32 addr;
InitNandFlash();
if(support) {
for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) {
ReadPage(addr, (U8 *)dat);
memcpy(pEnv, dat, sizeof(EnvParams));
return 0;
}
}
return -1;
}
#endif
/********************** add by chang *********************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -