关于c:S3C2440移植uboot之支持NAND启动

5次阅读

共计 7595 个字符,预计需要花费 19 分钟才能阅读完成。

  上一节 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 那些事”]

正文完
 0