第二阶段:boorloader的移植

来源:互联网 发布:ed2k网络连接不上 编辑:程序博客网 时间:2024/06/08 17:29

第二阶段: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

2vivi

vivi是韩国mizi 公司开发的bootloader, 适用于ARM9处理器。 Vivi有两种工作模式:启动加载模式和下载模式。启动加载模式可以在一段时间后(这个时间可更改)自行启动linux内核,这vivi的默认模式。如果修改或更新需要进入下载模式,在下载模式下,vivi为用户提供一个命令行接口通过接口可以使用vivi提供的一些命令,来实现flash的烧写、管理、操作mtd分区信息、启动系统等功能。 

其它还有一些bootloader实现如下表所示:

名称

说明

支持的架构

LILO

Linux的磁盘引导加载程序

x86

GRUB

LILOGNU版本

x86

Loadlin

DOS引导Linux

x86

RedBoot

eCos为基础的引导程序

x86 ARMPowerPCMIPS

ROLO

ROM引导Linux,且不需要BIOS

x86

Etherboot

从以太网卡启动Linux系统的固件

x86

LinuxBIOS

Linux为基础的BIOS的替代品

x86

blob

来自LART计划的引导程序

ARM

由于u-boot的通用性好,功能全面,适合初学者学习和使用,我们选用u-boot作为基准代码,在此基础上进行修改,完成移植工作。

二.移植准备

1.目标板: 

这是进行U-Boot移植首先要明确的。可以根据目标板上CPUFLASHSDRAM的情况,以尽可能相一致为原则,先找出 一个与所移植目标板为同一个或同一系列处理器的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

和一些已有开发板有关的文件,比如makefileU-Boot.ldS等都和具体开发板的硬件和地址分配有关。

common

与体系结构无关的文件,实现各种命令的C文件

cpu

 CPU相关文件,其中的子目录都是以U-Boot所支持的CPU为名,比如子目录arm926ejSmips等,每个特定的子目录都包括cpu.cinterrupt.cstart.s。其中cpu.c初始化CPU、设置指令cache和数据cache等。Interruput.c设置系统的各种中断和异常;start.sU-Boot自动执行时的第一个文件,它主要是设置系统堆栈和工作方式,为进入C程序奠定基础。

disk

Disk驱动的分区处理代码

doc

文档

drivers

通用设备驱动程序,例如各种网卡、支持CFIFlash、串口、USB

fs

支持文件系统的文件,目前支持cramfsfatfdosjffs2registerfs

include

头文件,还有对各种硬件平台支持的汇编文件,系统配置文件等

net

与网络有关的代码,BOOTP协议、TFTP协议、RARPNFS

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模式、禁止IRQFIQ、关闭看门狗、屏蔽所有中断。设置时钟(FCLK,HCLK,PCLK)、清空I/D cache、清空TLB、禁止MMUcache、配置内存控制器、为搬运代码做准备、搬移uboot映像到RAM中(使用copy_loop实现)、分配堆栈、清空bss段(使用clbss_l实现)。

第二阶段(stage 2)通常用C语言来实现。

start_armboot(): 

     一系列初始化(cpu, 板卡,中断,串口,控制台等),开启I/D cache。初始化FLASH,根据系统配置执行其他初始化操作。打印LOG,使能中断,获取环境变量,初始化网卡。最后进入main_loop()函数。在main_loop函数中会检查bootdelaybootcmd环境变量,如果bootcmd已经设置过,则在等待bootdelay个毫秒后会自动执行bootcmd。如果等待过程中被用户中断(ctl+c)或者bootcmd没有设置,则会等待用户输入命令。   

关键点一: U-Boot移植参考板

     这是进行U-Boot移植首先要明确的。可以根据目标板上CPUFLASHSDRAM的情况,以尽可能相一致为原则,先找出 一个与所移植目标板为同一个或同一系列处理器的U-Boot支持板为移植参考板。对U-Boot移植新手,建议依照循序渐进的原则,目标板文件名暂时先用移 植参考板的名称,在逐步熟悉U-Boot移植基础上,再考虑给目标板重新命名。在实际移植过程中,可用Linux命令查找移植参考板的特定代码,如 grep –r 2410 ./ 可确定出在U-Boot中与smdk2410板有关的代码,依此对照目标板实际进行屏蔽或修改。同时应不局限于移植参考板中的代码,要广泛借鉴U-Boot 中已有的代码更好地实现一些具体的功能。 

关键点二: U-Boot烧写地址和CPU寄存器参数设置 

     不同目标板,对U-BootFLASH中存放地址要求不尽相同。事实上,这是由处理器中断复位向量来决定的,与主板硬件相关 。也就是说,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有两个PLLphase locked loop)一个是MPLL,一个是UPLLMPLL用于CPU及其他外围器件,UPLL用于USB      

     1MPLL, 用于产生FCLK, HCLK, PCLK三种频率, 这三种频率分别有不同的用途:

     FCLKCPU提供的时钟信号。
     HCLK是为AHB总线提供的时钟信号, Advanced High-performance Bus,主要用于高速外设,比如内存控制器,中断控制器,LCD控制器, DMA 等。 

S3C2440DataSheet里可以看到,S3C2440最大支持400MHz的主频,但是这并不意味着一定工作在400MHz下面,可以通过设定MPLL, UPLL寄存器来设定CPU的工作频率。

     PCLK是为APB总线提供的时钟信号,Advanced Peripherals Bus,主要用于低速外设,比如看门狗,UART控制器, IIS, I2C, SDI/MMC, GPIORTC and SPI等。

     2UPLL,专门用于驱动USB host/Device。并且驱动USB host/Device的频率必须为48MHz

   果要设置MPLLUPLL,要注意它们的先后顺序,MPLLUPLL的设定是有前后顺序的,必须先设定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;

}

6lowlevel_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)

4get_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

 1U_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是否彻底成功可以将内核烧写到开发板上看看是否可以运行,这将是第三阶段中的内容——内核移植过程。

原创粉丝点击