`
flytreeleft
  • 浏览: 93271 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

UBoot支持双启动(Nor and Nand)及环境变量保存的实现

阅读更多

本文所要讲述的是如何使UBoot只编译一次就能支持从Nor Flash和Nand Flash启动,并且在保存环境变量时能够保存在其所在的Flash中.

注意,本文针对的为S3C2410芯片,其他芯片原理相同,可在适当修改代码后进行移植.

我们知道UBoot源码本身直接支持从Nor Flash启动,这是Nor Flash的可执行特性决定的.而针对Nand Flash,则涉及到前4K数据的问题.S3C2410的Nand Flash控制器有一个特殊的功能,就是能在上电后自动将Nand Flash中的前4K数据搬移到4K内部的RAM中,并把0x00000000设置为内部RAM的起始地址,然后CPU从内部RAM的0x000000位置启动,该过程由硬件自动完成.
所以,要使UBoot支持从Nand Flash启动,必须在其前4K代码执行过程中完成将自身复制到RAM中的工作.

但是,我们现在需要让UBoot支持双启动,现在的问题就是该如何判断UBoot是在Nor Flash还是在Nand Flash中呢?呵呵,在S3C2410(S3C2440)中,这个可以通过BWSCON(BUS WIDTH & WAIT CONTROL REGISTER)控制寄存器[2:1]的值进行判断,如果为00则表示是从Nand Flash启动的.因此,我们可以直接通过如下代码进行判断并在BWSCON[2:1]为00时跳转到UBoot复制自身(copy_myself)的代码处:

    #define BWSCON      0x48000000  
    ldr     r0, =BWSCON  
    ldr     r0, [r0]  
    ands    r0, r0, #6      @ 判断BWSCON[2:1]是否为00,如果是,则跳转到copy_myself  
    beq     copy_myself 
 

好了,双启动问题算是解决了,但是新的问题又来了,这个环境变量又应该如何保存呢?是都保存到Nor Flash还是Nand Flash呢?当然,最好的方式还是保存到各自所在的Flash中.这个可以设置一个标志,在进入Nand Flash启动代码时设置该标志,表示从Nand Flash启动,然后,在保存环境变量时通过该标志的值判断是调用Nor Flash的保存方法还是Nand Flash的保存方法.

下面讲解具体的修改过程(以u-boot-2010.09为例).
首先,修改include/configs/smdk2410.h文件,添加如下宏定义:

#define CONFIG_CMD_ENV  // 开启环境变量操作命令  
#define CONFIG_CMD_NAND // 开启Nand Flash操作命令  
#ifdef CONFIG_CMD_NAND  
#   define CONFIG_SYS_NAND_BASE            0x4E000000 //Nand配置寄存器基地址  
#   define CONFIG_SYS_MAX_NAND_DEVICE      1  
#   define CONFIG_MTD_NAND_VERIFY_WRITE    1  
  
#   define CONFIG_NAND_S3C2410  
#   define STACK_BASE 0x33f00000   /* 堆栈基址 */  
#   define STACK_SIZE 0x8000       /* 堆栈大小 */  
#endif  
  
/*--------------------------------------------------------------------- 
 * Boot From Nor or Nand Flash or both 
 */  
#define CONFIG_NOR_BOOT  
#define CONFIG_NAND_BOOT  
  
#ifdef CONFIG_NOR_BOOT  
#   define PHYS_FLASH_1     0x00000000 /* Flash Bank #1 */  
#   define CONFIG_SYS_FLASH_BASE        PHYS_FLASH_1  
  
#   define CONFIG_AMD_LV160B    /* 使用AM29LV160DB Nor Flash芯片 */  
  
#   define CONFIG_SYS_MAX_FLASH_BANKS   1   /* max number of memory banks */  
  
/* timeout values are in ticks */  
#   define CONFIG_SYS_FLASH_ERASE_TOUT  (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */  
#   define CONFIG_SYS_FLASH_WRITE_TOUT  (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */  
  
#   define  CONFIG_ENV_IS_IN_FLASH  /* 将环境变量保存到Nor Flash中*/  
#endif  
  
#ifdef CONFIG_NAND_BOOT  
#   define UBOOT_RAM_BASE       0x33f80000  
#   define NAND_CTL_BASE        0x4E000000  
#   define bINT_CTL(Nb)     __REG(INT_CTL_BASK + (Nb))  
#   define oNFCONF          0x00  
#   define oNFCMD           0x04  
#   define oNFADDR          0x08  
#   define oNFDATA          0x0c  
#   define oNFSTAT          0x10  
#   define oNFECC           0x14  
  
#   define CONFIG_UBOOT_SIZE        0x30000  
#   define CONFIG_ENV_IS_IN_NAND    /* common/env_nand.c */  
  
#   ifndef CONFIG_NOR_BOOT  
#       define CONFIG_SYS_NO_FLASH  
#       undef CONFIG_CMD_FLASH  
#       undef CONFIG_CMD_IMLS  
#   endif  
#endif  
  
/*--------------------------------------------------------------------------- 
 * Nor Flash Device 
 */  
#ifdef CONFIG_AMD_LV160B  
#   define PHYS_FLASH_SIZE      0x00200000  /* 2MB */  
#   define CONFIG_SYS_MAX_FLASH_SECT    (35)    /* max number of sectors on one chip */  
#   define CONFIG_ENV_ADDR      (CONFIG_SYS_FLASH_BASE + 0x030000)/* addr of environment */  
#endif  
  
/*-------------------------------------------------------------------------- 
 * Environment Setting 
 */  
// 环境变量的大小必须为sector的整数倍,此处直接设置为0x1000,  
// 能够同时满足Nor Flash和Nand Flash的要求  
#define CONFIG_ENV_SIZE     0x10000  
#ifdef  CONFIG_ENV_IS_IN_FLASH  
//# define  CONFIG_ENV_ADDR  (CONFIG_SYS_FLASH_BASE + 0x30000)  
#endif  
#ifdef  CONFIG_ENV_IS_IN_NAND  
#   define  CONFIG_ENV_OFFSET   CONFIG_UBOOT_SIZE /* 环境变量紧接在uboot之后 */  
#endif  
 

然后,修改启动文件arch/arm/cpu/arm920t/start.S,增加Nand Flash启动代码和启动标志的设置(直接修改relocate代码段):

/* 双启动判断 */  
#define BWSCON      0x48000000  
    ldr     r0, =BWSCON  
    ldr     r0, [r0]  
    ands    r0, r0, #6      @ 判断BWSCON[2:1]是否为00,如果是,则跳转到copy_myself  
    beq     copy_myself  
  
#ifdef CONFIG_NOR_BOOT  
#ifndef CONFIG_SKIP_RELOCATE_UBOOT  
relocate:               /* relocate U-Boot to RAM       */  
    adr r0, _start      /* r0 <- current position of code   */  
    ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */  
    cmp r0, r1          /* don't reloc during debug         */  
    beq stack_setup  
      
    ldr r2, _armboot_start  
    ldr r3, _bss_start  
    sub r2, r3, r2      /* r2 <- size of armboot            */  
    add r2, r0, r2      /* r2 <- source end address         */  
  
copy_loop:  
    ldmia   r0!, {r3-r10}       /* copy from source address [r0]    */  
    stmia   r1!, {r3-r10}       /* copy to   target address [r1]    */  
    cmp r0, r2          /* until source end addreee [r2]    */  
    ble copy_loop  
      
    b stack_setup       /* 跳过nand启动代码 */  
#endif  /* CONFIG_SKIP_RELOCATE_UBOOT */  
#endif  /* CONFIG_NOR_BOOT */  
  
#ifdef  CONFIG_NAND_BOOT  
copy_myself:         
    @ reset NAND  
    mov r1, #NAND_CTL_BASE  
    ldr r2, =0xf830             @ initial value  
    str r2, [r1, #oNFCONF]  
    ldr r2, [r1, #oNFCONF]  
    bic r2, r2, #0x800          @ enable chip  
    str r2, [r1, #oNFCONF]  
    mov r2, #0xff           @ RESET command  
    strb r2, [r1, #oNFCMD]  
    mov r3, #0                  @ wait  
  
nand1:   
    add r3, r3, #0x1  
    cmp r3, #0xa  
    blt nand1  
  
nand2:  
    ldr r2, [r1, #oNFSTAT]      @ wait ready  
    tst r2, #0x1  
    beq nand2  
  
    ldr r2, [r1, #oNFCONF]  
    orr r2, r2, #0x800          @ disable chip  
    str r2, [r1, #oNFCONF]  
  
    @ get read to call C functions (for nand_read())  
    ldr sp, DW_STACK_START      @ setup stack pointer  
    mov fp, #0                  @ no previous frame, so fp=0  
  
    @ copy U-Boot to RAM  
    ldr r0, =UBOOT_RAM_BASE     @ buf : first parameter of nand_read_ll()  
    mov r1, #0x0            @ start_addr : second parameter of nand_read_ll()  
    mov r2, #CONFIG_UBOOT_SIZE  @ size : third parameter of nand_read_ll()  
    bl  nand_read_ll  
    tst r0, #0x0  
    beq ok_nand_read  
  
bad_nand_read:  
    loop2:  b     loop2             @ infinite loop  
  
ok_nand_read:  
    @ set flag : 0->boot from nand;1->boot from nor  
    @ set flag after finishing to copy U-Boot to memory  
    ldr r0, =boot_flash     @ defined in common/cmd_nvedit.c  
    mov r1, #0x0  
    str r1, [r0]  
      
    @ verify  
    mov r0, #0  
    ldr r1, =UBOOT_RAM_BASE     @ NOTE: DON'T USE '_TEXT_BASE'  
    mov r2, #0x400          @ 4 bytes * 1024 = 4K-bytes  
  
go_next:  
    ldr r3, [r0], #4  
    ldr r4, [r1], #4  
    teq r3, r4  
    bne notmatch  
    subs r2, r2, #4  
    beq  stack_setup  
    bne  go_next  
  
notmatch:  
    loop3:  b     loop3         @ infinite loop  
#endif  /* CONFIG_NAND_BOOT */  
    .align 2  
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4  
 

其中,boot_flash为1表示从Nor Flash启动,为0则表示从Nand Flash启动,为使该值能够正确被修改,所以将其在UBoot复制完毕后进行修改.代码中的UBOOT_RAM_BASE不要直接替换为_TEXT_BASE,虽然两者值相同,但是在运行中却有问题,我就因为使用了_TEXT_BASE,导致费了很多时间,前车之荐,请勿效仿!
nand_read_ll为新增加的Nand Flash读取方法,在board/samsung/smdk2410目录下新建文件nand_read.c,并添加如下代码:

#include <config.h>  
#define __REGb(x) (*(volatile unsigned char *)(x))  
#define __REGi(x) (*(volatile unsigned int *)(x))  
#define NF_BASE   0x4e000000  
#define NFCONF    __REGi(NF_BASE + 0x0)  
#define NFCMD     __REGb(NF_BASE + 0x4)  
#define NFADDR    __REGb(NF_BASE + 0x8)  
#define NFDATA    __REGb(NF_BASE + 0xc)  
#define NFSTAT    __REGb(NF_BASE + 0x10)  
  
#define BUSY 1  
inline void wait_idle(void) {  
    int i;  
  
    while(!(NFSTAT & BUSY))  
        for(i=0; i<10; i++);  
}  
  
#define NAND_SECTOR_SIZE 512  
#define NAND_BLOCK_MASK   (NAND_SECTOR_SIZE - 1)  
  
/* low level nand read function */  
int nand_read_ll(unsigned char *buf,   
                unsigned long start_addr,   
                int            size)  
{  
    int i, j;  
  
    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {  
        return -1; /* invalid alignment */  
    }  
  
    /* chip Enable */  
    NFCONF &= ~0x800;  
    for(i=0; i<10; i++);  
  
    for(i=start_addr; i < (start_addr + size);) {  
        /* READ0 */  
        NFCMD = 0;  
  
        /* Write Address */  
        NFADDR = i & 0xff;  
        NFADDR = (i >> 9) & 0xff;  
        NFADDR = (i >> 17) & 0xff;  
        NFADDR = (i >> 25) & 0xff;  
  
        wait_idle();  
  
        for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {  
            *buf = (NFDATA & 0xff);  
            buf++;  
        }  
    }  
  
    /* chip Disable */  
    NFCONF |= 0x800; /* chip disable */  
  
    return 0;  
}  
 

修改Makefile,使nand_read.c能够被编译进UBoot:
COBJS := smdk2410.o flash.o nand_read.o
为了保证nand_read_ll方法能够被编译到UBoot代码的前4K中,以确保代码的正确执行,还需修改链接文件arch/arm/cpu/arm920t/u-boot.lds,如下:

.text :  
    {  
        arch/arm/cpu/arm920t/start.o    (.text)  
        board/samsung/smdk2410/lowlevel_init.o  (.text)  
        board/samsung/smdk2410/nand_read.o  (.text)  
        *(.text)  
    }
 

最后,该修改代码以支持环境变量的保存了.
在UBoot中,环境变量操作的命令在文件common/cmd_nvedit.c中定义和实现,而针对不同Flash的操作,如env_init,saveenv和env_relocate_spec,则在common/env_flash.c和common/env_nand.c中进行定义和实现.
为了双启动的支持,并且能够支持单启动(Nor或Nand启动),我们将上面三个方法整合到了cmd_nvedit.c中,并将env_flash.c和env_nand.c中的这三个方法添加上nor和nand前缀,用于区分调用,并防止同时编译时的重定义.
然后,将env_flash.c和env_nand.c中定义的env_name_spec和env_ptr两个变量放到cmd_nvedit.c中进行定义,这两个文件直接使用extern关键字引用这两个变量.由于函数env_get_char_spec在env_flash.c和env_nand.c中都进行了定义,所以也和env_init一样转到cmd_nvedit.c中进行定义.
接着,就是定义启动标志boot_flash,并设置初值为1.

具体修改如下:
在common/cmd_nvedit.c中增加如下代码:

// 1:NOR FLASH启动,0:NAND FLASH启动  
// boot_flash将在start.S中被修改  
int boot_flash = 1;  
char * env_name_spec;  
env_t * env_ptr;  
  
extern nor_env_get_char_spec(int index);  
extern nand_env_get_char_spec(int index);  
extern int nor_env_init(void);  
extern int nand_env_init(void);  
extern int nor_saveenv(void);  
extern int nand_saveenv(void);  
extern void nor_env_relocate_spec(void);  
extern void nand_env_relocate_spec(void);  
#ifdef ENV_IS_EMBEDDED  
    extern uchar environment[];  
#endif  
  
uchar env_get_char_spec(int index)  
{  
    if (boot_flash) {  
        return nor_env_get_char_spec(index);  
    } else {  
        return nand_env_get_char_spec(index);  
    }  
}  
   
int env_init(void)  
{  
    if (boot_flash) {  
    #ifdef ENV_IS_EMBEDDED  
        env_ptr = (env_t *)(&environment[0]);  
    #else  
        env_ptr = (env_t *)CONFIG_ENV_ADDR;  
    #endif  
        env_name_spec = "Flash";  
          
        return nor_env_init();  
    } else {  
    #if defined(ENV_IS_EMBEDDED)  
        env_ptr = (env_t *)(&environment[0]);  
    #elif defined(CONFIG_NAND_ENV_DST)  
        env_ptr = (env_t *)CONFIG_NAND_ENV_DST;  
    #else  
        env_ptr = NULL;  
    #endif  
        env_name_spec = "NAND";  
          
        return nand_env_init();  
    }  
}  
  
int saveenv(void)  
{  
    if (boot_flash) {  
        return nor_saveenv();  
    } else {  
        return nand_saveenv();  
    }  
}  
  
void env_relocate_spec(void)  
{  
    if (boot_flash) {  
        return nor_env_relocate_spec();  
    } else {  
        return nand_env_relocate_spec();  
    }  
}  
 

在common/env_flash.c和common/env_nand.c中,去掉对env_name_spec和env_ptr的定义,改为外部引用:

extern char * env_name_spec;  
extern env_t *env_ptr; 
 

最后,在env_get_char_spec,env_init,saveenv和env_relocate_spec方法前分别添加前缀"nor_"和"nand_".

好了,现在编译UBoot:

make smdk2410_config && make all
 

下载到开发板上试试吧!

 

 

参考资料:
1. <<如何让U-boot实现Nand/Nor 双启动>>
2. <<Nand Flash 和 Nor Flash 双启动方法探究>>  关于S3C2440的
3. <<成功在skyeye 上实现U-Boot 的Nand命令并从Nand中启动Linux>>
4. <<从Nand Flash启动U-BOOT的基本原理>>
5. <<关于u-boot同时支持nand启动和Nor启动环境变量的保存位置>> 标志修改的代码放置位置好像不行,我这没有成功

分享到:
评论

相关推荐

    支持nand启动的uboot

    **支持NAND启动的U-Boot详解** U-Boot,全称Microcontroller Bootloader,是一款广泛应用在嵌入式系统中的开放源代码引导加载程序。它为各种嵌入式硬件平台提供了一个灵活、可扩展的启动环境,使得系统能够顺利地从...

    UBOOT环境变量.

    U-Boot环境变量是一系列用于保存系统状态和配置信息的变量集合。它们被存储在非易失性存储器中,并在每次启动时加载到内存中供U-Boot使用。通过设置不同的环境变量,用户可以灵活地控制系统的启动行为。 #### 常用...

    linux启动.txt

    总结来说,实现UBoot支持双启动(Nor和Nand)及环境变量保存的实现主要涉及以下几个步骤: 1. 检测启动设备类型:通过读取BWSCON寄存器来判断启动来源。 2. 在Nand Flash启动时,包含复制UBoot到RAM的代码。 3. 设置...

    Uboot环境变量与内核MTD分区关系

    在启动时,Uboot会读取环境变量,这些环境变量包含了关于系统启动的必要信息,比如启动参数、内核映像位置、文件系统位置等。环境变量可以在Uboot交互式命令行中修改,也可以在系统烧写或更新时预先设置。 在MTD...

    uboot代码完全解析

    在系统启动时,uboot会加载这些环境变量到RAM中以便使用,如果环境变量不存在或出错,uboot会使用默认值。 uboot的代码中还有许多关键的函数,如start_armboot,它是uboot启动主程序的入口,负责初始化硬件,加载...

    ARM上电启动及Uboot代码分析

    ### ARM上电启动及Uboot代码分析 #### 摘要 本文旨在深入解析Uboot在ARM架构下的启动过程,重点研究从上电至第一条指令的执行,以及在此过程中涉及的cache、TLB等硬件组件的操作。通过分析,旨在帮助读者理解ARM...

    uboot启动源码

    2. **环境变量管理**:UBoot支持通过环境变量配置系统参数,如网络设置、设备驱动等,这些变量可以存储在Flash中,便于系统重启后保持配置。 3. **文件系统加载**:UBoot可以读取和挂载各种文件系统,如FAT、JFFS2等...

    Uboot-boot-analyse.rar_uboot_启动分析

    - **环境变量**:UBoot使用环境变量来存储配置信息,如网络设置、启动设备等。这部分会加载或初始化这些变量。 - **硬件设备初始化**:包括串口、GPIO、时钟、中断控制器等,为后续操作做好准备。 - **设备树...

    linux内核驱动之uboot环境变量.docx

    综上所述,U-Boot环境变量是实现自定义启动流程的关键要素,通过合理设置不同类型的环境变量,开发者可以灵活地控制启动过程中的各个细节,包括网络配置、内核加载方式以及启动参数等。这对于嵌入式系统的调试和部署...

    移植笔记-之从Norflash启动的uboot.pdf

    在解读文件“移植笔记-之从Norflash启动的uboot.pdf”时,首先需要了解文件所涉及的核心技术和概念。该文档主要关注嵌入式系统开发领域,特别是针对U-Boot固件的移植过程,以及如何从Norflash存储器启动U-Boot。接...

    uboot移植,uboot手册

    1. **移植环境准备**:移植uboot首先需要搭建交叉编译环境,包括选择合适的GCC交叉编译工具链,设置环境变量,确保能正确编译针对目标硬件的代码。 2. **理解硬件平台**:imx287和s3c2440是两种不同的处理器芯片。...

    uboot移植大全,全面介绍uboot移植

    移植过程中,可能需要根据实际情况调整环境变量,如设置启动设备、网络接口的MAC地址等。 十、持续更新与维护 U-Boot项目持续发展,新版本会引入新的特性、修复已知问题。因此,定期更新源码并重新移植是必要的,以...

    uboot移植 的常用命令详解

    13. `saveenv`/`loadenv`:保存或加载环境变量到非易失性存储。 四、U-Boot调试 1. `console`:U-Boot的控制台输出,可用于查看运行状态和错误信息。 2. `debug`选项:在配置阶段开启,可以获取更详细的调试信息。 ...

    uboot 移植全过程

    7. **引导加载程序烧录**:将编译好的UBoot二进制文件烧录到目标硬件的闪存中,通常是Nor Flash或Nand Flash。烧录工具如JTAG、OpenOCD、dfu-util等可以完成这个任务。 8. **启动与测试**:烧录完成后,可以通过...

    uboot 移植

    比如环境变量设置,串口和网络传输,NandFlash、NorFlash、SD卡操作,以及系统引导等。这些命令的使用,使得UBOOT不仅仅是一个简单的引导加载器,它还能帮助开发者完成系统调试和维护。例如,通过UBOOT的网络命令...

    uboot代码分析1

    U-Boot通常将环境变量存储在非易失性存储器如NAND、NOR、EEPROM或MMC中,以确保在系统重启后仍能保留这些设置。在启动过程中,U-Boot会将静态存储器中的环境变量读入RAM中,后续对环境变量的操作都是针对RAM中的副本...

    Uboot源码分析

    2. **NOR/NAND FLASH支持**:介绍了如何让U-Boot支持从NOR或NAND FLASH启动。 ### 结论 通过对U-Boot源码的分析,我们可以深入了解嵌入式系统的引导加载过程,以及如何定制和移植U-Boot以适应特定的硬件环境。这...

    uboot源代码分析及移植

    在FS2410板子上移植UBoot时,我们将实现从NOR Flash和NAND Flash启动,以及网络功能。移植过程通常涉及修改`board`目录下的源码,添加或修改驱动代码,调整配置文件,以确保UBoot能够识别和操作板上的硬件资源。 ...

Global site tag (gtag.js) - Google Analytics