2012-Linux->18(使U-BOOT能正确引导LINUX for 1_20 error,but...)->1
  GszpTVOH9zt3 2023年11月02日 26 0


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内核,得修改UBOOT的2410CPU频率。

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.8M,VIVI的200M能跑得好好的,那我把U-BOOT的频率改成200M,2.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-BOOT到NAND FLASH,通过setenv设置bootargs,

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

注意:

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

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

作者:Leo

重新搭建嵌入式LINUX中碰到的问题

                                    已经搭建好的嵌入式环境不小心被破坏了,破坏得还真彻底,需要重新从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只是用来设置一些随机启动的参数,对文件能否正常运行关系不大。

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

uboot for s3c2410 nandboot 使用saveenv保存环境变量(3)

Tag:

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 */

uboot for s3c2410 nandboot 使用saveenv保存环境变量(2)

Tag:

/* 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;

uboot for s3c2410 nandboot 使用saveenv保存环境变量(1)

Tag:

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)) );
}

u-boot NAND flash的支持(使用新代码)

Tag:

在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, ) */
 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, */
 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,启动,便可以引导内核了。

基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (三)

Tag:

首先引用《嵌入式系统 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 移植完毕,感谢收看!

基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (二)

Tag:

中,参考了网上资料,列举如下:     
     《uboot1.1.4移植》网址:
      《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

基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (一)

Tag:

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

移植过程中,参考了网上资料,列举如下:       
       《uboot1.1.4移植》网址:
       《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文件

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  AYXfFrNq3tRi   2023年12月05日   35   0   0 redislinuxlinuxredis
  xaeiTka4h8LY   2024年04月26日   51   0   0 centoslinuxredis
GszpTVOH9zt3