• 沒有找到結果。

第 3 章 嵌入式系统的 BOOTLOADER

3.3 基于 S3C2410 开发板的 B OOT L OADER 实现

3.3.2 U-Boot 分析与移植

3.3.2.3 U-Boot 的移植过程

main_loop (); /*具体实现参见 common/main.c 文件*/

}

上述讲述了 U-Boot 在 Stage2 主要所做的工作,当然上述给出的只是一般情况下的,可 以根据具体的开发板相应的增加或减少实现代码。下面将介绍基于 S3C2410 开发板的 U-Boot 移植。

3.3.2.3 U-Boot 的移植过程

前面两节对 U-Boot 已经有了较为详细地介绍,本节开始讲述一个具体的 U-Boot 移植实 例,该实例的硬件环境是基于前面所述的 S3C2410 开发板。

软件环境:

l u-boot-1.1.3.tar.bz2(从http://sourceforge.net/projects/u-boot下载)

l arm-linux-gcc 3.3.6(根据第二章内容自己构建或从ftp.arm.kernel.org.uk直接下载)

准备好软、硬件环境后就开始真正的 U-Boot 移植工作了,下面将一步一步介绍移植的 具体过程。

1.修改 Makefile

首先给要建立的 S3C2410 开发板取名为 mike2410,因为 U-Boot 的移植过程需要它。修 改 Makefile 的具体操作如下:

# tar –xvjf u-boot-1.1.3.tar.bz2

# cd u-boot-1.1.3

# vi Makefile

由于 mike2410 开发板和三星的 smdk2410 开发板很相似,所以在移植 U-Boot 时大部分 源代码都以 smdk2410 为模版,然后在此基础上进行修改。此处修改 Makefile 如图 3.2 所示,

在 Makefile 中添加了如下内容:

mike2410_config : unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t mike2400 NULL s3c24x0

其中,mike2400_config:unconfig 意思是为 mike2410 开发板建立一个编译项;第二行中 arm 的意思是 CPU 的架构是基于 ARM 体系的;arm920t 的意思是 CPU 的类型是 arm920t;

mike2410 的意思是开发版的型号;NULL 的意思是开发者或经销商的名称为空;s3c24x0 的意思是基于 s3c24x0 的片上系统。

图 3.2:修改 U-Boot 的 Makefile 2.建立 mike2410 开发板目录

在 board 目录下建立 mike2410 开发板子目录,目前 board 目录下已经有两百多种针对 不同开发板的子目录,由于 mike2410 开发板最接近 smdk2410 开发板,所以可以用下面的 简单方法建立 mike2410 开发板目录:

# cp –fr board/ smdk2410 board/ mike2410

# cd board/ mike2410

# mv smdk2410.c mike2410.c

同时需要修改 board/mike2410/Makefile 文件,修改如图 3.3 所示,修改的内容是 将 COBJS := smdk2410.o flash.o

改为 COBJS := mike2410.o flash.o

由 于 board/mike2410 目 录 下 的 源 代 码 文 件 为 mike2410.c, 所 以 编 译 中 间 文 件 为 mike2410.o,如果没有修改这个 Makefile 文件编译就会出错。

图 3.3 修改 mike2410 目录下的 Makefile 文件 3.建立配置头文件

在 include/configs 目录下建立 mike2410.h 头文件,建立方法如下:

# cd include/configs

# cp -fr smdk2410.h mike2410.h 4.指定交叉编译器的路径

在/etc/bashrc 文件中添加下面一行来指定交叉编译器的路径,这个路径不是绝对的,要 根据交叉编译工具链所放的位置决定。

export PATH=/opt/crosstool/gcc-3.3.6-glibc-2.3.2/arm-linux/bin:$PATH 5.测试编译

这 个步 骤的 目的 一是 为了检 查交 叉编 译器 是否正常 工作 ,二 是为 了测 试新建 的 mike2410 配置项是否能够正常编译,具体操作如下:

# cd u-boot-1.1.6

# make mike2410_config

# make CROSS_COMPILE=arm-linux-

如果编译正确,将在 u-boot-1.1.6 目录下生成 u-boot、u-boot.bin 和 u-boot.srec 三个映像 文件。其中:u-boot 是 ELF 格式二进制的 image 文件,u-boot.bin 是原始的二进制 image 文 件,u-boot.srec 是 Motorola S-Record 格式的 image 文件。到这一步说明建立好了 mike2410 的 U-Boot 编译项,但是具体的实现部分还需要修改,因为现在的实现代码还是完全和 smdk2410 开发板一样的,而不能工作在 mike2410 开发板上,接下来的步骤就是根据 mike2410 开发板的硬件配置和设计要求来进一步移植。

6.修改 start.S 文件

首先在 ldr pc, _start_armboot 一行之前添加下面内容,由于 U-Boot 中没有支持从 NAND Flash 启动,所以将程序自己复制到 DRAM 里面去需要新加代码实现,一般通过

copy_myself 函数来实现,其参考 VIVI 的 copy_myself 代码。

#ifdef CONFIG_S3C2410_NAND_BOOT bl copy_myself

@ jump to ram

ldr r1, =on_the_ram add pc, r1, #0 nop

nop

1: b 1b @ infinite loop on_the_ram:

#endif

然后在_start_armboot: .word start_armboot 一行之后添加下面内容,该部分的内容基本 上都参考 VIVI 代码实现,这段代码的主要目的是搬运 NAND Flash 数据到 DRAM 里面。

#ifdef CONFIG_S3C2410_NAND_BOOT copy_myself:

mov r10, lr

@ reset NAND

mov r1, #NAND_CTL_BASE

ldr r2, =0xf830 @ initial value str r2, [r1, #oNFCONF]

ldr r2, [r1, #oNFCONF]

bic r2, r2, #0x800 @ enable chip str r2, [r1, #oNFCONF]

mov r2, #0xff @ RESET command strb r2, [r1, #oNFCMD]

mov r3, #0 @ wait

1: add r3, r3, #0x1 cmp r3, #0xa blt 1b

2: ldr r2, [r1, #oNFSTAT] @ wait ready tst r2, #0x1

beq 2b

ldr r2, [r1, #oNFCONF]

orr r2, r2, #0x800 @ disable chip str r2, [r1, #oNFCONF]

@ get read to call C functions (for nand_read())

ldr sp, DW_STACK_START @ setup stack pointer mov fp, #0 @ no previous frame, so fp=0

@ copy vivi to RAM

ldr r0, =UBOOT_RAM_BASE

mov r1, #0x0 mov r2, #0x30000 bl nand_read_ll

tst r0, #0x0

beq ok_nand_read

#ifdef CONFIG_DEBUG_LL bad_nand_read:

ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord

1: b 1b @ infinite loop

#endif

ok_nand_read:

#ifdef CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord

#endif

@ verify

mov r0, #0

ldr r1, =UBOOT_RAM_BASE

mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes go_next:

ldr r3, [r0], #4 ldr r4, [r1], #4

teq r3, r4

bne notmatch subs r2, r2, #4

beq done_nand_read bne go_next

notmatch:

#ifdef CONFIG_DEBUG_LL sub r0, r0, #4

ldr r1, SerBase

bl PrintHexWord ldr r0, STR_FAIL ldr r1, SerBase

bl PrintWord

#endif

1: b 1b

done_nand_read:

#ifdef CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord

#endif

mov pc, r10

@ clear memory

@ r0: start address

@ r1: length mem_clear:

mov r2, #0 mov r3, r2

mov r4, r2 mov r5, r2 mov r6, r2 mov r7, r2 mov r8, r2 mov r9, r2

clear_loop:

stmia r0!, {r2-r9}

subs r1, r1, #(8 * 4) bne clear_loop mov pc, lr

#endif @ CONFIG_S3C2410_NAND_BOOT

接着在 start.S 文件最后添加下面几行的内容,用于定义栈地址变量。到这里 start.S 文 件已经修改完毕,接着添加 NAND Flash 读函数。

#ifdef CONFIG_S3C2410_NAND_BOOT .align 2

DW_STACK_START:

.word STACK_BASE+STACK_SIZE-4

#endif

7.添加 nand_read.c 和 nandflash.h 源文件

在 start.S 文件中调用了 nand_read_ll 函数,该函数用于 NAND Flash 读操作,在 U-Boot 中没有定义,需要新加该函数的实现,该函数的实现可以参考 VIVI 源代码,在 board/mike2410 目录下新建 nand_read.c 源文件,文件内容下:

#include <config.h>

#define __REGb(x) (*(volatile unsigned char *)(x))

#define __REGi(x) (*(volatile unsigned int *)(x))

#define NF_BASE 0x4e000000

#define NFCONF __REGi(NF_BASE + 0x0)

#define NFCMD __REGb(NF_BASE + 0x4)

#define NFADDR __REGb(NF_BASE + 0x8)

#define NFDATA __REGb(NF_BASE + 0xc)

#define NFSTAT __REGb(NF_BASE + 0x10)

#define BUSY 1

inline void wait_idle(void) { int i;

while(!(NFSTAT & BUSY)) for(i=0; i<10; i++);

}

#define NAND_SECTOR_SIZE 512

#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)

/* low level nand read function */

int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) {

int i, j;

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { return -1; /* invalid alignment */

}

/* chip Enable */

NFCONF &= ~0x800;

for(i=0; i<10; i++);

for(i=start_addr; i < (start_addr + size);) { /* READ0 */

NFCMD = 0;

/* Write Address */

NFADDR = i & 0xff;

NFADDR = (i >> 9) & 0xff;

NFADDR = (i >> 17) & 0xff;

NFADDR = (i >> 25) & 0xff;

wait_idle();

for(j=0; j < NAND_SECTOR_SIZE; j++, i++) { *buf = (NFDATA & 0xff);

buf++;

} }

/* chip Disable */

NFCONF |= 0x800; /* chip disable */

return 0;

}

新建完 nand_read.c 文件后,需要修改相同目录下的 Makefile 文件,否则编译会出错,

修改内容为:

将 COBJS := mike2410.o flash.o

改为:COBJS := mike2410.o flash.o nand_read.o

同时需要在 board/mike2410 目录下添加 nandflash.h 文件,该文件主要定义了 NAND Flash 的一些芯片配置函数,具体代码如下:

#include <s3c2410.h>

#if (CONFIG_COMMANDS & CFG_CMD_NAND) typedef enum {

NFCE_LOW, NFCE_HIGH } NFCE_STATE;

static inline void NF_Conf(u16 conf) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCONF = conf;

}

static inline void NF_Cmd(u8 cmd) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCMD = cmd;

}

static inline void NF_CmdW(u8 cmd) {

NF_Cmd(cmd);

udelay(1);

}

static inline void NF_Addr(u8 addr) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFADDR = addr;

}

static inline void NF_SetCE(NFCE_STATE s) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

switch (s) {

case NFCE_LOW:

nand->NFCONF &= ~(1<<11);

break;

case NFCE_HIGH:

nand->NFCONF |= (1<<11);

break;

} }

static inline void NF_WaitRB(void) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

while (!(nand->NFSTAT & (1<<0)));

}

static inline void NF_Write(u8 data) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFDATA = data;

}

static inline u8 NF_Read(void) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

return(nand->NFDATA);

}

static inline void NF_Init_ECC(void) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCONF |= (1<<12);

}

static inline u32 NF_Read_ECC(void) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

return(nand->NFECC);

}

#endif

8.修改 mike2410.c 文件

修改这个文件的主要目的有两个,一是初始化 CPU 相关寄存器来支持 USB 主、从设备;

二是初始化 NAND Flash 设备。添加代码如下:

#include "nandflash.h" //添加该头文件

int board_init (void) {

……

/* 根据 S3C2410 用户手册,设置相应的寄存器值来支持 USB*/

gpio->MISCCR |= (1<<3);

gpio->MISCCR &= ~((1<<12)|(1<<13));

……

}

/* 添加以下代码实现 NAND flash 的初始化*/

#if (CONFIG_COMMANDS & CFG_CMD_NAND) extern ulong nand_probe(ulong physadr);

static inline void NF_Reset(void) {

int i;

NF_SetCE(NFCE_LOW);

NF_Cmd(0xFF); /* reset command */

for(i = 0; i < 10; i++); /* tWB = 100ns. */

NF_WaitRB(); /* wait 200~500us; */

NF_SetCE(NFCE_HIGH);

}

static inline void NF_Init(void) {

#if 0 /* a little bit too optimistic */

#define TACLS 0

#define TWRPH0 3

#define TWRPH1 0

#else

#define TACLS 0

#define TWRPH0 4

#define TWRPH1 2

#endif

NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TW RPH1<<0));

NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TW RPH1<<0));

}

void nand_init(void) {

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

NF_Init();

#ifdef DEBUG

printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);

#endif

printf ("%4lu KB\n", nand_probe((ulong)nand) >> 10);

}

#endif

9.修改头文件 mike2410.h

修改 include/configs/ mike2410.h 文件,在该文件中添加如下内容,其中定义了栈的基地 址和、栈的大小、RAM 的基地址以及定义 NAND Flash 设置参数等内容。

……

#define CONFIG_CMDLINE_TAG 1

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG 1

……

#define CONFIG_COMMANDS \

(CONFIG_CMD_DFL | \ CFG_CMD_CACHE | \ CFG_CMD_ENV | \ CFG_CMD_PING | \ CFG_CMD_NAND | \ /*CFG_CMD_EEPROM |*/ \ /*CFG_CMD_I2C |*/ \ CFG_CMD_REGINFO | \ CFG_CMD_ELF)

……

/* Nandflash Boot */

#define CONFIG_S3C2410_NAND_BOOT 1

#define STACK_BASE 0x33ff8000

#define STACK_SIZE 0x8000

#define UBOOT_RAM_BASE 0x33f00000

/* NAND Flash Controller */

#define NAND_CTL_BASE 0x4E000000

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

#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

#define NAND_WAIT_READY(nand) NF_WaitRB()

#define NAND_DISABLE_CE(nand) NF_SetCE(NFCE_HIGH)

#define NAND_ENABLE_CE(nand) NF_SetCE(NFCE_LOW)

#define WRITE_NAND_COMMAND(d, adr) NF_Cmd(d)

#define WRITE_NAND_COMMANDW(d, adr) NF_CmdW(d)

#define WRITE_NAND_ADDRESS(d, adr) NF_Addr(d)

#define WRITE_NAND(d, adr) NF_Write(d)

#define READ_NAND(adr) NF_Read()

/* the following functions are NOP's because S3C24X0 handles this in hardware */

#define NAND_CTL_CLRALE(nandptr)

#define NAND_CTL_SETALE(nandptr)

#define NAND_CTL_CLRCLE(nandptr)

#define NAND_CTL_SETCLE(nandptr)

#define CONFIG_MTD_NAND_VERIFY_WRITE 1

#define CONFIG_MTD_NAND_ECC_JFFS2 1

#endif /* CONFIG_COMMANDS & CFG_CMD_NAND */

然后修改以下各宏的值,包括内存相关的地址、启动提示字母和网络的设置。

#define CFG_MEMTEST_END 0x33F00000 /* 64 MB in DRAM */

#define CFG_LOAD_ADDR 0x30008000 /* default load address */

#define PHYS_SDRAM_1_SIZE 0x04000000 /*64 MB */

#define CFG_PROMPT "MIKE2410 # " /* Monitor Command Prompt */

#define CONFIG_IPADDR 192.168.1.10

#define CONFIG_SERVERIP 192.168.1.1

#define CFG_ENV_IS_IN_NAND 1

#define CFG_ENV_OFFSET 0x30000 10.修改 cmd_nand.c 文件

cmd_nand.c 文件在 commom 目录下,修改该文件的目的就是添加包含 nandflash.h 的头 文件,因为如果没有包含该头文件,编译时将出错如图 3.4 所示,正是因为该文件调用了 nandflash.h 头文件中的变量而没有包含该头文件引起的,包含该头文件后将编译正确。

图 3.4 没有包含 nandflash.h 引起的错误 11.重新编译

如果以上步骤都正确的话,执行下面的编译命令,将会在 U-Boot 的根目录下重新生成 u-boot.bin 可执行性文件。

# make all ARCH=arm CROSS_COMPILE = arm-linux- 12.用 Jtag 烧写 u-boot.bin 文件

用开发板上自带的 Jtage 线和开发板连接,使用三星公司提供的 SJF(Sec Jtag Flash)工具 将上面生成的 u-boot.bin 文件烧写到开发板上,烧写过程如图 3.5 所示。

图 3.5 用 SJF 烧写 U-Boot 的过程

正确烧写完 u-boot.bin 文件后,运行超级终端或 DNW 软件,DNW 是三星公司提供的 一个使用方便的串口调试软件,断开 Jtag 线,连上串口线,给开发板上电,将在屏幕中显 示如下信息,表明 U-Boot 正常启动了。

U-Boot 1.1.3 (Jan 21 2007 - 20:26:48)

U-Boot code: 33F80000 -> 33F99A28 BSS: -> 33F9DD4C RAM Configuration:

Bank #0: 30000000 64 MB Flash: 512 kB

NAND:65536 KB

*** Warning - bad CRC or NAND, using default environment In: serial

Out: serial Err: serial MIKE2410#

U-Boot 提供了许多命令,通常使用 help 或“?”来查看 U-Boot 的所有命令,查看结果 如下。

MIKE2410# help

? - alias for 'help' autoscr - run script from memory base - print or set address offset bdinfo - print Board Info structure boot - boot default, i.e., run 'bootcmd' bootd - boot default, i.e., run 'bootcmd' bootelf - Boot from an ELF image in memory bootm - boot application image from memory

bootp - boot image via network using BootP/TFTP protocol bootvx - Boot vxWorks from an ELF image

cmp - memory compare

coninfo - print console devices and information cp - memory copy

crc32 - checksum calculation dcache - enable or disable data cache echo - echo args to console erase - erase FLASH memory

flinfo - print FLASH memory information go - start application at address 'addr' help - print online help

icache - enable or disable instruction cache

iminfo - print header information for application image imls - list all images found in flash

itest - return true/false on integer compare

loadb - load binary file over serial line (kermit mode)

nfs - boot image via network using NFS protocol nm - memory modify (constant address) ping - send ICMP ECHO_REQUEST to network host printenv- print environment variables

protect - enable or disable FLASH write protection

rarpboot- boot image via network using RARP/TFTP protocol reset - Perform RESET of the CPU

run - run commands in an environment variable saveenv - save environment variables to persistent storage setenv - set environment variables

sleep - delay execution for some time

tftpboot- boot image via network using TFTP protocol version - print monitor version

以下将介绍 U-Boot 常用命令:

boot_params = 0x30000100 //启动引导参数

3.tftp(tftpboot):利用 tftp 协议将 PC 本地上的映象文件下载到指定地址的 SDRAM 中,

执行该命令的前提是所用 PC 上已经安装了 tftp 服务。具体使用方法如下:

MIKE2410# tftp 0x30008000 zImage

TFTP from server 192.168.1.5; our IP address is 192.168.1.10 Filename 'zImage'.

Load address: 0x30008000

Loading: #################################################################

#################################################################

############################################

done

Bytes transferred = 890752 (d9780 hex)

其中,0x30008000 为指定下载到 SDRAM 的地址,zImage 为下载映象的文件名。

4.bootm:从内核的入口地址引导内核。具体使用方法如下:

MIKE2410# bootm 0x30008000

## Booting image at 30008000 ...

Starting kernel ...

Uncompressing Linux...done, booting the kernel.

5.go:直接跳转到可执行性文件的入口地址,执行可执行性文件。使用方法如下:

5.go:直接跳转到可执行性文件的入口地址,执行可执行性文件。使用方法如下: