📄 nand.c
字号:
#include "dbldr_spec.h"#include "lib.h"#include "2410addr.h"#include "nand.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 READCMD0 (0x00)#define READCMD1 (0x01)#define READCMD2 (0x50)#define ERASECMD0 (0x60)#define ERASECMD1 (0xd0)#define PROGCMD0 (0x80)#define PROGCMD1 (0x10)#define QUERYCMD (0x70)#define RdIDCMD (0x90)static UINT32 _nand_addr_flag;#ifdef _HFRK_LINUX_2_4_struct partition nand_part[] = { {0x00000000, 0x00030000, "boot"}, //256K {0x00030000, 0x001d0000, "kernel"}, {0x00200000, 0x00600000, "rootfs"}, //6M {0x00800000, 0x00800000, "ext-fs1"}, //8M {0x01000000, 0x01000000, "ext-fs2"}, //16M {0x02000000, 0x02000000, "ext-fs3"}, //32M {0, 0 , 0}};#elsestruct partition nand_part[] = { { 0x00000000, 0x00020000, "boot" }, { 0x00020000, 0x00300000, "kernel" }, { 0x00320000, 0x00500000, "rootfs" }, { 0x00820000, 0x00100000, "etc" }, { 0x00920000, 0x00b00000, "user" }, { 0x01420000, 0x02b00000, "qt" }, { 0, 0, NULL }};#endifINT32 nand_part_num = 0;static void _init_nand_part_num(void);static void _init_cfg(void);static UINT32 _read_id(void);static UINT16 _read_status(void);static UINT32 _wait_busy(void);static INT32 _check_bad_blk(UINT32 addr);static UINT32 _erase_block(UINT32 addr);static void _mark_bad_blk(UINT32 addr);static void _read_page(UINT32 addr, UINT8 *buf);static void _init_nand_flash(void);static void _write_to_nand_flash(INT32 part_num, UINT8 *buf, INT32 len);static void _disable_nand_flash(void);static void _init_nand_part_num(void){ INT32 i; if (!nand_part_num) { for (i = 0; nand_part[i].name != NULL; i++) { /* nothing */ } nand_part_num = i; }}void disp_nand_part(void){ INT32 i; printf("no. offset size name\n"); for (i = 0; nand_part[i].name != NULL; i++) { printf("%d 0x%08x 0x%08x [%s]\n", i, nand_part[i].offset, nand_part[i].size, nand_part[i].name); } if (!nand_part_num) { nand_part_num = i; }}STATUS nand_write(INT32 part_num, INT8 *buf, INT32 size){ _init_nand_part_num(); if (part_num >= nand_part_num || part_num < 0) { printf("invalid partition number\n"); return ERROR; } if (!buf || size < 0) { printf("invalid parameter(s) in nand_write()\n"); return ERROR; } if (!size) { return OK; } _init_nand_flash(); _write_to_nand_flash(part_num, buf, size); _disable_nand_flash(); return OK;}STATUS load_prog_from_nand(INT32 part_num, INT8 *dest){ UINT32 start_page, size; INT8 *ram_addr; UINT32 i; _init_nand_part_num(); if (part_num >= nand_part_num || part_num < 0) { printf("invalid partition number\n"); return ERROR; } if (!dest) { printf("invalid parameter(s) in load_prog_from_nand()\n"); return ERROR; } _init_nand_flash(); start_page = nand_part[part_num].offset >> 9; size = nand_part[part_num].size; ram_addr = dest; for (i = 0; size > 0; ) { if (!(i & 0x1f)) { if (_check_bad_blk(i + start_page)) { printf("skipped bad block at 0x%x\n", i + start_page); i += 32; size -= (32 << 9); continue; } } _read_page((i + start_page), (UINT8 *)ram_addr); i++; size -= 512; ram_addr += 512; } DsNandFlash(); return OK;}/*****************************************************************************/static void _init_cfg(void){ //enable nand flash control, initilize ecc, chip disable, rNFCONF = (1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7);}static UINT32 _read_id(void){ UINT32 id; NFChipEn(); WrNFCmd(RdIDCMD); WrNFAddr(0); while(NFIsBusy()); id = RdNFDat() << 8; id |= RdNFDat(); NFChipDs(); return id;}static UINT16 _read_status(void){ UINT16 stat; NFChipEn(); WrNFCmd(QUERYCMD); stat = RdNFDat(); NFChipDs(); return stat;}static UINT32 _wait_busy(void){ UINT8 stat; WrNFCmd(QUERYCMD); do { stat = RdNFDat(); } while(!(stat & 0x40)); WrNFCmd(READCMD0); return stat & 1;}static INT32 _check_bad_blk(UINT32 addr){ UINT8 dat; addr &= ~0x1f; NFChipEn(); WrNFCmd(READCMD2); //point to area c WrNFAddr(5); //mark offset 4,5,6,7 WrNFAddr(addr); WrNFAddr(addr >> 8); if(_nand_addr_flag) WrNFAddr(addr >> 16); _wait_busy(); dat = RdNFDat(); WrNFCmd(READCMD0); //point to area a NFChipDs(); return (dat != 0xff);}static void _mark_bad_blk(UINT32 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(_nand_addr_flag) { WrNFAddr(addr >> 16); } WrNFDat(0); //mark with 0 WrNFDat(0); WrNFDat(0); //mark with 0 WrNFDat(0); WrNFCmd(PROGCMD1); _wait_busy(); //needn't check return status WrNFCmd(READCMD0); //point to area a NFChipDs();}static UINT32 _erase_block(UINT32 addr){ UINT8 stat; addr &= ~0x1f; NFChipEn(); WrNFCmd(ERASECMD0); WrNFAddr(addr); WrNFAddr(addr >> 8); if(_nand_addr_flag) { WrNFAddr(addr >> 16); } WrNFCmd(ERASECMD1); stat = _wait_busy(); NFChipDs();#ifdef ER_BAD_BLK_TEST if(!((addr + 0xe0) & 0xff)) { stat = 1; /* just for testing bad block */ }#endif printf("."); return stat;}/* addr = page address */static void _read_page(UINT32 addr, UINT8 *buf){ UINT16 i; NFChipEn(); WrNFCmd(READCMD0); WrNFAddr(0); WrNFAddr(addr); WrNFAddr(addr >> 8); if(_nand_addr_flag) WrNFAddr(addr >> 16); InitEcc(); _wait_busy(); for(i = 0; i < 512; i++) { buf[i] = RdNFDat(); } NFChipDs();}static UINT32 _write_page(UINT32 addr, UINT8 *buf){ UINT16 i; UINT8 stat, tmp[3]; NFChipEn(); WrNFCmd(PROGCMD0); WrNFAddr(0); WrNFAddr(addr); WrNFAddr(addr >> 8); if(_nand_addr_flag) { 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 = _wait_busy(); NFChipDs();#ifdef WR_BAD_BLK_TEST if((addr&0xff)==0x17) { stat = 1; /* just for test bad block */ }#endif if(stat) { printf("write nand flash 0x%08x failed\n", addr); } else { UINT8 rd_dat[512]; _read_page(addr, rd_dat); for(i = 0; i < 512; i++) { if(rd_dat[i] != buf[i]) { printf("check data at page 0x%x, offset 0x%x failed\n", addr, i); stat = 1; break; } } } return stat;}/*****************************************************************************/static void _init_nand_flash(void){ UINT32 id; _init_cfg(); id = _read_id(); printf("nand flash id = 0x%04x\n", id); if ((0x9873 == id) || (0xec75 == id)) { _nand_addr_flag = 0; } else if (0xec76 == id) { _nand_addr_flag = 1; } else { printf("invalid flash id\n"); DBLDR_PANIC; } printf("nand flash status = 0x%08x\n", _read_status());}static void _write_to_nand_flash(INT32 part_num, UINT8 *buf, INT32 len){ UINT32 start_page = nand_part[part_num].offset >> 9; UINT32 block_cnt = nand_part[part_num].size >> 14; INT8 ch; INT32 skip_blks = 0; INT32 i; INT8 *ram_addr; INT32 size; printf("are you sure to write at the start page %d, block count %d? [y/n] ", start_page, block_cnt); while (1) { ch = UART_GETCH(); if (('Y' == ch) || ('y' == ch)) { printf("%c\n", ch); /* echo */ break; } else if (('N' == ch) || ('n' == ch)) { printf("%c\n", ch); /* echo */ return; } } printf("now write the nand flash page %d from ram address 0x%08x, len = %d\n", start_page, (UINT32)buf, len); skip_blks = 0; ram_addr = buf; size = len; for (i = 0; size > 0; ) { if (!(i & 0x1f)) { if (_erase_block(i + start_page)) { nand_part[part_num].size -= (32 << 9); /* one block is broken */ /* partition available size - 1 block size */ if (len > nand_part[part_num].size) { printf("\nprogram nand flash fail\n"); return; } _mark_bad_blk(i + start_page); skip_blks++; i += 32; continue; } } if (_write_page(i + start_page, (UINT8 *)ram_addr)) { ram_addr -= ((i & 0x1f) << 9); size += ((i & 0x1f) << 9); i &= ~0x1f; nand_part[part_num].size -= (32 << 9); /* one block is broken */ /* partition available size - 1 block size */ if (len > nand_part[part_num].size) { printf("\nprogram nand flash fail\n"); return; } _mark_bad_blk(i + start_page); skip_blks++; i += 32; continue; } ram_addr += 512; size -= 512; i++; } printf("\nprogrm nand flash successfully\n"); if (skip_blks) { printf("warning: skiped %d bad blocks\n"); }}static void _disable_nand_flash(void){ DsNandFlash();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -