2012-Linux->18(使U-BOOT能正确引导LINUX for 1_20 error,but...)->1

1、为了能使得U-BOOT正确引导linux内核。必须传递合适的参数给内核。

修改include/configs/zj2410.h如下:

……

……

/************************************************************

* RTC

************************************************************/

#define     CONFIG_RTC_S3C24X0      1

/* allow to overwrite serial and ethaddr */

#define CONFIG_ENV_OVERWRITE

#define CONFIG_BAUDRATE              115200

/************************************************************/

/* My Add */

/* enable passing of ATAGs    */

#define CONFIG_CMDLINE_TAG       1

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG    1

/***********************************************************

* Command definition

***********************************************************/

#define CONFIG_COMMANDS \

                      (CONFIG_CMD_DFL    | \

                      CFG_CMD_CACHE       | \

                      CFG_CMD_NAND        | \

                      /*CFG_CMD_EEPROM |*/ \

                      /*CFG_CMD_I2C|*/ \

                      /*CFG_CMD_USB |*/ \

                      CFG_CMD_REGINFO| \

                      CFG_CMD_DATE| \

                      CFG_CMD_ELF)

……

……

2、为了能稳定正确引导linux内核,得修改UBOOT2410CPU频率。

smdk2410的U-BOOT原来运行频率是202.8M,在这个频率我已开始能正确引导内核,但是后来突然就不能引导了,总是死在下面这个地方:

Uncompressing Linux....................................................... done, booting the kernel.

按照网上的说法,内核中,在\arch\arm\mach_s3c2410\s3c2410.c
      fclk = s3c2410_get_pll(MPLLCON, xtal);   //读出来的fclk结果和bootloader的频率不一致。

既然不能用202.8MVIVI200M能跑得好好的,那我把U-BOOT的频率改成200M2.6.20.3的内核和阳初光盘的2.4.18的内核都能正确稳定地引导了。

修改board/yangchu2410/smdk2410.c文件如下:

#define FCLK_SPEED 1

#if FCLK_SPEED==0   /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1   /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x5c   /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif

好了,编译烧写U-BOOTNAND FLASH,通过setenv设置bootargs

引导内核时就可以将bootargs传递给内核了。

注意:

1、对于U-BOOT而言,启动内核时候使用bootm命令才能传递内核参数,使用go命令是不传递内核参数的。

2、bootm命令引导的只能是用U-BOOTmkimage工具做过的内核映像,所以要引导阳初光盘带的内核映像,必须用其工具转换一下,至于这个工具怎么用,到U-BOOTtools目录下找这个工具去吧,./mkimage--help或者网上找找资料看下就知道了。^_^

转载于http://blog.chinaunix.net/u1/56388/showart_438727.html

Leo 发表于14:57:00 | 阅读全文 | 评论 0编辑 | 分享 0
  •                                     已经搭建好的嵌入式环境不小心被破坏了,破坏得还真彻底,需要重新从bootloader烧起,这不能不说是一件痛苦的事。同样的UBOOT,同样的内 核,也是同样的烧写工具,却碰到了不同的问题。难道这些问题是由唯一不同的时间产生的,没这么恐怖吧(呵呵),不过还好,折腾了一天还是把问题都解决了, 生怕下次还碰到类似的事,所以把碰到的问题和解决方法都记录下来:

    1.一个匪夷所思的问题
    把UBOOT烧到板子里,很顺利,其实也不应该出现问题,可是在UBOOT下用tftp时,问题来了,怎么也烧不进去,到loading:*这里就不动 了,反复好几次都这样,网上一查,没这样的问题,真是晕了。要不再烧一次UBOOT试试,学习中一直没耐心还是控制住了自己,又把UBOOT烧了一遍,这 次可更厉害了,在UBOOT中随便用什么命令,都出现:

    data abort                                                                    
    pc : [<33f85a18>]    lr : [<33f852fc>]                                        
    sp : 33f07f78  ip : 33f07f78  fp : 33f07f98                                   
    r10: 00000001  r9 : 33f94cfc  r8 : 33f3ffdc                                   
    r7 : 00000001  r6 : 33f4027f  r5 : 0000000e  r4 : 33f9901d                    
    r3 : 00000000  r2 : 33f9901d  r1 : 00000000  r0 : 33f9901d                    
    Flags: nzCv  IRQs off  FIQs off  Mode SVC_32                                  
    Resetting CPU ...

    这问题真让我无从下手啊,当然最本能的反映就是google,可是也没查到什么解决办法。真是个诡异的问题,正当想放弃的时候,突然想到:为什么这次会出 现不同的问题呢,如果我再烧一次呢,会怎么样?由于好奇,我还是忍着性子又烧了一次。没想到这次还真出现奇迹了,居然好了,所有命令都正常使用,tftp 也能用了,看到loading:######### 这信息真让我兴奋。不过前面的问题到底是怎么回事现在还不清楚,估计跟没有擦除nand有关,估计归估计,有时间好好研究下,呵呵。

    2.Nand write 出错拉!
    tftp能用了,内核通过bootm也能正常启动,现在该把zImage写入nand了,本来以为这一不步会很顺利,可是出错拉:

    NAND write: device 0 offset 196608, size 1048576 ... nand_write_page: Failed wrR
    NAND write: device 0 offset 196608, size 1048576 ... nand_write_page: Failed write verify, R

    其原因是:网上说是在write前没有擦除nand,不过我记得好象是擦除了,可问题还在,不过我erase nand的大小跟 write nand 的大小一样。后来让erase nand的大小大于 write nand的大小,在我板子上这样的:nand erase 0x30000 0x1d0000,nand write 0x31000000 0x3000 0x110000

    这样一改就好了,write ok..

    3.Bad Magic Number
    在内核自启动时,出现了Bad Magic Number错误,网上有这样的问题,可没看到有效的解决方法。其中有位仁兄说到:启动参数设置错误,0x33000000处不可以执行。有的开发板 sdram不是在0x33000000,所以不能把kernel uImage下载到0x33000000中运行。如我之前的bootcmd参数为:setenv bootcmd tftpboot 33000000 uImage\; bootm 33000000。但板子Omap5912的sdram地址在0x100000000,将参数改为setenv bootcmd tftpboot 10000000 uImage\; bootm 10000000后便可以启动kernel了。

    可我的板子的SDRAM是从0x30000000开始的啊,这解决方法不适合我的情况。睡觉前突然想到:自启动也是把0x30000(这个地址是我 nand存放内核的起始地址)加载到0x31000000处,然后运行,为什么不行呢?用tftp把内核直接在载到0x31000000怎么就可以呢,难 到是nand read时没有正确的把内核从nand加载到sdram,是起始地址(0x30000)不对吗?我试着把起始地址改成0x40000。这下还真准了,能正 常启动了。是不是在设置uboot环境变量时占用了内核在nand中的部分位置,即0x30000处,有这个可能,虽然不大确定,呵呵。

    网上有位兄弟总结了在嵌入式Linux启动过程中的一些问题,还不错,先搞过来,以后在参考,呵呵:

    1.Bad Magic Number

    ## Booting image at 33000000 ...

    Bad Magic Number

    OMAP5912 OSK # (tftp下载好kernel的uImage后就停止在这,不能启动kernel)

    问题原因:启动参数设置错误,0x30000000处不可以执行。

    有的开发板sdram不是在0x33000000,所以不能把kernel uImage下载到0x33000000中运行。如我之前的bootcmd参数为:setenv bootcmd tftpboot 33000000 uImage\; bootm 33000000。但板子Omap5912的sdram地址在0x100000000,将参数改为setenv bootcmd tftpboot 10000000 uImage\; bootm 10000000后便可以启动kernel了。

    2.启动停止在"Starting kernel ..."

    TFTP from server 192.168.167.170; our IP address is 192.168.167.15

    Filename 'uImage'

    Load address: 0x10000000

    Loading: ############

    ##############

    done

    Bytes transferred = 2025908 (1ee9b4 hex)

    ## Booting image at 10000000 ...

    Image Name:   Linux-2.6.18-mh8_pro500-versatil

    Image Type:   ARM Linux Kernel Image (uncompressed)

    Data Size:    2025844 Bytes =  1.9 MB

    Load Address: 30008000

    Entry Point:  30008000

    Verifying Checksum ... OK

    OK

    Starting kernel ...   (卡在这里)

    问题原因:多半是kernel没编译成功。

    确认configure参数是否配置正确,是否选择了正确的目标编译平台,如smdk2410等。

    3.不能启动kernel

    Starting kernel ...

    Uncompressing Linux.................

    .......... done, booting the kernel.

    问题原因:可能是Bootargs参数设置错误,确认bootargs设置是否正确。

    4.不能挂载nfs

    eth0: link up

    IP-Config: Complete:

    device=eth0, addr=192.168.167.15, mask=255.255.255.0, gw=192.168.167.254,

    host=192.168.167.15, domain=, nis-domain=(none),

    bootserver=192.168.167.170, rootserver=192.168.167.170, rootpath=

    Looking up port of RPC 100003/2 on 192.168.167.170

    Root-NFS: Unable to get nfsd port number from server, using default

    Looking up port of RPC 100005/1 on 192.168.167.170

    Root-NFS: Unable to get mountd port number from server, using default

    mount: server 192.168.167.170 not responding, timed out

    Root-NFS: Server returned error -5 while mounting /work/nfs/rootfs_bluetooth_omap

    VFS: Unable to mount root fs via NFS, trying floppy.

    VFS: Cannot open root device "nfs" or unknown-block(2,0)

    Please append a correct "root=" boot option

    Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)

    问题原因:这种情况通常是nfs配置问题。

    确认uboot的bootargs参数里和nfs相关的ip地址信息设置是否正确,以及Host机/etc/exports配置无误,重起nfs服务,重 新尝试连接。另外还需要注意bootargs内console和mem两个参数的设置。kernel2.6后console最好设置为 ttySAC0,mem也要根据开发板实际情况设置正确。

    5.文件系统不能启动问题

    eth0: link up

    IP-Config: Complete:

    device=eth0, addr=192.168.167.15, mask=255.255.255.0, gw=192.168.167.254,

    host=192.168.167.15, domain=, nis-domain=(none),

    bootserver=192.168.167.170, rootserver=192.168.167.170, rootpath=

    Looking up port of RPC 100003/2 on 192.168.167.170

    Looking up port of RPC 100005/1 on 192.168.167.170

    VFS: Mounted root (nfs filesystem).

    Freeing init memory: 128K

    /sbin/initKernel panic - not syncing: Attempted to kill init!

    问题原因:制作的文件系统缺少运行busybox所需的libcrypt.so库,新版本会有缺库提示,老版本(1.60)没有。

    注:运行一个busybox文件系统至少需要如下几个库:

    ld-linux.so.x

    libc.so.6

    libcrypt.so.x

    较新版本的busybox可能还需要

    libm.so.6

    libgcc_s.so.x

    (x为版本号)


    6.文件系统不能启动问题2

    eth0: link up

    IP-Config: Complete:

    device=eth0, addr=192.168.167.15, mask=255.255.255.0, gw=192.168.167.254,

    host=192.168.167.15, domain=, nis-domain=(none),

    bootserver=192.168.167.170, rootserver=192.168.167.170, rootpath=

    Looking up port of RPC 100003/2 on 192.168.167.170

    Looking up port of RPC 100005/1 on 192.168.167.170

    VFS: Mounted root (nfs filesystem).

    Freeing init memory: 128K

    Kernel panic - not syncing: No init found.  Try passing init= option to kernel.

    问题原因:对比一个可用的文件系统后发现,缺少了ld-linux.so.x库,文件系统里只有ld-linux.so.x的连接文件,少拷了库文件。


    8.不能获得帐户UID信息

    Could not get password database information for UID of current process: User "???" unknown or no memory to allocate password entry

    Unknown username "root" in message bus configuration file

    Could not get password database information for UID of current process: User "???" unknown or no memory to allocate password entry

    Failed to start message bus: Could not get UID and GID for username "root"

    问题原因:

    情况一:系统帐户验证出现问题.怀疑是调用getuid、getguid时并没有返回正确值,可能是缺少帐户验证相关库,实际排查后发现,缺少libnss_files库。拷贝交叉编译器的libnss_files库到文件系统后,启动文件系统成功。

    情况二:系统没有root帐号。可以由whoami命令看出。

    手动创建帐号。

    #vi /etc/passwd

    root:x:0:0:root:/root:/bin/sh

    kyo:x:500:500:kyo:/home/kyo:/bin/bash

    添加组

    #vi group

    root:x:0:root

    9.Freeing init memory: 128K

    init started: BusyBox v1.6.1 (2007-08-27 14:33:15 CST) multi-call binary

    starting pid 834, tty '': '/etc/init.d/rcS'

    Cannot run '/etc/init.d/rcS': No such file or directory

    Please press Enter to activate this console.

    发现没有/etc/init.d/rcS文件系统一样能正常启动。看来rcS只是用来设置一些随机启动的参数,对文件能否正常运行关系不大。

    注:这个不是错误,是偶然发现。

    原文链接: http://www.linuxdiyf.com/viewarticle.php?id=84579
    Leo 发表于14:50:00 | 阅读全文 | 评论 0编辑 | 分享 0
  • puts ("Erasing Nand...");

    //if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))

    if (nand_legacy_erase(nand_dev_desc+0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))

          return 1;

    puts ("Writing to Nand... ");

    total = CFG_ENV_SIZE;

    //ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

    nand_legacy_rw(nand_dev_desc+0, 0x00 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total,(u_char*)env_ptr);

    if (ret || total != CFG_ENV_SIZE)

          return 1;

    puts ("done\n");

    return ret;

    }

    #endif /* CFG_ENV_OFFSET_REDUND */

    #endif /* CMD_SAVEENV */

    #ifdef CFG_ENV_OFFSET_REDUND

    void env_relocate_spec (void)

    {

    #if !defined(ENV_IS_EMBEDDED)

    ulong total;

    int crc1_ok = 0, crc2_ok = 0;

    env_t *tmp_env1, *tmp_env2;

    total = CFG_ENV_SIZE;

    tmp_env1 = (env_t *) malloc(CFG_ENV_SIZE);

    tmp_env2 = (env_t *) malloc(CFG_ENV_SIZE);

    nand_read(&nand_info[0], CFG_ENV_OFFSET, &total,

          (u_char*) tmp_env1);

    nand_read(&nand_info[0], CFG_ENV_OFFSET_REDUND, &total,

          (u_char*) tmp_env2);

    crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);

    crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);

    if(!crc1_ok && !crc2_ok)

          return use_default();

    else if(crc1_ok && !crc2_ok)

          gd->env_valid = 1;

    else if(!crc1_ok && crc2_ok)

          gd->env_valid = 2;

    else {

          /* both ok - check serial */

          if(tmp_env1->flags == 255 && tmp_env2->flags == 0)

              gd->env_valid = 2;

          else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)

              gd->env_valid = 1;

          else if(tmp_env1->flags > tmp_env2->flags)

              gd->env_valid = 1;

          else if(tmp_env2->flags > tmp_env1->flags)

              gd->env_valid = 2;

         else /* flags are equal - almost impossible */

              gd->env_valid = 1;

    }

    free(env_ptr);

    if(gd->env_valid == 1) {

          env_ptr = tmp_env1;

          free(tmp_env2);

    } else {

          env_ptr = tmp_env2;

          free(tmp_env1);

    }

    #endif /* ! ENV_IS_EMBEDDED */

    }

    #else /* ! CFG_ENV_OFFSET_REDUND */

    /*

    * The legacy NAND code saved the environment in the first NAND device i.e.,

    * nand_dev_desc + 0. This is also the behaviour using the new NAND code.

    */

    void env_relocate_spec (void)

    {

    #if !defined(ENV_IS_EMBEDDED)

    ulong total;

    int ret;

    total = CFG_ENV_SIZE;

    //ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

    ret=nand_legacy_rw(nand_dev_desc+0, 0x01 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);

        if (ret || total != CFG_ENV_SIZE)

          return use_default();

    if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)

          return use_default();

    #endif /* ! ENV_IS_EMBEDDED */

    }

    #endif /* CFG_ENV_OFFSET_REDUND */

    #if !defined(ENV_IS_EMBEDDED)

    static void use_default()

    {

    puts ("*** Warning - bad CRC or NAND, using default environment\n\n");

    if (default_environment_size > CFG_ENV_SIZE){

          puts ("*** Error - default environment is too large\n\n");

          return;

    }

    memset (env_ptr, 0, sizeof(env_t));

    memcpy (env_ptr->data,

              default_environment,

              default_environment_size);

    env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);

    gd->env_valid = 1;

    }

    #endif

    #endif /* CFG_ENV_IS_IN_NAND */


    原文:http://blog.chinaunix.net/u1/56388/showart_438720.html
    Leo 发表于07:02:00 | 阅读全文 | 评论 0编辑 | 分享 0
  • /* this is called before nand_init()

    * so we can't read Nand to validate env data.

    * Mark it OK for now. env_relocate() in env_common.c

    * will call our relocate function which will does

    * the real validation.

    *

    * When using a NAND boot image (like sequoia_nand), the environment

    * can be embedded or attached to the U-Boot image in NAND flash. This way

    * the SPL loads not only the U-Boot image from NAND but also the

    * environment.

    */

    int env_init(void)

    {

    #if defined(ENV_IS_EMBEDDED)

    ulong total;

    int crc1_ok = 0, crc2_ok = 0;

    env_t *tmp_env1, *tmp_env2;

    total = CFG_ENV_SIZE;

    tmp_env1 = env_ptr;

    tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);

    crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);

    crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);

    if (!crc1_ok && !crc2_ok)

          gd->env_valid = 0;

    else if(crc1_ok && !crc2_ok)

          gd->env_valid = 1;

    else if(!crc1_ok && crc2_ok)

          gd->env_valid = 2;

    else {

          /* both ok - check serial */

          if(tmp_env1->flags == 255 && tmp_env2->flags == 0)

              gd->env_valid = 2;

          else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)

              gd->env_valid = 1;

          else if(tmp_env1->flags > tmp_env2->flags)

              gd->env_valid = 1;

          else if(tmp_env2->flags > tmp_env1->flags)

              gd->env_valid = 2;

          else /* flags are equal - almost impossible */

              gd->env_valid = 1;

    }

    if (gd->env_valid == 1)

          env_ptr = tmp_env1;

    else if (gd->env_valid == 2)

          env_ptr = tmp_env2;

    #else /* ENV_IS_EMBEDDED */

    gd->env_addr= (ulong)&default_environment[0];

    gd->env_valid = 1;

    #endif /* ENV_IS_EMBEDDED */

    return (0);

    }

    #ifdef CMD_SAVEENV

    /*

    * The legacy NAND code saved the environment in the first NAND device i.e.,

    * nand_dev_desc + 0. This is also the behaviour using the new NAND code.

    */

    #ifdef CFG_ENV_OFFSET_REDUND

    int saveenv(void)

    {

    ulong total;

    int ret = 0;

    env_ptr->flags++;

    total = CFG_ENV_SIZE;

    if(gd->env_valid == 1) {

          puts ("Erasing redundant Nand...");

          if (nand_erase(&nand_info[0],

                      CFG_ENV_OFFSET_REDUND, CFG_ENV_SIZE))

              return 1;

          puts ("Writing to redundant Nand... ");

          ret = nand_write(&nand_info[0], CFG_ENV_OFFSET_REDUND, &total,

                   (u_char*) env_ptr);

    } else {

          puts ("Erasing Nand...");

          if (nand_erase(&nand_info[0],

                      CFG_ENV_OFFSET, CFG_ENV_SIZE))

              return 1;

          puts ("Writing to Nand... ");

          ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total,

                   (u_char*) env_ptr);

    }

    if (ret || total != CFG_ENV_SIZE)

          return 1;

    puts ("done\n");

    gd->env_valid = (gd->env_valid == 2 ? 1 : 2);

    return ret;

    }

    #else /* ! CFG_ENV_OFFSET_REDUND */

    int saveenv(void)

    {

    ulong total;

    int ret = 0;



    原文:http://blog.chinaunix.net/u1/56388/showart_438720.html
    Leo 发表于07:01:00 | 阅读全文 | 评论 0编辑 | 分享 0
  • 1、因为定义了CFG_NAND_LEGACY,因此主要修改saveenv中对nand的读写函数为nand_legacy的读写函数,修改common/env_nand.c如下:

    #include <common.h>

    #if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */

    #include <command.h>

    #include <environment.h>

    #include <linux/stddef.h>

    #include <malloc.h>

    #include <nand.h>

    #if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_NAND)) == (CFG_CMD_ENV|CFG_CMD_NAND))

    #define CMD_SAVEENV

    #elif defined(CFG_ENV_OFFSET_REDUND)

    #error Cannot use CFG_ENV_OFFSET_REDUND without CFG_CMD_ENV & CFG_CMD_NAND

    #endif

    #if defined(CFG_ENV_SIZE_REDUND) && (CFG_ENV_SIZE_REDUND != CFG_ENV_SIZE)

    #error CFG_ENV_SIZE_REDUND should be the same as CFG_ENV_SIZE

    #endif

    #ifdef CONFIG_INFERNO

    #error CONFIG_INFERNO not supported yet

    #endif

    /*My Add*/

    int nand_legacy_erase(struct nand_chip* nand,

    size_t ofs, size_t len, int clean);

    int nand_legacy_rw (struct nand_chip* nand, int cmd,

         size_t start, size_t len,

         size_t * retlen, u_char * buf);

    /*My Add*/

    extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];

    /* info for NAND chips, defined in drivers/nand/nand.c */

    //extern nand_info_t nand_info[];

    nand_info_t nand_info[CFG_MAX_NAND_DEVICE];

    /* references to names in env_common.c */

    extern uchar default_environment[];

    extern int default_environment_size;

    char * env_name_spec = "NAND";

    #ifdef ENV_IS_EMBEDDED

    extern uchar environment[];

    env_t *env_ptr = (env_t *)(&environment[0]);

    #else /* ! ENV_IS_EMBEDDED */

    env_t *env_ptr = 0;

    #endif /* ENV_IS_EMBEDDED */

    /* local functions */

    #if !defined(ENV_IS_EMBEDDED)

    static void use_default(void);

    #endif

    DECLARE_GLOBAL_DATA_PTR;

    uchar env_get_char_spec (int index)

    {

    return ( *((uchar *)(gd->env_addr + index)) );

    }


    原文:http://blog.chinaunix.net/u1/56388/showart_438720.html
    Leo 发表于23:59:00 | 阅读全文 | 评论 0编辑 | 分享 0
  • 在u-boot-1.1.6移植(二)http://blog.chinaunix.net/u2/74310/showart.php?id=1091929中 提到:u-boot 运行至第二阶段进入 start_armboot()函数。其中 nand_init()函数是对 nand flash 的最初初始化函数。其调用与 CFG_NAND_LEGACY 宏有关,如果没定义 CFG_NAND_LEGACY 这个宏,就按照start_armboot()调用 drivers/nand/nand.c 中的 nand_init 函数(该函数在 1.1.6 已经被实现), 但还有个 board_nand_init()函数没实现,需自己添加;如果定义了CFG_NAND_LEGACY,就不使用默认的 nand_init,而调用自己写的 nand_init 函数了。u-boot-1.1.6中对NAND flash的支持有新旧两套代码,新代码在drivers/nand目录下,旧代码在drivers/nand_legacy目录下,文档doc /README.nand对这两套代码有所说明:使用旧代码需要定义更多的宏,u-boot-1.1.6移植(二)中可以看到,比较复杂,而新代码移植自 Linux 2.6.12,它更加智能,可以自动识别更多型号的NAND flash。本文使用新代码并移植在优龙FS2410成功。
         NAND flash 的支持以及下篇《u-boot烧写yaffs文件系统映象》参考《嵌入式Linux应用开发完全手册》,实验时得到该书作者南方兄的热情帮助,在 此感谢!
    移植过程:
    一、代码搬运
         u-boot启动时,需要 copy u-boot to ram 的过程,通过自己定义的 nand_read.c实现,该步骤与u-boot-1.1.6移植(一)同,参考http://blog.chinaunix.net/u2/74310/showart.php?id=1091899,需要注意的是增加对nand flash支持后编译出来的bin文件将大于128KB,所以修改start.S即可:
    @ copy UBOOT to RAM
         ldr     r0, _TEXT_BASE
         mov      r1, #0x0
         mov     r2, #0x20000 //改为mov r2,#0x40000,这是FS2410分配给u-boot的存储空间
         bl     nand_read_ll
    二、修改配置文件 include/configs/fs2410.h 使支持NAND

        /***********************************************************
    * Command definition
    ***********************************************************/
    #define CONFIG_COMMANDS \
                   (CONFIG_CMD_DFL      | \
                   CFG_CMD_CACHE      | \
                   CFG_CMD_ENV           | \
                   CFG_CMD_NET           | \
                   CFG_CMD_PING      | \
                   CFG_CMD_NAND      | \
                   /*CFG_CMD_EEPROM |*/ \
                   /*CFG_CMD_I2C      |*/ \
                   /*CFG_CMD_USB      |*/ \
                   CFG_CMD_REGINFO  | \
                   CFG_CMD_DATE      | \
                   CFG_CMD_ELF)

    #define CFG_NAND_BASE          0x4E000000
    #define CFG_MAX_NAND_DEVICE     1     /* Max number of NAND devices          */
    #define NAND_MAX_CHIPS          1

    /*保存环境变量用到的宏,否则不能 saveenv */
    #define CFG_ENV_IS_IN_NAND     1
    #define CFG_NAND_BASE          0x4E000000
    #define CMD_SAVEENV
    #define CFG_ENV_SIZE             0x10000 /* Total Size of Environment Sector */
    #define CFG_ENV_OFFSET       0x30000 /*环境变量在NAND FLASH的0x30000处*/

    /*修改默认配置参数以方便使用*/
    #define CONFIG_BOOTDELAY     3
    #define CONFIG_BOOTARGS          "noinitrd root=/dev/mtdblock2 init=/linuxrc devfs=mount console=ttySAC0,115200"
    #define CONFIG_ETHADDR     08:00:3e:26:0a:5b
    #define CONFIG_NETMASK           255.255.255.0
    #define CONFIG_IPADDR          192.168.1.100
    #define CONFIG_SERVERIP          192.168.1.2
    /*#define CONFIG_BOOTFILE     "elinos-lart" */
    #define CONFIG_BOOTCOMMAND     "nand read 0x30007fc0 0x40000 0x1c0000; bootm 0x30007fc0"
    三、建立cpu/arm920t/s3c24x0/nand_flash.c,实现board_nand_init函数
         《嵌入式Linux应用开发完全手册》 中介召的 nand_flash.c包含对S3C2440 的支持,在这里一并列出,供日后参考。

    (1)针对S3C2410、S3C2440 NAND Flash控制器的不同来定义一些数据结构和函数,在include/s3c24x0.h 文件中增加S3C2440_NAND数据结构。

    /* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */
    typedef struct {
         S3C24X0_REG32     NFCONF;
         S3C24X0_REG32     NFCONT;
         S3C24X0_REG32     NFCMD;
         S3C24X0_REG32     NFADDR;
         S3C24X0_REG32     NFDATA;
         S3C24X0_REG32     NFMECCD0;
         S3C24X0_REG32     NFMECCD1;
         S3C24X0_REG32     NFSECCD;
         S3C24X0_REG32     NFSTAT;
         S3C24X0_REG32     NFESTAT0;
         S3C24X0_REG32     NFESTAT1;
         S3C24X0_REG32     NFMECC0;
         S3C24X0_REG32     NFMECC1;
         S3C24X0_REG32     NFSECC;
         S3C24X0_REG32     NFSBLK;
         S3C24X0_REG32     NFEBLK;
    } /*__attribute__((__packed__))*/ S3C2440_NAND;

    (2)在 include/s3c2410.h 文件中仿照 S3C2410_GetBase_NAND函数定义S3C2440_GetBase_NAND函数。

    /* for s3c2440, www.100ask.net */
    static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)
    {
         return (S3C2440_NAND * const)S3C2410_NAND_BASE;
    }

    (3) cpu/arm920t/s3c24x0/nand_flash.c

    /*
    * Nand flash interface of s3c2410/s3c2440, by www.100ask.net
    * Changed from drivers/mtd/nand/s3c2410.c of kernel 2.6.13
    */

    #include <common.h>

    #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
    #include <s3c2410.h>
    #include <nand.h>

    DECLARE_GLOBAL_DATA_PTR;

    #define S3C2410_NFSTAT_READY     (1<<0)
    #define S3C2410_NFCONF_nFCE      (1<<11)

    #define S3C2440_NFSTAT_READY     (1<<0)
    #define S3C2440_NFCONT_nFCE      (1<<1)


    /* select chip, for s3c2410 */
    static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
    {
         S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

         if (chip == -1) {
             s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;
         } else {
             s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;
         }
    }

    /* command and control functions, for s3c2410
    *
    * Note, these all use tglx's method of changing the IO_ADDR_W field
    * to make the code simpler, and use the nand layer's code to issue the
    * command and address sequences via the proper IO ports.
    *
    */
    static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
    {
         S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
         struct nand_chip *chip = mtd->priv;

         switch (cmd) {
         case NAND_CTL_SETNCE:
         case NAND_CTL_CLRNCE:
             printf("%s: called for NCE\n", __FUNCTION__);
             break;

         case NAND_CTL_SETCLE:
             chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;
             break;

         case NAND_CTL_SETALE:
             chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;
             break;

             /* NAND_CTL_CLRCLE: */
             /* NAND_CTL_CLRALE: */
         default:
             chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
             break;
         }
    }

    /* s3c2410_nand_devready()
    *
    * returns 0 if the nand is busy, 1 if it is ready
    */
    static int s3c2410_nand_devready(struct mtd_info *mtd)
    {
         S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

         return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);
    }


    /* select chip, for s3c2440 */
    static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
    {
         S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

         if (chip == -1) {
             s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;
         } else {
             s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;
         }
    }

    /* command and control functions */
    static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
    {
         S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
         struct nand_chip *chip = mtd->priv;

         switch (cmd) {
         case NAND_CTL_SETNCE:
         case NAND_CTL_CLRNCE:
             printf("%s: called for NCE\n", __FUNCTION__);
             break;

         case NAND_CTL_SETCLE:
             chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;
             break;

         case NAND_CTL_SETALE:
             chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;
             break;

             /* NAND_CTL_CLRCLE: */
             /* NAND_CTL_CLRALE: */
         default:
             chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
             break;
         }
    }

    /* s3c2440_nand_devready()
    *
    * returns 0 if the nand is busy, 1 if it is ready
    */
    static int s3c2440_nand_devready(struct mtd_info *mtd)
    {
         S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

         return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);
    }

    /*
    * Nand flash hardware initialization:
    * Set the timing, enable NAND flash controller
    */
    static void s3c24x0_nand_inithw(void)
    {
         S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
         S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

    #define TACLS    0
    #define TWRPH0  4
    #define TWRPH1  2

         if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
         {
             /* Enable NAND flash controller, Initialize ECC, enable chip select, Set flash memory timing */
             s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
         }
         else
         {
             /* Set flash memory timing */
             s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
             /* Initialize ECC, enable chip select, NAND flash controller enable */
             s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);
         }
    }

    /*
    * Called by drivers/nand/nand.c, initialize the interface of nand flash
    */
    void board_nand_init(struct nand_chip *chip)
    {
         S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
         S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

         s3c24x0_nand_inithw();

         if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410) {
             chip->IO_ADDR_R     = (void *)&s3c2410nand->NFDATA;
             chip->IO_ADDR_W     = (void *)&s3c2410nand->NFDATA;
             chip->hwcontrol     = s3c2410_nand_hwcontrol;
             chip->dev_ready     = s3c2410_nand_devready;
             chip->select_chip  = s3c2410_nand_select_chip;
             chip->options       = 0;
         } else {
             chip->IO_ADDR_R     = (void *)&s3c2440nand->NFDATA;
             chip->IO_ADDR_W     = (void *)&s3c2440nand->NFDATA;
             chip->hwcontrol     = s3c2440_nand_hwcontrol;
             chip->dev_ready     = s3c2440_nand_devready;
             chip->select_chip  = s3c2440_nand_select_chip;
             chip->options       = 0;
         }

         chip->eccmode        = NAND_ECC_SOFT;
    }

    #endif

    四、将nand_flash.c编入 u-boot,修改 cpu/arm920t/s3c24x0/Makefile文件

    COBJS     = i2c.o interrupts.o serial.o speed.o \
           usb_ohci.o nand_flash.o

    至此,编译生成 u-boot.bin 并烧入NAND Flash,启动,便可以引导内核了。


    原文链接:http://blog.chinaunix.net/u2/74310/showart.php?id=1135068
    Leo 发表于23:57:00 | 阅读全文 | 评论 0编辑 | 分享 0
  • 首先引用《嵌入式系统 Boot Loader 技术内幕》的一段话:Boot Loader 的设计与实现是一个非常复杂的过程。如果不能从串口收到那激动人心的"uncompressing linux.................. done, booting the kernel……"内核启动信息,恐怕谁也不能说:"嗨,我的 boot loader 已经成功地转起来了!" 我对此深有体会,这就是为什么这篇文章推迟一个星期才出来的原因。

    u-boot实现linux内核引导步骤:

    1、U-BOOT给linux内核传递合适参数的定义

    修改include/configs/fs2410.h如下:

    ……

    ……

    /************************************************************

    * RTC

    ************************************************************/

    #define        CONFIG_RTC_S3C24X0    1

    /* allow to overwrite serial and ethaddr */

    #define CONFIG_ENV_OVERWRITE

    #define CONFIG_BAUDRATE         115200

    /************************************************************/

    /* enable passing of ATAGs        */

    #define CONFIG_CMDLINE_TAG  1

    #define CONFIG_SETUP_MEMORY_TAGS 1

    #define CONFIG_INITRD_TAG        1

    /***********************************************************

    * Command definition

    ***********************************************************/

    #define CONFIG_COMMANDS \

                          (CONFIG_CMD_DFL     | \

                          CFG_CMD_CACHE      | \

                          CFG_CMD_NAND | \

                          /*CFG_CMD_EEPROM |*/ \

                          /*CFG_CMD_I2C     |*/ \

                          /*CFG_CMD_USB  |*/ \

                          CFG_CMD_REGINFO  | \

                          CFG_CMD_DATE  | \

                          CFG_CMD_ELF)

    ……

    ……

    2、修改UBOOT的2410CPU频率

    smdk2410的U-BOOT原来运行频率是 202.8M,而FS2410的BIOS里面是200M,所以不修改频率可能会出点问题。按照网上的说法,内核中,在\arch\arm \mach_s3c2410\s3c2410.c 中,fclk = s3c2410_get_pll(MPLLCON, xtal);   //读出来的fclk结果和bootloader的频率不一致。

    修改board/fs2410/fs2410.c文件如下:

    #define FCLK_SPEED 1

    #if FCLK_SPEED==0   /* Fout = 203MHz, Fin = 12MHz for Audio */

    #define M_MDIV 0xC3

    #define M_PDIV 0x4

    #define M_SDIV 0x1

    #elif FCLK_SPEED==1   /* Fout = 202.8MHz */

    //#define M_MDIV 0xA1

    //#define M_PDIV 0x3

    //#define M_SDIV 0x1

    #define M_MDIV 0x5c   /* Fout = 200MHz */

    #define M_PDIV 0x4

    #define M_SDIV 0x0

    #endif

    3、修改include/configs/fs2410.h中的CFG_LOAD_ADDR的地址为0x30007FC0

    这是内核的加载地址,board/smdk2410/config.mk文件注释中提到Linux内核希望自己被加载到0x30008000的内存地址,而由于uImage会在kernel镜像之前加上大小为0x40的头文件消息,所以需要减去0x40。

    4、制作uImage

    在编译内核的时候如果用命令make uImage来生成uImage的话,我发现Load Address 30008000,  Entry Point  30008000,为什么这样我没细研究,所以我用mkimage来生成uImage,做法如下:

    [root@localhost tftpboot]#mkimage -n 'linux-2.6.25' -A arm -O linux -T kernel -C none -a 0x30007fc0 -e 0x30008000 -d zImage uImage

    Image Name    linux-2.6.25

    Created       Thu Jul 3 101845 2008

    Image Type    ARM Linux Kernel Image (uncompressed)

    Data Size     1556188 Bytes =1556252 kB = 1.5 MB

    Load Address 0x30007fc0

    Entry Point  0x30008000

    这里解释一下参数的意义:

             -A == set architecture to 'arch'

             -O == set operating system to 'os'

             -T == set image type to 'type'

             -C == set compression type 'comp'

             -a == set load address to 'addr' (hex)

             -e == set entry point to 'ep' (hex)

             -n == set image name to 'name'

             -d == use image data from 'datafile'

             -x == set XIP (execute in place)

    这里我移植的是2.6.25内核,当然也可以:Load Address 0x30008000 、Entry Point  0x30008040

    5、固化

            make修改好的u-boot,将u-boot.bin和uImage写入flash相应位置,然后设置u-boot启动命令:

    [FS2410]#setenv bootargs root=1f02 init=/linuxrc console=ttySAC0,115200 devfs=mount

    [FS2410]#setenv bootcmd nand read 0x30007fc0 0x40000 0x1c0000\;bootm 0x30007fc0

    [FS2410]#saveenv

    Saving Environment to NAND...

    Erasing Nand...Writing to Nand... done

    好了,可以通过printenv、bdinfo等命令查看自己的u-boot参数了,最后reset一下,如果运气好点的话,就会看到那激动人心的

    Uncompressing Linux....................................................... done, booting the kernel.

    之后就是一阵洋文飘过……

    后记:

    s3c2410上移植uboot和linux2.6内核.虽然网上的文章多多,但真正要在自己的板子上跑起来还真是问题多。其间参考了不少网上同行们的文章,受益匪浅。最后我还将调制过程中遇到的问题总结列出,供后人参考。

    问题一:Load Address  、Entry Point 设置问题
    Starting kernel ...
    undefined instruction
    pc : [<c30008028>] lr : [<c0f91b14>]
    sp : 33f4fc10 ip : 00000001 fp : 33f4fca4
    r10: 33f9e70c r9 : 33ece9cd r8 : 33f4ffdcc
    r7 : 33f4ffb8 r6 : 00000000 r5 : 00000000 r4 : 00000000
    r3 : 30008000 r2 : c0000100 r1 : 000000c1 r0 : 00000000
    Flags: nZCv IRQs off FIQs off Mode SVC_32
    Resetting CPU ...

    引导内核在这里进不去,网上也没一个很好的说法,由上图可知:Load Address 0x30008000 、Entry Point  0x30008000 ,#bootm的时候,显示是的内核前头加上的64byte的信息r1:000000c1 r0:00000000……按照上述制作uImage的方法设Load Address  、Entry Point 就ok。

    /************下面引用了网上文章的原话********************************************************/

    u-boot 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START + 0x8000 地址处。在跳转时,要满足下列条件:

    a) CPU 寄存器的设置: R0 = 0 ; R1 =机器类型 ID ,本系统的机器类型 ID = 193 。 R2 =启动参数标记列表在 RAM 中的起始基地址;

    b) CPU 模式:必须禁止中断 (IRQs 和 FIQs) ; CPU 必须工作在 SVC 模式;

    c) Cache 和 MMU 的设置: MMU 必须关闭;指令 Cache 可以打开也可以关闭;数据 Cache 必须关闭。

    系统采用下列代码来进入内核函数:

    theKernel = (void (*)(int, int))ntohl(hdr->ih_ep);

    theKernel(0, bd->bi_arch_number); 其中, hdr 是 image_header_t 类型的结构体, hdr->ih_ep 指向内核的第一条指令地址,即 Linux 操作系统下的 /kernel/arch/arm/boot/compressed/head.S 汇编程序。 theKernel() 函数调用应该不会返回,如果该调用返回,则说明出错。

    //theKernel(0, bd->bi_arch_number); 应该是:
           theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

    问题二:Starting kernel ...就没显示了.

    郁闷吧,解决了第一个问题,又来了这个问题,什么都没显示了,错在哪呢?

    theKernel (0, bd->bi_arch_number, bd->bi_boot_params);没有给内核正确传递参数?经过setenv修改启动参数、修改bi_arch_number的机器ID 号,都未果,结果发现,优龙的linux-2.6.8.1-pxt1不能引导,我交叉编译Linux-2.6.25,制作uImage,结果正常启动,至 于为什么linux-2.6.8.1-pxt1不能引导,我没做深入分析。

    问题三:Uncompressing Linux....................................................... done, booting the kernel    就不动了

    我没有遇到,摘用网上解法:一般这个错误有两种原因:
    一个内核的commandline ,一个是由于主频设置的问题
    1. 通过go启动内核的话参数用的是编译时的..而bootm则是启动的经过处理的uImage(加了一个头)
    所以用bootm就会把uboot设置的commandline传给内核..如果是用bootm启动出现bootint the 
    kernel没显示了.则应该好好检查一下.可以printenv打印看uboot有没设置对commandline

    2.主频问题,就是在MPLLCON这个寄存器的配置上。(board/s3c2410/s3c2410.c)
    在VIVI:MPLLCON = 0x0005c040;计算出来的Mpll = 200Mhz
    Uboot116:MPLLCON = 0x000a1031;计算出来的Mpll = 202Mhz
    那么,及有可能就是内核已经启动,而波特率不对,使打印出问题
    把MPLLCON改成 = 0x0005c040就有显示了.

    问题四:Error: unrecognized/unsupported machine ID (r1 = 0x33f4fca8)

    分析:

    tftp uImage到0x30008000,然后,go 0x30008000,这样uboot没有传参数给内核,go命令是不传递内核参数的所以会有Error: unrecognized/unsupported machine ID (r1 = 0x33f4fca8)这样的错误
    一种方法是修改common/cmd_boot.c
    /*#if defined(CONFIG_I386)*/           
      DECLARE_GLOBAL_DATA_PTR;         
    /*#endif*/                                         
    #if !defined(CONFIG_NIOS)
           /*******************add here*******************************/     
    if(argc==2)
             rc = ((ulong (*)(int, char *[]))addr) (0, gd->bd->bi_arch_number);
      else       
    /*********************add end *****************************/   
               rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]);
    解决
    还可以在arch/arm/kernel/head.S写死r1
    mov     r1, #0xc1

    个人建议不修改,用bootm命令。

    至此,u-boot-1.1.6 移植完毕,感谢收看!

    原文链接:http://blog.chinaunix.net/u2/74310/showart.php?id=1091939

    Leo 发表于23:53:00 | 阅读全文 | 评论 0编辑 | 分享 0
  • 本文实现u-boot的写操作,实验过程 中,参考了网上资料,列举如下:     
         《uboot1.1.4移植》网址:
         http://hi.baidu.com/edaworld/blog/item/c40f83a8a2e6d1b5cb130cca.html
         《uboot for s3c2410 nandboot 使用saveenv保存环境变量》网址:
         http://blog.chinaunix.net/u1/56388/showart_438720.html
         《基于smdk2410 开发板u-boot-1.2.0 对 nand flash的支持》PDF文档。

    涉及文件:
    common/env_nand.c
    Driver/nand_legacy/ nand_legacy.c
    Include/configs/fs2410.h

    具体修改分析:
    Lib_arm/board.c
    u-boot 运行至第二阶段进入 start_armboot()函数。其中 nand_init()函数是对 nand flash 的最初初始化函数。其调用与 CFG_NAND_LEGACY 宏有关,如果没定义 CFG_NAND_LEGACY 这个宏,就按照start_armboot()调用 drivers/nand/nand.c 中的 nand_init 函数(该函数在 1.1.6 已经被实现), 但还有个 board_nand_init()函数没实现,需自己添加。如果定义了CFG_NAND_LEGACY,就不使用默认的 nand_init,而调用自己写的 nand_init 函数了,这里我们选择第二种方式。

    具体步骤如下:
    1. 加入 NAND 闪存芯片型号
    在/include/linux/mtd/ nand_ids.h 中对如下结构体赋值进行修改:
    static struct nand_flash_dev nand_flash_ids[]= {
    ......
    {"Samsung K9F1208U0M",     NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0},     /*2008-6-25*/
    ......
                                                }
    这样对于该款 NAND 闪存芯片的操作才能正确执行。

    2.  编写 NAND 闪存初始化函数
    在/drivers/nand_legacy/nand_legacy.c 中加入 nand_init()函数。
    /*08-6-25 START*/
    /*-----------------------------------------------------------------------
    * NAND flash basic functions
    * Added by wei jing 2008.6.25
    * Copied from board/mpl/vcma9/vcma9.h & vcma9.c
    */
    #if (CONFIG_COMMANDS & CFG_CMD_NAND)
    #include <s3c2410.h>


    /*----------------------------------------------------------------------*/

    typedef enum {
         NFCE_LOW,
         NFCE_HIGH
    } NFCE_STATE;

    static inline void NF_Conf(u16 conf)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         nand->NFCONF = conf;
    }

    static inline void NF_Cmd(u8 cmd)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         nand->NFCMD = cmd;
    }

    static inline void NF_CmdW(u8 cmd)
    {
         NF_Cmd(cmd);
         udelay(1);
    }

    static inline void NF_Addr(u8 addr)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         nand->NFADDR = addr;
    }

    static inline void NF_SetCE(NFCE_STATE s)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         switch (s) {
              case NFCE_LOW:
                   nand->NFCONF &= ~(1<<11);
                   break;

              case NFCE_HIGH:
                   nand->NFCONF |= (1<<11);
                   break;
         }
    }

    static inline void NF_WaitRB(void)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         while (!(nand->NFSTAT & (1<<0)));
    }

    static inline void NF_Write(u8 data)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         nand->NFDATA = data;
    }

    static inline u8 NF_Read(void)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         return(nand->NFDATA);
    }

    static inline void NF_Init_ECC(void)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         nand->NFCONF |= (1<<12);
    }

    static inline u32 NF_Read_ECC(void)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         return(nand->NFECC);
    }

    extern ulong
    nand_probe(ulong physadr);


    static inline void NF_Reset(void)
    {
         int i;

         NF_SetCE(NFCE_LOW);
         NF_Cmd(0xFF);          /* reset command */
         for(i = 0; i < 10; i++);     /* tWB = 100ns. */
         NF_WaitRB();          /* wait 200~500us; */
         NF_SetCE(NFCE_HIGH);
    }


    static inline void NF_Init(void)
    {
    #if 0 /* a little bit too optimistic */
    #define TACLS    0
    #define TWRPH0  3
    #define TWRPH1  0
    #else
    #define TACLS    0
    #define TWRPH0  4
    #define TWRPH1  2
    #endif

         NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));
         /*nand->NFCONF = (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); */
         /* 1  1     1      1,    1       xxx,  r xxx,    r xxx */
         /* En 512B 4step ECCR nFCE=H tACLS    tWRPH0    tWRPH1 */

         NF_Reset();
    }

    void
    nand_init(void)
    {
         S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

         NF_Init();
    #ifdef DEBUG
         printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);
    #endif
         printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);
    }

    #endif /* CONFIG_COMMANDS & CFG_CMD_NAND */

    /*08-6-25 END*****************************************************/

    /*
    * Exported variables etc.
    */
    可 以看到 nand_init()调用 NF_Init()函数,使能 nand flash 控制器和 nand flash;调用 NF_Reset()函数置位,NF_WaitRB()查询 nand flash 的状态,最后在调用 nand_probe((ulong)nand)函数探测 nand flash.

    3. 修改include/configs/fs2410.h,在上次修改的基础上加上如下代码,定义 NAND 闪存命令层的底
    接口函数等:

    #define CFG_NAND_LEGACY          1
    //#define NFCE_LOW         0
    //#define NFCE_HIGH        1
    #define CFG_ENV_IS_IN_NAND     1
    #define CFG_NAND_BASE          0x4E000000
    #define CMD_SAVEENV
    #define CFG_ENV_SIZE             0x10000 /* Total Size of Environment Sector */
    #define CFG_ENV_OFFSET       0x20000 /*环境变量在NAND FLASH的0x20000处*/
    #define CFG_MONITOR_BASE PHYS_SDRAM_1
    /*-----------------------------------------------------------------------
    * NAND flash settings
    */
    #if (CONFIG_COMMANDS & CFG_CMD_NAND)

    #define CFG_NAND_LEGACY
    #define CFG_MAX_NAND_DEVICE     1     /* Max number of NAND devices          */
    #define SECTORSIZE 512

    #define ADDR_COLUMN 1
    #define ADDR_PAGE 2
    #define ADDR_COLUMN_PAGE 3

    #define NAND_ChipID_UNKNOWN      0x00
    #define NAND_MAX_FLOORS 1
    #define NAND_MAX_CHIPS 1

    #define NAND_WAIT_READY(nand)     NF_WaitRB()

    #define NAND_DISABLE_CE(nand)     NF_SetCE(NFCE_HIGH)
    #define NAND_ENABLE_CE(nand)     NF_SetCE(NFCE_LOW)


    #define WRITE_NAND_COMMAND(d, adr)     NF_Cmd(d)
    #define WRITE_NAND_COMMANDW(d, adr)     NF_CmdW(d)
    #define WRITE_NAND_ADDRESS(d, adr)     NF_Addr(d)
    #define WRITE_NAND(d, adr)          NF_Write(d)
    #define READ_NAND(adr)               NF_Read()
    /* the following functions are NOP's because S3C24X0 handles this in hardware */
    #define NAND_CTL_CLRALE(nandptr)
    #define NAND_CTL_SETALE(nandptr)
    #define NAND_CTL_CLRCLE(nandptr)
    #define NAND_CTL_SETCLE(nandptr)

    #define CONFIG_MTD_NAND_VERIFY_WRITE     1
    #define CONFIG_MTD_NAND_ECC_JFFS2     1

    #endif     /* CONFIG_COMMANDS & CFG_CMD_NAND */

    /*08-6-25***************************************************/
    4. 在fs2410.h中打开命令:
    /***********************************************************
    * Command definition
    ***********************************************************/
    #define CONFIG_COMMANDS \
                   (CONFIG_CMD_DFL      | \
                   CFG_CMD_CACHE      | \
                   CFG_CMD_ENV           | \
                   CFG_CMD_NET           | \
                   CFG_CMD_PING      | \
                   CFG_CMD_NAND      | \            /* 打开 nand flash 命令 */
                   /*CFG_CMD_EEPROM |*/ \
                   /*CFG_CMD_I2C      |*/ \
                   /*CFG_CMD_USB      |*/ \
                   CFG_CMD_REGINFO  | \
                   CFG_CMD_DATE      | \
                   CFG_CMD_ELF)

    好 了,make一下,看看结果,很不幸运,/env_nand.c:206 undefined reference to 'nand_info'等等问题,如图1所示,原来nand flash 真正的擦除和读写函数使用的是 drivers/nand_legacy/ 目录下面的读写、擦除函数
    int nand_legacy_erase(struct nand_chip* nand, size_t ofs,size_t len, int clean);
    int nand_legacy_rw(struct nand_chip* nand, int cmd,size_t start, size_t len,size_t * retlen, u_char * buf);
    5. 修改saveenv中对nand的读写函数为nand_legacy的读写函数,修改common/env_nand.c如下:

    #include <common.h>

    #if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */

    #include <command.h>
    #include <environment.h>
    #include <linux/stddef.h>
    #include <malloc.h>
    #include <nand.h>

    #if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_NAND)) == (CFG_CMD_ENV|CFG_CMD_NAND))
    #define CMD_SAVEENV
    #elif defined(CFG_ENV_OFFSET_REDUND)
    #error Cannot use CFG_ENV_OFFSET_REDUND without CFG_CMD_ENV & CFG_CMD_NAND
    #endif

    #if defined(CFG_ENV_SIZE_REDUND) && (CFG_ENV_SIZE_REDUND != CFG_ENV_SIZE)
    #error CFG_ENV_SIZE_REDUND should be the same as CFG_ENV_SIZE
    #endif

    #ifdef CONFIG_INFERNO
    #error CONFIG_INFERNO not supported yet
    #endif

    /*  My Add*/

    int nand_legacy_erase(struct nand_chip* nand,

    size_t ofs, size_t len, int clean);

    int nand_legacy_rw (struct nand_chip* nand, int cmd,
              size_t start, size_t len,
              size_t * retlen, u_char * buf);

    /*  My Add*/

    extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];

    /* info for NAND chips, defined in drivers/nand/nand.c */
    //extern nand_info_t nand_info[];

    nand_info_t nand_info[CFG_MAX_NAND_DEVICE];

    /* references to names in env_common.c */
    extern uchar default_environment[];
    extern int default_environment_size;
    ......
    ......
    #else /* ! CFG_ENV_OFFSET_REDUND */
    int saveenv(void)          /* 2008-6-26 by weij */
    {
         ulong total;
         int ret = 0;

         puts ("Erasing Nand...");
         //if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
         if (nand_legacy_erase(nand_dev_desc+0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))
              return 1;

         puts ("Writing to Nand... ");
         total = CFG_ENV_SIZE;
         //ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
         nand_legacy_rw(nand_dev_desc+0, 0x00 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);

         if (ret || total != CFG_ENV_SIZE)
              return 1;

         puts ("done\n");
         return ret;
    }
    #endif /* CFG_ENV_OFFSET_REDUND */
    ......
    ......
    /*
    * The legacy NAND code saved the environment in the first NAND device i.e.,
    * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
    */
    void env_relocate_spec (void)
    {
    #if !defined(ENV_IS_EMBEDDED)
         ulong total;
         int ret;

         total = CFG_ENV_SIZE;
         //ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

         ret=nand_legacy_rw(nand_dev_desc+0, 0x01 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);

           if (ret || total != CFG_ENV_SIZE)
              return use_default();

         if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
              return use_default();
    #endif /* ! ENV_IS_EMBEDDED */
    }
    #endif /* CFG_ENV_OFFSET_REDUND */
    ......
    ......
    修改完毕,make一下,看到了期盼的画面如图2、3所示,由于能够saveenv,所以就没有了warning -bad CRC的警告,ping一下,主机能用,ok,tftp一下,Loading: TTTTT,如图4所示,莫惊慌,
    《基 于smdk2410 开发板u-boot-1.2.0 对 nand flash的支持》PDF文档中,说把某段代码注释掉,其实我的是防火墙关掉就ok,图5、6是tftp优龙自带的S3C2410_BIOS.bin 到RAM然后go的结果。下一篇将完成内核引导……

    图1

    图2、3

    4


    图5、6

    原文链接:http://blog.chinaunix.net/u2/74310/showart.php?id=1091929

    Leo 发表于23:50:00 | 阅读全文 | 评论 0编辑 | 分享 0
  • 买到开发板之初,就开始移植u-boot,问题多多,加上扳子硬件烧写出了问题,折腾半个多月,放弃,一种挫败 感久久不能抹去;偶然间发现扬创开发板“基于u-boot移植修改完善”的utu-bootloader,买之,回来打开光盘一看,暂不提供u-boot 移植源代码。凭着职业的冷静,我克制住,和网上的朋友一样,奋战几个夜晚,完成了从NAND FLASH启动、NAND FLASH读写、内核引导。

    移植过程中,参考了网上资料,列举如下:       
           《uboot1.1.4移植》网址:
           http://hi.baidu.com/edaworld/blog/item/c40f83a8a2e6d1b5cb130cca.html
           《uboot for s3c2410 nandboot 使用saveenv保存环境变量》网址:
           http://blog.chinaunix.net/u1/56388/showart_438720.html
           《基于smdk2410 开发板u-boot-1.2.0 对 nand flash的支持》PDF文档。
    同时推荐博客:http://blog.chinaunix.net/u1/34474/showart.php?id=363269
                
    一、移植前说明:

    1. 工作环境:
                  Fedora 8 ,内核2.6.25
           交叉编译器:
                  Arm-linux-gcc 3.3.2
           目标板:
           优龙FS2410,NAND Flash:64M K9F1208,NOR Flash:2M SST39VF1601 (本次移植不包含NOR Flash  支持), RAM 64M ,CS8900Q3

    2. 下载源码,建立工作目录

           u-boot的源码可以从以下网址下载:
           http://downloads.sourceforge.net/u-boot/u-boot-1.1.6.tar.bz2
           建立工作目录:
           mkdir /uboot
           cd /uboot
           把下载的源码拷贝到该目录,解压;
           tar jxvf u-boot-1.1.6.tar.bz2 

    二、移植步骤如下:

    (1)、建立自己fs2410开发板的配置

           1)# cp –r board/smdk2410 board/fs2410      
           2)# cp include/configs/smdk2410.h include/configs/fs2410.h

    fs2410.h 是开发板的配置文件,他包括开发板的CPU、系统时钟、RAM、FLASH系统及其他相关的配置信息,由于u-boot已经支持三星的SMDK2410开 发板,所以移植的时候直接拷贝SMDK2410的配置文件,做相应的修改即可。由于Uboot对SMDK2410板的NAND Flash初始化部分没有写,即lib_arm/board.c中的start_armboot函数中有这么一句:
    #if (CONFIG_COMMANDS & CFG_CMD_NAND)
    puts ("NAND:");
    nand_init(); /* go init the NAND */
    #endif
    但是在board/smdk2410目录下源文件中都没有定义nand_init这个函数。所以需要我们补充这个函数以及这个函数涉及的底层操作,NAND Flash的读写操作相对复杂,将在u-boot-1.1.6移植的第二部分介绍。

    (2). 修改顶层Makefile

    cd /uboot/u-boot-1.1.6
    vi Makefile
    找到:
    smdk2410_config       :       unconfig
           @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
    在其后面添加:
    fs2410_config       :       unconfig
           @$(MKCONFIG) $(@:_config=) arm arm920t fs2410 NULL s3c24x0

    各项的意思如下:
    arm:           CPU的架构(ARCH)
    arm920t:       CPU的类型(CPU),其对应于cpu/arm920t子目录。
    fs2410:       开发板的型号(BOARD),对应于board/fs2410目录。
    NULL:          开发者/或经销商(vender)。
    s3c24x0:       片上系统(SOC)。
    (3).  include/configs/fs2410.h:
                  
                  修改:
                  # define      CFG_PROMPT        “SMDK2410 #”
                  为:
                  # define      CFG_PROMPT        “fs2410 #” 
           这是u-boot的命令行提示符。
    (4) 修改board/fs2410/Makefile
           将:
           OBJS       := smdk2410.o flash.o
           改为:
           OBJS        := fs2410.o flash.o
           当然,fs2410下的 smdk2410.c要改成fs2410.c;
    (5)依照你自己开发板的内存地址分配情况修改board/fs2410/lowlevel_init.S文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值