zoukankan      html  css  js  c++  java
  • 三,移植uboot-支持NAND启动

    文档时间:2018-08-10

    交叉编译器:arm-linux-gcc-4.3.2

    Ubuntu版本:16.04

    uboot版本:2013.10

    1,分析为何不能从 nand 启动

    将上一章编译好的 u-boot.bin 烧写到 nand flash 中,将板子设置位 nand 启动,发现串口无任何输出,说明 nand 启动未成功,查看反汇编文件 u-boot.dis

    先生成 u-boot.dis:

    arm-linux-objdump -D u-boot > u-boot.dis

     打开 u-boot.dis :

    发现 u-boot 如果从 nand 启动,有问题,主要是因为 s3c2440 sram 太小,只有 4k,而在前 4k 地址中,调用了很多 4k 地址以外的函数,这样就会导致程序跑飞

    因此,为了能够让 uboot 支持 nand 启动,需要在前 4k 就完成代码重定位和代码拷贝的工作

    2,修改代码实现 nand 启动

    1),参考裸机程序关于 nand 部分和代码拷贝部分,添加 nand_read_ll.c 文件

    在 board/samsung/jz2440 目录下新建 nand_read_ll.c 文件,将以前裸机程序中关于 nand 部分和 代码拷贝部分的代码复制到此文件中,完成后,代码如下:

      1 /**
      2 * u-boot-2012.04.01_100ask/board/samsung/smdk2440/init.c
      3 **/
      4 
      5 
      6 /* NAND FLASH控制器 */
      7 #define NFCONF (*((volatile unsigned long *)0x4E000000))
      8 #define NFCONT (*((volatile unsigned long *)0x4E000004))
      9 #define NFCMMD (*((volatile unsigned char *)0x4E000008))
     10 #define NFADDR (*((volatile unsigned char *)0x4E00000C))
     11 #define NFDATA (*((volatile unsigned char *)0x4E000010))
     12 #define NFSTAT (*((volatile unsigned char *)0x4E000020))
     13 
     14 
     15 void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);
     16 
     17 static void nand_init_ll(void)
     18 {
     19 #define TACLS   0
     20 #define TWRPH0  1
     21 #define TWRPH1  0
     22     /* 设置时序 */
     23     NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
     24     /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
     25     NFCONT = (1<<4)|(1<<1)|(1<<0);    
     26 }
     27 
     28 static int isBootFromNorFlash(void)
     29 {
     30     volatile int *p = (volatile int *)0;
     31     int val;
     32 
     33     val = *p;
     34     *p = 0x12345678;
     35     if (*p == 0x12345678)
     36     {
     37         /* 写成功, 是nand启动 */
     38         *p = val;
     39         return 0;
     40     }
     41     else
     42     {
     43         /* NOR不能像内存一样写 */
     44         return 1;
     45     }
     46 }
     47 
     48 void copy_code_to_sdram(volatile unsigned int *src, volatile unsigned int *dest, unsigned int len)
     49 {    
     50     unsigned int i = 0;
     51     
     52     /* 如果是NOR启动 */
     53     if (isBootFromNorFlash())
     54     {
     55         while (i < len)
     56         {
     57             *dest++ = *src++;
     58             i += 4;
     59         }
     60     }
     61     else
     62     {
     63         nand_init_ll();
     64         nand_read_ll((unsigned int)src, (unsigned char *)dest, len);
     65     }
     66 }
     67 
     68 void clear_bss(void)
     69 {
     70     extern int __bss_start, _bss_end;
     71     int *p = &__bss_start;
     72     
     73     for (; p < &_bss_end; p++)
     74         *p = 0;
     75 }
     76 
     77 static void nand_select(void)
     78 {
     79     NFCONT &= ~(1<<1);    
     80 }
     81 
     82 static void nand_deselect(void)
     83 {
     84     NFCONT |= (1<<1);    
     85 }
     86 
     87 static void nand_cmd(unsigned char cmd)
     88 {
     89     volatile int i;
     90     NFCMMD = cmd;
     91     for (i = 0; i < 10; i++);
     92 }
     93 
     94 static void nand_addr_byte(unsigned char addr)
     95 {
     96     volatile int i;
     97     
     98     NFADDR = addr;
     99     for (i = 0; i < 10; i++);    
    100 }
    101 
    102 static void nand_wait_ready(void)
    103 {
    104     while (!(NFSTAT & 1));
    105 }
    106 
    107 static unsigned char nand_r_data(void)
    108 {
    109     return NFDATA;
    110 }
    111 
    112 void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
    113 {
    114     int i = 0;
    115     unsigned int page = addr/2048;
    116     unsigned int col = addr&(2048-1);
    117         
    118     /* 1. 选中 */
    119     nand_select();
    120 
    121     while (i < len)
    122     {
    123         /* 2. 发出读命令00h */
    124         nand_cmd(0x00);
    125 
    126         /* 3. 发出地址(分5步发出) */
    127         nand_addr_byte(col&0xff);
    128         nand_addr_byte((col>>8)&0xff);
    129 
    130         nand_addr_byte(page&0xff);
    131         nand_addr_byte((page>>8)&0xff);
    132         nand_addr_byte((page>>16)&0xff);
    133 
    134         /* 4. 发出读命令30h */
    135         nand_cmd(0x30);
    136 
    137         /* 5. 判断状态 */
    138         nand_wait_ready();
    139 
    140         /* 6. 读数据 */
    141         for (; (col < 2048) && (i < len); col++)
    142         {
    143             buf[i++] = nand_r_data();
    144         }
    145         if(i==len)
    146             break;
    147         
    148         col = 0;
    149         page++;
    150     }
    151 
    152     /* 7. 取消选中 */        
    153     nand_deselect();
    154 }

    在 board/samsung/jz2440/Makefile 中增加对 nand_read_ll.c 文件的编译支持(红色部分为修改代码):

    COBJS    := jz2440.o
    COBJS    += nand_read_ll.o
    SOBJS    := lowlevel_init.o

     2),修改 include/configs/jz2440.h 文件

    查找 CONFIG_SYS_TEXT_BASE 将其值改为:

    #define CONFIG_SYS_TEXT_BASE    0x33f00000

     0x33f00000是 uboot 重定位之后的地址,从0x33f00000到0x34000000,给uboot预留了1M的存储空间

    3),修改 arch/arm/lib/crt0.S 文件

    从之前的 arch/arm/cpu/arm920t/start.S 文件知道,程序最后会跳到 _main 处,如下所示:

    而 _main 的入口在 crt0.S 中,调用 C 函数也是在 crt0.S 中,因此我们需要修改 crt0.S 文件,修改代码如下(红色为修改部分,蓝色部分为删除代码):

    #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
        ldr    sp, =(CONFIG_SPL_STACK)
    #else
        ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
    #endif
        bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
        sub    sp, #GD_SIZE    /* allocate one GD above SP */
        bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
        mov    r9, sp        /* GD is above SP */
    __TEXT_BASE:
      .word CONFIG_SYS_TEXT_BASE

    mov r0,#0 //r0对应第一个参数:源地址 ldr r1,__TEXT_BASE //_TEXT_BASE : 0x33f00000:目的地址 ldr r2,__bss_start   // __bss_start - _start (有效代码大小) sub r2, r2, r1
       bl copy_code_to_sdram //该函数首先会初始化nand控制器,然后复制代码到SDRAM连接地址dest上 bl clear_bss //清除bss段 ldr pc, =call_board_init_f //绝对跳转,跳到SDRAM中执行 call_board_init_f: mov r0, #0 bl board_init_f ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ ldr r9, [r9, #GD_BD] /* r9 = gd->bd */ sub r9, r9, #GD_SIZE /* new GD is below bd */ ldr r1, __TEXT_BASE /* dest_addr */ //第二个参数目的地址 /* call board_init_r */ bl board_init_r /* 进入第二阶段 */
    #if ! defined(CONFIG_SPL_BUILD) /* * Set up intermediate environment (new sp and gd) and call * relocate_code(addr_moni). Trick here is that we'll return * 'here' but relocated. */ ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ ldr r9, [r9, #GD_BD] /* r9 = gd->bd */ sub r9, r9, #GD_SIZE /* new GD is below bd */ adr lr, here ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */ add lr, lr, r0 ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */ b relocate_code here: /* Set up final (full) environment */ bl c_runtime_cpu_setup /* we still call old routine here */ ldr r0, =__bss_start /* this is auto-relocated! */ ldr r1, =__bss_end /* this is auto-relocated! */ mov r2, #0x00000000 /* prepare zero to clear BSS */ clbss_l:cmp r0, r1 /* while not at end of BSS */ strlo r2, [r0] /* clear 32-bit BSS word */ addlo r0, r0, #4 /* move to next */ blo clbss_l bl coloured_LED_init bl red_led_on /* call board_init_r(gd_t *id, ulong dest_addr) */ mov r0, r9 /* gd_t */ ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */ /* call board_init_r */ ldr pc, =board_init_r /* this is auto-relocated! */ /* we should not return here. */ #endif

    (PS:上述修改文件中用 __TEXT_BASE 代替 CONFIG_SYS_TEXT_BASE 宏,是因为__TEXT_BASE 定义在前,而宏是在 jz2440.h 文件中定义,为了让代码编译靠前) 

    !!!__TEXT_BASE  不能用start.S 中的 _TEXT_BASE 代替!!!

    4),修改 arch/arm/lib/board.c 里的 board_init_f 函数(红色部分为修改代码) :

        /*
         * reserve memory for U-Boot code, data & bss
         * round down to next 4 kB limit
         */
        //addr -= gd->mon_len;
        addr = CONFIG_SYS_TEXT_BASE;
        addr &= ~(4096 - 1);
    
        debug("Reserving %ldk for U-Boot at: %08lx
    ", gd->mon_len >> 10, addr);
    unsigned int board_init_f(ulong bootflag)
        memcpy(id, (void *)gd, sizeof(gd_t));
    
        return ((unsigned int)id);    //将id传给 board_init_r

    addr 就是目的地址,因此需要修改为 0x33f00000,如果不修改,原先的栈就会被覆盖,导致代码死掉 

    修改 include/common.h 中对 board_init_f 的声明(红色部分为修改代码):

    /* arch/$(ARCH)/lib/board.c */
    unsigned int    board_init_f(ulong);

    5),修改链接脚本 u-boot.lds(arch/arm/cpu目录下)

    修改 u-boot.lds 将 nand_read_ll.c(实现代码拷贝,代码重定位) lowlevel.S(初始化ADRAM) 放在前面编译,修改如下,红色部分为修改代码:

        . = ALIGN(4);
        .text :
        {
            *(.__image_copy_start)
            CPUDIR/start.o (.text*)
            board/samsung/jz2440/lowlevel.o (.text*)
            board/samsung/jz2440/nand_read_ll.o (.text*)
            *(.text*)
        }

    修改完毕,编译,出现如下错误:

    输入命令 grep "R_ARM_RELATIVE" * -nR 进行搜索,发现 Makefile 中有一个检查重定位的规则,屏蔽该规则,代码如下(红色为修改部分):

    # ARM relocations should all be R_ARM_RELATIVE.
    checkarmreloc: $(obj)u-boot
    #    @if test "R_ARM_RELATIVE" != 
            "`$(CROSS_COMPILE)readelf -r $< | cut -d ' ' -f 4 | grep R_ARM | sort -u`"; 
            then echo "$< contains relocations other than 
            R_ARM_RELATIVE"; false; fi

    再次编译,成功,进行烧写(可以先把旧的u-boot.bin烧写到norflash,然后通过旧的uboot把新的uboot烧写到nand flash),得到如下界面,表示启动成功

    到此,我们的代码已经支持NOR启动,NAND启动了!

  • 相关阅读:
    17 applyMiddleware MainMiddleWare, redux-thunk , createStore
    16 redux简介
    15 react-redux provider组件
    14 React Refs
    13 React 表单与事件
    12 React AJAX
    Vue3 getCurrentInstance与ts结合使用的问题
    Vue3 更改setup中定义的值不渲染到视图上【Vue2.x向Vue3.x的迁移(踩坑)日记】
    Vue3 中组件传值emit【Vue2.x向Vue3.x的迁移日记】
    vue js 模糊匹配搜索查询
  • 原文地址:https://www.cnblogs.com/zhyy-mango/p/9451821.html
Copyright © 2011-2022 走看看