在上一节的内容里,只是初步的修改了uboot的时钟、SDRAM,让uboot在从nor启动的时候可以顺利的启动起来,然后添加了我们自己的重定位代码和对nand flash的操作,为从nand启动的时候代码重定位做准备,其实uboot还并没有可以正常的启动起来,这一节就来实现uboot的nor启动和nand启动,这节过后,我们的uboot就可以正常的启动了
1、nor启动
上一节uboot启动的时候会输出错误信息,如下
Flash: *** failed ***
在uboot里搜索这个错误在哪里,可以找到这个错误信息是在执行uboot的第二阶段代码board_init_r函数里,
可以看到这里执行了flash_init,可以看出这里函数的返回值应该是小于0的,flash_init失败,打印出下面的错误信息,然后执行了hang函数,这个函数里是一个死循环,所以,显示出来的是我们的uboot在打印出flash初始化失败之后会卡死哪里,等待重启,所以这里我们要把这个hang函数给去掉,让uboot可以往下执行
接下来,我们进入flash_init这个函数,看看我们的Nor flash到底有没有被识别出来,在这个函数里调用了flash_detect_legacy函数来检测flash,追踪这个函数,在cfi_flash.c这个文件里有两个同名的函数,一个是默认的,什么也没有做,它们是通过宏CONFIG_FLASH_CFI_LEGACY来选择的,如果没有定义这个宏需要在smdk2440.h中进行添加,flash_detect_legacy这个函数看起来不是很清楚,如果不想仔细去分析它的话可以打开宏调试开关
#define _DEBUG 1
#define DEBUG,先编译、烧写进去看它会输出什么调试信息,
在这个信息里有flash的设备ID和厂家ID,分别是c2和2249,这个是不是我们使用的flash的ID呢,我们需要去看数据手册,在MX29LV160DB的手册里可以看到,它的厂家ID是c2h,设备ID是2249,所以,我们的flash是已经被识别出来呢,既然识别出来了还是初始化失败说明uboot里并没有这款Nor flash的信息,继续往下看,找到匹配函数jedec_flash_match
可以看到在这个函数里是把刚才识别出来的信息,在一个数组里进行匹配,进去这个数组里看一下,是不是真的没有我们所需要的项,
数组里确实保存的是nor flash的信息,数组项很多我就不展示了,不过每一项都是一样的,我看了一下,确实是没有包含我们需要的flash的项存在,就需要手动添加,在这之前,先来看看这些结构体都是什么意思
.mfr_id = (u16)SST_MANUFACT, //厂家ID
.dev_id = SST39LF020, //设备ID
.name = "SST 39LF020", //名字
.uaddr = {
//解锁地址,nor flash可以像内存一样去读,但是写nor flash之前需要解锁,
我们这个flash需要往555地址发出AA,和往2AA地址发出55,555和2AA就是它的解锁地址
[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
},
.DevSize = SIZE_256KiB, //flash大小,我们是2MBit
.CmdSet = P_ID_AMD_STD, //命令集
.NumEraseRegions= 1,
//擦除块的种类,nor flash在擦除的时候结构是不一样的,选择一共有几种擦除块的大小
.regions = {
ERASEINFO(0x01000,64), //和上面对应
}
在添加之前,我们先在nor flash的数据手册里寻找我们需要的信息,
,我们的大小总共是2M,16位位宽,就是1M * 16,
这里是它的块的结构,这个信息其实就是上面我们的擦除块的结构,下面有它的详细信息
添加nor flash的信息,不再多说
{
.mfr_id = (u16)MX_MANUFACT,
.dev_id = 0x2249,
.name = "MXIC MX29LV160DB",
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_2MiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(16*1024, 1),
ERASEINFO(8*1024, 2),
ERASEINFO(32*1024, 1),
ERASEINFO(64*1024, 31),
}
},
编译,烧写进nor flash,启动 ,已经可以识别出flash的大小是2M,但是还是有错误信息
ERROR: too many flash sectors(分区太多,)修改这个问题,把限制扇区的宏修改一下
#define CONFIG_SYS_MAX_FLASH_SECT (19)
#define CONFIG_SYS_MAX_FLASH_SECT (128)
再次烧写,成功启动,使用flinfo查看分区信息,
读写nor flsh,
erase 80000 8ffff //擦除从80000开始到8ffff结束的地址
cp.b 30000000 80000 10000 //从内存里拷贝数据过去
md.b 30000000 //查看这个地址里存放的是什么
md.b 80000 //看这个地址处的数据,是否一样
已经可以满足从nor flash的启动了,但是还有一点小问题,在start.s里对栈进行了设置,但是呢在uboot的内存图里栈又被重新设置了,设置到了uboot的影像上边的区域,所以,在uboot第二阶段代码之前,我们还需要重新设置栈的位置,在start.s中进行设置
base_sp是上面定义的一个变量,在第一阶段函数里进行了赋值
重新编译、烧写即可
2、nand启动
之前编译错误的时候我们把对nand的支持给去掉了,现在需要重新打开,并添加2440的一个宏选项
为了方便 ,拷贝driver/mtd/nand/s3c2410_nand.c driver/mtd/nand s3c2440_nand.c,修改同目录下的Makefile,添加编译s3c2440_nand.c
COBJS-
(CONFIG_NAND_S3C2440) += s3c2440_nand.o
现在回到board.c里查看nand的操作,在board_init_r函数里
调用流程nand_init -> nand_init_chip -> board_nand_init ,调用到了s3c2440_nand.c中,board_nand_init这个函数比较重要,
这里是nand控制器的时序设置和必要的控制器的设置,这些就不再多说,和我们裸机代码里的一样,可以把那里的程序拿过来直接使用,注意这里的nand->select_chip函数指针原本是设置为NULL的,这里我们需要把它重新设置一下,
片选信号由nfcont寄存器的bit1提供,还有一个函数比较重要,如下,这个函数我们先记住,后面会再回来设置的
board_nand_init这个函数先看到这里,回到前面看nand_scan函数,调用到了nand_scan_ident这个函数,函数里设置了nand的一些默认的操作函数,使用函数nand_set_defaults进行设置,进去看一看
这个函数指针如果是空的话,就会重新设置一个函数,是不能用的,所以前面必须要把这个函数指针不能设置为NULL,
nand的另一个函数指针被设置为nand_command,它是用来
这个函数是对nand进行操作的可以看到ctrl一开始是被设置为NAND_CTRL_CLE,所以开始是发出命令,后面被设置为了ALE的宏,发出地址,使用chip->cmd_ctrl(mtd, command, ctrl);函数发出的,这个函数是即发出命令,又发出地址,命令和地址是通过参数ctrl进行判别的,来看一下这个函数,
s3c2440_hwcontrol这个函数是我们自己实现的,它里面会判断是发出命令还是地址,会写入到相应的寄存器里,到这里其实对nand的修改就已经完成了,看似修改的地方不多,但是注意的地方还是挺多的,比如文件里面的nand基地址在这里我没有提出来,但是在修改的时候这些必须是要去检查的,还有nand控制器的时序设置,这些是不能出错的,需要仔细一点,
好了,把我们的程序编译,烧写到nor flash里,启动,就已经可以识别出来nand flash了
然后烧写到nand flash里,启动,nor启动的时候是可以访问Nor和nand,但是nand启动的时候不能访问nor