这段时间因为疫情在家,失业了也没有什么其他的事情,想着好好学习一下u-boot相关内容。

正好手头上有之前买了然后吃灰的OK6410,根据网上的相关资料着手移植到u-boot 2018版本,折腾了快半个月的时间还是没有成功,每次bl _main后就会挂掉,不知道具体原因很是困惑,也找了一些调试方法,比如通过Jlink直接调试,通过Jlink-gdb-server,最后没怎么搞明白如何调试,但是发现运行后进入了data_abort异常位置。分析应该是relocate出现问题,也找了很久无果,然后想着好好分析一些飞凌提供的旧版本的u-boot。

开发板硬件资源

1
2
3
4
5
6
7
8
飞凌OK6410开发板
DDR: 256MB 型号:K4X1G163PC (64Mx16bit=128MB) * 2
NAND: 1GB 型号:MT29F16G08ABACAWP, SLC, PageSize=4K
SD: SD/MMC Host Controller 使用channel 0

LCD: WXCAT43-TG3#001, 4.3寸 屏
Ethernet: DM9000A

如何编译

根据根目录下的Makefile文件

image-20220319181929608

编译方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
#使用的工具链是飞凌提供的,gcc version 4.3.2

#指定交叉工具链
export CROSS_COMPILE=arm-linux-

#配置u-boot
#从sd卡启动
make forlinx_sd_ram256_config

#从nand启动
make forlinx_nand_ram256_config
#编译
make -j8

mkconfig shell脚本主要的配置:

image-20220319182906640

从SD卡启动

u-boot怎么放入SD卡

根据S3C6410_Internal_ROM_Booting.pdf的启动流程说明:

s3c6410启动时,iROM中的BL0会加载sd卡中的u-boot前8K到iRAM

image-20220319175545735

怎么将u-boot分成两部分(BL1,BL2)

sd卡的分区方式(u-boot,kernel,rootfs等如何存放):
本人使用的时SHDC sd卡,所以分区格式为

image-20220319180259352

有点疑惑的是这个Signature分区,作用是什么??

所以想看看sd卡的u-boot如何烧写Nand Flash中的 u-boot

如何烧写:

  • 方法1:使用飞凌提供的SD_Write.exe工具,工具将会按照sd卡的类型写入数据
    注意u-boot源码中相关参数的定义,比如u-boot的大小,ENV的大小需要和SD_Write.exe定义的一致,因为BL1在拷贝BL2的时候需要知道BL2的存放地址,
    根据源码中movi.c 和要求的分区格式计算:参考[BL1如何搬迁BL2到SDRAM](# BL1如何搬迁BL2到SDRAM)
    因不知道飞凌提供工具对应的参数,所以不建议使用此方法

  • 方法2:Linux下使用dd命令

    1
    2
    3
    4
    5
    #第一部分:
    dd if=u-boot.bin of=./bl1.bin bs=512 count=16

    #第二部分:
    cp u-boot.bin ./bl2.bin

    烧写shell脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    #!/bin/bash

    SDCARD=/dev/sdb
    SPL_BOOT=bl1.bin
    UBOOT=u-boot.bin

    #保留大小, SDHC=1025, SD=1
    RES_SZ=1025

    SECTOR_SIZE=512 #Block大小
    SIG_SZ=1 #signature block-size, 512byte
    BL1_SZ=16 #BL1 block-size, 8K
    BL2_SZ=512 #BL2 block-size, 256K
    ENV_SZ=32 #ENV block-size, 16K

    BL1_SIZE=`expr $BL1_SZ \* $SECTOR_SIZE / 1024`
    BL2_SIZE=`expr $BL2_SZ \* $SECTOR_SIZE / 1024`


    #sd卡容量
    SDCARD_SECTORS=`cat /sys/block/${SDCARD##*/}/size`

    #BL1 BL2写入位置
    START_BL1_POS=$(($SDCARD_SECTORS-$RES_SZ-$SIG_SZ-$BL1_SZ))
    START_BL2_POS=$(($START_BL1_POS-$ENV_SZ-$BL2_SZ))


    #打印结果
    print_result()
    {
    if [ "$1" == 0 ]; then
    echo "success"
    else
    echo "failed"
    exit -1
    fi
    }

    #需要root权限,如果没有提示信息
    if [ `whoami` != "root" ];then
    echo "Need root permision to execute the script!"
    exit
    fi

    #BL1创建
    echo "Create bl1.bin...."
    rm -rf bl1.bin
    dd if=u-boot.bin of=bl1.bin bs=512 count=16

    #判断sd卡是否存在
    echo "sd/mmc: $SDCARD"
    if [ ! -b "$SDCARD" ]; then
    cat << EOF
    no device found
    Usage: $0 <sd-dev> [sd-type]
    defalutly, <sd-dev> is /dev/sdb, sd-type is "sdhc" in ("sdhc","sd")
    EOF
    exit 1
    fi

    # 写入数据
    echo -n "write bl1 to sd/mmc at offset: $START_BL1_POS block-size: $BL1_SZ size: $BL1_SIZE K... "
    dd bs=$SECTOR_SIZE seek=$START_BL1_POS if=/dev/zero of=$SDCARD count=$BL1_SZ > /dev/null 2>&1
    dd bs=$SECTOR_SIZE seek=$START_BL1_POS if=$SPL_BOOT of=$SDCARD count=$BL1_SZ > /dev/null 2>&1
    print_result "$?"

    echo -n "write bl2 to sd/mmc at offset: $START_BL2_POS block-size: $BL2_SZ size: $BL2_SIZE K... "
    dd bs=$SECTOR_SIZE seek=$START_BL2_POS if=/dev/zero of=$SDCARD count=$BL2_SZ > /dev/null 2>&1
    dd bs=$SECTOR_SIZE seek=$START_BL2_POS if=$UBOOT of=$SDCARD count=$BL2_SZ > /dev/null 2>&1
    print_result "$?"

    sync
    exit 0

    参考:

    代码烧写部分:https://blog.csdn.net/Golden_Chen/article/details/86644879

BL1流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
reset                        #cpu/s3c64xx/start.S
cpu_init_crit
bl lowlevel_init #board/samsung/smdk6410/lowlevel_init.S

#判断运行的代码是否已经relocate; start.S
#BL1运行在iRAM,所以没有relocate,执行movi_bl2_copy

#搬迁BL2到SDRAM
bl movi_bl2_copy #cpu/s3c64xx/movi.c

b after_copy #cpu/s3c64xx/start.S

skip_hw_init
stack_setup
clear_bss

#跳转到BL2
ldr pc, _start_armboot #cpu/s3c64xx/start.S

BL1如何搬迁BL2到SDRAM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#SD卡中的代码 如何搬运 确定了 第二部分在哪里

#如何搬运的代码

#ifdef CONFIG_BOOT_MOVINAND // u-boot-1.1.6/cpu/s3c64xx/start.S
ldr sp, _TEXT_PHY_BASE
bl movi_bl2_copy
b after_copy
#endif

#搬运代码核心
CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, (uint *)BL2_BASE, MOVI_INIT_REQUIRED);
#define CopyMovitoMem(a,b,c,d,e) (((int(*)(int, uint, ushort, uint *, int))(*((uint *)(TCM_BASE + 0x8))))(a,b,c,d,e)) // 这个代码是 定义在 iTCM 中的


HSMMC_CHANNEL
0
用的哪一个channel : 0
MOVI_BL2_POS
#define MOVI_BL2_POS (MOVI_LAST_BLKPOS - MOVI_BL1_BLKCNT - MOVI_BL2_BLKCNT - MOVI_ENV_BLKCNT)
从哪个位置搬移 : 全部的块大小(由iROM中的代码算出来,位于signature处) - BL大小(16个sector,由手册决定) - BL2大小(512个,由u-boot决定,所以第二部分最大为256KB) - 环境所占大小(32个,由u-boot决定)
MOVI_BL2_BLKCNT
#define MOVI_BL2_BLKCNT (PART_SIZE_BL / MOVI_BLKSIZE)
搬移多少个块 : 512个块,256KB
BL2_BASE
#define BL2_BASE (CFG_PHY_UBOOT_BASE)
搬到哪里: 0x5FE00000,位于sdram
MOVI_INIT_REQUIRED
0
是否重新初始化:否

By: _popOK6410A 开发板 (三) u-boot-1.1.6 boot 解析

BL0中厂商固化的拷贝函数(S3C6410_Internal_ROM_Booting.pdf):

image-20220319185609073

BL2流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#BL2 是 从_start_armboot开始的: ldr    pc, _start_armboot         #cpu/s3c64xx/start.S

_start_armboot:
.word start_armboot #cpu/s3c64xx/start.S

start_armboot() #lib_arm/board.c
#gd_t 结构初始化

#初始化: 函数首地址存放在 init_sequence[] 指针数组
cpu_init() #cpu/s3c64xx/cpu.c
board_init() #board/samsung/smdk6410.c
interrupt_init() #cpu/s3c64xx/interrupts.c

env_init() #common/env_movi.c (函数所在文件和启动方式相关)

init_baudrate() #lib_arm/board.c
serial_init() #cpu/s3c64xx/serial.c
console_init_f() #common/console.c
display_banner() #lib_arm/board.c
print_cpuinfo() #cpu/s3c64xx/speed.c
checkboard() #board/samsung/smdk6410.c
dram_init() #board/samsung/smdk6410.c
display_dram_config()#lib_arm/board.c

flash_init() #board/samsung/flash.c
lcd_setmem() #common/lcd.c
mem_malloc_init() #lib_arm/board.c
nand_init() #board/samsung/smdk6410.c

#sd/mmc控制器初始化 (和启动方式相关)
movi_set_capacity()
movi_set_ofs()
movi_init() #cpu/s3c64xx/movi.c

env_relocate() #common/env_common.c

#设备相关驱动初始化
devices_init() #common/devices.c

jumptable_init() #common/exports.c
console_init_r() #common/console.c
enable_interrupts() #cpu/s3c64xx/interrupts.c
board_late_init() #board/samsung/smdk6410.c
eth_initialize() #net/eth.c

#main循环
main_loop() #common/main.c
#还没有超时或被中断
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
#解析bootcmd命令
parse_string_outer() #common/hush.c
run_list #common/hush.c
run_list_real #common/hush.c
run_pipe_real #common/hush.c
#查找&执行命令
cmdtp = find_cmd(child->argv[i]); #common/command.c
#cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;
#命令列表首地址为__u_boot_cmd_start ,链接器脚本board/samsung/smdk6410/u-boot.lds中定义
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;

if (cmdtp == NULL) {
#没有找到命令
}
else {
#执行命令
rcode = (cmdtp->cmd)(cmdtp, flag,child->argc-i,&child->argv[i]);
}
}

#被中断
ARMMenu() #common/main.c
#相关菜单选择……

**.u_boot_cmd**定义的位置为:include/command.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//告诉编译器将xxx放在 .u_boot_cmd段
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))

//用于定义命令tab的宏
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

/*
各个命令通过U_BOOT_CMD宏来定义,链接器将各个不同功能cmd_tab,
从__u_boot_cmd_start起始地址按顺序的存放;

通过find_cmd()函数查找命令:
cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;
for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
if (strncmp (cmd, cmdtp->name, len) == 0) {
if (len == strlen (cmdtp->name))
return cmdtp; //完全匹配
cmdtp_temp = cmdtp; //简短的命令?
n_found++;
}
}
*/


//U_BOOT_CMD定义命令的格式,如nand相关命令, common/cmd_nand.c

U_BOOT_CMD(nand, 5, 1, do_nand,
"nand - NAND sub-system\n",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2] - addr off|partition size\n"
"nand write[.jffs2] - addr off|partiton size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
#ifdef CFG_NAND_YAFFS_WRITE
"nand write[.yaffs[1]] - addr off|partition size - write `size' byte yaffs image\n"
" starting at offset `off' from memory address `addr' (.yaffs1 for 512+16 NAND)\n"
#endif
"nand write[.uboot] - addr off|partition size\n"
"nand write[.ok] - sound beep ok\n"
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand dump[.oob] off - dump page\n"
"nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
"nand markbad off - mark bad block at offset (UNSAFE)\n"
"nand biterr off - make a bit error at offset (UNSAFE)\n"
"nand lock [tight] [status] - bring nand to lock state or display locked pages\n"
"nand unlock [offset] [size] - unlock section\n");


对于飞凌提供的从sd卡启动的固件,上电默认自动烧写所有固件,那么bootcmd是什么呢?

common/env_movi.c中定义的env_init()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int env_init(void)
{
//没有定义 ENV_IS_EMBEDDED
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;

return (0);
}

//common/env_common.c
uchar default_environment[] = {
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif
//....
}

//include/configs/smdk6410.h
//从sd卡启动
#define CONFIG_BOOTCOMMAND "nand led-start;nand erase;fatload mmc 0:1 0x50008000 u-boot.bin;nand write.uboot 0x50008000 0 0x200000;fatload mmc 0:1 0x50008000 zImage;nand write.e 0x50008000 0x500000 0x500000; fatload mmc 0:1 0x50008000 rootfs.yaffs2; nand write.yaffs2 0x50008000 0x01e00000 $filesize; nand beep; nand led-end"

//nand led-start; 开始提示:led
//nand erase; 擦除nand flash
//fatload mmc 0:1 0x50008000 u-boot.bin;nand write.uboot 0x50008000 0 0x200000; 烧写u-boot
//fatload mmc 0:1 0x50008000 zImage;nand write.e 0x50008000 0x500000 0x500000; 烧写kernel
//fatload mmc 0:1 0x50008000 rootfs.yaffs2; nand write.yaffs2 0x50008000 0x01e00000 $filesize; 烧写rootfs
//nand beep; nand led-end 结束提示led, beep

启动信息:

image-20220319232123289

BL2如何将sd卡中u-boot烧写到nand

bootcmd启动命令,知道执行的是nand write.uboot 0x50008000 0 0x200000命令。

从前面.u_boot_cmd的分析,知道nand write.uboot是在common/cmd_nand.c中定义, 命令函数是do_nand()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//--------------do_nand()分析
typedef struct mtd_info nand_info_t;

nand_info_t *nand;
nand = &nand_info[nand_curr_device]; //nand_curr_device=0

if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0)
/* write */
nand_write_opts(nand, &opts); //drivers/nand/nand_util.c

//板子的nand, page-size=4K, 最小write单位为page
else if (!read && s != NULL && (!strcmp(s, ".uboot")) && nand->writesize == 4096) {
//困惑:这里addr每次的偏移为啥是2K??
/*
通过后面看从nand启动时nand_cp.c中的困惑,从网上找到了答案:
BL0是将nandflash的块0的前4页中,每页头2K组合成8K,拷贝到steppingstone中的。
所以每个page只写SDRAM中的2K内容,下面代码相当于后2K和下一个page前2K是重复的。
*/
size=4096;
nand_write(nand, off, &size, (u_char *)addr); //page0-2K

off+=4096;
addr+=2048;
nand_write(nand, off, &size, (u_char *)addr); //page1-2k

off+=4096;
addr+=2048;
nand_write(nand, off, &size, (u_char *)addr); //page2-2k

off+=4096;
addr+=2048;
nand_write(nand, off, &size, (u_char *)addr); //page3-2k, BL1=8K, write done.

off+=4096;
addr+=2048;
size=1024*1024-4*4096; //虽然传入参数u-boot的大小是2M,没有使用参数,这里写死了是1M, 1M-已写入的16K
ret = nand_write(nand, off, &size, (u_char *)addr); //写BL2+空白未使用

}

//--------------------nand_write函数
static inline int nand_write(nand_info_t *info, ulong ofs, ulong *len, u_char *buf)
{
//这里调用的是 mtd->write接口,它和nand如何关联的??
return info->write(info, ofs, *len, (size_t *)len, buf);
}

//info->write 实际调用得是drivers/nand/nand_base.c中的nand_write
/**
* nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
* @to: offset to write to
* @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes
* @buf: the data to write
*
* NAND write with ECC
*/
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
int ret;

/* Do not allow reads past end of device */
if ((to + len) > mtd->size)
return -EINVAL;
if (!len)
return 0;

nand_get_device(chip, mtd, FL_WRITING);

chip->ops.len = len;
chip->ops.datbuf = (uint8_t *)buf;
chip->ops.oobbuf = NULL;

ret = nand_do_write_ops(mtd, to, &chip->ops);

*retlen = chip->ops.retlen;

nand_release_device(mtd);

return ret;
}


//-----------nand_info_t *nand 如何获得得
int nand_curr_device = -1;
nand_info_t nand_info[CFG_MAX_NAND_DEVICE]; //CFG_MAX_NAND_DEVICE=1

static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];
static ulong base_address[CFG_MAX_NAND_DEVICE] = CFG_NAND_BASE_LIST; //CFG_NAND_BASE_LIST=0x70200010 nand控制器首地址

nand_init() //driver/nand/nand.c
nand_init_chip()
board_nand_init() //cpu/s3c64xx/nand.c

if (nand_scan(mtd, 1) == 0) {
if (!mtd->name)
mtd->name = (char *)default_nand_name; //default_nand_name="nand"
}
//问题:nand 和mtd是如何关联的???

所以可以看出手上的这份文档S3C6410_Internal_ROM_Booting.pdf中关于nand的分区是有问题的

有可能后续修改了而我们没有最新文档。

按照代码,及上面所述BL0的拷贝方式,这里BL1应该占4Page, 关于Signature这个段,有些不理解,看了SPV210的 手册S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf相关的描述,是在secure boot的时候才需要的,按照个人理解这里也是一样,所以不需要。

image-20220320010838834

从Nand Flash启动

BL1流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#和从sd卡启动的流程大体相同,只是搬迁BL2不一样

reset #cpu/s3c64xx/start.S
cpu_init_crit
bl lowlevel_init #board/samsung/smdk6410/lowlevel_init.S

#判断运行的代码是否已经relocate; start.S
#BL1运行在iRAM,所以没有relocate,执行copy_from_nand

#搬迁BL2到SDRAM
bl copy_from_nand #cpu/s3c64xx/start.S
copy_uboot_to_ram #cpu/s3c64xx/nand_cp.c

skip_hw_init
stack_setup
clear_bss

#跳转到BL2
ldr pc, _start_armboot #cpu/s3c64xx/start.S

BL1如何搬迁BL2到SDRAM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#cpu/s3c64xx/start.S

mov r0, #0x1000
bl copy_from_nand


/*
* copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)
* r0: size to be compared
* Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size
*/
.globl copy_from_nand
copy_from_nand:
mov r10, lr /* save return address */

mov r9, r0
/* get ready to call C functions */
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
mov r9, #0x1000
bl copy_uboot_to_ram

3: tst r0, #0x0
bne copy_failed

ldr r0, =0x0c000000
ldr r1, _TEXT_PHY_BASE
1: ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne compare_failed /* not matched */
subs r9, r9, #4
bne 1b

4: mov lr, r10 /* all is OK */
mov pc, lr

copy_failed:
nop /* copy from nand failed */
b copy_failed

compare_failed:
nop /* compare failed */
b compare_failed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//cpu/s3c64xx/nand_cp.c

copy_uboot_to_ram()
//MT29F8G08ABABAWP
large_block = 2;
nandll_read_blocks(CFG_PHY_UBOOT_BASE, 0x3c000, large_block); //读240KB
if(large_block == 2)
{
/* Read pages */
//这里为什么是page_shift-1,这样不是覆盖了2K数据??
for (i = 0; i < 4; i++, buf+=(1<<(page_shift-1))) {
nandll_read_page(buf, i, large_block);
}
/* Read pages */
for (i = 4; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) {
nandll_read_page(buf, i, large_block);
}
}

看代码的时候一直很困惑,不知道为啥第一次读4page的数据,偏移量是page_shift-1, 这样每次会覆盖2K数据。

然后在网上看到了资料:

从nandflash启动时,BL0是将nandflash的块0的前4页中,每页头2K组合成8K,拷贝到steppingstone中的

BL0是厂家固化好的代码,我们改不了。如果我们要自己一些启动代码就需要这点。无论是写入,还是读取这8K的启动代码,也要遵循这样的约定

所以也解决了前面[BL2如何将sd卡中u-boot烧写到nand](# BL2如何将sd卡中u-boot烧写到nand) “sd卡中的u-boot程序,烧录u-boot到nand时,addr的偏移为啥是2048”的困惑。

这里要感谢drsonxu的这篇博客:关于OK6410的NandFlash启动的一些事实 .

BL2流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#和从sd卡启动大致相同,只有
#BL2 是 从_start_armboot开始的: ldr pc, _start_armboot #cpu/s3c64xx/start.S

_start_armboot:
.word start_armboot #cpu/s3c64xx/start.S

start_armboot() #lib_arm/board.c
#初始化: 函数首地址存放在 init_sequence[] 指针数组

#....参考从sd卡启动

#nand控制器初始化
nand_init();

#....参考从sd卡启动

TODO:待解决问题

nand_write()实际调用的是mtd->write(), 那么nand驱动是如何和mtd驱动关联的,暂时还没看懂???

参考

OK6410A 开发板 (三) u-boot-1.1.6 boot 解析

关于OK6410的NandFlash启动的一些事实

s3c6410初始化2G nand flash的一些注意点