📄 nand.c
字号:
if (ecc_status == -1) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } if (eccmode != NAND_ECC_HW3_512) { ecc_status = nand_correct_data(&data_poi[256], &ecc_code[3], &ecc_calc[3]); if (oob_buf) { *((int *) &oob_data[oob]) = ecc_status; oob += sizeof(int); } if (ecc_status == -1) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } } readdata: if (col || (len - read) < end) { for (j = col; j < end && read < len; j++) buf[read++] = data_poi[j]; } else read += NAND_PAGE_SIZE; /* For subsequent reads align to page boundary. */ col = 0; /* Increment page address */ page++; } /* De-select the NAND device */ nand_select_chip(-1); /* Return success, if no ECC failures, else -EIO * fs driver will take care of that, because * retlen == desired len and result == -EIO */ *retlen = read; return ecc_failed ? -EIO : 0;}/* * NAND read out-of-band */static int nand_read_oob(loff_t from, size_t len, size_t * retlen, u_char * buf){ int i, j, k, col, page; int erase_state = 0; /* Shift to get page */ page = ((int) from) >> NAND_PAGE_SHIFT; /* Mask to get column */ col = from & 0x0f; /* Initialize return length value */ *retlen = 0; /* Do not allow reads past end of device */ if ((from + len) > NAND_FLASH_SIZE) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ //nand_get_chip( FL_READING, &erase_state); /* Select the NAND device */ nand_select_chip(0); /* Send the read command */ nand_command(NAND_CMD_READOOB, col, page); /* Read the data, if we read more than one page * oob data, let the device transfer the data ! */ i = 0; while (i < len) { int thislen = (NAND_PAGE_OOB_SIZE - col) & (NAND_PAGE_OOB_SIZE - 1); if (!thislen) thislen = NAND_PAGE_OOB_SIZE; // thislen = min_t(int, thislen, len); nand_read_buf(&buf[i], thislen); i += thislen; col += thislen; /* Delay between pages */// udelay (this->chip_delay); for (k = 0; k < 10; k++) for (j = 0; j < 1000; j++); } /* De-select the NAND device */ nand_select_chip(-1); /* Return happy */ *retlen = len; return 0;}#define NOTALIGNED(x) ((x & (NAND_PAGE_SIZE-1)) != 0)///** NAND write with ECC */static int nand_write_ecc(loff_t to, size_t len, size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel){ unsigned long page1st, blkAddr = -1; int page, ret = 0, oob = 0, written = 0;// struct nand_chip *this = mtd->priv; u_char *data_poi; /* Do not allow write past end of device */ if ((to + len) > NAND_FLASH_SIZE) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); return -EINVAL; } /* reject writes, which are not page aligned */ if (NOTALIGNED(to)) {// printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; } // if oobsel is NULL, use chip defaults if (oobsel == NULL) oobsel = &oobinfo_buf; /* Shift to get page */ page = ((int) to) >> ADD2SHIFT; /* Grab the lock and see if the device is available */// nand_get_chip ( FL_WRITING, NULL); /* Select the NAND device */ nand_select_chip(0); nand_command(NAND_CMD_RESET, -1, -1); // set the WP *(base + NAND_SET_WP_REG) = 1; /* Check the WP bit */ nand_command(NAND_CMD_STATUS, -1, -1); if (!(nand_read_byte() & 0x80)) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n"); ret = -EIO; goto out; } /* Loop until all data is written */ while (written < len) { // before doing write, checking if this block is bad block or not ? // 32-pages per block, determine the 1st page page1st = ((unsigned long) page / NAND_BLK_PER_PAGE) * NAND_BLK_PER_PAGE; /* get the first page of this current block */ if (blkAddr != page1st) { // checking this block, if not checked yet blkAddr = page1st; if (nand_block_bad(blkAddr) != 0) { // this block is bad block, double confirm this is bad one, then try next block buart_print("\n\rBad flash block detected!"); // move forward to the 1st page of next block page = ((page + NAND_BLK_PER_PAGE) / NAND_BLK_PER_PAGE) * NAND_BLK_PER_PAGE; continue; } } // data_poi = (u_char *) & buf[written]; // ???? this->data_poi /* We use the same function for write and writev */ if (eccbuf) { ret = nand_write_page(data_poi, page, &eccbuf[oob], oobsel); oob += NAND_PAGE_OOB_SIZE; } else ret = nand_write_page(data_poi, page, NULL, oobsel); // if (ret) goto out; /* Update written bytes count */ written += NAND_PAGE_SIZE; /* Increment page address */ page++; } out: // clear the WP *(base + NAND_CLR_WP_REG) = 1; /* De-select the NAND device */ nand_select_chip(-1); *retlen = written; return ret;}static u_char ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};/* * NAND write out-of-band */static int nand_write_oob(loff_t to, size_t len, size_t * retlen, const u_char * buf){ int column, page, status, ret = 0, i;// struct nand_chip *this = mtd->priv;// DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Shift to get page */ page = ((int) to) >> ADD2SHIFT; /* Mask to get column */ column = to & 0x1f; /* Initialize return length value */ *retlen = 0; /* Do not allow write past end of page */ if ((column + len) > NAND_PAGE_OOB_SIZE) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); return -EINVAL; } /* Grab the lock and see if the device is available */// nand_get_chip ( FL_WRITING, NULL); /* Select the NAND device */ nand_select_chip(0); /* Reset the chip. Some chips (like the Toshiba TC5832DC found in one of my DiskOnChip 2000 test units) will clear the whole data page too if we don't do this. I have no clue why, but I seem to have 'fixed' it in the doc2000 driver in August 1999. dwmw2. */ nand_command(NAND_CMD_RESET, -1, -1); // set the WP *(base + NAND_SET_WP_REG) = 1; /* Check the WP bit */ nand_command(NAND_CMD_STATUS, -1, -1); if (!(nand_read_byte() & 0x80)) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n"); ret = -EIO; goto out; } /* Write out desired data */ nand_command(NAND_CMD_SEQIN, NAND_PAGE_SIZE, page); /* prepad 0xff for partial programming */ nand_write_buf(ffchars, column); /* write data */ nand_write_buf(buf, len); /* postpad 0xff for partial programming */ nand_write_buf(ffchars, NAND_PAGE_OOB_SIZE - (len + column)); /* Send command to program the OOB data */ nand_command(NAND_CMD_PAGEPROG, -1, -1); status = nand_wait(FL_WRITING); /* See if device thinks it succeeded */ if (status & 0x01) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; } /* Return happy */ *retlen = len;//#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ nand_command(NAND_CMD_READOOB, column, page); /* Loop through and verify the data */ for (i = 0; i < len; i++) { if (buf[i] != nand_read_byte()) {// DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); ret = -EIO; goto out; } }//#endif out: // clear the WP *(base + NAND_CLR_WP_REG) = 1; /* De-select the NAND device */ nand_select_chip(-1); return ret;}//================================================================// original APIs// src points to the beginning flash addressint nand_read(UINT8 * dst, UINT8 * src, UINT32 len){#ifdef NAND_ECC // testing by ProChao size_t retlen; nand_read_ecc((loff_t) src, (size_t) len, &retlen, (u_char *) dst, NULL, NULL); return (int) retlen;#else UINT32 i, j, col, row1, row2; int page; // ProChao *(base + NAND_CLR_CE_REG) = 1; for (i = 0; i < len; i += NAND_PAGE_SIZE, src += NAND_PAGE_SIZE) { *(base + NAND_CLR_SPn_REG) = 1; col = (int) src & ADD1MASK; row1 = ((int) src & ADD2MASK) >> ADD2SHIFT; row2 = ((int) src & ADD3MASK) >> ADD3SHIFT; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = 0; *(base + NAND_CLR_CLE_REG) = 1; *(base + NAND_SET_ALE_REG) = 1; *(base + NAND_RW_REG) = col; *(base + NAND_RW_REG) = row1; *(base + NAND_RW_REG) = row2; *(base + NAND_CLR_ALE_REG) = 1; // wait 1us */ for (j = 0; j < 1000; j++) { ;; } for (j = 0; j < NAND_PAGE_SIZE; j++) dst[i + j] = *(base + NAND_RW_REG); } *(base + NAND_SET_CE_REG) = 1;#endif return 0;}int nand_write(UINT8 * dst, UINT8 * src, UINT32 len){#ifdef NAND_ECC // testing by ProChao size_t retlen; nand_write_ecc((loff_t) dst, (size_t) len, &retlen, (const u_char *) src, NULL, NULL);// return (int) retlen;#else UINT32 i, j, col, row1, row2; base = (UINT8 *) NAND_REG_BASE; *(base + NAND_SET_WP_REG) = 1; *(base + NAND_CLR_CE_REG) = 1; for (i = 0; i < len; i += NAND_PAGE_SIZE, dst += NAND_PAGE_SIZE) { *(base + NAND_CLR_SPn_REG) = 1; col = (int) dst & ADD1MASK; row1 = ((int) dst & ADD2MASK) >> ADD2SHIFT; row2 = ((int) dst & ADD3MASK) >> ADD3SHIFT; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_WRITE1; *(base + NAND_CLR_CLE_REG) = 1; *(base + NAND_SET_ALE_REG) = 1; *(base + NAND_RW_REG) = col; *(base + NAND_RW_REG) = row1; *(base + NAND_RW_REG) = row2; *(base + NAND_CLR_ALE_REG) = 1; for (j = 0; j < NAND_PAGE_SIZE; j++) *(base + NAND_RW_REG) = src[j + i]; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_WRITE2; *(base + NAND_CLR_CLE_REG) = 1; /* wait 200 us */ for (j = 0; j < 20000; j++) { ;; } } *(base + NAND_SET_CE_REG) = 1; *(base + NAND_CLR_WP_REG) = 1;#endif return 0;}// note that, the addr must be the block starting addressint nand_erase(UINT8 * addr, UINT32 len){ UINT32 i, j, row1, row2; unsigned long page; base = (UINT8 *) NAND_REG_BASE; *(base + NAND_SET_WP_REG) = 1; *(base + NAND_CLR_SPn_REG) = 1; *(base + NAND_CLR_CE_REG) = 1; // here, NAND_SIZE_PER_BLK=0x4000 for (i = 0; i < len; i += NAND_SIZE_PER_BLK, addr += NAND_SIZE_PER_BLK) { // check if bad (invalid) blocks detected /* Shift to get first page */ page = (unsigned long) addr >> ADD2SHIFT; /* if (nand_block_bad( page) != 0) { // this block is bad block, double confirm this is bad one, then try next block buart_print("\n\rBad flash block detected!"); continue; } */ // erasing row1 = ((int) addr & ADD2MASK) >> ADD2SHIFT; row2 = ((int) addr & ADD3MASK) >> ADD3SHIFT; // *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_ERASE1; *(base + NAND_CLR_CLE_REG) = 1; *(base + NAND_SET_ALE_REG) = 1; *(base + NAND_RW_REG) = row1; *(base + NAND_RW_REG) = row2; *(base + NAND_CLR_ALE_REG) = 1; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_ERASE2; *(base + NAND_CLR_CLE_REG) = 1; /* wait 1ms */ for (j = 0; j < 100000; j++); } *(base + NAND_SET_CE_REG) = 1; *(base + NAND_CLR_WP_REG) = 1; return 0;}// for writing bootloaderint nand_write_boot(UINT8 * dst, UINT8 * src, UINT32 len){ volatile UINT8 *base, *dstorig; UINT32 i, j, col, row1, row2, k; base = (UINT8 *) NAND_REG_BASE; *(base + NAND_SET_WP_REG) = 1; *(base + NAND_CLR_CE_REG) = 1; i = 0; /* write spare area if < NAND_PAGE_OOB_SIZE */ while (i < NAND_BOOT_SIZE) { *(base + NAND_CLR_SPn_REG) = 1; col = (int) dst & ADD1MASK; row1 = ((int) dst & ADD2MASK) >> ADD2SHIFT; row2 = ((int) dst & ADD3MASK) >> ADD3SHIFT; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_WRITE1; *(base + NAND_CLR_CLE_REG) = 1; *(base + NAND_SET_ALE_REG) = 1; *(base + NAND_RW_REG) = col; *(base + NAND_RW_REG) = row1; *(base + NAND_RW_REG) = row2; *(base + NAND_CLR_ALE_REG) = 1; for (j = 0; j < NAND_PAGE_SIZE; j++) *(base + NAND_RW_REG) = src[i + j]; i += NAND_PAGE_SIZE; dst += NAND_PAGE_SIZE; // enable spare area *(base + NAND_SET_SPn_REG) = 1; for (k = 0; k < NAND_PAGE_OOB_SIZE; k++) *(base + NAND_RW_REG) = src[i + k]; i += NAND_PAGE_OOB_SIZE; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_WRITE2; *(base + NAND_CLR_CLE_REG) = 1; /* wait 200 us */ for (j = 0; j < 20000; j++) { ;; } } i = NAND_BOOT_SIZE; while (i < len) { *(base + NAND_CLR_SPn_REG) = 1; col = (int) dst & ADD1MASK; row1 = ((int) dst & ADD2MASK) >> ADD2SHIFT; row2 = ((int) dst & ADD3MASK) >> ADD3SHIFT; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_WRITE1; *(base + NAND_CLR_CLE_REG) = 1; *(base + NAND_SET_ALE_REG) = 1; *(base + NAND_RW_REG) = col; *(base + NAND_RW_REG) = row1; *(base + NAND_RW_REG) = row2; *(base + NAND_CLR_ALE_REG) = 1; for (j = 0; j < NAND_PAGE_SIZE; j++) *(base + NAND_RW_REG) = src[i + j]; i += NAND_PAGE_SIZE; dst += NAND_PAGE_SIZE; *(base + NAND_SET_CLE_REG) = 1; *(base + NAND_RW_REG) = CMD_WRITE2; *(base + NAND_CLR_CLE_REG) = 1; /* wait 200 us */ for (j = 0; j < 20000; j++) { ;; } } *(base + NAND_SET_CE_REG) = 1; *(base + NAND_CLR_WP_REG) = 1; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -