上一节 S3C2440 移植 uboot 之新建单板_时钟_SDRAM_串口移植 uboot 初始化了时钟,配置了反对串口,这一节咱们持续批改 uboot 反对 NAND 启动。
@[TOC]
1. 去掉 “-pie” 选项
参考之前 uboot 应用的 start.S, init.c 来批改 uboot 代码新的 uboot 链接地址位于 0, 且在 arm-linux-ld 时加了 ”-pie” 选项, 使得 u -boot.bin 里多了"*(.rel*)", "*(.dynsym)"
, 从而程序十分大, 不利于从 NAND 启动(重定位之前的启动代码应该少于 4K).
所以接下来批改代码, 并勾销 ”-pie” 选项.
应用 grep “-pie” * -nR 找到:
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie // LDFLAGS: arm-linux-ld 的参数
所以屏蔽 arch/arm/config.mk 文件的 ”LDFLAGS_u-boot += -pie” 这行即可
2. 批改之前的 init.c
将以前写 uboot 里的 init.c 放入 board/samsung/smdk2440 目录, 并查看是否有同名函数名, 若函数只在同文件应用, 则增加 static. 并批改 Makefile 减少对 init.c 的反对
vi board/samsung/smdk2440/Makefile
批改 include/configs/smdk2440.h 文件,将 CONFIG_SYS_TEXT_BASE 宏改为 0x33f80000, 也就是 uboot 重定位后的地位, 这里留了 512K 空间供应 uboot 重定位
批改完的代码如下所示
/* 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))
/* GPIO */
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/* UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
#define TXD0READY (1<<2)
void nand_read_ll(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_init();
nand_read_ll((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 nand_init_ll(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_ll(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();}
3. 批改 start.s 重定位局部
批改 arch/arm/cpu/arm920t/start.S, 更改重定位代码。因为 nand 启动时,2440 未初始化之前只有前 4K 可读写, 所以将重定位代码放在 start.S 的 cpu_init_crit(初始化 SDRAM)段前面。批改后代码如下
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) // 等于 0x30000f80
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
bl nand_init_ll
mov r0, #0 //r0->src
//ldr r1, =_start
ldr r1,_TEXT_BASE // 链接地址 _TEXT_BASE : 0x33f80000 0x34000000-0x33f80000=512k uboot 512k 足以
ldr r2,_bss_start_ofs // _bss_start_ofs: __bss_start - _start (无效代码大小)
bl copy_code_to_sdram
bl clear_bss // 革除 bss 段(参考自制 uboot 章节)
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
下面的_TEXT_BASE, 在 start.S 靠前处定义:
因为它位于靠前处, 保障了_TEXT_BASE 存在前 4k 空间里, 若间接应用 ldr r1,=CONFIG_SYS_TEXT_BASE, 编译器可能会将这个宏定义放在 SDRAM 上, 则会出错。
重定位写在后面了, 所以咱们还要删除 start.S 前面的 u -boot-2012.04.01\arch\arm\lib\board.c 中的 relocate_code 重定位段, 革除 BSS 段。同时在 relocate_code(addr_sp, id, addr); 前面减少 return (unsigned int) id;,批改函数为 unsigned int board_init_f(ulong bootflag)。
同时正文掉 board.c 中如下的内容,固定 addr 的值。
删除 start.s 中原有的重定位代码,删除局部如下
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _bss_start_ofs
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_SPL_BUILD
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
#endif
clear_bss:
#ifndef CONFIG_SPL_BUILD
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
bl coloured_LED_init
bl red_led_on
#endif
start.s 减少第二阶段启动代码
call_board_init_f:
ldr r0,=0x00000000
bl board_init_f
/*unsigned int id 的值存在 r0 中,正好给 board_init_r 应用 */
ldr r1, =_TEXT_BASE
/* 调用第二阶段代码 */
bl board_init_r
4. 批改链接脚本
把 start.S, init.c(实现重定位), lowlevel.S(实现初始化 SDRAM)等文件放在最后面
rm u-boot.lds
vi arch/arm/cpu/u-boot.lds
增加以下字段:
. = ALIGN(4);
.text :
{
__image_copy_start = .;
CPUDIR/start.o (.text) //CPUDIR 为 arch/arm/cpu/arm920t 目录
board/samsung/smdk2440/libsmdk2440.o (.text)
*(.text)
}
libsmdk2440.o 是将 smdk2440 单板目录下的所有.c, S 文件编译后, 连接成一个库文件.
5. 报错批改
报错
board.c:259: error: conflicting types for 'board_init_f'
/work/system/u-boot-2012.04.01/include/common.h:276: error: previous declaration of 'board_init_f' was here
/work/system/u-boot-2012.04.01/config.mk:312: recipe for target 'board.o' failed
依据批示批改 u -boot-2012.04.01/include/common.h 276 行如下
报错
board/samsung/smdk2440/libsmdk2440.o: In function `clear_bss':
/work/system/u-boot-2012.04.01/board/samsung/smdk2440/init.c:77: undefined reference to `__bss_end_'Makefile:472: recipe for target'u-boot' failed
依据批示批改 u -boot-2012.04.01/board/samsung/smdk2440/init.c:77 行如下
6. 从新批改链接地址
咱们指定了 CONFIG_SYS_TEXT_BASE 0x33f80000,所以咱们的 uboot 不能超过 512k,0x33f80000 这个是不包含 bss 段的全局变量的。查看 start.s 文件。
在反汇编中搜寻_bss_end_ofs,00094b40 为整个代码段的大小(包含了 bss 段),转换为 10 进制 609088,曾经大于了 512k,所以从新批改 CONFIG_SYS_TEXT_BASE 0x33f00000。预留 uboot 空间为 0x34000000-0x33f00000=1M
而后通过旧的 uboot, 将新的 uboot 烧写到 nand 中
usb 1 30000000 // 先下载到 SDRAM 上
nand erase 0 0x80000 // 擦除 512kb, 必须大于新的 uboot
nand write 30000000 0 0x80000 // 将 SDRAM 上的新 uboot 写入 nand
查看 u -boot.lds
烧写后, 如下图所示:
nand 启动便实现实现了, 下面的 Flash: *** failed ***
是属于 uboot 第二阶段函数 board_init_r()里的代码, 示意不反对 nor flash, 不能实现读, 写, 擦除等命令。
下一节 S3C2440 移植 uboot 之反对 NORFLASH 咱们将移植 uboot 反对咱们的 s3c2440。
如遇到排版错乱的问题,能够通过以下链接拜访我的 CSDN。
**CSDN:[CSDN 搜寻“嵌入式与 Linux 那些事”]