/*
* 作者:韦访 rookie_wei
* 说明:本文以JZ2440开发板为例,CUP为S3C2440,烧写工具为JLINK,基于Ubuntu
* u-boot版本为u-boot2014.01
*
*注:本文参考的是韦东山毕业班课程
*
*日期:2014.7.21
*
*/
第一步----分析启动过程
启动从arch\arm\cpu\arm920t\start.S开始
1.跳转到start_code处
2.将CPU设置为SVC32模式
3.关看门狗
4.屏蔽所有IRQ
5.向INTSUBMSK子中断屏蔽寄存器写入0x3ff
6.设置分频系数,即FCLK:HCLK:PCLK
7.调用cpu_init_crit
a.激活v4 I/D caches
b.关闭MMU stuff和caches
//重定位代码前,需要启动RAM timing
c.调用lowlevel_init,设置内存控制器bank0--bank7 (在lowlevel_init.S )
8. bl _main //通过搜索_mian,发现在文件(arch/arm/lib/crt0.S)有ENTRY(_main)根据注释,判断就是跳转到这里,
9. Set up initial C runtime environment and call board_init_f(0).
10. bl board_init_f
init_sequence //主要进行下列初始化工作,很重要
arch_cpu_init
mark_bootstage
board_early_init_f //配置MPLL,UPLL, 设置IO端口
timer_init
env_init //环境初始化
init_baudrate //波特率初始化
serial_init //串口初始化
console_init_f //控制台初始化
display_banner
print_cpuinfo //显示CPU信息
dram_init //配置有效的RAM banks
第二步-----新建单板
tar -xjf u-boot-2014.01.tar.bz2 //解压
cd board/samsung/ //到三星单板目录
cp smdk2410/ smdk2440 -rf //拷贝smdk2410为smdk2440
cd smdk2440/
mv smdk2410.c smdk2440.c //将smdk2410.c改为smdk2440.c
vim Makefile //打开当前目录下的Makefile文件
将 obj-y := smdk2410.o
改为 obj-y := smdk2440.o
cd ../../../include/configs/
cp smdk2410.h smdk2440.h
vim boards.cfg //打开u-boot-2014.01下的boards.cfg
复制Active arm arm920t s3c24x0 samsung - smdk2410
将2410改为2440,这样就可以执行make smdk2440_config 配置2440开发板了
vim Makefile //打开u-boot-2014.01下的Makefile
//主要是将编译器改为arm-linux-gcc,否则编译出错
找到 ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
改为 ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=arm-linux- //注意此处-后面不能有空格
endif
第三步----编译运行
3.1执行make smdk2440_config
make
生成文件u-boot.bin即可执行代码,将其烧写到开发板
3.2启动开发板,串口没有任何信息,说明不能用
第四步----修改代码
4.1 arch\arm\cpu\arm920t\start.S
将/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
改为:
/* FCLK:HCLK:PCLK = 1:4:8 */
/* default FCLK is 400MHz ! */
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
编译、烧写到开发板,发现串口有输出,但是乱码
4.2 由于是串口出现的问题,所以,找到串口初始化函数serial_init
get_current
default_serial_console()
s3c24xx_serial0_device
宏DECLARE_S3C_SERIAL_FUNCTIONS
serial_init_dev
_serial_setbrg
get_PCLK
get_HCLK
由上追踪发现,如果定义了CONFIG_S3C2440则HCLK按2440,否则为2410,所以要在smdk2440.h
里定义CONFIG_S3C2440且去掉CONFIG_S3C2410。
4.3 执行make,出错,根据错误信息分析
提示的错误是在s3c2410_nand.c,与nand flash有关,但是目前最紧迫的问题是串口问题,所以
应该屏蔽掉nand Flash的操作,将smdk2440.h的#define CONFIG_CMD_NAND注释掉,执行make。
仍然出错,提示错误文件为yaffs_uboot_glue.c,与yaffs文件系统有关,照样屏蔽,#define CONFIG_YAFFS2。
执行make编译通过,烧写到开发板,串口问题解决,OK。
4.4 发现打印出的时钟有点偏差,如下
CPUID: 32440001
FCLK: 405.600 MHz
HCLK: 101.400 MHz
PCLK: 50.700 MHz
DRAM: 64 MiB、
肯定是时钟设置不对,找到时钟设置MPLL在smdk2440.c文件里
/* configure MPLL */
writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,&clk_power->mpllcon);
根据芯片手册和开发板原理图知,开发板晶振为12M,所以想要主频为400M,则需要将
MDIV 设为0x5c PDIV为ox01 SDIV为0x01
所以,改为
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
#define M_MDIV 0x5c
#define M_PDIV 0x01
#define M_SDIV 0x01
执行make,烧写到开发板,正确显示如下
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
4.5 发现打印有提示
WARNING: Caches not enabled
搜索Caches not enabled,发现在arch\arm\lib\Cache.c,enable_caches(void)函数
并没有实现功能,所以要实现enable_caches(void)函数,在arch\arm\lib\board.c加上,如下
void enable_caches()
{
__asm__(
"mrc p15, 0, r0, c1, c0, 0\n"
"orr r0, r0, #(1<<12)\n"
"mcr p15, 0, r0, c1, c0, 0\n"
);
}
编译烧写运行,成功去掉提示信息。
4.6 发现打印信息有提示:
Flash: *** failed ***
搜索Flash: ,发现在common\Board_r.c里,代码分析:
initr_flash
flash_init
flash_detect_legacy
flash_read_jedec_ids(info);
debug("JEDEC PROBE: ID %x %x %x\n",
info->manufacturer_id,
info->device_id,
info->device_id2);
可以看出,有能打印出设备ID的调试信息,但是得在smdk2440.h加上#define DEBUG
编译烧写到开发板
打印出信息:
Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
fwc addr 00005554 cmd 55 0055 16bit x 16 bit
fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID c2 2249 0
fwc addr 00000000 cmd ff 00ff 16bit x 16 bit
fwc addr 00000000 cmd 90 0090 16bit x 16 bit
fwc addr 00000000 cmd ff 00ff 16bit x 16 bit
JEDEC PROBE: ID 13 ea00 0
*** failed ***
开发板所用的norflash 是AM29LV160DB,根据芯片手册发现,该设备ID为2249
所以上面打印的信息是正确的,但是却还报错,继续分析代码。
上面信息打印正确,那么错误的应该是在它后面,进入函数
jedec_flash_match
jedec_table
jedec_table在文件drivers\mtd\jedec_flash.c
jedec_table里面罗列的一些FLASH的信息,
在smdk2440.c的board_flash_get_legacy函数提示默认的芯片是AM29LV800BB,
与本开发板不符。
仿照jedec_table别的设备,添加如下:
#ifdef CONFIG_SYS_FLASH_LEGACY_2Mx16
{
.mfr_id = (u16)MX_MANUFACT,
.dev_id = AM29LV160DB,
.name = "AMD AM29LV160DB",
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_2MiB,
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(16 * 1024, 1),
ERASEINFO(8 * 1024, 2),
ERASEINFO(32 * 1024, 1),
ERASEINFO(64 * 1024, 31),
}
}
#endif
并在smdk2440.h中将CONFIG_SYS_FLASH_LEGACY_512Kx16
替换为CONFIG_SYS_FLASH_LEGACY_2Mx16
去掉#define DEBUG
编译烧写运行,打印出:
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
Flash: 2 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 #
说明已经识别出norflash并且能进入SMDK2410 #,但是有提示Flash: ERROR: too many flash sectors
搜索too many flash sectors
找到原因是宏CONFIG_SYS_MAX_FLASH_SECT定位19,但是我们的扇区却为35,将其改为任意大于35的即可
#define CONFIG_SYS_MAX_FLASH_SECT (50)
编译运行,问题解决
4.7 由于u-boot主要是启动内核,上述操作虽然能启动了u-boot,但还远远不够,首要任务是驱动nand flash
以存放内核和文件系统等数据
还记得上面已经把nand flash屏蔽了吧,现在把它打开,在smdk2440.h里将#define CONFIG_CMD_NAND解注。
编译,出错,根据提示知道是drivers/mtd/nand/s3c2410_nand.c文件出错,为了不破坏s3c2410_nand.c源码,将其复制为s3c2440_nand.c,
并在其目录下的Makefile添加obj-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o。
将smdk2440.h里的CONFIG_NAND_S3C2410改为CONFIG_NAND_S3C2440。
将s3c2440_nand.c所有2410改为2440。
将
#define S3C2440_NFCONF_TACLS(x) ((x)<<8)
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<4)
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<0)
改为(请参考s3c2440手册nand flash控制器篇)
#define S3C2440_NFCONF_TACLS(x) ((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)
并将cfg = S3C2440_NFCONF_EN;注释
由于2410和2440 nand flash控制器的区别,2440不仅要操作nfconf,还有操作nfcont,
所以在
//cfg = S3C2440_NFCONF_EN;
cfg |= S3C2440_NFCONF_TACLS(tacls - 1);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
writel(cfg, &nand_reg->nfconf);
后加上nfcont寄存器的操作,
//使能nand flash控制器,Initialize ECC decoder/encoder
writel((1<<4)|(1<<0),&nand_reg->nfcont);
nand 启动分析:
nand_init
nand_init_chip
board_nand_init //单板nand初始化,非常重要
nand_scan
nand_scan_ident
nand_set_defaults //提供nand_chip结构体基本的nand操作函数
nand_get_flash_type
select_chip(mtd, 0); //片选芯片,第二个参数很重要,记住,选中是0
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); //读设备ID
.....
在s3c2440_nand.c文件发现代码nand->select_chip = NULL,如此重要的片选操作居然没有对应函数实现。
在s3c2440_nand.c添加以下函数,并且将
nand->select_chip = NULL
改为
nand->select_chip = s3c2440_nand_select_chip;
static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
switch(chip)
{
case -1: //disable chip select
writel(readl(&nand->nfcont) | ((1<<1)), &nand->nfcont);
break;
case 0: //enable chip select
writel(readl(&nand->nfcont) & (~(1<<1)), &nand->nfcont);
break;
default:
debug("chip select error!\n");
}
}
将函数s3c2440_hwcontrol改为如下,因为2410和2440的nand flash控制器不同。
该函数用于选择是命令操作还是地址操作。
static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
if (ctrl & NAND_CLE)
{
writeb(cmd, &nand->nfcmd); //前8位有效,所以用writeb写入足以
}
else if (ctrl & NAND_ALE)
{
writeb(cmd, &nand->nfaddr);
}
}
编译运行,能识别nand flash:
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
Flash: 2 MiB
NAND: 256 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 #
OK,继续修改
4.8 修改网卡
由输出信息知,u-boot默认的网卡是CS8900,但是我们的开发板用的是DM9000网卡,所以并不能使用。
网络相关的在目录drivers/net下,打开其目录下的Makefile,发现DM9000与宏CONFIG_DRIVER_DM9000有关。
CS8900和CONFIG_CS8900有关
在smdk2440.h里将CONFIG_CS8900有关的注释掉,添加CONFIG_DRIVER_DM9000
编译
发现错误如下
dm9000x.c:148: error: 'DM9000_DATA' undeclared (first use in this function)
搜索DM9000_DATA,仿照mini2440.h里的DM9000,向smdk2440.h添加
#define CONFIG_DRIVER_DM9000
#define CONFIG_DRIVER_DM9000_NO_EEPROM
#define CONFIG_DM9000_BASE 0x20000300
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE+4)
编译运行,发现如下错误
Net: No ethernet found.
搜索Net:
在文件arch/arm/lib/board.c里发现
eth_initialize
board_eth_init
cs8900_initialize
发现默认的还是cs8900,
试着把cs8900_initialize改成dm9000_initialize,发现有此函数,搜索dm9000_initialize,
仿照别的代码
添加
#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif
编译运行,成功识别dm9000
In: serial
Out: serial
Err: serial
Net: dm9000
在串口运行print,可以看到
ethact=dm9000
ipaddr=10.0.0.110
netmask=255.255.255.0
serverip=10.0.0.1
stderr=serial
stdin=serial
stdout=serial
搜索ipaddr=,进入宏CONFIG_IPADDR
发现可以修改IP和网关等信息,可以根据需要修改,也可以不改,
添加#define CONFIG_ETHADDR 00:0c:29:78:c8:73 设置MAC地址
试一下能ping通电脑
4.9 修改默认参数
由打印提示信息*** Warning - bad CRC, using default environment,
我们搜索using default environment
在文件common\Env_common.c找到相关语句
在Env_common.c 里发现default_environment数组,这个数值很重要。
在smdk2440.h里添加
#define CONFIG_BOOTARGS "console=ttySAC0,115200 root=/dev/mtdblock3"
#define CONFIG_BOOTCOMMAND "nand read 30000000 0xa0000 0x400000; bootm 30000000"
注:0xa0000是nand flash里的内核分区首地址,0x400000是内核分区的大小
倒推出环境变量的保存地址,在u-boot串口输入 ? save 找到命令saveenv,在源码搜索saveenv。
在common/env_nand.c里有,vi common/Makefile发现 obj-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o,
所以要定义CONFIG_ENV_IS_IN_NAND。进入env_nand.c发现CONFIG_ENV_OFFSET,即环境偏移地址,需要定义。
还发现CONFIG_ENV_SIZE,也要定义,还发现CONFIG_ENV_RANGE,也要设置。
先去掉//#define CONFIG_ENV_IS_IN_FLASH以免与CONFIG_ENV_IS_IN_NAND冲突
所以要在smdk2440.h里添加:
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00080000 //根据分区定义值得到
#define CONFIG_ENV_SIZE 0x20000
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
4.10 定义分区
在u-boot输入 "?"
找到命令mtdparts,即分区的命令
搜索源码 find -name *mtdparts*
发现/common/cmd_mtdparts.c
打开其文件夹下的Makefile
发现obj-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
所以要在smdk2440.h里添加
#define CONFIG_CMD_MTDPARTS
随便搜索一下源码
grep "define CONFIG_CMD_MTDPARTS" -Rn
随便找一个文件(也不是那么随意,注意是nand flash,别的有可能是nor flash)。参考其写如下代码添加到smdk2440.h
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_PARTITIONS
#define MTDIDS_DEFAULT "nand0=rookie_wei-nand"
#define MTDPARTS_DEFAULT \
"mtdparts=rookie_wei-nand:" \
"512k(bootloader)," \
"128k(params)," \
"4m(kernel)," \
"-(root)"
再在board.c里的board_init_r加上
run_command("mtdparts default",1);
这样启动就会自动分区了,不需要每次都输入.
4.11、支持yaffs文件系统
还记得4.3步的时候我们把 #define CONFIG_YAFFS2注释掉了吗?
解注,编译,运行
在u-boot命令行输入nand ?
居然没有发现nand write.yaffs
搜索nand write
在cmd_nand.c文件发现,原来没有定义头文件CONFIG_CMD_NAND_YAFFS
在smdk2440.h添加:
#define CONFIG_CMD_NAND_YAFFS
再编译运行查看,有
nand write.yaffs - addr off|partition size
write 'size' bytes starting at offset 'off' with yaffs format
from memory address 'addr', skipping bad blocks.
烧写文件系统,启动,没有成功
搜索函数nand_write_skip_bad,#ifdef CONFIG_CMD_NAND_YAFFS下面,将ops.mode = MTD_OPS_AUTO_OOB;,改为ops.mode = MTD_OPS_RAW;。
将 if (!rval)
break;
改为
if (rval)
break;
4.12、支持启动yaffs
将\drivers\mtd\nand\Nand_util.c的nand_write_skip_bad函数的
if (!need_skip && !(flags & WITH_DROP_FFS)) 改为
if (!need_skip && !(flags & WITH_DROP_FFS)&&!(flags & WITH_YAFFS_OOB))
* 作者:韦访 rookie_wei
* 说明:本文以JZ2440开发板为例,CUP为S3C2440,烧写工具为JLINK,基于Ubuntu
* u-boot版本为u-boot2014.01
*
*注:本文参考的是韦东山毕业班课程
*
*日期:2014.7.21
*
*/
第一步----分析启动过程
启动从arch\arm\cpu\arm920t\start.S开始
1.跳转到start_code处
2.将CPU设置为SVC32模式
3.关看门狗
4.屏蔽所有IRQ
5.向INTSUBMSK子中断屏蔽寄存器写入0x3ff
6.设置分频系数,即FCLK:HCLK:PCLK
7.调用cpu_init_crit
a.激活v4 I/D caches
b.关闭MMU stuff和caches
//重定位代码前,需要启动RAM timing
c.调用lowlevel_init,设置内存控制器bank0--bank7 (在lowlevel_init.S )
8. bl _main //通过搜索_mian,发现在文件(arch/arm/lib/crt0.S)有ENTRY(_main)根据注释,判断就是跳转到这里,
9. Set up initial C runtime environment and call board_init_f(0).
10. bl board_init_f
init_sequence //主要进行下列初始化工作,很重要
arch_cpu_init
mark_bootstage
board_early_init_f //配置MPLL,UPLL, 设置IO端口
timer_init
env_init //环境初始化
init_baudrate //波特率初始化
serial_init //串口初始化
console_init_f //控制台初始化
display_banner
print_cpuinfo //显示CPU信息
dram_init //配置有效的RAM banks
第二步-----新建单板
tar -xjf u-boot-2014.01.tar.bz2 //解压
cd board/samsung/ //到三星单板目录
cp smdk2410/ smdk2440 -rf //拷贝smdk2410为smdk2440
cd smdk2440/
mv smdk2410.c smdk2440.c //将smdk2410.c改为smdk2440.c
vim Makefile //打开当前目录下的Makefile文件
将 obj-y := smdk2410.o
改为 obj-y := smdk2440.o
cd ../../../include/configs/
cp smdk2410.h smdk2440.h
vim boards.cfg //打开u-boot-2014.01下的boards.cfg
复制Active arm arm920t s3c24x0 samsung - smdk2410
将2410改为2440,这样就可以执行make smdk2440_config 配置2440开发板了
vim Makefile //打开u-boot-2014.01下的Makefile
//主要是将编译器改为arm-linux-gcc,否则编译出错
找到 ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
改为 ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=arm-linux- //注意此处-后面不能有空格
endif
第三步----编译运行
3.1执行make smdk2440_config
make
生成文件u-boot.bin即可执行代码,将其烧写到开发板
3.2启动开发板,串口没有任何信息,说明不能用
第四步----修改代码
4.1 arch\arm\cpu\arm920t\start.S
将/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
改为:
/* FCLK:HCLK:PCLK = 1:4:8 */
/* default FCLK is 400MHz ! */
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
编译、烧写到开发板,发现串口有输出,但是乱码
4.2 由于是串口出现的问题,所以,找到串口初始化函数serial_init
get_current
default_serial_console()
s3c24xx_serial0_device
宏DECLARE_S3C_SERIAL_FUNCTIONS
serial_init_dev
_serial_setbrg
get_PCLK
get_HCLK
由上追踪发现,如果定义了CONFIG_S3C2440则HCLK按2440,否则为2410,所以要在smdk2440.h
里定义CONFIG_S3C2440且去掉CONFIG_S3C2410。
4.3 执行make,出错,根据错误信息分析
提示的错误是在s3c2410_nand.c,与nand flash有关,但是目前最紧迫的问题是串口问题,所以
应该屏蔽掉nand Flash的操作,将smdk2440.h的#define CONFIG_CMD_NAND注释掉,执行make。
仍然出错,提示错误文件为yaffs_uboot_glue.c,与yaffs文件系统有关,照样屏蔽,#define CONFIG_YAFFS2。
执行make编译通过,烧写到开发板,串口问题解决,OK。
4.4 发现打印出的时钟有点偏差,如下
CPUID: 32440001
FCLK: 405.600 MHz
HCLK: 101.400 MHz
PCLK: 50.700 MHz
DRAM: 64 MiB、
肯定是时钟设置不对,找到时钟设置MPLL在smdk2440.c文件里
/* configure MPLL */
writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,&clk_power->mpllcon);
根据芯片手册和开发板原理图知,开发板晶振为12M,所以想要主频为400M,则需要将
MDIV 设为0x5c PDIV为ox01 SDIV为0x01
所以,改为
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
#define M_MDIV 0x5c
#define M_PDIV 0x01
#define M_SDIV 0x01
执行make,烧写到开发板,正确显示如下
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
4.5 发现打印有提示
WARNING: Caches not enabled
搜索Caches not enabled,发现在arch\arm\lib\Cache.c,enable_caches(void)函数
并没有实现功能,所以要实现enable_caches(void)函数,在arch\arm\lib\board.c加上,如下
void enable_caches()
{
__asm__(
"mrc p15, 0, r0, c1, c0, 0\n"
"orr r0, r0, #(1<<12)\n"
"mcr p15, 0, r0, c1, c0, 0\n"
);
}
编译烧写运行,成功去掉提示信息。
4.6 发现打印信息有提示:
Flash: *** failed ***
搜索Flash: ,发现在common\Board_r.c里,代码分析:
initr_flash
flash_init
flash_detect_legacy
flash_read_jedec_ids(info);
debug("JEDEC PROBE: ID %x %x %x\n",
info->manufacturer_id,
info->device_id,
info->device_id2);
可以看出,有能打印出设备ID的调试信息,但是得在smdk2440.h加上#define DEBUG
编译烧写到开发板
打印出信息:
Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
fwc addr 00005554 cmd 55 0055 16bit x 16 bit
fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
fwc addr 00000000 cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID c2 2249 0
fwc addr 00000000 cmd ff 00ff 16bit x 16 bit
fwc addr 00000000 cmd 90 0090 16bit x 16 bit
fwc addr 00000000 cmd ff 00ff 16bit x 16 bit
JEDEC PROBE: ID 13 ea00 0
*** failed ***
开发板所用的norflash 是AM29LV160DB,根据芯片手册发现,该设备ID为2249
所以上面打印的信息是正确的,但是却还报错,继续分析代码。
上面信息打印正确,那么错误的应该是在它后面,进入函数
jedec_flash_match
jedec_table
jedec_table在文件drivers\mtd\jedec_flash.c
jedec_table里面罗列的一些FLASH的信息,
在smdk2440.c的board_flash_get_legacy函数提示默认的芯片是AM29LV800BB,
与本开发板不符。
仿照jedec_table别的设备,添加如下:
#ifdef CONFIG_SYS_FLASH_LEGACY_2Mx16
{
.mfr_id = (u16)MX_MANUFACT,
.dev_id = AM29LV160DB,
.name = "AMD AM29LV160DB",
.uaddr = {
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_2MiB,
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(16 * 1024, 1),
ERASEINFO(8 * 1024, 2),
ERASEINFO(32 * 1024, 1),
ERASEINFO(64 * 1024, 31),
}
}
#endif
并在smdk2440.h中将CONFIG_SYS_FLASH_LEGACY_512Kx16
替换为CONFIG_SYS_FLASH_LEGACY_2Mx16
去掉#define DEBUG
编译烧写运行,打印出:
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
Flash: 2 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 #
说明已经识别出norflash并且能进入SMDK2410 #,但是有提示Flash: ERROR: too many flash sectors
搜索too many flash sectors
找到原因是宏CONFIG_SYS_MAX_FLASH_SECT定位19,但是我们的扇区却为35,将其改为任意大于35的即可
#define CONFIG_SYS_MAX_FLASH_SECT (50)
编译运行,问题解决
4.7 由于u-boot主要是启动内核,上述操作虽然能启动了u-boot,但还远远不够,首要任务是驱动nand flash
以存放内核和文件系统等数据
还记得上面已经把nand flash屏蔽了吧,现在把它打开,在smdk2440.h里将#define CONFIG_CMD_NAND解注。
编译,出错,根据提示知道是drivers/mtd/nand/s3c2410_nand.c文件出错,为了不破坏s3c2410_nand.c源码,将其复制为s3c2440_nand.c,
并在其目录下的Makefile添加obj-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o。
将smdk2440.h里的CONFIG_NAND_S3C2410改为CONFIG_NAND_S3C2440。
将s3c2440_nand.c所有2410改为2440。
将
#define S3C2440_NFCONF_TACLS(x) ((x)<<8)
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<4)
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<0)
改为(请参考s3c2440手册nand flash控制器篇)
#define S3C2440_NFCONF_TACLS(x) ((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)
并将cfg = S3C2440_NFCONF_EN;注释
由于2410和2440 nand flash控制器的区别,2440不仅要操作nfconf,还有操作nfcont,
所以在
//cfg = S3C2440_NFCONF_EN;
cfg |= S3C2440_NFCONF_TACLS(tacls - 1);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
writel(cfg, &nand_reg->nfconf);
后加上nfcont寄存器的操作,
//使能nand flash控制器,Initialize ECC decoder/encoder
writel((1<<4)|(1<<0),&nand_reg->nfcont);
nand 启动分析:
nand_init
nand_init_chip
board_nand_init //单板nand初始化,非常重要
nand_scan
nand_scan_ident
nand_set_defaults //提供nand_chip结构体基本的nand操作函数
nand_get_flash_type
select_chip(mtd, 0); //片选芯片,第二个参数很重要,记住,选中是0
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); //读设备ID
.....
在s3c2440_nand.c文件发现代码nand->select_chip = NULL,如此重要的片选操作居然没有对应函数实现。
在s3c2440_nand.c添加以下函数,并且将
nand->select_chip = NULL
改为
nand->select_chip = s3c2440_nand_select_chip;
static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
switch(chip)
{
case -1: //disable chip select
writel(readl(&nand->nfcont) | ((1<<1)), &nand->nfcont);
break;
case 0: //enable chip select
writel(readl(&nand->nfcont) & (~(1<<1)), &nand->nfcont);
break;
default:
debug("chip select error!\n");
}
}
将函数s3c2440_hwcontrol改为如下,因为2410和2440的nand flash控制器不同。
该函数用于选择是命令操作还是地址操作。
static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
if (ctrl & NAND_CLE)
{
writeb(cmd, &nand->nfcmd); //前8位有效,所以用writeb写入足以
}
else if (ctrl & NAND_ALE)
{
writeb(cmd, &nand->nfaddr);
}
}
编译运行,能识别nand flash:
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
Flash: 2 MiB
NAND: 256 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 #
OK,继续修改
4.8 修改网卡
由输出信息知,u-boot默认的网卡是CS8900,但是我们的开发板用的是DM9000网卡,所以并不能使用。
网络相关的在目录drivers/net下,打开其目录下的Makefile,发现DM9000与宏CONFIG_DRIVER_DM9000有关。
CS8900和CONFIG_CS8900有关
在smdk2440.h里将CONFIG_CS8900有关的注释掉,添加CONFIG_DRIVER_DM9000
编译
发现错误如下
dm9000x.c:148: error: 'DM9000_DATA' undeclared (first use in this function)
搜索DM9000_DATA,仿照mini2440.h里的DM9000,向smdk2440.h添加
#define CONFIG_DRIVER_DM9000
#define CONFIG_DRIVER_DM9000_NO_EEPROM
#define CONFIG_DM9000_BASE 0x20000300
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE+4)
编译运行,发现如下错误
Net: No ethernet found.
搜索Net:
在文件arch/arm/lib/board.c里发现
eth_initialize
board_eth_init
cs8900_initialize
发现默认的还是cs8900,
试着把cs8900_initialize改成dm9000_initialize,发现有此函数,搜索dm9000_initialize,
仿照别的代码
添加
#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif
编译运行,成功识别dm9000
In: serial
Out: serial
Err: serial
Net: dm9000
在串口运行print,可以看到
ethact=dm9000
ipaddr=10.0.0.110
netmask=255.255.255.0
serverip=10.0.0.1
stderr=serial
stdin=serial
stdout=serial
搜索ipaddr=,进入宏CONFIG_IPADDR
发现可以修改IP和网关等信息,可以根据需要修改,也可以不改,
添加#define CONFIG_ETHADDR 00:0c:29:78:c8:73 设置MAC地址
试一下能ping通电脑
4.9 修改默认参数
由打印提示信息*** Warning - bad CRC, using default environment,
我们搜索using default environment
在文件common\Env_common.c找到相关语句
在Env_common.c 里发现default_environment数组,这个数值很重要。
在smdk2440.h里添加
#define CONFIG_BOOTARGS "console=ttySAC0,115200 root=/dev/mtdblock3"
#define CONFIG_BOOTCOMMAND "nand read 30000000 0xa0000 0x400000; bootm 30000000"
注:0xa0000是nand flash里的内核分区首地址,0x400000是内核分区的大小
倒推出环境变量的保存地址,在u-boot串口输入 ? save 找到命令saveenv,在源码搜索saveenv。
在common/env_nand.c里有,vi common/Makefile发现 obj-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o,
所以要定义CONFIG_ENV_IS_IN_NAND。进入env_nand.c发现CONFIG_ENV_OFFSET,即环境偏移地址,需要定义。
还发现CONFIG_ENV_SIZE,也要定义,还发现CONFIG_ENV_RANGE,也要设置。
先去掉//#define CONFIG_ENV_IS_IN_FLASH以免与CONFIG_ENV_IS_IN_NAND冲突
所以要在smdk2440.h里添加:
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00080000 //根据分区定义值得到
#define CONFIG_ENV_SIZE 0x20000
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
4.10 定义分区
在u-boot输入 "?"
找到命令mtdparts,即分区的命令
搜索源码 find -name *mtdparts*
发现/common/cmd_mtdparts.c
打开其文件夹下的Makefile
发现obj-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
所以要在smdk2440.h里添加
#define CONFIG_CMD_MTDPARTS
随便搜索一下源码
grep "define CONFIG_CMD_MTDPARTS" -Rn
随便找一个文件(也不是那么随意,注意是nand flash,别的有可能是nor flash)。参考其写如下代码添加到smdk2440.h
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_PARTITIONS
#define MTDIDS_DEFAULT "nand0=rookie_wei-nand"
#define MTDPARTS_DEFAULT \
"mtdparts=rookie_wei-nand:" \
"512k(bootloader)," \
"128k(params)," \
"4m(kernel)," \
"-(root)"
再在board.c里的board_init_r加上
run_command("mtdparts default",1);
这样启动就会自动分区了,不需要每次都输入.
4.11、支持yaffs文件系统
还记得4.3步的时候我们把 #define CONFIG_YAFFS2注释掉了吗?
解注,编译,运行
在u-boot命令行输入nand ?
居然没有发现nand write.yaffs
搜索nand write
在cmd_nand.c文件发现,原来没有定义头文件CONFIG_CMD_NAND_YAFFS
在smdk2440.h添加:
#define CONFIG_CMD_NAND_YAFFS
再编译运行查看,有
nand write.yaffs - addr off|partition size
write 'size' bytes starting at offset 'off' with yaffs format
from memory address 'addr', skipping bad blocks.
烧写文件系统,启动,没有成功
搜索函数nand_write_skip_bad,#ifdef CONFIG_CMD_NAND_YAFFS下面,将ops.mode = MTD_OPS_AUTO_OOB;,改为ops.mode = MTD_OPS_RAW;。
将 if (!rval)
break;
改为
if (rval)
break;
4.12、支持启动yaffs
将\drivers\mtd\nand\Nand_util.c的nand_write_skip_bad函数的
if (!need_skip && !(flags & WITH_DROP_FFS)) 改为
if (!need_skip && !(flags & WITH_DROP_FFS)&&!(flags & WITH_YAFFS_OOB))