上一节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_coderelocate_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    fixnextfixabs:    /* 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    fixnextfixrel:    /* relative fix: increase location by offset */    ldr    r1, [r0]    add    r1, r1, r9fixnext:    str    r1, [r0]    add    r2, r2, #8        /* each rel.dyn entry is 8 bytes */    cmp    r2, r3    blo    fixloop#endifclear_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.ldsvi 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,必须大于新的ubootnand 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那些事”]