最详尽的ARM+LINUX移植攻略 linux2.6.30.4内核+yaffs2文件系统+uboot 2009.08

转载地址:http://bbs.witech.com.cn/thread-4094-1-1.html

平台: 
虚拟机:VirtualBox Ubuntu 9.10 
文件传输工具:SSHSecureShellClient-3.2.9 
交叉编译环境:arm-linux-gcc-4.3.2 
与开发板通信:tftp 
Uboot移植步骤一: 
建立交叉编译环境:arm-linux-gcc-4.3.2 
1.将arm-linux-gcc-4.3.2.tgz复制到任意路径下; 
2.确保安装了标准C开发环境,sudo apt-get install build-essential libncurses5-dev; 
3.在终端进入arm-linux-gcc-4.3.2.tgz存放目录,再sudo tar -zxvf arm-linux-gcc-4.3.2.tgz -C /(注意大写C字母后留一个空格),这样会自动解压到/usr/local/4.3.2目录下); 
4.修改环境变量,使交叉编译环境生效。 
vim ~/.profile 
在这个文件最后添加上自己的环境变量:export PATH=$PATH:/usr/local/arm/4.3.2/bin 
然后在终端执行source ~/.profile ,即可立即生效。 
5. arm-linux-gcc -v 
Using built-in specs. 
Target: arm-none-linux-gnueabi 
Configured with: /scratch/julian/lite-respin/linux/src/gcc-4.3/configure --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi --enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --enable-shared --enable-symvers=gnu --enable-__cxa_atexit --with-pkgversion='Sourcery G++ Lite 2008q3-72' --with-bugurl=https://support.codesourcery.com/GNUToolchain/ --disable-nls --prefix=/opt/codesourcery --with-sysroot=/opt/codesourcery/arm-none-linux-gnueabi/libc --with-build-sysroot=/scratch/julian/lite-respin/linux/install/arm-none-linux-gnueabi/libc --with-gmp=/scratch/julian/lite-respin/linux/obj/host-libs-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr --with-mpfr=/scratch/julian/lite-respin/linux/obj/host-libs-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr --disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/julian/lite-respin/linux/install/arm-none-linux-gnueabi/bin --with-build-time-tools=/scratch/julian/lite-respin/linux/install/arm-none-linux-gnueabi/bin 
Thread model: posix 
gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72)

U-boot-2009.08移植TE2440II开发板--在SDRAM中运行 
因为串口的波特率问题纠结了我2天,嘿嘿。 
1.首先创建自己板子的目录 
cd u-boot-2009.08 
mkdir board/samsung/TE2440II 
cp board/samsung/smdk2410/* board/samsung/TE2440II/ 
mv board/samsung/TE2440II/smdk2410.c board/samsung/TE2440II/TE2440II.c 
2.添加配置文件 
cp include/configs/smdk2410.h include/configs/TE2440II.h 
在include/configs/smdk2410.h include/configs/TE2440II.h中添加 
#define CONFIG_SKIP_LOWLEVEL_INIT         1    
因为是先在SDRAM中运行,所以要跳过底层的初始化。暂时没有添加CONFIG_2440,用原来的CONFIG_2410,以提高移植速度。 
注意暂时不要添加#define CONFIG_SKIP_RELOCATE_UBOOT    1 
否则就要更改你的下载地址为0x33f80000,让他去搬运代码吧 
3.修改board/samsung/TE2440II/ 目录下的Makefile,把COBJS := 修改为 
COBJS    := TE2440II.o flash.o 
4.修改顶层Makefile 
TE2440II_config : unconfig                                                   
           @$(MKCONFIG) $(@:_config=) arm arm920t TE2440II samsung s3c24x0 
注意有个Tab键 
5. 修改顶层Makefile文件,在CROSS_COMPILE ?=后面添加自己的交叉编译工具。 
CROSS_COMPILE ?= /usr/local/arm/4.3.2/bin/arm-linux- 
6.完成这几步后编译一下 
    make TE2440II_config 
    make 
下到SDRAM中,终端应该没有任何信息,需要设置波特率。 
1.    修改TE2440II.c文件 
#elif FCLK_SPEED==1        /* Fout = 405MHz */ 
#define M_MDIV    0x7f 
#define M_PDIV    0x2 
#define M_SDIV    0x1 
#endif

2.    修改cpu/arm920t/start.S 
外部晶振为12MHz,通过MPLLCON设置MPLL为405M 
#if defined(CONFIG_S3C2410) 
#define MPLLCON 0x4C000004 
#define UPLLCON 0x4c000008 
#define LOCKTIME 0x4C000000 
#define CAMDIVN  0x4C000018 
    ldr r0,=LOCKTIME 
    ldr r1,=0xffffffff 
    str r1,[r0] 
//清除摄像头分频寄存器的值    
ldr r0,=CAMDIVN                 
    mov r1,#0 
    str r1,[r0] 
    ldr r0, =CLKDIVN 
    mov r1, #5 
    str r1,[r0]

    //手册说HDIVN不为0,加这个 
    mrc  p15, 0, r1, c1, c0, 0         //read ctrl register        
    orr   r1, r1, #0xc0000000          //Asynchronous 
    mcr  p15, 0, r1, c1, c0, 0         //write ctrl register

        ldr r0, =UPLLCON                   //同时修改UPLLCON和MPLLCON需要先修   
    ldr r1, =0x00038022                  //改UPLLCON,且之间要间隔至少7个nop 
    str r1,[r0]                           //手册有些 
       nop                            
       nop 
       nop 
       nop 
       nop 
       nop 
       nop 
       nop 
     ldr r0, =MPLLCON 
    ldr r1, =0x0007f021 
    str r1,[r0] 
#endif    
3.    修改cpu/arm920t/s3c24x0/speed.c 
由于S3C2440和S3C2410的MPLL计算公式改变了,所以要改一下。 
get_PLLCLK改成这样 
static ulong get_PLLCLK(int pllreg) 

    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); 
    ulong r, m, p, s;

    if (pllreg == MPLL) 
    r = clk_power->MPLLCON; 
    else if (pllreg == UPLL) 
    r = clk_power->UPLLCON; 
    else 
    hang();

    m = ((r & 0xFF000) >> 12) + 8; 
    p = ((r & 0x003F0) >> 4) + 2; 
    s = r & 0x3; 
if (pllreg == MPLL) //MPLL的算法和UPLL是不同的。这里m=2*m 
    { 
        m <<= 1; 
    }

    p = ((r & 0x003F0) >> 4) + 2; 
    s = r & 0x3;

    return ((CONFIG_SYS_CLK_FREQ * m) / (p << s)); 

get_HCLK改成这样 
/* return HCLK frequency */ 
ulong get_HCLK(void) 

    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); 
    return get_FCLK()/4; 
    //return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK()); 

get_PCLK改成这样 
/* return PCLK frequency */ 
ulong get_PCLK(void) 

    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); 
    return get_HCLK()/2; 
    //return((clk_power->CLKDIVN & 0x1) ? get_HCLK()/2 : get_HCLK()); 

4.    我出问题的地方是串口,显示的基本跟正常的一样,但是显示为乱码,是串口波特率的问题。在drivers/serial/serial_s3c24x0.c中,修改 
uart->UBRDIV = 27; 
我直接设定了,不用鸟u-boot再鸟算了,他自己怎么也算不对,我帮他。 
5.    make TE2440II_config 
       make 
下载到SDRAM中,哈哈。

U-boot-2009.08移植TE2440II开发板--支持Norflash

TE2440II开发板使用的Norflash是INTEL的JS28F320J3D75,4M,32个block,每个128KB。本文添加对Norflash的支持,使Uboot可以烧录到Norflash,从Norflash启动,并执行Norflash下的命令。 
这样需要注释掉 /include/configs/TE2440II.h中的 
#define CONFIG_SKIP_LOWLEVEL_INIT     1    
//#define CONFIG_SKIP_RELOCATE_UBOOT    1   
把include/configs/TE2440II.h的Physical Memory Map和FLASH and environment organization修改为,这里添加了/board/cmi/flash.c中部份变量的宏定义。FLASH and environment organization这里的sector指的是手册中的bank,所以大小是128KB,为32块。#define CONFIG_ENV_ADDR         (CONFIG_SYS_FLASH_BASE + 0x40000),这个偏移是自己定的,是放环境变量的,只要不在uboot的代码区就可以。 
CONFIG_SYS_FLASH_ERASE_TOUT和CONFIG_SYS_FLASH_WRITE_TOUT是超时的时间,如果小了,自己改大些。cpu/arm920t/s3c24x0/timer.c中讲述了怎么获得时间的。 
/*----------------------------------------------------------------------- 
* Physical Memory Map 
*/ 
#define CONFIG_NR_DRAM_BANKS    1       /* we have 1 bank of DRAM */ 
#define PHYS_SDRAM_1        0x30000000 /* SDRAM Bank #1 */ 
#define PHYS_SDRAM_1_SIZE    0x04000000 /* 64 MB */

#define PHYS_FLASH_1        0x00000000 /* Flash Bank #1 */

#define CONFIG_SYS_FLASH_BASE        PHYS_FLASH_1 
#define FLASH_BASE0_PRELIM  PHYS_FLASH_1 
#define CONFIG_SYS_MONITOR_BASE TEXT_BASE

/*----------------------------------------------------------------------- 
* FLASH and environment organization 
*/ 
#define CONFIG_SYS_MAX_FLASH_BANKS    1    /* max number of memory banks */ 
#define CONFIG_INTEL_JS28F320 1 
#define PHYS_FLASH_SIZE 0x400000   /* 4M */ 
#define CONFIG_SYS_MAX_FLASH_SECT 32 
#define CONFIG_ENV_ADDR         (CONFIG_SYS_FLASH_BASE + 0x40000)

/* timeout values are in ticks */ 
#define CONFIG_SYS_FLASH_ERASE_TOUT    (2*CONFIG_SYS_HZ) /* Timeout for Flash Erase */ 
#define CONFIG_SYS_FLASH_WRITE_TOUT    (2*CONFIG_SYS_HZ) /* Timeout for Flash Write */

#define    CONFIG_ENV_IS_IN_FLASH    1 
#define CONFIG_ENV_SIZE        0x20000    /* Total Size of Environment Sector */

#endif    /* __CONFIG_H */ 
用board/cmi/下的flash.c文件替换board/samsung/TE2440II/下的flash.c,因为cmi目录下的正好是JS28F320J3D75的驱动文件。删除这个write_short函数的申明和定 义、删除write_buff函数。替换成下面的两个函数: 
/****************************************************************************************************** 
* Copy memory to flash. 
*/

int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) 

   ulong cp, wp; 
   ushort data; 
   int l; 
   int i, rc;

   wp = (addr & ~1);        /* get lower word aligned address */

   /* 
    * handle unaligned start bytes 
    */ 
   if ((l = addr - wp) != 0) 
   { 
      data = 0; 
      for (i=0, cp=wp; i<l; ++i, ++cp) { 
       data = (data >> 8) | (*(uchar *)cp << 8); 
      } 
      for (; i<2 && cnt>0; ++i) { 
     data = (data >> 8) | (*src++ << 8); 
     --cnt; 
     ++cp; 
      } 
      for (; cnt==0 && i<2; ++i, ++cp) { 
     data = (data >> 8) | (*(uchar *)cp << 8); 
      }

      if ((rc = write_word(info, wp, data)) != 0) { 
     return (rc); 
      } 
      wp += 2; 
   }

   /* 
    * handle word aligned part 
    */ 
   while (cnt >= 2) { 
      data = *((vu_short*)src); 
      if ((rc = write_word(info, wp, data)) != 0) { 
      return (rc); 
      } 
      src += 2; 
      wp  += 2; 
      cnt -= 2; 
   }

   if (cnt == 0) { 
      return ERR_OK; 
   }

   /* 
    * handle unaligned tail bytes 
    */ 
   data = 0; 
   for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) { 
      data = (data >> 8) | (*src++ << 8); 
      --cnt; 
   } 
   for (; i<2; ++i, ++cp) { 
      data = (data >> 8) | (*(uchar *)cp << 8); 
   }

   return write_word(info, wp, data); 
}

/****************************************************************************************************** 
* Copy memory to flash. 
*/

static int write_word (flash_info_t *info, ulong dest, ushort data) 

   vu_short *addr = (vu_short *)dest, val; 
   int rc = ERR_OK; 
   int flag;

   /* Check if Flash is (sufficiently) erased , fix by kavin*/ 
   if ((*addr & data) != data) 
      return ERR_NOT_ERASED;

   /* 
    * Disable interrupts which might cause a timeout 
    * here. Remember that our exception vectors are 
    * at address 0 in the flash, and we don't want a 
    * (ticker) exception to happen while the flash 
    * chip is in programming mode. 
    */ 
   flag = disable_interrupts();

   /* clear status register command */ 
   *addr = 0x50;

   /* program set-up command */ 
   *addr = 0x40;

   /* latch address/data */ 
   *addr = data;

   /* arm simple, non interrupt dependent timer */ 
   reset_timer_masked();

   /* wait while polling the status register */ 
   while(((val = *addr) & 0x80) != 0x80) 
   { 
      if (get_timer_masked() > CONFIG_SYS_FLASH_WRITE_TOUT) { 
      rc = ERR_TIMOUT; 
      /* suspend program command */ 
      *addr = 0xB0; 
      goto outahere; 
      } 
   }

   if(val & 0x1A) {        /* check for error */ 
      printf("\nFlash write error %02x at address %08lx\n", 
           (int)val, (unsigned long)dest); 
      if(val & (1<<3)) { 
     printf("Voltage range error.\n"); 
     rc = ERR_PROG_ERROR; 
     goto outahere; 
      } 
      if(val & (1<<1)) { 
     printf("Device protect error.\n"); 
     rc = ERR_PROTECTED; 
     goto outahere; 
      } 
      if(val & (1<<4)) { 
     printf("Programming error.\n"); 
     rc = ERR_PROG_ERROR; 
     goto outahere; 
      } 
      rc = ERR_PROG_ERROR; 
      goto outahere; 
   }

outahere: 
   /* read array command */ 
   *addr = 0xFF;

   if (flag) 
      enable_interrupts();

   return rc; 

修改flash.c文件中的一个宏定义: 
把: 
#define FLASH_BLOCK_SIZE        0x00010000 
改为: 
#define FLASH_BLOCK_SIZE        0x00020000 
修改开发板目录下的lowlevel_init.S文件中SDARM刷新参数为: 
#define REFCNT    1258    /* period=7.8125us, HCLK=405/4 Mhz, (2048+1-7.8125*405/4) */ 
Lowlevel_init.S中对SDRAM进行了初始化,因为我们要把第二阶段的代码搬运到SDRAM中,REFCNT是刷新计数器,这个在移植的时候是一定要修改的。手册上有公式:Refresh period = (2^11-refresh_count+1)/HCLK,我使用的这款芯片在datasheet写着8192Refresh cycle/64ms,所以一个刷新周期为64ms/8192=7.8125us。目前公认的标准是,存储体中电容中数据有效保存期上限是64ms,也就是说每一行刷新的循环周期是64ms,这样刷新的速度就是:行数量/64ms。我的理解是CPU并不知道你用的SDRAM的刷新速度是多少,特殊功能寄存器也没有直接传递刷新速度的位,但是有一个刷新计数器,可以通过刷新计数器间接获得刷新速度,所以要设定刷新计数器。 
然后就可以烧录Norflash了。

支持DM9000A
今天看了Nandflash部分,感觉不是一时半会儿能搞定的,所以先避实就虚呵呵,搞定了网卡。飞凌TE24440II使用的是双网卡,CS8900和DM9000A。已经有很好的网卡驱动代码,我们只要根据自己的板子适当修改一下就行,所以难度比Nandflash低得多。废话少说,看看怎么改。 
首先注释掉跟CS8900有关的部分 
//#define CONFIG_DRIVER_CS8900    1    /* we have a CS8900 on-board */ 
//#define CS8900_BASE        0x19000300 
//#define CS8900_BUS16        1 /* the Linux driver does accesses as shorts */ 
在include/configs/TE2440II.h中添加 
#define CONFIG_DRIVER_DM9000 1 
#define CONFIG_NET_MULTI 1 
#define CONFIG_DM9000_NO_SROM 1 
#define CONFIG_DM9000_BASE 0x20000000   //网卡片选地址 
#define DM9000_IO CONFIG_DM9000_BASE   //网卡命令端口 
#define DM9000_DATA (CONFIG_DM9000_BASE+4) //网卡数据端口 
//增加ping命令 
#define CONFIG_CMD_PING                   
//MAC地址 
#define CONFIG_ETHADDR 08:00:3e:26:0a:5b 
#define CONFIG_NETMASK 255.255.255.0 
//开发板的IP地址 
#define CONFIG_IPADDR 192.168.1.105 
//Linux主机的IP地址 
#define CONFIG_SERVERIP 192.168.1.103 
注释掉以前跟这个重复的。 
添加网卡初始化代码: 修改board/samsung/TE2440II/TE2440II.c 
#include <net.h> 
#include <netdev.h> 
#ifdef CONFIG_DRIVER_DM9000 
int board_eth_init(bd_t *bis) 

    return dm9000_initialize(bis); 

#endif 
在drivers/net/dm9000x.c中修改(屏蔽掉dm9000_init中的这一部分,不然使用网卡的时候会报“could not establish link”的错误) 
#if 0 
    i = 0; 
    while (!(phy_read(1) & 0x20)) {    /* autonegation complete bit */ 
        udelay(1000); 
        i++; 
        if (i == 10000) { 
            printf("could not establish link\n"); 
            return 0; 
        } 
    } 
#endif 
修改drivers/net/dm9000x.c。屏蔽掉dm9000_halt函数中的内容,否则ping不通。 
/* 
  Stop the interface. 
  The interface is stopped when it is brought. 
*/ 
static void dm9000_halt(struct eth_device *netdev) 

    //DM9000_DBG("%sn", __func__);

    ///* RESET devie */ 
    //phy_write(0, 0x8000);    /* PHY RESET */ 
    //DM9000_iow(DM9000_GPR, 0x01);    /* Power-Down PHY */ 
    //DM9000_iow(DM9000_IMR, 0x80);    /* Disable all interrupt */ 
    //DM9000_iow(DM9000_RCR, 0x00);    /* Disable RX */ 

重新编译烧录到Norflash就可以了。 
这里需要注意的是#define CONFIG_DM9000_BASE 0x20000000   //网卡片选地址。而不是0x20003000,这个是DM9000,而我们使用的是DM9000A。因为CMD接在ADDR2上所以#define DM9000_DATA (CONFIG_DM9000_BASE+4)。因为DM9000A的地址信号和数据信号复用,CMD引脚决定传输的是地址信号还是数据信号。数据手册上说CMD为0时是地址信号所以DM9000_IO CONFIG_DM9000_BASE,CMD为1时,是数据信号,所以#define DM9000_DATA (CONFIG_DM9000_BASE+4)。DM9000A内部有一个4K Dword SRAM,因为数据线和地址线是复用的,所以如果这部分用地址线进行寻址,范围是16KB,所以在 0x20000000~0x20000000+16KB范围内都可以的。所以0x20003000是碰巧在这里的。第一次ping不同,第二次开始就可以ping通了,这个是正常现象。

支持Nandflash操作

分析了一下Uboot中Nandflash的驱动,u-boot-2009.08使用的是和Linux内核一样的MTD(内存技术设备)架构。在Uboot下对Nand的支持体现在命令行下实现对nand flash的操作,为:nand info,nand device,nand read,nand write,nand erease,nand bad。用到的主要数据结构有:struct nand_flash_dev,struct nand_chip。前者包括主要的芯片型号,存储容量,设备ID,I/O总线宽度等信息;后者是具体对nand flash进行操作时用到的信息。 
对Nandflash驱动代码的分析:


1)lib_arm/board.c中start_armboot()函数中调用了nand_init()。 
2)nand_init()函数定义在drivers/mtd/nand/Nand.c文件中,调用了同文件下的nand_init_chip()函数和board_nand_select_device()函数,并累加Nandflash的总大小。 
3)nand_init_chip()函数初始化了IO_ADDR_R和IO_ADDR_W,调用board_nand_init()和nand_scan()。(在drivers/mtd/nand/S3c2410_nand.c中) 
4)board_nand_init()函数在drivers/mtd/nand/S3c2410_nand.c中,初始化NFCONF配置寄存器。主要对struct nand_chip结构体的函数指针赋值,让他们指向自己为nand驱动编写的一些函数,该数据结构在include/linux/mtd/nand.h中定义。 
5)nand_scan()函数在drivers/mtd/nand/Nand_base.c文件中定义,并调用了nand_scan_ident()和nand_scan_tail()函数。 
6)nand_scan_ident()调用了同文件下的nand_set_defaults()和nand_get_flash_type(),nand_set_defaults()函数对struct nand_chip结构体的函数指针进行了赋值。在此函数中cmdfunc映射到了nand_command,nand_get_flash_type()读取了厂商和设备ID,并对struct nand_chip结构体的变量和mtd_info进行初始化操作。 
7)nand_scan_tail()进行了ECC的设置和剩下的MTD驱动函数的初始化。 
8)nand_select_device()函数用来打开或关闭nand芯片,-1是打开,0是关闭。chip->cmd_ctrl映射到hwcontrol(在drivers/mtd/nand/S3c2410_nand.c的board_nand_init()函数中)。 
9)返回nand_init(),这样nand的初始化就完成了。 
移植Nandflash驱动,主要是修改S3c2410_nand.c。 
看一个Read操作的例子:


以common/env_nand.c里读取Nandflash的环境变量为例, 
env_nand.c中调用了nand_read(&nand_info[0], offset, &len, char_ptr); 
nand_read在include/nand.h中定义。 
static inline int nand_read(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf) 

    return info->read(info, ofs, *len, (size_t *)len, buf); 

nand_read又调用info->read,即mtd_info的read,mtd_info与nand_info_t同名。 
mtd_info的read函数在drivers/nand/nand_base.c中的nand_scan_tail函数中被映射到nand_read(),在nand_read()中调用nand_do_read_ops()。这是最后一层,通过调用nand_chip中的函数完成带ECC的读操作。

现在进行移植: 
修改include/configs/TE2440II.h如下 
/* 
* Command line configuration. 
*/ 
#include <config_cmd_default.h>

#define CONFIG_CMD_CACHE 
#define CONFIG_CMD_DATE 
#define CONFIG_CMD_ELF 
#define CONFIG_CMD_NAND 
#define CONFIG_CMDLINE_EDITING 
#ifdef CONFIG_CMDLINE_EDITING 
#undef CONFIG_AUTO_COMPLETE 
#else 
#define CONFIG_AUTO_COMLETE 
#endif

/* 
* NAND flash setting 
*/ 
#if defined(CONFIG_CMD_NAND) 
#define CONFIG_SYS_NAND_BASE 0x4e000000 
#define CONFIG_SYS_MAX_NAND_DEVICE 1 
#define CONFIG_MTD_NAND_VERIFY_WRITE 1 
#define NAND_SAMSUNG_LP_OPTIONS 1 
#define CONFIG_NAND_S3C2440 1 
#endif 
环境变量那部分修改: 
//#define CONFIG_ENV_IS_IN_FLASH    1 
#define CONFIG_ENV_IS_IN_NAND 1         /*环境变量的保存位置*/ 
在drivers/mtd/nand/Makefile文件中添加: 
COBJS-y += s3c2440_nand.o 
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o 
我们最重要的是修改s3c2410_nand.c,把它复制重命名为s3c2440_nand.c,因为s3c2410和s3c2440在nand控制器方面有很多不同,所以要进行移植。 
修改s3c2440_nand.c为: 
#define    NF_BASE        0x4e000000 
#define    NFCONF         __REGi(NF_BASE + 0x0) 
#define     NFCONT        __REGi(NF_BASE + 0x4) 
#define    NFCMD           __REGb(NF_BASE + 0x8) 
#define    NFADDR         __REGb(NF_BASE + 0xc) 
#define    NFDATA          __REGb(NF_BASE + 0x10) 
#define     NFMECCD0    __REGi(NF_BASE + 0x14) 
#define     NFMECCD1    __REGi(NF_BASE + 0x18) 
#define     NFSECCD       __REGi(NF_BASE + 0x1C) 
#define    NFSTAT           __REGb(NF_BASE + 0x20) 
#define    NFSTAT0         __REGi(NF_BASE + 0x24) 
#define    NFSTAT1         __REGi(NF_BASE + 0x28) 
#define    NFMECC0        __REGi(NF_BASE + 0x2C) 
#define    NFMECC1        __REGi(NF_BASE + 0x30) 
#define    NFSECC           __REGi(NF_BASE + 0x34) 
#define    NFSBLK           __REGi(NF_BASE + 0x38) 
#define    NFEBLK           __REGi(NF_BASE + 0x3c)

#define S3C2440_NFCONT_nCE    (1<<1) 
#define S3C2440_ADDR_NALE 0x0c 
#define S3C2440_ADDR_NCLE 0x08

ulong IO_ADDR_W = NF_BASE;

static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) 

    struct nand_chip *chip = mtd->priv; 
    DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

    if (ctrl & NAND_CTRL_CHANGE) { 
        IO_ADDR_W = NF_BASE; 
        if (!(ctrl & NAND_CLE)) //要写的是地址 
            { 
            IO_ADDR_W |= S3C2440_ADDR_NALE;} 
        if (!(ctrl & NAND_ALE)) //要写的是命令 
            { 
            IO_ADDR_W |= S3C2440_ADDR_NCLE;}

        if (ctrl & NAND_NCE)   
            {NFCONT &= ~S3C2440_NFCONT_nCE; //使能nand flash 
            //DEBUGN("NFCONT is 0x%x ",NFCONT); 
            //DEBUGN("nand Enable "); 
            } 
        else 
            {NFCONT |= S3C2440_NFCONT_nCE;  //禁止nand flash 
            //DEBUGN("nand disable "); 
            } 
    }

    if (cmd != NAND_CMD_NONE) 
        writeb(cmd,(void *)IO_ADDR_W); 
}

static int s3c2440_dev_ready(struct mtd_info *mtd) 

    DEBUGN("dev_ready\n"); 
    return (NFSTAT & 0x01); 
}

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

int board_nand_init(struct nand_chip *nand) 

     u_int32_t cfg; 
     u_int8_t tacls, twrph0, twrph1; 
     S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); 
     DEBUGN("board_nand_init()\n"); 
     clk_power->CLKCON |= (1 << 4);

    DEBUGN("CONFIG_S3C2440\n"); 
        twrph0 = 4; twrph1 = 2; tacls = 0; 
    cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4); 
    NFCONF = cfg; 
    //DEBUGN("cfg is %x\n",cfg); 
    //DEBUGN("NFCONF is %lx\n",NFCONF); 
    cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0); 
    NFCONT = cfg; 
    //DEBUGN("cfg is %lx\n",cfg); 
    //DEBUGN("NFCONT is %x\n",NFCONT);

/* initialize nand_chip data structure */ 
    nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;

    /* read_buf and write_buf are default */ 
    /* read_byte and write_byte are default */

    /* hwcontrol always must be implemented */ 
    nand->cmd_ctrl = s3c2440_hwcontrol; 
    nand->dev_ready = s3c2440_dev_ready; 
    return 0; 

s3c2440_hwcontrol函数主要控制是写命令还是写地址。 
我遇到的问题,由于board_nand_init()函数我没有添加return 0,导致后面的判断没法进行,结果读出的NAND为0MiB,所以移植一定要仔细阅读源码,还有个问题就是uboot的打印信息中出现NAND_ECC_NONE selected by board driver. This is not recommended!!,这根ECC的校验模式有关,有人说“据说vivi或uboot通过软件算法产生的ecc校验码于S3C2410 NAND Flash 控制器产生的ecc校验码不一致”,所以我就没改什么,我把那个打印信息注释掉了。

支持Nandflash启动
从nandflash启动最关键的部分是rellocated,即代码重定位。s3c2440数据手册有这么一段,所以代码重定位是由nandflash控制器自动完成的,而不是一些人说的由CPU完成的。

在include/configs/TE2440II.h中添加nandflash控制器的定义:
/*
* NAND flash setting
*/
#if defined(CONFIG_CMD_NAND)
#define CONFIG_SYS_NAND_BASE 0x4e000000
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
#define NAND_SAMSUNG_LP_OPTIONS 1                  //大页要添加这个
#define CONFIG_NAND_S3C2440 1                        
#define CONFIG_S3C2440_NAND_BOOT 1
#define NAND_CTL_BASE 0x4E000000
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFADDR 0x0c
#define oNFDATA 0x10
#define oNFCMD 0x08
#define oNFSTAT 0x20
#define oNFECC 0x2c
#endif

/*
* Command line configuration.
*/
下添加
#define CONFIG_CMD_NAND
修改环境变量那部分
//#undef CONFIG_ENV_IS_IN_FLASH      1
#define CONFIG_ENV_IS_IN_NAND 1
其次,修改cpu/arm920t/start.S这个文件,使u-boot从Nand Flash启动
为了让他自动识别是从norflash还是从nandflash启动添加,BWSCON的第2,1为即OM1,OM0。为00时是从nandflash启动,其他为从norflash启动,判断OM1和OM0,就可以让uboot自动识别启动方式。
#define BWSCON 0x48000000
       ldr r0, =BWSCON
       ldr r1,[r0]
       ands r1, r1, #0x6
       beq nand_boot
nor_boot:
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
添加nandflash的启动代码,核心是relocated部分。首先设置nandflash控制器,然后将nandflash中从0开始的uboot复制到SDRAM中的TEXT_BASE处,TEXT_BASE在config.mk中定义,值为0x33f80000。复制好后,比较nandflash和SDRAM中的数据,如果前4K相同,表示搬移成功。下面的汇编代码注意ATPC标准规定r0~r3,用于参数传递和返回值。
/********************************************************/
//#define CONFIG_S3C2440_NAND_BOOT 1

nand_boot:
#define CONFIG_S3C2440_NAND_BOOT 1
#define NAND_CTL_BASE 0x4E000000
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20
#define LENGTH_UBOOT 0x40000
    @ reset NAND

    mov    r1, #NAND_CTL_BASE
    ldr    r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
    str    r2, [r1, #oNFCONF]
    ldr    r2, [r1, #oNFCONF]
   
    ldr    r2, =((1<<4)|(0<<1)|(1<<0) )    @ Active low CE Control
    str    r2, [r1, #oNFCONT]
    ldr    r2, [r1, #oNFCONT]
   
    ldr    r2, =(0x6)    @ RnB Clear
    str    r2, [r1, #oNFSTAT]
    ldr    r2, [r1, #oNFSTAT]
   
    mov    r2, #0xff    @ RESET command
    strb    r2, [r1, #oNFCMD]
   
    mov    r3, #0    @ wait
nand1:
    add    r3, r3, #0x1
    cmp    r3, #0xa
    blt    nand1
nand2:
    ldr    r2, [r1, #oNFSTAT]    @ wait ready
    tst    r2, #0x4
    beq    nand2
   
    ldr    r2, [r1, #oNFCONT]
    orr    r2, r2, #0x2    @ Flash Memory Chip Disable
    str    r2, [r1, #oNFCONT]
   
    @ get read to call C functions (for nand_read())
    ldr    sp, DW_STACK_START    @ setup stack pointer
    mov    fp, #0    @ no previous frame, so fp=0

    @ copy U-Boot to RAM
    ldr    r0, =TEXT_BASE               //传递给C代码的第一个参数:u-boot在RAM中的起始地址
    mov    r1, #0x0                        //传递给C代码的第二个参数:Nand Flash的起始地址
    mov    r2, #LENGTH_UBOOT    //传递给C代码的第三个参数:u-boot的长度大小
/**********************************************************/
/************************************************************/

    bl    nand_read_ll
    tst    r0, #0x0
    beq    ok_nand_read
bad_nand_read:
loop2:
    b    loop2    @ infinite loop
ok_nand_read:
    @ verify
    mov    r0, #0
    ldr    r1, =TEXT_BASE
    mov    r2, #0x400    @ 4 bytes * 1024 = 4K-bytes
go_next:
    ldr    r3, [r0], #4
    ldr    r4, [r1], #4
    teq    r3, r4
    bne    notmatch
    subs    r2, r2, #4
    beq    stack_setup
    bne    go_next
notmatch:
loop3:
    b    loop3    @ infinite loop
#endif
        
       /* Set up the stack                                            */
stack_setup:

       ldr   r0, _TEXT_BASE          /* upper 128 KiB: relocated uboot   */
       sub r0, r0, #CONFIG_SYS_MALLOC_LEN       /* malloc area                      */
       sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
       sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
       sub sp, r0, #12           /* leave 3 words for abort-stack    */

clear_bss:
       ldr   r0, _bss_start             /* find start of bss segment        */
       ldr   r1, _bss_end              /* stop here                        */
       mov r2, #0x00000000        /* clear                            */

clbss_l:str     r2, [r0]          /* clear loop...                    */
       add r0, r0, #4
       cmp r0, r1
       ble  clbss_l

       ldr   pc, _start_armboot

_start_armboot:  .word start_armboot
#define STACK_BASE 0x33ff8000
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
在board/samsung/TE2440II/目录下添加nand_read.c文件,内容如下,在K9F2G08的datasheet中有这么一段


所以地址由5个周期传完。前两个周期用来寻页内地址。后三个周期是页间寻址。1device=2048block=2048*64page=2048*64*(2k+64)Bytes
#include <config.h>
#include <linux/mtd/nand.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGw(x) (*(volatile unsigned short *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE  0x4e000000
#define NFCONF  __REGi(NF_BASE + 0x0)
#define NFCONT  __REGi(NF_BASE + 0x4)
#define NFCMD  __REGb(NF_BASE + 0x8)
#define NFADDR  __REGb(NF_BASE + 0xc)
#define NFDATA  __REGb(NF_BASE + 0x10)
#define NFDATA16 __REGw(NF_BASE + 0x10)
#define NFSTAT  __REGb(NF_BASE + 0x20)
#define NFSTAT_BUSY (1 << 2)
#define nand_select() (NFCONT &= ~(1 << 1))
#define nand_deselect() (NFCONT |= (1 << 1))
#define nand_clear_RnB() (NFSTAT |= NFSTAT_BUSY)
static inline void nand_wait(void)
{
  int i;
while (!(NFSTAT & NFSTAT_BUSY))
  for (i=0; i<10; i++);
}
/* configuration for 2440 with 2048byte sized flash */
#define NAND_5_ADDR_CYCLE
#define NAND_PAGE_SIZE  2048
#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
#define NAND_BLOCK_MASK  (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE  (NAND_PAGE_SIZE * 64)
static int nand_read_page_ll(unsigned char *buf, unsigned long addr)
{
unsigned int i, page_num;
nand_clear_RnB();
NFCMD = NAND_CMD_READ0;
page_num = addr >> 11; /* addr / 2048 */
/* Write Address */
NFADDR = 0;
NFADDR = 0;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART;
nand_wait();
for (i = 0; i < NAND_PAGE_SIZE; i++)
{
  *buf = (NFDATA & 0xff);
  buf++;
}
return NAND_PAGE_SIZE;
}
/* low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;
    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
    {
     return -1;    /* invalid alignment */
    }
  /* chip Enable */
nand_select();
nand_clear_RnB();
for (i=0; i<10; i++);
for (i=start_addr; i < (start_addr + size);)
{
  j = nand_read_page_ll(buf, i);
  i += j;
  buf += j;
}
  /* chip Disable */
nand_deselect();
  return 0;
}
然后在Makefile中添加
COBJS    := my2440.o flash.o nand_read.o
修改TE2440II下的链接脚本u-boot.lds,使初始化和重定位代码被链接到前4KB。
.text :
{
    cpu/arm920t/start.o    (.text)
    board/samsung/my2440/lowlevel_init.o (.text)
    board/samsung/my2440/nand_read.o (.text)
    *(.text)
}

支持东华 3.5寸LCD输出console信息和BMP图片、logo
由于linux启动代码,仍然出现乱码,而我将启动信息输出到lcd就没有乱码。暂时这个问题还没有解决,lcd其实早已完成,今天整理下,再解决那个问题。

下面是我绘制的主要的lcd驱动调用流程图。start_armboot()在lib_arm/board.c中,stdio_init()在common/stdio.cdrv_video_init(),video_init(),video_logo (),video_fb_address()在drivers/video/cfb_console.c中,video_hw_init()在drivers/video/s3c2410_fb.c中,board_video_init()在board/samsung/TE2440II/TE2440II.c。



最终调用了board_video_init()函数,这个函数由我们自己来编写,由于以前写过裸机的lcd程序,所以时序就可以直接拿来用,不用调了,哈哈。在这个函数中主要还是对那5个lcd的控制寄存器进行初始化。这里要注意根据不同的屏,进行x,y的调整,我用的是东华WXCAT35-TG3#001,主要就是初始化一个GraphicDevice *pGD结构体。


view plaincopy to clipboardprint?
#define MVAL        (0)  
#define MVAL_USED   (0)     //0=each frame   1=rate by MVAL  
#define INVVDEN     (0)     //0=normal       1=inverted  
#define BSWP        (0)     //Byte swap control  
#define HWSWP       (0)     //Half word swap control  
//TFT 240320  
#define LCD_XSIZE_TFT_240320    (320)     
#define LCD_YSIZE_TFT_240320    (240)  
//TFT240320  
#define HOZVAL_TFT_240320   (LCD_XSIZE_TFT_240320-1)  
#define LINEVAL_TFT_240320  (LCD_YSIZE_TFT_240320-1)  
//Timing parameter for WXCAT35-TG3#001"  
#define VBPD_240320     (3)       
#define VFPD_240320     (5)  
#define VSPW_240320     (15)  
#define HBPD_240320     (58)  
#define HFPD_240320     (15)  
#define HSPW_240320_WXCAT35 (8)  //Adjust the horizontal displacement of the screen   
#define CLKVAL_TFT_240320   (7)       
//FCLK=405MHz,HCLK=101.25MHz,VCLK=4602272Hz  
void board_video_init(GraphicDevice *pGD)   
{   
    S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD();   
      S3C2410_NAND * const nand = S3C2410_GetBase_NAND();  
    /* FIXME: select LCM type by env variable */   
       
    /* Configuration for GTA01 LCM on QT2410 */   
    lcd->LCDCON1 = 0x00000778; /* CLKVAL=7, BPPMODE=16bpp, TFT, ENVID=0 */   
    lcd->LCDCON2 = (VBPD_240320<<24)|(LINEVAL_TFT_240320<<14)|(VFPD_240320<<6)|(VSPW_240320);   
    lcd->LCDCON3 = (HBPD_240320<<19)|(HOZVAL_TFT_240320<<8)|(HFPD_240320);   
    lcd->LCDCON4 = (MVAL<<8)|(HSPW_240320_WXCAT35);  
    lcd->LCDCON5 = 0x00000f09;   
    lcd->LPCSEL  = 0x00000000;   
}  


明白上边的流程后一切变得很简单,只要根据自己的屏调整好时序就行了。添加一个驱动文件这个是一个外国的牛人已经写好的。在drivers/video/下添加s3c2410_fb.c。代码如下:

view plaincopy to clipboardprint?
/* 
* (C) Copyright 2006 by OpenMoko, Inc. 
* Author: Harald Welte <[email protected]

* This program is free software; you can redistribute it and/or 
* modify it under the terms of the GNU General Public License as 
* published by the Free Software Foundation; either version 2 of 
* the License, or (at your option) any later version. 

* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
* GNU General Public License for more details. 

* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
* MA 02111-1307 USA 
*/  
#include <common.h>  
#if defined(CONFIG_VIDEO_S3C2410)  
#include <video_fb.h>  
#include "videomodes.h"  
#include <s3c2410.h>  
/* 
* Export Graphic Device 
*/  
GraphicDevice smi;  
#define VIDEO_MEM_SIZE 0x200000 /* 240x320x16bit = 0x25800 bytes */  
extern void board_video_init(GraphicDevice *pGD);  
/******************************************************************************* 

* Init video chip with common Linux graphic modes (lilo) 
*/  
void *video_hw_init (void)  
{  
S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD();  
GraphicDevice *pGD = (GraphicDevice *)&smi;  
int videomode;  
unsigned long t1, hsynch, vsynch;  
char *penv;  
int tmp, i, bits_per_pixel;  
struct ctfb_res_modes *res_mode;  
struct ctfb_res_modes var_mode;  
// unsigned char videoout;  
/* Search for video chip */  
printf("Video: ");  
tmp = 0;  
videomode = CFG_SYS_DEFAULT_VIDEO_MODE;  
/* get video mode via environment */  
if ((penv = getenv ("videomode")) != NULL) {  
/* deceide if it is a string */  
if (penv[0] <= '9') {  
videomode = (int) simple_strtoul (penv, NULL, 16);  
tmp = 1;  
}  
} else {  
tmp = 1;  
}  
if (tmp) {  
/* parameter are vesa modes */  
/* search params */  
for (i = 0; i < VESA_MODES_COUNT; i++) {  
if (vesa_modes.vesanr == videomode)  
break;  
}  
if (i == VESA_MODES_COUNT) {  
printf ("no VESA Mode found, switching to mode 0x%x ",  
CFG_SYS_DEFAULT_VIDEO_MODE);  
i = 0;  
}  
res_mode =  
(struct ctfb_res_modes *) &res_mode_init[vesa_modes.  
resindex];  
bits_per_pixel = vesa_modes.bits_per_pixel;  
}   
else {  
res_mode = (struct ctfb_res_modes *) &var_mode;  
bits_per_pixel = video_get_params (res_mode, penv);  
}  
/* calculate hsynch and vsynch freq (info only) */  
t1 = (res_mode->left_margin + res_mode->xres +  
res_mode->right_margin + res_mode->hsync_len) / 8;  
t1 *= 8;  
t1 *= res_mode->pixclock;  
t1 /= 1000;  
hsynch = 1000000000L / t1;  
t1 *=  
(res_mode->upper_margin + res_mode->yres +  
res_mode->lower_margin + res_mode->vsync_len);  
t1 /= 1000;  
vsynch = 1000000000L / t1;  
/* fill in Graphic device struct */  
sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,  
res_mode->yres, bits_per_pixel, (hsynch / 1000),  
(vsynch / 1000));  
printf ("%s\n", pGD->modeIdent);  
pGD->winSizeX = res_mode->xres;  
pGD->winSizeY = res_mode->yres;  
pGD->plnSizeX = res_mode->xres;  
pGD->plnSizeY = res_mode->yres;  
switch (bits_per_pixel) {  
case 8:  
pGD->gdfBytesPP = 1;  
pGD->gdfIndex = GDF__8BIT_INDEX;  
break;  
case 15:  
pGD->gdfBytesPP = 2;  
pGD->gdfIndex = GDF_15BIT_555RGB;  
break;  
case 16:  
pGD->gdfBytesPP = 2;  
pGD->gdfIndex = GDF_16BIT_565RGB;  
break;  
case 24:  
pGD->gdfBytesPP = 3;  
pGD->gdfIndex = GDF_24BIT_888RGB;  
break;  
}  
/* statically configure settings */  
pGD->winSizeX = pGD->plnSizeX = 320;  
pGD->winSizeY = pGD->plnSizeY = 240;  
pGD->gdfBytesPP = 2;  
pGD->gdfIndex = GDF_16BIT_565RGB;  
pGD->frameAdrs = LCD_VIDEO_ADDR;  
pGD->memSize = VIDEO_MEM_SIZE;  
board_video_init(pGD);  
lcd->LCDSADDR1 = pGD->frameAdrs >> 1;  
/* This marks the end of the frame buffer. */  
lcd->LCDSADDR2 = (lcd->LCDSADDR1&0x1fffff) + (pGD->winSizeX+0) * pGD->winSizeY;  
lcd->LCDSADDR3 = (pGD->winSizeX & 0x7ff);  
/* Clear video memory */  
memset((void *)pGD->frameAdrs, 0, pGD->memSize);  
/* Enable Display */  
lcd->LCDCON1 |= 0x01; /* ENVID = 1 */  
return ((void*)&smi);  
}  
void  
video_set_lut (unsigned int index, /* color number */  
unsigned char r, /* red */  
unsigned char g, /* green */  
unsigned char b /* blue */  
)  
{  
}  
#endif /* CONFIG_VIDEO_S3C2410 */  

在你的配置头文件中添加如下宏定义:

view plaincopy to clipboardprint?
#define CONFIG_CMD_BMP  
#define CONFIG_VIDEO  
#define CONFIG_VIDEO_S3C2410  
#define CONFIG_VIDEO_LOGO  
#define VIDEO_FB_16BPP_PIXEL_SWAP  
#define CONFIG_VIDEO_SW_CURSOR  
#define CONFIG_VIDEO_BMP_LOGO  


这样就基本完成了,重新启动一下是不是就显示出samsung的logo了。如果先改成自己喜欢的图片,修改tools/logos/denx.bmp,记住一定是是8bpp的bmp图,修改Makefile文件,修改/tools目录下的Makefile文件,大约是44~46行,

view plaincopy to clipboardprint?
ifeq ($(LOGO_BMP),)  
LOGO_BMP= logos/denx.bmp  
endif  
把 denx.bmp 替换为你需要显示的logo图片的文件名,保存退出,重新编译uboot。图片的转化方法,在终端输入命令:
jpegtopnm $1 | ppmquant 31 | ppmtobmp -bpp 8 > $2
使用方法: (脚本名) ( 待处理的JPG图片名) (输出文件名)
这样就可以显示出你自己喜欢的logo图片了。

如果想将串口的打印信息显示在lcd上,添加环境变量。

view plaincopy to clipboardprint?
#define CONFIG_EXTRA_ENV_SETTINGS   \                 
    "stdin=serial\0"        \             
    "stdout=vga"            \  
    "stderr=serial\0"       \             


只要让stdout等于vga就可以了。在lib_arm/board.c文件中可以看到console_init初始化两次,我们修改的影响第二次的初始化,第一次的不影响,所以还会有部分输出信息显示在串口上的。Lcd就到这里,有什么问题我再及时改正吧。

Linux 2.6.30.4移植TE2440II开发板 
宿主机:ubuntu9.10
目标机:s3c2440
交叉编译器:arm-linux-gcc-4.3.2
交叉编译器路径:/usr/local/arm/4.3.2
要移植的内核版本:linux-2.6.30.4
文件系统类型: yaffs2

步骤包括:

1)给linux内核打上yaffs2补丁

2)修改机器码

3)修改目标板的arch和编译器路径,

4)增加devfs文件管理器支持

5)修改晶振频率

6)修改MTD分区

7)关闭ECC校验

8)修改nandflash驱动

9)配置内核

首先,从官网上下载linux-2.6.30.4的内核。
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/可以找到。

新建目录mkdir /home/haker,将内核源码包解压到hacker/目录下

tar –zxvf linux-2.6.30.4.tar.gz

1)给内核打jaffs2补丁

下载最新的驱动http://www.aleph1.co.uk/cgi-bin/ ... fs2.tar.gz?view=tar 

解压到/home/hacker/下

tar –zxvf yaffs2.tar.gz

进入目录

cd yaffs2

给内核打补丁

./patch-ker.sh c /home/hacker/linux-2.6.30.4

加上c 他会自动解压到后面的目录中

成功后会打印信息:

Updating /home/hacker/linux-2.6.30.4/fs/Kconfig

Updating /home/hacker/linux-2.6.30.4/fs/Makefile

2)修改机器码

暂时我使用的是飞凌的boot,自己的boot还没有完全做好,飞凌boot的默认机器码是193,修改arch/arm/tools/mach-types,将

s3c2410 ARCH_S3C2410 S3C2410 193  删掉

然后将

s3c2440 ARCH_S3C2440 S3C2440 362

修改为  
s3c2440 ARCH_S3C2440 S3C2440 193

3)修改目标板的arch和编译器路径

修改linux/2.6.30.4下的Makefile将

ARCH ?= $(SUBARCH)

CROSS_COMPILE ?=

修改成

ARCH ?= arm

CROSS_COMPILE ?= /usr/local/arm/4.3.2/bin/arm-linux-

4)增加devfs文件管理器支持

修改fs/Kconfig,找到

menu “Pseudo filesystems”

添加

config DEVFS_FS

      bool “/dev file system support (OBSOLETE)”

      default y

config DEVFS_MOUNT

bool “Automatially mount at bool”

default

depends on DEVFS_FS

5)修改晶振频率

arch/arm/mach-s3c2440/mach-smdk2440.c

/*s3c24xx_init_clocks(16934400);*/  s3c24xx_init_clocks(12000000); 

6)修改MTD分区,由于自己的uboot还没有完全做好,暂时用飞凌的boot的分区,

修改文件arch/arm/plat-s3c24xx/common-smdk.c

static struct mtd_partition smdk_default_nand_part[] = {

        [0] = {

                .name        = "Boot",

                .size        = 0x00100000,

                .offset = 0

        },

        [1] = {

                .name        = "MyApp",

                .size        = 0x003c0000,

                .offset = 0x00140000,

        },

        [2] = {

                .name        = "Kernel",

                .size        = 0x00300000,

                .offset = 0x00500000,

        },

        [3] = {

                .name        = "fs_yaffs",

                .size        = 0x03c00000,         //60M

                .offset = 0x00800000,

        },       

        [4] = {

                .name        = "WINCE",

                .size        = 0x03c00000,

                .offset = 0x04400000,

        }

};

7)关闭ECC校验

文件drivers/mtd/nand/s3c2410.c

函数:s3c2410_nand_init_chip

/*chip->ecc.mode = NAND_ECC_SOFT; */  chip->ecc.mode = NAND_ECC_NONE;

这个有两个 软件校验和硬件校验都要关掉

8)修改nandflash驱动,修改drivers/mtd/nand下面的nand_bbt.c文件:

static struct nand_bbt_descr largepage_memorybased = {

        .options = 0,

        .offs = 0,

        .len = 1,           // 原数值为2,支持2K每页的flash修改为1。K9F1G08,K9F2G08是2k每页的flash

        .pattern = scan_ff_pattern

};

static struct nand_bbt_descr largepage_flashbased = {

        .options = NAND_BBT_SCAN2NDPAGE,

        .offs = 0,

        .len = 1,           //原数值为2,支持2K每页的flash修改为1。K9F1G08,K9F2G08是2k每页的flash

        .pattern = scan_ff_pattern

};

9)配置内核

make menuconfig
首先加载s3c24xx系列的通用配置,然后在此基础上修改
配置完后将配置文件保存为.config,这样方便下次make menuconfig时默认加载上次配置过的文件

交叉编译内核

make zImage

如果没有任何错误,编译出来的内核在arch/arm/boot/目录下,文件zImage即是。

基于busybox1.15.0的yaffs2文件系统移植TE2440II开发板
首先说一下各个知识点:
使用的busybox是1.15.0。什么是busybox呢,busybox是很多标准linux一个单个可执行实现,很多标准linux工具都可以共享很多共同的元素。例如,很多基于文件的元素(比如grep和find)都需要在文件中搜索文件的代码。当这些工具被合并到一个可执行程序中时,他们就可以共享这些相同的元素,这样可以产生更小的可执行程序。实际上,busybox可以将大约3.5M的工具包装成大约200KB大小。这就为引导盘和嵌入式linux设备提供了更多的工具。我们可以对2.4或2.6版本的linux内核使用这个工具。
几个常用的make选项:
make clean 清除源代码树
make distclean 彻底清除源代码树
make menuconfig N-curses(基于菜单的)配置工具
make defconfig 启用默认的(通用)配置
make config 基于菜单的配置工具
uClibc与glibc。CC的标准就是glibc这个库,里边有GCC各种标准函数的实现,使用uClibc,这是一个对大小进行优化过的C库,它为嵌入式系统开发。
根文件系统前面加一个“根”字,说明它是加载其他文件系统的根,既然是根,那么如果没有这个根,其他文件系统就没法加载。他包括系统引导和其他文件系统挂载所必须的文件,根文件系统包括Linux启动所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在Linux挂载分区时Linux一定会找到/etc/fstab这个挂载文件等,根文件系统还包括了应用程序bin目录等。

1)Jffs2

JFFS嵌入式系统文件系统最早是由瑞典 Axis Communications公司基于Linux2.0的内核为嵌入式系统开发的文件系统。JFFS2是RedHat公司基于JFFS开发的闪存文件系统,最初是针对RedHat公司的嵌入式产品eCos开发的嵌入式文件系统,所以JFFS也可以用于Linux,uCLinux中。

Jffs2:日志闪存嵌入式系统文件系统版本2(Journalling Flash FileSystem v2)主要用于NOR型闪存,基于MTD驱动层,特点是,可读写的,支持数据压缩的,基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。缺点主要是当文件系统已经满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。

2)Yaffs Yet Another Flash File System

Yaffs/yaffs2是专门为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统。与jffs2相比,它减少一些功能(例如不支持数据压缩),所以速度更快,挂载时间更短,对内存的占用较小。另外他是跨平台的文件系统,除了Linux和eCos,还支持WinCE,pSOS和ThreadX等。

Yaffs/yaffs自带NAND芯片驱动,并且为嵌入式提供了直接访问文件系统的API,用于可以不使用Linux中的MTD与VFS,直接对文件系统操作。

3)Cramfs

Cramfs是Linux的创始人Linux Torvalds参与开发的一种只读的压缩文件系统。他也基于MTD驱动程序。在cramfs文件系统中,每一页(4KB)被压缩,可以随机页访问,其压缩比高达2:1,为嵌入式系统节省了大量的Flash存储空间,使系统可通过更低容量的FLASH存储相同的文件,从而降低系统成本。Cramfs文件系统以压缩方式存储,在运行时解压缩。

4)NFS

NFS是由Sun开发并发展起来的一项不同机器,不同操作系统之间通过网络共享文件的技术 

然后开始操作:
一.
给内核打上补丁,使内核对yaffs2文件系统支持。
下载最新的驱动http://www.aleph1.co.uk/cgi-bin/ ... fs2.tar.gz?view=tar 
解压:
tar zxvf yaffs2.tar.gz
cd yaffs2
./patch-ker.sh  c  /home/hacker/linux-2.6.30.4
成功后打印信息:
1.      Updating /file/fl/linux-2.6.33/fs/Kconfig
2.      Updating /file/fl/linux-2.6.33/fs/Makefile
进入linux-2.6.30.4目录,把s3c2410的默认配置写入config文件。
1.      make s3c2410_defconfig
配置文件系统选项
配置yaffs2文件系统 
修改配置如下:
1.      File systems  ---> 
2.         

  • Miscellaneous filesystems  --->
    3.              <*>   YAFFS2 file system support 
    4.                  -*-     512 byte / page devices
    5.                  -*-     2048 byte (or larger) / page devices 
    6.                     
  •        Autoselect yaffs2 format 
    7.                     
  •      Cache short names in RAM
    二:
    编译busybox生成文件系统所需要的应用程序
    1.解压busybox源码,修改Makefile使之编译成ARM平台:
    #tar -jxvf busybox-1.15.0.tar.tar
    #cd busybox-1.15.0
    #gedit Makefile
    修改CROSS_COMPILE ?= arm-linux- ARCH = arm
    2.配置busybox,下面是一个人配置的busybox 1.13.0,借来参考,基本差不多。
    make menuconfig
    Busybox Settings --->
        General Configuration --->
                Buffer allocation policy (Allocate with Malloc) --->
            
  • Show verbose applet usage messages
            
  • Store applet usage messages in compressed form
            
  • Support --install [-s] to install applet links at runtime
            
  • Enable locale support (system needs locale for this to work)
            
  • Support for --long-options
            
  • Use the devpts filesystem for Unix98 PTYs
            
  • Support writing pidfiles
            
  • Runtime SUID/SGID configuration via /etc/busybox.conf
            
  • Suppress warning message if /etc/busybox.conf is not readable
            (/proc/self/exe) Path to BusyBox executable
        Build Options --->
            
  • Build BusyBox as a static binary (no shared libs)
            
  • Build with Large File Support (for accessing files > 2 GB)
        Installation Options --->
            [ ] Don't use /usr
                Applets links (as soft-links) --->
            (./_install) BusyBox installation prefix
        Busybox Library Tuning --->
            (6) Minimum password length
            (2) MD5: Trade Bytes for Speed
            
  • Faster /proc scanning code (+100 bytes)
            
  • Command line editing
            (1024) Maximum length of input
            
  • vi-style line editing commands
            (15) History size
            
  • History saving
            
  • Tab completion
            
  • Fancy shell prompts
            (4) Copy buffer size, in kilobytes
            
  • Use ioctl names rather than hex values in error messages
            
  • Support infiniband HW
    Linux Module Utilities --->
        (/lib/modules) Default directory containing modules
        (modules.dep) Default name of modules.dep
       
  • insmod
       
  • rmmod
       
  • lsmod
       
  • modprobe
        --- Options common to multiple modutils
        [ ] Support version 2.2/2.4 Linux kernels
       
  • Support tainted module checking with new kernels
       
  • Support for module.aliases file
       
  • Support for module.symbols fileLinux System Utilities --->
    3.编译和安装busybox:
    make;make install
    安装好后会在busybox-1.15.0/_install/目录下生成:bin,linuxrc,sbin,usr。
    4.开始构建文件系统
    1)创建一个root_2.6.30.4目录,把busybox-1.15.0/_install/目录下的复制过来,并在该目录下创建文件系统所需要的其他目录。
    #mkdir root-2.6.30.4
    #cp -rf busybox-1.15.0/_install/* root-2.6.30.4/
    #cd root-2.6.30.4/
    #mkdir dev etc home lib mnt opt proc tmp var
    2)添加必须的文件,文件和文件夹都用chmod 777 xxx,修改权限
    "dev"目录,创建两个设备文件:
    #mknod console c 5 1
    #mknod null c 1 3
    etc"目录,创建各种配置文件并向里面添加内容,没有列出的就不用添加:
    group: 系统用户组配置文件,内容如下:
    root:*:0:
    daemon:*:1:
    bin:*:2:
    sys:*:3:
    adm:*:4:
    tty:*:5:
    disk:*:6:
    lp:*:7:lp
    mail:*:8:
    news:*:9:
    uucp:*:10:
    proxy:*:13:
    kmem:*:15:
    dialout:*:20:
    fax:*:21:
    voice:*:22:
    cdrom:*:24:
    floppy:*:25:
    tape:*:26:
    sudo:*:27:
    audio:*:29:
    ppp:x:99:
    500:x:500:plg
    501:x:501:fa
    inittab: 系统init进程配置文件,内容如下:
    # /etc/inittab
    ::sysinit:/etc/init.d/rcS
    console::askfirst:-/bin/sh
    ::ctrlaltdel:/sbin/reboot
    ::shutdown:/bin/umount -a –r
    passwd: 系统密码文件,内容如下:
    root::0:0:root:/:/bin/sh
    ftp::14:50:FTP User:/var/ftp:
    bin:*:1:1:bin:/bin:
    daemon:*:2:2:daemon:/sbin:
    nobody:*:99:99:Nobody:/:
    hacker::502:502:Linux User,,,:/home/hacker:/bin/sh
    sysconfig/HOSTNAME: 主机名称文件,内容如下:
    TE2440II
    注意HOSTNAME是文件名,TE2440II是文件中的内容。
    fstab: 系统挂载文件系统列表,内容如下:

    # device  mount-point   type     options     dump   fsck order
    none      /proc         proc     defaults    0      0
    none      /dev/pts      devpts   mode=0622   0      0
    tmpfs     /dev/shm      tmpfs    defaults    0      0
    init.d/rcS: 系统启动加载项,内容如下:

    #!/bin/sh

    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    runlevel=S
    prevlevel=N
    umask 022
    export PATH runlevel prevlevel

    #
    #    Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
    #
    /bin/mount -t proc none /proc
    /bin/mount -t tmpfs none /tmp
    /bin/mount -t tmpfs none /var

    /bin/mkdir -p /var/log

    /bin/hostname -F /etc/sysconfig/HOSTNAME
    profile: 用户环境配置文件,内容如下:
    # Ash profile 
    # vim: syntax=sh
    # No core files by default
    #ulimit -S -c 0 > /dev/null 2>&1
    USER="`id -un`"
    LOGNAME=$USER
    PS1='[\u@\h \W]\# '
    PATH=$PATH:/usr/local/bin
    LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
    HOSTNAME=`/bin/hostname`
    export USER LOGNAME PS1 PATH LD_LIBRARY_PATH
    resolv.conf: DNS配置文件,内容如下:
    nameserver 61.144.56.100
    "home"目录:创建一个hacker目录,与etc目录passwd文件中的hacker相对应
    "lib"目录:这个里面放的都是库文件,直接从交叉编译器的库文件目录中拷贝过来:
    #cp -f /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/*so* lib/ -a
    6. 使用yaffs制作工具编译构建好的文件系统。使用mkyaffs2image,复制到/usr/sbin/目录下,给予777权限。
    然后mkyaffs2image root-2.6.30.4 root-2.6.30.4.bin
    注意一个路径是这样的 /etc/init.d/rcS, rcS是文件
    Kernel panic - not syncing: Attempted to kill init! 
      上网搜索了一些相关信息,找到了解决问题的途径。 原因在于:编译内核和busybox使用的编译器是arm-linux-gcc 4.3.2,而这个编译器默认是打开“EABI选项”的,这样编译出来的busybox就是EABI的。但是内核编译的时候,默认是把“EABI选项”关掉的。所以busybox和内核无法正常配合。把“EABI选项”打开,重新编译内核后,一切正常。
    Kernel Features  --->
  • Use the ARM EABI to compile the kernel
  •    Allow old ABI binaries to run with this kernel (EXPERIMENTAL) (NEW)


  • 你可能感兴趣的:(最详尽的ARM+LINUX移植攻略 linux2.6.30.4内核+yaffs2文件系统+uboot 2009.08)