S3C2440移植uboot之支持NAND启动
source link: https://segmentfault.com/a/1190000038680747
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
上一节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那些事”]
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK