您的位置:首页 > 其它

基于MTD的NANDFLASH设备驱动底层实现原理分析(三)

2014-04-22 09:23 507 查看
转载地址:/article/8530043.html

非常

的说:我突然发现在写这些关于NAND驱动的文章的时候,原来我一直是在改写别人的博客。。。。。其实这并不要紧的,我也觉得这不仅仅是一种比较好的学习方法了,为什么呢,因为当我在看他的博客的时候,我明白了一点,然后当我自己要写的时候。。对这个东东又进一步了解一点了。。呵呵Copy也分档次了

五、硬件时序到软件代码的演变过程对nand_base.c部分代码的分析

该文件位于</linux2.6.35/dricer/mtd/nand/nand_base.c>

还是把那个读NAND的硬件时序图给贴上,如下图:



①:此阶段,是读命令第一个周期,发送的命令为0x00。

②:此阶段,依次发送列地址,关于这些行地址,列地址等是如何计算出来的,后面的内容

会有详细解释。

③:此阶段是发送对应的行地址

④:此阶段是发送读命令第二周期 2nd cycle所对应的命令,0x30

⑤:此阶段是等待时间,等待 Nand Flash硬件上准备好对应的数据,以便后续读出。

⑥:此阶段,就是一点点地把所需要的数据读出来。

MTD 读取数据的入口是 nand_read,然后调用 nand_do_read_ops,此函数主体如下:

static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,

struct mtd_oob_ops *ops)

{

/***此处省略部分代码**/

。。。。。。。。。。。。。。

while(1) {

/******省略****/

.。。。。。。。。。。。。。。。

if (likely(sndcmd)) {/*#define NAND_CMD_READ0 0*/

/*1)***读取数据前肯定要先发送对应的读页命令******/

chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);

sndcmd = 0;

}

/* Now read the page into the buffer */

if (unlikely(ops->mode == MTD_OOB_RAW))

ret = chip->ecc.read_page_raw(mtd, chip,

bufpoi, page);

else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)

ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);

else

/******执行到这里read_page函数读取对应的数据了******/

ret = chip->ecc.read_page(mtd, chip, bufpoi,

page);

if (ret < 0)

break;

/* Transfer not aligned data */

if (!aligned) {

if (!NAND_SUBPAGE_READ(chip) && !oob)

chip->pagebuf = realpage;

memcpy(buf, chip->buffers->databuf + col, bytes);

}

buf += bytes;

。。。。。。。。。。。。。。。。。。

if (mtd->ecc_stats.failed - stats.failed)

return -EBADMSG;

return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;

}

上面这些代码都不需要我们去实现的,使用MTD层的自定义代码就行。。。

nand_command_lp的分析

static void nand_command_lp(struct mtd_info *mtd, unsigned int command,

int column, int page_addr)

{

register struct nand_chip *chip = mtd->priv;

/* Emulate NAND_CMD_READOOB */

if (command == NAND_CMD_READOOB) {

column += mtd->writesize;

command = NAND_CMD_READ0;

}

/* Command latch cycle */

/* 此处就是就是发送读命令的第一个周期1st Cycle的命令,即0x00,对应着上述步骤中的① */

chip->cmd_ctrl(mtd, command & 0xff,

NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);

if (column != -1 || page_addr != -1) {

int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;

/* Serially input address */

if (column != -1) {

/* Adjust columns for 16 bit buswidth */

if (chip->options & NAND_BUSWIDTH_16)

column >>= 1;

/* 发送两个column列地址,对应着上述步骤中的② */

chip->cmd_ctrl(mtd, column, ctrl);/*发送列地址1*/

ctrl &= ~NAND_CTRL_CHANGE;

chip->cmd_ctrl(mtd, column >> 8, ctrl);/*发送列地址2*/

}

if (page_addr != -1) {

/* 接下来是发送三个Row,行地址,对应着上述步骤中的② */

chip->cmd_ctrl(mtd, page_addr, ctrl);/*发送行地址1*/

chip->cmd_ctrl(mtd, page_addr >> 8,/*发送行地址2*/

NAND_NCE | NAND_ALE);

/* One more address cycle for devices > 128MiB */

if (chip->chipsize > (128 << 20))

chip->cmd_ctrl(mtd, page_addr >> 16,/*发送行地址3*/

NAND_NCE | NAND_ALE);

}

}

chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);

/*

* program and erase have their own busy handlers

* status, sequential in, and deplete1 need no delay

*/

switch (command) {

。。。。。。。。。。。。。

return;

/***复位**/

case NAND_CMD_RESET:

if (chip->dev_ready)

break;

udelay(chip->chip_delay);

chip->cmd_ctrl(mtd, NAND_CMD_STATUS,

NAND_NCE | NAND_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;

/*读忙信号*/

case NAND_CMD_RNDOUT:

/* No ready / busy check necessary */

chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,

NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);

chip->cmd_ctrl(mtd, NAND_CMD_NONE,

NAND_NCE | NAND_CTRL_CHANGE);

return;

/* 接下来发送读命令的第二个周期2nd Cycle的命令,即0x30,对应着上述步骤

中的④ */

case NAND_CMD_READ0:

chip->cmd_ctrl(mtd, NAND_CMD_READSTART,

NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);

chip->cmd_ctrl(mtd, NAND_CMD_NONE,

NAND_NCE | NAND_CTRL_CHANGE);

/* 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. */

/* 此处是对应着④中的tWB的等待时间*/

ndelay(100);

/* 接下来就是要等待一定的时间,使得Nand Flash硬件上准备好数据,以供你之

后读取,即对应着步骤⑤ */

nand_wait_ready(mtd);

}

还有一个步骤没有实现那就是步骤⑥了一点一点的把数据读出来

nand_read_page_hwecc分析

static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,

uint8_t *buf, int page)

{

。。。。。。。。。。。。。。。。。。。。。。

for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {

chip->ecc.hwctl(mtd, NAND_ECC_READ);

/**这个最重要了这才是真正的从NAND的缓冲区中把数据给读出来****/

chip->read_buf(mtd, p, eccsize);

chip->ecc.calculate(mtd, p, &ecc_calc[i]);

}

。。。。。。。。。。

return 0;

}

上面的 read_buf,就是真正的去读取数据的函数了,由于不同的Nand Flash controller 控制器所实现的方式不同,所以这个函数必须在你的 Nand Flash驱动中实现,即MTD 层,能帮我们实现的都实现了,不能实现的,那肯定是我们自己的事情了。。。接下来的工作是什么?MTD原始设备和硬件驱动层的交互了.这个才是我们要去真正实现的。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: