移植u-boot-2012到mini2440开发板的笔记

本文详细介绍U-Boot移植到mini2440开发板的过程,包括修改代码以支持不同启动方式、添加对NAND Flash的支持、配置网络及文件系统等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分类: LINUX


移植u-boot-2012.07mini2440开发板的笔记

<1363976004@qq.com>

1.下载、解压、编译、u-boot源码

1)tar xjf u-boot-2012.07.tar.bz2

2)cd u-boot-2012.04.01

3)make smdk2410_config

4)Make

5)烧写到mini2440开发板的Nor flash中,启动开发板,观察现象。

2.创建mini2440单板

1)u-boot-2012.07/board/samsung目录下的smdk2410复制为mini2440,将该目录下的smdk2410.c命名为mini2440.c,修改mini2440目录下的Makefile,将COBJS:= smdk2410.o改为COBJS:= mini2440.o

2)board.cfg65行的

smdk2410      arm      arm920t     -           samsung        s3c24x0

后面添加

mini2440    arm      arm920t     -           samsung        s3c24x0

3)u-boot-2012.07/include/configs中的smdk2410.h复制为mini2440.h

3.阅读u-boot代码分析启动过程并修改代码

1)set the cpu to SVC32 mode

2)turn off the watchdog

3)设置时钟分频系数,使用默认的时钟120MHz

4)设置内存控制器

5)board_init_f(start.S)

-->for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { (board.c)

if ((*init_fnc_ptr)() != 0) {

hang ();}

  -->board_early_init_f(smdk2410.c) (该函数中设置系统时钟)

    -->serial_init(serial_s3c24x0.c)

-->serial_init_dev(serial_s3c24x0.c)

  -->_serial_setbrg(serial_s3c24x0.c)

-->get_PCLK(speed.c)

  -->get_HCLK(speed.c)

........(发现宏CONFIG_S3C2440未定义,故使用的是2410的时钟,故应定义宏CONFIG_S3C2440)

【通过以上的分析可知:在设置时钟与设置内存控制器的顺序是先设置内存控制器,再设置系统时钟,故存在问题。故应先设置时钟,在已设置的时钟下,在设置内存控制器,让内存工作在合适的频率下,使其SDRAM正常工作】

更改:

A.start.S中:

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

改为

#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))

/* 2. 设置时钟 */

ldr r0, =0x4c000014

mov r1, #0x05;   // FCLK:HCLK:PCLK=1:4:8

str r1, [r0]

/* 如果HDIVN0CPU的总线模式应该从“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 /* 写入控制寄存器 */

/* MPLLCON = S3C2440_MPLL_200MHZ */

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

 

B.mini2440.cboard_early_init_f函数中去掉

writel(0xFFFFFF, &clk_power->locktime);

writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,

      &clk_power->mpllcon);

(start.S中已经设置了时钟)

C.通过之前的分析可知:u-boot的源代码中已经带有了2440的串口初始化函数,只需在配置文件mini2440.h中定义宏CONFIG_S3C2440,去掉CONFIG_S3C2410即可。

#define CONFIG_S3C2410改为 #define CONFIG_S3C2440 

D.放在linux编译,发现错误,找出出现错误的文件,并找到该目录下的Makefile,找出控制该文件的宏,在mini2440.h文件中去掉该宏。然后在编译,如再有错误在重复以上步骤,直到编译成功。(只需去掉宏CONFIG_CMD_NAND的定义)

E.将生成的u-boot.bin烧如Nor flash中启动开发板,可以看到开发板可以看到有信信息输出,证明该u-boot的对2440的时钟以及串口的支持已经正常。

6) 在串口上打印的信息中有 ### ERROR ### Please RESET the board ###

搜索 Please RESET the board可以直到该信息是在board.c中答应出来的

分析代码可知:

if (flash_size > 0) {

....................

}

else

{

puts(failed);

hang();

--> puts("### ERROR ### Please RESET the board ###\n");

for (;;);

}

可知该u-boot只支持nor flash启动,当不能识别nor flash时就打印错误,并让程序进入死循环,但是mini2440的开发板既支持nor flash启动也支持nand flash启动。当开发板从nand flash启动时,cpu看到的零地址是片内内存的地址,这是cpu根本就不能看到nor flash

故应去掉board.c中:

puts(failed);

hang();

并加上:

puts("0  KB\n");  (当不能识别nor  flash时打印出flash: 0KB,但程序还是继续运行。)

7)当从nand flash启动时,在上电后在硬件上,会将nand flash中前4k的代码复制到s3c2440的片内内存中,cpu此时看到的零地址是片内内存,即从片内内存开始执行,又由于u-boot的代码远大于4k,故在复制的4k的代码中应完成以下几件事:

A. 初始化内存控制器,是的SDRAM能正常工作

B. nand flash中的代码复制到SDRAM

当以nor flash启动时,nor flash能像读内存一样的读,不能像写内存一样的写,cpu可以直接在nor flash上取得指令执行,故在开始就要做得事情就是要将nor flash上的代码复制到SDRAM中,让代码能正常运行。

通过分析u-boot的源代码可知,代码中的重定位代码是从内存的最高地址,减去需要使用的地址,算出代码重点位的起始地址。然后将代码修改后复制到SDRAM中,但是这种做法,很复杂,从定位代码大于4k,故不适用源代码中的方式,而采用将代码固定的复制到某个地址,在前4K的代码使用位置无关码。这样就使代码简单,在4k的代码中可以完成。

当以nand flash启动时,要将nand flash中的代码复制到SDRAM中,故应该提供nand flash的读函数,即在单板目录下添加mini2440_init.c文件并修改该目录下的Makefile,代码如下:

/* NAND FLASH控制器 */

#define NFCONF (*((volatile unsigned long *)0x4E000000))

#define NFCONT (*((volatile unsigned long *)0x4E000004))

#define NFCMMD (*((volatile unsigned char *)0x4E000008))

#define NFADDR (*((volatile unsigned char *)0x4E00000C))

#define NFDATA (*((volatile unsigned char *)0x4E000010))

#define NFSTAT (*((volatile unsigned char *)0x4E000020))

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);

static int isBootFromNorFlash(void)

{

volatile int *p = (volatile int *)0;

int val;

val = *p;

*p = 0x12345678;

if (*p == 0x12345678)

{

/* 写成功,是nand启动 */

*p = val;

return 0;

}

else

{

/* NOR不能像内存一样写 */

return 1;

}

}

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)

{

int i = 0;

/* 如果是nor启动 */

if (isBootFromNorFlash())

{

while (i < len)

{

dest[i] = src[i];

i++;

}

}

else

{

nand_read((unsigned int)src, dest, len);

}

}

void clear_bss(void)

{

extern int __bss_start, __bss_end__;

int *p = &__bss_start;

for (; p < &__bss_end__; p++)

*p = 0;

}

void my_nand_init(void)

{

#define TACLS   0

#define TWRPH0  1

#define TWRPH1  0

/* 设置时序*/

NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

/* 使能nand flash控制器,初始化ECC,禁止片选 */

NFCONT = (1<<4)|(1<<1)|(1<<0);

}

static void nand_select(void)

{

NFCONT &= ~(1<<1);

}

static void nand_deselect(void)

{

NFCONT |= (1<<1);

}

static void nand_cmd(unsigned char cmd)

{

volatile int i;

NFCMMD = cmd;

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

}

static void nand_addr(unsigned int addr)

{

unsigned int col  = addr % 2048;

unsigned int page = addr / 2048;

volatile int i;

NFADDR = col & 0xff;

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

NFADDR = (col >> 8) & 0xff;

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

NFADDR  = page & 0xff;

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

NFADDR  = (page >> 8) & 0xff;

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

NFADDR  = (page >> 16) & 0xff;

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

}

static void nand_wait_ready(void)

{

while (!(NFSTAT & 1));

}

static unsigned char nand_data(void)

{

return NFDATA;

}

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)

{

int col = addr % 2048;

int i = 0;

/* 1.选中 */

nand_select();

while (i < len)

{

/* 2. 发出读命令00h */

nand_cmd(0x00);

/* 3. 发出地址(分5步发出) */

nand_addr(addr);

/* 4. 发现读命令30h */

nand_cmd(0x30);

/* 5. 判断状态 */

nand_wait_ready();

/* 6. 读数据*/

for (; (col < 2048) && (i < len); col++)

{

buf[i] = nand_data();

i++;

addr++;

}

col = 0;

}

/* 7. 取消选中*/

nand_deselect();

}

board.c中的void board_init_f(ulong bootflag)函数改为返回id的具有返回值的函数

并在start.S中定义一个变量,board.c函数中赋值,该变量用于存放栈指针。

因为在start.S中已经完成了重定位,故board_init_f函数中去掉relocate_code

start.S中的

call_board_init_f:

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

ldr r0,=0x00000000

bl board_init_f

改为:

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

bl  my_nand_init  /* 初始化nand 控制器 */

mov r0, #0              // 源

ldr r1, _TEXT_BASE      // 目的

ldr r2, _bss_start_ofs  // 长度

bl copy_code_to_sdram   // 从定位代码

bl clear_bss            // 清bss段

ldr pc,=call_board_init_f  // 跳到SDRAM中执行

/* Set stackpointer in internal RAM to call board_init_f */

call_board_init_f:

ldr r0,=0x00000000

bl board_init_f

ldr r1, _TEXT_BASE   // call_board_init_f 函数的返回值存放在r0中,刚好让  // board_init_r函数使用

// 函数使用

ldr sp, sp_addr_base  // 重新设置栈

bl board_init_r       // 进入第二阶段

mini2440.h中将

#define CONFIG_SYS_TEXT_BASE 0x0

改为

#define CONFIG_SYS_TEXT_BASE 0x33f80000  // 重定位代码的基地址为33f80000 (在高地址处留出512ku-boot运行)

原来的代码在链接时加了"-pie"选项使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)"

故应去掉 "-pie"选项

arch/arm/config.mkLDFLAGS_u-boot += -pie 去掉这行

修改链接脚本start.S, init.c, lowlevel.S等文件放在最前面

即在arch/arm/cpu/u-boot.lds文件在CPUDIR/start.o后面添加:

      board/samsung/smdk2440/libsmdk2440.o

8)移植u-boot支持nor flash的烧写与擦除

通过之前的移植,在串口上有输出,为了得到了nor flash的厂家id和设备id,所以在代码中添加了一些打印信息,而这些打印信息是通过宏开关决定的,分析代码可知,只需在cfi_flash.c文件中添加 

#define DEBUG  1

#define _DEBUG  1

就可以打开宏开关,得到打印信息,然后编译烧写,观察串口的打印信息。信息如下:

Flash: fwc addr (null) cmd f0 00f0 16bit x 16 bit

fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit

fwc addr 00005554 cmd 55 0055 16bit x 16 bit

fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit

fwc addr (null) cmd f0 00f0 16bit x 16 bit

JEDEC PROBE: ID 1 2249 0

fwc addr (null) cmd ff 00ff 16bit x 16 bit

fwc addr (null) cmd 90 0090 16bit x 16 bit

fwc addr (null) cmd ff 00ff 16bit x 16 bit

JEDEC PROBE: ID 14 ea00 0

*** Warning - bad CRC, using default environment

可以得到nor flash的厂家id和设备id分别为1、 0x2249

在代码中搜索JEDEC PROBE可以知道,该信息在代码中cfi_flash.c文件中打印出来的,代码为:

debug("JEDEC PROBE: ID %x %x %x\n",

info->manufacturer_id,

info->device_id,

info->device_id2);

if (jedec_flash_match(info, info->start[0]))

break;

-->jedec_flash_match

 -->for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {

if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&

    (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {

fill_info(info, &jedec_table[i], base);

ret = 1;

break;

}

可知:识别出ID后,在与数组jedec_table比较的时候没有匹配的,故应在jedec_table的定义处添加一项符合该nor flash的信息,即添加

{

.mfr_id = (u16)AMD_MANUFACT,  

.dev_id = 0x2249,

.name = "ST Micro M29F400BB",

.uaddr = {

[1] = MTD_UADDR_0x0555_0x02AA /* x16 */

},

.DevSize = SIZE_2MiB,

.CmdSet = CFI_CMDSET_AMD_LEGACY,

.NumEraseRegions = 4,

.regions = {

ERASEINFO(0x04000, 1),

ERASEINFO(0x02000, 2),

ERASEINFO(0x08000, 1),

ERASEINFO(0x10000, 31),

}

},

在编译烧写,发现会打印出  ERROR: too many flash sectors

搜索代码可知是由于:

if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {

printf("ERROR: too many flash sectors\n");

break;

故需要修改宏CONFIG_SYS_MAX_FLASH_SECT的值,将配置文件中mini2440.h中的

#define CONFIG_SYS_MAX_FLASH_SECT (19)

改为

#define CONFIG_SYS_MAX_FLASH_SECT (50)  

(只需这个值打于35即可,因为该nor flash一共35个扇区)

9)为了使u-boot的命令行输入命令时,可以通过TAB键补全,只需在配置文件 mini2440.h中定义宏

#define CONFIG_AUTO_COMPLETE

10)修改输入命令行前面的提示SMDK2410 # :只需将配置文件 mini2440.h中定义宏

#define CONFIG_SYS_PROMPT "SMDK2410 # "

改为

#define CONFIG_SYS_PROMPT "[mini2440@u-boot]# "

这样在命令行前面的提示就变成了[mini2440@u-boot]# 

11)修改u-boot,使其支持nand flash的烧写与读写工作。

drivers/mtd/nand 目录下将s3c2410_nand.c复制为s3c2440_nand.c,并修改Makefile,通过宏CONFIG_NAND_S3C2440控制s3c2440_nand.c文件是否编译,在mini2440.h中添加

#define CONFIG_NAND_S3C2440

去掉

#define CONFIG_NAND_S3C2410

分析board.c,在board_init_r函数中发现:

#if defined(CONFIG_CMD_NAND)

puts("NAND:  ");

nand_init(); /* go init the NAND */

#endif

所以在nand_init函数中初始化nand flash

nand_init  (board.c)

  -->board_nand_init  (nand.c)

  -->nand_init_chip   (nand.c)

-->nand_scan     (nand_base.c)

  -->nand_scan_ident  (nand_base.c)

-->nand_set_defaults  (nand_base.c)

-->nand_get_flash_type  (nand_base.c)

  -->nand_scan_tail   (nand_base.c)

阅读s3c2440的芯片手册可知,应修改nand 控制器的时序:

#define S3C2440_NFCONF_TACLS(x)    ((x)<<8)

#define S3C2440_NFCONF_TWRPH0(x)   ((x)<<4)

#define S3C2440_NFCONF_TWRPH1(x)   ((x)<<0)

改为

#define S3C2440_NFCONF_TACLS(x)    ((x)<<12)

#define S3C2440_NFCONF_TWRPH0(x)   ((x)<<8)

#define S3C2440_NFCONF_TWRPH1(x)   ((x)<<4)

去掉:

cfg = S3C2440_NFCONF_EN;

为了搞nand flash的烧写速度,可以将

tacls = 4;

twrph0 = 8;

twrph1 = 8;

改为:

tacls = 4;

twrph0 = 8;

twrph1 = 8;

为了使能NAND Flash控制器初始化ECC, 禁止片选

应添加:
cfg = (1<<4)|(1<<1)|(1<<0);

writel(cfg, &nand_reg->nfcont);

board_nand_init函数中的

nand->select_chip = NULL;

改为

nand->select_chip = nand_select_chip;

并添加函数:

static void nand_select_chip(struct mtd_info *mtd, int chipnr)

{

struct s3c2440_nand *nand = s3c2440_get_base_nand();

switch (chipnr) {

case -1:

/* 取消选中 */

nand->nfcont |= (1<<1);

break;

case 0:

//chip->cmd_ctrl(mtd, 0, 0 | NAND_CTRL_CHANGE);

/* 选中 */

nand->nfcont &= ~(1<<1);

break;

default:

BUG();

}

将函数S3C2440_hwcontrol改为:

static void S3C2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)

{

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);

}

}

在配置文件中定义宏:

#define  CONFIG_s3c2440_nand_HWECC

12)修改u-boot支持DM9000网卡

阅读代码发现,在u-boot的源代码中已经支持了DM9000的代码,只需添加进去即可。

A.查看 drivers/net/Makefile,发现dm9000x的编译由宏CONFIG_DRIVER_DM9000控制,所以必须在配置文件中定义宏。

B.修改配置文件mini2440.h

#define CONFIG_CS8900

#define CONFIG_CS8900_BASE     0x19000300

#define CONFIG_CS8900_BUS16 */

改为:

#define  CONFIG_DRIVER_DM9000

#define CONFIG_DM9000_BASE      0x20000000

#define DM9000_IO                CONFIG_DM9000_BASE

#define DM9000_DATA             (CONFIG_DM9000_BASE + 4) 

C. 在mini2440.c中的函数board_eth_init中添加

dm9000_initialize(dis);

13)添加默认参数:

 在mini2440.h的配置文件中添加默认参数:

#define CONFIG_NETMASK 255.255.255.0

#define CONFIG_IPADDR 192.168.1.128

#define CONFIG_SERVERIP 192.168.1.125

#define CONFIG_ETHADDR        00:0c:29:4d:e4:f4

#define CONFIG_BOOTARGS   "console=ttySAC0,115200 root=/dev/mtdblock3"

#define CONFIG_BOOTCOMMAND  "nand read 30000000 kernel;bootm 30000000"

 

14)设置环境变量的保存地址

15)u-boot中保存环境变量的命令时saveenv,在代码中搜索saveenv知道,要想使环境变量保存在nand flash中,则必须将env_nand.c编译内u-boot中,查看common/Makefile 知道由宏CONFIG_ENV_IS_IN_NAND控制env_nand.c的编译,故应在配置文件mini2440.h

#define  CONFIG_ENV_IS_IN_NAND

u-boot源码提供环境变量的保存位置是在nor flash中,故应去掉宏

#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000)

#define CONFIG_ENV_IS_IN_FLASH

#define CONFIG_ENV_SIZE 0x10000

#define CONFIG_ENV_OVERWRITE

然后编译,发现错误,提示需要定义宏CONFIG_ENV_OFFSETCONFIG_ENV_SIZE

继续在mini2440.h的文件中定义

#define  CONFIG_ENV_OFFSET  0x40000

#define  CONFIG_ENV_SIZE     0x20000

16)添加分区

在配置文件中添加宏:

#define CONFIG_CMD_MTDPARTS

#define CONFIG_MTD_DEVICE

#define MTDIDS_DEFAULT "nand0=mini2440-0"  /* 那一个设备 */

#define MTDPARTS_DEFAULT "mtdparts=mini2440-0:256k(u-boot)," \

"128k(params)," \

"5m(kernel)," \

"-(rootfs)"

board.cboard_init_r函数中添加代码:

run_command("mtdparts default", 0); 

17)为了能启动mini2440linux内核,必须修改mini2440.c文件中

将 board_init函数中的

gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

改为:

gd->bd->bi_arch_number = MACH_TYPE_MINI2440;

18)修改u-boot支持yaffs文件系统的烧写

在配置文件中定义宏:

#define CONFIG_CMD_NAND_YAFFS

common/cmd_nand.c的第670行左右:

ret = nand_write_skip_bad(nand, off, &rwsize,

(u_char *)addr,

WITH_INLINE_OOB);

改为:

ret = nand_write_skip_bad(nand, off, &rwsize,

(u_char *)addr,

WITH_YAFFS_OOB);

drivers/mtd/nand/nand_util.c中的第556行左右:

ops.mode = MTD_OOB_AUTO;

改为:

ops.mode = MTD_OOB_RAW;

  注:该比较是我一遍移植,一边写的,应该不会有什么大问题,自己认为写的还较详细,希望对有需要的朋友有所帮助,有什么错误或者问题可以联系<1363976004@qq.com>

并指出,本人将不胜感激。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值