📄 smc_core.c
字号:
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 */ this->cmdfunc(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 */ this->cmdfunc(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)) this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page + 1); else#endif this->cmdfunc(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]*/buf[(*retlen) + 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 */ this->cmdfunc(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 */ this->cmdfunc(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 */ this->cmdfunc(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 */ this->cmdfunc(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 */ this->cmdfunc(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; size_t retlen; char oobbuf[16]; 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; } memset(oobbuf,0,sizeof(oobbuf)); /* 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 */ this->cmdfunc(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 */ this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); this->cmdfunc(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 */ this->cmdfunc(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 DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed erase, page 0x%08x\n", page); nand_write_oob(mtd,page<<this->page_shift,16,&retlen,oobbuf); /* Select the NAND device */ nand_select(); //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; //if (!(this->cmdfunc)) this->cmdfunc = nand_command; /* Select the device */#if defined(CONFIG_ARCH_S3C2410) nand_select();#elif defined(CONFIG_ARCH_S3C2440) this->hwcontrol(NAND_CTL_SETNCE); this->hwcontrol(NAND_CTL_CLRRnB); #endif /* Send the command for reading device ID */ nand_command(mtd, NAND_CMD_READID, 0x00, -1);#if defined(CONFIG_ARCH_S3C2410) this->wait_for_ready();#elif defined(CONFIG_ARCH_S3C2440) for (i = 0; i<100 ;i++);#endif /* Read manufacturer and device IDs */ nand_maf_id = this->read_data(); nand_dev_id = this->read_data(); //printk("Get NAND device: Manufacture ID:" // " 0x%02x, Chip ID: 0x%02x\n", // nand_maf_id, nand_dev_id); /* 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].dev_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].pagesize == PAGESIZE256) { 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 (!(nand_flash_ids[i].pagesize)) { int extid; /* The 3rd id byte contains non relevant data ATM */ extid = this->read_data(); /* The 4th id byte is the important one */ extid = this->read_data(); /* Calc pagesize */ mtd->oobblock = 1024 << (extid & 0x3); extid >>= 2; /* Calc oobsize */ mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ //busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; mtd->name = nand_flash_ids[i].name; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; this->page_shift = 11; this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; } else if (!(mtd->size) && !(nand_flash_ids[i].pagesize == PAGESIZE256)) { 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 /* Do not replace user supplied command function ! */ if ((mtd->oobblock>512) && (this->cmdfunc == nand_command)) this->cmdfunc = nand_command_lp; 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 + -