基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH)

买到开发板之初,就开始移植u-boot,问题多多,加上扳子硬件烧写出了问题,折腾半个多月,放弃,一种挫败感久久不能抹去;偶然间发现扬创开发板“基于u-boot移植修改完善”的utu-bootloader,买之,回来打开光盘一看,暂不提供u-boot移植源代码。凭着职业的冷静,我克制住,和网上的朋友一样,奋战几个夜晚,完成了从NAND FLASH启动、NAND FLASH读写、内核引导。
移植过程中,参考了网上资料,列举如下:
《uboot1.1.4移植》网址:
http://hi.baidu.com/edaworld/blog/item/c40f83a8a2e6d1b5cb130cca.html
《uboot for s3c2410 nandboot 使用saveenv保存环境变量》网址:
http://blog.chinaunix.net/u1/56388/showart_438720.html
《基于smdk2410 开发板u-boot-1.2.0 对 nand flash的支持》PDF文档。
同时推荐博客:http://blog.chinaunix.net/u1/34474/showart.php?id=363269

一、移植前说明:

1. 工作环境:
Fedora 8 ,内核2.6.25
交叉编译器:
Arm-linux-gcc 3.3.2
目标板:
优龙FS2410,NAND Flash:64M K9F1208,NOR Flash:2M SST39VF1601 (本次移植不包含NOR Flash 支持), RAM 64M ,CS8900Q3

2. 下载源码,建立工作目录
u-boot的源码可以从以下网址下载:
http://downloads.sourceforge.net/u-boot/u-boot-1.1.6.tar.bz2
建立工作目录:
mkdir /uboot
cd /uboot
把下载的源码拷贝到该目录,解压;
tar jxvf u-boot-1.1.6.tar.bz2

二、移植步骤如下:

(1)、建立自己fs2410开发板的配置

1)# cp –r board/smdk2410 board/fs2410
2)# cp include/configs/smdk2410.h include/configs/fs2410.h

fs2410.h是开发板的配置文件,他包括开发板的CPU、系统时钟、RAM、FLASH系统及其他相关的配置信息,由于u-boot已经支持三星的SMDK2410开发板,所以移植的时候直接拷贝SMDK2410的配置文件,做相应的修改即可。由于Uboot对SMDK2410板的NAND Flash初始化部分没有写,即lib_arm/board.c中的start_armboot函数中有这么一句:
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* go init the NAND */
#endif
但是在board/smdk2410目录下源文件中都没有定义nand_init这个函数。所以需要我们补充这个函数以及这个函数涉及的底层操作,NAND Flash的读写操作相对复杂,将在u-boot-1.1.6移植的第二部分介绍。

(2). 修改顶层Makefile

cd /uboot/u-boot-1.1.6
vi Makefile
找到:
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
在其后面添加:
fs2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t fs2410 NULL s3c24x0

各项的意思如下:
arm: CPU的架构(ARCH)
arm920t: CPU的类型(CPU),其对应于cpu/arm920t子目录。
fs2410: 开发板的型号(BOARD),对应于board/fs2410目录。
NULL: 开发者/或经销商(vender)。
s3c24x0: 片上系统(SOC)。
(3). include/configs/fs2410.h:

修改:
# define CFG_PROMPT “SMDK2410 #”
为:
# define CFG_PROMPT “fs2410 #”
这是u-boot的命令行提示符。
(4) 修改board/fs2410/Makefile
将:
OBJS := smdk2410.o flash.o
改为:
OBJS := fs2410.o flash.o
当然,fs2410下的 smdk2410.c要改成fs2410.c;
(5)依照你自己开发板的内存地址分配情况修改board/fs2410/lowlevel_init.S文件
这里我参考了FS2410开发板自带S3C2410_BIOS,代码如下:
#include
#include
/* some parameters for the board */
/*
*
* Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
*
* Copyright (C) 2002 Samsung Electronics SW.LEE
*
*/
#define BWSCON 0x48000000
/* BWSCON */
#define DW8 (0x0)
#define DW16 (0x1)
#define DW32 (0x2)
#define WAIT (0x1
(6)测试编译能否成功:
make fs2410_config
make
如果没有问题,在u-boot-1.1.6目录下就生成u-boot.bin,因为到这一步只是做了点小改动,并未涉及敏感问题,测试一下可增加点信心,烧到扳子看到如图1所示。当然也有make不成功的时候,如按照上述步骤编译u-boot-1.1.5的时候,出现“没有规则创建'all'需要的目标'hello_world.srec'”,如图1所示,解决方法:
把example文件夹下的Makefile中的
第147行
%.srec: % 改成: %.srec: %.o
第150行
%.bin: % 改成: %.bin: %.o
网上还有一种改法,我没试过,不作说明。
(7)在board/fs2410加入NAND Flash读函数,建立nand_read.c,加入如下内容(copy from vivi):
#include #include "linux/mtd/mtd.h"

#include "linux/mtd/nand.h"

#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;
}


(10)修改cpu/arm920t/start.S文件
2410的启动代码可以在外部的NAND FLASH上执行,启动时,NAND FLASH的前4KB(地址为0x00000000,OM[1:0]=0)将被装载到SDRAM中被称为Setppingstone的地址中,然后开始执行这段代码。启动以后,这4KB的空间可以做其他用途,在start.S加入搬运代码如下:
...........
...........
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
/*08-6-24********************************************************/
#ifdef CONFIG_S3C2410_NAND_BOOT /*这个一定要放在堆栈设置之前*/
bl copy_myself
#endif /*CONFIG_S3C2410_NAND_BOOT*/
/*08-6-24********************************************************/
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up the stack */
stack_setup:
..................
/**************************************************************************
*
* copy u-boot to ram 放在start.S靠后的位置
*
*************************************************************************
*/
#ifdef CONFIG_S3C2410_NAND_BOOT
/*
@ copy_myself: copy u-boot to ram
*/
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
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0

@ copy UBOOT to RAM
ldr r0, _TEXT_BASE
mov r1, #0x0
mov r2, #0x20000
bl nand_read_ll

teq r0, #0x0
beq ok_nand_read

bad_nand_read:
1: b 1b @ infinite loop

ok_nand_read:

@ verify

mov r0, #0
ldr r1, _TEXT_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:
1: b 1b
done_nand_read:

mov pc, r10

#endif
@ CONFIG_S3C2440_NAND_BOOT

DW_STACK_START:
.word STACK_BASE STACK_SIZE-4

(11)修改include/configs/fs2410.h文件,添加如下内容:
/*08-6-25***************************************************/
/*-----------------------------------------------------------------------
* NAND FLASH BOOT
*/
#define CONFIG_S3C2410_NAND_BOOT 1
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x8000
#define UBOOT_RAM_BASE 0x30100000

#define NAND_CTL_BASE 0x4e000000
#define bINT_CTL(Nb) _REG(INT_CTL_BASE (Nb))


#define oNFCONF 0x00
#define oNFCMD 0x04
#define oNFADDR 0x08
#define oNFDATA 0x0c
#define oNFSTAT 0x10
#define oNFECC 0x14
/*--------------------------------------------------------------------*/
#define NAND_MAX_CHIPS 1
(12)修改board/fs2410/Makefile OBJS := fs2410.o flash.o nand_read.o
(13)重新编译u-boot
make fs2410_config
make
13)通过fs2410的NOR FLASH上的BIOS将u-boot.bin烧写到nand flash中就可以从NAND flash启动了
我的u-boot启动信息如图2所示,可以看出:和第一次make的结果一样,u-boot命令依然不能用,也就是说不能用saveenv保存设置,因为我们现在只是完成了u-boot从NAND FLASH的启动工作,添加了nand_read.c函数,而不能实现写操作,在《基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (二)》中将实现u-boot的一些命令,tftp、 saveenv、 go等。
附件:
图1

图2

 

 

本文实现u-boot的写操作,实验过程中,参考了网上资料,列举如下:
《uboot1.1.4移植》网址:
http://hi.baidu.com/edaworld/blog/item/c40f83a8a2e6d1b5cb130cca.html
《uboot for s3c2410 nandboot 使用saveenv保存环境变量》网址:
http://blog.chinaunix.net/u1/56388/showart_438720.html
《基于smdk2410 开发板u-boot-1.2.0 对 nand flash的支持》PDF文档。
涉及文件:
common/env_nand.c
Driver/nand_legacy/ nand_legacy.c
Include/configs/fs2410.h
具体修改分析:
Lib_arm/board.c
u-boot 运行至第二阶段进入 start_armboot()函数。其中 nand_init()函数是对 nand flash 的最初初始化函数。其调用与 CFG_NAND_LEGACY 宏有关,如果没定义 CFG_NAND_LEGACY 这个宏,就按照start_armboot()调用 drivers/nand/nand.c 中的 nand_init 函数(该函数在 1.1.6 已经被实现), 但还有个 board_nand_init()函数没实现,需自己添加。如果定义了CFG_NAND_LEGACY,就不使用默认的 nand_init,而调用自己写的 nand_init 函数了,这里我们选择第二种方式。
具体步骤如下:
1. 加入 NAND 闪存芯片型号
在/include/linux/mtd/ nand_ids.h 中对如下结构体赋值进行修改:
static struct nand_flash_dev nand_flash_ids[]= {
......
{"Samsung K9F1208U0M", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0}, /*2008-6-25*/
......
}
这样对于该款 NAND 闪存芯片的操作才能正确执行。
2. 编写 NAND 闪存初始化函数
在/drivers/nand_legacy/nand_legacy.c 中加入 nand_init()函数。
/*08-6-25 START*/
/*-----------------------------------------------------------------------
* NAND flash basic functions
* Added by wei jing 2008.6.25
* Copied from board/mpl/vcma9/vcma9.h & vcma9.c
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#include
/*----------------------------------------------------------------------*/
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 &= ~(1NFCONF |= (1NFSTAT & (1NFDATA = 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 |= (1NFECC);
}
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 NFCONF = (1> 20);
}
#endif /* CONFIG_COMMANDS & CFG_CMD_NAND */
/*08-6-25 END*****************************************************/
/*
* Exported variables etc.
*/
可以看到 nand_init()调用 NF_Init()函数,使能 nand flash 控制器和 nand flash;调用 NF_Reset()函数置位,NF_WaitRB()查询 nand flash 的状态,最后在调用 nand_probe((ulong)nand)函数探测 nand flash.
3. 修改include/configs/fs2410.h,在上次修改的基础上加上如下代码,定义 NAND 闪存命令层的底
接口函数等:
#define CFG_NAND_LEGACY 1//#define NFCE_LOW 0//#define NFCE_HIGH 1#define CFG_ENV_IS_IN_NAND 1#define CFG_NAND_BASE 0x4E000000#define CMD_SAVEENV#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ #define CFG_ENV_OFFSET 0x20000 /*环境变量在NAND FLASH的0x20000处*/#define CFG_MONITOR_BASE PHYS_SDRAM_1 /*----------------------------------------------------------------------- * NAND flash settings */ #if (CONFIG_COMMANDS & CFG_CMD_NAND)#define CFG_NAND_LEGACY#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 */ /*08-6-25***************************************************/
4. 在fs2410.h中打开命令:
/***********************************************************
* Command definition
***********************************************************/
#define CONFIG_COMMANDS
(CONFIG_CMD_DFL |
CFG_CMD_CACHE |
CFG_CMD_ENV |
CFG_CMD_NET |
CFG_CMD_PING |
CFG_CMD_NAND | /* 打开 nand flash 命令 */
/*CFG_CMD_EEPROM |*/
/*CFG_CMD_I2C |*/
/*CFG_CMD_USB |*/
CFG_CMD_REGINFO |
CFG_CMD_DATE |
CFG_CMD_ELF)
好了,make一下,看看结果,很不幸运,/env_nand.c:206 undefined reference to 'nand_info'等等问题,如图1所示,原来nand flash 真正的擦除和读写函数使用的是 drivers/nand_legacy/ 目录下面的读写、擦除函数
int nand_legacy_erase(struct nand_chip* nand, size_t ofs,size_t len, int clean);
int nand_legacy_rw(struct nand_chip* nand, int cmd,size_t start, size_t len,size_t * retlen, u_char * buf);
5. 修改saveenv中对nand的读写函数为nand_legacy的读写函数,修改common/env_nand.c如下:
#include
#if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */
#include
#include
#include
#include
#include
#if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_NAND)) == (CFG_CMD_ENV|CFG_CMD_NAND))
#define CMD_SAVEENV
#elif defined(CFG_ENV_OFFSET_REDUND)
#error Cannot use CFG_ENV_OFFSET_REDUND without CFG_CMD_ENV & CFG_CMD_NAND
#endif
#if defined(CFG_ENV_SIZE_REDUND) && (CFG_ENV_SIZE_REDUND != CFG_ENV_SIZE)
#error CFG_ENV_SIZE_REDUND should be the same as CFG_ENV_SIZE
#endif
#ifdef CONFIG_INFERNO
#error CONFIG_INFERNO not supported yet
#endif
/* My Add*/

int nand_legacy_erase(struct nand_chip* nand,

size_t ofs, size_t len, int clean);
int nand_legacy_rw (struct nand_chip* nand, int cmd,
size_t start, size_t len,
size_t * retlen, u_char * buf);
/* My Add*/

extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
/* info for NAND chips, defined in drivers/nand/nand.c */
//extern nand_info_t nand_info[];
nand_info_t nand_info[CFG_MAX_NAND_DEVICE];
/* references to names in env_common.c */
extern uchar default_environment[];
extern int default_environment_size;
......
......
#else /* ! CFG_ENV_OFFSET_REDUND */
int saveenv(void) /* 2008-6-26 by weij */
{
ulong total;
int ret = 0;
puts ("Erasing Nand...");
//if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
if (nand_legacy_erase(nand_dev_desc 0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))
return 1;
puts ("Writing to Nand... ");
total = CFG_ENV_SIZE;
//ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
nand_legacy_rw(nand_dev_desc 0, 0x00 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return 1;
puts ("done ");
return ret;
}
#endif /* CFG_ENV_OFFSET_REDUND */
......
......
/*
* The legacy NAND code saved the environment in the first NAND device i.e.,
* nand_dev_desc 0. This is also the behaviour using the new NAND code.
*/
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
ulong total;
int ret;
total = CFG_ENV_SIZE;
//ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
ret=nand_legacy_rw(nand_dev_desc 0, 0x01 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return use_default();
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}
#endif /* CFG_ENV_OFFSET_REDUND */
......
......
修改完毕,make一下,看到了期盼的画面如图2、3所示,由于能够saveenv,所以就没有了warning -bad CRC的警告,ping一下,主机能用,ok,tftp一下,Loading: TTTTT,如图4所示,莫惊慌,《基于smdk2410 开发板u-boot-1.2.0 对 nand flash的支持》PDF文档中,说把某段代码注释掉,其实我的是防火墙关掉就ok,图5、6是tftp优龙自带的S3C2410_BIOS.bin 到RAM然后go的结果。下一篇将完成内核引导……

图1
[/url]

图2、3



4


图5、6

[url=http://img.blog.163.com/photo/2DXpTBwU6663PqSy_cDVGw==/5067956955675801272.jpg]

 

 

 

 

首先引用《嵌入式系统 Boot Loader 技术内幕》的一段话:Boot Loader 的设计与实现是一个非常复杂的过程。如果不能从串口收到那激动人心的"uncompressing linux.................. done, booting the kernel……"内核启动信息,恐怕谁也不能说:"嗨,我的 boot loader 已经成功地转起来了!" 我对此深有体会,这就是为什么这篇文章推迟一个星期才出来的原因。
u-boot实现linux内核引导步骤:
1、U-BOOT给linux内核传递合适参数的定义
修改include/configs/fs2410.h如下:
……
……
/************************************************************
* RTC
************************************************************/
#define CONFIG_RTC_S3C24X0 1
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#define CONFIG_BAUDRATE 115200

/************************************************************/
/* enable passing of ATAGs */
#define CONFIG_CMDLINE_TAG 1
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1

/***********************************************************
* Command definition
***********************************************************/
#define CONFIG_COMMANDS
(CONFIG_CMD_DFL |
CFG_CMD_CACHE |
CFG_CMD_NAND |
/*CFG_CMD_EEPROM |*/
/*CFG_CMD_I2C |*/
/*CFG_CMD_USB |*/
CFG_CMD_REGINFO |
CFG_CMD_DATE |
CFG_CMD_ELF)
……
……
2、修改UBOOT的2410CPU频率
smdk2410的U-BOOT原来运行频率是202.8M,而FS2410的BIOS里面是200M,所以不修改频率可能会出点问题。按照网上的说法,内核中,在archarmmach_s3c2410s3c2410.c 中,fclk = s3c2410_get_pll(MPLLCON, xtal); //读出来的fclk结果和bootloader的频率不一致。
修改board/fs2410/fs2410.c文件如下:
#define FCLK_SPEED 1
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif
3、修改include/configs/fs2410.h中的CFG_LOAD_ADDR的地址为0x30007FC0
这是内核的加载地址,board/smdk2410/config.mk文件注释中提到Linux内核希望自己被加载到0x30008000的内存地址,而由于uImage会在kernel镜像之前加上大小为0x40的头文件消息,所以需要减去0x40。
4、制作uImage
在编译内核的时候如果用命令make uImage来生成uImage的话,我发现Load Address 30008000, Entry Point 30008000,为什么这样我没细研究,所以我用mkimage来生成uImage,做法如下:
[root@localhost tftpboot]#mkimage -n 'linux-2.6.25' -A arm -O linux -T kernel -C none -a 0x30007fc0 -e 0x30008000 -d zImage uImage
Image Name linux-2.6.25
Created Thu Jul 3 101845 2008
Image Type ARM Linux Kernel Image (uncompressed)
Data Size 1556188 Bytes =1556252 kB = 1.5 MB
Load Address 0x30007fc0
Entry Point 0x30008000

这里解释一下参数的意义:
-A == set architecture to 'arch'
-O == set operating system to 'os'
-T == set image type to 'type'
-C == set compression type 'comp'
-a == set load address to 'addr' (hex)
-e == set entry point to 'ep' (hex)
-n == set image name to 'name'
-d == use image data from 'datafile'
-x == set XIP (execute in place)
这里我移植的是2.6.25内核,当然也可以:Load Address 0x30008000 、Entry Point 0x30008040
5、固化
make修改好的u-boot,将u-boot.bin和uImage写入flash相应位置,然后设置u-boot启动命令:
[FS2410]#setenv bootargs root=1f02 init=/linuxrc console=ttySAC0,115200 devfs=mount
[FS2410]#setenv bootcmd nand read 0x30007fc0 0x40000 0x1c0000;bootm 0x30007fc0
[FS2410]#saveenv
Saving Environment to NAND...
Erasing Nand...Writing to Nand... done
好了,可以通过printenv、bdinfo等命令查看自己的u-boot参数了,最后reset一下,如果运气好点的话,就会看到那激动人心的
Uncompressing Linux....................................................... done, booting the kernel.
之后就是一阵洋文飘过……
后记:
s3c2410上移植uboot和linux2.6内核.虽然网上的文章多多,但真正要在自己的板子上跑起来还真是问题多。其间参考了不少网上同行们的文章,受益匪浅。最后我还将调制过程中遇到的问题总结列出,供后人参考。
[/url]



问题一:Load Address 、Entry Point 设置问题
Starting kernel ...
undefined instruction
pc : [] lr : []
sp : 33f4fc10 ip : 00000001 fp : 33f4fca4
r10: 33f9e70c r9 : 33ece9cd r8 : 33f4ffdcc
r7 : 33f4ffb8 r6 : 00000000 r5 : 00000000 r4 : 00000000
r3 : 30008000 r2 : c0000100 r1 : 000000c1 r0 : 00000000
Flags: nZCv IRQs off FIQs off Mode SVC_32
Resetting CPU ...


引导内核在这里进不去,网上也没一个很好的说法,由上图可知:Load Address 0x30008000 、Entry Point 0x30008000 ,#bootm的时候,显示是的内核前头加上的64byte的信息r1:000000c1 r0:00000000……按照上述制作uImage的方法设Load Address 、Entry Point 就ok。
/************下面引用了网上文章的原话********************************************************/
u-boot 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START + 0x8000 地址处。在跳转时,要满足下列条件:
a) CPU 寄存器的设置: R0 = 0 ; R1 =机器类型 ID ,本系统的机器类型 ID = 193 。 R2 =启动参数标记列表在 RAM 中的起始基地址;
b) CPU 模式:必须禁止中断 (IRQs 和 FIQs) ; CPU 必须工作在 SVC 模式;
c) Cache 和 MMU 的设置: MMU 必须关闭;指令 Cache 可以打开也可以关闭;数据 Cache 必须关闭。
系统采用下列代码来进入内核函数:
theKernel = (void (*)(int, int))ntohl(hdr->ih_ep);
theKernel(0, bd->bi_arch_number); 其中, hdr 是 image_header_t 类型的结构体, hdr->ih_ep 指向内核的第一条指令地址,即 Linux 操作系统下的 /kernel/arch/arm/boot/compressed/head.S 汇编程序。 theKernel() 函数调用应该不会返回,如果该调用返回,则说明出错。
//theKernel(0, bd->bi_arch_number); 应该是:
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
问题二:Starting kernel ...就没显示了.


郁闷吧,解决了第一个问题,又来了这个问题,什么都没显示了,错在哪呢?
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);没有给内核正确传递参数?经过setenv修改启动参数、修改bi_arch_number的机器ID号,都未果,结果发现,优龙的linux-2.6.8.1-pxt1不能引导,我交叉编译Linux-2.6.25,制作uImage,结果正常启动,至于为什么linux-2.6.8.1-pxt1不能引导,我没做深入分析。
问题三:Uncompressing Linux....................................................... done, booting the kernel 就不动了
我没有遇到,摘用网上解法:一般这个错误有两种原因:
一个内核的commandline ,一个是由于主频设置的问题
1. 通过go启动内核的话参数用的是编译时的..而bootm则是启动的经过处理的uImage(加了一个头)
所以用bootm就会把uboot设置的commandline传给内核..如果是用bootm启动出现bootint the
kernel没显示了.则应该好好检查一下.可以printenv打印看uboot有没设置对commandline
2.主频问题,就是在MPLLCON这个寄存器的配置上。(board/s3c2410/s3c2410.c) 在VIVI:MPLLCON = 0x0005c040;计算出来的Mpll = 200Mhz Uboot116:MPLLCON = 0x000a1031;计算出来的Mpll = 202Mhz 那么,及有可能就是内核已经启动,而波特率不对,使打印出问题把MPLLCON改成 = 0x0005c040就有显示了.
问题四:Error: unrecognized/unsupported machine ID (r1 = 0x33f4fca8)
[url=http://img.blog.163.com/photo/HJix1MPzs18U4Ze3UzUrWA==/919578748914505230.jpg]

分析:
tftp uImage到0x30008000,然后,go 0x30008000,这样uboot没有传参数给内核,go命令是不传递内核参数的所以会有Error: unrecognized/unsupported machine ID (r1 = 0x33f4fca8)这样的错误 一种方法是修改common/cmd_boot.c /*#if defined(CONFIG_I386)*/ DECLARE_GLOBAL_DATA_PTR; /*#endif*/ #if !defined(CONFIG_NIOS) /*******************add here*******************************/ if(argc==2) rc = ((ulong (*)(int, char *[]))addr) (0, gd->bd->bi_arch_number); else /*********************add end *****************************/ rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]); 解决 还可以在arch/arm/kernel/head.S写死r1 mov r1, #0xc1
个人建议不修改,用bootm命令。
至此,u-boot-1.1.6 移植完毕,感谢收看!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值