在上一篇mtd框架中我们真正的东西并不多,也就是明白到底当我们看/dev/mtd0 /dev/mtdblock0 为什么会一样的效果. 理清了它们之间的关系.这里我们就nand flash驱动代码和mtd框架是如何结合的.
话不多说了,从初始化代码我们来分析:
-
int __init XXX_nand_init(void)
-
{
-
struct nand_chip *this;
-
int err = 0;
-
int num_of_parts = 0;
-
const char *part_type = 0;
-
struct mtd_partition *mtd_parts = 0;
-
u32 physaddr;
-
int nand_dev_num;
-
MV_CPU_DEC_WIN addr_win;
-
...
-
-
physaddr = addr_win.addrWin.baseLow;
-
-
mv_mtd = kmalloc(sizeof(struct mtd_info)+sizeof(struct nand_chip), GFP_KERNEL);
-
if (!mv_mtd) {
-
printk(KERN_INFO "Failed to allocate NAND MTD structuren");
-
err = -ENOMEM;
-
goto out;
-
}
-
-
memset((char *)mv_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip));
-
-
baseaddr = (unsigned long)ioremap(physaddr, 1024);
-
if (!baseaddr) {
-
printk(KERN_INFO "Failed to remap NAND MTDn");
-
err = -EIO;
-
goto out_mtd;
-
}
-
-
this = (struct nand_chip *)((char *)mv_mtd+sizeof(struct mtd_info));
-
mv_mtd->priv = this;
-
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)baseaddr;
-
this->cmd_ctrl = board_hwcontrol;
-
#ifdef CONFIG_MTD_NAND_LNC_8BYTE_READ
-
this->read_buf = mv_nand_read_buf;
-
#endif
-
-
this->ecc.mode = NAND_ECC_NONE;
-
-
this->chip_delay = 100;
-
if (nand_scan(mv_mtd, 1)) {
-
err = -ENXIO;
-
goto out_ior;
-
}
-
-
#ifdef CONFIG_MTD_PARTITIONS
-
mv_mtd->name = "nand_mtd";
-
num_of_parts = parse_mtd_partitions(mv_mtd, part_probes, &mtd_parts, 0, "");
-
if (num_of_parts > 0)
-
part_type = "command line";
-
else
-
num_of_parts = 0;
-
if (num_of_parts == 0) {
-
mtd_parts = nand_parts_info;
-
num_of_parts = MV_NUM_OF_NAND_PARTS;
-
part_type = "static";
-
}
-
-
printk(KERN_INFO "Using %s partition definitionn", part_type);
-
add_mtd_partitions(mv_mtd, mtd_parts, num_of_parts);
-
#endif
-
goto out;
-
-
out_ior:
-
iounmap((void *)baseaddr);
-
out_mtd:
-
kfree(mv_mtd);
-
out:
-
return err;
-
}
这里是硬件驱动的一个框架,关键部分黑体表示.
我们来看这一行:
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)baseaddr;
这里的IO地址表示的nand flash映射的reg地址,直接操作即可操作nandflash控制器,进而操作nandflash存储芯片.
具体的时序操作控制我们这里看到: this
->cmd_ctrl
= board_hwcontrol;
-
static void board_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-
{
-
struct nand_chip *this = (struct nand_chip *)mtd->priv;
-
if (ctrl & NAND_CTRL_CHANGE) {
-
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~3);
-
ctrl &= ~NAND_CTRL_CHANGE;
-
switch (ctrl) {
-
case NAND_CTRL_CLE:
-
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | 1); /*x8=>1, x16=>2*/
-
break;
-
case NAND_CTRL_ALE:
-
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | 2); /*x8=>2, x16=>4*/
-
break;
-
}
-
}
-
if (cmd != NAND_CMD_NONE)
-
writeb(cmd, this->IO_ADDR_W);
-
}
其实就是根据nand flash时序的操作过程,来对io地址来进行不同的写值操作. 后面我们还很多函数用到它.
这里我们发现的是mv_mtd是如何初始化的呢? 包括struct nand_chip this;我们继续往后面看nand_scan函数
-
/**
-
* nand_scan - [NAND Interface] Scan for the NAND device
-
* @mtd: MTD device structure
-
* @maxchips: Number of chips to scan for
-
*
-
* This fills out all the uninitialized function pointers
-
* with the defaults.
-
* The flash ID is read and the mtd/chip structures are
-
* filled with the appropriate values.
-
* The mtd->owner field must be set to the module of the caller
-
*
-
*/
-
int nand_scan(struct mtd_info *mtd, int maxchips)
-
{
-
int ret;
-
-
/* Many callers got this wrong, so check for it for a while... */
-
if (!mtd->owner && caller_is_module()) {
-
printk(KERN_CRIT "%s called with NULL mtd->owner!n",
-
__func__);
-
BUG();
-
}
-
-
ret = nand_scan_ident(mtd, maxchips);
-
if (!ret)
-
ret = nand_scan_tail(mtd);
-
return ret;
-
}
这个函数是在nand_base.c中实现的,它包含了两个重要的函数:
-
/**
-
* 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 (IS_ERR(type)) {
-
printk(KERN_WARNING "No NAND device found!!!n");
-
chip->select_chip(mtd, -1);
-
return PTR_ERR(type);
-
}
-
-
/* Check for a chip array */
-
for (i = 1; i < maxchips; i++) {
-
chip->select_chip(mtd, i);
-
/* See comment in nand_get_flash_type for reset */
-
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
/* 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 detectedn", i);
-
-
/* Store the number of chips and calc total size for mtd */
-
chip->numchips = i;
-
mtd->size = i * chip->chipsize;
-
-
return 0;
-
}
这里我们看粗体部分的它们是在什么地方初始化的呢?
我们忽略了代码开始的一个函数:
nand_set_defaults(chip, busw);
-
/*
-
* Set default functions
-
*/
-
static void nand_set_defaults(struct nand_chip *chip, int busw)
-
{
-
/* check for proper chip_delay setup, set 20us if not */
-
if (!chip->chip_delay)
-
chip->chip_delay = 20;
-
-
/* check, if a user supplied command function given */
-
if (chip->cmdfunc == NULL)
-
chip->cmdfunc = nand_command;
-
-
/* check, if a user supplied wait function given */
-
if (chip->waitfunc == NULL)
-
chip->waitfunc = nand_wait;
-
-
if (!chip->select_chip)
-
chip->select_chip = nand_select_chip;
-
if (!chip->read_byte)
-
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
-
if (!chip->read_word)
-
chip->read_word = nand_read_word;
-
if (!chip->block_bad)
-
chip->block_bad = nand_block_bad;
-
if (!chip->block_markbad)
-
chip->block_markbad = nand_default_block_markbad;
-
if (!chip->write_buf)
-
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
-
if (!chip->read_buf)
-
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
-
if (!chip->verify_buf)
-
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
-
if (!chip->scan_bbt)
-
chip->scan_bbt = nand_default_bbt;
-
-
if (!chip->controller) {
-
chip->controller = &chip->hwcontrol;
-
spin_lock_init(&chip->controller->lock);
-
init_waitqueue_head(&chip->controller->wq);
-
}
-
-
}
我们看到它们的默认初始化:
chip
->cmdfunc = nand_command;
chip
->select_chip = nand_select_chip;
chip
->read_byte = busw ? nand_read_byte16 : nand_read_byte;
... 这里我们不在一一列出.
我们明显看出它们初始化的函数都在mtd框架里的实现的函数,似乎和真正的nand flash驱动没有什么关系,它们是如何真正运作的呢?
我们那nand_command来做简单的分析,就会明白了.
-
/**
-
* nand_command - [DEFAULT] Send command to NAND device
-
* @mtd: MTD device structure
-
* @command: the command to be sent
-
* @column: the column address for this command, -1 if none
-
* @page_addr: the page address for this command, -1 if none
-
*
-
* Send command to NAND device. This function is used for small page
-
* devices (256/512 Bytes per page)
-
*/
-
static void nand_command(struct mtd_info *mtd, unsigned int command,
-
int column, int page_addr)
-
{
-
register struct nand_chip *chip = mtd->priv;
-
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
-
-
/*
-
* Write out the command to the device.
-
*/
-
if (command == NAND_CMD_SEQIN) {
-
int readcmd;
-
-
if (column >= mtd->writesize) {
-
/* OOB area */
-
column -= mtd->writesize;
-
readcmd = NAND_CMD_READOOB;
-
} else if (column < 256) {
-
/* First 256 bytes --> READ0 */
-
readcmd = NAND_CMD_READ0;
-
} else {
-
column -= 256;
-
readcmd = NAND_CMD_READ1;
-
}
-
chip->cmd_ctrl(mtd, readcmd, ctrl);
-
ctrl &= ~NAND_CTRL_CHANGE;
-
}
-
chip->cmd_ctrl(mtd, command, ctrl);
-
-
/*
-
* Address cycle, when necessary
-
*/
-
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
-
/* Serially input address */
-
if (column != -1) {
-
/* Adjust columns for 16 bit buswidth */
-
if (chip->options & NAND_BUSWIDTH_16)
-
column >>= 1;
-
chip->cmd_ctrl(mtd, column, ctrl);
-
ctrl &= ~NAND_CTRL_CHANGE;
-
}
-
if (page_addr != -1) {
-
chip->cmd_ctrl(mtd, page_addr, ctrl);
-
ctrl &= ~NAND_CTRL_CHANGE;
-
chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
-
/* One more address cycle for devices > 32MiB */
-
if (chip->chipsize > (32 << 20))
-
chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
-
}
-
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-
/*
-
* program and erase have their own busy handlers
-
* status and sequential in needs no delay
-
*/
-
switch (command) {
-
-
case NAND_CMD_PAGEPROG:
-
case NAND_CMD_ERASE1:
-
case NAND_CMD_ERASE2:
-
case NAND_CMD_SEQIN:
-
case NAND_CMD_STATUS:
-
return;
-
-
case NAND_CMD_RESET:
-
if (chip->dev_ready)
-
break;
-
udelay(chip->chip_delay);
-
chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
-
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-
chip->cmd_ctrl(mtd,
-
NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
-
return;
-
-
/* This applies to read commands */
-
default:
-
/*
-
* If we don't have access to the busy pin, we apply the given
-
* command delay
-
*/
-
if (!chip->dev_ready) {
-
udelay(chip->chip_delay);
-
return;
-
}
-
}
-
/* Apply this short delay always to ensure that we do wait tWB in
-
* any case on any machine. */
-
ndelay(100);
-
-
nand_wait_ready(mtd);
-
}
看到粗体部分的函数,我们是否想起了,代码初始化的部分呢?
this
->cmd_ctrl
= board_hwcontrol;
是的,后面的很多mtd代码里函数都会调用this->cmd_ctrl这个函数,我们就不再一一列举了.
在nand_set_defaults函数中,对struct nand_chip 结构的很多函数指针进行了初始化.
我们接着往下看这个函数:nand_get_flash_type ,它的作用是什么呢?
-
/*
-
* Get the flash and manufacturer id and lookup if the type is supported
-
*/
-
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
-
struct nand_chip *chip,
-
int busw, int *maf_id)
-
{
-
struct nand_flash_dev *type = NULL;
-
int i, dev_id, maf_idx;
-
int tmp_id, tmp_manf;
-
-
/* Select the device */
-
chip->select_chip(mtd, 0);
-
-
/*
-
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
-
* after power-up
-
*/
-
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
-
/* Send the command for reading device ID */
-
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
-
/* Read manufacturer and device IDs */
-
*maf_id = chip->read_byte(mtd);
-
dev_id = chip->read_byte(mtd);
-
-
/* Try again to make sure, as some systems the bus-hold or other
-
* interface concerns can cause random data which looks like a
-
* possibly credible NAND flash to appear. If the two results do
-
* not match, ignore the device completely.
-
*/
-
-
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
-
/* Read manufacturer and device IDs */
-
-
tmp_manf = chip->read_byte(mtd);
-
tmp_id = chip->read_byte(mtd);
-
-
if (tmp_manf != *maf_id || tmp_id != dev_id) {
-
printk(KERN_INFO "%s: second ID read did not match "
-
"%02x,%02x against %02x,%02xn", __func__,
-
*maf_id, dev_id, tmp_manf, tmp_id);
-
return ERR_PTR(-ENODEV);
-
}
-
-
/* Lookup the flash id */
-
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-
if (dev_id == nand_flash_ids[i].id) {
-
type = &nand_flash_ids[i];
-
break;
-
}
-
}
-
-
if (!type)
-
return ERR_PTR(-ENODEV);
-
-
if (!mtd->name) {
-
#ifdef CONFIG_MTD_NAND_NFC_GANG_SUPPORT
-
sprintf(nand_name, "%s%s", type->name,
-
(chip->num_devs == 2) ? " - Ganged" : "");
-
type->name = nand_name;
-
#endif
-
mtd->name = type->name;
-
}
-
-
chip->chipsize = (uint64_t)type->chipsize << 20;
-
#ifdef CONFIG_MTD_NAND_NFC_GANG_SUPPORT
-
chip->chipsize *= chip->num_devs;
-
if(chip->num_devs > 1)
-
type->options |= NAND_BUSWIDTH_16;
-
#endif
-
-
/* Newer devices have all the information in additional id bytes */
-
if (!type->pagesize) {
-
int extid;
-
/* The 3rd id byte holds MLC / multichip data */
-
chip->cellinfo = chip->read_byte(mtd);
-
/* The 4th id byte is the important one */
-
extid = chip->read_byte(mtd);
-
/* Calc pagesize */
-
mtd->writesize = 1024 << (extid & 0x3);
-
extid >>= 2;
-
/* Calc oobsize */
-
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
-
#ifdef CONFIG_MTD_NAND_NFC_GANG_SUPPORT
-
mtd->writesize *= chip->num_devs;
-
#endif
-
extid >>= 2;
-
/* Calc blocksize. Blocksize is multiples of 64KiB */
-
mtd->erasesize = (64 * 1024) << (extid & 0x03);
-
#ifdef CONFIG_MTD_NAND_NFC_GANG_SUPPORT
-
mtd->erasesize *= chip->num_devs;
-
#endif
-
extid >>= 2;
-
/* Get buswidth information */
-
busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
-
#ifdef CONFIG_MTD_NAND_NFC_GANG_SUPPORT
-
if(chip->num_devs > 1)
-
busw = NAND_BUSWIDTH_16;
-
#endif
-
} else {
-
/*
-
* Old devices have chip data hardcoded in the device id table
-
*/
-
mtd->erasesize = type->erasesize;
-
mtd->writesize = type->pagesize;
-
mtd->oobsize = mtd->writesize / 32;
-
#ifdef CONFIG_MTD_NAND_NFC_MLC_SUPPORT
-
/* New devices have non standard OOB size */
-
if (chip->oobsize_ovrd)
-
mtd->oobsize = chip->oobsize_ovrd;
-
#endif
-
busw = type->options & NAND_BUSWIDTH_16;
-
#ifdef CONFIG_MTD_NAND_NFC_GANG_SUPPORT
-
mtd->erasesize *= chip->num_devs;
-
mtd->writesize *= chip->num_devs;
-
#endif
-
}
-
-
/* Try to identify manufacturer */
-
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
-
if (nand_manuf_ids[maf_idx].id == *maf_id)
-
break;
-
}
-
-
/*
-
* Check, if buswidth is correct. Hardware drivers should set
-
* chip correct !
-
*/
-
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
-
printk(KERN_INFO "NAND device: Manufacturer ID:"
-
" 0x%02x, Chip ID: 0x%02x (%s %s)n", *maf_id,
-
dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
-
printk(KERN_WARNING "NAND bus width %d instead %d bitn",
-
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
-
busw ? 16 : 8);
-
return ERR_PTR(-EINVAL);
-
}
-
-
/* Calculate the address shift from the page size */
-
chip->page_shift = ffs(mtd->writesize) - 1;
-
/* Convert chipsize to number of pages per chip -1. */
-
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
-
-
chip->bbt_erase_shift = chip->phys_erase_shift =
-
ffs(mtd->erasesize) - 1;
-
if (chip->chipsize & 0xffffffff)
-
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
-
else
-
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;
-
-
/* Set the bad block position */
-
chip->badblockpos = mtd->writesize > 512 ?
-
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
-
-
/* Get chip options, preserve non chip based options */
-
chip->options &= ~NAND_CHIPOPTIONS_MSK;
-
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
-
-
/*
-
* Set chip as a default. Board drivers can override it, if necessary
-
*/
-
chip->options |= NAND_NO_AUTOINCR;
-
-
/* Check if chip is a not a samsung device. Do not clear the
-
* options for chips which are not having an extended id.
-
*/
-
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
-
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
-
-
/* Check for AND chips with 4 page planes */
-
if (chip->options & NAND_4PAGE_ARRAY)
-
chip->erase_cmd = multi_erase_cmd;
-
else
-
chip->erase_cmd = single_erase_cmd;
-
-
/* Do not replace user supplied command function ! */
-
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
-
chip->cmdfunc = nand_command_lp;
-
-
printk(KERN_INFO "NAND device: Manufacturer ID:"
-
" 0x%02x, Chip ID: 0x%02x (%s %s)n", *maf_id, dev_id,
-
nand_manuf_ids[maf_idx].name, type->name);
-
-
return type;
-
}
从注释中我们已经很清晰了,但是这里不能忽略的是粗体部分,尤其是
nand_flash_ids,在初始化的时候我们要把我们特定nand flash信息添加到这个表里。才能识别,不然驱动就没法往下继续执行了.
我们继续回到nand_scan函数中来,我们看另外一个关键的函数:
-
/**
-
* nand_scan_tail - [NAND Interface] Scan for the NAND device
-
* @mtd: MTD device structure
-
*
-
* 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;
-
default:
-
printk(KERN_WARNING "No oob scheme defined for "
-
"oobsize %dn", 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
-
*/
-
-
switch (chip->ecc.mode) {
-
case NAND_ECC_HW_OOB_FIRST:
-
/* Similar to NAND_ECC_HW, but a separate read_page handle */
-
if (!chip->ecc.calculate || !chip->ecc.correct ||
-
!chip->ecc.hwctl) {
-
printk(KERN_WARNING "No ECC functions supplied; "
-
"Hardware ECC not possiblen");
-
BUG();
-
}
-
if (!chip->ecc.read_page)
-
chip->ecc.read_page = nand_read_page_hwecc_oob_first;
-
-
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_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;
-
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) &&
-
(!chip->ecc.read_page ||
-
chip->ecc.read_page == nand_read_page_hwecc ||
-
!chip->ecc.write_page ||
-
chip->ecc.write_page == nand_write_page_hwecc)) {
-
printk(KERN_WARNING "No ECC functions supplied; "
-
"Hardware ECC not possiblen");
-
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_page_raw)
-
chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
-
if (!chip->ecc.write_page_raw)
-
chip->ecc.write_page_raw = nand_write_page_raw_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 ECCn",
-
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.read_subpage = nand_read_subpage;
-
chip->ecc.write_page = nand_write_page_swecc;
-
chip->ecc.read_page_raw = nand_read_page_raw;
-
chip->ecc.write_page_raw = nand_write_page_raw;
-
chip->ecc.read_oob = nand_read_oob_std;
-
chip->ecc.write_oob = nand_write_oob_std;
-
if (!chip->ecc.size)
-
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");
-
#if 0
-
/*close internal ecc */
-
nand_command(mtd, 0xEF, 0x90, -1);
-
writeb(0x00, chip->IO_ADDR_W);
-
writeb(0x00, chip->IO_ADDR_W);
-
writeb(0x00, chip->IO_ADDR_W);
-
writeb(0x00, chip->IO_ADDR_W);
-
printk("close internal ecc ");
-
#endif
-
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.read_page_raw = nand_read_page_raw;
-
chip->ecc.write_page_raw = nand_write_page_raw;
-
chip->ecc.write_oob = nand_write_oob_std;
-
chip->ecc.size = 512;//mtd->writesize;
-
chip->ecc.bytes = 8;//0;
-
break;
-
-
default:
-
printk(KERN_WARNING "Invalid NAND_ECC_MODE %dn",
-
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 < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
-
chip->ecc.layout->oobavail +=
-
chip->ecc.layout->oobfree[i].length;
-
mtd->oobavail = chip->ecc.layout->oobavail;
-
-
/*
-
* 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 parametersn");
-
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:
-
case 16:
-
mtd->subpage_sft = 2;
-
break;
-
}
-
}
-
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
-
-
/* Initialize state */
-
chip->state = FL_READY;
-
-
/* 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->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);
-
}
这里加入关于ecc校验函数的一些初始化.对于nand flash的ecc对数据位的ecc校验的重要性和必要性,这么我们不多解释.当然关于nandflash芯片的具体oob信息需要在这里初始化和指定,不然读不到正确的数据(还有一些nand flash芯片支持内置校验,关于校验我们足够在写一篇了), 最后就是对mtd的一些操作函数的初始化.
这里我们还是在简单的说明下这个函数的一些部分:
-
/**
-
* nand_read_page_raw - [Intern] read raw page data without ecc
-
* @mtd: mtd info structure
-
* @chip: nand chip info structure
-
* @buf: buffer to store read data
-
* @page: page number to read
-
*
-
* Not for syndrome calculating ecc controllers, which use a special oob layout
-
*/
-
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-
uint8_t *buf, int page)
-
{
-
chip->read_buf(mtd, buf, mtd->writesize);
-
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
return 0;
-
}
看到没有chip->read_buf其实都是通过chip->cmd_ctrl的各种封装和操作.最后就是对mtd的初始化,这里我们终于看到了.
我们看一下: mtd->read =nand_read;
-
/**
-
* nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
-
* @mtd: MTD device structure
-
* @from: offset to read from
-
* @len: number of bytes to read
-
* @retlen: pointer to variable to store the number of read bytes
-
* @buf: the databuffer to put data
-
*
-
* Get hold of the chip and call nand_do_read
-
*/
-
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
-
size_t *retlen, uint8_t *buf)
-
{
-
struct nand_chip *chip = mtd->priv;
-
int ret;
-
-
/* Do not allow reads past end of device */
-
if ((from + len) > mtd->size)
-
return -EINVAL;
-
if (!len)
-
return 0;
-
-
nand_get_device(chip, mtd, FL_READING);
-
-
chip->ops.len = len;
-
chip->ops.datbuf = buf;
-
chip->ops.oobbuf = NULL;
-
-
ret = nand_do_read_ops(mtd, from, &chip->ops);
-
-
*retlen = chip->ops.retlen;
-
-
nand_release_device(mtd);
-
-
return ret;
-
}
nand_do_read_ops(mtd, from, &chip->ops);关键的一行代码,它也是通过chip里一些函数来实现真正的操作.
关于文章开始代码的初始化函数的最后一个操作就是add_mtd_partitions了.网上很多文章对这个函数都解释的很好的.
这里为什么这么长篇大论的自己分析一番,当然只是一个小小的入门和开始.这里都是针对linux kernel里的代码来说明,有机会也要说下uboot下是如何初始化的.
阅读(10109) | 评论(0) | 转发(3) |