U-Boot移植过程概要记录

3 篇文章 0 订阅
3 篇文章 0 订阅

1,移植环境:
u-boot版本:u-boot-2012.04.01(包含了S3C2410 , 但是未包含S3C2440)
硬件环境: S3C2440平台

2,过程:
1),首先解压缩 tar -xvf u-boot-2012.04.01.tar.bz2;
然后编译make smdk2410_config && make ,之后得到u-boot.bin,通过openjtag烧入Norflash,从Norflash启动开发板,通过minicom串口查看没有任何反应;

2),u-boot-2012.04.01,第一阶段启动过程分析:
->设置CPU到管理模式
->关闭Watchdog
->屏蔽所有中断
->禁止MMU和Caches及初始化SDRAM
->设置栈,在board_init_f函数中初始化:划分内存,设置时钟,初始化串口,初始化控制台等重要的初始化;
->在relocate_code代码中:重新设置栈,重定位代码;
->处理.rel.dyn(通过编译选项PIE生成的代码段)代码段相关的链接地址到新地址,即就是处理位置无关代码;
->清bss段;
->对S3C24X0不支持从Nandflash启动,所以进入board_init_r函数:初始化gd_t结构体实例,设置malloc内存空间等,获取flash大小,进入main_loop函数;
->在main_loop函数中通过bootcmd命令进入u-boot启动第二阶段启动内核;

3),对于S3C2440,在上面的步骤中有两个地方需要说明:
在设置分频系数的代码如下:
这里写图片描述

对于S3C2440,通过查询硬件手册可知 default FCLK 是12MHz;
这里写图片描述

分频系数设置在SDRAM初始化之前,
初始化SDRAM的时候对SDRAM控制器的时钟相关寄存器使用下面的值:
这里写图片描述

即使用HCLK=60Mhz,但是在SDRAM之前并未设置MPLL,而是在board_init_f->board_early_init_f函数设置时钟的时候才设置时钟控制器的MPLL;
通过上述时钟频率的分析,可知,S3C2440初始化SDRAM的时候 HCLK并不是60MHz,所以此处需要调整,所以这样初始化的SDRAM在使用的时候会有问题;

4),添加S3C2440单板目录:
cp -rd board/samsung/smdk2410/ board/samsung/smdk2440/
修改其中的smdk2410.c 为smdk2440.c
修改board/samsung/smdk2440/Makefile中的2410为2440

cp include/configs/smdk2410.h include/configs/smdk2440.h
并修改如下内容:
这里写图片描述

这里写图片描述
为了能够编译通过,将CONFIG_CMD_NAND 和 CONFIG_YAFFS2宏注释掉,暂时先关闭Nandflash;

修改源码目录下面的boards.cfg文件,添加内容如下:
这里写图片描述

修改完毕之后执行make smdk2440_config && make 开始编译,编译通过得到u-boot.bin暂时还是无法运行;

5),修改上述3)中问题;
修改策略:将时钟控制器的初始化全部放在SDRAM初始化之前(根据硬件手册设置MPLL,设置分频系数,设置总线异步模式);然后初始化SDRAM(根据硬件手册从新设置SDRAM控制器寄存器的值)

start.S 和 smdk2440.c 中修改时钟控制器部分,lowlevel_init.S修改SDRAM控制器部分;

arch/arm/cpu/arm920t/start.S

        /* modify by gh begin */
        /* FCLK:HCLK:PCLK = 1:4:8 */
        ldr     r0, =CLKDIVN
        mov     r1, #0x5
        str     r1, [r0]

        /* set BUS mode */
        mrc p15,0,r0,c1,c0,0
        orr r0,r0,#0xc0000000
        mcr p15,0,r0,c1,c0,0 

        /* set MPLL FCLK=400MHz */
        ldr     r0,=0x4C000004
        ldr     r1,=0x5c011
        str     r1,[r0]
        /* modify by gh end */

board/samsung/smdk2440/smdk2440.c : serial_init_dev方法

        /* modify by gh begin; */
        /* to reduce PLL lock time, adjust the LOCKTIME register */
        //writel(0xFFFFFF, &clk_power->locktime);
        /* configure MPLL */
        //writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,
        //       &clk_power->mpllcon);
        /* some delay between MPLL and UPLL */
        //pll_delay(4000);
        /* modify by gh end; */

board/samsung/smdk2440/lowlevel_init.S中的内存控制器初始化值:

/* modify by gh begin  */
SMRDATA:
        .long 0x32333330
        .long 0x000007a0
        .long 0x00002a60
        .long 0x00002a60
        .long 0x00002a60
        .long 0x00002a60
        .long 0x00002a60
        .long 0x00018001
        .long 0x00018001
        .long 0x008404f5
        .long 0x000000b1
        .long 0x00000020
        .long 0x00000020
/* modify by gh end  */

经过以上修改之后的执行结果如下图:

这里写图片描述
已经有串口信息输出了,只不过是乱码,还需要进一步修改;

6),修改串口输出:
串口初始化方法的调用路径:

board_init_f->serial_init->serial_init_dev->_serial_setbrg

serial_init_dev方法的修改在上述3)问题的修改中已经修改完毕,查看_serial_setbrg这个方法,在这个方法中用PCLK时钟和波特率计算UBRDIV寄存器的[10:0]为的值,在获取PCLK时钟的get_PCLK方法中最终会调用到get_HCLK方法,在这个方法中已经支持S3C2440只不过未定义CONFIG_S3C2440的宏,代码如下图:

这里写图片描述

在 include/configs/smdk2440.h中添加CONFIG_S3C2440宏定义,注释CONFIG_S3C2410宏定义;

这里写图片描述

为了编译通过还需要修改如下两个宏定义:

这里写图片描述

这里写图片描述

修改完毕之后,执行make distclean 然后重新配置编译,烧写到Norflash之后,效果如下图:

这里写图片描述

串口已经能够正常运行;

7),修改Norflash信息获取:
1> Norflash支持XIP技术,所以从Norflash启动时,Norflash不需要初始化;
2> Norflash支持两种规范JEDEC,CFI(Common Flash Interface);
JEDEC规范是从Norflash中查寻到厂商ID和设备ID,然后用这两个ID在u-boot中记录的芯片信息数组中查询Norflash的其他硬件信息,例如:大小,sector的种类的数量,位宽等;
CFI规范将所有的硬件信息存储在Norflash芯片内,u-boot可以从Norflash读取所有的硬件信息;

从上述串口输出截图中的错误信息可以定位到,如下代码问题:
arch/arm/lib/board.c中的方法 board_init_r(gd_t *id, ulong dest_addr);

void board_init_r(gd_t *id, ulong dest_addr)
{
    flash_size = flash_init();
    if (flash_size > 0) {
          . . . . .
    } else {//由于flash_size=0,打印错误信息;
        puts(failed);
        hang();
    }

进一步跟踪代码; flash_init(cfi_flash.c)->flash_detect_legacy(cfi_flash.c);就会看到

#ifdef CONFIG_FLASH_CFI_LEGACY

u-boot默认使用JEDEC规范,而u-boot的硬件信息数组:

static const struct amd_flash_info jedec_table[];      drivers/mtd/jedec_flash.c

中并没有我用的Norflash硬件信息:MX29LV160DBTI-70G;所以,有两种该法支持Norflash;
1> 在jedec_table数组中添加MX29LV160DBTI-70G的硬件信息(硬件信息查询芯片数据手册);
2> 在include/configs/smdk2440.h中去掉CONFIG_FLASH_CFI_LEGACY宏定义,让u-boot使用CFI规范,然后在根据错误信息修改最大sector的数量,修改如下:

/* modify by gh begin */
//#define CONFIG_SYS_MAX_FLASH_SECT     (19)
#define CONFIG_SYS_MAX_FLASH_SECT       (35)
/* modify by gh end */

/* modify by gh begin */
//#define CONFIG_FLASH_CFI_LEGACY
/* modify by gh end */

我按照第二种修改方法修改完毕之后,烧写重启开发板,结果如下图:

这里写图片描述

u-boot已经启动成功,可以输入u-boot的各种命令,可以读写Norflash;

9),用u-boot的loadb命令和minicom的kermit模式发送文件,将uImage装载到SDRAM中,然后启动内核,在u-boot命令行输入loadb 30000000,然后用minicom发送文件:
发送过程如下图:

这里写图片描述

传送完毕之后,执行bootm 30000000命令,可以看到内核启动成功,如下图:

这里写图片描述

这里写图片描述

内核启动成功!

10)支持Nandflash;
Nandflash初始化序列如下:

start.S -> board_init_r(arch/arm/lib/board.c) -> 
nand_init(drivers/mtd/nand/nand.c) -> nand_init_chip(drivers/mtd/nand/nand.c)  -> 
board_nand_init(drivers/mtd/nand/s3c2440_nand.c) 和 nand_scan(drivers/mtd/nand/nand_base.c)

对上面调用序列分析,通过和S3C2440 芯片手册 和 Nandflash芯片手册中的操作过程比对,可以发现需要修改一下几点:

修改include/configs/smdk2440.h

/* modify by gh begin; */
#define CONFIG_CMD_NAND //去掉之前的注释;

#define CONFIG_S3C24XX_CUSTOM_NAND_TIMING
#define CONFIG_S3C24XX_TACLS                  0
#define CONFIG_S3C24XX_TWRPH0                 1
#define CONFIG_S3C24XX_TWRPH1                 0
/* modify by gh end; */
// modify by gh begin
#ifndef CONFIG_S3C2440
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#else
#define CONFIG_NAND_S3C2440 //如果是S3C2440则添加这个宏;
#endif
// modify by gh end

创建drivers/mtd/nand/s3c2440_nand.c

cp drivers/mtd/nand/s3c2410_nand.c  drivers/mtd/nand/s3c2440_nand.c

修改drivers/mtd/nand/Makefile
添加如下代码:

# modify by gh begin
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
# modify by gh end

修改drivers/mtd/nand/s3c2440_nand.c
首先把S3C2410对于的宏定义修改为S3C2440,然后根据芯片手册(S3C2440芯片手册,Nandflash芯片手册)调整宏定义的值

/* modify by gh begin */
#define S3C2440_NFCONF_EN          (1<<0)
/* modify by gh end */

 /* modify by gh begin */
#define S3C2440_NFCONF_nFCE        (1<<1)

#define S3C2440_NFCONF_TACLS(x)    ((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x)   ((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x)   ((x)<<4)

#define S3C2440_ADDR_NALE 0xC
#define S3C2440_ADDR_NCLE 8
/* modify by gh end */
static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
         ... ...
        if (ctrl & NAND_CTRL_CHANGE) {
                ulong IO_ADDR_W = (ulong)nand;
                /* modify by gh begin */
                if (ctrl & NAND_CLE)
                        IO_ADDR_W |= S3C2440_ADDR_NCLE;
                if (ctrl & NAND_ALE)
                        IO_ADDR_W |= S3C2440_ADDR_NALE;
                /* modify by gh end; */
                chip->IO_ADDR_W = (void *)IO_ADDR_W;
                /* modify by gh begin */
                if (ctrl & NAND_NCE)
                        writel(readl(&nand->nfcont) & ~S3C2440_NFCONF_nFCE,
                               &nand->nfcont);
                else
                        writel(readl(&nand->nfcont) | S3C2440_NFCONF_nFCE,
                               &nand->nfcont);
                /* modify by gh end; */
        }
        ... ...
}
int board_nand_init(struct nand_chip *nand)
{
    ... ...
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
        tacls  = CONFIG_S3C24XX_TACLS;
        twrph0 = CONFIG_S3C24XX_TWRPH0;
        twrph1 =  CONFIG_S3C24XX_TWRPH1;
#else
        tacls = 4;
        twrph0 = 8;
        twrph1 = 8;
#endif
        /* modify by gh begin */
        writel((1<<4|1<<1|1),&nand_reg->nfcont);

        cfg = S3C2440_NFCONF_TACLS(tacls);
        cfg |= S3C2440_NFCONF_TWRPH0(twrph0);
        cfg |= S3C2440_NFCONF_TWRPH1(twrph1);
        writel(cfg, &nand_reg->nfconf);
        /* modify by gh end; */
     ... ...
 }

修改drivers/mtd/nand/nand_base.c

static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
        struct nand_chip *chip = mtd->priv;

        switch (chipnr) {
        case -1:
                chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
                break;
        case 0:
                /* add by gh begin */
                chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE |  NAND_CTRL_CHANGE);
                /* add by gh end; */
                break;

        default:
                BUG();
        }
}

修改完毕编译,烧写到Norflash上,运行结果如下图:

这里写图片描述

从Nandflash的kernel分区(0x60000,2M)加载uImage到SDRAM,然后bootm 30000000运行:

nand read  0x30000000 0x60000 0x200000
bootm 30000000

也可以在u-boot命令行执行:

set bootcmd "nand read  0x30000000 0x60000 0x200000;bootm 30000000"
save  //将bootcmd参数保存到u-boot的环境变量中;
reset //重启之后直接进入Linux内核;

运行结果如下图:

这里写图片描述
这里写图片描述

从Nandflash加载Linux内核,启动成功!

由于Norflash空间不够大,放不下内核,所以,通常将Linux内核和u-boot都放在Nandflash的分区上,然后直接从Nandflash启动,这个有两种方案:
1> u-boot本身的SPL;
2> 去掉直接u-boot的编译时的PIE选项和重定位代码时对链接地址的动态处理,这样可以减少u-boot体积,使得重定位代码的位置尽量位于SRAM的4k空间内,手工安排u-boot链接地址,将u-boot装载到SDRAM确定的地址上;
上述两种方案,这篇博客就不详细说明了,后续博客再详细说明;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值