成都学生兼职网:u-boot-1.3.4在S3C2410上的移植

来源:百度文库 编辑:中财网 时间:2024/05/05 15:02:31
首先声明本移植文档大部文来自韦东山大哥的<<嵌入式linux完全开发手册>>一书,特此声明!。
首先介绍一下开发板用的优龙的fs2410开发板。硬件资源有:
BANK0外接容量为2M,位宽为16的NOR FLASH 芯片 SST39VF1601。
BANK3外结10M网卡芯片CS8900A,位宽为16。
通过NAND FLASH的控制器外接容量为64MB,位宽为8的NAND FLASH芯片k9f1208u0m。
BANK6外接两片容量为32MB,位宽为16的SDRAM芯片K4S561632,组成容量为64MB,位宽为32的内存。
由于U-BOOT的SMDK2410本身支持了NORFLASH AM29LV800,但我们的是SST39VF1601,这里我们可以直接修改这个文件,或者在源码里找到SST39VF1601的驱动。这里我们都尝试作一下。然后就是支持NAND FLASH的读写,和支持yaffs文件系统镜像的烧写。并支持xmodem协议。
我们将在开发板SMDK2410的基础上进行移植

1。新建一个开发板的相应目录和文件。
为了不破坏源代码,将关于SMDK2410相关的文件和目录都拷贝一份。并且设置好交叉编译器的环境变量。
这里将board/smdk2410复制拷贝一份为board/fs2410。然后将board/fs2410/smdk2410.c文件修改为board/fs2410/fs2410.c,并将include/configs/smdk2410.h复制拷贝一份为include/configs/fs2410.h。
修改顶层Makefile,添加如下两行:
可以在:
smdk2410_config :   unconfig
    @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
后添加:
fs2410_config   :   unconfig
    @$(MKCONFIG) $(@:_config=) arm arm920t fs2410 NULL s3c24x0
将:
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
endif
修改为:
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-softfloat-linux-gnu- (arm gcc 为3.4.5)
endif

然后修改board/fs2410/Makefile,修改如下:
COBJS   := smdk2410.o flash.o
修改为:
COBJS   := fs2410.o flash.o

2.修改SDRAM的配置
SDRAM的初始化在第一阶段完成,就是在board/fs2410/lowlevel_init.S文件中设置存储控制器。由于我们的SDRAM外接在BANK6上,所以检查一下BANK6的设置:位宽为32,宏 B6_BWSCON 为      (DW32),32位,另外还要根据HCLK设置SDRAM的刷新参数,主要是REFCNT寄存器。由于本开发板使用的HCLK为100MHz,需要SDRAM芯片的具体参数重新计算REFCNT的数值:
#define REFCNT          1113    /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
改为:
(参考K4S561632手册“8192 refresh cycles / 64ms”可知刷新的周期为:7.8125us)
#define REFCNT          1268    /* period=7.8125us, HCLK=100Mhz, (2048+1-7.8125*100) */
对于BANK3外接了CS8900A,原来的配置是符合的,无须更改,而对于BANK1,BANK2,BANK4,BANK5,BANK7,没有使用,所以在U-BOOT也不用关心。

3。时钟的配置
在board/fs2410/fs241.c的board_init函数,首先修改为异步总线模式:
具体修改在clk_power->LOCKTIME = 0xFFFFFF;之前加上:
__asm__ ("mrc p15,0,r1,c1,c0,0\n"
            "orr r1,r1,#0xc0000000\n"
            "mcr p15,0,r1,c1,c0,0\n"
            :::"r1"
            );
这里的设置在手册里说明了:如果HDIVN=1,CPU的总线模式应该从the fast bus mode变为the asynchronous bus mode,可以通过上述指令完成,如果HDIVN=1,而CPU的总线模式仍为the fast bus mode,则CPU的工作频率将自动变为HCLK,而不再是FCLK。

4。串口的初始化
在U-BOOT的第二阶段lib_arm/board.c中start_armboot函数调用serial_init函数(cpu/arm920t/s3c24x0/serial.c)初始化串口时,会调用get_PCLK函数( cpu/arm920t/s3c24x0/speed.c),这里把时钟设置好就行了。如果你是在移植s3c2440,这个地方是需要修改的。主要频率是不一样的。

     至此,编译执行make fs2410_config && make CROSS_COMPILE=arm-softfloat-linux-gnu-编译生成的u-boot.bin,下载到板子的NOR FLASH,就有答应信息了。下面介绍怎么样支持SST39VF1601 NOR FLASH和怎么样支持NAND FLASH的读写和支持串口xmodem协议。

U-Boot 1.3.4 (Oct 30 2009 - 16:21:38)

DRAM: 64 MB
Flash: 512 kB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
SMDK2410 #

5。支持NOR FLASH(SST39VF1601)
现在还无法通过U-BOOT的命令来烧写NOR FLASH,在配置文件include/configs/fs2410.h里默认的信号是AM29LV400,而我们的是SST39VF1601。修改如下(include/configs/fs2410.h):
添加:
#define CONFIG_SST_39VF1601   1
#define CFG_MAX_FLASH_BANKS 1
#define PHYS_FLASH_SIZE       0x200000   /* 2MB */
#define CFG_MAX_FLASH_SIZE    (512)       /* max number of sectors on one chip */
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x40000)   /* addr of environment */
并将关于AM29LV400和AM29LV800的信息全部注释掉。
NOR FLASH的操作函数在board/fs2410/flash.c中实现。它支持AM29LV400和AM29LV800.为了了解NORFLASH的操作,我们直接修改这个文件。首先我们的板子已经有了一个U-BOOT,但由于烧写的问题,我们这里启动一个调试方法,具体就是在配置文件include/configs/fs2410.h里定义:
#define CONFIG_SKIP_LOWLEVEL_INIT,这个宏用于cpu/arm920t/start.S里,主要是对CPU和存储控制器的初始化,所以调试阶段跳过初始化。然后修改board/fs2410/config.mk:
将TEXT_BASE = 0x33F80000暂时修改为:
TEXT_BASE = 0x33E00000。最后将u-boot.bin下载到这个地址,然后 从这个地址启动u-boot即可。
修改以上步骤以后,接下来我们修改board/fs2410/flash.c:
将:
#define MAIN_SECT_SIZE 0x10000 /* 64 KB */
修改为:
#define MAIN_SECT_SIZE 0x1000 /* 4 KB */(按sector操作)

将:
#define MEM_FLASH_ADDR1     (*(volatile u16 *)(CFG_FLASH_BASE + (0x00000555 << 1)))
#define MEM_FLASH_ADDR2     (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002AA << 1)))
修改为:
#define MEM_FLASH_ADDR1     (*(volatile u16 *)(CFG_FLASH_BASE + (0x000005555 << 1)))
#define MEM_FLASH_ADDR2     (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002AAA << 1)))
这个参数参看SST39VF1601的手册可以得到。

在flash_init函数里仿照:
if defined(CONFIG_AMD_LV400)
            (AMD_MANUFACT & FLASH_VENDMASK) |
            (AMD_ID_LV400B & FLASH_TYPEMASK);
添加对SST39VF1601厂商ID和DEVICE ID的设置:
添加:
#if defined (CONFIG_SST_39VF1601)  
            (SST_MANUFACT & FLASH_VENDMASK)
            (SST_ID_xF1601 & FLASH_TYPEMASK);

由于SST39VF1601每个SECTOR的大小都是一样的。所以修改:
将:
for (j = 0; j < flash_info[i].sector_count; j++) {
            if (j <= 3) {
                /* 1st one is 16 KB */
                if (j == 0) {
                    flash_info[i].start[j] =
                        flashbase + 0;
                }
........
........
修改为:
for (j = 0; j < flash_info[i].sector_count; j++) {
     flash_info[i].start[j] =flashbase + j*MAIN_SECT_SIZE;
                }

当我们键入flinfo命令的时候,将我们的nor flash的信息答应,这里我们在flash_print_info添加相应的支持:
在:
case (AMD_MANUFACT & FLASH_VENDMASK):
        printf ("AMD: ");
        break;
后添加:
case (SST_MANUFACT & FLASH_VENDMASK):
        printf ("SST: ");
        break;

在:
case (AMD_ID_LV800B & FLASH_TYPEMASK):
        printf ("1x Amd29LV800BB (8Mbit)\n");
        break;
之后添加:
case (SST_ID_xF1601& FLASH_TYPEMASK):
        printf ("1x SST39VF1610 (16Mbit)\n");
        break;
接下来修改flash_erase函数,这里我们用SECTOR进行擦出操作。具体修改如下:
将:
if ((info->flash_id & FLASH_VENDMASK) !=
        (AMD_MANUFACT & FLASH_VENDMASK)) {
        return ERR_UNKNOWN_FLASH_VENDOR;
修改为:if ((info->flash_id & FLASH_VENDMASK) !=
        (SST_MANUFACT & FLASH_VENDMASK)) {
        return ERR_UNKNOWN_FLASH_VENDOR;
将以前的块的擦出操作的内容修改为:
首先看一下SST39VF1601的datasheet,看第3页可以知道:
Data# Polling (DQ7)                                           
When the SST39LF/VF160 are in the internal Program
operation, any attempt to read DQ7 will produce the com-
plement of the true data. Once the Program operation is
completed, DQ7 will produce true data. Note that even
though DQ7 may have valid data immediately following the
completion of an internal Write operation, the remaining
data outputs may still be invalid: valid data on the entire
data bus will appear in subsequent successive Read
cycles after an interval of 1 μs. During internal Erase opera-
tion, any attempt to read DQ7 will produce a ‘0’. Once the
internal Erase operation is completed, DQ7 will produce a
‘1’. The Data# Polling is valid after the rising edge of fourth
WE# (or CE#) pulse for Program operation. For Sector-,
Block- or Chip-Erase, the Data# Polling is valid after the ris-
ing edge of sixth WE# (or CE#) pulse. See Figure 5 for
Data# Polling timing diagram and Figure 16 for a flowchart.

TOggle bit (DQ6)
During the internal Program or Erase operation, any con-
secutive attempts to read DQ6 will produce alternating 1s
and 0s, i.e., toggling between 1 and 0. When the internal
Program or Erase operation is completed, the DQ6 bit will
stop toggling. The Toggle Bit is valid after the rising edge of
fourth WE# (or CE#) pulse for Program operation. For Sec-
tor-, Block- or Chip-Erase, the Toggle Bit is valid after the
rising edge of sixth WE# (or CE#) pulse. See Figure 6 for
Toggle Bit timing diagram and Figure 16 for a flowchart.
和一个时序操作图参看第6页可以得到。
通过这些信息,在我们的驱动里进行相应的修改,具体如下:                                                             

for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
        printf ("Erasing sector %2d ... ", sect);

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

        if (info->protect[sect] == 0) {    /* not protected */
            vu_short *addr = (vu_short *) (info->start[sect]);

            MEM_FLASH_ADDR1 = CMD_UNLOCK1;
            MEM_FLASH_ADDR2 = CMD_UNLOCK2;
            MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;

            MEM_FLASH_ADDR1 = CMD_UNLOCK1;
            MEM_FLASH_ADDR2 = CMD_UNLOCK2;
            *addr = CMD_ERASE_CONFIRM;
           
            while (1)
            {

                if ((*addr & 0x40) != (*addr & 0x40))
                    continue;
                if (*addr & 0x80)
                {
                    rc = ERR_OK;

                    break;
                }
            }
            printf ("ok.\n");

然后修改对FLASH的写函数,参考手册在上面以阐述:
    MEM_FLASH_ADDR1 = CMD_UNLOCK1;
    MEM_FLASH_ADDR2 = CMD_UNLOCK2;
    MEM_FLASH_ADDR1 = CMD_PROGRAM;
    *addr = data;

    /* arm simple, non interrupt dependent timer */
    reset_timer_masked ();
   
    while (1)
    {
        //unsigned short i = *(volatile unsigned short *) addr & 0x40;
        if ((*addr & 0x40) != (*addr & 0x40))  
            continue;
        if ((*addr & 0x80) == (data & 0x80))
        {
            rc = ERR_OK;
            break;      
        }
    }

保存重新编译:
tftp 33e00000 u-boot.bin
go 33e00000 u-boot.bin
启动如下:
U-Boot 1.3.4 (Nov 3 2008 - 10:50:50)

DRAM: 64 MB
Flash: 2 MB
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot: 0
SMDK2410 #
擦除擦作:
SMDK2410 # protect off all
Un-Protect Flash Bank # 1
SMDK2410 # erase 50000 +50000
Erasing sector 80 ... ok.
Erasing sector 81 ... ok.
Erasing sector 82 ... ok.
Erasing sector 83 ... ok.
Erasing sector 84 ... ok.
写操作:
SMDK2410 # cp.b 30008000 50000 50000
Copy to Flash... done
查看flash信息:
SMDK2410 # flinfo

Bank # 1: SST: 1x SST39VF1610 (16Mbit)
Size: 2 MB in 512 Sectors

Sector Start Addresses:
    00000000      00001000      00002000      00003000      00004000    
    00005000      00006000      00007000      00008000      00009000
测试OK。然后将board/configs/fs2410.h里的宏CONFIG_SKIP_LOWLEVEL_INIT去掉和board/fs2410/config.mk的TEXT_BASE修改为0x33f80000,下载到nor flash既可。这里我们还用调试的方法来调试支持Nand Flash的读写操作。具体修改如下:

、U-BOOT 1.1.5以后的版本对NAND FLASH的支持有新旧两套代码,心代码在drivers/mtd/nand目录下面,就代码在drivers/mtd/nand_legacy目录下面。文档doc/README.nand对这两套代码作了详细的说明,这里就不说了。但以后的趋势就是旧代码将从u- boot里去除掉。这里我们移植用新的代码来支持nand flash.如果让U-BOOT支持 nand flash首先在include/configs/fs2410.h里添加CONFIG_CMD_NAND宏,这些宏在incldue/config_cmd_all.h定义。然后选择哪套代码需要在include/configs/fs2410.h定义CONFIG_NAND_LEGACY宏,不定义则用新的代码。我们使用新的代码来支持nand flash。
现在开始移植:
首先在include/configs/fs2410.h定义:
#define CONFIG_CMD_NAND
#define CFG_MAX_NAND_DEVICE 1             //板子上有一块nand flash设备
#define CFG_NAND_BASE     0x4e000000   //nand flash控制器的基址
然后交叉编译,下载到开发板的SDRAM中。运行,得到:
U-Boot 1.3.4 (Nov 3 2008 - 13:52:09)

DRAM: 64 MB
Flash: 2 MB
NAND: 64 MiB
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot: 0
SMDK2410 #

查看nand flash的信息:
SMDK2410 # nand info
Device 0: NAND 64MiB 3,3V 8-bit, sector size 16 KiB

擦出 nand:
SMDK2410 # nand erase 0 6400000

NAND erase: device 0 offset 0x0, size 0x6400000
Skipping bad block at 0x00004000                                           
Skipping bad block at 0x00020000                                           
Skipping bad block at 0x00024000                                           
Erasing at 0x3ffc000 -- 64% complete.
NAND 64MiB 3,3V 8-bit: MTD Erase failure: -22

NAND 64MiB 3,3V 8-bit: MTD get bad block failed: -22
ERROR
现在的代码支持的非常好,能自动检测出坏快。不错!

接下来就让我们的u-boot支持yaffs文件系统镜像的烧写,这个功能太实用了。不错!现在的U-BOOT本身带了烧写内核,烧写cramfs,jffs2文件镜像文件,但是在nand flash上,yaffs文件系统的性能更加,所以我们添加相应的命令来支持烧写yaffs文件系统镜像。这里就不阐述了yaffs文件系统的特性了。大家可以上网搜索一下这方面的文章。这里主要讲一下怎么去移植。
首先在common/cmd_nand.c里仿照jffs2来写一些yaffs的内容:
在:
U_BOOT_CMD(nand, 5, 1, do_nand,
     "nand    - NAND sub-system\n",
    "info                  - show available NAND devices\n"
    "nand device [dev]     - show or set current device\n"
    "nand read[.jffs2]     - addr off|partition size\n"
     "nand write[.jffs2]    - addr off|partition size - read/write `size' bytes starting\n"
    "    at offset `off' to/from memory address `addr'\n"
之后添加nand read.yaffs 的使用说明:
"nand read.yaffs     - addr off|partition size\n"
"nand write.yaffs    - addr off|partition size - read/write `size' bytes starting\n"

然后在nand命令的处理函数里do_nand中增加对write.yaffs的支持,do_nand在common/cmd_nand.c中实现:
在:
if (s != NULL &&
             (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
的判断后面加:
else if (s != NULL &&
             (!strcmp(s, ".yaffs") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
             if (read) {
                 /* read */
                 nand_read_options_t opts;
                memset(&opts, 0, sizeof(opts));
                  opts.buffer = (u_char*) addr;
                opts.length = size;
                opts.offset = off;
                 opts.readoob = 1;
                 opts.quiet      = quiet;
                 ret = nand_read_opts(nand, &opts);
            } else {
                 /* write */
               nand_write_options_t opts;
                memset(&opts, 0, sizeof(opts));
                opts.buffer = (u_char*) addr;
                opts.length = size;
                opts.offset = off;
                 /* opts.forcejffs2 = 1; */
                 //opts.pad = 1;
                  opts.noecc = 1;
                opts.writeoob = 1;
                  opts.blockalign = 1;
                 opts.quiet      = quiet;
                  ret = nand_write_opts(nand, &opts);
            }
         }

由于前面设置了opts.noecc = 1,不使用ecc校验码,烧写过程中会提示这个信息:
Writing data without ECC to NAND-FLASH is not recommended
Writing data without ECC to NAND-FLASH is not recommended
Writing data without ECC to NAND-FLASH is not recommended
Writing data without ECC to NAND-FLASH is not recommended
Writing data without ECC to NAND-FLASH is not recommended
可以修改driver/mtd/nand/nand_base.c文件的nand_write_page函数,将它去掉,修改如下:
case NAND_ECC_NONE:
        //printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
        this->write_buf(mtd, this->data_poi, mtd->oobblock);
       break;
这样,U-BOOT就可以支持yaffs文件镜像的烧写了:
U-Boot 1.3.4 (Nov 3 2008 - 16:01:43)

DRAM: 64 MB
Flash: 2 MB
NAND: 64 MiB
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot: 0
SMDK2410 # nand erase 200000 600000

NAND erase: device 0 offset 0x200000, size 0x600000
Erasing at 0x7fc000 -- 100% complete.
OK
SMDK2410 # tftp 30008000 rootfs.yaffs
TFTP from server 192.168.1.2; our IP address is 192.168.1.3
Filename 'rootfs.yaffs'.
Load address: 0x30008000
Loading: #################################################################
    #################################################################
    #################################################################
    #################################################################
    ###########T ######################################################
    #############################################
done
Bytes transferred = 5417280 (52a940 hex)
SMDK2410 # nand write.yaffs 30008000 200000 52a940

NAND write: device 0 offset 0x200000, size 0x52a940

Writing data at 0x702600 -- 100% complete.
5417280 bytes written: OK
SMDK2410 #

然后就是支持LINUX内核启动参数的设置:
只需要在include/configs/fs2410.h里增加两个宏就OK了。分别是:
#define CONFIG_SETUP_MEMORY_TAGS 1 //向内核传递内存分布信息
#define CONFIG_CMDLINE_TAG 1                 //向内核传递命令行参数
编译。
然后将tool/mkimage拷贝到系统的/usr/bin目录下面:
sudo chmod 777 /usr/bin/mkimage
接下来就是验证:
首先使用 u-boot/tools/mkimage为linux内核加头:
mkimage -n 'linux-2.6.26.5' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage zImage.img
然后使用 tftp将其装载到内存中:
tftp 0x30008000 zImage.img
将内存中程序固化到flash:
nand erase 0x40000(flash存储地址首地址) 0x200000(应大于实际内核大小)
nand write 0x30008000 0x40000 0x200000
设置启动环境变量:
setenv bootcmd nand read 0x30008000 0x40000 0x200000\;bootm 0x30008000
saveenv
启动开发板,启动信息如下:
U-Boot 1.3.4 (Nov 3 2008 - 17:16:30)
DRAM: 64 MB
Flash: 2 MB
NAND: 64 MiB
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot: 0

NAND read: device 0 offset 0x40000, size 0x200000
2097152 bytes read: OK
## Booting kernel from Legacy Image at 30008000 ...
   Image Name:   linux-2.6.26.5
   Created:      2008-11-03   9:10:18 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1852992 Bytes = 1.8 MB
   Load Address: 30008000
   Entry Point: 30008040
   Verifying Checksum ... OK
   XIP Kernel Image ... OK
OK

Starting kernel ...

Uncompressing Linux..................................................................................................................... done, booting the kernel.
Linux version 2.6.26.5 (yoyoili@yoyoili-laptop) (gcc version 3.4.5) #43 Mon Nov 3 17:09:56 CST 2008
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
Machine: SMDK2410
Memory policy: ECC disabled, Data cache writeback
CPU S3C2410A (id 0x32410002)
S3C2410: core 202.800 MHz, memory 101.400 MHz, peripheral 50.700 MHz
S3C24XX Clocks, (c) 2004 Simtec Electronics
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
Kernel command line: root=/dev/nfs nfsroot=192.168.1.8:/home/yoyoili/source/system_study/rootfs ip=192.168.1.222 init=/linuxrc console=ttySAC0,115200
irq: clearing subpending status 00000002
PID hash table entries: 256 (order: 8, 1024 bytes)
timer tcon=00500000, tcnt a509, tcfg 00000200,00000000, usec 00001e4c
Console: colour dummy device 80x30
console [ttySAC0] enabled
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 61056KB available (3360K code, 322K data, 144K init)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
net_namespace: 192 bytes
NET: Registered protocol family 16
S3C2410 Power Management, (c) 2004 Simtec Electronics
S3C2410: Initialising architecture
S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics
DMA channel 0 at c4800000, irq 33
DMA channel 1 at c4800040, irq 34
DMA channel 2 at c4800080, irq 35
DMA channel 3 at c48000c0, irq 36
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb