首先看几个全局变量,这些全局变量记录了nand设备的信息,并提供了驱动操作接口。
本文是基于s5pv210的uboot撰写的,mtd框架是通用的,其他cpu也类似。
typedef struct mtd_info nand_info_t;//记住,nand_info_t 就是mtd_info 结构体
int nand_curr_device = -1;
nand_info_t nand_info[CFG_MAX_NAND_DEVICE];//CFG_MAX_NAND_DEVICE配置为1
static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];
看程序首先从入口看,无论是uboot还是linux内核,所有的设备(包括实际或抽象的)操作,必须注册该设备,也就是进行设备结构体初始化。
nand驱动的入口就是nand_init。
nand_init->
nand_init_chip->
board_nand_init(nand);//读nand id,初始化nand结构体 nand->ecc nand操作函数,如果是id = d5,默认8bitecc,如果没有匹配的nand id,默认1bitecc
if (nand_scan(mtd, 1) == 0) {
ret = nand_scan_ident(mtd, maxchips);
if (!ret)
ret = nand_scan_tail(mtd);
add_mtd_device,这一步很关键了,mtd->write怎么来的就看这里了。
s5pv210烧写uboot、logo、内核等分区使用8bitecc,只有烧写yaffs使用1bitecc(通过命令nand write.OEMyaffs)。
重新缕一下初始化流程:
先初始化nand_chip再初始化mtd(即nand_info),其中nand_init_chip
把nand_chip挂在mtd->priv指针上, board_nand_init负责初始化
nand_chip.ecc成员函数,nand_set_defaults(chip, busw);负责初始化mtd->priv(
nand_chip)的剩余其他成员/函数,
nand_scan_ident->nand_get_flash_type负责获取初始化部分mtd信息(大小、oobsize、writesize等),nand_scan_tail负责初始化mtd的第一层操作函数(
write_oob等)和chip的
write_page等函数。
带oob的读写操作:
oob操作通常是mtd_write_oob调用mtd->_write_oob或mtd->_read_oob函数,该函数读写页数据同时读写OOB。
nand_scan_tail函数初始化对_write_oob函数指针进行初始化:
mtd->write_oob = nand_write_oob;
nand_write_oob_>nand_do_write_oob
初始化完整路线是 nand_init->nand_init_chip -> nand_scan>nand_scan_tail
-
void nand_init(void)
-
{
-
int i;
-
unsigned int size = 0;
-
for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
-
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
-
size += nand_info[i].size;
-
if (nand_curr_device == -1)
-
nand_curr_device = i;
-
}
-
#ifndef CONFIG_DIS_BOARD_INFO
-
printf("%d MB ", size / (1024 * 1024));
-
-
#if defined(CFG_NAND_FLASH_BBT)
-
printf("(Flash Based BBT Enabled)");
-
#endif
-
-
printf("\n");
-
#endif /* CONFIG_DIS_BOARD_INFO */
-
#ifdef CFG_NAND_SELECT_DEVICE
-
/*
-
* Select the chip in the board/cpu specific driver
-
*/
-
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
-
#endif
-
}
-
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
-
ulong base_addr)
-
{
-
mtd->priv = nand;
-
-
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
-
board_nand_init(nand);
-
-
if (nand_scan(mtd, 1) == 0) {
-
if (!mtd->name)
-
mtd->name = (char *)default_nand_name;
-
-
#ifdef CONFIG_MTD_DEVICE
-
/*
-
* Add MTD device so that we can reference it later
-
* via the mtdcore infrastructure (e.g. ubi).
-
*/
-
mtd->name = dev_name;
-
add_mtd_device(mtd);
-
#endif
-
} else
-
mtd->name = NULL;
-
-
}
-
int nand_scan(struct mtd_info *mtd, int maxchips)
-
{
-
int ret;
-
-
#if 0
-
/* Many callers got this wrong, so check for it for a while... */
-
if (!mtd->owner && caller_is_module()) {
-
printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
-
BUG();
-
}
-
#endif
-
-
ret = nand_scan_ident(mtd, maxchips);
-
if (!ret)
-
ret = nand_scan_tail(mtd);
-
return ret;
-
}
nand_scan_ident负责扫描nand设备的id。
-
/**
-
* nand_scan_ident - [NAND Interface] Scan for the NAND device
-
* @mtd: MTD device structure
-
* @maxchips: Number of chips to scan for
-
*
-
* This is the first phase of the normal nand_scan() function. It
-
* reads the flash ID and sets up MTD fields accordingly.
-
*
-
* The mtd->owner field must be set to the module of the caller.
-
*/
-
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
-
{
-
int i, busw, nand_maf_id;
-
struct nand_chip *chip = mtd->priv;
-
struct nand_flash_dev *type;
-
-
/* Get buswidth to select the correct functions */
-
busw = chip->options & NAND_BUSWIDTH_16;
-
/* Set the default functions */
-
nand_set_defaults(chip, busw);
-
-
/* Read the flash type */
-
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
-
-
if (!type) {
-
// printk (KERN_WARNING "No NAND device found!!!\n");
-
chip->select_chip(mtd, -1);
-
return 1;
-
}
-
-
/* Check for a chip array */
-
for (i = 1; i < maxchips; i++) {
-
chip->select_chip(mtd, i);
-
/* Send the command for reading device ID */
-
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
/* Read manufacturer and device IDs */
-
if (nand_maf_id != chip->read_byte(mtd) ||
-
type->id != chip->read_byte(mtd))
-
break;
-
}
-
if (i > 1)
-
printk(KERN_INFO "%d NAND chips detected\n", i);
-
-
/* Store the number of chips and calc total size for mtd */
-
chip->numchips = i;
-
mtd->size = i * chip->chipsize;
-
-
return 0;
-
}
nand_scan_tail用于检查mtd操作函数,如果之前在board_nand_init函数中没有初始化nand操作接口指针,则在会使用默认函数初始化nand操作指针。最后扫描坏块。
-
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: Number of chips to scan for
*
* This is the second phase of the normal nand_scan() function. It
* fills out all the uninitialized function pointers with the defaults
* and scans for a bad block table if appropriate.
*/
-
int nand_scan_tail(struct mtd_info *mtd)
-
{
-
int i;
-
struct nand_chip *chip = mtd->priv;
-
-
if (!(chip->options & NAND_OWN_BUFFERS))
-
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
-
if (!chip->buffers)
-
return -ENOMEM;
-
-
/* Set the internal oob buffer location, just after the page data */
-
chip->oob_poi = chip->buffers->databuf + mtd->writesize;
-
-
/*
-
* If no default placement scheme is given, select an appropriate one
-
*/
-
if (!chip->ecc.layout) {
-
switch (mtd->oobsize) {
-
case 8:
-
chip->ecc.layout = &nand_oob_8;
-
break;
-
case 16:
-
chip->ecc.layout = &nand_oob_16;
-
break;
-
case 64:
-
chip->ecc.layout = &nand_oob_64;
-
break;
-
case 128:
-
chip->ecc.layout = &nand_oob_128;
-
break;
-
case 218:
-
chip->ecc.layout = &nand_oob_218;
-
break;
-
default:
-
printk(KERN_WARNING "No oob scheme defined for "
-
"oobsize %d\n", mtd->oobsize);
-
BUG();
-
}
-
}
-
-
if (!chip->write_page)
-
chip->write_page = nand_write_page;
-
-
/*
-
* check ECC mode, default to software if 3byte/512byte hardware ECC is
-
* selected and we have 256 byte pagesize fallback to software ECC
-
*/
-
if (!chip->ecc.read_page_raw)
-
chip->ecc.read_page_raw = nand_read_page_raw;
-
if (!chip->ecc.write_page_raw)
-
chip->ecc.write_page_raw = nand_write_page_raw;
-
-
switch (chip->ecc.mode) {
-
case NAND_ECC_HW:
-
/* Use standard hwecc read page function ? */
-
if (!chip->ecc.read_page)
-
chip->ecc.read_page = nand_read_page_hwecc;
-
if (!chip->ecc.write_page)
-
chip->ecc.write_page = nand_write_page_hwecc;
-
if (!chip->ecc.read_oob)
-
chip->ecc.read_oob = nand_read_oob_std;
-
if (!chip->ecc.write_oob)
-
chip->ecc.write_oob = nand_write_oob_std;
-
-
case NAND_ECC_HW_SYNDROME:
-
if (!chip->ecc.calculate || !chip->ecc.correct ||
-
!chip->ecc.hwctl) {
-
printk(KERN_WARNING "No ECC functions supplied, "
-
"Hardware ECC not possible\n");
-
BUG();
-
}
-
/* Use standard syndrome read/write page function ? */
-
if (!chip->ecc.read_page)
-
chip->ecc.read_page = nand_read_page_syndrome;
-
if (!chip->ecc.write_page)
-
chip->ecc.write_page = nand_write_page_syndrome;
-
if (!chip->ecc.read_oob)
-
chip->ecc.read_oob = nand_read_oob_syndrome;
-
if (!chip->ecc.write_oob)
-
chip->ecc.write_oob = nand_write_oob_syndrome;
-
-
if (mtd->writesize >= chip->ecc.size)
-
break;
-
printk(KERN_WARNING "%d byte HW ECC not possible on "
-
"%d byte page size, fallback to SW ECC\n",
-
chip->ecc.size, mtd->writesize);
-
chip->ecc.mode = NAND_ECC_SOFT;
-
-
case NAND_ECC_SOFT:
-
chip->ecc.calculate = nand_calculate_ecc;
-
chip->ecc.correct = nand_correct_data;
-
chip->ecc.read_page = nand_read_page_swecc;
-
chip->ecc.write_page = nand_write_page_swecc;
-
chip->ecc.read_oob = nand_read_oob_std;
-
chip->ecc.write_oob = nand_write_oob_std;
-
chip->ecc.size = 256;
-
chip->ecc.bytes = 3;
-
break;
-
-
case NAND_ECC_NONE:
-
printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
-
"This is not recommended !!\n");
-
chip->ecc.read_page = nand_read_page_raw;
-
chip->ecc.write_page = nand_write_page_raw;
-
chip->ecc.read_oob = nand_read_oob_std;
-
chip->ecc.write_oob = nand_write_oob_std;
-
chip->ecc.size = mtd->writesize;
-
chip->ecc.bytes = 0;
-
break;
-
-
default:
-
printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
-
chip->ecc.mode);
-
BUG();
-
}
-
-
/*
-
* The number of bytes available for a client to place data into
-
* the out of band area
-
*/
-
chip->ecc.layout->oobavail = 0;
-
for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
-
chip->ecc.layout->oobavail +=
-
chip->ecc.layout->oobfree[i].length;
-
-
/*
-
* Set the number of read / write steps for one page depending on ECC
-
* mode
-
*/
-
chip->ecc.steps = mtd->writesize / chip->ecc.size;
-
if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
-
printk(KERN_WARNING "Invalid ecc parameters\n");
-
BUG();
-
}
-
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
-
-
/*
-
* Allow subpage writes up to ecc.steps. Not possible for MLC
-
* FLASH.
-
*/
-
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
-
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
-
switch(chip->ecc.steps) {
-
case 2:
-
mtd->subpage_sft = 1;
-
break;
-
case 4:
-
case 8:
-
mtd->subpage_sft = 2;
-
break;
-
}
-
}
-
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
-
-
/* XXX U-BOOT XXX */
-
#if 0
-
/* Initialize state */
-
chip->state = FL_READY;
-
#endif
-
-
/* De-select the device */
-
chip->select_chip(mtd, -1);
-
-
/* Invalidate the pagebuffer reference */
-
chip->pagebuf = -1;
-
-
/* Fill in remaining MTD driver data */
-
mtd->type = MTD_NANDFLASH;
-
mtd->flags = MTD_CAP_NANDFLASH;
-
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_oob = nand_read_oob;
-
mtd->write_oob = nand_write_oob;
-
mtd->sync = nand_sync;
-
mtd->lock = NULL;
-
mtd->unlock = NULL;
-
mtd->suspend = nand_suspend;
-
mtd->resume = nand_resume;
-
mtd->block_isbad = nand_block_isbad;
-
mtd->block_markbad = nand_block_markbad;
-
-
/* propagate ecc.layout to mtd_info */
-
mtd->ecclayout = chip->ecc.layout;
-
-
/* Check, if we should skip the bad block table scan */
-
if (chip->options & NAND_SKIP_BBTSCAN)
-
return 0;
-
-
/* Build bad block table */
-
return chip->scan_bbt(mtd);
-
}
烧写uboot、logo、内核等分区使用8bitecc,只有烧写yaffs使用1bitecc(tftp烧写通过nand write.yaffs,SD卡烧写通过命令nand write.OEMyaffs)。
-
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-
const uint8_t *buf, int page, int cached, int raw)
-
{
-
int status;
-
-
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
-
/* jsgood: org: #else block only */
-
#if defined(CONFIG_NAND_BL1_8BIT_ECC) && \
-
(defined(CONFIG_S3C6430) || \
-
defined(CONFIG_S3C2450) || \
-
defined(CONFIG_S3C2416) || \
-
defined(CONFIG_S5PC100) || \
-
defined(CONFIG_S5PC110) || \
-
defined(CONFIG_S5PV210) || \
-
defined(CONFIG_S5P6440))
-
#ifdef CONFIG_TQ210
-
if ((mtd->writesize == 512 && page < 512) || (mtd->writesize == 2048 && page < 256) ||
-
(mtd->writesize == 4096 && page < 128)) {
-
#else
-
if (page < CFG_NAND_PAGES_IN_BLOCK) {
-
#endif
-
memset(chip->oob_poi, 0xff, mtd->oobsize);
-
s3c_nand_write_page_8bit(mtd, chip, buf);//烧写bootloader
-
} else
-
#elif defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S3C6410)
-
if (page < CFG_NAND_PAGES_IN_BLOCK) {
-
memset(chip->oob_poi, 0xff, mtd->oobsize);
-
s3c_nand_write_page_8bit_for_irom(mtd, chip, buf);
-
} else
-
#endif
-
{
-
if (unlikely(raw))
-
chip->ecc.write_page_raw(mtd, chip, buf);
-
else
-
chip->ecc.write_page(mtd, chip, buf);//烧写其他分区使用1bitecc
-
}
实际上烧写u-boot是使用nand_block_write这个函数烧写的。
-
//nand_block_write is used to write u-boot
-
int nand_block_write(struct mtd_info *mtd, loff_t to, size_t len,
-
size_t *retlen, const u_char * buf)
-
{
-
struct nand_chip *this = mtd->priv;
-
int eraseshift = this->phys_erase_shift;
-
int blocks = len >> eraseshift;
-
int blocksize = (1 << eraseshift);
-
loff_t ofs;
-
size_t _retlen = 0;
-
int ret;
-
#if (defined(CONFIG_S5PC110) || defined(CONFIG_S5PV210)) && defined(CONFIG_EVT1) && !defined(CONFIG_FUSED) && !defined(CONFIG_SECURE)
-
int i;
-
ulong checksum;
-
uint8_t *ptr;
-
#endif
-
-
ofs = to;
-
-
if (ofs & (blocksize - 1)) {
-
printk(" ERROR: Starting address 0x%x is not a block start address\n",
-
(unsigned int) ofs);
-
return 1;
-
}
-
if (len & (blocksize - 1)) {
-
printk(" ERROR: Length (0x%x) is not block aligned\n", (unsigned int) len);
-
return 1;
-
}
-
printk("Main area read (%d blocks):\n", blocks);
-
-
#if (defined(CONFIG_S5PC110) || defined(CONFIG_S5PV210)) && defined(CONFIG_EVT1) && !defined(CONFIG_FUSED) && !defined(CONFIG_SECURE)
-
if (to == 0) {
-
ptr = buf + 16;
-
for(i = 16, checksum = 0; i < 8192; i++) {
-
checksum += *ptr;
-
ptr++;
-
}
-
*((volatile u32 *)(buf + 0x8)) = checksum;
-
printk("Checksum is calculated.\n");
-
}
-
-
#endif
-
printk("Main area write (%d blocks):\n", blocks);
-
*retlen = 0;
-
-
while (blocks) {
-
ret = mtd->block_isbad(mtd, ofs);
-
if (ret) {
-
printk("Bad blocks %d at 0x%x is skipped\n",
-
(u32)(ofs >> eraseshift), (u32)ofs);
-
goto next;
-
}
-
-
ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
-
if (ret) {
-
printk("Write failed 0x%x, %d", (u32)ofs, ret);
-
goto next;
-
}
-
-
buf += blocksize;
-
blocks--;
-
*retlen += _retlen;
-
next:
-
ofs += blocksize;
-
}
-
-
return 0;
-
}
注意ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
为什么mtd->write就是8bitecc烧写?这就回头看当初注册mtd的代码了。
在nand_scan_tail函数最后有一句 mtd->write = nand_write;
nand_write调用nand_do_write_ops
-
/**
-
* nand_do_write_ops - [Internal] NAND write with ECC
-
* @mtd: MTD device structure
-
* @to: offset to write to
-
* @ops: oob operations description structure
-
*
-
* NAND write with ECC
-
*/
-
static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
-
struct mtd_oob_ops *ops)
-
{
-
int chipnr, realpage, page, blockmask, column;
-
struct nand_chip *chip = mtd->priv;
-
uint32_t writelen = ops->len;
-
uint8_t *oob = ops->oobbuf;
-
uint8_t *buf = ops->datbuf;
-
int ret, subpage;
-
#if 0
-
/* jsgood */
-
int percent = 0;
-
int percent_complete = 0;
-
#endif
-
ops->retlen = 0;
-
if (!writelen)
-
return 0;
-
-
/* reject writes, which are not page aligned */
-
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
-
printk(KERN_NOTICE "nand_write: "
-
"Attempt to write not page aligned data\n");
-
return -EINVAL;
-
}
-
-
column = to & (mtd->writesize - 1);
-
subpage = column || (writelen & (mtd->writesize - 1));
-
-
if (subpage && oob)
-
return -EINVAL;
-
-
chipnr = (int)(to >> chip->chip_shift);
-
chip->select_chip(mtd, chipnr);
-
-
/* Check, if it is write protected */
-
if (nand_check_wp(mtd))
-
return -EIO;
-
-
realpage = (int)(to >> chip->page_shift);
-
page = realpage & chip->pagemask;
-
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
-
-
/* Invalidate the page cache, when we write to the cached page */
-
if (to <= (chip->pagebuf << chip->page_shift) &&
-
(chip->pagebuf << chip->page_shift) < (to + ops->len))
-
chip->pagebuf = -1;
-
-
/* If we're not given explicit OOB data, let it be 0xFF */
-
if (likely(!oob))
-
memset(chip->oob_poi, 0xff, mtd->oobsize);
-
-
while(1) {
-
int bytes = mtd->writesize;
-
int cached = writelen > bytes && page != blockmask;
-
uint8_t *wbuf = buf;
-
-
/* Partial page write ? */
-
if (unlikely(column || writelen < (mtd->writesize - 1))) {
-
cached = 0;
-
bytes = min_t(int, bytes - column, (int) writelen);
-
chip->pagebuf = -1;
-
memset(chip->buffers->databuf, 0xff, mtd->writesize);
-
memcpy(&chip->buffers->databuf[column], buf, bytes);
-
wbuf = chip->buffers->databuf;
-
}
-
-
if (unlikely(oob))
-
oob = nand_fill_oob(chip, oob, ops);
-
-
ret = chip->write_page(mtd, chip, wbuf, page, cached,
-
(ops->mode == MTD_OOB_RAW));
-
if (ret)
-
break;
-
-
writelen -= bytes;
-
#if 0
-
/* jsgood */
-
percent = ((ops->len - writelen) * 100) / ops->len;
-
-
if (percent != percent_complete) {
-
printf("\rWriting page at 0x%x -- %d%% complete.", page, percent);
-
percent_complete = percent;
-
}
-
#endif
-
if (!writelen)
-
break;
-
-
column = 0;
-
buf += bytes;
-
realpage++;
-
-
page = realpage & chip->pagemask;
-
/* Check, if we cross a chip boundary */
-
if (!page) {
-
chipnr++;
-
chip->select_chip(mtd, -1);
-
chip->select_chip(mtd, chipnr);
-
}
-
}
-
-
#if 0
-
/* jsgood */
-
printf("\n");
-
#endif
-
ops->retlen = ops->len - writelen;
-
if (unlikely(oob))
-
ops->oobretlen = ops->ooblen;
-
return ret;
-
}
最后调用了chip->write_page
nand_scan_tail函数中有一句:
-
if (!chip->write_page)
-
{
-
puts("chip->write_page = nand_write_page\n");//richard
-
chip->write_page = nand_write_page;}
-
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-
const uint8_t *buf, int page, int cached, int raw)
-
{
-
int status;
-
-
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
-
/* jsgood: org: #else block only */
-
#if defined(CONFIG_NAND_BL1_8BIT_ECC) && \
-
(defined(CONFIG_S3C6430) || \
-
defined(CONFIG_S3C2450) || \
-
defined(CONFIG_S3C2416) || \
-
defined(CONFIG_S5PC100) || \
-
defined(CONFIG_S5PC110) || \
-
defined(CONFIG_S5PV210) || \
-
defined(CONFIG_S5P6440))
-
#ifdef CONFIG_TQ210
-
if ((mtd->writesize == 512 && page < 512) || (mtd->writesize == 2048 && page < 256) ||
-
(mtd->writesize == 4096 && page < 128)) {
-
#else
-
if (page < CFG_NAND_PAGES_IN_BLOCK) {
-
#endif
-
memset(chip->oob_poi, 0xff, mtd->oobsize);
-
s3c_nand_write_page_8bit(mtd, chip, buf);
-
} else
-
#elif defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S3C6410)
-
if (page < CFG_NAND_PAGES_IN_BLOCK) {
-
memset(chip->oob_poi, 0xff, mtd->oobsize);
-
s3c_nand_write_page_8bit_for_irom(mtd, chip, buf);
-
} else
-
#endif
-
{
-
if (unlikely(raw))
-
chip->ecc.write_page_raw(mtd, chip, buf);
-
else
-
chip->ecc.write_page(mtd, chip, buf);
-
}
-
-
/*
-
* Cached progamming disabled for now, Not sure if its worth the
-
* trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
-
*/
-
cached = 0;
-
-
if (!cached || !(chip->options & NAND_CACHEPRG)) {
-
-
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-
status = chip->waitfunc(mtd, chip);
-
/*
-
* See if operation failed and additional status checks are
-
* available
-
*/
-
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-
status = chip->errstat(mtd, chip, FL_WRITING, status,
-
page);
-
-
if (status & NAND_STATUS_FAIL)
-
return -EIO;
-
} else {
-
chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
-
status = chip->waitfunc(mtd, chip);
-
}
-
-
#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-
/* Send command to read back the data */
-
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
-
if (chip->verify_buf(mtd, buf, mtd->writesize))
-
return -EIO;
-
#endif
-
return 0;
-
}
这样就明白了,chip->write_page使用8bitecc,chip->ecc.write_page使用1bitecc。
mtd->write也就是调用chip->write_page使用8bitecc烧写。
另外mtd->write_oob就是执行nand_write_oob->
if (!ops->datbuf)
ret = nand_do_write_oob(mtd, to, ops);
else
ret = nand_do_write_ops(mtd, to, ops);
-
static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
-
struct mtd_oob_ops *ops)
-
{
-
int chipnr, realpage, page, blockmask, column;
-
struct nand_chip *chip = mtd->priv;
-
uint32_t writelen = ops->len;
-
uint8_t *oob = ops->oobbuf;
-
uint8_t *buf = ops->datbuf;
-
int ret, subpage;
-
#if 0
-
/* jsgood */
-
int percent = 0;
-
int percent_complete = 0;
-
#endif
-
ops->retlen = 0;
-
if (!writelen)
-
return 0;
-
-
/* reject writes, which are not page aligned */
-
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
-
printk(KERN_NOTICE "nand_write: "
-
"Attempt to write not page aligned data\n");
-
return -EINVAL;
-
}
-
-
column = to & (mtd->writesize - 1);
-
subpage = column || (writelen & (mtd->writesize - 1));
-
-
if (subpage && oob)
-
return -EINVAL;
-
-
chipnr = (int)(to >> chip->chip_shift);
-
chip->select_chip(mtd, chipnr);
-
-
/* Check, if it is write protected */
-
if (nand_check_wp(mtd))
-
return -EIO;
-
-
realpage = (int)(to >> chip->page_shift);
-
page = realpage & chip->pagemask;
-
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
-
-
/* Invalidate the page cache, when we write to the cached page */
-
if (to <= (chip->pagebuf << chip->page_shift) &&
-
(chip->pagebuf << chip->page_shift) < (to + ops->len))
-
chip->pagebuf = -1;
-
-
/* If we're not given explicit OOB data, let it be 0xFF */
-
if (likely(!oob))
-
memset(chip->oob_poi, 0xff, mtd->oobsize);
-
-
while(1) {
-
int bytes = mtd->writesize;
-
int cached = writelen > bytes && page != blockmask;
-
uint8_t *wbuf = buf;
-
-
/* Partial page write ? */
-
if (unlikely(column || writelen < (mtd->writesize - 1))) {
-
cached = 0;
-
bytes = min_t(int, bytes - column, (int) writelen);
-
chip->pagebuf = -1;
-
memset(chip->buffers->databuf, 0xff, mtd->writesize);
-
memcpy(&chip->buffers->databuf[column], buf, bytes);
-
wbuf = chip->buffers->databuf;
-
}
-
-
if (unlikely(oob))
-
oob = nand_fill_oob(chip, oob, ops);
-
-
ret = chip->write_page(mtd, chip, wbuf, page, cached,
-
(ops->mode == MTD_OOB_RAW));
-
if (ret)
-
break;
-
-
writelen -= bytes;
-
#if 0
-
/* jsgood */
-
percent = ((ops->len - writelen) * 100) / ops->len;
-
-
if (percent != percent_complete) {
-
printf("\rWriting page at 0x%x -- %d%% complete.", page, percent);
-
percent_complete = percent;
-
}
-
#endif
-
if (!writelen)
-
break;
-
-
column = 0;
-
buf += bytes;
-
realpage++;
-
-
page = realpage & chip->pagemask;
-
/* Check, if we cross a chip boundary */
-
if (!page) {
-
chipnr++;
-
chip->select_chip(mtd, -1);
-
chip->select_chip(mtd, chipnr);
-
}
-
}
-
-
#if 0
-
/* jsgood */
-
printf("\n");
-
#endif
-
ops->retlen = ops->len - writelen;
-
if (unlikely(oob))
-
ops->oobretlen = ops->ooblen;
-
return ret;
-
}
总结:
烧写boot、内核采用8bitecc,流程:
mtd->write > nand_write > nand_do_write_ops > chip->write_page > chip->write_page > s3c_nand_write_page_8bit(mtd, chip, buf);
烧写yaffs镜像采用1bitecc,流程:
nand_OEM_write_opts(nand, &opts,Dir) > meminfo->write_oob >
nand_write_oob->
if (!ops->datbuf)
ret = nand_do_write_oob(mtd, to, ops);
else
ret = nand_do_write_ops(mtd, to, ops);
nand_do_write_ops > chip->write_page >
chip->write_page使用8bitecc,chip->ecc.write_page使用1bitecc。
mtd->write也就是调用chip->write_page使用8bitecc烧写。
烧写函数选择:
在源数据不包含OOB的情况下使用mtd->write即nand_write函数,在源数据含有OOB(yaffs镜像)的情况下使用write_oob即nand_write_oob函数
阅读(2534) | 评论(0) | 转发(0) |