2007.8.13
u-boot
1.在网上找了几个u-boot的移植文档,之前一直没有成功,后来,设置好u-boot的程序运行地址后,make clean && make at91rm9200dk_config && make ,生成u-boot.bin文件。
2.在调试好arm9200的仿真器后,选择File->Load memory from file ,选择u-boot.bin 文件。
3.文件Load 成功以后,将PC指针设置为u-boot程序的运行地址。
4.执行程序,即可在串口终端看到u-boot的提示符。
2007.8.14
1.发现在文件Start.S中调用了LowLevelInit函数,初始化SDRAM,终端,DEBUG串口,NAND等,根据需要添加。在u-boot中没有进行LowLevelInit,所以会出现初始化不正确的时候会有问题。
2.经常会出现IIC不能写的状况,原因不明。
3.AXD调试的时候,经常要重启才可以。有时候要进行断电。
4.u-boot的程序启动地址在board/at91rm9200dk/config.mk中修改TEXT_BASE的值
2007.8.15
1.研究PMC时钟是怎么回事,给个时钟是如何产生的,看数据手册的方框图。
设置master clock 的寄存器,选择使用slow clock ,main clock,plla,pllb中的一个作为时钟输入,通过master clock controller后生成master clock 和process clock.选择的plla和pllb可以通过设置相应的寄存器来倍频main clock.
1.u-boot-
文件从flash中读取到sdram中的内存的位置不是这个地址,也还是可以启动的。所以,之前的bios9200的代码完全不用作任何的改变,就可以将u-boot烧写到nand flash上,并且读入内存,启动u-boot。之前虽然也进行过直接烧写的工作,但是可能是u-boot中的代码,初始化的串口有问题,造成没有什么输出,显示的。现在代码中写死了。
2.阅读了一下bios9200的代码,关键的部分在于,不同的板子,要进行不同的LowLevelInit工作的,所以之前的at91rm9200_for_Uboot,不能够使用,也是因为LowLevelInit初始化的可能有些问题,在u-boot 启动的时候,按照网上的修改方法,并没有进行LowLevelInit,所以出现问题。
3.u-boot的移植配置,参看以下文章
开发板H FLSH: [编辑] [编辑]
[编辑]
[编辑] [编辑] board 目标板相关文件,比如Makefile和u-boot.lds等都和具体的开发板的硬件和地址分配有关; [编辑] 1、增加目标平台到./board/下(此步骤可选,主要为了不影响源码) 因为我们当前平台h cd u-boot- 2、进入./include/configs下 以at91rm9200dk.h为模板,生成h cd u-boot- 3、修改Makefile以及 编辑源码根目录下的Makefile,搜索at91rm9200, vi u-boot- 4、根据具体的硬件配置,修改参数 因为在at91rm9200引导时,厂商提供了前期初始化的boot.bin,它主要作了部分的硬件初始化,替代U-boot的 stage1部分,所以在U-boot中就应该去掉这部分功能,不然会导致重复配置,使U-boot在初始配置时当掉,因此我们要修改. /include/configs/h vi u-boot- 5、下面我们要进行针对板子的具体化设置 编辑./board/h 将gd->bd->bi_arch_number = MACH_TYPE_AT91RM9200; 再编辑./include/asm-arm/mach-types.h,跳转到第740行,添加硬件设备的ID号,我们在这里使用1888作为h #define MACH_TYPE_H 这样我们的开发板就有自己的设备号了,不过kernel是不成认的,如果你想让全世界人都承认,你还要到www.kernel.com去申请你的设备,这样一来所有内核源码中都会有这一段代码了;上面的做法仅用来测试使用。 (至此一个可以启动的U-boot就已经完成了) [编辑] a.PC宿主机设置 在windows下,打开超级终端,设置串口为115200 8N1 无流控 b.JP100设置为2-3短接,从片内rom启动,启动片内ROM中的程序。上电,复位,超级终端下出现”CCCCCCC” c.用Xmodem协议发送loader.bin,发完继续出现”CCCCCC” d.再用Xmodem协议发送u-boot.bin,发完显示>U-Boot>提示符 e.擦除FLASH: >protect off all 上述两步擦除FLASH中所有内容,若只擦除uboot所占部分,则 >protect off 10000000 1001FFFF 或(待证实) >protect off 1:0-1 f.装入boot.bin >loadb 20000000 (能过串口线(Kermit mode)来装载二进制文件) 在超级终端下,用kermit模式发送boot.bin >cp.b 20000000 10000000 5ffff g.装入u-boot.gz >loadb 20000000 用kermit模式发送u-boot.gz >cp.b 20000000 10010000 ffff h.JP100设置为1-2短接,从flash启动,启动Flash中固化的程序。 [编辑] a.网络参数设置 >setenv ethaddr 12:34:56:78:99:aa ;MAC地址 b.系统自动运行 注意:这里设置为络服务器启动模式,用网线从主机上下载内核和文件系统到SDRAM中,每次掉电后都要重新开始。 >setenv bootargs root=/dev/ram rw initrd=0x21100000,6000000 ramdisk_size=15360 initrd指定根文件系统的位置 >setenv bootcmd tftp 21000000 uimage/; tftp 21100000 ramdisk.gz/; bootm 21000000 设定自动启动脚本,先用tftp下载内核镜象到21000000 ,然后下载文件系统到21100000,再从内核镜象地址21000000启动 注意:必须确保主机上启动了tftp服务,在根目录上有tftpboot目录。可用rpm –q tftp查看是否安装了tftp,若没有的话,则需要安装。在服务配置里选定tftp服务,开始。设置开机时自动启动tftp服务。执行ntsysv命 令,然后选择需要开机自动启动的服务,nfs,tftp等,以空格选择。 在linux下的终端执行minicom,则启动串口终端,可以用minicom –s设置。 |
主要参看了网上的几篇文章,http://bbs2.chinaunix.net/viewthread.php?tid=855860
http://www.lupaworld.com/23340/viewspace_4343.html
重点内容如下部分:
对于uboot的移植请参考我之前写的《U-Boot的编译与移植到QT-S3C44B0X开发板上》http://bbs.chinaunix.net/viewthr ... p;highlight=pywj777
非常感谢dozec的《基于S3C2410的Linux全线移植文档》http://bbs.chinaunix.net/viewthr ... 的Linux全线移植文档我的nand flash移植大部分是参考这个文档移植成功的。
下面对nand flash的初始化代码nand_init()进行分析:
1.如果定义(CONFIG_COMMANDS & CFG_CMD_NAND)没定义(CFG_NAND_LEGACY) 则start_armboot()调用driver/nand/nand.c中的nand_init(),否则如果定义(CONFIG_COMMANDS & CFG_CMD_NAND)并且有定义了CFG_NAND_LEGACY,则调用自己定义的nand_init()。在我当前的情景中是使用driver/nand/nand.c中的nand_init()。
2.nand_init()调用本文件中的nand_init_chip()对nand进行初始化。
3.nand_init_chip()首先调用board_nand_init()。
4.board_nand_init()是需要自己添加的函数,这个函数的主要功能是对struct nand_chip结构体的函数指针赋值,让它们指向自己为nand驱动编写的一些函数,对未赋值的指针,uboot会在后面为其赋上通用nand驱动函数指针。
5.nand_init_chip()接着调用nand_scan().
6.nand_scan()定义在drivers/nand/nand_base.c文件中。它首先对struct nand_chip结构体中在board_nand_init()函数中未赋值的指针赋上通用nand驱动函数指针。
7.通用nand驱动函数nand_select_chip()赋值给struct nand_chip结构体的函数指针用于打开或关闭nand芯片,0为打开,1为关闭。在这个函数中会调用nand_chip结构体中的hwcontrol函数指针,这个指针指向的函数是需要自己编写的。这个函数指针在board_nand_init()函数中被赋值。主要作用是向nand flash发送一些nand flash开启与关闭命令。
8.nand_scan()剩余部分初始化nand_chip和mtd_info结构体。
9.nand_scan()最后在返回时调用drivers/nand/nand_bbt.c文件中的nand_default_bbt()。
10.nand_default_bby()选择一个坏块描述表,返回时调用本文件中的nand_scan_bbt()。
11.nand_scan_bbt()寻找建立一个坏块描述表。
12.最后返回到nand_init(),这样nand驱动的初始化完成了。
下面对命令nand read addr ofs size的执行流程进行分析:
1.nand read addr ofs size命令的作用是从nand flash地址的偏移量ofs处读取长度为size字节的数据存储到内存地址addr处。
2.common/main.c文件中的main_loop()主要执行read_line()读取命令行。
3.read_line()读取到命令行后会调用common/main.c文件中的run_command()。
4.run_command()调用common/command.c文件中的find_cmd()在.u_boot_cmd段中寻找该命令的cmd_tbl_t结构,找到后返回该结构。该命令的结构是通过定义在include/command.h中的宏定义U_BOOT_CMD登记进.u_boot_cmd段中的。
5.run_command()找到该命令的cmd_tbl_t结构后则执行该命令对应的函数。对于本情景是nand命令对应的函数do_nand()。
6.do_nand()有两个版本,一个是定义了CFG_NAND_LEGACY。另一个是未定义CFG_NAND_LEGACY。这两个版本都定义在common/cmd_nand.c文件中。对于本情景使用未定义CFG_NAND_LEGACY的do_nand()函数。要使用do_nand()还必须定义宏CONFIG_COMMANDS&CFG_CMD_NAND。(若未定义CFG_NAND_LEGACY则在这个情景中的do_nand()函数调用的函数都定义在drivers/nand_legacy/nand_legacy.c文件中)。
7.对于我们的情景do_nand()会调用定义在include/nand.h文件中的nand_read()。
8.nand_read()则调用本nand芯片对应的nand_info_t结构的read指针。而read指针在nand_scan()中被指向了同文件(drivers/nand/nand_base.c)中的nand_read()函数。
9.nand_read()函数最终会调用nand_chip结构中的cmdfunc指针,通过这个指针指向的函数向nand flash芯片发送命令。最终完成整个命令的执行。
为了让uboot支持自己QT板子的nand flash而进行修改的部分
1.前面的移植请参考我写的一篇《U-Boot的编译与移植到QT-S3C44B0X开发板上》,现在在board/51EDA/QT/目录下建立nand.c文件。
2.在nand.c中添加自己的board_nand_init()函数。设定nand_chip结构中的hwcontrol和dev_ready指针指向自己的函数QT_hwcontrol和QT_device_ready。并建立自己的QT_hwcontrol和QT_device_ready函数。
3.由于自己板子的nand flash的命令发送方式与uboot提供的通用nand flash命令发送方式不同,所以在nand.c文件中建立自己的命令发送函数QT_nand_command(),并在board_nand_init()函数中将nand_chip结构中的cmdfunc指针指向QT_nand_command()函数,使其使用自己定义的发送命令函数。
4.在include/configs/QT.h中定义CFG_NAND_BASE用于指定自己板子nand flash的I/O地址。
5.在CONFIG_COMMANDS中打开CFG_CMD_NAND选项。
6.在include/configs/QT.h中定义NAND_MAX_CHIPS指定自己板子的nand flash芯片数。
7.在include/configs/QT.h中定义CFG_MAX_NAND_DEVICE指定想要支持的nand flash设备数。
dozec的《基于S3C2410的Linux全线移植文档》在U-BOOT对Nand Flash的支持中的移植方法是在定义了CFG_NAND_LEGACY情况下移植的。而我的是在未定义CFG_NAND_LEGACY的情况下移植的。
基于以上的分析,仔细阅读u-boot的代码主要修改board/at91rm9200dk/at91rm9200dk.c
/*
* Disk On Chip (NAND) Millenium initialization.
* The NAND lives in the CS2* space
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe (ulong physadr);
#define AT91_SMARTMEDIA_BASE 0x40000000 /* physical address to access memory on NCS3 */
void nand_init (void)
{
/* Setup Smart Media, fitst enable the address range of CS3 */
*AT
//CFGR
#define AT
#define AT
AT
//根据不同的flash 对寄存器进行相应的设置
/* AT
AT
SM_TDF | AT
AT
AT
(AT
(AT
AT
/* enable the SMOE line PC0=SMCE, A21=CLE, A22=ALE */
*AT
AT
*AT
AT
//flash CE接PC15 RE接PC14,所以进行以下配置,根据不同的板子来
*AT
//enable PC14 bid output
*AT
*AT
//pull-up 14
AT
AT
//enable pc15 for output
*AT
AT
//进行短暂的延时
int j;
for(j=0;j<50000;j++);
printf ("%4lu MB/n", nand_probe(AT91_SMARTMEDIA_BASE) >> 20);
}
修改配置文件include/configs/at91rm9200dk.h中关于nand flash的宏定义
//增加nand的命令支持
#define CONFIG_COMMANDS /
((CONFIG_CMD_DFL | CFG_CMD_MII |/
CFG_CMD_DHCP | CFG_CMD_NAND ) & /
~(CFG_CMD_BDI | /
CFG_CMD_IMI | /
CFG_CMD_AUTOSCRIPT | /
CFG_CMD_FPGA | /
CFG_CMD_MISC | /
CFG_CMD_LOADS ))
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
//#include <asm/arch/AT91RM9200.h>
#define CFG_NAND_LEGACY 1 //使用board/at91rm9200dk/at91rm9200dk.c中的nand_init()函数和driver/nand_legacy/nand_legacy.c中的函数,如果不定义,使用driver/nand/nand.c中的nand_init()
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
#define NAND_ChipID_UNKNOWN 0x00
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
//my ale cle 这个不是很明白,应该根据你的板子上的连接来设置,看你的flash 上的cle和ale分别接的是那一根地址线
#define AT91_SMART_MEDIA_ALE (1 << 21) /* our ALE is AD21 */
#define AT91_SMART_MEDIA_CLE (1 << 22) /* our CLE is AD22 */
//PC15接的是CE,PC14接的是RE
#define NAND_DISABLE_CE(nand) do { *AT
#define NAND_ENABLE_CE(nand) do { *AT
#define NAND_WAIT_READY(nand) while (!(*AT
#define WRITE_NAND_COMMAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_CLE) = (__u8)(d); } while(0)
#define WRITE_NAND_ADDRESS(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_ALE) = (__u8)(d); } while(0)
#define WRITE_NAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr) = (__u8)d; } while(0)
#define READ_NAND(adr) ((volatile unsigned char)(*(volatile __u8 *)(unsigned long)adr))
/* the following are NOP's in our implementation */
//要进行修改,按以下定义
#define NAND_CTL_CLRALE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_ALE))
#define NAND_CTL_SETALE(nandptr) (nandptr|AT91_SMART_MEDIA_ALE)
#define NAND_CTL_CLRCLE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_CLE))
#define NAND_CTL_SETCLE(nandptr) (nandptr|AT91_SMART_MEDIA_CLE)
1.解决环境变量env的存储问题。
描述:在cmd_nvedit.c中,检查环境变量存储在那里。可选的有 CFG_ENV_IS_IN_NVRAM
CFG_ENV_IS_IN_EEPROM
CFG_ENV_IS_IN_FLASH
CFG_ENV_IS_IN_DATAFLASH
CFG_ENV_IS_IN_NAND
CFG_ENV_IS_NOWHERE
在include/configs/at91rm9200.h中定义其中的一种就可以,因为还没有搞好I
#define CFG_ENV_IS_IN_NAND
#define CFG_ENV_OFFSET 0x40000 //环境变量存储位置偏移
#define CFG_ENV_SIZE 0x20000 //环境变量存储大小
#define CFG_ENV_ADDR 0x40040000
并且注释掉其他的ENV的设置。
由于nand的驱动使用了nand_legacy.c中的nand接口函数。所以要修改common/env_nand.c中的saveenv 函数和env_relocate_spec函数。
int saveenv(void)
{
ulong total;
int ret = 0;
puts ("Erasing Nand...");
/*
if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
return 1;
*/
if (nand_legacy_erase(&nand_dev_desc[0], CFG_ENV_OFFSET, CFG_ENV_SIZE,1))
return 1;
puts ("Writing to Nand... ");
total = CFG_ENV_SIZE;
/*
ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return 1;
*/
ret = nand_legacy_rw(&nand_dev_desc[0] , 0x00 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
puts ("done/n");
return ret;
}
/*
* The legacy NAND code saved the environment in the first NAND device i.e.,
* nand_dev_desc + 0. This is also the behaviour using the new NAND code.
*/
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
ulong total;
int ret;
total = CFG_ENV_SIZE;
// ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
ret = nand_legacy_rw(&nand_dev_desc[0], 0x01 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return use_default();
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}
内核与文件系统移植成功。其中经历了不少的问题。主要是这么几个方面:
1. 在uboot中的bootargs的设置,init=/linuxrc console=/dev/ttyS0,115200 root=/dev/mtdblock2。
2. 自动启动内核的时候,bootcmd的设置在内核中要给nand flash 分好区的,在第三个分区烧写上文件系统。
3. 编译busybox,写好rcS文件。
1.明确的几个问题。
1)在当前的启动方式下,uboot仅仅相当于提供了方便的方式下载内核,文件系统的任务,如何能够让uboot自己完成启动的全部任务。目前为eeprom中的bios程序,调用烧写在nand flash上的uboot,完成启动。但是bios要是从nand flash上读出uboot,就必须移植nand flash的驱动才可以,这样相当于bios也可以完成烧写nand flash的任务。那么是不是有办法让uboot烧写在eeprom中,自己启动的。
2.出现不能初始化console的错误的时候,可能是/dev没有加载,在编译内核的时候,要选中自动加载/dev在boot的时候,这个选项。不然程序会因为找不到/dev/console出错。
2007.8.13
u-boot
1.在网上找了几个u-boot的移植文档,之前一直没有成功,后来,设置好u-boot的程序运行地址后,make clean && make at91rm9200dk_config && make ,生成u-boot.bin文件。
2.在调试好arm9200的仿真器后,选择File->Load memory from file ,选择u-boot.bin 文件。
3.文件Load 成功以后,将PC指针设置为u-boot程序的运行地址。
4.执行程序,即可在串口终端看到u-boot的提示符。
2007.8.14
1.发现在文件Start.S中调用了LowLevelInit函数,初始化SDRAM,终端,DEBUG串口,NAND等,根据需要添加。在u-boot中没有进行LowLevelInit,所以会出现初始化不正确的时候会有问题。
2.经常会出现IIC不能写的状况,原因不明。
3.AXD调试的时候,经常要重启才可以。有时候要进行断电。
4.u-boot的程序启动地址在board/at91rm9200dk/config.mk中修改TEXT_BASE的值
2007.8.15
1.研究PMC时钟是怎么回事,给个时钟是如何产生的,看数据手册的方框图。
设置master clock 的寄存器,选择使用slow clock ,main clock,plla,pllb中的一个作为时钟输入,通过master clock controller后生成master clock 和process clock.选择的plla和pllb可以通过设置相应的寄存器来倍频main clock.
1.u-boot-
文件从flash中读取到sdram中的内存的位置不是这个地址,也还是可以启动的。所以,之前的bios9200的代码完全不用作任何的改变,就可以将u-boot烧写到nand flash上,并且读入内存,启动u-boot。之前虽然也进行过直接烧写的工作,但是可能是u-boot中的代码,初始化的串口有问题,造成没有什么输出,显示的。现在代码中写死了。
2.阅读了一下bios9200的代码,关键的部分在于,不同的板子,要进行不同的LowLevelInit工作的,所以之前的at91rm9200_for_Uboot,不能够使用,也是因为LowLevelInit初始化的可能有些问题,在u-boot 启动的时候,按照网上的修改方法,并没有进行LowLevelInit,所以出现问题。
3.u-boot的移植配置,参看以下文章
开发板H FLSH: [编辑] [编辑]
[编辑]
[编辑] [编辑] board 目标板相关文件,比如Makefile和u-boot.lds等都和具体的开发板的硬件和地址分配有关; [编辑] 1、增加目标平台到./board/下(此步骤可选,主要为了不影响源码) 因为我们当前平台h cd u-boot- 2、进入./include/configs下 以at91rm9200dk.h为模板,生成h cd u-boot- 3、修改Makefile以及 编辑源码根目录下的Makefile,搜索at91rm9200, vi u-boot- 4、根据具体的硬件配置,修改参数 因为在at91rm9200引导时,厂商提供了前期初始化的boot.bin,它主要作了部分的硬件初始化,替代U-boot的 stage1部分,所以在U-boot中就应该去掉这部分功能,不然会导致重复配置,使U-boot在初始配置时当掉,因此我们要修改. /include/configs/h vi u-boot- 5、下面我们要进行针对板子的具体化设置 编辑./board/h 将gd->bd->bi_arch_number = MACH_TYPE_AT91RM9200; 再编辑./include/asm-arm/mach-types.h,跳转到第740行,添加硬件设备的ID号,我们在这里使用1888作为h #define MACH_TYPE_H 这样我们的开发板就有自己的设备号了,不过kernel是不成认的,如果你想让全世界人都承认,你还要到www.kernel.com去申请你的设备,这样一来所有内核源码中都会有这一段代码了;上面的做法仅用来测试使用。 (至此一个可以启动的U-boot就已经完成了) [编辑] a.PC宿主机设置 在windows下,打开超级终端,设置串口为115200 8N1 无流控 b.JP100设置为2-3短接,从片内rom启动,启动片内ROM中的程序。上电,复位,超级终端下出现”CCCCCCC” c.用Xmodem协议发送loader.bin,发完继续出现”CCCCCC” d.再用Xmodem协议发送u-boot.bin,发完显示>U-Boot>提示符 e.擦除FLASH: >protect off all 上述两步擦除FLASH中所有内容,若只擦除uboot所占部分,则 >protect off 10000000 1001FFFF 或(待证实) >protect off 1:0-1 f.装入boot.bin >loadb 20000000 (能过串口线(Kermit mode)来装载二进制文件) 在超级终端下,用kermit模式发送boot.bin >cp.b 20000000 10000000 5ffff g.装入u-boot.gz >loadb 20000000 用kermit模式发送u-boot.gz >cp.b 20000000 10010000 ffff h.JP100设置为1-2短接,从flash启动,启动Flash中固化的程序。 [编辑] a.网络参数设置 >setenv ethaddr 12:34:56:78:99:aa ;MAC地址 b.系统自动运行 注意:这里设置为络服务器启动模式,用网线从主机上下载内核和文件系统到SDRAM中,每次掉电后都要重新开始。 >setenv bootargs root=/dev/ram rw initrd=0x21100000,6000000 ramdisk_size=15360 initrd指定根文件系统的位置 >setenv bootcmd tftp 21000000 uimage/; tftp 21100000 ramdisk.gz/; bootm 21000000 设定自动启动脚本,先用tftp下载内核镜象到21000000 ,然后下载文件系统到21100000,再从内核镜象地址21000000启动 注意:必须确保主机上启动了tftp服务,在根目录上有tftpboot目录。可用rpm –q tftp查看是否安装了tftp,若没有的话,则需要安装。在服务配置里选定tftp服务,开始。设置开机时自动启动tftp服务。执行ntsysv命 令,然后选择需要开机自动启动的服务,nfs,tftp等,以空格选择。 在linux下的终端执行minicom,则启动串口终端,可以用minicom –s设置。 |
主要参看了网上的几篇文章,http://bbs2.chinaunix.net/viewthread.php?tid=855860
http://www.lupaworld.com/23340/viewspace_4343.html
重点内容如下部分:
对于uboot的移植请参考我之前写的《U-Boot的编译与移植到QT-S3C44B0X开发板上》http://bbs.chinaunix.net/viewthr ... p;highlight=pywj777
非常感谢dozec的《基于S3C2410的Linux全线移植文档》http://bbs.chinaunix.net/viewthr ... 的Linux全线移植文档我的nand flash移植大部分是参考这个文档移植成功的。
下面对nand flash的初始化代码nand_init()进行分析:
1.如果定义(CONFIG_COMMANDS & CFG_CMD_NAND)没定义(CFG_NAND_LEGACY) 则start_armboot()调用driver/nand/nand.c中的nand_init(),否则如果定义(CONFIG_COMMANDS & CFG_CMD_NAND)并且有定义了CFG_NAND_LEGACY,则调用自己定义的nand_init()。在我当前的情景中是使用driver/nand/nand.c中的nand_init()。
2.nand_init()调用本文件中的nand_init_chip()对nand进行初始化。
3.nand_init_chip()首先调用board_nand_init()。
4.board_nand_init()是需要自己添加的函数,这个函数的主要功能是对struct nand_chip结构体的函数指针赋值,让它们指向自己为nand驱动编写的一些函数,对未赋值的指针,uboot会在后面为其赋上通用nand驱动函数指针。
5.nand_init_chip()接着调用nand_scan().
6.nand_scan()定义在drivers/nand/nand_base.c文件中。它首先对struct nand_chip结构体中在board_nand_init()函数中未赋值的指针赋上通用nand驱动函数指针。
7.通用nand驱动函数nand_select_chip()赋值给struct nand_chip结构体的函数指针用于打开或关闭nand芯片,0为打开,1为关闭。在这个函数中会调用nand_chip结构体中的hwcontrol函数指针,这个指针指向的函数是需要自己编写的。这个函数指针在board_nand_init()函数中被赋值。主要作用是向nand flash发送一些nand flash开启与关闭命令。
8.nand_scan()剩余部分初始化nand_chip和mtd_info结构体。
9.nand_scan()最后在返回时调用drivers/nand/nand_bbt.c文件中的nand_default_bbt()。
10.nand_default_bby()选择一个坏块描述表,返回时调用本文件中的nand_scan_bbt()。
11.nand_scan_bbt()寻找建立一个坏块描述表。
12.最后返回到nand_init(),这样nand驱动的初始化完成了。
下面对命令nand read addr ofs size的执行流程进行分析:
1.nand read addr ofs size命令的作用是从nand flash地址的偏移量ofs处读取长度为size字节的数据存储到内存地址addr处。
2.common/main.c文件中的main_loop()主要执行read_line()读取命令行。
3.read_line()读取到命令行后会调用common/main.c文件中的run_command()。
4.run_command()调用common/command.c文件中的find_cmd()在.u_boot_cmd段中寻找该命令的cmd_tbl_t结构,找到后返回该结构。该命令的结构是通过定义在include/command.h中的宏定义U_BOOT_CMD登记进.u_boot_cmd段中的。
5.run_command()找到该命令的cmd_tbl_t结构后则执行该命令对应的函数。对于本情景是nand命令对应的函数do_nand()。
6.do_nand()有两个版本,一个是定义了CFG_NAND_LEGACY。另一个是未定义CFG_NAND_LEGACY。这两个版本都定义在common/cmd_nand.c文件中。对于本情景使用未定义CFG_NAND_LEGACY的do_nand()函数。要使用do_nand()还必须定义宏CONFIG_COMMANDS&CFG_CMD_NAND。(若未定义CFG_NAND_LEGACY则在这个情景中的do_nand()函数调用的函数都定义在drivers/nand_legacy/nand_legacy.c文件中)。
7.对于我们的情景do_nand()会调用定义在include/nand.h文件中的nand_read()。
8.nand_read()则调用本nand芯片对应的nand_info_t结构的read指针。而read指针在nand_scan()中被指向了同文件(drivers/nand/nand_base.c)中的nand_read()函数。
9.nand_read()函数最终会调用nand_chip结构中的cmdfunc指针,通过这个指针指向的函数向nand flash芯片发送命令。最终完成整个命令的执行。
为了让uboot支持自己QT板子的nand flash而进行修改的部分
1.前面的移植请参考我写的一篇《U-Boot的编译与移植到QT-S3C44B0X开发板上》,现在在board/51EDA/QT/目录下建立nand.c文件。
2.在nand.c中添加自己的board_nand_init()函数。设定nand_chip结构中的hwcontrol和dev_ready指针指向自己的函数QT_hwcontrol和QT_device_ready。并建立自己的QT_hwcontrol和QT_device_ready函数。
3.由于自己板子的nand flash的命令发送方式与uboot提供的通用nand flash命令发送方式不同,所以在nand.c文件中建立自己的命令发送函数QT_nand_command(),并在board_nand_init()函数中将nand_chip结构中的cmdfunc指针指向QT_nand_command()函数,使其使用自己定义的发送命令函数。
4.在include/configs/QT.h中定义CFG_NAND_BASE用于指定自己板子nand flash的I/O地址。
5.在CONFIG_COMMANDS中打开CFG_CMD_NAND选项。
6.在include/configs/QT.h中定义NAND_MAX_CHIPS指定自己板子的nand flash芯片数。
7.在include/configs/QT.h中定义CFG_MAX_NAND_DEVICE指定想要支持的nand flash设备数。
dozec的《基于S3C2410的Linux全线移植文档》在U-BOOT对Nand Flash的支持中的移植方法是在定义了CFG_NAND_LEGACY情况下移植的。而我的是在未定义CFG_NAND_LEGACY的情况下移植的。
基于以上的分析,仔细阅读u-boot的代码主要修改board/at91rm9200dk/at91rm9200dk.c
/*
* Disk On Chip (NAND) Millenium initialization.
* The NAND lives in the CS2* space
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe (ulong physadr);
#define AT91_SMARTMEDIA_BASE 0x40000000 /* physical address to access memory on NCS3 */
void nand_init (void)
{
/* Setup Smart Media, fitst enable the address range of CS3 */
*AT
//CFGR
#define AT
#define AT
AT
//根据不同的flash 对寄存器进行相应的设置
/* AT
AT
SM_TDF | AT
AT
AT
(AT
(AT
AT
/* enable the SMOE line PC0=SMCE, A21=CLE, A22=ALE */
*AT
AT
*AT
AT
//flash CE接PC15 RE接PC14,所以进行以下配置,根据不同的板子来
*AT
//enable PC14 bid output
*AT
*AT
//pull-up 14
AT
AT
//enable pc15 for output
*AT
AT
//进行短暂的延时
int j;
for(j=0;j<50000;j++);
printf ("%4lu MB/n", nand_probe(AT91_SMARTMEDIA_BASE) >> 20);
}
修改配置文件include/configs/at91rm9200dk.h中关于nand flash的宏定义
//增加nand的命令支持
#define CONFIG_COMMANDS /
((CONFIG_CMD_DFL | CFG_CMD_MII |/
CFG_CMD_DHCP | CFG_CMD_NAND ) & /
~(CFG_CMD_BDI | /
CFG_CMD_IMI | /
CFG_CMD_AUTOSCRIPT | /
CFG_CMD_FPGA | /
CFG_CMD_MISC | /
CFG_CMD_LOADS ))
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
//#include <asm/arch/AT91RM9200.h>
#define CFG_NAND_LEGACY 1 //使用board/at91rm9200dk/at91rm9200dk.c中的nand_init()函数和driver/nand_legacy/nand_legacy.c中的函数,如果不定义,使用driver/nand/nand.c中的nand_init()
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
#define NAND_ChipID_UNKNOWN 0x00
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
//my ale cle 这个不是很明白,应该根据你的板子上的连接来设置,看你的flash 上的cle和ale分别接的是那一根地址线
#define AT91_SMART_MEDIA_ALE (1 << 21) /* our ALE is AD21 */
#define AT91_SMART_MEDIA_CLE (1 << 22) /* our CLE is AD22 */
//PC15接的是CE,PC14接的是RE
#define NAND_DISABLE_CE(nand) do { *AT
#define NAND_ENABLE_CE(nand) do { *AT
#define NAND_WAIT_READY(nand) while (!(*AT
#define WRITE_NAND_COMMAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_CLE) = (__u8)(d); } while(0)
#define WRITE_NAND_ADDRESS(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_ALE) = (__u8)(d); } while(0)
#define WRITE_NAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr) = (__u8)d; } while(0)
#define READ_NAND(adr) ((volatile unsigned char)(*(volatile __u8 *)(unsigned long)adr))
/* the following are NOP's in our implementation */
//要进行修改,按以下定义
#define NAND_CTL_CLRALE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_ALE))
#define NAND_CTL_SETALE(nandptr) (nandptr|AT91_SMART_MEDIA_ALE)
#define NAND_CTL_CLRCLE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_CLE))
#define NAND_CTL_SETCLE(nandptr) (nandptr|AT91_SMART_MEDIA_CLE)
1.解决环境变量env的存储问题。
描述:在cmd_nvedit.c中,检查环境变量存储在那里。可选的有 CFG_ENV_IS_IN_NVRAM
CFG_ENV_IS_IN_EEPROM
CFG_ENV_IS_IN_FLASH
CFG_ENV_IS_IN_DATAFLASH
CFG_ENV_IS_IN_NAND
CFG_ENV_IS_NOWHERE
在include/configs/at91rm9200.h中定义其中的一种就可以,因为还没有搞好I
#define CFG_ENV_IS_IN_NAND
#define CFG_ENV_OFFSET 0x40000 //环境变量存储位置偏移
#define CFG_ENV_SIZE 0x20000 //环境变量存储大小
#define CFG_ENV_ADDR 0x40040000
并且注释掉其他的ENV的设置。
由于nand的驱动使用了nand_legacy.c中的nand接口函数。所以要修改common/env_nand.c中的saveenv 函数和env_relocate_spec函数。
int saveenv(void)
{
ulong total;
int ret = 0;
puts ("Erasing Nand...");
/*
if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
return 1;
*/
if (nand_legacy_erase(&nand_dev_desc[0], CFG_ENV_OFFSET, CFG_ENV_SIZE,1))
return 1;
puts ("Writing to Nand... ");
total = CFG_ENV_SIZE;
/*
ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return 1;
*/
ret = nand_legacy_rw(&nand_dev_desc[0] , 0x00 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
puts ("done/n");
return ret;
}
/*
* The legacy NAND code saved the environment in the first NAND device i.e.,
* nand_dev_desc + 0. This is also the behaviour using the new NAND code.
*/
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
ulong total;
int ret;
total = CFG_ENV_SIZE;
// ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
ret = nand_legacy_rw(&nand_dev_desc[0], 0x01 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return use_default();
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}
内核与文件系统移植成功。其中经历了不少的问题。主要是这么几个方面:
1. 在uboot中的bootargs的设置,init=/linuxrc console=/dev/ttyS0,115200 root=/dev/mtdblock2。
2. 自动启动内核的时候,bootcmd的设置在内核中要给nand flash 分好区的,在第三个分区烧写上文件系统。
3. 编译busybox,写好rcS文件。
1.明确的几个问题。
1)在当前的启动方式下,uboot仅仅相当于提供了方便的方式下载内核,文件系统的任务,如何能够让uboot自己完成启动的全部任务。目前为eeprom中的bios程序,调用烧写在nand flash上的uboot,完成启动。但是bios要是从nand flash上读出uboot,就必须移植nand flash的驱动才可以,这样相当于bios也可以完成烧写nand flash的任务。那么是不是有办法让uboot烧写在eeprom中,自己启动的。
2.出现不能初始化console的错误的时候,可能是/dev没有加载,在编译内核的时候,要选中自动加载/dev在boot的时候,这个选项。不然程序会因为找不到/dev/console出错。