第二阶段:boorloader的移植
以下文章出自顶嵌高级讲师李亚锋老师:顶嵌网址www.top-e.org
第二阶段:boorloader的移植
一. BootLoader简介
应用程序 |
文件系统 |
操作系统内核 |
BootLoader |
简单的说bootloader是一段程序,它的作用就是加载操作系统,BootLoader(引导加载程序)是系统加电后运行的 第一段软件代码。通过这段代码实现硬件的初始化,建立内存空间的映射图,为操作系统内核准备好硬件环境并引导内核的启动。如右图所示的那样在设备的启动过程中bootloader位于最底层,首先被运行来引导操作系统运行,很容易可以看出 bootloader是底层程序所以它的实现严重地依赖于硬件,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。尽管如此,一些功能强大、支持硬件环境较多的BootLoader也被广大的使用者和爱好者所支持,从而形成了一些被广泛认可的、较为通用的的bootloader实现。简单的介绍几种:
1.U-BOOT
uboot是一个庞大的公开源码的软件。他支持一些系列的arm体系,包含常见的外设的驱动,是一个功能强大的板极支持包。其代码可以从下载 U-BOOT是由PPCBOOT发展起来的,是PowerPC、ARM9、Xscale、X86等系统通用的Boot方案,从官方版本 0.3.2开始全面支持SC系列单板机。u-boot是一个开源的bootloader。
2.vivi
vivi是韩国mizi 公司开发的bootloader, 适用于ARM9处理器。 Vivi有两种工作模式:启动加载模式和下载模式。启动加载模式可以在一段时间后(这个时间可更改)自行启动linux内核,这是vivi的默认模式。如果修改或更新需要进入下载模式,在下载模式下,vivi为用户提供一个命令行接口通过接口可以使用vivi提供的一些命令,来实现flash的烧写、管理、操作mtd分区信息、启动系统等功能。
其它还有一些bootloader实现如下表所示:
名称 | 说明 | 支持的架构 |
LILO | Linux的磁盘引导加载程序 | x86 |
GRUB | LILO的GNU版本 | x86 |
Loadlin | 从DOS引导Linux | x86 |
RedBoot | 以eCos为基础的引导程序 | x86 、ARM、PowerPC、MIPS等 |
ROLO | 从ROM引导Linux,且不需要BIOS | x86 |
Etherboot | 从以太网卡启动Linux系统的固件 | x86 |
LinuxBIOS | 以Linux为基础的BIOS的替代品 | x86 |
blob | 来自LART计划的引导程序 | ARM |
由于u-boot的通用性好,功能全面,适合初学者学习和使用,我们选用u-boot作为基准代码,在此基础上进行修改,完成移植工作。
二.移植准备
1.目标板:
这是进行U-Boot移植首先要明确的。可以根据目标板上CPU、FLASH、SDRAM的情况,以尽可能相一致为原则,先找出 一个与所移植目标板为同一个或同一系列处理器的U-Boot支持板为移植参考板。
以上图片是本次移植所用到的开发板实物图
一些重要参数如下:
CPU处理器
– Samsung S3C2440AL,主频400MHz,最高533MHz。
SDRAM内存
– 板载64MB SDRAM
– 32bit数据总线
– SDRAM时钟频率高达100MHz
– Hynix809E
Flash存储器
– 板载64MB Nand Flash,掉电非易失
– 板载2MB Nor Flash
– K9F1208u00
网卡
– DM9000EP
2.源文件:
选择一标准的u-boot代码:u-boot-1.1.6
3.烧写工具:
u-boot的烧写使用JTAG线进行下载,用SJF2440.exe软件进行烧写,使用DNW终端进行串口调试。用串口线相连。
4.知识储备:
u-boot的目录结构:
目录 | 说明 |
board | 和一些已有开发板有关的文件,比如makefile和U-Boot.ldS等都和具体开发板的硬件和地址分配有关。 |
common | 与体系结构无关的文件,实现各种命令的C文件 |
cpu | CPU相关文件,其中的子目录都是以U-Boot所支持的CPU为名,比如子目录arm926ejS、mips等,每个特定的子目录都包括cpu.c和interrupt.c,start.s。其中cpu.c初始化CPU、设置指令cache和数据cache等。Interruput.c设置系统的各种中断和异常;start.s是U-Boot自动执行时的第一个文件,它主要是设置系统堆栈和工作方式,为进入C程序奠定基础。 |
disk | Disk驱动的分区处理代码 |
doc | 文档 |
drivers | 通用设备驱动程序,例如各种网卡、支持CFI的Flash、串口、USB等 |
fs | 支持文件系统的文件,目前支持cramfs、fat、fdos、jffs2和registerfs |
include | 头文件,还有对各种硬件平台支持的汇编文件,系统配置文件等 |
net | 与网络有关的代码,BOOTP协议、TFTP协议、RARP和NFS等 |
lib_arm | 与ARM体系结构相关的代码 |
tools | 创建S-Record格式文件和U-Boot images的工具 |
u-boot代码:
由于代码比较庞大,只简单分析启动部分。网络和书很多书中有详细的分析,如果想详细了解查阅相关资料,或着提出讨论,还可以登陆顶嵌公司网站技术文档里查看。网址:http://www.top-e.org/jiaoshi/html/?320.html
U-Boot启动过程可以分成两个阶段(stage)
下面是u-boot启动过程的流程图其中左右两部分分别是启动过程的两个阶段
第一阶段(stage 1)是依赖于CPU体系结构的代码(如设备初始化代码等),一般用汇编语言来实现。主要进行以下方面的设置:设置ARM进入SVC模式、禁止IRQ和FIQ、关闭看门狗、屏蔽所有中断。设置时钟(FCLK,HCLK,PCLK)、清空I/D cache、清空TLB、禁止MMU和cache、配置内存控制器、为搬运代码做准备、搬移uboot映像到RAM中(使用copy_loop实现)、分配堆栈、清空bss段(使用clbss_l实现)。
第二阶段(stage 2)通常用C语言来实现。
start_armboot():
一系列初始化(cpu, 板卡,中断,串口,控制台等),开启I/D cache。初始化FLASH,根据系统配置执行其他初始化操作。打印LOG,使能中断,获取环境变量,初始化网卡。最后进入main_loop()函数。在main_loop函数中会检查bootdelay和bootcmd环境变量,如果bootcmd已经设置过,则在等待bootdelay个毫秒后会自动执行bootcmd。如果等待过程中被用户中断(ctl+c)或者bootcmd没有设置,则会等待用户输入命令。
关键点一: U-Boot移植参考板
这是进行U-Boot移植首先要明确的。可以根据目标板上CPU、FLASH、SDRAM的情况,以尽可能相一致为原则,先找出 一个与所移植目标板为同一个或同一系列处理器的U-Boot支持板为移植参考板。对U-Boot移植新手,建议依照循序渐进的原则,目标板文件名暂时先用移 植参考板的名称,在逐步熟悉U-Boot移植基础上,再考虑给目标板重新命名。在实际移植过程中,可用Linux命令查找移植参考板的特定代码,如 grep –r 2410 ./ 可确定出在U-Boot中与smdk2410板有关的代码,依此对照目标板实际进行屏蔽或修改。同时应不局限于移植参考板中的代码,要广泛借鉴U-Boot 中已有的代码更好地实现一些具体的功能。
关键点二: U-Boot烧写地址和CPU寄存器参数设置
不同目标板,对U-Boot在FLASH中存放地址要求不尽相同。事实上,这是由处理器中断复位向量来决定的,与主板硬件相关 。也就是说,U-Boot烧写具体位置是由硬件决定的,而不是程序设计来选择的。
根据CPU处理器系列、类型不同,寄存器名称与作用有一定差别。必须根据目标板的实际,进行合 理配置。一个较为可行和有效的方法,就是借鉴参考移植板的配置,再根据目标板实际,进行合理修改。这是一个较费时间和考验耐力的过程,需要仔细对照处理器 各寄存器定义、参考设置、目标板实际作出选择并不断测试。
关键点三:串口调试。
能从串口输出信息,即使是乱码,也可以说U-Boot移植取得了实质性突破。 依据笔者调试经历,串口是否有输出,除了与串口驱动相关外,还与FLASH相关的寄存器设置有关。因为U-Boot是从FLASH中被引导启动的,如果 FLASH设置不正确,U-Boot代码读取和执行就会出现一些问题。因此,还需要就FLASH的相关寄存器设置进行一些参数调试。同时,要注意串口收发 芯片相关引脚工作波形。依据笔者调试情况,如果串口无输出,有一种可能就是该芯片损坏或工作不正常。 如果出现乱码,有一种可能就是波特率等参数设置有问题。
三.修改源代码:
1. 添加新开发板信息
(1)顶层Makefile:为了能让u-boot在编译之前根据此规则来获得具体的配置文件和编译规则。
在smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
之后,添加以下内容:
tq2440_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t tq2440 NULL s3c24x0 |
添加交叉编译器路径(根据个人情况):
ifeq ($(ARCH),arm) CROSS_COMPILE= /opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux/bin/arm-softfloat-linux- endif |
(2)建立新开发板目录:可以把类似的开发板进行修改
cd board
mkdir tq2440
cd tq2440
cp -arf ../smdk2410/* .
mv smdk2410.c tq2440.c
(3)修改 board/tq2440/u-boot.lds
在cpu/arm920t/start.o (.text)后添加:
board/tq2440/boot_init.o (.text) |
并在tq2440目录下新建boot_init.c文件,内容参考源文件,该代码主要实现了CopyCode2Ram函数,该函数功能是拷贝flash代码到sdram中,实现原理如下图。
CopyCode2Ram函数实现原理
(4)修改tq2440目录下的Makefile
COBJS := tq2440.o flash.o boot_init.o |
(5)修改tq2440.c
增加宏定义:
#define S3C2440_MPLL_400MHZ ((0x7f<<12)|(0x02<<4)|(0x01)) #define S3C2440_UPLL_48MHZ ((0x38<<12)|(0x02<<4)|(0x02)) |
S3C2440的主时钟源来自外部晶振(XTIPLL)或外部时钟(EXTCLK)。S3C2440有两个PLL(phase locked loop)一个是MPLL,一个是UPLL。MPLL用于CPU及其他外围器件,UPLL用于USB。
【1】MPLL, 用于产生FCLK, HCLK, PCLK三种频率, 这三种频率分别有不同的用途:
FCLK是CPU提供的时钟信号。
HCLK是为AHB总线提供的时钟信号, Advanced High-performance Bus,主要用于高速外设,比如内存控制器,中断控制器,LCD控制器, DMA 等。
从S3C2440的DataSheet里可以看到,S3C2440最大支持400MHz的主频,但是这并不意味着一定工作在400MHz下面,可以通过设定MPLL, UPLL寄存器来设定CPU的工作频率。
PCLK是为APB总线提供的时钟信号,Advanced Peripherals Bus,主要用于低速外设,比如看门狗,UART控制器, IIS, I2C, SDI/MMC, GPIO,RTC and SPI等。
【2】UPLL,专门用于驱动USB host/Device。并且驱动USB host/Device的频率必须为48MHz。
如果要设置MPLL和UPLL,要注意它们的先后顺序,MPLL和UPLL的设定是有前后顺序的,必须先设定UPLL,然后才能设定MPLL,而且中间需要大约7个空指令(NOP)的间隔。
定义MPLL/UPLL/CLKDIV,参考S3C2440芯片用户手册,参考255页内容如下:
#define S3C2440_CLKDIV 0x05 /* FCLK:HCLK:PCLK = 1:4:8 */
该寄存器参考内如下:
修改board_init函数如下:
int board_init (void) { S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
/* FCLK:HCLK:PCLK = 1:4:8 */ clk_power->CLKDIVN = S3C2440_CLKDIV; /* change to asynchronous bus mod */ __asm__( "mrc p15, 0, r1, c1, c0, 0/n" /* read ctrl register */ "orr r1, r1, #0xc0000000/n" /* Asynchronous */ "mcr p15, 0, r1, c1, c0, 0/n" /* write ctrl register */ :::"r1" );
/* to reduce PLL lock time, adjust the LOCKTIME register */ clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */ clk_power->MPLLCON = S3C2440_MPLL_400MHZ;
/* some delay between MPLL and UPLL */ delay (4000);
/* configure UPLL */ clk_power->UPLLCON = S3C2440_UPLL_48MHZ;
/* some delay between MPLL and UPLL */ delay (8000);
/* set up the I/O ports */ gpio->GPACON = 0x007FFFFF; gpio->GPBCON = 0x00044555; gpio->GPBUP = 0x000007FF; gpio->GPCCON = 0xAAAAAAAA; gpio->GPCUP = 0x0000FFFF; gpio->GPDCON = 0xAAAAAAAA; gpio->GPDUP = 0x0000FFFF; gpio->GPECON = 0xAAAAAAAA; gpio->GPEUP = 0x0000FFFF; gpio->GPFCON = 0x000055AA; gpio->GPFUP = 0x000000FF; gpio->GPGCON = 0xFF95FFBA; gpio->GPGUP = 0x0000FFFF; gpio->GPHCON = 0x002AFAAA; gpio->GPHUP = 0x000007FF;
/* arch number of SMDK2410-Board */ gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
/* adress of boot parameters */ gd->bd->bi_boot_params = 0x30000100;
icache_enable(); dcache_enable();
return 0; } |
(6)lowlevel_init.S
#define B1_BWSCON (DW32) 修改为 #define B1_BWSCON (DW16)
#define B5_BWSCON (DW16) 修改为 #define B5_BWSCON (DW8)
#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
修改为
#define REFCNT 0x4f4/*period=7.8125us,HCLK=100Mhz, (2048+1-7.8125*100) */
二. 头文件修改 include/configs/tq2440.h
(1) cp include/configs/smdk2410.h include/configs/tq2440.h
(2) 增加宏定义:
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE 0x20000300
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE + 4)
#define CONFIG_DM9000_USE_16BIT
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_CMDLINE_TAG 1
(3)#define CONFIG_COMMANDS /中增加如下三项:
CFG_CMD_PING | /
CFG_CMD_JFFS2 | /
CFG_CMD_NAND | /
(4)修改网络相关参数:
#define CONFIG_BOOTDELAY 1
#define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0"
#define CONFIG_ETHADDR 0a:1b:2c:3d:4e:5f
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.6
#define CONFIG_SERVERIP 192.168.1.8
(5)#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#if 0
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
#endif
修改为:
#if 0
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#endif
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
(6) 在最后#endif /* __CONFIG_H */前增加NAND相关宏定义:
#define CFG_NAND_BASE 0
#define CFG_MAX_NAND_DEVICE 1
#define NAND_MAX_CHIPS 1
三. 修改cpu/arm920t/start.S
(1) #elif defined(CONFIG_S3C2410)后添加:
# define INTMOD 0X4A000004
(2)将
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
修改为:
#if 0
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
(3) 在
bl cpu_init_crit
#endif后面加上
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
sub sp, r0, #12 /* leave 3 words for abort-stack */
bl clock_init
(4) 将下列代码替换
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
替换为:
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq clear_bss
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
#if 1
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
#else
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
4.相关头文件
(1) include/s3c24x0.h
在下面结构体中添加S3C24X0_REG32 CAMDIVN;
typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
}
添加NAND寄存器结构体
/* NAND FLASH (see S3C2440 manual chapter 6, www.top-e.org) */
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFMECCD0;
S3C24X0_REG32 NFMECCD1;
S3C24X0_REG32 NFSECCD;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFESTAT0;
S3C24X0_REG32 NFESTAT1;
S3C24X0_REG32 NFMECC0;
S3C24X0_REG32 NFMECC1;
S3C24X0_REG32 NFSECC;
S3C24X0_REG32 NFSBLK;
S3C24X0_REG32 NFEBLK;
} /*__attribute__((__packed__))*/ S3C2440_NAND;
(2) cpu/arm920t/s3c24x0/speed.c
【1】在#define MPLL 0
#define UPLL 1上面增加
DECLARE_GLOBAL_DATA_PTR;
【2】在 m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;后面 增加
/* support both of S3C2410 and S3C2440 */
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
else
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s)); /* S3C2440 */
【3】增加宏定义
/* for s3c2440 */
#define S3C2440_CLKDIVN_PDIVN (1<<0)
#define S3C2440_CLKDIVN_HDIVN_MASK (3<<1)
#define S3C2440_CLKDIVN_HDIVN_1 (0<<1)
#define S3C2440_CLKDIVN_HDIVN_2 (1<<1)
#define S3C2440_CLKDIVN_HDIVN_4_8 (2<<1)
#define S3C2440_CLKDIVN_HDIVN_3_6 (3<<1)
#define S3C2440_CLKDIVN_UCLK (1<<3)
#define S3C2440_CAMDIVN_CAMCLK_MASK (0xf<<0)
#define S3C2440_CAMDIVN_CAMCLK_SEL (1<<4)
#define S3C2440_CAMDIVN_HCLK3_HALF (1<<8)
#define S3C2440_CAMDIVN_HCLK4_HALF (1<<9)
#define S3C2440_CAMDIVN_DVSEN (1<<12)
【4】get_HCLK get_PCLK函数修改
ulong get_HCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
unsigned long clkdiv;
unsigned long camdiv;
int hdiv = 1;
/* support both of S3C2410 and S3C2440 */
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
else
{
clkdiv = clk_power->CLKDIVN;
camdiv = clk_power->CAMDIVN;
/* work out clock scalings */
switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
case S3C2440_CLKDIVN_HDIVN_1:
hdiv = 1;
break;
case S3C2440_CLKDIVN_HDIVN_2:
hdiv = 2;
break;
case S3C2440_CLKDIVN_HDIVN_4_8:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
break;
case S3C2440_CLKDIVN_HDIVN_3_6:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
break;
}
return get_FCLK() / hdiv;
}
}
/* return PCLK frequency */
ulong get_PCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
unsigned long clkdiv;
unsigned long camdiv;
int hdiv = 1;
/* support both of S3C2410 and S3C2440 */
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
return((clk_power->CLKDIVN & 0x1) ? get_HCLK()/2 : get_HCLK());
else
{
clkdiv = clk_power->CLKDIVN;
camdiv = clk_power->CAMDIVN;
/* work out clock scalings */
switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
case S3C2440_CLKDIVN_HDIVN_1:
hdiv = 1;
break;
case S3C2440_CLKDIVN_HDIVN_2:
hdiv = 2;
break;
case S3C2440_CLKDIVN_HDIVN_4_8:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
break;
case S3C2440_CLKDIVN_HDIVN_3_6:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
break;
}
return get_FCLK() / hdiv / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
}
}
(3) common/env_nand.c
// puts ("*** Warning - bad CRC or NAND, using default environment/n/n"); //HJ_del
注释此句
(4) include/nand.h
struct nand_write_options {结构体中添加
int skipfirstblk; /* if true, skip the first good block*/
(5) include/s3c2410.h
添加:
/* for s3c2440, www.top-e.org */
static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)
{
return (S3C2440_NAND * const)S3C2410_NAND_BASE;
}
5.增加函数实现
(1)common/cmd_load.c
【1】增加函数声明
/* support xmodem*/
static ulong load_serial_xmodem (ulong offset);
并后面添加其函数实现:
/* support xmodem */
static ulong load_serial_xmodem (ulong offset)
{
int size;
char buf[32];
int err;
int res;
connection_info_t info;
char xmodemBuf[1024];
ulong store_addr = ~0;
ulong addr = 0;
size = 0;
info.mode = xyzModem_xmodem;
res = xyzModem_stream_open (&info, &err);
if (!res) {
while ((res =
xyzModem_stream_read (xmodemBuf, 1024, &err)) > 0) {
store_addr = addr + offset;
size += res;
addr += res;
#ifndef CFG_NO_FLASH
if (addr2info (store_addr)) {
int rc;
rc = flash_write ((char *) xmodemBuf,
store_addr, res);
if (rc != 0) {
flash_perror (rc);
return (~0);
}
} else
#endif
{
memcpy ((char *) (store_addr), xmodemBuf,
res);
}
}
} else {
printf ("%s/n", xyzModem_error (err));
}
xyzModem_stream_close (&err);
xyzModem_stream_terminate (false, &getcxmodem);
flush_cache (offset, size);
printf ("## Total Size = 0x%08x = %d Bytes/n", size, size);
sprintf (buf, "%X", size);
setenv ("filesize", buf);
return offset;
}
【2】增加UBOOT命令
/* support xmodem */
U_BOOT_CMD(
loadx, 3, 0, do_load_serial_bin,
"loadx - load binary file over serial line (xmodem mode)/n",
"[ off ] [ baud ]/n"
" - load binary file over serial line"
" with offset 'off' and baudrate 'baud'/n"
);
【3】在
printf ("## Ready for binary (ymodem) download "
"to 0x%08lX at %d bps.../n",
offset,
load_baudrate);前添加
/* support xmodem */
if (strcmp(argv[0],"loadx")==0) {
printf ("## Ready for binary (xmodem) download "
"to 0x%08lX at %d bps.../n",
offset,
load_baudrate);
addr = load_serial_xmodem (offset);
} else if (strcmp(argv[0],"loady")==0) {
(2)common/cmd_nand.c
【1】U_BOOT_CMD(nand, 5, 1, do_nand,中, 增加
"nand read.yaffs addr off size - read the `size' byte yaffs image starting/n"
" at offset `off' to memory address `addr'/n"
"nand write.yaffs addr off size - write the `size' byte yaffs image starting/n"
" at offset `off' from memory address `addr'/n"
【2】在
} else {
/* write */
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
/* opts.forcejffs2 = 1; */
opts.pad = 1;
opts.blockalign = 1;
opts.quiet = quiet;
ret = nand_write_opts(nand, &opts);
}后面添加
}else if ( s != NULL && !strcmp(s, ".yaffs")){
if (read) {
/* read */
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
opts.readoob = 1;
opts.quiet = quiet;
ret = nand_read_opts(nand, &opts);
} else {
/* write */
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
/* opts.forceyaffs = 1; */
opts.noecc = 1;
opts.writeoob = 1;
opts.blockalign = 1;
opts.quiet = quiet;
opts.skipfirstblk = 1;
ret = nand_write_opts(nand, &opts);
}
(3)common/main.c
// run_command (s, 0);此句注释,并添加
boot_zImage(0x4c000,0x200000);
(4)drivers/dm9000x.c
【1】修改
for (i = 0; i < 6; i++)
((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i); char *tmp = getenv("ethaddr");
为:
char *end;
for (i = 0; i < 6; i++)
// ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
{
bd->bi_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
if(tmp)
tmp = (*end) ? end+1 : end;
}
【2】 DM9000_iow(DM9000_IMR, IMR_PAR); /* Enable TX/RX interrupt mask */前添加#if 0
return 0;前添加#endif
(5) drivers/nand/nand_base.c
最后return this->scan_bbt (mtd);
修改为 return 0;
(6) drivers/nand/nand_util.c
【1】 u_char *buffer = opts->buffer;
size_t written;
int result;后面添加
int skipfirstblk = opts->skipfirstblk;
【2】在
readlen = meminfo->oobblock;
if (opts->pad && (imglen < readlen)) {前面添加
/* skip the first good block when wirte yaffs image */
if (skipfirstblk) {
mtdoffset += erasesize_blockalign;
skipfirstblk = 0;
continue;
}
(7)增加新文件 lib_arm/boot_zImage.c
#include <common.h>
#include <command.h>
#include <def.h>
#include <image.h>
#include <zlib.h>
#include <asm/byteorder.h>
#include <s3c2410.h>
#include "asm-arm/mach-types.h"
#define LINUX_KERNEL_OFFSET 0x8000
#define LINUX_PARAM_OFFSET 0x100
#define LINUX_PAGE_SIZE 0x00001000
#define LINUX_PAGE_SHIFT 12
#define LINUX_ZIMAGE_MAGIC 0x016f2818
#define DRAM_SIZE 0x04000000
extern int nand_read_ll_lcd(unsigned char*, unsigned long, int);
/*
* Disable IRQs
*/
#define local_irq_disable() /
({ /
unsigned long temp; /
__asm__ __volatile__( /
"mrs %0, cpsr @ local_irq_disable/n" /
" orr %0, %0, #128/n" /
" msr cpsr_c, %0" /
: "=r" (temp) /
: /
: "memory", "cc"); /
})
static inline void cpu_arm920_cache_clean_invalidate_all(void)
{
__asm__(
" mov r1, #0/n"
" mov r1, #7 << 5/n" /* 8 segments */
"1: orr r3, r1, #63 << 26/n" /* 64 entries */
"2: mcr p15, 0, r3, c7, c14, 2/n" /* clean & invalidate D index */
" subs r3, r3, #1 << 26/n"
" bcs 2b/n" /* entries 64 to 0 */
" subs r1, r1, #1 << 5/n"
" bcs 1b/n" /* segments 7 to 0 */
" mcr p15, 0, r1, c7, c5, 0/n" /* invalidate I cache */
" mcr p15, 0, r1, c7, c10, 4/n" /* drain WB */
);
}
void cache_clean_invalidate(void)
{
cpu_arm920_cache_clean_invalidate_all();
}
static inline void cpu_arm920_tlb_invalidate_all(void)
{
__asm__(
"mov r0, #0/n"
"mcr p15, 0, r0, c7, c10, 4/n" /* drain WB */
"mcr p15, 0, r0, c8, c7, 0/n" /* invalidate I & D TLBs */
);
}
void tlb_invalidate(void)
{
cpu_arm920_tlb_invalidate_all();
}
void call_linux(long a0, long a1, long a2)
{
local_irq_disable();
cache_clean_invalidate();
tlb_invalidate();
__asm__(
"mov r0, %0/n"
"mov r1, %1/n"
"mov r2, %2/n"
"mov ip, #0/n"
"mcr p15, 0, ip, c13, c0, 0/n" /* zero PID */
"mcr p15, 0, ip, c7, c7, 0/n" /* invalidate I,D caches */
"mcr p15, 0, ip, c7, c10, 4/n" /* drain write buffer */
"mcr p15, 0, ip, c8, c7, 0/n" /* invalidate I,D TLBs */
"mrc p15, 0, ip, c1, c0, 0/n" /* get control register */
"bic ip, ip, #0x0001/n" /* disable MMU */
"mcr p15, 0, ip, c1, c0, 0/n" /* write control register */
"mov pc, r2/n"
"nop/n"
"nop/n"
: /* no outpus */
: "r" (a0), "r" (a1), "r" (a2)
: "r0","r1","r2","ip"
);
}
/*
* pram_base: base address of linux paramter
*/
static void setup_linux_param(ulong param_base)
{
struct param_struct *params = (struct param_struct *)param_base;
char *linux_cmd;
// printk("Setup linux parameters at 0x%08lx/n", param_base);
memset(params, 0, sizeof(struct param_struct));
params->u1.s.page_size = LINUX_PAGE_SIZE;
params->u1.s.nr_pages = (DRAM_SIZE >> LINUX_PAGE_SHIFT);
/* set linux command line */
linux_cmd = getenv ("bootargs");
if (linux_cmd == NULL) {
printk("Wrong magic: could not found linux command line/n");
} else {
memcpy(params->commandline, linux_cmd, strlen(linux_cmd) + 1);
// printk("linux command line is: /"%s/"/n", linux_cmd);
}
}
/*
* dst: destination address
* src: source
* size: size to copy
* mt: type of storage device
*/
static inline int copy_kernel_img(ulong dst, const char *src, size_t size)
{
int ret = 0;
ret = nand_read_ll((unsigned char *)dst,
(unsigned long)src, (int)size);
return ret;
}
int boot_zImage(ulong from, size_t size)
{
int ret;
ulong boot_mem_base; /* base address of bootable memory 鍢庡敱? */
ulong to;
ulong mach_type;
boot_mem_base = 0x30000000;
/* copy kerne image */
to = boot_mem_base + LINUX_KERNEL_OFFSET;
printk("Copy linux kernel from 0x%08lx to 0x%08lx, size = 0x%08lx ... ",
from, to, size);
ret = copy_kernel_img(to, (char *)from, size);
if (ret) {
printk("failed/n");
return -1;
} else {
printk("Copy Kernel to SDRAM done,");
}
if (*(ulong *)(to + 9*4) != LINUX_ZIMAGE_MAGIC) {
printk("Warning: this binary is not compressed linux kernel image/n");
printk("zImage magic = 0x%08lx/n", *(ulong *)(to + 9*4));
} else {
// printk("zImage magic = 0x%08lx/n", *(ulong *)(to + 9*4));
;
}
/* Setup linux parameters and linux command line */
setup_linux_param(boot_mem_base + LINUX_PARAM_OFFSET);
/* Get machine type */
mach_type = MACH_TYPE_S3C2440;
// printk("MACH_TYPE = %d/n", mach_type);
/* Go Go Go */
printk("NOW, Booting Linux....../n");
call_linux(0, mach_type, to);
return 0;
}
int do_boot_zImage (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
boot_zImage(0x4c000,0x200000);
return 0;
}
U_BOOT_CMD(
boot_zImage, 3, 0, do_boot_zImage,
"boot_zImage - boot Linux 's zImage/n",
" - boot Linux 's zImage"
);
int boot_noos(ulong from, size_t size)
{
int ret;
ulong boot_mem_base; /* base address of bootable memory 鍢庡敱? */
ulong to;
boot_mem_base = 0x30000000;
/* copy kerne image */
to = boot_mem_base;
printk("Copy code from 0x%08lx to 0x%08lx, size = 0x%08lx ... ",
from, to, size);
ret = copy_kernel_img(to, (char *)from, size);
if (ret) {
printk("failed/n");
return -1;
} else {
printk("Copy code to SDRAM done,");
}
/* Go Go Go */
printk("NOW, Booting code....../n");
run_command("go 0x30000000", 0);
return 0;
}
int do_boot_noos (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
boot_noos(0x4c000,0x200000);
return 0;
}
U_BOOT_CMD(
boot_noos, 3, 0, do_boot_noos,
"boot_noos - boot SKY2440_test/n",
" - boot SKY2440_test"
);
四.u-boot烧写:
1.硬件连接
把JTAG下载板接到并口,把JTAG下载板上和开发板上的JTAG口用JTAG线相连。
2.烧写过程
首先运行SJF2440.exe。点击“开始”中的“运行”,如下图所示:
在弹出的菜单中输入“cmd”点击确定,如下图所示:
在弹出的界面中用DOS命令进入SJF2440所在文件夹打开开发板电源运行SJF2440,过程如下图所示:
选择“0”回车,“0”回车,“0”回车。如下图所示:
烧写成功后按“2”退出,可以连接串口线用DNW查看串口信息设置使用的串口COM和波特率115200
后可以看到u-boot界面如图:
看到界面已经很接近成功了,要检验u-boot是否彻底成功可以将内核烧写到开发板上看看是否可以运行,这将是第三阶段中的内容——内核移植过程。