当前位置:首页 >> 信息与通信 >>

移植u-boot-1.3到GT2440


作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

移植 u-boot-1.3.4 到 GT2440 
    硬件配置  1、 GT2440\其它开发板  2、 其中 nand flash 为 2Kb 一页(具体和 512byte 的有什么区别,参考 n

and 元件手册,或 者上网搜一下,对于 uboot,主要是读 nand 时的写地址的不一样)  3、 串行线  4、 J-link\j-tag(笔者用的是 jlink,主要用于 uboot 的调试,因为你移植马上能用的可 能性不大,所以需要调试)    软件配置:  1、u-boot-1.3.4  2、 - j-link 或者 H-jtag     

一、从 nand flash 启动 uboot 的原理 
  Uboot 源码是不支持从 nand 中启动的, 但是 2410 2440 是支持的, 而且对于闪存, nand 比较大容量,比较便宜,所以使用 nand 启动 uboot 是比较需要的。那么它启动的原理是什 么?    其实从 nand flash 控制器有一个特殊功能,会自动把 nand flash 前 4K 内容复制到 4K  SRAM 中(注意,是只有 4k 的 SRAM 而不是 SDRAM,超过怎么办,所以要复制到 SDRAM 中,如 下图)中,并把 0x00000000 设置成内存起始地址,cpu 从这个地址开始运行。这个过程不需 要程序干涉。    这 4K 的内容,主要是保存的 uboot 的部分功能(拷贝功能) ,执行后,再把 nand 里的 内容拷贝到 SDRAM 中,原因有下:  1、 SDRAM 运行速度快  2、 实际的 uboot 代码永远大于 4Kb 的空间, ,所以要开辟一个新空间给 uboot 运行 

这就是前 4K 所在的地方

1

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

     

 

2

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

二、uboot 的运行流程 

 
首先先大概分析一下 uboot,这样有利于明白,移植的每一步是需要做些什么?  像网上说的,uboot 编译时首先编译的是 u-boot-1.3.4\board\你的开发板文件夹 \config.lds,看一个 2410 的例子:  ENTRY(_start)  SECTIONS  {                          . = ALIGN(4);  .rodata : { *(.rodata) }  . = 0x00000000;  . = ALIGN(4);  .text      :  {    cpu\arm920t\start.o    *(.text)  }  (.text) 

3

作者:guolele 2010-11-3                                }  . = ALIGN(4);  __bss_start = .;  .bss : { *(.bss) }  _end = .;  __u_boot_cmd_start = .;  .u_boot_cmd : { *(.u_boot_cmd) }  __u_boot_cmd_end = .;  . = ALIGN(4);  .got : { *(.got) }  . = ALIGN(4);  .data : { *(.data) } 

博客: http://hi.baidu.com/guolele1990/blog

(1) 从 ENTRY(_start)可以看出 u-boot 的入口函数是_start,这个没错  (2) 从. = 0x00000000 也许可以看出_start 的地址是 0x00000000,事实并不是这样的,这 里的 0x00000000 只是清零地址计数器,实际链接时,都是以 TEXT_BASE 为基地址,具体请 参考 u-boot 根目录下的 config.mk.    顺着这个 config.lds 文件,就开始执行 u-boot-1.3.4\cpu\arm920t\start.S  它里面大概执行流程是  (1)  CPU 为 SVC 模式  (2)  定义中断向量表  (3)  关闭中断 (因为 uboot 不需要使用中断)  (4)  底层初始化:两个函数 cpu_init_crit 和 lowlevel_init  cpu_init_crit 是禁止 MMU 和 CACHE, 为什么?因为如果你不禁止, 有些数据会残留 在 cache 上,会造成脏数据(《具体也可以参考 ARM 体系结构与编程》)  lowlevel_init 主要是定义部分寄存器以及初始化 SDRAM  (5)  然后把代码拷贝到内存中(没修改时为下面代码,修改后使用自己移植的)  #ifndef CONFIG_SKIP_RELOCATE_UBOOT   relocate:           /* relocate U-Boot to RAM         */    adr  r0, _start         /* r0 <- current position of code   */    ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */    cmp     r0, r1          /* don't reloc during debug        */    beq     stack_setup     

4

作者:guolele 2010-11-3  ldr r2, _armboot_start    ldr r3, _bss_start  

博客: http://hi.baidu.com/guolele1990/blog

 sub r2, r3, r2     /* r2 <- size of armboot             */    add r2, r0, r2      /* r2 <- source end address         */      copy_loop:    ldmia r0!, {r3-r10}  /* copy from source address [r0]    */    stmia r1!, {r3-r10}  /* copy to   target address [r1]     */    cmp r0, r2    /* until source end addreee [r2]     */    ble copy_loop   #endif /* CONFIG_SKIP_RELOCATE_UBOOT */  (6)  初始化堆栈(其实就是在内存中开辟一个区域,用于保存数据,其实是栈,经典映射 图如下图)  (7)  调用 C 语言函数入口,start_armboot  到此第一阶段基本完成  注意 b 跳转跟 ldr  Ldr pc,=label  Ldr  伪指令,将内存值赋给 PC,也是依赖于当前 PC 值,但是偏移量是 label 的运行时的 地址    跳转是不一样的  b 跳转,依赖当前 PC 值,偏移量通过指令 bit[23:0]算出 

这就是创建的堆

这就是创建的栈

 

5

作者:guolele 2010-11-3 第二阶段是 start_armboot 

博客: http://hi.baidu.com/guolele1990/blog

其实这个函数是定义在 u-boot-1.3.4\lib_arm\board.c  他的作用是初始化,这初始化跟第一阶段的不一样,第一阶段的初始化主要是比较低层的, 面现在已经建立起 C 的运行环境,所以可以初始化一点其它函数  这里主要初始化的是  主要定义在 init_fnc_t *init_sequence[]这个指针数组里(注,参考《ARM79 出口-u-boot 移植手册》)  1、 cpu_init    定义在 cpu\arm920t 里, 并没有做实质性的工作, 因为笔者们现在还没有 定义 CONFIG_USE_IRQ 所以,代码来到这,直接 return0  2、 board_init    定义在开发板.c 里,笔者这是 GT2440.c。它主要的工作是初始化系 统时钟, 引脚 IO 设置, 使能数据 cache 和指令 cache, 考虑到板子可能会发生意外中断, 还初始化了中断,下一步就初始化中断  3、 interrupt_init    这实际上是定时器的中断初始化。定义在 cpu\arm920t\s3c24x0\Interrupts.c 里  4、 env_init    环境初始化。在 u-boot-1.3.4\common\env_nand.c 里    用于初始化波特率  5、 init_baudrate 

6、 serial_init      用于初始化串口,定义在 u-boot-1.3.4\cpu\arm920t\s3c24x0\serial.c 里  7、 console_init_f    作用是告诉编译器,笔者们目前是使用串口的,  8、 display_banner    串口初始化完成,所以就可以打印信息,成功后,就可以不用点 灯大法,可以使用串口输出来调试了  9、 print_cpuinfo  10、   初始化完这些函数后,就进入其它函数  flash_init()。定义在…\board\gt2440(开发板目录,以后就不打了)\flash.c,它是负责 显示你的 nor flash 有多大,然后用后面的函数 display_flash_config 显示它。当你打开 它,会发现这里兼容 AMD 的芯片,如果你的不是 AMD 的就要修改 flash ID 号了  如何修改?先在这作简单介绍  就是在 gt2440.h 原本定义#define CONFIG_AMD_LV800 1 屏蔽掉  然后定义自己的  #define CONFIG_SST_VF1601    1  后面再修改 FLASH_BANK_SIZE、CFG_MAX_FLASH_SECT  但是由于 sst nor 操作是不相同的,所以就需要修改 board/gt2440/flash.c    mem_malloc_init()  初始化内存,非常关键,要把这块区域清零,以便后续来使用它。  后面几个就是什么 LCD、VFD 之类的先不理它  到了 nand_init()了, 这里的话, 涉及到后面讲的是使用在 gt2440.c 里定义的 nand_init() 还是 uboot 自带的,就要靠几个宏定义,现在先放一放,知道这里是初始化 nand 的就可以 了。    可选  checkboard  可选,后面还有几个选的,就不说了 

6

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

  然后是什么打印环境变量,开中断,还有一个有关网卡的函数,笔者使用的是 cs8900 所以直接用它自带的,如果读者的是 dm9000 或者其它,就应该自己写了后替换它,推荐使 用宏。最后面,一系列之后,到了 main_loop()。Uboot 执行完成       

三、 

UBOOT 移植 

1、注意问题  了解了大概 uboot 的运行过程,现在开始移植,移植前,说明几个问题  由于 uboot-1.3.4 较于较早的版本, 就是 Makefile 有一定的变化, 使得对于 24x0 处理器从 nand 启动会有问题, 就是有人说的无法运行过 lowlevel_init。 这个问题产生的原因是因为 编译器将笔者们自己添加的用于 nandboot 的子函数放到了 4K 之后(为什么说是 4K,uboot 从 nand 启动原理,前面说过),解决办法: 
1、顶层 Makefile 文件中:  #__LIBS := ¥(subst ¥(obj),,¥(LIBS)) ¥(subst ¥(obj),,¥(LIBBOARD))  __LIBS := ¥(subst ¥(obj),,¥(LIBBOARD)) ¥(subst ¥(obj),,¥(LIBS))  这样修改之后查看 map 文件可以发现,lowlevel_init 函数链接到了前面.  2、在不修改 Makefile 的情况下,可以通过修改目标板下的链接文件 u-boot.lds 来使 lowlevel_init 放在 4K 之内: cpu/arm920t/start.o (.text) board/net2410e/lowlevel_init.o (.text) 把之放到 start.o 的后面.  这相当于修改链接脚本,未做验证,笔者使用第一种方法! 

3、 开始移植/*其中,蓝色为修改内容,红色为添加内容,参考《移植 u-boot-1.3.4 到 s3c2440》*/  下载源码,网址:  U-Boot 软件包下载网站:http://sourceforge.net/project/u-boot  笔者更喜欢从这里下载源码:ftp://ftp.denx.de/pub/u-boot/  1) 解压 uboot  #tar –xjvf u-boot-1.3.4.tar.gz2    2) 修改 Makefile  #cd u-boot-1.3.4  #vi Makefile 或者直接在图形界面打开 Makefile,可能这种方法更好用 

7

作者:guolele 2010-11-3
修改内容如下: 

博客: http://hi.baidu.com/guolele1990/blog

__LIBS := ¥(subst ¥(obj),,¥(LIBS)) ¥(subst ¥(obj),,¥(LIBBOARD))  改为: 

__LIBS := ¥(subst ¥(obj),,¥(LIBBOARD)) ¥(subst ¥(obj),,¥(LIBS)) 
添加开发板信息 

sbc2410x_config: unconfig @¥(MKCONFIG) ¥(@:_config=) arm arm920t sbc2410x NULL  s3c24x0  
 

gt2440_config : unconfig @¥(MKCONFIG) ¥(@:_config=) arm arm920t  gt2440  NULL   s3c24x0   /*  各项的意思如下:     gt2440_config : 这个名字是将来你配置板子时候用到的名字,参见 make  gt2440_config 命令。  arm: CPU 的架构(ARCH)   arm920t: CPU 的类型(CPU),其对应于 cpu/arm920t 子目录。   gt2440: 开发板的型号(BOARD),对应于 board/ gt2440 目录。   NULL: 开发者/或经销商(vender)。 s3c24x0: 片上系统(SOC)。  */   
3) 在/board/下建立自己的开发板目录  由于笔者们开发者那填了 NULL,所以直接创建,如果有填,则要再建一个子目录,因为笔者们是以 sbc2410x 这板为基础移植的,所以还要将它的内容复制到开发板文件夹上。  [root@localhost u-boot-1.3.4]#mkdir /board/gt2440  [root@localhost u-boot-1.3.4]#cp –arf sbc2410x/* gt2440/  [root@localhost u-boot-1.3.4]#cd gt2440  [root@localhost u-boot-1.3.4]#mv sbc2410x.c gt2440.c  [root@localhost u-boot-1.3.4]#ls 可以看到下面这些文件   

config.mk  flash.c  lowlevel_init.s Makefile 
[root@localhost u-boot-1.3.4]#vi Makefile 

  GT2440.c  u-boot.lds 

8

作者:guolele 2010-11-3
    4) COBJS := gt2440.o flash.o 

博客: http://hi.baidu.com/guolele1990/blog

在 include/configs/中建立开发板所需要的配置头文件  [root@localhost  u-boot-1.3.4]#cp ../../include/configs/sbc2410x.h ../../include/configs/gt2440.h   

  5)   测试交叉编译能否成功 

  这里提醒一下,移植 uboot 是需要交叉编译有浮点运算功能的,安装 arm-linux 时,应该选用有浮点运算 的,而不是最新的,因为最新的未必是最好的,uboot 也是一样,新的只是移植简单了,对于交叉编译工 具,笔者选用的是 arm-linux-gcc-3.4.1  安装步骤:限于篇幅,详情可看笔者的一篇日志 http://hi.baidu.com/guolele1990/blog/item/38789835cf1cd2d2a2cc2b5c.html   

(1) 

配置 

[root@localhost u-boot-1.3.4]#make gt2440_config  Configure for gt2440 board  (2)  测试编译 

[root@localhost u-boot-1.3.4]#make  编译信息最后两行 

arm-linux-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec  arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin    6) 开始针对自己的开发板移植  1. 修改/cpu/arm920t/start.S 

9

作者:guolele 2010-11-3 1.1 修改寄存器地址定义 

博客: http://hi.baidu.com/guolele1990/blog

#if defined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)  /*turn off the watchdog*/  #if defined(CONFIG_S3C2400)  # define pWTCON        0x15300000  # define INTMSK        0x14400008    /* Interupt-Controller base addresses */  # define CLKDIVN    0x14800014    /* clock divisor register */  #else  # define pWTCON        0x53000000  /*该地址用来屏蔽看门狗*/  # define INTMSK        0x4A000008    /* Interupt-Controller base addresses 该地址用 来屏蔽中断*/  # define INTSUBMSK    0x4A00001C /*该地址用来屏蔽子中断*/  # define CLKDIVN    0x4C000014    /* clock divisor register 该地址用来决定 FCLK、 HCLK、PCLK 的比例*/  #define CLK_CTL_BASE        0x4c000000  /* 从 S3C2440A.pdf 中可以看出该寄存器是存放 Mpll 和 Upll 的 P254 */  #if defined(CONFIG_S3C2440)   #define MDIV_405       0x7f << 12   /*  参见 P255 表,同时要知道本开发板的 Fin 是 12MHz,需要的 Fclk(也就是 Mpll)是 405MHz*/  #define PSDIV_405       0x21       /* 同上,同时设定 PDIV 和 SDIV 的值,PDIV 和 SDIV 参 见 S3C2440A.pdf*/  #endif  #endif    1.2 修改中断禁止部分    # if defined(CONFIG_S3C2410)  //ldr  r1,0x3ff 

  ldr    r1, =0x7ff   //根据 2410 芯片手册,INTSUBMSK 有 11 位可用,                         //vivi 也是 0x7ff, 不知为什么 U-Boot 一直没改过来。 但是由于 芯片复位默认 

10

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

//所有的终端都是被屏蔽的,所以这个不影响工   ldr    r0, =INTSUBMSK   str    r1, [r0]  # endif  # if  defined(CONFIG_S3C2440)      ldr    r1, =0x7fff   //根据 2440 芯片手册,INTSUBMSK 有 15 位可用      ldr    r0, =INTSUBMSK      str    r1, [r0]  # endif    1.3 修改时钟设置  /*时钟控制逻辑单元能够产生 s3c2440 需要的时钟信号,包括 CPU 使用的主频 FCLK,AHB 总 线使用的 HCLK,APB 总线设备使用的 PCLK,2440 里面的两个锁相环(PLL),其中一个对应 FCLK、HCLK、PCLK,另外一个对应 UCLK(48MHz)*/  /* FCLK:HCLK:PCLK = 1:4:8 */      ldr    r0, =CLKDIVN      mov    r1, #5      str    r1, [r0]  /*协处理器操作 
CP15 —系统控制协处理器 (the system control coprocessor)他通过协处理器指令 MCR 和 MRC 提 供具体的寄存器来配置和控制 caches、MMU、保护系统、配置时钟模式(在 bootloader 时钟初始化 用到) ,详情可看《ARM 体系结构与编程》或者 http://hi.baidu.com/guolele1990/blog/item/57a96f3d26bc33ea838b136a.html 笔者的一个浅谈, 也是参考那本书的 

*/      mcr p15,0,r1,c1,c0,0  orr r1,r1,#0xc0000000    /*读协处理器 p15  c1 寄存器的值到 r1*/ 

  mcr p15,0,r1,c1,c0,0    /*把 r1 的内容写到 c1 中去,禁止 MMU、禁止地址对齐 检查功能、禁止 caches、禁止写入缓冲、异常中断处理程序进入 32 位地址模式、禁止 26 位地址异常检查、选择时期中止模型、选择 little-endian。。。。。。详情可以看《ARM 体系结构与编程》的 5.2 节*/      #if defined(CONFIG_S3C2440)  /*now, CPU clock is 405.00 Mhz   qljt*/ 

11

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

mov    r1, #CLK_CTL_BASE      mov    r2, #MDIV_405                   /* mpll_405mhz */  add    r2, r2, #PSDIV_405             /* mpll_405mhz */  str    r2, [r1, #0x04]               /* MPLLCON 实际上是设置寄存器 CLK_CTL_BASE+0x04=0x4c000004 的值 */  #endif  #endif    /* CONFIG_S3C2400 || CONFIG_S3C2410|| CONFIG_S3C2440 */    1.4 将 Flash 启动改成从 NAND Flash 启动(这里网上还有一个小程序,是判别现在是 nor 还是 nand 启动的,原理可参考 http://blog.chinaunix.net/u1/34474/showart.php?id=2085212,  其实就是利用 start.S 里的魔方数以及 nand 和 nor 的写特性,然后可以同时烧进 nor 和 nand 中,主要区别在于,nor 可以直接运行 uboot。笔者这里没加)  将 u-boot 重定向语句段屏蔽  @#if ndef  CONFIG_AT91RM9200  #if  0  #ifndef CONFIG_SKIP_RELOCATE_UBOOT  relocate:                /* relocate U-Boot to RAM        */      adr    r0, _start        /* r0 <- current position of code   */      ldr    r1, _TEXT_BASE        /* test if we run from flash or RAM */      cmp     r0, r1                /* don't reloc during debug         */      beq     stack_setup        ldr    r2, _armboot_start      ldr    r3, _bss_start      sub    r2, r3, r2        /* r2 <- size of armboot            */      add    r2, r0, r2        /* r2 <- source end address         */    copy_loop: 

12

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

    ldmia    r0!, {r3-r10}        /* copy from source address [r0]    */      stmia    r1!, {r3-r10}        /* copy to   target address [r1]    */      cmp    r0, r2            /* until source end addreee [r2]    */      ble    copy_loop  #endif    /* CONFIG_SKIP_RELOCATE_UBOOT */  #endif/*#if 0*/  #endif  /*CONFIG_AT91RM9200 */  然后添加(参考 VIVI):  #ifdef CONFIG_S3C2440_NAND_BOOT     /*往下四段内容都是针对 S3C2440 的关于 NAND-FLASH 的寄存器的设置*/      mov    r1, #NAND_CTL_BASE     

    ldr    r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )  /*总线宽为 8  Bit,设定 TWRPH1,TWRPH0(nWE 高低电平持续时间)*/      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  /*这些宏是在 include/configs/GT2440.h 中被定义的

13

作者:guolele 2010-11-3     strb    r2, [r1, #oNFCMD]  /*delay 一段时间*/    mov r3, #0                   @ wait  nand1:     add  r3, r3, #0x1    cmp r3, #0xa    blt   nand1  /*等待 nand-flash 的复位完毕信号*/  nand2:    ldr   r2, [r1, #oNFSTAT]      @ wait ready    tst    r2, #0x4    beq  nand2      ldr    r2, [r1, #oNFCONT] 

博客: http://hi.baidu.com/guolele1990/blog

 orr    r2, r2, #0x2        @ Flash Memory Chip Disable  /*在这里先 Display fansh CE 先,在 C 函数中再 enable*/  str    r2, [r1, #oNFCONT]                            /*下面这段用来初始化栈指针 sp 和帧指针 fp,至于它们的定义和作用参考文件夹” 栈指 针 sp 和帧指针 fp”里面的内容  记住它们都是与函数调用时候相关的。简单来讲就是子函数被调用以后是通过指针的相 对位置来查找调用参数和局部变量的,但是由于 sp 经常变化,所以需要 fp 来协助。*/  @ get ready to call C functions (for nand_read())    ldr   sp, DW_STACK_START       @ setup stack pointer /*sp 是指堆栈指针*/    mov fp, #0                    @ no previous frame, so fp=0     

@ copy U-Boot to RAM    /*注意: 现在是运行在 4k 的 SRAM 里, 现在要把 nand flash 的内容拷贝到 SDRAM 中!vivi 里面应该是有一段是针对 gpio 的程序,也许使用来 debug 用 的信号灯,这里省略了*/    /* TEXT_BASE 是 uboot 自己的入口地址, u-boot-1.3.4-board/gt2440 的 config.mk 在 中定义  有趣的是外国人的逆向思维很厉害, 它们很灵活地把它放在 SDRAM 的最后 0x80000 地方, 也就是 0x33F80000  

14

作者:guolele 2010-11-3 */ 

博客: http://hi.baidu.com/guolele1990/blog

ldr   r0, =TEXT_BASE /*r0 : 把 u-boot 复制到 ram 的那个位置*/           mov     r1, #0x0    mov r2, #0x20000  bl    nand_read_ll        /*r1 : 从 falsh 的那个位置开始复制*/    /*r2 : 复制多大的内容*/ 

/*跳到执行 uboot 复制的程序入口,这个函数从哪里来?自

己在后面写的,也可以参考 vivi 的*/     tst    r0, #0x0      /*这里特别注意 r0 的值是指 nand_read_ll 执行完以后的

返回值,而不是上面 ldr   r0, =TEXT_BASE 的值,可以查看 uboot 反汇编文件,跟踪到 nand_read_ll 可得 mov r0,#0*/     beq  ok_nand_read  /*如果读 nand_read 失败的话,那么死循环*/   

bad_nand_read:   

loop2:    b     loop2          @ infinite loop  ok_nand_read:  @ verify   

 

/*下面这段程序的作用就是用开始执行的 4Kbytes 程序跟笔者们复制到 SRAM 中的 uboot 的 前 4K 程序进行比较,从而校验,现在运行在 SRAM 里*/    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 

15

作者:guolele 2010-11-3   bne  go_next    notmatch:  loop3:     b     loop3         @ infinite loop  #endif @ CONFIG_S3C2440_NAND_BOOT     

博客: http://hi.baidu.com/guolele1990/blog

1.5 跳转到 C 函数之前, 即跳出 start.S 进入第二阶段之前, 加个 led 控制, 点灯大法, 具体参照读者的硬件配置          #if defined(CONFIG_S3C2440)  /*LED1 on u-boot stage 1 is ok!,gt2440.h*/      mov    r1, #GPIO_CTL_BASE      add    r1, r1, #oGPIO_B      ldr    r2,=0x3D57FC      str    r2, [r1, #oGPIO_CON]      ldr    r2, =0x7ff      str    r2, [r1, #oGPIO_UP]      ldr    r2, =0x7fce      str    r2, [r1, #oGPIO_DAT]  #endif/*s3c2440*/    _start_armboot: .word start_armboot  1.6 在“_start_armboot:  .word start_armboot”后加入    #if defined(CONFIG_S3C2440_NAND_BOOT)  .align  2    /*四字节对齐*/  DW_STACK_START:.word STACK_BASE+STACK_SIZE-4/*这里的 STACK_BASE 和 STACK_SIZE 将 在 gt2440.h 中定义*/  #endif  2. 修改 include/configs/gt2440.h 文件,因为参考的 s3c2410 与 s3c2440 的 nand  flash 控制器寄存器不同,其他相同的可以不改  /*   * Nandflash Boot    ldr pc, _start_armboot  ble clbss_l 

16

作者:guolele 2010-11-3  */  #define CONFIG_S3C2440_NAND_BOOT 1  #define STACK_BASE    0x33f00000  #define STACK_SIZE    0x8000  /* NAND Flash Controller */ 

博客: http://hi.baidu.com/guolele1990/blog

#define NAND_CTL_BASE        0x4E000000  /* Offset */  #define oNFCONF            0x00 /*这些宏是在 start.S 中被调用的*/  #define oNFCONT            0x04  #define oNFCMD            0x08  #define oNFADDR            0x0c  #define oNFDATA            0x10  #define oNFSTAT            0x20  #define oNFECC            0x2c  /* GPIO */  #define GPIO_CTL_BASE        0x56000000  #define oGPIO_F            0x50  #define oGPIO_CON       0x0   /* R/W, Configures the pins of the port */  #define oGPIO_DAT        0x4    /* R/W,    Data register for port */  #define oGPIO_UP        0x8    /* R/W, Pull-up disable register */  #endif    /* __CONFIG_H */    3. /*    * nand_read.c: Simple NAND read functions for booting from NAND    *   在 board/gt2440 中加入 NAND FLASH 读函数文件同(参考的是《GT2440 之 U-boot 使用及移植详细手册》,可实现不同大小的 nand 读操作) 

17

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

 * This is used by cpu/arm920/start.S assembler code,    * and the board-specific linker script must make sure this    * file is linked within the first 4kB of NAND flash.    *    * Taken from GPLv2 licensed vivi bootloader,    * Copyright (C) 2002 MIZI Research, Inc.    *    * Author: Hwang, Chideok <hwang@mizi.com>    * Date  : ¥Date: 2004/02/04 10:37:37 ¥    *    * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc   * Author: Harald Welte <laforge@openmoko.org>    */      #include <common.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   #if defined(CONFIG_S3C2410)   #define NFCONF  __REGi(NF_BASE + 0x0)   #define NFCMD  __REGb(NF_BASE + 0x4)     #define NFADDR  __REGb(NF_BASE + 0x8)   #define NFDATA  __REGb(NF_BASE + 0xc)   #define NFSTAT  __REGb(NF_BASE + 0x10)   #define NFSTAT_BUSY 1   #define nand_select() (NFCONF &=  ̄0x800)   #define nand_deselect() (NFCONF |= 0x800)   #define nand_clear_RnB() do {} while (0)   #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)   #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)  

18

作者:guolele 2010-11-3 #define NFDATA16 __REGw(NF_BASE + 0x10)   #define NFSTAT  __REGb(NF_BASE + 0x20)   #define NFSTAT_BUSY 1  

博客: http://hi.baidu.com/guolele1990/blog

#define nand_select() (NFCONT &=  ̄(1 << 1))   #define nand_deselect() (NFCONT |= (1 << 1))   #define nand_clear_RnB() (NFSTAT |= (1 << 2))   #endif      static inline void nand_wait(void)   {    int i;       while (!(NFSTAT & NFSTAT_BUSY))     for (i=0; i<10; i++);   }      struct boot_nand_t { /*用来贮存芯片的参数*/   int page_size;    int block_size;    int bad_block_offset;   // unsigned long size;   };      #if 0   #if defined(CONFIG_S3C2410) || defined(CONFIG_GT2440)   /* configuration for 2410 with 512byte sized flash */   #define NAND_PAGE_SIZE  512   #define BAD_BLOCK_OFFSET 5   #define NAND_BLOCK_MASK  (NAND_PAGE_SIZE - 1)   #define NAND_BLOCK_SIZE  0x4000   #else   /* 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)   #endif /* defined(CONFIG_S3C2410) || defined(CONFIG_GT2440)*/    

19

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

/* compile time failure in case of an invalid configuration */   #if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)   #error "S3C2410 does not support nand page size != 512"   #endif /* defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)*/  #endif /*IF 0*/     static int is_bad_block(struct boot_nand_t * nand, unsigned long i)   {    unsigned char data;    unsigned long page_num;       nand_clear_RnB();   /*page_size 的不同主要是读的时候写地址不一样, 的为 5 次, 次 Colmn 3 次 row address  2K 2 而 512 的是 1 次 Colmn 和 3 次 row address 具体怎么安排,可看芯片手册  还有一些宏,例如 NAND_CMD_READ0 定义在 include/linux/mtd/nand.h 里*/   if (nand->page_size == 512) {     NFCMD = NAND_CMD_READOOB; /* 0x50 */     NFADDR = nand->bad_block_offset & 0xf;     NFADDR = (i >> 9) & 0xff;     NFADDR = (i >> 17) & 0xff;     NFADDR = (i >> 25) & 0xff;    } else if (nand->page_size == 2048) {     page_num = i >> 11; /* addr / 2048 */     NFCMD = NAND_CMD_READ0;     NFADDR = nand->bad_block_offset & 0xff;     NFADDR = (nand->bad_block_offset >> 8) & 0xff;     NFADDR = page_num & 0xff;     NFADDR = (page_num >> 8) & 0xff;     NFADDR = (page_num >> 16) & 0xff;     NFCMD = NAND_CMD_READSTART;    } else {     return -1;    }    nand_wait();    data = (NFDATA & 0xff);    if (data != 0xff)     return 1;       return 0;  

20

作者:guolele 2010-11-3 }     

博客: http://hi.baidu.com/guolele1990/blog

static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf,  unsigned long addr)   {    unsigned short *ptr16 = (unsigned short *)buf;    unsigned int i, page_num;       nand_clear_RnB();       NFCMD = NAND_CMD_READ0;       if (nand->page_size == 512) {     /* Write Address */     NFADDR = addr & 0xff;     NFADDR = (addr >> 9) & 0xff;     NFADDR = (addr >> 17) & 0xff;     NFADDR = (addr >> 25) & 0xff;    } else if (nand->page_size == 2048) {     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; /*0x30*/   }   else   {     return -1;    }    nand_wait();      #if defined(CONFIG_S3C2410)    for (i = 0; i < nand->page_size; i++) {     *buf = (NFDATA & 0xff);   /*8 位线宽*/    buf++;    }  

21

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)    for (i = 0; i < (nand->page_size>>1); i++) {     *ptr16 = NFDATA16; /*16 位线宽*/    ptr16++;    }   #endif /* defined(CONFIG_S3C2410)*/      return nand->page_size;   }      static unsigned short nand_read_id()   {    unsigned short res = 0;    NFCMD = NAND_CMD_READID;    NFADDR = 0;    res = NFDATA;    res = (res << 8) | NFDATA;    return res;   }      extern unsigned int dynpart_size[];      /* low level nand read function */   int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)   {    int i, j;    unsigned short nand_id;    struct boot_nand_t nand;       /* chip Enable */    nand_select();    nand_clear_RnB();        for (i = 0; i < 10; i++)     ;    nand_id = nand_read_id();    if (0) { /* dirty little hack to detect if nand id is misread */     unsigned short * nid = (unsigned short *)0x31fffff0;     *nid = nand_id;  

22

作者:guolele 2010-11-3  }      

博客: http://hi.baidu.com/guolele1990/blog

       if (nand_id == 0xec76 ||  /* Samsung K91208 */              nand_id == 0xad76 ) { /*Hynix HY27US08121A*/     nand.page_size = 512;     nand.block_size = 16 * 1024;     nand.bad_block_offset = 5;    // nand.size = 0x4000000;    } else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */        nand_id == 0xecda || /* Samsung K9F2G08U0B */        nand_id == 0xecd3 ) { /* Samsung K9K8G08 */     nand.page_size = 2048;     nand.block_size = 128 * 1024;     nand.bad_block_offset = nand.page_size;    // nand.size = 0x8000000;    } else {     return -1; // hang    }    if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))     return -1; /* invalid alignment */       for (i=start_addr; i < (start_addr + size);) {   #ifndef CONFIG_S3C2410_NAND_SKIP_BAD /*不检查坏块*/    if (i & (nand.block_size-1)== 0) {      if (is_bad_block(&nand, i) ||          is_bad_block(&nand, i + nand.page_size)) {       /* Bad block */       i += nand.block_size;       size += nand.block_size;       continue;      }     }   #endif     j = nand_read_page_ll(&nand, buf, i);     i += j;     buf += j;    }       /* chip Disable */  

23

作者:guolele 2010-11-3  nand_deselect();       return 0;   }    

博客: http://hi.baidu.com/guolele1990/blog

/*===========================================================  到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误  ===========================================================*/  909090909090909090909090  4. 修改 board/gt2440/lowlevel_init.S 文件  由于这个是底层的初始化文件,所以要根据读者的开发板情况来配置或者修改 /board/gt2440/lowlevel_init.S 文件  /* REFRESH parameter 下面这 6 个配置都可以参考 s3c2440A datasheet P210 的 REFRESH 寄存器 */  #define REFEN             0x1    /* Refresh enable */  #define TREFMD             0x0    /* CBR(CAS before RAS)/Auto refresh */  #define Trp             0x01    /* 3clk 这个值可以参考本版子上的 SDRAM 的 datasheet*/  #define Trc             0x3    /* 也就是 SDRAM datasheet 里面的 Tsrc 7clk 本来这个地方 是 Trc, 但从 lowlevel_init.S 里面的调用来看, 应该是 s3c2440 的寄存器 REFRESH 的 Tsrc 才对,好多地方都没有改过来,只是个名字而已,不影响结果  注意:如果这里改了,那么下面这句中的 Trc 也要改为相应的  Tsrc:  .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)*/  #define Tchr             0x2    /* 3clk,这个从 lowlevel_init.S 里面的调用来看是属于 REFRESH 的保留位,不知道为什么还要给他赋值*/  #define REFCNT    1259 /*这个值的算法参考 s3c2440A datasheet P210 的 Refresh Counter  Refresh count = 2^11 + 1- HCLK * period  */     /*下面不厌其烦地解析一下 lowlevel_init.S 这个原文件*/     #define BWSCON  0x48000000  ……  #define Tchr      0x2 /* 3clk */ 

24

作者:guolele 2010-11-3 #define REFCNT      0x0459 

博客: http://hi.baidu.com/guolele1990/blog

/**************************************/  /*1.要知道上面这些配置的最终会被用到下面 SMRDATA 这个数据池里面,所以必须要明白 SMRDATA 这个数据池是用  来干什么的,SMRDATA 后面每一个.word 后面放置的数据都是将要写入 BWSCON 开始的寄 存器的,总共有 13 个.word ,它们后面放置的值将会分别写入 0x48000000、0x48000004、 0x48000008…一直到 0x48000030 共 13 个寄存器。 */  /*2.上面那些配置的值是怎样决定的呢,详细请参考 s3c2440A 和你所用 SDRAM 的 datasheet。细心找总是能找到的。*/  /*3.而上面的那些配置值最终是通过下面 lowlevel_init 后面的这段函数写到寄存器里面 的,下面对该段函数逐一分析:*/  _TEXT_BASE:       .globl lowlevel_init  lowlevel_init:            /* memory control configuration */  /* make r0 relative the current location so that it */  /* reads SMRDATA out of FLASH rather than memory ! */  ldr     r0, =SMRDATA  ldr r1, _TEXT_BASE  .word  TEXT_BASE 

    sub r0, r0, r1  /*其实明白了前三条语句这段程序就不难懂了, 归根到底就是为什么 将 SMRDATA 的值减去_TEXT_BASE 的值?  原因如下:  当笔者们编译出 uboot 的时候, 编译器会给 uboot 这程序定一个初始地址作为基地址, 其它 就以它为基准, 这个地址就是在 config.mk 里指定的 TEXT_BASE, 笔者的定为 0x33f80000。   笔者们使用的是从 nandflash boot 的方式,目前程序仍然在 4K-bytes ‘Steppingstone’ (即开始的 4K SRAM)上面运行。  现在代码还没有搬运到内存中,什么时候搬?就是下一段代码要做的。所以如果调用这个 label 的话,找不到数据的,因为那个位置没东西,那数据在哪?在 flash 中!!那怎么 找?其实 flash 是安排在 0x0 地址中的,所以真正的数据也是在相对于 0x0 的位置,那怎 么找?就是用你相对于 text_base 的位置减去 text_base 的不就可以吗?事实笔者们也是 这样做的。*/      0:          ldr     r3, [r0], #4  str     r3, [r1], #4  cmp     r2, r0  bne     0b  ldr r1, =BWSCON /* Bus Width Status Controller */  add     r2, r0, #13*4  /*总共 13 个寄存器*/ 

25

作者:guolele 2010-11-3             /* everything is fine now */  mov pc, lr 

博客: http://hi.baidu.com/guolele1990/blog

.ltorg  /*数据缓冲池,上网可以查得资料*/ 

/* the literal pools origin */     SMRDATA:     ……         .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)      .word 0xb2      .word 0x30  /*需要注意的是 CAS Latency 的值在这里直接配置*/  .word 0x30  /***********************************************************  到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误  ************************************************************/    5. 修改 board/gt2440/gt2440.c  这个文件主要板级初始化的任务(如:GPIO 初始化,lcd、网卡初始化类,PLL),修改的 地方主要包括:修改 PLL、增加 LCD 初始化函数(暂时没加)、修改 GPIO 设置、如果网上 不是 CS8900 还要添加网卡芯片的初始化函数。  这里主要修改 GPIO 设置和 PLL 设置  #elif FCLK_SPEED==1 /* Fout = 405MHz */   //#define M_MDIV 0x5c   //#define M_PDIV 0x4   //#define M_SDIV 0x0   #define M_MDIV 0x7f   #define M_PDIV 0x2   #define M_SDIV 0x1   #elif USB_CLOCK==1   //#define U_M_MDIV 0x48   //#define U_M_PDIV 0x3   #define U_M_MDIV 0x38   #define U_M_PDIV 0x2   #define U_M_SDIV 0x2  

26

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

/*对于 PLL 时钟问题,笔者把参考《ARM79 出口-u-boot 移植手册》,将 UPLLCON 的配置和 MPLLCON 的配置顺序颠倒一下(不颠倒也是可以工作的,但是 S3c2440 datasheet 文档中明 确规定,笔者们就按它说的去做吧)*/  /* configure UPLL */    clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) +   U_M_SDIV);        /* some delay between MPLL and UPLL */   delay(0xffff);  delay(0xffff);    delay(0xffff);       /* configure MPLL */    clk_power->MPLLCON = ((M_MDIV << 12       /* some delay between MPLL and UPLL */       delay(0xffff);    delay(0xffff);    delay(0xffff);  ......   /* set up the I/O ports */   gpio->GPACON = 0x007FFFFF;   //  gpio->GPBCON = 0x00044556;  gpio->GPBCON =0x3D57FC; /*for LED*/  ......   /* arch number of S3C2440 -Board */   gd->bd->bi_arch_number = MACH_TYPE_S3C2440 ;   /* adress of boot parameters */   gd->bd->bi_boot_params = 0x30000100;   icache_enable();   dcache_enable();   gpio->GPBDAT = 0x7f8e; /*for LED*/  //int board_init (void)设置完成后,LED1 和 LED2 会亮起!   return 0;   }   这里说明一下,gt2440.c 完成的板级初始化函数在哪里调用。其实它是被定义在  init_fnc_t *init_sequence[]  这个初始化函数指针集里的, 很熟悉吧?就是在前面介绍流程 board.c 里面, 它从汇编跳到 这执行 start_armboot()函数,在函数里一一执行。  /*=========================================================== 

27

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误  ===========================================================*/    6. /*   * High Level Configuration Options   * (easy to change)   */  #define CONFIG_ARM920T        1    /* This is an ARM920T Core    */  //#define    #define    CONFIG_S3C2440        1  /* 在前面很多地方调用到 CONFIG_S3C2440 ,他是在这 里定义  */  #define CONFIG_GT2440    1  /* 针对一些本开发板配置的宏控制*/  ......  /***********************************************************   * Command definition   ***********************************************************/  #define CONFIG_CMD_DHCP  #define CONFIG_CMD_ELF  #define CONFIG_CMD_PING   #define CONFIG_CMD_NAND  #define CONFIG_CMD_NET    #define CONFIG_CMD_ENV      #define    CFG_LONGHELP                  /* undef to save memory        */      /*这个宏和 CFG_CMD_LEGACY 控制调用 nand_init()的 地方(是在 nand.c 还是 gt2440.c)问题*/    /*在 board.c 里得到调用,判断是否使用 net*/  /*环境变量相关的宏*/  CONFIG_S3C2410      1  1  /* in a SAMSUNG S3C2410 SoC     */  /* on a friendly-arm SBC-2410X Board  */  实现 NAND flash 的读写,再次修改/include/configs/gt2440.h  这里主要是定义了两个宏和屏蔽了原来的宏,修改 

//#define CONFIG_SBC2410X 

28

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

#define    CFG_PROMPT   "[GT2440]#" /*这个就 是你启动开发板后命令行显示的内容了*/  /*Monitor Command Prompt  */  #define    CFG_CBSIZE        256          /* Console I/O Buffer Size    */  ......  #define    CFG_LOAD_ADDR      0x30008000   /*以后 linux kernel 就要放在这里执行 */   /* default load address    */    ......  //#define CFG_ENV_IS_IN_FLASH       1 /这里的 flash 应该是指 nor 了/  #define    CFG_ENV_IS_IN_NAND    1 /*定义这个宏的目的是为了调用 nand flash 类型的 saveenv 因为还有其它类型存储器的 saveenv, u-boot 中查看 saveenv 的定义, 在 有多少中 定义就有多少种*/  /*在 linux 对 nand flash 分区的时候,给 u-boot 分配 256k 的空间(0 ̄0x40000)  其中 u-boot.bin    [0x0 ̄0x30000]  占 192K  而   u-boot 的参数 [0x30000 ̄0x40000] 占 64k  */  #define CFG_ENV_OFFSET  0x30000    #define CFG_ENV_SIZE    0x10000   

/*注意:网上很多地方都有关于 CONFIG_CMD_NAND 、CFG_NAND_LEGACY、 drivers/mtd/nand/nand.c 中的 nand_init()函数以及 board/gt2440/GT2440.c 中的 nand_init()函数这四个东西的关系,他们就是一些宏,在不同的文件中有宏关系,从而实 现调用不同的 nand_init(),有兴趣可以跟踪一下,附录有他们调用的关系,这里笔者定义 了 CFG_NAND_LEGACY 和 CONFIG_CMD_NAND, 所以调用的是 gt2440.c 的 nand_init()函数, 现 在有没有?当然没有,要自己写,下一步骤就是修改这个*/  #define CFG_NAND_LEGACY     1  /*----------------------------------------------------------------------   * NAND flash settings   */  #if defined (CONFIG_CMD_NAND)  #define CFG_NAND_BASE 0x4E000000   它是 NAND 控制寄存器的基地址*/ 

/*这个宏在 drivers/mtd/nand/nand.c 中被调用,

29

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

/* NandFlash 控制器在 SFR 区起始寄存器地址 */  #define CFG_MAX_NAND_DEVICE 1  #define LARGE_NAND_FLASH  #ifndef LARGE_NAND_FLASH   /* 支持的最大 Nand Flash 数据 */  #define SECTORSIZE 512   /* 1 页的大小 */  #define NAND_SECTOR_SIZE SECTORSIZE   #define NAND_BLOCK_MASK 511   /*本 flash 一个 block 的大小-1*/  /* 页掩码 */  #define ADDR_COLUMN 1 /*意思是你所用的 nandflash 的 Column 地址占多少个字节*/  /* 一个字节的 Column 地址 */   #define ADDR_PAGE 3 /*意思是你所用的 nandflash 的(row)page 地址占多少个字节*/  /* 3 字节的页块地址!!!!!*/  #define ADDR_COLUMN_PAGE 4 /*意思是你所用的 nandflash 的 column 地址+page 地址共占 多少个字节*/  /* 总共 4 字节的页块地址!!!!! */  #else   /* 支持的最大 Nand Flash 数据 */  #define SECTORSIZE 2048   /* 1 页的大小 */  #define NAND_SECTOR_SIZE SECTORSIZE   #define NAND_BLOCK_MASK 2047  /* 页掩码 */  #define ADDR_COLUMN 2  /* 一个字节的 Column 地址 */   #define ADDR_PAGE 3  #define ADDR_COLUMN_PAGE  #endif    #define NAND_ChipID_UNKNOWN 0x00   /* 未知芯片的 ID 号 */  #define NAND_MAX_FLOORS 1    /*怎样算一 floor*/  #define NAND_MAX_CHIPS 1  /* Nand Flash 命令层底层接口函数 */  #define rNFCONF (*(volatile unsigned int *)0x4e000000)  #define rNFCONT (*(volatile unsigned int *)0x4e000004)  #define rNFCMD (*(volatile unsigned char *)0x4e000008)  #define rNFADDR (*(volatile unsigned char *)0x4e00000c)  #define rNFDATA (*(volatile unsigned char *)0x4e000010)  5    /*本 flash 一个 block 的大小-1*/    1  //原因是笔者这使用的是大容易 nand 为 2K 每页 

30

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

#define rNFSTAT (*(volatile unsigned int *)0x4e000020)  #define rNFECC (*(volatile unsigned int *)0x4e00002c)  /*下面部分内容是修改的*/  /* Nand Flash 命令层底层接口函数 ,函数哪里来?自己定义呗?所以下一步骤还要写这 些函数*/  /*  #define NAND_WAIT_READY(nand)  #define NAND_DISABLE_CE(nand)  #define NAND_ENABLE_CE(nand)  NF_WaitRB()  NF_SetCE(NFCE_HIGH)  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)    #define READ_NAND(adr)    */   #define WRITE_NAND_ADDRESS(d, adr) {rNFADDR = d;}  #define WRITE_NAND(d, adr) {rNFDATA = d;}  #define READ_NAND(adr) (rNFDATA)  #define NAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));}  #define WRITE_NAND_COMMAND(d, adr) {rNFCMD = d;}  #define WRITE_NAND_COMMANDW(d, adr)    NF_CmdW(d)     # if defined(CONFIG_S3C2440)  #define NAND_DISABLE_CE(nand) {rNFCONT |= (1<<1);}  #define NAND_ENABLE_CE(nand) {rNFCONT &=  ̄(1<<1);}  #endif  # if defined(CONFIG_S3C2410)  #define NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);}  #define NAND_ENABLE_CE(nand) {rNFCONF &=  ̄(1<<11);}  #endif    /* 允许 Nand Flash 写校验 打开下面宏定义*/  #define CONFIG_MTD_NAND_VERIFY_WRITE 1  ......  #endif    /* __CONFIG_H */  7. 在 board/gt2440/gt2440.c 的未尾添加对 nand flash 的初始化函数(在后面 nand 操作都要用到)    NF_Write(d)  NF_Read() 

31

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

#if defined(CONFIG_CMD_NAND) /*大概在 145 行*/  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_WaitRB(void)  { 

32

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

    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 u32 NF_Read_ECC(void)  {      S3C2410_NAND * const nand = S3C2410_GetBase_NAND();      return(nand->NFECC);  }    #if defined(CONFIG_S3C2440)  static inline void NF_Cont(u16 cont)   {      S3C2410_NAND * const nand = S3C2410_GetBase_NAND();      nand->NFCONT = cont;  }    static inline void NF_SetCE(NFCE_STATE s)  {      S3C2410_NAND * const nand = S3C2410_GetBase_NAND();      switch (s) { 

33

作者:guolele 2010-11-3     case NFCE_LOW:          nand->NFCONT &=  ̄(1<<1);          break;      case NFCE_HIGH:          nand->NFCONT |= (1<<1);          break;      }  }    static inline void NF_Init_ECC(void)  { 

博客: http://hi.baidu.com/guolele1990/blog

    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();      nand->NFCONT |= (1<<4);  }    #else  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;      } 

34

作者:guolele 2010-11-3 }    static inline void NF_Init_ECC(void)  { 

博客: http://hi.baidu.com/guolele1990/blog

    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();      nand->NFCONF |= (1<<12);  }  #endif /*对应#if defined(CONFIG_S3C2440)*/    static inline void NF_Init(void)  {  #if 0  #define TACLS 0  #define TWRPH0 3  #define TWRPH1 0  #else  #define TACLS 0  #define TWRPH0 4  #define TWRPH1 2  #endif    #if defined(CONFIG_S3C2440)      NF_Conf((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));      NF_Cont((0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1 )|(1<<0));   #else      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 */  #endif      NF_Reset(); 

35

作者:guolele 2010-11-3 }    #endif  8. 修改 cpu/arm920t/s3c24x0/Nand.c 

博客: http://hi.baidu.com/guolele1990/blog

很多人说 u-boot-1.3.4 已经不支持 CFG_NAND_LEGACY 了,但其实还是支持的,定 义了 CFG_NAND_LEGACY 后 Nand.c 要做如下修改:  #error "U-Boot legacy NAND support not available for S3C2410"  改成  // #error "U-Boot legacy NAND support not available for S3C2410"  /*到这里,编译是不能通过的,原因上一节中 CONFIG_S3C2410 这个宏定义被注释 掉,下面要用 CONFIG_S3C2440 这个宏打开 CONFIG_S3C2410 所打开的内容*/    9. 在 s3c2440 与 s3c2410 能够的文件中添加“CONFIG_S3C2440”,使得原来 s3c2410 的代码可以编译进来  (1)/include/common.h 文件的第 492 行:/*一些公用的常用函数,例如 get_fclk()*/  #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) ||  defined(CONFIG_LH7A40X) || defined(CONFIG_S3C2440)  (2)/include/s3c24x0.h:文件的第 85、95、99、110、148、404 行:/*一些关 于 S3C2440 寄存器的结构体*/  #if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)  (3)/cpu/arm920t/s3c24x0/interrupts.c 文件的第 33 行:/*主要把一些头文件 包含进去*/  #if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined  (CONFIG_TRAB) || defined (CONFIG_S3C2440)  第 38 行:  #elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)  (4)/cpu/arm920t/s3c24x0/serial.c 文件的第 22 行:/*主要把一些头文件包含 进去*/  #if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined  (CONFIG_TRAB) || defined (CONFIG_S3C2440)  第 26 行:  #elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)  (5)/cpu/arm920t/s3c24x0/speed.c 文件的第 33 行:  #if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined  (CONFIG_TRAB) || defined (CONFIG_S3C2440)  第 37 行:  #elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)  顺便修改源代码,以匹配 s3c2440:  static ulong get_PLLCLK(int pllreg)  { 

36

作者:guolele 2010-11-3    ......        m = ((r & 0xFF000) >> 12) + 8;      p = ((r & 0x003F0) >> 4) + 2;      s = r & 0x3; 

博客: http://hi.baidu.com/guolele1990/blog

/*这两个 PLL 的算法参见 S3C2440datasheet 的 254 页*/  #if defined(CONFIG_S3C2440)     if (pllreg == MPLL)      return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));  * CONFIG_SYS_CLK_FREQ  / 在 qljt2440.h 中定义*/      else if (pllreg == UPLL)  #endif        return((CONFIG_SYS_CLK_FREQ * m) / (p << s));  }  ......  /* return FCLK frequency */  ulong get_FCLK(void)  {      return(get_PLLCLK(MPLL));  }     /* return HCLK frequency */  ulong get_HCLK(void)  {      S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();   /*看看 s3c2410 与 s3c2440 的 datasheet 就知道 s3c2440 的 HCLK 可选择的值多很 */    if (clk_power->CLKDIVN & 0x6)     

37

作者:guolele 2010-11-3   { 

博客: http://hi.baidu.com/guolele1990/blog

       if ((clk_power->CLKDIVN & 0x6)==2)        return(get_FCLK()/2);  if ((clk_power->CLKDIVN & 0x6)==6)        return((clk_power->CAMDIVN &  0x100) ? get_FCLK()/6 : get_FCLK()/3);         /*注意这里的 CAMDIVN 还没有被 定义,在/include/s3c24x0.h 中定义 所以下一个大步骤就去定义*/        if ((clk_power->CLKDIVN & 0x6)==4)        return((clk_power->CAMDIVN &  0x200) ? get_FCLK()/8 : get_FCLK()/4);                   return(get_FCLK());   }    else   {          return(get_FCLK());       }  //    return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());  }  ......  (6)/cpu/arm920t/s3c24x0/usb_ohci.c 文件的第 45 行:  #elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)  (7)drivers/rtc/s3c24x0_rtc.c 文件的第 35 行:  #elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)   (8)在文件中添加“defined(CONFIG_GT2440)”,使得原来 SBC2410X 开发板的代 码可以编译进来,  /cpu/arm920t/s3c24x0/interrupts.c 文件的第 181 行:       #elif defined(CONFIG_SBC2410X) || \        defined(CONFIG_SMDK2410) || \        defined(CONFIG_VCMA9) || defined(CONFIG_GT2440)    tbclk = CFG_HZ; /*对于 CFG_HZ 的值,结合 uboot 的说明和 s3c2440datasheet 就比较容易理解*/ 

38

作者:guolele 2010-11-3 #else 

博客: http://hi.baidu.com/guolele1990/blog

(9)/cpu/arm920t/s3c24x0/usb.c 文件的第 31 行:   #elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)  (10)/cpu/arm920t/s3c24x0/i2c.c 文件的第 35 行:   #elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)  第 66、85、142、150、174 行:  将“#ifdef CONFIG_S3C2410”改为   #if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)  (11)drivers/usb/usb_ohci.c 文件的第 68 行附近:  #if defined(CONFIG_ARM920T) || \      defined(CONFIG_S3C2400) || \      defined(CONFIG_S3C2410) || \      defined(CONFIG_S3C2440) || \      defined(CONFIG_440EP) || \      defined(CONFIG_PCI_OHCI) || \      defined(CONFIG_MPC5200)    10. 在/include/s3c24x0.h 中加入 2440 的 NAND FLASH 寄存器定义和 CAMDIVN 定义:  typedef struct {       S3C24X0_REG32   LOCKTIME; 

         S3C24X0_REG32   MPLLCON;           S3C24X0_REG32   UPLLCON;           S3C24X0_REG32   CLKCON;           S3C24X0_REG32   CLKSLOW;           S3C24X0_REG32   CLKDIVN;           S3C24X0_REG32   CAMDIVN;  } S3C24X0_CLOCK_POWER;  ...... 

39

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

#if defined(CONFIG_S3C2410)  //2410 的 NAND FLASH 寄存器  typedef struct {           S3C24X0_REG32   NFCONF;           S3C24X0_REG32   NFCMD;           S3C24X0_REG32   NFADDR;           S3C24X0_REG32   NFDATA;           S3C24X0_REG32   NFSTAT;           S3C24X0_REG32   NFECC;  } S3C2410_NAND;  #endif  #if defined (CONFIG_S3C2440)  typedef struct {           S3C24X0_REG32   NFCONF;           S3C24X0_REG32   NFCONT;           S3C24X0_REG32   NFCMD;           S3C24X0_REG32   NFADDR;           S3C24X0_REG32   NFDATA;           S3C24X0_REG32   NFMECC0;           S3C24X0_REG32   NFMECC1;           S3C24X0_REG32   NFSECC;           S3C24X0_REG32   NFSTAT;           S3C24X0_REG32   NFESTAT0;           S3C24X0_REG32   NFESTAT1; 

40

作者:guolele 2010-11-3          S3C24X0_REG32   NFECC;  } S3C2410_NAND;  #endif    11. 修改/lib_arm 中的 board.c。  #include <common.h>  #include <command.h>  #include <malloc.h>  #include <devices.h>  #include <version.h>  #include <net.h>  #include <s3c2410.h>      ......    12. 修改 common/env_nand.c  这个文件主要是用来处理 

博客: http://hi.baidu.com/guolele1990/blog

......  #ifdef CONFIG_INFERNO  #error CONFIG_INFERNO not supported yet  #endif    int nand_legacy_rw (struct nand_chip* nand, int cmd,          size_t start, size_t len,          size_t * retlen, u_char * buf);  extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];  extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, size_t len,  int clean);    /* info for NAND chips, defined in drivers/nand/nand.c */  nand_info_t nand_info[CFG_MAX_NAND_DEVICE];    ......    #else /* ! CFG_ENV_OFFSET_REDUND */  int saveenv(void)  {      size_t total; 

41

作者:guolele 2010-11-3     int ret = 0; 

博客: http://hi.baidu.com/guolele1990/blog

    nand_erase_options_t nand_erase_options;        nand_erase_options.length = CFG_ENV_RANGE;      nand_erase_options.quiet = 0;      nand_erase_options.jffs2 = 0;      nand_erase_options.scrub = 0;      nand_erase_options.offset = CFG_ENV_OFFSET;        if (CFG_ENV_RANGE < CFG_ENV_SIZE)          return 1;      puts ("Erasing Nand...\n");  /*在 248 行附近*/  //    if (nand_erase_opts(&nand_info[0], &nand_erase_options))    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;  /*在 254 行附近*/  //    if (writeenv(CFG_ENV_OFFSET, (u_char *) env_ptr)) {  //        puts("FAILED!\n");  //        return 1;  //    } 

42

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

ret = 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;  }    #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)      size_t total;      int ret;        total = CFG_ENV_SIZE;  /*在 360 行附近*/  //    ret = readenv(CFG_ENV_OFFSET, (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);/*edited by yaoyi  20090314,1.3.4 是先进入到 readenv,而非直接调用 nand_legacy_rw。 因此干脆就不 用到 readenv 了,直接注释掉,添加以上代码 */      if (ret || total != CFG_ENV_SIZE)          return use_default();   

43

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

    if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)          return use_default();  #endif /* ! ENV_IS_EMBEDDED */  }    13. 修改 include/nand.h    虽然笔者用的是自己写的 nand_init,但是笔者这程序和其他程序都会用到 nand.h 里定义 的一些东西,所以还是要把这些定义加进来  .......  //#ifndef CFG_NAND_LEGACY   #include <linux/mtd/compat.h>   #include <linux/mtd/mtd.h>   #include <linux/mtd/nand.h>   .......  //#endif /* !CFG_NAND_LEGACY */  /*===========================================================  到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误  ===========================================================*/    14. 为了在 uboot 里显示你现在的 nand 的大小, 修改 include/linux/mtd/nand_ids.h 的结构体 nand_flash_ids   /*这个结构体是为了在初始化 nand 时,用读到的 id 和这里面匹配,如果有就输出该 nand 的信息*/  static struct nand_flash_dev nand_flash_ids[] = {  ....../*结构体 nand_flash_dev 在 doc2000.h 中定义*/  /*厂家 型号,生产商编号,本模块的编号,总共容纳地址的位数,存储页字节数 是否为 256 , 地址需要多少字节数减一(行列地址总共) , 擦除 1 个 block 的大小, 是否为 16 位总线*/      {"Samsung KM29N16000",NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000, 0},      {"Samsung K9F2G08U0B",    NAND_MFR_SAMSUNG, 0xDA, 28, 0, 4, 0x10000, 1},      {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000, 0},  ......   };        其中"Samsung K9F2G08U0B"是 nand 的名字,无关紧要  NAND_MFR_SAMSUNG 是该 nand 的 maker code 三星的是 0xec  0xDA 是本模块的编号,也就是 device code,笔者的为 0xda 

44

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

  28 是你的芯片总共容纳的地址位数,也就是有效的地址位数,个人认为是在输入地址 时,有效的那些位数是多少。这个地方控制你显示的大小的。  0, 即是否为 256 字节一页,笔者的为 2048 一页,所以为 0  0x10000 为擦除 1 个 block 的大小, 简单来说就是一个 block 的大小, flash 为 1block  本 = 32*1page = 32*2048 = 0x10000  1 为是否 16 位总线,笔者的为 16 位    假如没有移植这一步骤,会出现 nand=0MB 这种情况,还有会出现什么读到地址尾之类的    15. 修改 lib_arm 中的 board.c 添加几个 debug 信息,即点几个灯  #include <common.h>  #include <command.h>  #include <malloc.h>  #include <devices.h>  #include <version.h>  #include <net.h>     ......     static int display_banner (void)  {                  S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();           gpio->GPFBDAT =0x7f8e;    //在串口初始化和 console 初始化完成,串口输出信息之前,LED1、LED2、LED3 会亮起!      printf ("\n\n%s\n\n", version_string);      debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",             _armboot_start, _bss_start, _bss_end);      printf ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",              _armboot_start, _bss_start, _bss_end);        #ifdef CONFIG_MODEM_SUPPORT      debug ("Modem Support enabled\n"); 

45

作者:guolele 2010-11-3 #endif  #ifdef CONFIG_USE_IRQ 

博客: http://hi.baidu.com/guolele1990/blog

    debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);      debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);  #endif        return (0);  }     ......  void start_armboot (void)  {           init_fnc_t **init_fnc_ptr;           char *s;  #ifndef CFG_NO_FLASH           ulong size;  #endif  #if defined(CONFIG_VFD) || defined(CONFIG_LCD)           unsigned long addr;  #endif           S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();  ......           gpio->GPFDAT = 0x7f0e;    //在进入命令提示符之前,四个 LED 会同时亮起!           /* main_loop() can return to retry autoboot, if so just run it again.  */           for (;;) {                     main_loop (); 

46

作者:guolele 2010-11-3          }    

博客: http://hi.baidu.com/guolele1990/blog

         /* NOTREACHED - no way out of command loop except booting */  }  /*到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误*/    15. 裁减 flash 的支持 (这一步也可以不执行)  (1)在 board/qljt/qljt2440/flash.c 的头部加上:#if 0,尾部加上:#endif  (2)在 include/configs/qq2440.h 加上:  #undef CONFIG_CMD_FLASH  #undef CONFIG_CMD_IMLS  ….  #define CFG_NO_FLASH  1  (3)在 common/cmd_bootm.c 的”#include”语句后加上  #ifdef CONFIG_CMD_IMLS  #undef CONFIG_CMD_IMLS  #endif  16. 编译在这里, 如果你的 nor 不是上文说的是 AMD 的芯片, 那么你的 nor 显示也会不 正常,详情参考《ARM79 出品-uboot 移植手册》  附录:  二.  1.在 u-boot-1.3.2 前(不含 u-boot-1.3.2)nand_init 函数的调用关系,它的调用是被 “CONFIG_COMMANDS&  CFG_CMD_NAND”和“CFG_NAND_LEGACY”控制的,1:表示该值为真,0:表示该值为假  CONFIG_COMMANDS&  CFG_CMD_NAND  0  0  1  1    2.在 u-boot-1.3.2 后(含 u-boot-1.3.2)nand_init 函数的调用关系,它的调用是被 “CONFIG_CMD_NAND”和“CFG_NAND_LEGACY”控制的,1:表示该值为真,0:表示该值为假  CONFIG_CMD_NAND  CFG_NAND_LEGACY  /drivers/mtd/nand/nand.c 中的  0  1  0  1  CFG_NAND_LEGACY  /drivers/mtd/nand/nand.c 中的  nand_init()函数  0  0  1  0  0  0  1  1 

/board/qljt/qljt2440/qljt244 中的 nand_init()函数 

/board/qljt/qljt2440/qljt244 中的 nand_init()函数 

47

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog nand_init()函数 

0  0  1  1    三、调试 uboot 

0  1  0  1 

0  0  1  0 

0  0  1  1 

调试 uboot 有很多方法,其中主要分两大类,一是用 jlink 或者 jtag 然后使用调试工具, 如 GDB,AXD 以及 RVD 之类的,二是直接下载到内存中去运行  两种方法应该场合不一样,后一种是推荐使用,但是前提是要有网络,而前一种方法因为可 以实现单步源码级调试,有很多场合也非常有用,下面介绍一下  1、 使用 jlink 和 AXD  首先,打开 AXD 后,按 Alt+L 打开命令窗  对于命令窗,说明:  如果板子没有网口,在调试 U-Boot 和 uclinux 时就没法用 gdb 调试。  这时只能利用串口和 JTAG 口进行调试,linux 下可以用 BDI 这个玩意调试,可是 BDI 非常 昂贵,不适合大众需求。  我总结了下,根据我的调试经验,可以用 ADS 调试 linux 的程序。  打开 AXD,按下 Alt + L ;或者点 System Views 下 Command Line Interface,就可以打开 一个命令行:  输入 help 查看帮助文件。  比较有用的命令如:  LoadBinary = 将一个文件导入 RAM     LoadSymbols = 导入符号表                 SetPC = 设置 PC 寄存器                        Run = 开始运行  OB + 文件名 = 按照批处理文件运行  所有的命令在 GUI 里面也是有的,可以利用批处理文件(OB 命令)来免去敲命令和点菜单的 麻烦,  以调试 u-boot 为例,写一个批处理文件放在 D 盘,文件名为 u-boot.txt,内容如下:  loadbinary Y:\u-boot-1.1.4\u-boot.bin 0x33f80000  loadsymbols Y:\u-boot-1.1.4\u-boot  setpc 0x33f80000  run  打开 AXD,按下 ALT+L,键盘输入:ob d:\u-boot.txt  那么 AXD 会自动运行批处理文件内的命令,自动载入 u-boot 的二进制代码,自动载入符号 表,设置指针为 0x00100000,并开始运行。 

48

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

在调试时,最后自己一步步输入命令做  loadbinary 简写 lb,只能将二进制文件加载到 ram 中,不能将地址指定到 flash 中    在 loadsymbols 之后,等待进度条显示加载完成,将 setpc (pc)指到 u-boot.bin 的加 载位置,即可单步调试。  这时 ads 会提示寻找 u-boot 的入口文件 start.s 地址, 此时需要手动指定 start.s 的位置, 通常这时可以在 linux 下建立 smaba 服务共享,将整个 u-boot 的文件夹映射成 windows 下 一个盘符,这样就可以指定目录地址了。    在进入 c 语言代码中后,ads 还可能出现提示指定 board.c、string.c 等其他文件的地址, 这都需要手动做。  此后就可以用 ads 进行 c 语言级的 u-boot 源码调试了!  这种方法应该没问题的,因为我实验了很多次了,都成功了,这可是偶找了近一个月才弄清 楚的方法..........  同样,这种方法不知道是否可以用在 uclinux 上调试,正在进行试验。  参考地址:http://www.mcuzone.com/artical_index.html 下的使用 AXD 在 9261 上调试 u- boot。  按照上面说的,就可以调试到,其中软件会叫你指定一些文件,指定完就可以持到源文件, 在源文件上调试  二、出现的问题  ****************************************  在 nor flashs 模式下调试  ************************************  1、调试前如果没加上 Init script ,会出现 raise an exption,cause:The processor wa s reset.  所以参考开发板的配套资料  在命令行打入(我的 GT2440 是)  setmem 0x53000000,0x00000000,32  setmem 0x4a000008,0xffffffff,32  setmem 0x4a00001c,0x000007ff,32  setmem 0x53000000,0x00000000,32  setmem 0x56000050,0x000055aa,32  setmem 0x4c000014,0x00000007,32  setmem 0x4c000000,0x00ffffff,32  setmem 0x4c000004,0x00061012,32 

49

作者:guolele 2010-11-3 setmem 0x4c000008,0x00040042,32  setmem 0x48000000,0x22111120,32  setmem 0x48000004,0x00002f50,32  setmem 0x48000008,0x00000700,32  setmem 0x4800000c,0x00000700,32  setmem 0x48000010,0x00000700,32  setmem 0x48000014,0x00000700,32  setmem 0x48000018,0x0007fffc,32  setmem 0x4800001c,0x00018005,32  setmem 0x48000020,0x00018005,32  setmem 0x48000024,0x008e0459,32  setmem 0x48000028,0x00000032,32  setmem 0x4800002c,0x00000030,32  setmem 0x48000030,0x00000030,32  ——————————  用于初始化内存  —————————— 

博客: http://hi.baidu.com/guolele1990/blog

后面我把它写到一个 startrun.ini 里,然后用 ob ...就行了 

运行到 bl      lowlevel_init 运行不下去,有两种可能 

50

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

  第一种是 lowlevel_init 没有运行在前 4K 内存中  解决办法  方法一:  顶层 Makefile 文件中:  #__LIBS := ¥(subst ¥(obj),,¥(LIBS)) ¥(subst ¥(obj),,¥(LIBBOARD))  __LIBS := ¥(subst ¥(obj),,¥(LIBBOARD)) ¥(subst ¥(obj),,¥(LIBS))  这样修改之后查看 map 文件可以发现,lowlevel_init 函数链接到了前面.  方法二:  在不修改 Makefile 的情况下,可以通过修改目标板下的链接文件 u-boot.lds 来使 lowlev el_init 放在 4K 之内: cpu/arm920t/start.o (.text) board/net2410e/lowlevel_init. o (.text) 把之放到 start.o 的后面.  这相当于修改链接脚本,未做验证,我使用第一种方法!  第二种问题是解决第一种后,还出现 

51

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

  这个问题解决办法:  --------------------------------------------------------------------  为方便使用,同时,也是方便 u-boot 的调试。因此,我要将此 u-boot 代码再做一修改, 使其可以在内存中运行。这样,可以用  开发板自带的 vivi 将其下载到内存中,再在内存中运行 u-boot。要想它在内存中运行, 方法很简单,将/root/u-boot-  1.3.1/cpu/arm920t 中的 start.s 中  #ifndef CONFIG_SKIP_LOWLEVEL_INIT         bl       cpu_init_crit  #endif  此段代码中的 bl cpu_init_crit 注释掉,即不进行 CPU 的初始化工作(此工作,当前在板 子上运行的 vivi 已完成,故不能再次进行)  ,即改为  #ifndef CONFIG_SKIP_LOWLEVEL_INIT         @bl       cpu_init_crit  #endif  修改/board/hugerat/rat2440/config.mk 中 text_base 值为 0x33000000  使用 vivi 命令 load ram 0x33000000 0x17ea8 x 将 u-boot.bin 装入内存。 再用 go 0x3300 0000 命令,即可。  ******************************************************  直接在 nand flash 模式下调试  ---------------------------------------------------------  uboot 直接加载到 SDRAM 是不能运行的, 必须屏蔽掉 uboot 中的 CPU 及 RAM 初始化代码才行,   因为从 Norflash 启动时已经初始化过了。  **********************************  其实最简单的方法就是在你创建的头文件中定义 CONFIG_SKIP_LOWLEVEL_INIT 

52

作者:guolele 2010-11-3 其实就是跳过底层初始化 

博客: http://hi.baidu.com/guolele1990/blog

因为执行 lowlevel_init 会初始化 SDRAM,但是这工作在 NORflash 上已经执行,如果又执 行,则将清空  内存版 u-boot 的制作简单地说,就是注释掉不需要运行的相关代码,主要是:  1)内存,flash 的初始化  2)ARM 的内存重映射  3)相关时钟初始化  ***********************************  2、 用 tftp 下载在内存里调试  出自于:http://hi.baidu.com/guolele1990  首先,手头上要有的软硬件:  1、移植好的 uboot(具有 tftp 和 go 功能),可选用开发板配套的,这里我使用的是自己 移植的(比较有成功感)  2、tftp 就要有网线,这里这调试局限,要有网络,如果没有,可以使用 AXD 调试,详情请 看另一文章  3、串口线当然要,超级终端也是必须  开始:  1、下载移植好的 uboot(不是调试的,是成功的)  可下载到 nor 也可以 nand  2、下载要调试的 uboot 到内存中,需要了解几个信息  (1)内存的大小:SDRAM:64M(开发板不同而不同)  了解到内存是从 30000000 开始的,那 64M 就是 3000,0000 ̄3400,0000,这里有个问题,你 uboot 从 nor 或者 nand 运行时,再经过一系列拷贝之类,就在内存中运行,在哪里运行? 就是_TEXT_BASE=33f80000 的位置后 512K 中运行,所以移植如果超过 512 就要注意,这时 可以修改 board\开发板文件\config.mk 那时指定,当然现在不是这问题。现在是什么问题 呢?现在的问题是如果我还是把 uboot 用 tftp 下载到 33f80000里可不可以, 解决这问题前, 还有一个问题,我为什么下载到 33f80000?我们先看一段代码 start.S 里: 

53

作者:guolele 2010-11-3 ***************** CHECK_CODE_POSITION  ******************************************/   

博客: http://hi.baidu.com/guolele1990/blog

adr r0, _start /* r0 <- current position of code   */   ldr r1, _TEXT_BASE /* test if we run from flash or RAM */   cmp r0, r1   /* don't reloc during debug         */   beq stack_setup    /***************** CHECK_CODE_POSITION  ******************************************/  这段代码是检测你现在是否运行在 RAM 中,它怎么知道?就是看你开始的代码是不是为 text_base 的值,如果你移植的不是,那当然会再执行下面的 nor 或者 flash 拷贝了  解决上面这问题, 重新回到为什么不下载到 33f80000?我们知道, 它现在运行在 33f80000, 如果你再 tftp 进去,那不是把现在的执行中的代码都清除了?有什么后果?死机!!!  所以不能下载到 33f80000 里,那么应该下载到哪里?我应该是要下载到 TEXT_BASE 指定的 地址里的,所以我们要执行这样的操作:修改 TEXT_BASE 的值!!!  修改\board\开发板目录\config.mk  将 TEXT_BASE 改成 33000000 这个虽然顺便改,但是不能改到别的什么堆啊什么栈空间里, 这样程序也执行不下去,最好的就是修改到后面,面不影响原来的就可以。  (2)还有一个问题,就是底层初始化,底层初始化会将内存清空一次的,所以不应该让它 执行,所以在开发板头文件中应该定义:CONFIG_SKIP_LOWLEVEL_INIT  要解决的问题解决了,现在是下载  先打开开发板,执行移植好的 uboot,然后不 tftp 下载 uboot 到指定内存中 33000000,然 后执行  go 33000000  就可以运行了!!!    Uboot 移植到此结束,希望对大家有帮助,后面可能还会加其它功能,那只是后话。。 。。 

54

作者:guolele 2010-11-3

博客: http://hi.baidu.com/guolele1990/blog

提供一个移植 uboot 也做得非常好的网址, http://www.cublog.cn/u3/101649/showart_2276917.html  Guolele1990 

55


相关文章:
移植u-boot1.3.4到GT2440
移植u-boot1.3.4到GT2440_工程科技_专业资料。移植u-boot1.3.4到GT2440移植u-boot1.3.4 到 GT2440(尹强) (尹强) 1.准备一个干净的源码 1.准备一个干...
移植u-boot-1.3.4到S3C2440
移植u-boot-1.3.4到GT24... 89页 1下载券 ld命令和u-boot中的lds文.....2. 首先,U-Boot1.3.4 还没有支持 s3c2440,移植仍是用 2410 的文件稍作...
U-boot移植详解(基于s3c2440FL2440移植全纪录)
U-boot移植详解(基于s3c2440FL2440移植全纪录)_IT/计算机_专业资料。、U-...//r1 的内容为0 str r1, [r0] //将R1 的内容送到Ro 寄存器中去 3. 屏蔽...
基于ARM9 S3C2440的GT2440开发板的u-boot的移植
移植 u-boot-1.3.4 到 s3c2440》*/ 下载源码,网址: U-Boot 软件包...gt2440: 开发板的型号(BOARD),对应于 board/ GT2440 目录。 NULL: 开发者/...
S3C2440移植uboot过程全解+移植记录
S3C2440移植uboot过程全解+移植记录_计算机软件及应用_IT/计算机_专业资料。基于S3C2440uboot移植过程 一、 Uboot 移植前的准备 1、修改 makefile、配置文件 在...
u-boot在S3C2440上的移植问题及解决方法集锦(二)
u-boot在S3C2440上的移植问题及解决方法集锦(二)_...重新编译 u-boot, 下载到开发板, 运行,如图5所示...Linux内核在S3C2440上移... 31下载券 基于S3C...
天祥TX2440对u-boot的移植
天祥TX2440u-boot移植_计算机软件及应用_IT/计算机...我使用的是3.4.1,这里也可以写绝对路径 修改完 ...TX2440,把 smdk2410目录下的所有文件拷到 TX2440,...
移植U-Boot-2009.08到友善之臂mini2440
主要参考的是: Tekkaman Ninja:移植 U-Boot.1.3.1 到 S3C244 和 S3C2410 flyslightly:移植 U-Boot-2008.10 到友善之臂 mini2440 移植步骤将分为几个部分...
u-boot-2011.03在TQ2440上的移植--最新uboot移植文档
u-boot-2011.03在TQ2440上的移植--最新uboot移植文档_IT/计算机_专业资料。u...1、到 ftp://ftp.denx.de/pub/u-boot/下载 u-boot-2010.06.tar.bz2 2...
更多相关标签:
gt2440 uboot移植 | mini2440 uboot移植 | jz2440 uboot 移植 | tq2440 uboot移植 | s3c2440 uboot移植 | 2440 uboot移植 | fl2440 uboot移植 | u boot移植到2440 |