分类: LINUX
2010-05-17 19:29:38
|
在vivi中使用的flash有nor和nand,而mtd的作用就是提供一个中间层的驱动,实现接口函数的统一管理,这里首先介绍nand flash在mtd中的实现。
在vivi bootloader中,第6步的时候就是实现mtd中间驱动的实现,MTD驱动的函数调用关系如下:
mtd_dev_init()---->mtd_init()---->smc_init()在这里需要说明,mtd_init()函数可以按照配置调用不同的函数,包括cfi_init(),smc_init(),amd_init(),这里不同的函数对应不同的flash设备的初始化。
其中cfi_init()是intel发起的nor flash的接口标准。
smc_init()是smc智能卡接口,我们使用的nand flash使用的就是这个接口
amd_init()是AMD flash接口
在完成上面初始化以后则是增加flash命令,这部分于后面的增加命令相似(关于命令的部分在后面的章节会有专门的说明)
---->add_command(&flash_command)
下面来具体看看函数的实现,首先我们要注意到的是两个数据结构,分别是mtd_info(mtd_info是表示MTD设备的结构,每个分区也被表示为一个mtd_info,如果有两个MTD设备,每个设备有三个分区,那么在系统中就一共有6个mtd_info结构),一下是vivi中mtd_info结构
|
还有一个重要的结构nand_chip,这个结构中包含了nand flash所有的信息
|
|
首先看看上面三个结构,了解结构中包含的信息
在回来继续分析smc_init()函数,首先函数需要申请一个地址空间用来存放struct mtd_info和struct nand_chip,返回地址给mymtd
mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
定义一个nand_chip结构的变量this; struct nand_chip *this
this = (struct nand_chip *)(&mymtd[1])这个地方有必要解释一下:
其中,mymtd是指向struct mtd_info的指针,那么mymtd[1]实际上是等效于*(mymtd + 1)的数学计算模式,注意mymtd并非数组,这里仅仅利用了编译器翻译的特点。对于指针而言,加1实际上增加的指针对应类型的值,在这里地址实际上增加了sizeof(struct mtd_info),因为前面分配了两块连续的地址空间,所以&(*(mymtd + 1))实际上就是mtd_info数据结构结束的下一个地址,然后实现强制转换,于是this就成为了nand_chip的入口指针了。但是,这里必须要把握好,因为这个地方是不会进行内存的检查的,也就是说,如果你使用了mymtd[2],那么仍然按照上述公式解析,虽然可以运算,可是就是明显的指针泄漏了,可能会出现意料不到的结果。写了一个测试程序,对这点进行了探讨,要小心内存问题。(参考了CalmArrow的解释)
static int
smc_init(void)
{
struct nand_chip *this;
//u_int16_t nfconf;
u_int16_t nfcont;
/* Allocate memory for MTD device structure and private data */
mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
if (!mymtd) {
printk("Unable to allocate S3C2440 NAND MTD device structure.\n");
return -ENOMEM;
}
/* Get pointer to private data */
this = (struct nand_chip *)(&mymtd[1]);
/* Initialize structures */
memset((char *)mymtd, 0, sizeof(struct mtd_info));
memset((char *)this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
mymtd->priv = this;
/* set NAND Flash controller */
nfcont = NFCONT;
/* NAND Flash controller enable */
nfcont |= NFCONT_FCTRL_EN;
nfcont |= NFCONT_ECC_INIT;
nfcont |= NFCONT_MAINECC_LOCK;
NFCONT = nfcont;
/* Set flash memory timing */
// nfconf &= ~NFCONF_TWRPH1;
// nfconf |= NFCONF_TWRPH1_7;
// nfconf &= ~NFCONF_TWRPH0;
// nfconf |= NFCONF_TWRPH0_7;
// nfconf &= ~NFCONF_TACLS;
// nfconf &= ~NFCONF_TACLS_7;
// NFCONF = nfconf;
/* Set address of NAND IO lines */
this->hwcontrol = smc_hwcontrol;
this->write_cmd = write_cmd;
this->write_addr = write_addr;
this->read_data = read_data;
this->write_data = write_data;
this->wait_for_ready = wait_for_ready;
/* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */
//this->hwcontrol(NAND_CTL_SETNCE);
// this->write_cmd(NAND_CMD_RESET);
// this->wait_for_ready();
// this->hwcontrol(NAND_CTL_CLRNCE);
smc_insert(this);
return 0;
}
紧接着就是初始两个结构
memset((char *)mymtd, 0, sizeof(struct mtd_info));
memset((char *)this, 0, sizeof(struct nand_chip));
使得mymtd->priv指向this结构。也就是使得这两部分联系起来
设置nand flash的寄存器
NFCONT |= ((1<<0) & (1 << 4) & (1 << 5));
由于nand_chip是直接于nanf flash挂钩的,应此在此定义一些函数直接对nand flash进行操作
先看整体,再对每个细节进行分析:
this->hwcontrol = smc_hwcontrol;
this->write_cmd = write_cmd;
this->write_addr = write_addr;
this->read_data = read_data;
this->write_data = write_data;
this->wait_for_ready = wait_for_ready;
我们首先来看smc_hwcontrol函数,也就是nand flash的硬件控制,实现很简单,根据vivi中定义的情况之处理3中情况(1,2,10,其他的命令只是简单的退出)
|
|
|
|
|
等待准备好:
|