www.pudn.com > cmd_nand.rar > cmd_nand.c
/* * (C) 2004 Samsung Electronics * Young-jun Jang* - add/modify nandw,nandr, nande, nandv * - bad block management (bbcheck, bbmark) * - yaffs image r/w (nandyw, nandyr) * (C) 2004 Samsung Electronics * SW.LEE * - 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 */ #include #if defined(CONFIG_S3C24XX) #if (CONFIG_COMMANDS & CFG_CMD_NAND) #include #include #include #include #include #include #ifdef CONFIG_SHOW_BOOT_PROGRESS #include #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 >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; } blk = simple_strtoul(argv[1], NULL, 16); page = simple_strtoul(argv[2], NULL, 10); check_blk_range(blk); check_page_range(page); nandll_read_page((u8 *) page_buf, (blk * NAND_BLOCK_SIZE) + (page * NAND_PAGE_SIZE)); for (i = 0; i < 32; i++) { printf("%03x: %08x %08x %08x %08x\n", i << 4, page_buf[(i << 2) + 0], page_buf[(i << 2) + 1], page_buf[(i << 2) + 2], page_buf[(i << 2) + 3]); } nandll_read_oob((char *) oob_buf, (blk * NAND_BLOCK_SIZE) + (page * NAND_PAGE_SIZE)); printf("\nOOB: %08x %08x %08x %08x\n\n", oob_buf[0], oob_buf[1], oob_buf[2], oob_buf[3]); return 0; } int do_nandyw(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { ulong startblk, size, memadr; int ecc_option; if (argc != 5) { printf("Usage:\n%s\n", cmdtp->usage); return 1; } startblk = simple_strtoul(argv[1], NULL, 16); check_blk_range(startblk); size = simple_strtoul(argv[2], NULL, 16); memadr = simple_strtoul(argv[3], NULL, 16); ecc_option = (argv[4][0] == 'y') ? NF_USE_ECC : NF_USE_MTD_ECC; // yaffs image don't use 1st block startblk++; NF_Reset(); s3c24x0_nand_write(startblk, size, memadr, NF_RW_YAFFS, ecc_option); return 0; } int do_nandyr(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); // yaffs image don't use 1st block startblk++; NF_Reset(); s3c24x0_nand_read(startblk, size, memadr, NF_RW_YAFFS); return 0; } /* getfree added U_BOOT_CMD TABLE 2003.12.05 */ U_BOOT_CMD(nandr, 4, 0, do_nandr, "nandr - read data from NAND (specific)\n", "blk# size memaddr\n" " - SMDK24XX NAND Flash Read Command\n" " - targetblock 0~0xfff(4095), targetsize memory addr\n"); U_BOOT_CMD(nandw, 4, 0, do_nandw, "nandw - write data to NAND (specific)\n", "blk# size memaddr\n" " - SMDK24XX NAND Flash Write Command\n" " - targetblock 0~0xfff(4095), targetsize memory addr\n"); /* add command (nande, bbmark, bbcheck) by jyj. (2004.8.10) */ U_BOOT_CMD(nande, 3, 0, do_nande, "nande - erase NAND block (specific)\n", "startblk# endblk#\n" " - SMDK24XX NAND Flash Erase Command\n" " - block range : 0 ~ 0xfff(4095) in hex value\n"); U_BOOT_CMD(bbmark, 3, 0, do_bbmark, "bbmark - mark NAND bad block (specific)\n", "blk# on/off\n" " - SMDK24XX NAND Flash Mark Bad Block Command\n" " - block range : 0 ~ 0xfff(4095) as hex value\n" " - on/off : mark/unmark bad block\n"); U_BOOT_CMD(bbcheck, 3, 0, do_bbcheck, "bbcheck - show NAND bad block (specific)\n", " - SMDK24XX NAND Flash Show Bad Block Command"); U_BOOT_CMD(nandv, 3, 0, do_nandv, "nandv - show NAND block data (specific)\n", "blk page\n" " - SMDK24XX NAND Flash Show Block Data Command\n" " - block range : 0 ~ 0xfff(4095) in hexa\n" " - page range : 0 ~ 31 in decimal\n"); U_BOOT_CMD(nandyw, 5, 0, do_nandyw, "nandyw - write YAFFS block in NAND (specific)\n", "blk# size addr ecc_option\n" " - SMDK24XX NAND Flash Write Command for Yaffs\n" " - targetblock 0~0xfff(4095), targetsize memory addr\n" " - ecc_option : [y] use yaffs ecc / [m] use mtd ecc\n"); U_BOOT_CMD(nandyr, 4, 0, do_nandyr, "nandyr - read YAFFS block in NAND (specific)\n", "blk# size addr\n" " - SMDK24XX NAND Flash Read Command for Yaffs\n" " - block 0~0xfff(4095)\n"); U_BOOT_CMD(nandE, 4, 0, do_nandE, "nandE - erase block and OOB (specific)\n", "blk# size" " - delete all blocks in given range regardless Bad Blcok\n"); /* * NF_MarkBadBlock : */ static int NF_MarkBadBlock(u32 block, int mark_flag) { int i; u32 blockPage; #ifdef S3C24X0_16BIT_NAND u16 *Buf = (unsigned short *) seBuf; #endif blockPage = (block << 6); seBuf[0] = 0x44; seBuf[1] = 0xff; seBuf[40] = 0xff; seBuf[41] = 0xff; seBuf[42] = 0xff; seBuf[43] = 0xff; seBuf[44] = 0xff; seBuf[45] = 0xff; seBuf[46] = 0xff; seBuf[47] = 0xff; seBuf[48] = 0xff; seBuf[49] = 0xff; seBuf[50] = 0xff; seBuf[51] = 0xff; seBuf[52] = 0xff; seBuf[53] = 0xff; seBuf[54] = 0xff; seBuf[55] = 0xff; seBuf[56] = 0xff; seBuf[57] = 0xff; seBuf[58] = 0xff; seBuf[59] = 0xff; seBuf[60] = 0xff; seBuf[61] = 0xff; seBuf[62] = 0xff; seBuf[63] = 0xff; // seBuf[5] = 0x44; // 0xff is good block, else is bad block if (mark_flag == NF_BB_OFF) seBuf[0] = 0xff; NF_nFCE_L(); // NFCMD_REG = NAND_CMD_READOOB; // NFCMD_REG = NAND_CMD_SEQIN; // Write 1st command NFCMD_REG = 0x80; NFADDR_REG = 0x00; // The mark of bad block is NFADDR_REG = 0x00; NFADDR_REG = blockPage & 0xff; // marked 5th spare array NFADDR_REG = (blockPage >>8) & 0xff; // in the 1st page. for (i = 0; i < NAND_OOB_SIZE; i++) { NFDATA8_REG = seBuf[i]; } // NFCMD_REG = NAND_CMD_PAGEPROG; NFCMD_REG = 0x10; for (i = 0; i < 10; i++); NF_TRANSRnB(); NFCMD_REG = NAND_CMD_STATUS; for (i = 0; i < 3; i++); if (NFDATA8_REG & 0x1) { // Spare arrray write error NF_nFCE_H(); printf("[Program error is occurred but ignored]\n"); } else { NF_nFCE_H(); } if (mark_flag == NF_BB_ON) { printf("[block 0x%x is marked as a bad block]\n", block); } else { printf("[block 0x%x is marked as a good block]\n", block); } return 1; } static int NF_WritePage(u32 block, u32 page, u8 * buffer) { int i; int j = 0; int loop = 0; u32 blockPage = (block * NAND_PAGES_IN_BLOCK) + page; #ifdef S3C24X0_16BIT_NAND u16 *Buf = (unsigned short) seBuf; u16 *ptr16 = buffer; #else u8 *ptr8 = buffer; #endif int ret = 1; #ifdef ECC_CHECK NF_RSTECC(); // Initialize ECC NF_MECC_UnLock(); NF_CLRRnB(); #endif NAND_WP_OFF(); NF_nFCE_L(); // NFCMD_REG = NAND_CMD_READ0; // NFCMD_REG = NAND_CMD_SEQIN; NFCMD_REG = 0x80; NFADDR_REG = 0x00; NFADDR_REG = 0x00; NFADDR_REG = blockPage & 0xff; NFADDR_REG = ((blockPage >> 8) & 0xff); #ifndef ECC_CHECK for(i = 0;i >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 // NFCMD_REG = NAND_CMD_PAGEPROG; NFCMD_REG = 0x10; for (i = 0; i < 10; i++); NF_TRANSRnB(); NFCMD_REG = 0x70;//NAND_CMD_STATUS; for (i = 0; i < 10; i++); if (NFDATA8_REG & 0x1) { /* Page Error */ printf("[PROGRAM_ERROR:block#=%d]\n", block); NF_MarkBadBlock(block, NF_BB_ON); ret = 0; } NF_nFCE_H(); NAND_WP_ON(); #ifdef ECC_CHECK NF_WriteOob(block,page,seBuf,-1); #endif return ret; } static int NF_WriteOob(u32 block, u32 page, u8 * buffer, int yaffs_option) { int i; u32 blockPage = (block * NAND_PAGES_IN_BLOCK) + page; #ifdef S3C24X0_16BIT_NAND u16 *ptr16 = buffer; #else u8 *ptr8 = buffer; u8 oobBuf[NAND_OOB_SIZE]; for (i = 0; i < NAND_OOB_SIZE; i++) { oobBuf[i] = (*ptr8++); } if (yaffs_option == NF_USE_MTD_ECC) { oobBuf[8] = 0xFF; oobBuf[9] = 0xFF; oobBuf[10] = 0xFF; oobBuf[13] = 0xFF; oobBuf[14] = 0xFF; oobBuf[15] = 0xFF; } #endif NF_nFCE_L(); // NFCMD_REG = NAND_CMD_READOOB; // NFCMD_REG = NAND_CMD_SEQIN; NFCMD_REG =0x80; NFADDR_REG = 0x00; NFADDR_REG = 0x08; NFADDR_REG = (blockPage & 0xff); NFADDR_REG = ((blockPage >> 8) & 0xff); for (i = 0; i < NAND_OOB_SIZE; i++) { NFDATA8_REG = oobBuf[i]; } // NFCMD_REG = NAND_CMD_PAGEPROG; NFCMD_REG = 0x10; for (i = 0; i < 10; i++); NF_TRANSRnB(); NFCMD_REG = NAND_CMD_STATUS; for (i = 0; i < 3; i++); if (NFDATA8_REG & 0x1) { /* Page Error */ printf("[Program error is occurred but ignored]\n"); } NF_nFCE_H(); /* printf("\n ECC :" ); for(i = 0;i<5;i++) { printf(" %x ",oobBuf[i]); } */ return 1; } static void NF_Reset(void) { int i; NF_CLRRnB(); NF_nFCE_L(); NFCMD_REG = NAND_CMD_RESET; for (i = 0; i < 80; i++); NF_TRANSRnB(); NF_nFCE_H(); } /* * NF_EraseBlock */ #if 0 static int NF_EraseBlock (u32 block) { u32 blockPage; int i, ret = 1; NAND_WP_OFF(); blockPage = block * NAND_PAGES_IN_BLOCK; NF_CLRRnB(); NF_nFCE_L(); NFCMD_REG = 0x60//NAND_CMD_ERASE1; NFADDR_REG = blockPage & 0xff; NFADDR_REG = (blockPage >> 8) & 0xff; NFADDR_REG = (blockPage >> 16) & 0xff; NFCMD_REG = NAND_CMD_ERASE2; for (i = 0; i < 40; i++); NF_TRANSRnB(); NFCMD_REG = NAND_CMD_STATUS; if (NFDATA8_REG & 0x1) { /* we got Erase error */ printf("[ERASE_ERROR:block#=%d]\n", block); NF_MarkBadBlock(block, NF_BB_ON); ret = 0; } NF_nFCE_H(); NAND_WP_ON(); return ret; } #else static int NF_EraseBlock (u32 block) { u32 blockPage; int i, ret = 1; NAND_WP_OFF(); blockPage = block * NAND_PAGES_IN_BLOCK; NF_CLRRnB(); NF_nFCE_L(); NFCMD_REG = 0x60;//NAND_CMD_ERASE1; // NFADDR_REG = blockPage & 0xff; // NFADDR_REG = (blockPage >> 8) & 0xff; // NFADDR_REG = (blockPage >> 16) & 0xff; NFADDR_REG = (blockPage & 0xff); NFADDR_REG = ((blockPage >> 8) & 0xff); NFCMD_REG = 0xD0;//NAND_CMD_ERASE2; for (i = 0; i < 40; i++); NF_TRANSRnB(); NFCMD_REG = NAND_CMD_STATUS; if (NFDATA8_REG & 0x1) { /* we got Erase error */ printf("[ERASE_ERROR:block#=%d]\n", block); NF_MarkBadBlock(block, NF_BB_ON); ret = 0; } NF_nFCE_H(); NAND_WP_ON(); return ret; } #endif static int NF_IsBadBlock(u32 block) { int i; int blockPage; #ifdef S3C24X0_16BIT_NAND u16 data; #else u8 data; #endif blockPage = block * NAND_PAGES_IN_BLOCK; NF_CLRRnB(); NF_nFCE_L(); //Joe # if 0 NFCMD_REG = NAND_CMD_READOOB; #ifdef S3C24X0_16BIT_NAND NFADDR_REG = 512 & 0x7; /* X16 A0~A2 are valid */ #else NFADDR_REG = 517 & 0xf; // Read the mark of bad block in spare array(M addr=5) #endif NFADDR_REG = blockPage & 0xff; // The mark of bad block is in 0 page NFADDR_REG = (blockPage >> 8) & 0xff; // For block number A[24:17] #ifdef NAND_3_ADDR_CYCLE #else NFADDR_REG = (blockPage >> 16) & 0xff; // For block number A[25] #endif #endif NFCMD_REG = 0x0; NFADDR_REG = 0x00; NFADDR_REG = 0x08; NFADDR_REG = (blockPage&0xff); NFADDR_REG =((blockPage>>8)&0xff); NFCMD_REG = 0x30; // data = NFDATA8_REG; for (i = 0; i < 10; i++); /* dummy check me */ NF_TRANSRnB(); data = NFDATA8_REG; NF_nFCE_H(); if (data != 0xff) { printf("[block 0x%x has been marked as a bad block(%x)]\n", block, data); return 1; } else { return 0; } } /* void nand_init() { printf("64MB\n"); } */ #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */ #endif /* CONFIG_S3C24XX */