将u-boot 2012.04.01移植到JZ2440开发板
NAND FLASH在u-boot中的初始化位置参见http://blog.csdn.net/r21nn/article/details/73718514
分析完毕NAND flash的初始化和识别过程后,这里开始执行对u-boot支持NAND flash的移植
1、首先拷贝s3c2410_nand.c一份,并改名为s3c2440_nand.c,并修改此文件中的Makefile,即增加如下一行
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
2、可以看到上一步骤中要想s3c2440_nand.o被成功连接,需要宏开关CONFIG_NAND_S3C2440,因此在smdk2440.h中增加如下两行,并将原先对于部分的S3C2410的部分注释掉
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
3、开始修改s3c2440_nand.c中的内容,首先第一步为改名,即将所有的之前2410的名字改为2440,例如s3c2410_hwcontrol改为s3c2440_hwcontrol
所以接下里的部分就是要重点关注发命令,发地址,读ID等,这里就要与具体外接的NAND FLASH联系起来,不同的NAND的读ID命令可能不一样,不过我们的开发板
的读ID命令和smdk2410完全一样,无需修改,需要修改的部分为芯片选中取消函数。
6、在nand_set_defaults中有chip->select_chip = nand_select_chip,我们只需修改nand_select_chip函数即可,修改为
而nand_command是以一页为512字节的操作函数,这里需要替换成2k字节的操作函数,u-boot中已经提供了2k的操作函数nand_command_lp,所以做如下修改
应该要修改,我猜测不修改也能行的原因可能是我们在初始化过程中写地址时只写了读ID地址(0x00>>1,0x00为NAND 看到的地址,0x00>>1为cpu发出的地址,在NAND的
数据手册中,地址均为NAND看到的地址,我们应用时需要转化为cpu看到的地址)。
8、nand_command_lp的参数为行地址和列地址,而通常情况下行地址和列地址需要多次写入,因为NAND的数据线为8位,一次只能写8为数据,以大页为例,写地址占据5个时钟 周期,2周期列地址,3周期页地址,nand_command_lp计算出具体的列地址和页地址,真正8位地址的写入交给s3c2440_hwcontrol,这个函数在u-boot可以简化,简化如下
NAND FLASH在u-boot中的初始化位置参见http://blog.csdn.net/r21nn/article/details/73718514
NAND的初始化函数为nand_init,先来看一看各函数的调用流程
nand_init
-->board_nand_init
-->时序设置(NCONF),NAND使能(NCONT)
-->nand->cmd_ctrl = s3c2440_hwcontrol
-->nand->dev_ready = s3c2440_dev_ready
-->nand_init_chip
-->board_nand_init
-->nand_scan
-->nand_scan_ident
-->nand_set_defaults(s3c2440对于NAND操作的各种默认函数)
-->chip->cmdfunc = nand_command
-->chip->waitfunc = nand_wait
-->chip->select_chip = nand_select_chip
-->......
-->chip->controller = &chip->hwcontrol
-->nand_get_flash_type(这个函数中进行读取厂家ID和设备ID,与nand_flash_ids表比对,看是否支持读到的NAND)
-->chip->select_chip(mtd, 0)
-->chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1)
-->chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1)
-->*maf_id = chip->read_byte(mtd)
-->*dev_id = chip->read_byte(mtd)
-->......
-->nand_scan_tail
因为一直u-boot对JZ2440的支持,是以smdk2410为基本的,所以我们先看看s3c2440和s2c2410的NAND控制器的差别s3c2410的NAND控制器提供了NFCONF,NFCMD,NFADDR,NFDATA,NFSTAT,NFECC等六个寄存器来控制其外接的NADN FLASHs3c2440的NAND控制器提供了NFCONF,NFCONT,NFCMD,NFADDR,NFSTAT和其他ECC相关的寄存器来控制其外接的NAND FLASH。
首先不谈其外接的NAND FLASH的不同,只从NAND控制器本身出发来比较一下两者的不同s3c2410的NFCONF寄存器用来使能NAND FLASH控制器,使能控制引脚信号nFCE,初始化信号ECC,设置NAND flash的时序信号而在S3C2440中,这部分功由两个寄存器来完成
NFCONF:设置时序和位宽
NFCONT:使能NADN FLASH控制器,使能控制信号引脚,初始化ECC
所以在smdk2410中涉及上述内容的代码都应该要修改分析完毕NAND flash的初始化和识别过程后,这里开始执行对u-boot支持NAND flash的移植
1、首先拷贝s3c2410_nand.c一份,并改名为s3c2440_nand.c,并修改此文件中的Makefile,即增加如下一行
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
2、可以看到上一步骤中要想s3c2440_nand.o被成功连接,需要宏开关CONFIG_NAND_S3C2440,因此在smdk2440.h中增加如下两行,并将原先对于部分的S3C2410的部分注释掉
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
3、开始修改s3c2440_nand.c中的内容,首先第一步为改名,即将所有的之前2410的名字改为2440,例如s3c2410_hwcontrol改为s3c2440_hwcontrol
4、开始修改具体的函数内容,根据nand_init的执行流程来修改,知道首先修改board_nand_init,时序设置和相关部分的使能都需要修改
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
改为
#define S3C2410_NFCONF_TACLS(x) ((x)<<12)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4)
5、上面完成对NAND FLASH的初始化,接下来就是要读取NAND FLASH的厂家ID与设备ID,与u-boot支持的NAND FLASH表进行比对,看是否支持此种NAND FLASH
所以接下里的部分就是要重点关注发命令,发地址,读ID等,这里就要与具体外接的NAND FLASH联系起来,不同的NAND的读ID命令可能不一样,不过我们的开发板
的读ID命令和smdk2410完全一样,无需修改,需要修改的部分为芯片选中取消函数。
6、在nand_set_defaults中有chip->select_chip = nand_select_chip,我们只需修改nand_select_chip函数即可,修改为
static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
switch (chipnr) {
case -1:
nand->nfcont |= (1<<1);
break;
case 0:
nand->nfcont &= ~(1<<1);
break;
default:
BUG();
}
}
7、在nand_get_flash_type函数为读取NAND ID并比对识别的过程,在这个过程中cmdfunc是一个很重要的函数,现在看一下这个函数调用过程
cmdfunc = nand_command
-->cmd_ctrl = s3c2440_hwcontrol
这里nand_command是一个很重要的函数,它承担了写命令与地址的任务,这个函数时根具体的NAND FLASH相关的,JZ2440中的NAND为大页,一页为2k大小
而nand_command是以一页为512字节的操作函数,这里需要替换成2k字节的操作函数,u-boot中已经提供了2k的操作函数nand_command_lp,所以做如下修改
chip->cmdfunc = nand_command
改为
chip->cmdfunc = nand_command_lp
在韦东山老师的毕业班NAND FLASH的移植视频中,这一块并没有修改,我将修改与不修改两种情况都实验过,发现都是可行的,不过对于大页的NAND FLASH还是
应该要修改,我猜测不修改也能行的原因可能是我们在初始化过程中写地址时只写了读ID地址(0x00>>1,0x00为NAND 看到的地址,0x00>>1为cpu发出的地址,在NAND的
数据手册中,地址均为NAND看到的地址,我们应用时需要转化为cpu看到的地址)。
8、nand_command_lp的参数为行地址和列地址,而通常情况下行地址和列地址需要多次写入,因为NAND的数据线为8位,一次只能写8为数据,以大页为例,写地址占据5个时钟 周期,2周期列地址,3周期页地址,nand_command_lp计算出具体的列地址和页地址,真正8位地址的写入交给s3c2440_hwcontrol,这个函数在u-boot可以简化,简化如下
static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
if (ctrl & NAND_CLE)
{
writeb(cmd,&nand->nfcmd);
}
else if (ctrl & NAND_ALE)
{
writeb(cmd,&nand->nfaddr);
}
}
9、到这里为止整改u-boot的移植就已经结束了,不过我们可以看一看,u-boot支持的NAND FLASH类型,所有支持的类型都记录在nand_flash_ids数组中下面截取这个数组的一部分
/* 1 Gigabit */
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 3,3V 8-bit", 0xD1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
{"NAND 128MiB 1,8V 16-bit", 0xAD, 0, 128, 0, LP_OPTIONS16},
/* 2 Gigabit */
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS}, /*这一项即为JZ2440中外接的K9F2G08U0C,设备ID为0xDA*/
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
/* 4 Gigabit */
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
/* 8 Gigabit */
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},