📄 cmd_nand.c
字号:
/* * (C) 2004 Samsung Electronics * Young-jun Jang <yj03.jang@samsung.com> * - add/modify nandw,nandr, nande, nandv * - bad block management (bbcheck, bbmark) * - yaffs image r/w (nandyw, nandyr) * (C) 2004 Samsung Electronics * SW.LEE <hitchcar@samsung.com> * - add nande, nandE * - support 16Bit / 3 Addr cycle nand * (C) 2003 Samsung Electronics * - getfree * * Driver for NAND support, Rick Bronson * borrowed heavily from: * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> */#include <common.h>#if defined(CONFIG_S3C24XX)#if (CONFIG_COMMANDS & CFG_CMD_NAND)#include <command.h>#include <malloc.h>#include <asm/io.h>#include <regs.h>#include <linux/mtd/nand.h>#include <jffs2/jffs2.h>#ifdef CONFIG_SHOW_BOOT_PROGRESS#include <status_led.h>#define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)#else#define SHOW_BOOT_PROGRESS(arg)#endif#define BAD_CHECK//#undef ECC_CHECK /* XXX: we will do in the future */#define ECC_CHECK#ifdef ECC_CHECK#define ECC_COUNT_BIT 256#endif#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))static int NF_EraseBlock(u32 blockNum);static int NF_WritePage(u32 block, u32 page, u8 * buffer);static int NF_WriteOob(u32 block, u32 page, u8 * buffer, int yaffs_option);static int NF_IsBadBlock(u32 block);static int NF_MarkBadBlock(u32 block, int mark_flag);static void NF_Reset(void);static u8 seBuf[NAND_OOB_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};/* * address format * 17 16 9 8 0 * -------------------------------------------- * | block(12bit) | page(5bit) | offset(9bit) | * -------------------------------------------- */static int nandll_read_page(uchar *buf, ulong addr){ int i; int loop = 0; int j = 0;#ifdef ECC_CHECK u8 oobbuf[NAND_OOB_SIZE] = {0};#endif#ifdef S3C24X0_16BIT_NAND ushort *ptr16 = (ushort *)buf;#endif if (addr & NAND_PAGE_MASK) { return -1; /* invalid alignment */ } // NFCONT_REG &= ~(1<<1); //NFCONT_REG &= ~(1<<1); //NAND_ENABLE_CE(); NFCONT_REG &= ~(1<<1);#ifdef ECC_CHECK NF_RSTECC(); // Initialize ECC NF_MECC_UnLock(); NF_CLRRnB();#endif NFCMD_REG = NAND_CMD_READ0; //0x0 /* Write Address */ NFADDR_REG = addr & 0xff; NFADDR_REG = (addr >> 7) & 0x0f; NFADDR_REG = (addr >> 11) & 0xff; NFADDR_REG = (addr >> 19) & 0xff; NFCMD_REG = 0x30; NF_TRANSRnB();#ifndef ECC_CHECK for(i=0; i < NAND_PAGE_SIZE; i++) { *buf = NFDATA8_REG; buf++; }#else seBuf[0] = 0xff; seBuf[1] = 0xff; loop = 0; for(i = 0;i<NAND_PAGE_SIZE;){ for(j= 0; j <ECC_COUNT_BIT;j++){ *buf = NFDATA8_REG; buf++; i++; } NF_MECC_Lock(); seBuf[40+loop] = (NFMECC0_REG & 0x0ff); seBuf[41+loop] = ((NFMECC0_REG >>8)&0xff); seBuf[42+loop] = ((NFMECC0_REG >>16)&0xff); seBuf[42+loop] |= 0x03; loop += 3; NF_RSTECC(); // Initialize ECC NF_MECC_UnLock(); NF_CLRRnB(); }#endif NFCONT_REG |= (1<<1);#if 0#ifdef ECC_CHECK nandll_read_oob(oobbuf,addr); printf("\nRead ECC :"); for(i = 0;i < 5; i++) printf("%x ",oobbuf[i]); printf("\nECC CODE :"); for(i = 0;i < 5; i++) printf("%x ",seBuf[i]);#endif#endif return 0;}static int nandll_read_oob(char *buf, ulong addr){ int i;#ifdef S3C24X0_16BIT_NAND ushort *ptr16 = (ushort *)buf;#else u8 *oobptr8 = (u8 *)buf;#endif /* Chip Enable */ NFCONT_REG &= ~(1<<1); //NFCONT_REG &= ~(1<<1); //NAND_ENABLE_CE(); NF_CLRRnB(); /* READOOB */ NFCMD_REG = 0x0;//NAND_CMD_READOOB; /* Write Address */ NFADDR_REG = 0x00;//addr & 0xff ; NFADDR_REG = 0x08;//(addr >> 0x07)&0x0f; NFADDR_REG = (addr >> 11) & 0xff; NFADDR_REG = (addr >> 19) & 0xff; NFCMD_REG = 0x30; NF_TRANSRnB(); for(i=0; i < NAND_OOB_SIZE; i++) { *oobptr8 = NFDATA8_REG; oobptr8++; } NFCONT_REG |= (1<<1); //NAND_DISABLE_CE();/* printf("\nLast OOB :"); for(i = 0;i < NAND_OOB_SIZE;i++) printf(" %2x ",buf[i]);*/ return 0;}static int is_bad_block(unsigned long addr){ char oob_buf[64]; nandll_read_oob((char *)oob_buf, addr); /* culprit */#ifdef S3C24X0_16BIT_NAND if ( (oob_buf[0] != 0xFF) || (oob_buf[1] != 0xFF) ) return 1;#else if (oob_buf[0] != 0xFF) return 1;#endif else return 0;}#ifdef OREIAS#define adjust_bank(x) \ do { \ if(x>=0x11e00000) \ x=x+0x6200000;\ } while(0)#endif#define check_blk_range(blk) \ do { \ if (blk<0 || blk>=4096) { \ printf( "out of block range\n" ); \ return 1; \ } \ } while(0)#define check_page_range(page) \ do { \ if (page<0 || page>=32) { \ printf( "out of page range\n" ); \ return 1; \ } \ } while(0)static int s3c24x0_nand_read(uint blockIndex, int size, uint destAddress, int flag){ char *buf = (char *) destAddress; char page_buf[NAND_PAGE_SIZE]; char oob_buf[NAND_OOB_SIZE]; int i, j; u32 src_addr = blockIndex * NAND_BLOCK_SIZE; printf("block read : "); while (size > 0) { if (flag != NF_RW_YAFFS) { /* If this block is bad, go next block */ if (is_bad_block(src_addr)) { src_addr += NAND_BLOCK_SIZE; continue; } } printf("%X ", (src_addr >> 17)); /* Read block */ for (i = 0; i < NAND_PAGES_IN_BLOCK; i++) { nandll_read_page((uchar *) page_buf, src_addr); for (j = 0; j < NAND_PAGE_SIZE; j++) { *buf++ = page_buf[j]; } size -= NAND_PAGE_SIZE; if (size <= 0) break; if (flag == NF_RW_YAFFS) { /* read oob */ nandll_read_oob((char *) oob_buf, src_addr); for (j = 0; j < NAND_OOB_SIZE; j++) { *buf++ = oob_buf[j]; } size -= NAND_OOB_SIZE; if (size <= 0) break; } src_addr += NAND_PAGE_SIZE; } } printf("\n"); return 0;}/* * s3c24x0_nand_write * * yaffs_option : only used when flag is yaffs mode. */static int s3c24x0_nand_write( uint targetBlock, uint targetSize, uint srcAddress, int flag, int yaffs_option){ int i; int programError = 0; u8 *srcPt, *saveSrcPt; u32 blockIndex; printf("\nNAND Flash Write\n"); printf("Source base address = 0x%x\n", srcAddress); printf("Target start block number = 0x%x (%d)\n", targetBlock, targetBlock); printf("Target size (0x4000*n) = 0x%x\n", targetSize); printf("block written :\n"); srcPt = (u8 *) srcAddress; blockIndex = targetBlock; while (1) { saveSrcPt = srcPt;#if 1#ifdef BAD_CHECK if (NF_IsBadBlock(blockIndex)) { blockIndex++; // for next block continue; }#endif if (!NF_EraseBlock(blockIndex)) { blockIndex++; // for next block printf(" Error-> Erase Block %d \n", (int) blockIndex); continue; }#endif for (i = 0; i < NAND_PAGES_IN_BLOCK; i++) { if (!NF_WritePage(blockIndex, i, srcPt)) { programError = 1; break; }/*#ifdef ECC_CHECK if (flag != NF_RW_YAFFS) { if (!NF_ReadPage(blockIndex, i, srcPt)) { printf("ECC Error(block=%d,page=%d!!!\n", (int) blockIndex, i); } }#endif*/ srcPt += NAND_PAGE_SIZE;/* if (flag == NF_RW_YAFFS) { if (!NF_WriteOob(blockIndex, i, srcPt, yaffs_option)) { programError = 1; break; } srcPt += NAND_OOB_SIZE; }*/ //printf("."); if ((u32) srcPt >= (srcAddress + targetSize)) { // Check end of buffer break; // Exit for loop } } if (programError == 1) { blockIndex++; srcPt = saveSrcPt; programError = 0; continue; } printf("%3x ", blockIndex); if (!((blockIndex+1) % 16)) printf("\n"); if ((u32) srcPt >= (srcAddress + targetSize)) break; // Exit while loop blockIndex++; } printf("\n\n"); return 0;}int do_nandE(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){ int startblk, size, eraseblocks, i; if (argc != 3) { printf("Usage:\n%s\n", cmdtp->usage); return 1; } startblk = simple_strtoul(argv[1], NULL, 16); size = simple_strtoul(argv[2], NULL, 16); printf("StartBlock %d (0x%x) : Size %d (0x%x) \n", startblk, startblk, size, size); eraseblocks = size / NAND_BLOCK_SIZE; printf("Total Erase Blocks %d (0x%x) \n", eraseblocks, eraseblocks); udelay(10000); NF_Reset(); for (i = 0; i < eraseblocks; i++) { NF_EraseBlock(startblk); startblk++; } return 0;}int do_nandw(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){ ulong startblk, size, memadr; if (argc != 4) { printf("Usage:\n%s\n", cmdtp->usage); return 1; } startblk = simple_strtoul(argv[1], NULL, 16); size = simple_strtoul(argv[2], NULL, 16); memadr = simple_strtoul(argv[3], NULL, 16); NF_Reset(); s3c24x0_nand_write(startblk, size, memadr, NF_RW_NORMAL, 0); { uint *magic = (uint*)(PHYS_SDRAM_1); magic[0] = 0x27051956; } return 0;}int do_nandr(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){ ulong startblk, size, memadr; if (argc != 4) { printf("Usage:\n%s\n", cmdtp->usage); return 1; } startblk = simple_strtoul(argv[1], NULL, 16); size = simple_strtoul(argv[2], NULL, 16); memadr = simple_strtoul(argv[3], NULL, 16); NF_Reset(); s3c24x0_nand_read(startblk, size, memadr, NF_RW_NORMAL); return 0;}int do_nande(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){ int i; ulong blk_start, blk_end; if (argc != 3) { printf("Usage:\n%s\n", cmdtp->usage); return 1; } blk_start = simple_strtoul(argv[1], NULL, 16); blk_end = simple_strtoul(argv[2], NULL, 16); for (i = blk_start; i <= blk_end; i++) { if (!NF_EraseBlock(i)) { printf("nand flash erase error : at block %x\n", i); } } printf("nand flash erase complete\n"); return 0;}int do_bbmark(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){ ulong blk; if (argc != 3) { printf("Usage:\n%s\n", cmdtp->usage); return 1; } blk = simple_strtoul(argv[1], NULL, 16); check_blk_range(blk); if (!NF_EraseBlock(blk)) { printf("erase error\n"); } if (strcmp(argv[2], "on") == 0) NF_MarkBadBlock(blk, NF_BB_ON); else NF_MarkBadBlock(blk, NF_BB_OFF); return 0;}int do_bbcheck(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){ int i, bb_cnt; printf("Bad block list : \n"); for (bb_cnt = 0, i = 0; i < 4096; i++) { if (NF_IsBadBlock(i)) { bb_cnt++; } } if (bb_cnt > 0) { printf("\n Total bad block count : %d \n", bb_cnt); } else { printf("No bad block\n"); } return 0;}/* show page data */int do_nandv(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){ int blk, page, i; u32 oob_buf[16 / 4]; u32 page_buf[512 / 4]; if (argc != 3) { printf("Usage:\n%s\n", cmdtp->usage); return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -