3 修改代码
a 修改start.s中时钟设置部分。
/*修改这里,时钟设置不正确*/
/* FCLK:HCLK:PCLK = 1:4:8 */
/*设置时钟*/
ldr r0,=0x4c000014
mov r1,#0x05
str r1,[r0]
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */
orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
ldr r0,=0x4c000004
ldr r1,=S3C2440_MPLL_400MHZ
str r1,[r0]
/*启动ICACHE*/
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
ldr pc,=call_board_init_f //这条汇编是绝对跳转指令
call_board_init_f: //这两句程序实现了 程序从nor跳转到sdram中运行。
ldr r0,=0x00000000
bl board_init_f
/*调用board_init_f函数返回值id,存在r0中,作为board_init_r的参数*/
ldr r1, _TEXT_BASE
ldr sp,base_sp //栈要重新设置,base_sp为定义的一个全局变量 :.globl base_sp base_sp: .long 0
bl board_init_r //base_sp 在board_init_f函数中base_sp = addr_sp;被赋值。
/*调用第二阶段代码*/
bl board_init_r
程序刚开始时的堆栈指针被定义为ldr sp,=(CONFIG_SYS_INIT_SP_ADDR) bic sp,sp,#7
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - GENERATED_GBL_DATA_SIZE)
修改smdk2440/smdk2410.c的 board_early_init_f 函数,去掉其对MPLL的设置。
b 修改sdram配置寄存器值
.long 0x22011110 @BWSCON
.long 0x00000700 @BANKCON0
.long 0x00000700 @BANKCON1
.long 0x00000700 @BANKCON2
.long 0x00000700 @BANKCON3
.long 0x00000700 @BANKCON4
.long 0x00000700 @BANKCON5
.long 0x00018005 @BANKCON6
.long 0x00018005 @BANKCON7
.long 0x008c07a3 @REFRESH
.long 0x000000b1 @BANKSIZE
.long 0x00000030 @MRSRB6
.long 0x00000030 @MRSRB7
也可以不用修改!
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x32
.word 0x30
.word 0x30
3.1 修改了以后,编译,下载,发现串口输出的东西是乱些乱码,初步认为是波特率没有设置好
查看串口波特率的设置,发现在get_HCLK里没有定义CONFIG_S3C2440
c 修改代码:include/configs/smdk2440.h:
去掉CONFIG_S3C2410 加上#define CONFIG_S3C2440
编译,s3c2410_nand.c:72 行出错。。去掉这个宏 CONFIG_NAND_S3C2410 暂时不把nand flash加进来
把CONFIG_CMD_NAND去掉也就把nand 所有宏都去掉了
编译后,出错:fs/yaffs2/libyaffs2.o: In function `yaffs_StartUp':
/home/zz/my-uboot-2012.4.01/fs/yaffs2/yaffscfg.c:210: undefined reference to `nand_info'
d 修改代码:include/configs/smdk2440.h: 注释掉:#define CONFIG_YAFFS2。
再次编译,make distclean make smdk2440_config make。能通过。
修改重定位代码后,发现不能从nor启动了。查了半天,原因是:isBootFromNorFlash 函数中定义的指针没有使用 volatile 关键字修饰
修改加上volatile 就Ok了。
e 修改start.S加上 .global base_sp base_sp: .long 0
修改board.c board_init_f 函数中 加上 extern ulong base_sp 在return 前加上base_sp = addr_sp;
f 修改代码使其支持nor flash
board_init_r
flash_init
flash_detect_legacy
flash_get_size
分析调试信息,打开DEBUG宏。在cfi_flash.c中添加#define DEBUG 1 #define _DEBUG 1
在jedec_flash.c中的 static const struct amd_flash_info jedec_table[] 数组中添加:
/*GQ2440使用的nor flash : S29AL016MB*/
{
.mfr_id = (u16)AMD_MANUFACT, /*厂家ID*/
.dev_id = 0x2249, /*设备ID*/
.name = "S29AL016MB",
.uaddr = { /*nor flash看到的解锁地址*/
[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),
}
},
编译、烧写后,运行出现 ERROR: too many flash sectors
修改配置头文件smdk2440.h
修改 #define CONFIG_SYS_MAX_FLASH_SECT (19)为(128)
去掉cfi_flash.c中添加#define DEBUG 1 #define _DEBUG 1
至此,uboot就能在Nor启动和运行了!!但是还不能使用网络,使用nand flash来引导内核
g 修改网卡程序 使它支持DM9000
加入对DM9000支持的配置宏
#if 0
#define CONFIG_CS8900 /* we have a CS8900 on-board */
#define CONFIG_CS8900_BASE 0x19000300
#define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */
#else
#define CONFIG_DRIVER_DM9000
#define CONFIG_DM9000_BASE 0x20000000 //由网卡接到CPU的BANK地址来决定的
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE + 4) //这个由网卡上的CMD引脚接的位置来决定,LDDR2位+4 LDDR1+2 LDDR0+0
#endif
修改内存配置寄存器组的值,这里只用修改
.long 0x00000740 @BANKCON4/*为了支持网卡而修改成740,原值为700*/
编译还是出错: Net: No ethernet found.
搜索代码找到这句:
在 board_init_r
puts("Net: ");
eth_initialize(gd->bd);
board_eth_init
#ifdef CONFIG_CS8900
rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
#endif
发现这里只调用了cs8900_initialize,所以添加如下代码
#ifdef CONFIG_DRIVER_DM9000
rc=dm9000_initialize(bis);
#endif
make通过。插上网线, set ipaddr 192.168.0.6 ping 192.168.0.1
出错: *** ERROR: `ethaddr' not set
原因没有设置网卡MAC地址
set ethaddr 00:11:22:33:44:55
set ipaddr 192.168.0.2
set serverip 192.168.0.1
测试OK。。网卡移植到此结束。
移植的uboot还不能引导linux内核。
原因是,uboot传递的机器码不对。对于国嵌的Linux内核,传递的机器码为MINI2440 也就1999
可能在uboot里 set machid 7cf 来设置。
set machid 7cf
set ethaddr 08:08:11:18:12:27
set bootargs noinitrd root=/dev/nfs rw nfsroot=192.168.0.1:/common/rootfs ip=192.168.0.2:192.168.0.255::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M
tftp 32000000 uimage
bootm 32000000
终于看到另人兴奋的字符飘动的界面了。。。。。吼吼
3.2 修改代码,支持nand flash。
a 打开宏 #define CONFIG_CMD_NAND
make ,出错,逐个修改错误
b s3c2410_nand.c:72:出错 s3c2410_nand.c:72: error: dereferencing pointer to incomplete type
这是因为配置文件中打开宏 CONFIG_S3C2440 关闭宏 CONFIG_S3C2410 而
#ifdef CONFIG_S3C2410
/* NAND FLASH (see S3C2410 manual chapter 6) */
struct s3c2410_nand { //2410的nand flash控制器寄存器
u32 nfconf;
u32 nfcmd;
u32 nfaddr;
u32 nfdata;
u32 nfstat;
u32 nfecc;
};
#endif
#ifdef CONFIG_S3C2440
/* NAND FLASH (see S3C2440 manual chapter 6) */
struct s3c2440_nand { //2440的nand flash控制器寄存器
u32 nfconf;
u32 nfcont;
u32 nfcmd;
u32 nfaddr;
u32 nfdata;
u32 nfeccd0;
u32 nfeccd1;
u32 nfeccd;
u32 nfstat;
u32 nfstat0;
u32 nfstat1;
};
#endif
所以struct s3c2410_nand *nand 结构体未定义,出错
c 复制driver/mtd/nand/s3c2410_nand.c为 s3c2440_nand.c
把s3c2440_nand.c 里所有函数名中的2410改为2440 在s3c2440_hwcontrol函数中
把原来的 struct s3c2410_nand *nand = s3c2410_get_base_nand();
修改成 struct s3c2440_nand *nand = s3c2440_get_base_nand();
修改smdk2440.h配置头文件,打开宏CONFIG_NAND_S3C2440,关闭宏CONFIG_NAND_S3C2410
/*
* NAND configuration
*/
#ifdef CONFIG_CMD_NAND
#ifdef CONFIG_S3C2410
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#else
#define CONFIG_NAND_S3C2440 //修改加上,使Makefile里会编译s3c2440_nand.o
#define CONFIG_SYS_S3C2440_NAND_HWECC //
#endif
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE 0x4E000000
#endif
修改Makefile 加上COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
d uboot第二阶段代码,nand分析过程
board_init_r
puts("NAND: ");
nand_init(); /* go init the NAND */
nand_init_chip(0) CONFIG_SYS_MAX_NAND_DEVICE==1
board_nand_init
设置nand_chip 结构体,提供底层操作函数
修改struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();为
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
#if 0 //这段代码是对2410的NFCONF寄存器设置数值的,和2440的设置值不同,注释掉
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
#endif
/*初始化nand控制器*/
cfg = ((tacls-1)<<12) | ((twrph0-1)<<8) | ((twrph1-1)<<4);
writel(cfg, &nand_reg->nfconf);
/*使能Nand Flash控制器,初始化ECC,禁止片选*/
writel( (1<<4) | (1<<1) | (1<<0) ,&nand_reg->nfcont);
nand->select_chip = s3c2440_nand_select;//片选函数自己写
nand_scan
nand_scan_ident
nand_set_defaults //设置设备的操作的默认函数
chip->select_chip = nand_select_chip;
chip->cmdfunc = nand_command;
nand_get_flash_type //读设备类型
chip->select_chip(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
nand_command(struct mtd_info *mtd, unsigned int command,int column, int page_addr)
//即可以用来发命令,也可以用来发地址:行地址和列地址
chip->cmd_ctrl(mtd, readcmd, ctrl);
nand->cmd_ctrl = s3c2440_hwcontrol;
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
*maf_id = chip->read_byte(mtd); //读厂家ID
*dev_id = chip->read_byte(mtd); //读设备ID
nand 协议层:知道发送什么命令
单板相关函数:知道怎么发关这数据:
选中/取消选中
发命令
发地址
R/W数据
判断状态
删除掉ECC相关的函数,因为ECC比较复杂
修改s3c2440_nand.c中所有s3c2410_hwcontrol 为 s3c2440_hwcontrol
/* ctrl : 表示发命令还是发数据
* dat:表示命令值或数据值
*/
static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
// struct nand_chip *chip = mtd->priv;
struct s3c2440_nand *nand = s3c2440_get_base_nand();
if(ctrl & NAND_CLE)/*发命令*/
{
writeb(dat,&nand->nfcmd);
}
else if(ctrl &NAND_ALE)/*发地址*/
{
writeb(dat,&nand->nfaddr);
}
}
//这里的writeb(当然用writel也可以,因为这两个寄存器有效数据都是8位)时,
//第二个参数加上&;这个函数在移植的过程中,少写了,这个函数的功能就是发命令或发地址
static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
if(chipnr==0)/*选中*/
{
nand->nfcont &= ~(1<<1);
}
else if(chipnr==-1)/*取消选中*/
{
nand->nfcont |= (1<<1);
}
else
BUG();
}
这里我共修改了include/configs/smdk2440.h drivers/mtd/nand/s3c2440_nand.c
drivers/mtd/nand/Makefile 三个文件
可以打开宏 #define CONFIG_YAFFS2,make distclean make smdk2440_config make
E:\u-boot.bin
D:\u-boot.bin
loady 30000000
protect off all
erase 0 7ffff
cp.b 30000000 0 80000
3.3 修改uboot支持环境参数的保存
在uboot启动时*** Warning - bad CRC, using default environment
a 在源码中搜索 using default environment
common/env_common.c中 set_default_env 函数打印出这些信息
查看 set_default_env 中的default_environment
这个数组里面很多的开关宏,依次修改之
加上这三个宏
#define CONFIG_BOOTARGS "noinitrd root=/dev/nfs rw nfsroot=192.168.0.1:/common/rootfs ip=192.168.0.2:192.168.0.255::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M"
#define CONFIG_BOOTCOMMAND "bootm 32000000"
#define CONFIG_ETHADDR "08:08:11:22:af"
修改这个三宏的IP地址,为了和开发用的主机一致
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.0.2
#define CONFIG_SERVERIP 192.168.0.1
#define CONFIG_SYS_PROMPT "SMDK2410 # " //用于修改在开发板上显示用户登录名
#if 0 /*the env save in nor flash*/
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000)
#define CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_SIZE 0x10000
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#endif
/*设置环境变量在nand中的存储位置擦出长度*/
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00040000 //环境变量存储的起始 nand 地址
#define CONFIG_ENV_SIZE 0x20000 /*128K正好是一个块,nand擦出是按块进行的*/
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE //
0x00000000-0x00040000 bootloader //nand 中的分区如下
0x00040000-0x00060000 params
0x00060000-0x00260000 kernel
0x00260000-0x10000000 root
b 裁减代码,去掉不常用的功能和命令
1去掉USB相关的宏
//#define CONFIG_USB_OHCI
//#define CONFIG_USB_KEYBOARD
//#define CONFIG_USB_STORAGE
//#define CONFIG_DOS_PARTITION
2去掉RTC时钟
//#define CONFIG_RTC_S3C24X0
3去掉一些命令行
//#define CONFIG_CMD_DATE
//#define CONFIG_CMD_DHCP
//#define CONFIG_CMD_USB
4关闭文件系统相关宏
/*
* File system
*/
#if 0
#define CONFIG_CMD_FAT
#define CONFIG_CMD_EXT2
#define CONFIG_CMD_UBI
#define CONFIG_CMD_UBIFS
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
#define CONFIG_YAFFS2
#define CONFIG_RBTREE
#endif
c saveenv命令
保存到 nand flash 上saveenv()在env_nand.c中
把env_nand.c编译到程序中,查看common/Makefile
由 COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o 可知
要打开 开关宏 CONFIG_ENV_IS_IN_NAND
nand erase [nand的起始地址] [nand的擦出大小]
nand write [欲读的内存起始地址] [写nand的起始地址] [大小]
nand read [欲写的内存起始地址] [读nand的起始地址] [大小]
d 在board.c中调用 mtdparts_init
/*mtdparts config配置nand 分区*/
#define CONFIG_MTD_DEVICE
#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nand0=sust2440-0"
#define MTDPARTS_DEFAULT "mtdparts=sust2440-0:256k(u-boot)," \
"128k(params)," \
"2m(kernel)," \
"-(rootfs)"
修改arch/arm/lib/board.c,在 board_init_r函数中的 for(;;){main_loop();}前
加上 run_command("mtdparts default", 0); 对mtdparts分区进行初始化
设置环境变量
bootargs=noinitrd root=/dev/nfs rw nfsroot=192.168.0.1:/common/rootfs ip=192.168.0.2:192.168.0.255::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M
bootcmd=nand read 32000000 kernel ; bootm 32000000
set machid 7cf //设置机器码为1999也就是MINI2440的机器码,怎么在代码中写死,没有找到方法
nand erase.part kernel
nand write 30000000 kernel
3.4 修改支持yaffs文件系统下载
修改smdk2440打开天关宏
/*支持yaffs文件系统下载*/
#define CONFIG_CMD_NAND_YAFFS
追踪代码cmd_nand.c 中的 nand_write_skip_bad函数
nand_write_skip_bad函数位于driver/mtd/nand/nand_util.c中
//ops.mode = MTD_OOB_AUTO;/*此处修改为MTD_OOB_RAW*/
ops.mode = MTD_OOB_RAW;
再修改
// if (!rval) /*此处写错了,根据韦东山视频修改;这处是源码的错误*/
make distclean;make smdk2440_config;make
tftp 31000000 u-boot.bin ;protect off all ;erase 0 3ffff ;cp.b 31000000 0 40000
tftp 31000000 u-boot-last-yaffs.bin ;nand erase.part u-boot ;nand write 31000000 u-boot
3.5 制作补丁文件和打补丁
make distclean
rm u-boot.dis -f
tar -xjf u-boot-2012.04.01.tar.bz2
制作补丁文件
diff -urN u-boot-2012.04.01 my-uboot-2012.4.01_zhaigch > my-uboot-2012.4.01_zhaigch.patch
源码的uboot 修改过的uboot 重定向输出到 补丁文件
打补丁
cd u-boot-2012.04.01 进入源码文件夹下
patch -p1 < ../my-uboot-2012.4.01_zhaigch.patch
补丁共修改这以下这些文件
patching file arch/arm/config.mk
patching file arch/arm/cpu/arm920t/start.S
patching file arch/arm/cpu/u-boot.lds
patching file arch/arm/include/asm/mach-types.h
patching file arch/arm/lib/board.c
patching file board/samsung/smdk2440/init.c
patching file board/samsung/smdk2440/lowlevel_init.S
patching file board/samsung/smdk2440/Makefile
patching file board/samsung/smdk2440/smdk2410.c
patching file boards.cfg
patching file common/cmd_bdinfo.c
patching file drivers/mtd/cfi_flash.c
patching file drivers/mtd/jedec_flash.c
patching file drivers/mtd/nand/Makefile
patching file drivers/mtd/nand/nand_base.c
patching file drivers/mtd/nand/nand_util.c
patching file drivers/mtd/nand/s3c2440_nand.c
patching file include/common.h
patching file include/configs/smdk2440.h
patching file arch/arm/config.mk
patching file arch/arm/cpu/arm920t/start.S
patching file arch/arm/cpu/u-boot.lds
patching file arch/arm/include/asm/mach-types.h
patching file arch/arm/lib/board.c
patching file board/samsung/smdk2440/init.c
patching file board/samsung/smdk2440/lowlevel_init.S
patching file board/samsung/smdk2440/Makefile
patching file board/samsung/smdk2440/smdk2410.c
patching file boards.cfg
patching file common/cmd_bdinfo.c
patching file drivers/mtd/cfi_flash.c
patching file drivers/mtd/jedec_flash.c
patching file drivers/mtd/nand/Makefile
patching file drivers/mtd/nand/nand_base.c
patching file drivers/mtd/nand/nand_util.c
patching file drivers/mtd/nand/s3c2440_nand.c
patching file include/common.h
patching file include/configs/smdk2440.h
4 关于机器码machid
在以上的代码移植过程中,烧写的uboot都要手动去设置 set machid 7cf
才能引导linux (因为我所用的linux识别的机器码为mini2440 的1999:0x7cf)
后来找到问题的所在了:
在 board/samsung/smdk2440/smdk2410.c 中的 board_init 函数中对板子进行设置
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
修改为: /* MINI2440-Board 的机器码在 arch/arm/include/asm/mach-types.h 文件中定义*/
gd->bd->bi_arch_number = MACH_TYPE_MINI2440;