基于s3c2410的uboot1.2.0的分析以及移植

UBOOT1.2.0分析及移植

格式弄的太乱了,不过还是希望对大家有所帮助 :D,下面是参考资料,这些都是移植uboot必看的资料。


参考资料:

(1)http://blog.chinaunix.net/u1/34474/showart.php?id=363269

这位高手的blog是每位想进去嵌入式行业的同学必看的。

(2)<<smdk2410+uboo1.2.0..>>pdf文档,百度上可以搜到的,非常感谢原作者的分享

(3) <<linux全线移植文档>>PDF,其次也参考了很多其他的资料,非常敬佩大家的钻研与奉献精神!

工作环境:

uboot1.2.0

Ubuntu8.10

cross_compile3.3.2


绪论

描述当前嵌入式产品的发展现状;

描述sangsun公司的产品,简单介绍s3c2410,以及板载配置。

2 bootloader的介绍,不同种类优劣性比较


论文出发点:目前的论文主要是针对Uboot的编译与移植,侧重点在如何配置适合自己开发板的参数,并将它移植到开发板。但并没有对uboot的工作流程进行清晰的分析,如果能够从本质上掌握整个uboot的工作原理,开发嵌入式产品时的周期也将缩短。因此对uboot的分析是必要的。


4 uboot目录结构。u-boot的源码顶层目录说明

目    录 特    性                解 释 说 明
board                  
平台依赖          存放电路板相关的目录文件,
                                        
例如:RPXlite(mpc8xx)
                                        smdk2410(arm920t)

                                        sc520_cdp(x86) 
等目录

cpu                    
平台依赖          存放CPU相关的目录文件
                                        
例如:mpc8xxppc4xx
                                        arm720t
arm920t、 xscalei386等目录

lib_ppc                
平台依赖          存放对PowerPC体系结构通用的文件,
                                        
主要用于实现PowerPC平台通用的函数

lib_arm                
平台依赖           存放对ARM体系结构通用的文件,
                                         
主要用于实现ARM平台通用的函数

lib_i386               
平台依赖           存放对X86体系结构通用的文件,
                                         
主要用于实现X86平台通用的函数

include                
通用                头文件和开发板配置文件,
                                          
所有开发板的配置文件都在configs目录下

common               
通用                通用的多功能函数实现
lib_generic            
通用                通用库函数的实现
net                    
 通用                存放网络的程序
fs                     
 通用                存放文件系统的程序
post                   
 通用                存放上电自检程序
drivers               
  通用                通用的设备驱动程序,主要有以太网接口的驱动
disk                  
  通用                硬盘接口程序
rtc                   
  通用                RTC的驱动程序
dtt                   
  通用                数字温度测量器或者传感器的驱动
examples               
应用例程             一些独立运行的应用程序的例子,例如helloworld
tools                 
  工具                存放制作S-Record或者u-boot格式的映像等工具,
                                          
例如mkimage

doc                   
  文档                开发使用文档


简单介绍一下makefile,开始着手于源码的Makefile分析。在整个uboot目录中,makefile可以分为三类,

1)顶层makefile

2)结构makefile

3)子目录makefile

正式分析Makefilemakefile内容比较容易理解。

Ubootmakefile总共有50几页,但其中重要的内容折合起来也就十二三页。


6正式开始分析uboot源码。

根据/board/smdk2410目录下的u-boot.lds可知,函数入口处在/cpu/arm920t/start.S中的_start处,且从0x00000000地址处开始。

因此首先应该分析start.S文件,这是第一个执行的汇编文件,非常的重要。

(1) cpu/arm920t/start.S

uboot启动也分stage1stage2两个阶段。Uboot加载流程。2410上电,nandflash4kb的内容以硬件的方式被拷贝到SRAM中,SRAMcpu核中与nandflash配合的芯片从而实现nandflash的自启动系统。在SRAM中的部分uboot代码执行并在第2阶段执行之前,将nandflash中的uboot的全部代码拷贝到SDRAM中运行。然后引导内核与文件系统。

由上可以看出,这4kb以内代码必须要能够完成一些初始化工作。其实这就是我们平时所说的Uboot运行两阶段中的第一阶段。这部分短小的代码用汇编语言编写而成,也就是我们的start.S了。下面是总结的一张流程图

.globl _start

1 _start: b reset 运行以后,先跳转到reset标签处

。。。。。。

  1. reset:

reset主要完成以下的功能。

  1. 首先切换到svc超级用户模式。在系统复位和软件中断时可以进入这种模式。

  2. 关闭看门狗。看门狗可以用作16位的定时器来请求中断服务。并在固定时钟内产生复位信号所以要关闭。

  3. 屏蔽所有的中断。通过设置INTMSKINTSUBMSK寄存器来实现。

  4. 设置时钟。2410的时钟一般采用默认的,不用另外设置。

3 #ifndef CONFIG_SKIP_LOWLEVEL_INIT 跳转到cpu_init_crit

bl cpu_init_crit

#endif 接下来跳转到cpu_init_crit处。Bl指令是带返回的。PC值将指向下一条指令。

cpu_init_crit:从注释中可以了解到。它主要来设置一些重要的寄存器和内存时钟的设置。

MCR.MRC指令统称为协处理器寄存器传送指令。

MCR{cond} coproc,opcode1,Rd,CRn,CRm,{,opcode2}

Coproc:指令操作的协处理器名。标准名为pn,n0~15

mcr p15, 0, r0, c7, c7, 0例如这条指令就是将寄存器r0中的值送到协处理器p15c7中去。

mrc即是将协处理中的寄存器的内容送到外部的寄存器中。


在重定位之前,我们必须设置内存时序,因为内存时钟是依赖于开发版的。在lowlevel_init.S文件里可以得到解释。lowlevel_init.S主要定义了各Bank的内钟等等

之后mov ip, lr //保存当前的lr。即是当前的pc值,因为再下一条指令又要进行跳转了。。

bl lowlevel_init//同样,这是条带返回的跳转。指向下一条指令。

mov lr, ip

mov pc, lr

因为lowevel_init被声明为.globl,可以全局使用,虽然不在start.S文件中定义。因此可以直接跳转到/board/smdk2410/lowlevel.S中来执行这个命令了。


它主要完成内存控制的配置,设置当前的PCnandflash的起始位置。

下面是Lowlevel_init中的部分代码

BWSCONBUS WIDTH&WAIT CONTROL REGISTER 0x48000000

可以来选择哪个BANK

ldr r0, =SMRDATA //SMRDATA的地址传到r0中。

ldr r1, _TEXT_BASE //通过将_TEXT_BASE中的值加载到r1

sub r0, r0, r1 //r0=r0-r1??

ldr r1, =BWSCON /* Bus Width Status Controller */

add r2, r0, #13*4//SMRDATA13条指令。

0:

ldr r3, [r0], #4//SMDDATA中的值循环。主要是涉及了BAND0~7的时钟啊,内存刷新什么的

str r3, [r1], #4

cmp r2, r0

bne 0b


/* everything is fine now */

mov pc, lr//返回到cpu_init_crit

这样返回到了cup_init_crit中,

.....

mov ip,lr //ip中保存了reset中调用cpu_init_crit的下一条指令地址

bl lowlevel_init

mov lr, ip //Lowlevel_init返回后,执行这条指令。将ip传给lr

mov pc, l //再传给pc,这样就回到了reset的下一条指令处

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */


返回到reset处吧~~#endif等着我们,到这里reset就执行完成了。执行完成以后返回到原命令处。继续执行接下去的命令。

ldr pc, _undefined_instruction

ldr pc, _software_interrupt

ldr pc, _prefetch_abort

ldr pc, _data_abort

ldr pc, _not_used

ldr pc, _irq

ldr pc, _fiq

定义各种异常模式。每种异常模式都有对应的pc来存储异常指令地址。接着继续执行这条指令以后的汇编代码,具体还是要结合start.S源码看的。


另外在/board/smdk2410/config,mk目录下存储着这样的信息。

# SMDK2410 has 1 bank of 64 MB DRAM

#

# 3000'0000 to 3400'0000

#

# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000

# optionally with a ramdisk at 3080'0000

#

# we load ourself to 33F8'0000

#

# download area is 3300'0000

#

TEXT_BASE = 0x33F80000

定义了TEXT_BASE的地址。另外UBOOT_RAM_BASE _armboot_start 都是这个地址


Start.S继续向下执行,到达relocate代码段

relocate那段代码只针对从norflash中启动的设备有效,可要可不要,因此要是设备支持从nandflash启动,需要添加能将uboot拷贝到RAM中的代码。start.S本身是在SRAM中运行的,添加的这部分拷贝代码就是用来将剩余的内容全部拷贝到RAM中去了。

我们这里只是分析阶段。具体怎么在这里添加拷贝代码,参考第二部分 正式移植


在添加的拷贝代码中,执行了一条跳转到nand_read_ll的指令。此函数在board/smdk2410/nand_read,c中定义了。但是uboot的源码包中没有这个函数,我们可以从vivi中获取这个函数~通过这个函数来将uboot读取到RAM中。

执行完这个函数以后,接着从copy_myself返回!!!检验一下是否将uboot已全部读取到TEXT_BASE中,如果成功,则继续执行下一条关键指令!!

ldr pc,_start_armboot 将这个函数的地址值赋给PC,直接实现跳转!

_start_armboot: .word start_armboot 

开始跳转到/lib_arm/board.c中定义的start_armboot函数中执行了。到现在为止就是第2阶段正式开始了。Start.S文件分析也到此结束!!


2board.c也非常重要,并且start_armboot()函数定义lib_arm/board.c文件中。

board.c是个非常重要的文件。包括了CS8900网卡驱动函数的声明、内存函数初始化的函数mem_malloc_initnandflash初始化、波特率初始化函数、输出一些硬件信息....start_armboot本身主要完成网络的设置等,并最终进入到main_loop()函数。即循环等待。下面先介绍几个重要的数据结构。


1初始化函数序列init_sequence[]
  init_sequence[]
数组保存着基本的初始化函数指针。这些函数名称和实现的程序文件在下列注释中。

  init_fnc_t *init_sequence[] = {
         cpu_init,             /* 
基本的处理器相关配置 -- cpu/arm920t/cpu.c */
         board_init,           /* 
基本的板级相关配置 -- board/smdk2410/smdk2410.c */
         interrupt_init,       /* 
初始化例外处理 -- cpu/arm920t/s3c24x0/interrupt.c */
         env_init,             /* 
初始化环境变量 -- common/env_flash.c */
         init_baudrate,        /* 
初始化波特率设置 -- lib_arm/board.c */
         serial_init,          /* 
串口通讯设置 -- cpu/arm920t/s3c24x0/serial.c */
         console_init_f,       /* 
控制台初始化阶段1 -- common/console.c */
         display_banner,       /* 
打印u-boot信息 -- lib_arm/board.c */
         dram_init,            /* 
配置可用的RAM -- board/smdk2410/smdk2410.c */
         display_dram_config,  /* 
显示RAM的配置大小 -- lib_arm/board.c */
         NULL,
  };


全局数据结构

typedef struct global_data {全局数据

bd_t *bd; //板子数据指针

unsigned long flags;//指示标志,如设备已经初始化等。

unsigned long baudrate;//波特率定义

unsigned long have_console; /* serial_init() was called 串口初始化*/

unsigned long reloc_off; /* Relocation Offset */

unsigned long env_addr; /* Address of Environment struct 环境参数地址*/

unsigned long env_valid; /* Checksum of Environment valid? 环境参数CRC检验有效标志*/

unsigned long fb_base; /* base address of frame buffer 帧地址*/

#ifdef CONFIG_VFD

unsigned char vfd_type; /* display type */

#endif

#if 0

unsigned long cpu_clk; /* CPU clock in Hz! */

unsigned long bus_clk;

unsigned long ram_size; /* RAM size */

unsigned long reset_status; /* reset status register at boot */

#endif

void **jt; /* jump table */

} gd_t; include/asm-arm/Global_data.h中定义。全局数据变量指针,它保存了U-boot运行时需要的全局数据。


开发板数据结构

typedef struct bd_info {

int bi_baudrate; /* serial console baudrate */

unsigned long bi_ip_addr; /* IP Address */

unsigned char bi_enetaddr[6]; /* Ethernet adress即网卡地址 */

struct environment_s *bi_env;

ulong bi_arch_number; /* unique id for this board */

ulong bi_boot_params; /* where this board expects params启动参数 */

struct /* RAM configuration */

{

ulong start;

ulong size;

} bi_dram[CONFIG_NR_DRAM_BANKS];

#ifdef CONFIG_HAS_ETH1

/* second onboard ethernet port */

unsigned char bi_enet1addr[6];

#endif

} bd_t; include/asm-arm/u-boot.h中定义。描述开发板的数据结构。


4 voidstart_armboot (void)函数分析
   
{
       //
全局数据变量指针gd占用r8
          DECLARE_GLOBAL_DATA_PTR;
          
          /* 
给全局数据变量gd安排空间*/
          gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
          memset ((void*)gd, 0, sizeof (gd_t));
          
          /* 
给板子数据变量gd->bd安排空间*/
          gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
          memset (gd->bd, 0, sizeof (bd_t));
          monitor_flash_len = _bss_start - _armboot_start;//
u-boot的长度。
          
          /* 
顺序执行init_sequence数组中的初始化函数 */
          for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
                 if ((*init_fnc_ptr)() != 0) {
                         hang ();
                 }
          }
          
          /*
配置可用的Flash */
          size = flash_init ();
       
 ……
          /* 
初始化堆空间 */
          mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
          /* 
重新定位环境变量, */
          env_relocate ();
          /* 
从环境变量中获取IP地址 */
          gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
          /* 
以太网接口MAC 地址 */
          ……
          devices_init ();      /* 
设备初始化 */
          jumptable_init ();  //
跳转表初始化
          console_init_r ();    /* 
完整地初始化控制台设备 */
          enable_interrupts (); /* 
使能中断处理 */
          /* 
通过环境变量初始化 */
          if ((s = getenv ("loadaddr")) != NULL) {
                  load_addr = simple_strtoul (s, NULL, 16);
          }
          /* main_loop()
循环不断执行 */
          for (;;) {
                  main_loop ();      /* 
主循环函数处理执行用户命令 -- common/main.c */
          }
   }


U-boot-arm.h中定义了这个变量。

extern ulong _armboot_start; /* code start */

extern ulong _bss_start; /* code + data end == BSS start */

extern ulong _bss_end; /* BSS end */

extern ulong IRQ_STACK_START; /* top of IRQ stack */

extern ulong FIQ_STACK_START; /* top of FIQ stack */



分析完start_armboot函数后,下面再分析几个比较重要的文件。

1) include/configs/smdk2410.h

主要是定义了一些宏。用来选择处理器,设置时钟,定义内存池的大小。设置网卡CS8900,还有串口与时钟的设置。

一些命令的定义。主要是CONFIG_COMMANDS宏中。看名称就能猜到是定义命令的意思了。包括CFG_CMD_CACHE命令等等,如果要设置nandflash启动,那么必须要使CFG_CMD_NANDCFG_CMD_PINGCFG_CMD_NET三个选项有效。接下去的程序就定义了一些关于IP地址,网关的设置。以及关于内存起始地址CFG_MEMTEST_STARTCFG_MEMTEST_END的定义。还有一些栈的设置。包含了许多宏地址的定义。因此这个文件很重要!!最后一些就包括了FLASH的环境设置。要进行修改。将SDRAM的起始地址0x30000000 flashbank1 0x00000000 联系起来。下表是一些比较重要的宏定义。

1

PHY_FLASH_1

0X00000000

CFG_FLASH_BASE

PHY_FLASH_1

CFG_PROMPT

SMDK2410#” 开发板的用户名称

CFG_MEMTEST_START

0X30000000

CFG_MEMTEST_END

0X33F00000

CFG_LOAD_ADDR

0X33000000默认的加载地址

PHYS_SDRAM_1

OX30000000 SDRAM bank1

PHYS_SDRAM_1_SIZE

0X04000000

CFG_ENV_IS_IN_FLASH

1

CFG_ENV_SIZE

0X10000 64K

这个文件的主要功能就分析完了。我对源码做了比较好的分析,这里就不一一列举了。利用source insight进行查看。


2/include/Cmd_confdefs.h 这个文件包含了全部命令的宏定义,好像是定义宏的地址~~~~smdk2410.h定义部分命令后,则必须将这个头文件include 进来。


3/include/s3c2410.h/include/s3c24x0.h

首先先分析s3c24x0.h文件。这个文件中定义了所有的硬件资源寄存器。包括内存控制,USB控制,中断、DMA等等。主要是通过这些结构体定义的对象与s3c2410.h中定义的SFR基地址结合,定义这个某个寄存器有哪些状态寄存器。

该文件中。主要定义了特殊寄存的基地址。SFR的范围0x48000000~0x5A000000

s3c24x0.h中的部分内容

typedef struct {

S3C24X0_REG32 BWSCON;

S3C24X0_REG32 BANKCON[8];

S3C24X0_REG32 REFRESH;

S3C24X0_REG32 BANKSIZE;

S3C24X0_REG32 MRSRB6;

S3C24X0_REG32 MRSRB7;

} /*__attribute__((__packed__))*/ S3C24X0_MEMCTL

定义一个s3c24x0_MEMCTL对象,这个结构体中都是内存的相关寄存器。

下面是s3c2410.h中的部分代码。利用24x0中的对象来获取基地址。两者结合~

static inline S3C24X0_MEMCTL * const S3C24X0_GetBase_MEMCTL(void)

{

return (S3C24X0_MEMCTL * const)S3C24X0_MEMCTL_BASE;

先定义S3C24X0_MEMCTL结构体对象, 再在s3c2410.h中定义一个const函数,表示这个函数的返回值是不变的。


(4)/include/common.h、 /common/cmd_nand.c、 /common/command.c common目录下包括一些通用的函数、如网络、硬盘、串口、nandflash等等.

这个文件主要定义了uboot的所有命令的形式。

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}每个命令就是一个cmd_tbl_t的对象。即每个命令都有一个结构体来描述。包括命令名字、参数的最大个数、重复数、命令执行函数、用法、帮助。从控制台中输入的命令是又command.c完成的,而find_cmd函数用来匹配具体的某个命令。


7内存分布情况从高到低分配。

对于smdk2410,RAM范围从0x30000000~0x34000000. u-boot占用高端内存区的1M大小。从前面的分析可知内存分配大致如下:



内存图的分析:在start.S

gdbd共占128个字节的大小。在给malloc区和bd数据结构分配后,如果定义了IRQ,则给栈分配IRQ+FIQ8K大小的区。CONFIG_STACKSIZE_IRQ=4K如果没有定义,则至少保存12个字节。在smdk2410.h有定义。从0x33f00000x340000001M地址,是留给uboot使用的。下面是从代码中总结出的信息,不知道对不对。需要进一步验证。DW_STACK_START,建立堆栈,栈起点0x33f00000,大小为0x8000 32K大小的栈?UBOOT_RAM_BASE _TEXT_BASE相同0x33f80000 _arm_boot_start也为0x33f80000.uboot源码分析暂到此结束。其实还是有许多不明白的地方。以后发现什么新的了再添加吧

分析到此告一段落,下面进入uboot的具体移植

1)创建自己的工作目录。board目录下创建自己的工作目录,将smdk2410目录下的内容全部拷贝到tc2410目录下

cd board

mkdir tc2410

cp -fr board/smdk2410 board/tc2410

cp include/configs/smdk2410.h include/configs/tc2410.h

修改tc2410目录下相关的文件名以及makefile,。在这个目录下需要添加nand_read.c文件,可以从vivi里面拷贝过来,nand_read.c文件主要实现了start.S文件中的nand_read_ll读写函数,用来将uboot拷贝到内存里去。

需要修改的地方:mv smdk2410.c tc2410.cCOBJS := tc2410.o flash.o nand_read.o

修改顶层makefile,添加自己的信息:

tc2410_config    :    unconfig
        @$(MKCONFIG) $(@:_config=) arm arm920t tc2410 null s3c24x0


2修改start.S

禁止中断部分也要修改

# if defined(CONFIG_S3C2410)
    ldr    r1, =0x7ff   //
根据2410芯片手册,INTSUBMSK11位可用,
                       //vivi
也是0x7ff,不知为什么UBoot一直没改过来。
    ldr    r0, =INTSUBMSK
    str    r1, [r0]
# endif

将以下UBoot的重定向语句替换这段relocate代码只对从norflash中启动的设备有效,因此可以去掉
#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:
    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 */


替换成:

#ifdef CONFIG_S3C2410_NAND_BOOT  

@ reset NAND
  mov r1, #NAND_CTL_BASE
  ldr   r2, =0xf830           @ initial value
  str   r2, [r1, #oNFCONF]
  ldr   r2, [r1, #oNFCONF]
  bic  r2, r2, #0x800              @ enable chip
  str   r2, [r1, #oNFCONF]
  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, #0x1
  beq  nand2

  ldr   r2, [r1, #oNFCONF]
  orr  r2, r2, #0x800              @ disable chip
  str   r2, [r1, #oNFCONF]

@ 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
  mov     r1, #0x0
  mov r2, #0x20000
  bl    nand_read_ll
 
这个函数在nand_read.c中实现
  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
,这句话的意思在start.S中已注释。
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 @ CONFIG_S3C2410_NAND_BOOT 

在 “  _start_armboot:    .word start_armboot  ” 后加入:
   .align     2
DW_STACK_START:  .word  STACK_BASE+STACK_SIZE-4

start.S文件修改到此结束。






3)在include/configs/tc2410.h头文件中添加nandflash的初始化信息,这个文件与板子密切相关,需要修改的地方也很多。

具体添加信息/*//添加的内容

//#define CFG_ENV_IS_IN_FLASH 1

#define CFG_ENV_IS_IN_NAND 1

#define CFG_ENV_OFFSET 0x020000

#define CFG_NAND_BASE 0x4E000000

#define CMD_SAVEENV

#define CFG_NAND_LEGACY

#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */

#define CFG_MONITOR_BASE PHYS_SDRAM_1


#if (CONFIG_COMMANDS & CFG_CMD_NAND)

#define CFG_NAND_BASE 0x4E000000

/* NandFlash控制器在SFR区起始寄存器地址 */

#define CFG_MAX_NAND_DEVICE 1

/* 支持的最在Nand Flash数据 */

#define SECTORSIZE 512

/* 1页的大小 */

#define NAND_SECTOR_SIZE SECTORSIZE

#define NAND_BLOCK_MASK 511

/* 页掩码 */

#define ADDR_COLUMN 1

/* 一个字节的Column地址 */

#define ADDR_PAGE 3

/* 3字节的页块地址!!!!!*/

#define ADDR_COLUMN_PAGE 4

/* 总共4字节的页块地址!!!!! */

#define NAND_ChipID_UNKNOWN 0x00

/* 未知芯片的ID号 */

#define NAND_MAX_FLOORS 1

#define NAND_MAX_CHIPS 1

/* Nand Flash命令层底层接口函数 */

#define WRITE_NAND_COMMAND(d, adr) {rNFCMD = d;}

#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 NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);}

#define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);}

/* the following functions are NOP's because S3C24X0 handles this in hardware 一定要加上 */

#define NAND_CTL_CLRALE(nandptr)

#define NAND_CTL_SETALE(nandptr)

#define NAND_CTL_CLRCLE(nandptr)

#define NAND_CTL_SETCLE(nandptr)

/* 允许Nand Flash写校验 */

#define CONFIG_MTD_NAND_VERIFY_WRITE 1


//添加的内容

/*

* Nandflash Boot

*/

#define CONFIG_S3C2410_NAND_BOOT 1

#define STACK_BASE 0x33f00000

#define STACK_SIZE 0x8000

#define UBOOT_RAM_BASE 0x33f80000

/* NAND Flash Controller */

#define NAND_CTL_BASE 0x4E000000

#define bINT_CTL(Nb) __REG(INT_CTL_BASE + (Nb))

/* Offset */

#define oNFCONF 0x00

#define oNFCMD 0x04

#define oNFADDR 0x08

#define oNFDATA 0x0c

#define oNFSTAT 0x10

#define oNFECC 0x14

#define rNFCONF (*(volatile unsigned int *)0x4e000000)

#define rNFCMD (*(volatile unsigned char *)0x4e000004)

#define rNFADDR (*(volatile unsigned char *)0x4e000008)

#define rNFDATA (*(volatile unsigned char *)0x4e00000c)

#define rNFSTAT (*(volatile unsigned int *)0x4e000010)

#define rNFECC (*(volatile unsigned int *)0x4e000014)

#define rNFECC0 (*(volatile unsigned char *)0x4e000014)

#define rNFECC1 (*(volatile unsigned char *)0x4e000015)

#define rNFECC2 (*(volatile unsigned char *)0x4e000016)

#endif /* CONFIG_COMMANDS & CFG_CMD_NAND*/

#endif /*__CONFIG_H*/

4)我使用的是勤研开发板,在vivi里面并没有找到关于内存区配置的信息。lowlevel.init文件不知道如何修改。看见网上很多人说根据开发板的内存区情况配置,我找了半天没找到,郁闷至极。。。不过没有影响我成功移植,:-)


5)在include/linux/mtd/nand_ids.h的结构体nand_flash_ids加入nandflash的具体信息。

static struct nand_flash_dev nand_flash_ids[] = {

......
    {"Samsung KM29N16000",NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000, 0},
 
   
 {"Samsung K9F1208U0B",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0},
    {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000, 0},
......

{NULL,}

};

6修改/lib_arm中的board.c

static int display_banner (void)
{
    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地址信息    
        _armboot_start, _bss_start, _bss_end);      
#ifdef CONFIG_MODEM_SUPPORT
    debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
    debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
    debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

    return (0);
}


7修改common/env_nand.c,具体nandflash的擦写需要使用nand_legacy_erase等函数实现,而不是nand-erase()函数
......

#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 */
extern nand_info_t nand_info[CFG_MAX_NAND_DEVICE];

......

#else /* ! CFG_ENV_OFFSET_REDUND */
int saveenv(void)
{
    ulong total;
    int ret = 0;

    puts ("Erasing Nand...");
    //if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))

if (nand_legacy_erase(nand_dev_desc + 0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))
        return 1;


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

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)
    ulong total;
    int ret;

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


8/board/tc2410/tc2410.c文件的末尾添加对Nand Flash 的初始化函数(在后面Nand Flash的操作都要用到)

u-boot运行至第二阶段进入start_armboot()函数。其中nand_init()函数是对nand flash的最初初始化函数。Nand_init()函数在两个文件中实现。其调用与CFG_NAND_LEGACY宏有关,如果没有定义这个宏,系统调用 drivers/nnd/nand.c中的nand_init();否则调用board/smdk2410/smdk2410.c中的nand_init()函数。这里我选择第二种方式。


#if (CONFIG_COMMANDS & CFG_CMD_NAND)
typedef enum {
NFCE_LOW,
NFCE_HIGH
} NFCE_STATE;

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

nand->NFCONF = conf;
}

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

nand->NFCMD = cmd;
}

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

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

nand->NFADDR = addr;
}

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

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

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

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

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

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

nand->NFDATA = data;
}

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

return(nand->NFDATA);
}

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

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

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

return(nand->NFECC);
}

#endif

/*

* NAND flash initialization.
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe(ulong physadr);


static inline void NF_Reset(void)
{
int i;

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


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

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

NF_Reset();
}

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

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

9)移植的大部分问题是解决了,但是将Uboot烧进去后,可能还是会碰到问题。<<smdk2410+开发板u-boot-1>>这本pdf资料描述的问题我全都碰到了。呵呵,不过根据书上所提出的方法,我们都可以一一解决。

比如你如果没打开tc2410.h文件中的CFG_CMD_PING选项,使用ping 192.168.1.X命令时,可能ping不通。

不能保存环境变量,

Nand flash saveenv命令实现的函数 common/env_nand.c主要由以下几个宏决定:

CFG_CMD_ENV

CFG_CMD_NAND

CFG_ENV_IS_IN_NAND ---> 此宏决定调用 common/env_nand.c中的saveenv()函数,

如果定义CFG_ENV_IS_IN_FLASH宏,则调用 common/env_flash.c中的saveenv()函数

CFG_ENV_OFFSET 0X20000

#define CFG_NAND_BASE 0X4E000000

#define CMD_SAVEENV

#define CFG_NAND_LEGACY

#define CFG_ENV_SIZE 0x10000 //64kB

这些也是要在tc2410.h中添加的信息。

c tftp下载时出现TTTTTTTTTT然后超时的提示信息。我被这个问题困扰了很长时间,我也按照<<smdk2410+开发板u-boot-1>>这本pdf资料修改,将U_BOOT_CMD(

bootm, CFG_MAXARGS, 1, do_bootm,

"bootm - boot application image from memory\n",

"[addr [arg ...]]\n - boot application image stored in memory\n"

"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"

"\t'arg' can be the address of an initrd image\n"

/*#ifdef CONFIG_OF_FLAT_TREE

"\tWhen booting a Linux kernel which requires a flat device-tree\n"

"\ta third argument is required which is the address of the

"\tdevice-tree blob. To boot that kernel without an initrd image,\

"\tuse a '-' for the second argument. If you do not pass a third\

"\ta bd_info struct will be passed instead\n"

endif */

Ifdef注释掉以后,然后再将config.mk中的OsO2都改做O.

终端再输入:make distclean

make tc2410_config

make CROSS_COMPILE=arm-linux-

生成了uboot镜像,共110.4K。烧到板子里去后,使用tftp下载内核,搞定!!!终于把uboot搞定了,断断续续的大概花了1个多月的时间,参考了网上众多高手的心得以及很多不错的资料,总算勉强的弄出来Uboot了,但还是有很多问题没有弄清楚呵呵,不过还是挺有成就感的。


疑问:

可以在include/configs/smdk2410.h中添加nandflash的宏定义

2 board.c里面的start_armboot()函数需要调用nand_init,即nandflash的初始化。在drive/nand/nand.c中有这样一段代码

#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)

意思就是 如果没有定义CFG_NAND_LEGACY那么则调用nand.c文件中的nand_init()函数。这个是默认的初始化函数。但还有个board_nand_init()函数没有实现。为了安全起见,我们可以定义CFG_NAND_LEGACY,从而可以调用board/smdk2410/smdk2410.c中的nand_init()函数.这样我们需要在smdk2410.c中添加这个初始化函数。nand_legacy.c中添加这个nand_init()与在smdk2410.c中添加有什么区别??

board/smdk2410/smdk2410.c文件里只有board_init(),dram_init()函数,没有nand_init()函数。那这个函数去哪里实现。

3 nand_read_ll用来将代码拷贝到RAM中去,这个函数可以从vivi中拷贝过来



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值