arm-linux东东之nand之3: nand_scan_ident出生
时间:2009-03-23 来源:qiuhuafeng
三 nand_scan_ident出生
读这样的代码.会不会觉得我很无聊.不过还得继续nand_scan_ident.500)this.width=500;" border=0>
2403行如果你的NAND是16的,就必须在进入nand_scan_ident之前做这样的一个语句:
Chip->options | =NAND_BUSWIDTH_16,表示我的NAND是16数据宽的.
2405行调用nand_set_defaults
500)this.width=500;" border=0>
给chip 值.没有给的.这里给defaults.
对照一下s3c2410_nand_init_chip
500)this.width=500;" border=0>
好回到nand_scan_ident中:
500)this.width=500;" border=0>2404行调用nand_get_flash_type
500)this.width=500;" border=0>
2243行调用select_chip.不知道你记不记得以前我们说过的
chip->select_chip = s3c2410_nand_select_chip;
于是进入s3c2410_nand_select_chip
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip){
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
struct nand_chip *this = mtd->priv;
unsigned long cur;
nmtd = this->priv;
info = nmtd->info;
if (chip != -1 && allow_clk_stop(info))
clk_enable(info->clk);
cur = readl(info->sel_reg);
if (chip == -1) {
cur |= info->sel_bit;
} else {
if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
dev_err(info->device, "invalid chip %d\n", chip);
return;
} if (info->platform != NULL) {
if (info->platform->select_chip != NULL)
(info->platform->select_chip) (nmtd->set, chip);
} cur &= ~info->sel_bit;
}
writel(cur, info->sel_reg);
if (chip == -1 && allow_clk_stop(info))
clk_disable(info->clk);
}
这里chip 就是0
250行就会被调用
251行读寄存器NFCONF.还记得不:
info->sel_reg = regs + S3C2440_NFCONT;
info->sel_bit = S3C2440_NFCONT_nFCE;
265行取反.也就是以前我们说的. Enable chip select
经过这么一调用NAND控制器就跑起来了.
回到nand_get_flash_type中来.
2246行chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
接下来要说NAND协议了.请注意.
于是调用
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);
}
我们来看下参数.mtd没有问题吧.command是命令.大概就有这么些命令:
#define NAND_CMD_READ0 0
#define NAND_CMD_READ1 1
#define NAND_CMD_RNDOUT 5
#define NAND_CMD_PAGEPROG 0x10
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
而这里的命令就是: NAND_CMD_READID
Column是列地址. page_addr是页地址.很多NAND一页就是512+16.
写一页数据怎么写呢?
一页分A区/B区/C区
A区就是512的上半部就是前一个256
B区就是512的下半部就是后一个256
C区就是那16个
通过命令选中区以后就可以通过Column来选择那个字
OK.很多NAND又分块.一块有几个页
500)this.width=500;" border=0>
这个图说明:一个块有32个页也就是说在page_addr分出5位来对页寻址.其他的就对块寻址.于是就这样发地址:
500)this.width=500;" border=0>
A0-A7就是Column地址 A9-A13就是页地址A14-A25就块地址.当然你的NAND可能与我的不同.我的是64M的.*L表示为0.