/*
* NAND write
*/
static int
nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
int i, page, col, cnt, status;
struct nand_chip *this = mtd->priv;
DEBUG(MTD_DEBUG_LEVEL3,
__FUNCTION__"(): to = 0x%08x, len = %i\n", (unsigned int)to,
(int) len);
//不可越界
/* 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;
//获取低八位的值,(页中的地址)
/* Get the starting column */
col = to & (mtd->oobblock - 1);
/* 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();
//如果被保护,则直接跳转到nand_write_exit()函数
if (!(this->read_data() & SMC_STAT_NOT_WP)) {
DEBUG(MTD_DEBUG_LEVEL0,
__FUNCTION__"(): Device is write protected!!!\n");
i = -EPERM;
goto nand_write_exit;
}
/* Loop until all data is written */
while (*retlen < len) {
/* Write data into buffer */
//将数据写入到this->data_buf中,并按相应位保存,因为我们采用的是512字节的 // 页面,因此数据不可超过512。
/****************************************************
*首先将我们需要写入的数据放在struct nand_chip结构的数据还存取中
*然后将不需要的数据全部写入0xff,在完成了数据的第一步缓存以后将数据依次写
*nand flash中的区域
/******************************************************
if ((col + len) >= mtd->oobblock)
for (i = col, cnt = 0; i < mtd->oobblock; i++, cnt++)
this->data_buf[i] = buf[(*retlen + cnt)];
else
for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++)
this->data_buf[i] = buf[(*retlen + cnt)];
/* Write ones for partial page programming */
for (i = mtd->oobblock; i < (mtd->oobblock + mtd->oobsize); i++)
this->data_buf[i] = 0xff;
/* Write pre-padding bytes into buffer */
for (i = 0; i < col; i++)
this->data_buf[i] = 0xff;
/* Write post-padding bytes into buffer */
if ((col + (len - *retlen)) < mtd->oobblock) {
for (i = (col + cnt); i < mtd->oobblock; i++)
this->data_buf[i] = 0xff;
}
/* Send command to begin auto page programming */
nand_command(mtd, NAND_CMD_SEQIN, 0x00, page);
/* Write out complete page of data */
this->hwcontrol(NAND_CTL_DAT_OUT); //无效
for (i = 0; i < (mtd->oobblock + mtd->oobsize); i++)
this->write_data(this->data_buf[i]);
this->hwcontrol(NAND_CTL_DAT_IN); //无效
/* Send command to actually program the data */
//写入命令0x10,参照上面的流程图,也就是第5步
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 for status */
nand_command(mtd, NAND_CMD_STATUS, -1, -1);
status = (int)this->read_data();
if (status & SMC_STAT_READY)
break;
}
/* See if device thinks it succeeded */
//检查状态寄存器的bit[0]1则说明有错误,0为成功
if (status & SMC_STAT_WRITE_ERR) {
DEBUG(MTD_DEBUG_LEVEL0,
__FUNCTION__"(): Failed write, page 0x%08x, " \
"%6i bytes were sucesful\n", page, *retlen);
i = -EIO;
goto nand_write_exit;
}
#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;
}
|