然后我们分析一下nand flash的读写等函数。
既然是命令那自然要看到U_BOOT_CMD宏,这个宏分析的很多就不分析了。在cmd_nand.c文件中。nand的命令执行函数是do_nand。当然我们没有定义CFG_NAND_LEGACY,要看这个分支。do_nand函数也没有什么好分析的,摘取几个命令的处理分析下。
1。nand bad命令
do_nand
nand_block_isbad//include/nand.h
nand_block_isbad//在Nand_base.c中, info->block_isbad函数指针指向
nand_block_checkbad//在Nand_base.c
nand_block_bad() //在Nand_base.c中,nand_chip,this->block_bad函数指针指向,
nand_isbad_bbt
//在Nand_bbt.c中
如下。
点击(此处)折叠或打开
- nand = &nand_info[nand_curr_device];
-
if (strcmp(cmd, "bad") == 0) {
- printf("\nDevice %d bad blocks:\n", nand_curr_device);
-
for (off = 0; off < nand->size; off += nand->erasesize) //按块循环
-
if (nand_block_isbad(nand, off)) //(1)
- printf(" %08x\n", off);
- return 0;
- }
这个函数的定义在include/nand.h中,它调用nand_info[]变量中的block_isbad函数指针指向的函数;这个指针在初始化时已经被分配,这里是Nand_base.c文件中的nand_block_isbad函数。这里有个小问题,那有两个都被编译的nand_block_isbad函数的定义,那到底调用的是哪个呢。答案是nand.h中的,因为Nand_base.c中的是被定义成static的函数,只能在本文件中使用。
点击(此处)折叠或打开
- static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
-
{
-
/* Check for invalid offset */
-
if (ofs > mtd->size)
- return -EINVAL;
- return nand_block_checkbad (mtd, ofs, 1, 0);
- }
点击(此处)折叠或打开
- static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
-
{
- struct nand_chip *this = mtd->priv;
-
if (!this->bbt) //如果nand_chip结构体变量中的bbt(坏块标记表)表指针是空的
- return this->block_bad(mtd, getchip);
-
/* Return info from the table */
- return nand_isbad_bbt (mtd, allowbbt);
- }
block_bad函数指针被指向nand_block_bad,分析它,
点击(此处)折叠或打开
- static int nand_block_bad(struct mtd_info *mtd, int getchip)
-
{
-
int page, chipnr, res = 0;
- struct nand_chip *this = mtd->priv;
- u16 bad;
- page = (int)(ofs >> this->page_shift) & this->pagemask; //(1)
-
if (getchip) { //选中芯片
- chipnr = (int)(ofs >> this->chip_shift);
-
/* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_READING);
-
/* Select the NAND device */
- this->select_chip(mtd, chipnr);
-
}
-
if (this->options & NAND_BUSWIDTH_16) {
- this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page);
- bad = cpu_to_le16(this->read_word(mtd));
-
if (this->badblockpos & 0x1)
- bad >>= 1;
-
if ((bad & 0xFF) != 0xff)
- res = 1;
-
} else {
- this->cmdfunc (mtd, this->badblockpos, page); //(2)
-
if (this->read_byte(mtd) != 0xff) //(3)
- res = 1;
-
}
-
if (getchip) {
-
/* deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
-
}
- return res;
- }
(1)从偏移地址获取页号。page_shift是page页位数(就是一页的大小的数值用二进制表示最高位的序号)。将偏移地址右移页位数,则低位就是页的号码,有相当于除页大小。然后在与上pagemask,就是页大小(主要是将高位置0,其实这里与不与感觉都无所谓,高位本来就是0)
(3)读出的位是否是0xff,如果不是就是坏块。
...................................
再看下如果有bbt表,nand_block_checkbad函数将调用nand_isbad_bbt。bbt表在初始化时scan_bbt函数已经建立。所以nand bad命令在这个uboot中都是通过查bbt表完成的。
点击(此处)折叠或打开
-
int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
-
{
- struct nand_chip *this = mtd->priv;
-
int block;
- uint8_t res;
-
/* Get block number * 2 */
- block = (int) (offs >> (this->bbt_erase_shift - 1)); //(1)
- res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; //(2)
- DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
-
(unsigned int)offs, res, block >> 1);
- switch ((int)res) {
-
case 0x00: return 0;
-
case 0x01: return 1;
-
case 0x02: return allowbbt ? 0 : 1;
-
}
- return 1;
- }
nand bad命令处理暂时分析到这里
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
分析nand read 命令:
nand read命令的调用顺序为:
do_nand //cmd_nand.c
nand_read_opts
///driver/mtd/nand/nand_util.c
nand_read //nand_base.c,meminfo->read指针指向
nand_read_ecc //nand_base.c
sep4020_nand_read_buf//cpu/sep4020/nand_flash.c
do_nand函数中read相关部分:
点击(此处)折叠或打开
-
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
-
int read;
-
if (argc < 4)
- goto usage;
- addr = (ulong)simple_strtoul(argv[2], NULL, 16);
- read = strncmp(cmd, 4) == 0; /* 1 = read, 0 = write */
- printf("\nNAND %s: ", read ? "read" : "write");
-
if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
- return 1;
- s = strchr(cmd, '.');
-
if (s != NULL &&
-
(!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
-
if (read) {
-
/* read */
- nand_read_options_t opts;
- memset(&opts, 0, sizeof(opts));
- opts.buffer = (u_char*) addr; //addr是内存地址,nand读出来的数据最终将存入这里
- opts.length = size; //读取的大小
- opts.offset = off; //flash地址
- opts.quiet = quiet;
- ret = nand_read_opts(nand, &opts); //读数据操作,opts将保存必要的信息。
-
} else {
-
/* write */
- nand_write_options_t opts;
- memset(&opts, sizeof(opts));
- opts.buffer = (u_char*) addr;
- opts.length = size;
- opts.offset = off;
-
/* opts.forcejffs2 = 1; */
- opts.pad = 1;
- opts.blockalign = 1;
- opts.quiet = quiet;
- ret = nand_write_opts(nand, &opts);
-
}
-
} else if (s != NULL && !strcmp(s, ".yaffs")) {
-
if (read) {
-
/* read */
- nand_read_options_t opts;
- memset(&opts, sizeof(opts));
- opts.buffer = (u_char*) addr;
- opts.length = size;
- opts.offset = off;
- opts.quiet = quiet;
- ret = nand_read_opts(nand, &opts);
-
} else {
-
/* write */
- nand_write_options_t opts;
- memset(&opts, sizeof(opts));
- opts.buffer = (u_char*) addr;
- opts.length = size;
- opts.offset = off;
-
/* opts.forceyaffs = 1; */
- opts.noecc = 1;
- opts.writeoob = 1;
- opts.blockalign = 1;
- opts.quiet = quiet;
- opts.skipfirstblk = 1;
- ret = nand_write_opts(nand, &opts);
-
}
-
} else if (s != NULL && !strcmp(s, ".oob")) {
-
/* read out-of-band data */
-
if (read)
- ret = nand->read_oob(nand, off, size, &size,
-
(u_char *) addr);
-
else
- ret = nand->write_oob(nand,
-
(u_char *) addr);
-
} else {
-
if (read)
- ret = nand_read(nand, (u_char *)addr);
-
else
- ret = nand_write(nand, (u_char *)addr);
-
}
- printf(" %d bytes %s: %s\n",
- read ? "read" : "written", ret ? "ERROR" : "OK");
- return ret == 0 ? 0 : 1;
- }
点击(此处)折叠或打开
-
/**
-
* nand_read_opts: - read image from NAND flash with support for varIoUs options
-
*
-
* @param meminfo NAND device to erase
-
* @param opts read options (@see struct nand_read_options)
-
* @return 0 in case of success
-
*
-
*/
-
int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
-
{
-
int imglen = opts->length;
-
int pagelen;
-
int baderaseblock;
-
int blockstart = -1;
-
int percent_complete = -1;
- loff_t offs;
- size_t readlen;
- ulong mtdoffset = opts->offset;
- u_char *buffer = opts->buffer;
-
int result;
-
/* make sure device page sizes are valid */
-
if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
-
&& !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
-
&& !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
- printf("UnkNown flash (not normal NAND)\n");
- return -1;
-
}
- pagelen = meminfo->oobblock
-
+ ((opts->readoob != 0) ? meminfo->oobsize : 0);
-
/* check, if length is not larger than device */
-
if (((imglen / pagelen) * meminfo->oobblock)
-
> (meminfo->size - opts->offset)) {
- printf("Image %d bytes,NAND page %d bytes,"
-
"OOB area %u bytes,device size %u bytes\n",
- imglen, pagelen, meminfo->oobblock, meminfo->size);
- printf("Input block is larger than device\n");
- return -1;
-
}
-
if (!opts->quiet)
- printf("\n");
-
/* get data from input and write to the device */
-
while (imglen && (mtdoffset < meminfo->size)) {
- WATCHDOG_RESET ();
-
/*
-
* new eraseblock, check for bad block(s). Stay in the
-
* loop to be sure if the offset changes because of
-
* a bad block, that the next block that will be
-
* written to is also checked. Thus avoiding errors if
-
* the block(s) after the skipped block(s) is also bad
-
* (number of blocks depending on the blockalign
-
*/
-
while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) {
- blockstart = mtdoffset & (~meminfo->erasesize+1);
- offs = blockstart;
- baderaseblock = 0;
-
/* check all the blocks in an erase block for
-
* bad blocks */
-
do {
-
int ret = meminfo->block_isbad(meminfo, offs);
-
if (ret < 0) {
- printf("Bad block check Failed\n");
- return -1;
-
}
-
if (ret == 1) {
- baderaseblock = 1;
-
if (!opts->quiet)
- printf("\rBad block at 0x%lx "
-
"in erase block from "
-
"0x%x will be skipped\n",
-
(long) offs,
- blockstart);
-
}
-
if (baderaseblock) {
- mtdoffset = blockstart
-
+ meminfo->erasesize;
-
}
- offs += meminfo->erasesize;
-
} while (offs < blockstart + meminfo->erasesize);
-
}
-
/* read page data to memory buffer */
- result = meminfo->read(meminfo, //读2048字节(不包含oob的一页),
- mtdoffset, //nand flash地址
- meminfo->oobblock, //页大小(2048),即需要读取的字节数
-
&readlen,
-
(unsigned char *) &data_buf);
-
if (result != 0) {
- printf("reading NAND page at offset 0x%lx Failed\n",
- mtdoffset);
- return -1;
-
}
-
if (imglen < readlen) {
- readlen = imglen;
-
}
- memcpy(buffer, data_buf, readlen);
- buffer += readlen;
- imglen -= readlen;
-
//上面是读页有效数据(2048),这里读oob数据。
-
if (opts->readoob) {
- result = meminfo->read_oob(meminfo,
- mtdoffset,
- meminfo->oobsize,
-
&readlen,
-
(unsigned char *)
-
&oob_buf);
-
if (result != 0) {
- printf("\nMTD readoob failure: %d\n",
- result);
- return -1;
-
}
-
if (imglen < readlen) {
- readlen = imglen;
-
}
- memcpy(buffer, oob_buf, readlen);
- buffer += readlen;
- imglen -= readlen;
-
}
-
if (!opts->quiet) {
- unsigned long long n = (unsigned long long)
-
(opts->length-imglen) * 100;
-
int percent;
- do_div(n, opts->length);
- percent = (int)n;
-
/* output progress message only at whole percent
-
* steps to reduce the number of messages printed
-
* on (slow) serial consoles
-
*/
-
if (percent != percent_complete) {
-
if (!opts->quiet)
- printf("\rReading data from 0x%x "
-
"-- %3d%% complete.", percent);
- percent_complete = percent;
-
}
-
}
- mtdoffset += meminfo->oobblock;
-
}
-
if (!opts->quiet)
- printf("\n");
-
if (imglen > 0) {
- printf("Could not read entire image due to bad blocks\n");
- return -1;
-
}
-
/* return happy */
- return 0;
- }
点击(此处)折叠或打开
- static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
-
{
- return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
- }
点击(此处)折叠或打开
-
/**
-
* nand_read_ecc - [MTD Interface] Read data with 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
-
* @oob_buf: filesystem supplied oob data buffer
-
* @oobsel: oob selection structure
-
*
-
* NAND read with ECC
-
*/
- static int nand_read_ecc (struct mtd_info *mtd,
- size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
-
{
-
int i, j, col, realpage, page, end, ecc, sndcmd = 1;
-
int read = 0, oob = 0, ecc_status = 0, ecc_Failed = 0;
- struct nand_chip *this = mtd->priv;
- u_char *data_poi, *oob_data = oob_buf;
- u_char ecc_calc[32];
- u_char ecc_code[32];
-
int eccmode, eccsteps;
- unsigned *oob_config;
-
int datidx;
-
int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
-
int eccbytes;
-
int compareecc = 1;
-
int oobreadlen;
- DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x,len = %i\n", (unsigned int) from, (int) len);
-
/* Do not allow reads past end of device */
-
if ((from + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
-
*retlen = 0;
- return -EINVAL;
-
}
-
/* Grab the lock and see if the device is available */
- nand_get_device (this, mtd ,FL_READING);
-
/* use userspace supplied oobinfo, if zero */
-
if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
-
/* Autoplace of oob data ? Use the default placement scheme */
-
if (oobsel->useecc == MTD_NANDECC_AutopLACE)
- oobsel = this->autooob;
- eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
- oob_config = oobsel->eccpos;
-
/* Select the NAND device */
- chipnr = (int)(from >> this->chip_shift);
- this->select_chip(mtd, chipnr);
-
/* First we calculate the starting page */
- realpage = (int) (from >> this->page_shift);
- page = realpage & this->pagemask;
-
/* Get raw starting column */
- col = from & (mtd->oobblock - 1);
-
end = mtd->oobblock;
- ecc = this->eccsize;
- eccbytes = this->eccbytes;
-
if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
- compareecc = 0;
- oobreadlen = mtd->oobsize;
-
if (this->options & NAND_HWECC_SYNDROME)
- oobreadlen -= oobsel->eccbytes;
-
/* Loop until all data read */
-
while (read < len) {
-
int aligned = (!col && (len - read) >= end);
-
/*
-
* If the read is not page aligned, we have to read into data buffer
-
* due to ecc, else we read into return buffer direct
-
*/
-
if (aligned)
- data_poi = &buf[read];
-
else
- data_poi = this->data_buf;
-
/* Check, if we have this page in the buffer
-
*
-
* FIXME: Make it work when we must provide oob data too,
-
* check the usage of data_buf oob field
-
*/
-
if (realpage == this->pagebuf && !oob_buf) {
-
/* aligned read ? */
-
if (aligned)
- memcpy (data_poi, this->data_buf, end);
- goto readdata;
-
}
-
/* Check, if we must send the read command */
-
if (sndcmd) { //板级读命令发送,其实这里主要设置了nandflash的地址。
- this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
- sndcmd = 0;
-
}
-
/* get oob area, if we have no oob buffer from fs-driver */
-
if (!oob_buf || oobsel->useecc == MTD_NANDECC_AutopLACE ||
- oobsel->useecc == MTD_NANDECC_AutopL_USR)
- oob_data = &this->data_buf[end];
- eccsteps = this->eccsteps;
- switch (eccmode) {
-
case NAND_ECC_NONE: { /* No ECC, Read in a page */
-
/* XXX U-BOOT XXX */
- #if 0
- static unsigned long lastwhinge = 0;
-
if ((lastwhinge / HZ) != (jiffies / HZ)) {
- printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
- lastwhinge = jiffies;
-
}
- #else
- puts("Reading data from NAND FLASH without ECC is not recommended\n");
- #endif
- this->read_buf(mtd, data_poi, end);
- break;
-
}
-
case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
- this->read_buf(mtd, end); //读取数据
-
for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc)
- this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
- break;
- default:
-
for (i = 0, i+=eccbytes, datidx += ecc) {
- this->enable_hwecc(mtd, NAND_ECC_READ);
- this->read_buf(mtd, ecc);
-
/* HW ecc with syndrome calculation must read the
-
* syndrome from flash immidiately after the data */
-
if (!compareecc) {
-
/* Some hw ecc generators need to kNow when the
-
* syndrome is read from flash */
- this->enable_hwecc(mtd, NAND_ECC_READSYN);
- this->read_buf(mtd, &oob_data[i], eccbytes);
-
/* We calc error correction directly, it checks the hw
-
* generator for an error, reads back the syndrome and
-
* does the error correction on the fly */
-
if (this->correct_data(mtd, &ecc_code[i]) == -1) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
-
"Failed ECC read,page 0x%08x on chip %d\n", chipnr);
- ecc_Failed++;
-
}
-
} else {
- this->calculate_ecc(mtd, &ecc_calc[i]);
-
}
-
}
- break;
-
}
-
/* read oobdata */
- this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
-
/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
-
if (!compareecc)
- goto readoob;
-
/* Pick the ECC bytes out of the oob data */
-
for (j = 0; j < oobsel->eccbytes; j++)
- ecc_code[j] = oob_data[oob_config[j]];
-
/* correct data, if neccecary */
-
for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
- ecc_status = this->correct_data(mtd, &ecc_code[j], &ecc_calc[j]);
-
/* Get next chunk of ecc bytes */
- j += eccbytes;
-
/* Check, if we have a fs supplied oob-buffer,
-
* This is the legacy mode. Used by YAFFS1
-
* Should go away some day
-
*/
-
if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
-
int *p = (int *)(&oob_data[mtd->oobsize]);
- p[i] = ecc_status;
-
}
-
if (ecc_status == -1) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read,page 0x%08x\n", page);
- ecc_Failed++;
-
}
-
}
- readoob:
-
/* check, if we have a fs supplied oob-buffer */
-
if (oob_buf) {
-
/* without autoplace. Legacy mode used by YAFFS1 */
- switch(oobsel->useecc) {
-
case MTD_NANDECC_AutopLACE:
-
case MTD_NANDECC_AutopL_USR:
-
/* Walk through the autoplace chunks */
-
for (i = 0, j = 0; j < mtd->oobavail; i++) {
-
int from = oobsel->oobfree[i][0];
-
int num = oobsel->oobfree[i][1];
- memcpy(&oob_buf[oob+j], &oob_data[from], num);
- j+= num;
-
}
- oob += mtd->oobavail;
- break;
-
case MTD_NANDECC_PLACE:
-
/* YAFFS1 legacy mode */
- oob_data += this->eccsteps * sizeof (int);
- default:
- oob_data += mtd->oobsize;
-
}
-
}
- readdata:
-
/* Partial page read, transfer data into fs buffer */
-
if (!aligned) {
-
for (j = col; j < end && read < len; j++)
- buf[read++] = data_poi[j];
- this->pagebuf = realpage;
-
} else
- read += mtd->oobblock;
-
/* Apply delay or wait for ready/busy pin
-
* Do this before the AUTOINCR check, so no problems
-
* arise if a chip which does auto increment
-
* is marked as NOAUTOINCR by the board driver.
-
*/
-
if (!this->dev_ready)
- udelay (this->chip_delay);
-
else
-
while (!this->dev_ready(mtd));
-
if (read == len)
- break;
-
/* For subsequent reads align to page boundary. */
- col = 0;
-
/* Increment page address */
- realpage++;
- page = realpage & this->pagemask;
-
/* Check, if we cross a chip boundary */
-
if (!page) {
- chipnr++;
- this->select_chip(mtd, -1);
- this->select_chip(mtd, chipnr);
-
}
-
/* Check, if the chip supports auto page increment
-
* or if we have hit a block boundary.
-
*/
-
if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
- sndcmd = 1;
-
}
-
/* deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
-
/*
-
* Return success, if no ECC failures, else -EBADMSG
-
* fs driver will take care of that, because
-
* retlen == desired len and result == -EBADMSG
-
*/
-
*retlen = read;
- return ecc_Failed ? -EBADMSG : 0;
- }
点击(此处)折叠或打开
- static void sep4020_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-
{
- register struct nand_chip *this = mtd->priv;
-
if(command == NAND_CMD_READOOB) //(1)
-
{
- column += mtd->oobblock;
- command = NAND_CMD_READ0;
-
}
-
//column是坏块在oob中的位置,加上oobblock(就是页大小pagesiz,不知道为什么起这个名字oobblock),这样就是
-
//地址中的列地址。command命令赋值NAND_CMD_READ0(0),读命令。
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
-
//命令引脚使能
- switch(command)
-
{
-
case NAND_CMD_READ0:
-
*(volatile unsigned long*)EMI_NAND_COM_RAW = 0x40003000;
-
//这个寄存器[7:0]命令的第一个字节00 [15:8]是命令的第二个字节30 .
-
//最高位是使能位(暂不开启),30位是字节表示1字节还是2字节命令。4=0100
- break;
-
case NAND_CMD_SEQIN:
-
*(volatile unsigned long*)EMI_NAND_COM_RAW = 0x40001080;
-
// 80,10 写flash
- break;
- default:
- this->write_byte(mtd,command);
- break;
-
}
- this->hwcontrol(mtd,NAND_CTL_CLRCLE);
-
//命令引脚无效
-
if (command == NAND_CMD_READID)
-
{
- EMI_NAND_COM |= 0x80000000; //使能EMI_NAND_COM
- this->hwcontrol(mtd, NAND_READ_ID);
- return;
-
}
-
if (command == NAND_CMD_STATUS)
-
{
- EMI_NAND_COM |= 0x80000000; //使能EMI_NAND_COM
- this->hwcontrol(mtd, NAND_READ_STATUS);
-
}
-
if (command == NAND_CMD_RESET)
-
{
- EMI_NAND_COM |= 0x80000000;
- this->hwcontrol(mtd, NAND_CTL_CLRALE);
-
}
-
/* Set ALE and clear CLE to start address cycle */
-
if (column != -1 || page_addr != -1) {
- this->hwcontrol(mtd, NAND_CTL_SETALE); //这里这个函数其实没什么用。
- EMI_NAND_ADDR1 = page_addr<<16; //page_addr是页号。128M,2Kflash一共就64K页
- EMI_NAND_ADDR2 = page_addr>>16; //对于一共总数64K的页,这个值等于0
- this->hwcontrol(mtd, NAND_CTL_CLRALE);
-
}
-
//
- }
分析sep4020_hwcontrol函数。此函数之所以存在,应该是为了和MCU通过引脚直接控制或其他MCU的nand flash的代码结构保持兼容,此处此函数的主要作用是将IO_ADDR_W替换成对应的寄存器地址
点击(此处)折叠或打开
- static void sep4020_hwcontrol(struct mtd_info *mtd, int cmd)
-
{
- struct nand_chip *this = mtd->priv;
- switch (cmd) {
-
case NAND_CTL_SETNCE:
-
case NAND_CTL_CLRNCE:
- break;
-
//对于nCE位的操作都不予理睬
-
case NAND_CTL_SETCLE:
- this->IO_ADDR_W = (void __iomem *) EMI_NAND_COM_RAW;
- break;
-
//IO_ADDR_W是nand flash的数据寄存器地址。是_iomem类型变量(这是个空的宏定义,
-
//但这样可以让人很容易知道这是个寄存器变量。),这里的作用是将EMI_NAND_COM_RAW即nand flash
-
//内存的地址赋值给IO_ADDR_W,这样后面的操作,在使用IO_ADDR_W时就是使用EMI_NAND_COM_RAW。
-
case NAND_CTL_SETALE:
- this->IO_ADDR_W = (void __iomem *) EMI_NAND_ADDR1_RAW;
- break;
-
case NAND_READ_ID:
- this->IO_ADDR_R = (void __iomem *) EMI_NAND_ID_RAW;
- break;
-
case NAND_READ_STATUS:
- this->IO_ADDR_R = (void __iomem *) EMI_NAND_STA_RAW;
- break;
-
/* NAND_CTL_CLRCLE: */
-
/* NAND_CTL_CLRALE: */
- default:
- this->IO_ADDR_W = (void __iomem *) EMI_NAND_DATA_RAW;
- this->IO_ADDR_R = (void __iomem *) EMI_NAND_DATA_RAW;
-
//在一些命令使能和地址使能后,将IO_ADDR_W还原成EMI_NAND_DATA_RAW nand flash数据寄存器地址
- break;
-
}
- }
this->read_buf(mtd,data_poi,end);read_buf指向的函数为sep4020_nand_read_buf,
点击(此处)折叠或打开
- static void sep4020_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-
{
-
int i;
- struct nand_chip *this = mtd->priv;
-
//配置DMAC用于nand的传输
- DMAC_C0CONTROL = ((2112>>2)<<14) + (1<<13) + (2<<9) +(2<<6) + (3<<3) + 3;
- DMAC_C0SRCADDR = EMI_NAND_DATA_RAW ;
- DMAC_C0DESTADD = vaddr; //vaddr在board_nand_init函数中,使用malloc分配的一块2112大的内存空间
- DMAC_C0CONfigURATION = 0x31d ;
- EMI_NAND_COM = 0xc0003000; //nand命令控制器,00 30读命令,且最高位使能nand控制器,开始读数据。
-
while(1)
-
{
-
if ((EMI_NAND_IDLE & 0x01) != 0)
- break;
-
}
-
if(len == 2048 || len == 2112) //如果要读取的长度是1页或包含oob的1页。则从vaddr开始复制len长度的数据
-
{
- memcpy(buf,vaddr,len);
-
}
-
else if(len == 64) //如果读取的长度是64,则是要只读取oob区域,则从vaddr+2048地址处开始复制。
-
{
- memcpy(buf,vaddr+2048,len);
-
}
- }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。