📄 smc_core.c
字号:
#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* * The NAND device assumes that it is always writing to * a cleanly erased page. Hence, it performs its internal * write verification only on bits that transitioned from * 1 to 0. The device does NOT verify the whole page on * a byte by byte basis. It is possible that the page was * not completely erased or the page is becoming unusable * due to wear. The read with ECC would catch the error * later when the ECC page check fails, but we would rather * catch it early in the page write stage. Better to write * no data than invalid data. */ /* Send command to read back the page */ if (col < mtd->eccsize) nand_command(mtd, NAND_CMD_READ0, col, page); else nand_command(mtd, NAND_CMD_READ1, col - 256, page); this->wait_for_ready(); /* Loop through and verify the data */ for (i = col; i < cnt; i++) { if (this->data_buf[i] != this->read_data()) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write verify, " \ "page 0x%08x, %6i bytes were succesful\n", page, *retlen); i = -EIO; goto nand_write_exit; } }#endif /* * If we are writing a large amount of data and/or it * crosses page or half-page boundaries, we set the * the column to zero. It simplifies the program logic. */ if (col) col = 0x00; /* Update written bytes count */ *retlen += cnt; /* Increment page address */ page++; } /* Return happy */ *retlen = len; i = 0;nand_write_exit: /* De-select the NAND device */ nand_deselect(); return i;}/* * NAND write witdh ECC, but only 1 sector! */static intnand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *ecc_code){ int i, page, cnt, status, ret; struct nand_chip *this = mtd->priv; unsigned int sector_size, page_size, oob_size; DEBUG(MTD_DEBUG_LEVEL3, __FUNCTION__"(): to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); sector_size = this->dev->szS; page_size = mtd->oobblock; oob_size = mtd->oobsize; if (to & (sector_size - 1)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Not Sector aligned\n"); return -EINVAL; } if (len != sector_size) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Only 1 Sector\n"); return -EINVAL; } /* Do not allow write past end of page */ if ((to + len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Attempted write past end of device\n"); return -EINVAL; } /* Shift to get page */ page = ((int) to) >> this->page_shift; /* Initialize return length value */ *retlen = 0; /* Select the NAND device */ nand_select(); /* Check the WP bit */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); if (!(this->read_data() & SMC_STAT_NOT_WP)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Device is write protected!!!\n"); ret = -EPERM; goto nand_write_err; } /* Loop until all data is written */ while (*retlen < len) { /* Send command to begin auto page programming */ nand_command(mtd, NAND_CMD_SEQIN, 0x00, page); this->hwcontrol(NAND_CTL_DAT_OUT); /* Write out complete page of data */ for (i = 0, cnt = 0; i < page_size; i++, cnt++) this->write_data(buf[(*retlen) + cnt]); /* Write ones for partial page programming */ for (i = 0; i < oob_size; i++) {#ifdef USE_256BYTE_NAND_FLASH if (*retlen & (sector_size -1)) this->write_data(ecc_code[SMC_OOB256_SIZE + i]); else#endif this->write_data(ecc_code[i]); } this->hwcontrol(NAND_CTL_DAT_IN); /* Send command to actually program the data */ nand_command(mtd, NAND_CMD_PAGEPROG, -1, -1); this->wait_for_ready(); /* * Wait for program operation to complete. This could * take up to 3000us (3ms) on some devices, so we try * and exit as quickly as possible */ status = 0; for (i = 0; i < 25; i++) { /* Delay for 125us */ udelay(125); /* Check the status */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); status = (int)this->read_data(); if (status & SMC_STAT_READY) break; } /* See if device thins it succeeded */ if (status & SMC_STAT_WRITE_ERR) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write, page 0x%08x, " \ "%6i bytes were succesful\n", page, *retlen); ret = -EIO; goto nand_write_err; }#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* * The NAND device assumes that it is always writing to * a cleanly erased page. Hence, it performs its internal * write verification only on bits tha transitioned from * 1 to 0. The device does NOT verify the whole page on a * byte by byte basis. It is possible that the page was * not completely erased or the page is becoming unusable * due to wear. The read with ECC would catch the error * later when the ECC page check fails, but we would rather * catch it early in the page write stage. Better to write * no data than invalid data. */ /* Send command to read back the page */#ifdef USE_256BYTE_NAND_FLASH if (*retlen & (sector_size - 1)) nand_command(mtd, NAND_CMD_READ0, 0x00, page + 1); else#endif nand_command(mtd, NAND_CMD_READ0, 0x00, page); this->wait_for_ready(); /* Loop through and verify the data */ for (i = 0; i < page_size; i++) { if (this->data_buf[i] != this->read_data()) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write verify, " \ "page 0x%08x, %6i bytes were succesful\n", page, *retlen); ret = -EIO; goto nand_write_err; } }#endif /* Update written bytes count */ *retlen += cnt; /* Increment page address */ page++; } *retlen = len; ret = 0;nand_write_err: /* De-select the NAND device */ nand_deselect(); return ret;}/* * NAND write out-of-band */static intnand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ int i, offset, page, status, ret; struct nand_chip *this = mtd->priv; DEBUG(MTD_DEBUG_LEVEL3, __FUNCTION__"(): to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); /* Shift to get page */ page = ((int)to) >> this->page_shift; /* Mask to get column */ offset = to & 0x1f; /* Initialize return length value */ *retlen = 0; /* Do not allow write past end of page */ if ((offset + len) > mtd->oobsize) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Attempt to write past end of page\n"); return -EINVAL; } /* Select the NAND device */ nand_select(); /* Check the WP bit */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); if (!(this->read_data() & SMC_STAT_NOT_WP)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Device is write protected!!!\n"); ret = -EPERM; goto nand_write_oob_err; } /* Write out desired data */ nand_command(mtd, NAND_CMD_SEQIN, offset + mtd->oobblock, page); this->hwcontrol(NAND_CTL_DAT_OUT); for (i = 0; i < len; i++) this->write_data(buf[i]); this->hwcontrol(NAND_CTL_DAT_IN); /* Send command to program the OOB data */ nand_command(mtd, NAND_CMD_PAGEPROG, -1, -1); this->wait_for_ready(); /* * Wait for program operation to complete. This could * take up to 3000us (3ms) on some devices, so we try * and exit as quickly as possible. */ status = 0; for (i = 0; i < 24; i++) { /* Delay for 125us */ udelay(125); /* Check the status */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); status = (int)this->read_data(); if (status & SMC_STAT_READY) break; } /* See if device thinks it succeeded */ if (status & SMC_STAT_WRITE_ERR) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write, page 0x%08x\n", page); ret = -EIO; goto nand_write_oob_err; }#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ nand_command(mtd, NAND_CMD_READOOB, offset, page); this->wait_for_ready(); /* Loop through and verify the data */ for (i = 0; i < len; i++) { if (buf[i] != this->read_data()) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write verify, page 0x%08x\n", page); ret = -EIO; goto nand_write_oob_err; } }#endif /* Return happy */ *retlen = len; ret = 0; nand_write_oob_err: /* De-select the NAND device */ nand_deselect(); return ret;}/* * NAND erase a block */static intnand_erase(struct mtd_info *mtd, struct erase_info *instr){ int i, page, len, status, pages_per_block; struct nand_chip *this = mtd->priv; DEBUG(MTD_DEBUG_LEVEL3, __FUNCTION__"(): start = 0x%08x, len = %i\n", (unsigned int)instr->addr, (unsigned int)instr->len); /* Start address must aligned on block boundary */ if (instr->addr & (mtd->erasesize - 1)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (instr->len & (mtd->erasesize - 1)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if ((instr->len + instr->addr) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Erase past end of device\n"); return -EINVAL; } /* Shift to get first page */ page = (int)(instr->addr >> this->page_shift); /* Calculate pages in each block */ pages_per_block = mtd->erasesize / mtd->oobblock; /* Select the NAND device */ nand_select(); /* Check the WP bit */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); if (!(this->read_data() & SMC_STAT_NOT_WP)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Device is write protected!!!\n"); nand_deselect(); return -EIO; } /* Loop through the pages */ len = instr->len; while (len) { /* Send commands to erase a page */ nand_command(mtd, NAND_CMD_ERASE1, -1, page); nand_command(mtd, NAND_CMD_ERASE2, -1, -1); this->wait_for_ready(); /* * Wait for program operation to complete. This could * take up to 4000us (4ms) on some devices, so we try * and exit as quickly as possible. */ status = 0; for (i = 0; i < 32; i++) { /* Delay for 125us */ udelay(125); /* Check the status */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); status = (int)this->read_data(); if (status & SMC_STAT_READY) break; } /* See if block erase succeeded */ if (status & SMC_STAT_WRITE_ERR) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed erase, page 0x%08x\n", page); nand_deselect();#if 0 instr->state = MTD_ERASE_FAILED; if (instr->callback) instr->callback(instr);#endif return -EIO; } /* Increment page address and decrement length */ len -= mtd->erasesize; page += pages_per_block; } /* De-select the NAND device */ nand_deselect();#if 0 /* Do call back function */ instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr);#endif /* Return happy */ return 0; }/* * Scan for the SMC device */intsmc_scan(struct mtd_info *mtd){ int i, nand_maf_id, nand_dev_id; struct nand_chip *this = mtd->priv; /* Select the device */ nand_select(); /* Send the command for reading device ID */ nand_command(mtd, NAND_CMD_READID, 0x00, -1); this->wait_for_ready(); /* Read manufacturer and device IDs */ nand_maf_id = this->read_data(); nand_dev_id = this->read_data(); /* Print and sotre flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (nand_maf_id == nand_flash_ids[i].manufacture_id && nand_dev_id == nand_flash_ids[i].model_id) {#ifdef USE_256BYTE_NAND_FLASH if (!mtd->size) { mtd->name = nand_flash_ids[i].name; mtd->erasesize = nand_flash_ids[i].erasesize; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; if (nand_flash_ids[i].page256) { mtd->oobblock = 256; mtd->oobsize = 8; this->page_shift = 8; } else { mtd->oobblock = 512; mtd->oobsize = 16; this->page_shift = 9; } this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; }#else if (!(mtd->size) && !(nand_flash_ids[i].page256)) { mtd->name = nand_flash_ids[i].name; mtd->erasesize = nand_flash_ids[i].erasesize; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; mtd->oobblock = 512; mtd->oobsize = 16; this->page_shift = 9; this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; }#endif printk("NAND device: Manufacture ID:" \ " 0x%02x, Chip ID: 0x%02x (%s)\n", nand_maf_id, nand_dev_id, mtd->name); break; } } /* De-select the device */ nand_deselect(); /* Print warning message for no device */ if (!mtd->size) { printk("No NAND device found!!!\n"); return 1; } /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; mtd->module = NULL; mtd->ecctype = MTD_ECC_SW; mtd->erase = nand_erase; mtd->point = NULL; mtd->unpoint = NULL; mtd->read = nand_read; mtd->write = nand_write; mtd->read_ecc = nand_read_ecc; mtd->write_ecc = nand_write_ecc; mtd->read_oob = nand_read_oob; mtd->write_oob = nand_write_oob; mtd->lock = NULL; mtd->unlock = NULL; /* Return happy */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -