目标:

开发环境:Ubuntu 12.04
开发板:JZ2440  256M NandFlash  64M SDRAM
交叉编译器:arm-linux-gcc-4.3.2
u-boot:u-boot-2012.04.01  

本节总结:

第一阶段:

 

uboot启动流程如下:

1.关看门狗
2.设置时钟
3.初始化SDRAM
(初始化寄存器以及清除bss段)
4.重定位
(将nand/nor中代码COPY到链接地址上,需要初始化nandflash,读flash)

 

  • 1)设置CPU为管理模式
  • 2)关看门狗
  • 3)关中断
  • 4)设置时钟频率
      
  • 5)关mmu,初始化各个bank
  • 6)进入board_init_f()函数
    (初始化定时器,GPIO,串口等,划分内存区域)
  • 7)重定位  
      复制uboot,然后修改SDRAM上的uboot链接地址)
  • 8)清bss
  • 9)跳转到board_init_r()函数,启动流程结束

5.执行main 

 


进入第二阶段:

 

 

6.写main函数,在main()中设置要传给内核的参数,然后跳转内核基地址处

 

1.首先来安装arm-linux-gcc-4.3.2交叉编译器

7.制作uboot.lds链接脚本

 

mkdir  arm-linux-gcc-4.3.2                 //创建目录

tar -xjf  arm-linux-gcc-4.3.2.tar.bz2 -C arm-linux-gcc-4.3.2/  //解压到arm-linux-gcc-4.3.2目录下

 

然后添加环境变量:

 

 

有两种方法,第一种只是临时修改,重启虚拟机便会复位:

编写步骤:

  最近在学习BootLoader,移植u-boot-2012.04.01到JZ2440开发板,现在把移植过程记录下来,一来梳理思路,二来方便以后更进一步学习。

export PATH=/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/bin:/usr/sbin:/usr/bin... ...
             //将arm-linux-gcc-4.3.2添加到环境变量

1.创建个名为”my_bootloader”根目录,方便编写uboot

 

第二种,重启不复位:

2.新建my_bootloader/si目录,创建source
insight工程

一、  u-boot分析过程

vi /etc/environment
添加:
PATH=/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/bin:/usr/sbin:/usr/bin... ...
                   //将arm-linux-gcc-4.3.2添加到环境变量

2.1
新建my_bootloader/start.S
(后缀名必须是大写的S,或者后面编译会报错)

    a、
初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH

2.然后进入ftp://ftp.denx.de/pub/u-boot/来下载u-boot-2012.04.01

编写start.S (第一阶段初始硬件文件):
start.s任务:
1.关看门狗
2.设置时钟
3.初始化SDRAM
4.重定位(把bootloader本身的代码从flash复制到它的链接地址(c函数编写),然后清空bss段(c函数编写))
5.执行main

 
  b、如果bootloader比较大,要把它重定位到SDRAM

2.1.创建source insight工程,来看代码

/*  看门狗寄存器            */
#define WTCON      0x53000000

/*  2.时钟寄存器            */
#define CLKDIVN    0x4C000014        //设置FCLK,HCLK,PCLK比例
#define MPLLCON   0x4C000004          //设置FCLK频率
#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))  //设置FCLK=200MHZ
#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))  //设置FCLK=400MHZ

/*  3.bank寄存器       */
#define BWSCON      0x48000000

.text                                /*设置代码段*/
.global   _start                  /*定义全局变量,要被连接脚本用到*/
_start:                           /*_start跳转到这里实现硬件初始化*/

    /*  1.关看门狗            */
       ldr r0,=WTCON
       mov r1,#0
       str r1,[r0]

    /*  2.设置时钟(必须设为异步总线模式)  */

       ldr r0,=CLKDIVN
       mov r1,#3                                  /*FCLK:HCLK:PCLK=1:2:4*/ 
       str r1,[r0]        
       mrc  p15, 0, r1, c1, c0                 /* 读出控制寄存器 */   
       orr   r1, r1, #0xc0000000         /* 设置为“asynchronous bus mode” */
       mcr    p15, 0, r1, c1, c0, 0             /* 写入控制寄存器 */       
       ldr r0,=MPLLCON
       ldr r1,=S3C2440_MPLL_200MHZ      //使用复杂的数不能用mov,需要用ldr
       str r1,[r0]

    /*  3.初始化SDRAM       */
       ldr r0,=BWSCON                   //r0=SDRAM寄存器基地址
       adr r1,SDRAM_CONFIG           //使用adr相对跳转,因为SDRAM未初始化
       add r2,r0,#(13*4)               //r2等于 SDRAM尾地址+4

0:
       ldr r3,[r1],#4                      //r3=r1里的  内容, &r1+=4;
       str r3,[r0],#4                      //*r0=r3,&r0+=4
       cmp r0,r2
       bne 0b                               //(ne:no equal   b:bank)   若r0!=r2,跳转到后面的0处

 /*  4.重定位                 */
        ldr sp,=0x34000000                     //64Msdram,所以设置栈SP=0x34000000,避免堆栈溢出
        mov r0,#0                           //r0->src
    ldr r1,=_start                     //r1->dest
    ldr r2,=__bss_start            //r2->len->__bss_start-_start
    sub r2,r2,r1
    bl copy_code_to_sdram          //复制代码到SDRAM连接地址dest上
    bl clear_bss                         //清除bss段 

   /*  5.执行main                */
        ldr lr,=halt                         //执行一个子程序调用返回时,需要先将返回地址赋给lr链接寄存器
        ldr pc,=main                              //初始化SDRAM后,可以使用pc 绝对跳转到SDRAM地址上
        mov pc,lr                             //若main函数跳出后,使PC等于lr链接寄存器,避免程序跑飞 

halt:                                   //死循环,避免跑飞
     b halt               

SDRAM_CONFIG:
    .long 0x22011110;     //BWSCON
    .long 0x00000700;     //BANKCON0
    .long 0x00000700;     //BANKCON1
    .long 0x00000700;     //BANKCON2
    .long 0x00000700;     //BANKCON3  
    .long 0x00000700;     //BANKCON4
    .long 0x00000700;     //BANKCON5
    .long 0x00018005;     //BANKCON6
    .long 0x00018005;     //BANKCON7
    .long 0x008C04F4;     //REFRESH
    .long 0x000000B1;     //BANKSIZE 
    .long 0x00000030;     //MRSRB6
    .long 0x00000030;     //MRSRB7

    c、把内核从NAND FLASH读到SDRAM

1)在board 目录下只添加:

3
新建my_bootloader/init.c,用于重定位,bss段清除,初始化NandFlash等

    d、设置”要传给内核的参数”

board/samsung/smdk2410/               // (2410单板文件)

在重定位函数中的nand驱动在(入口:.

    e、跳转执行内核

 2)在arch 目录下只添加:

3.1编写copy_code_tosdram()
重定位函数

具体代码分析

arch/arm/cpu/arm920t/                //(只添加这个目录下的*.c,*.S公用文件)                

arch/arm/cpu/arm920t/s3c24x0/        //(24x0架构所有文件)

arch/arm/include/asm/                //(只添加这个目录下的*.h公用头文件)

arch/arm/include/asm/proc-armv/      //(arm架构的文件)

arch/arm/include/asm/arch-s3c24x0/   //(24x0架构头文件)

arch/arm/lib/                        //(与arm相关的库文件)
void copy_code_to_sdram(unsigned char *src,unsigned char *dest,unsigned int len)            //复制代码到SDRAM连接地址dest上
{
      unsigned int i;
        /*判断nor启动还是nand启动*/
    if(is_boot_from_norflash())                 //nor启动,直接复制
    {
              for(i=0;i<len;i++)
              {
               dest[i]=src[i];
              }
    }
    else
    {
       nand_init();

    nand_read((unsigned int)src,dest,len);

    }
} 

1、set the cpu to SVC32 mode

3)在include/configs目录下只添加:

3.2编写isBootFramNorFlash()函数,来判断nand启动还是nor启动

2、turn off the watchdog

include/configs/smdk2410.h              // (用来配置2410单板的头文件)
/*判断nor启动还是nand启动*/
unsigned char is_boot_from_norflash(void)
{
         volatile unsigned int *p=(volatile unsigned int *)0;
     unsigned int i;
     i=*p;
     *p=0x12345678;
     if(*p==0x12345678)    //nand
     {
     *p=i;
     return 0;
     }
     else                    //nor
     {
        *p=i;
     return 1;
     }

3、mask all IRQs by setting all bits in
the INTMR

 2.2编译烧写:

3.3编写clear_bss()函数

4、设置时钟比例

tar xjf u-boot-2012.04.01.tar.bz2

cd u-boot-2012.04.01                 //进入解压后文件目录

make smdk2410_config                 //由于该uboot不支持2440板卡,所以只有配置2410板卡

make                                 //编译,生成u-boot.bin 
void clear_bss(void)  //清除BSS段
{
  extern int __bss_start,__bss_end;
  int  *p=&__bss_start;
  for( ;p<&__bss_end;p++)
  {
  *p=0;
  }
}

5、设置内存控制器

 

4编写连接脚本uboot.lds
(参考硬件实验里的uart.lds和u-boot-1.1.6里的u-boot.lds)

6、设置栈,调用C函数board_init_f

3.最后烧写u-boot.bin,发现无法启动,接下来便来分析uboot的启动流程

SECTIONS {
    . = 0x33f80000; //0地址里存放0X33F80000
    . = ALIGN(4);

    .text : { *(.text) }
    . = ALIGN(4);

    .rodata : { *(.rodata)  }
    . = ALIGN(4);

    .data : {   *(.data)    }
    . = ALIGN(4);

    __bss_start = .; 
    .bss : { *(.bss) *(COMMON) }
    __bss_end = .;
}

7、调用函数数组init_sequence里的各个函数

 4.首先查看arch/arm/cpu/u-boot.lds链接脚本

其中0x33f80000就是链接地址首地址,共512K空间存放bootloader
定义__bss_start和__bss_end符号,是用来程序开始之前将这些未定义的变量清0,节省内存
且bss_start-0x33f80000就等于代码的大小(copy_code_tosdram函数中len值)

    7.1 board_early_init_f :
设置系统时钟、设置GPIO

如下图所示,看到uboot最开始会进入_start:

 

………………………………..

 图片 1

8、重定位代码

 5.
_start位于arch/arm/cpu/arm920t/start.S     
    

    8.1 从NOR
FLASH把代码复制到SDRAM

所以,我们从start.S开始分析uboot启动流程:

   
8.2 程序的链接地址是0,访问全局变量、静态变量、调用函数时是使”基于0地址编译得到的地址”,现在把程序复制到了SDRAM,需要修改代码,把”基于0地址编译得到的地址”改为新地址。

.globl _start                                //声明_start全局符号,这个符号会被lds链接脚本用到
_start:    
b     start_code                            //跳转到start_code符号处,0x00
       ldr   pc, _undefined_instruction                    //0x04
       ldr   pc, _software_interrupt                       //0x08
       ldr   pc, _prefetch_abort                           //0x0c
       ldr   pc, _data_abort                               //0x10
       ldr   pc, _not_used                                 //0x14
       ldr   pc, _irq                                      //0x18
       ldr   pc, _fiq                                      //0x20

_undefined_instruction:  .word undefined_instruction
           //定义_undefined_instruction指向undefined_instruction(32位地址)

_software_interrupt:      .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:          .word data_abort
_not_used:             .word not_used
_irq:               .word irq
_fiq:               .word fiq

   .balignl 16,0xdeadbeef        //balignl使用,参考http://www.cnblogs.com/lifexy/p/7171507.html

   
8.3 程序里有些地址在链接时不能确定,要到运行前才能确定:fixabs

 其中符号保存的地址都在顶层目录/system.map中列出来了

9、clear_bss

 

10、调用C函数board_init_r:第2阶段的代码

6.
从上面看到, _start会跳转到start_code处

 

start_code:

    /*设置CPSR寄存器,让CPU进入管理模式*/
       mrs  r0, cpsr                 //读出cpsr的值
       bic   r0, r0, #0x1f           //清位
       orr   r0, r0, #0xd3          //位或
       msr  cpsr, r0                 //写入cpsr

#if   defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
       /*
        * relocate exception table
        */
       ldr   r0, =_start            
       ldr   r1, =0x0                //r1等于异常向量基地址
       mov r2, #16
copyex:
       subs       r2, r2, #1           //减16次,s表示每次减都要更新条件标志位
       ldr   r3, [r0], #4       
       str   r3, [r1], #4      //将_start标号后的16个符号存到异常向量基地址0x0~0x3c处
       bne  copyex             //直到r2减为0
#endif

#ifdef CONFIG_S3C24X0

       /* 关看门狗*/
#  define pWTCON       0x53000000
#  define INTMSK 0x4A000008    /* Interrupt-Controller base addresses */
#  define INTSUBMSK  0x4A00001C
#  define CLKDIVN       0x4C000014    /* clock divisor register */

       ldr   r0, =pWTCON       
       mov r1, #0x0        
       str   r1, [r0]           //关看门狗,使WTCON寄存器=0

       /*关中断*/
       mov r1, #0xffffffff
       ldr   r0, =INTMSK
       str   r1, [r0]                  //关闭所有中断
# if defined(CONFIG_S3C2410)
       ldr   r1, =0x3ff
       ldr   r0, =INTSUBMSK
       str   r1, [r0]                  //关闭次级所有中断
# endif

    /* 设置时钟频率, FCLK:HCLK:PCLK = 1:2:4 ,而FCLK默认为120Mhz*/
       ldr   r0, =CLKDIVN
       mov r1, #3
       str   r1, [r0]

 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
       bl    cpu_init_crit                         //关闭mmu,并初始化各个bank

#endif

call_board_init_f:
       ldr   sp, =(CONFIG_SYS_INIT_SP_ADDR) //CONFIG_SYS_INIT_SP_ADDR=0x30000f80
       bic   sp, sp, #7         //sp=0x30000f80
       ldr   r0,=0x00000000
       bl    board_init_f   

二、初始编译

 上面的CONFIG_SYS_INIT_SP_ADDR
=0x30000f80,是通过arm-linux-objdump -D
u-boot>u-boot.dis生成反汇编,然后从u-boot.dis得到的,如下图所示:

 1、
 解压 u-boot-2012.04.01.tar.bz2

 图片 2

tar xjf u-boot-2012.04.01.tar.bz2

 

进入解压后文件目录

 

cd u-boot-2012.04.01

7.然后进入第一个C函数:board_init_f()

2、在解压后文件目录下根据靠近的单板,配置

该函数主要工作是:

make smdk2410_config
make

清空gd指向的结构体、通过init_sequence函数数组,来初始化各个函数以及逐步填充gd结构体,最后划分内存区域,将数据保存在gd里,然后调用relocate_code()对uboot重定位

这个时候编译完成后是不能在JZ2440上正常运行

(gd是用来传递给内核的参数)

三、建立自己的单板,定制适合自己单板的bootloader

1)具体代码如下所示:

1、新建一个单板

void board_init_f(ulong bootflag) // bootflag=0x00000000
{
       bd_t *bd;
       init_fnc_t **init_fnc_ptr;         //函数指针
       gd_t *id;
       ulong addr, addr_sp;
#ifdef CONFIG_PRAM
       ulong reg;
#endif

       bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");
       /* Pointer is writable since we allocated a register for it */
       gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
    cd board/samsung/
    cp smdk2410 smdk2440 -rf
     cd ../../include/configs/
    cp smdk2410.h smdk2440.h

 其中gd是一个全局变量,用来传递给内核的参数用的,如下图所示,在arch/arn/include/asm/global_data.h中定义,*gd指向r8寄存器,所以r8专门提供给gd使用

修改boards.cfg

 图片 3

仿照2410,添加2440

而CONFIG_SYS_INIT_SP_ADDR,在6节里得到=0x30000f80,所以gd=0x30000f80

smdk2410                     arm         arm920t     -                  samsung        s3c24x0

 2)继续来看board_init_f():

添加

      __asm__ __volatile__("": : :"memory");           //memory:让cpu重新读取内存的数据

      memset((void *)gd, 0, sizeof(gd_t));        //将0x30000f80地址上的gd_t结构体清0

      gd->mon_len = _bss_end_ofs;  
         // _bss_end_ofs =__bss_end__ - _start,在反汇编找到等于0xae4e0,所以mon_len等于uboot的数据长度
      gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob);

       for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
            //调用init_sequence[]数组里的各个函数
      {
              if ((*init_fnc_ptr)() != 0)     //执行函数,若函数执行出错,则进入hang()
             {    
           hang ();   //打印错误信息,然后一直while
             }

       }
smdk2440                     arm         arm920t     -                   samsung        s3c24x0

 上面的init_sequence[]数组里存了各个函数,比如有:

make , 烧写调试

  • board_early_init_f():设置系统时钟,设置各个GPIO引脚
  • timer_init():初始化定时器
  • env_init():设置gd的成员变量
  • init_baudrate():设置波特率
  • dram_init():设置gd->ram_size=
    0x04000000(64MB)

2、根据需求进一步配置

3)继续来看board_init_f():

make menuconfig  
addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;  // addr=0x34000000 
// CONFIG_SYS_SDRAM_BASE:  SDRAM基地址,为0X30000000
// gd->ram_size:          等于0x04000000 


#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
       /* reserve TLB table */
       addr -= (4096 * 4);        //addr=33FFC000

       addr &= ~(0x10000 - 1);  // addr=33FF0000,   

       gd->tlb_addr = addr;   //将64kB分配给TLB,所以TLB地址为33FF0000~33FFFFFF
#endif

       /* round down to next 4 kB limit */
       addr &= ~(4096 - 1);                    //4kb对齐, addr=33FF0000
       debug("Top of RAM usable for U-Boot at: %08lx\n", addr);

       /*
        * reserve memory for U-Boot code, data & bss
        * round down to next 4 kB limit
        */
       addr -= gd->mon_len; // 在前面分析过gd->mon_len=0xae4e0,
                           //所以addr=33FF0000 -0xae4e0=33F41B20,

       addr &= ~(4096 - 1);  //4095=0xfff,4kb对齐, addr=33F41000
                             //所以分配给uboot各个段的重定位地址为33F41000~33FFFFFF
       debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

#ifndef CONFIG_SPL_BUILD
       addr_sp = addr - TOTAL_MALLOC_LEN; //分配一段malloc空间给addr_sp
                       //TOTAL_MALLOC_LEN=1024*1024*4,所以malloc空间为33BF1000~33F40FFF

       addr_sp -= sizeof (bd_t);            //分配一段bd_t结构体大的空间
    bd = (bd_t *) addr_sp;               //bd指向刚刚分配出来的bd_t结构体
    gd->bd = bd;                         // 0x30000f80处的gd变量的成员bd等于bd_t基地址

    addr_sp -= sizeof (gd_t);              //分配一个gd_t结构体大的空间
    id = (gd_t *) addr_sp;                 //id指向刚刚分配的gd_t结构体
    gd->irq_sp = addr_sp;                 //0x30000f80处的gd变量的成员irq_sp等于gd_t基地址

    addr_sp -= 12;
    addr_sp &= ~0x07;
    ... ...

    relocate_code(addr_sp, id, addr);  //进入relocate_code()函数,重定位代码,以及各个符号
    // addr_sp: 栈顶,该栈顶向上的位置用来存放gd->irq_sp、id 、gd->bd、malloc、uboot、TLB(64kb),
    //id:       存放 gd_t结构体的首地址
    // addr:    等于存放uboot重定位地址33F41000
}

3、修改Makefile
,开头指定架构和编译器

 执行完board_init_f()后,最终内存会划分如下图所示:

 ARCH=arm
 CROSS_COMPILE=arm-linux-

 图片 4

4、修改uboot代码,适合单板

其实此时uboot还在flash中运行,然后会进入start.S的relocate_code()里进行uboot重定位 

  uboot里先以60MHZ的时钟计算参数来设置内存控制器,但是MPLL还未设置

8.接下来进入重定位

  处理措施:
把MPLL的设置放到start.S里,取消board_early_init_f里对MPLL的设置

1)start.S的relocate_code()代码如下所示

a、设置PLL的时钟的函数在_main中的board_init_f中初始化函数列表中的 
boad_early_init_f
中,设置MPLL倍频值。它应该要在设置分频系数和初始化内存控制器之前来设置。

relocate_code:
       mov r4, r0      /* save addr_sp */              // addr_sp栈顶值
       mov r5, r1      /* save addr of gd */           // id值
       mov r6, r2      /* save addr of destination */  // addr值:uboot重定位地址

       /* Set up the stack        */
stack_setup:
       mov sp, r4                //设置栈addr_sp
       adr  r0, _start           //在顶层目录下system.map符号文件中找到_start =0,所以r0=0
       cmp r0, r6                //判断_start(uboot重定位之前的地址)和addr(重定位地址)是否一样
       beq clear_bss             /* skip relocation */ 

       mov r1, r6             /* r1 <- scratch for copy_loop */ //r1= addr(重定位地址)
       ldr   r3, _bss_start_ofs               //_bss_start_ofs=__bss_start - _start(uboot代码大小)
       add r2, r0, r3         /* r2 <- source end address*/   //r2= uboot重定位之前的结束地址

copy_loop:
       ldmia      r0!, {r9-r10}  /* copy from source address [r0] */
                              //将r0处的两个32位数据拷到r9-r10中,然后r0+=8

       stmia      r1!, {r9-r10}  /* copy to   target address [r1]*/
                             //将拷出来的两个数据放入r1(重定位地址)处,然后r1+=8

       cmp r0, r2  /* until source end address [r2]*/   //判断拷贝的数据是否到结束地址
       blo  copy_loop

做如下修改: 在smdk2410.c文件中找到设置MPLL部分的代码,注释掉。

 上面只是把代码复制到SDRAM上,而链接地址内容却没有改变,比如异常向量0x04的代码内容还是0x1e0,

    /* to reduce PLL lock time, adjust the LOCKTIME register */
         //writel(0xFFFFFF, &clk_power->locktime);

      /* configure MPLL */
         //writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,
           //     &clk_power->mpllcon);

我们以异常向量0x04为例,来看它的反汇编:

然后在start.S中再设置MPLL

 图片 5

 

如上图所示,即使uboot在SDRAM运行,由于代码没修改,PC也会跳到0x1e0(flash地址)

图片 6图片 7

和之前老的uboot有很大区别,以前老的uboot直接是使用的SDRAM链接地址,如下图所示:

#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
#if 0
    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr    r0, =CLKDIVN
    mov    r1, #3
    str    r1, [r0]
  #else
        /* 2. 设置时钟 400MHz */
        ldr r0, =0x4c000014
        //  mov r1, #0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
        mov r1, #0x05;            // FCLK:HCLK:PCLK=1:4:8
        str r1, [r0]
        /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
        mrc p15, 0, r1, c1, c0, 0       /* 读出控制寄存器 */
        orr r1, r1, #0xc0000000         /* 设置为“asynchronous bus mode” */
        mcr p15, 0, r1, c1, c0, 0       /* 写入控制寄存器 */

        #define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
        /* MPLLCON = S3C2440_MPLL_200MHZ */
        ldr r0, =0x4c000004
        ldr r1, =S3C2440_MPLL_400MHZ
        str r1, [r0]

        /* 启动ICACHE */
        mrc p15, 0, r0, c1, c0, 0   @ read control reg
        orr r0, r0, #(1<<12)
        mcr p15, 0, r0, c1, c0, 0   @ write it back
  #endif

 图片 8

View Code

所以,新的uboot采用了动态链接地址的方法,在链接脚本uboot.lds中,可以看到这两个段(.rel.dyn、.dynsym):

 

 图片 9

关闭看门狗、关中断

该两个段里,便是保存了各个文件的相对动态信息(.rel.dyn)、动态链接地址的符号(.dynsym)

图片 10图片 7

以上图的.rel.dyn段为例来分析,找到__rel_dyn_start符号处:

#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
#if 0
    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr    r0, =CLKDIVN
    mov    r1, #3
    str    r1, [r0]
  #else
        /* 2. 设置时钟 400MHz */
        ldr r0, =0x4c000014
        //  mov r1, #0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
        mov r1, #0x05;            // FCLK:HCLK:PCLK=1:4:8
        str r1, [r0]
        /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
        mrc p15, 0, r1, c1, c0, 0       /* 读出控制寄存器 */
        orr r1, r1, #0xc0000000         /* 设置为“asynchronous bus mode” */
        mcr p15, 0, r1, c1, c0, 0       /* 写入控制寄存器 */

        #define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
        /* MPLLCON = S3C2440_MPLL_200MHZ */
        ldr r0, =0x4c000004
        ldr r1, =S3C2440_MPLL_400MHZ
        str r1, [r0]

        /* 启动ICACHE */
        mrc p15, 0, r0, c1, c0, 0   @ read control reg
        orr r0, r0, #(1<<12)
        mcr p15, 0, r0, c1, c0, 0   @ write it back
  #endif
关闭看门狗、关中断

#ifdef CONFIG_S3C24X0
    /* turn off the watchdog */

# if defined(CONFIG_S3C2400)
#  define pWTCON    0x15300000
#  define INTMSK    0x14400008    /* Interrupt-Controller base addresses */
#  define CLKDIVN    0x14800014    /* clock divisor register */
#else
#  define pWTCON    0x53000000
#  define INTMSK    0x4A000008    /* Interrupt-Controller base addresses */
#  define INTSUBMSK    0x4A00001C
#  define CLKDIVN    0x4C000014    /* clock divisor register */
# endif

    ldr    r0, =pWTCON
    mov    r1, #0x0
    str    r1, [r0]

    /*
     * mask all IRQs by setting all bits in the INTMR - default
     */
    mov    r1, #0xffffffff
    ldr    r0, =INTMSK
    str    r1, [r0]
# if defined(CONFIG_S3C2410)
    ldr    r1, =0x3ff
    ldr    r0, =INTSUBMSK
    str    r1, [r0]
# endif
#endif

 图片 12

View Code

如上图所示,其中0x17表示的是符号的结束标志位,我们以0x20为例来讲解:

b、内存控制器的设置值改为如下

在之前,我们讲过0x20里面保存的是异常向量0x04跳转的地址(0x1e0),如下图所示:

在/board/samsung/smdk2410/lowlevel_init.S文件中做一下修改

 图片 13

图片 14图片 7

所以,接下来的代码,便会根据0x20里的值0x1e0(flash地址),将SDRAM的33F41000+0x20的内容改为33F41000+0x1e0(SDRAM地址),来改变uboot的链接地址

SMRDATA:
#if 0
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0x32
    .word 0x30
    .word 0x30
#else

  .long 0x22011110     //BWSCON
  .long 0x00000700     //BANKCON0
  .long 0x00000700     //BANKCON1
  .long 0x00000700     //BANKCON2
  .long 0x00000700     //BANKCON3
  .long 0x00000700     //BANKCON4
  .long 0x00000700     //BANKCON5
  .long 0x00018005     //BANKCON6
  .long 0x00018005     //BANKCON7
  .long 0x008C04F4     //REFRESH
  .long 0x000000B1     //BANKSIZE
  .long 0x00000030     //MRSRB6
  .long 0x00000030     //MRSRB7

 #endif

2)重定位的剩余代码,如下所示:

View Code

#ifndef CONFIG_SPL_BUILD
       /*
        * fix .rel.dyn relocations
        */
       ldr   r0, _TEXT_BASE             /* r0 <- Text base */  //r0=text段基地址=0
       sub  r9, r6, r0         /* r9 <- relocation offset */   //r9= 重定位后的偏移值=33F41000
       ldr   r10, _dynsym_start_ofs  /* r10 <- sym table ofs */ 
                                          //_dynsym_start_ofs =__dynsym_start - _start=0x73608
                                          //所以r10=动态符号表的起始偏移值=0x73608

       add r10, r10, r0            /* r10 <- sym table in FLASH */
                                       //r10=flash上的动态符号表基地址=0x73608

       ldr   r2, _rel_dyn_start_ofs     /* r2 <- rel dyn start ofs */
                                          //r2=__rel_dyn_start - _start=0x6b568
                                          //所以r2=相对动态信息的起始偏移值=0x6b568

       add r2, r2, r0         /* r2 <- rel dyn start in FLASH */
                                      //r2=flash上的相对动态信息基地址=0x6b568

       ldr   r3, _rel_dyn_end_ofs      /* r3 <- rel dyn end ofs */
                                          // _rel_dyn_end_ofs=__rel_dyn_end - _start=00073608
                                          //所以r3=相对动态信息的结束偏移值=00073608

       add r3, r3, r0         /* r3 <- rel dyn end in FLASH */
                                    //r3=flash上的相对动态信息结束地址=0x6b568

fixloop:
       ldr   r0, [r2]           /* r0 <- location to fix up, IN FLASH! */
                               //以0x20为例,r0=0x6b568地址处的内容= 0x20

       add r0, r0, r9         /* r0 <- location to fix up in RAM */
                                     //r0=33F41000+0x20=33F41020

       ldr   r1, [r2, #4]             //r1= 33F41024地址处的内容=0x17
       and  r7, r1, #0xff       
       cmp r7, #23                  /* relative fixup? */  //0x17=23,所以相等
       beq fixrel                                       //跳到:fixerl

       cmp r7, #2                    /* absolute fixup? */
       beq fixabs
       /* ignore unknown type of fixup */
       b     fixnext
fixabs:
       /* absolute fix: set location to (offset) symbol value */
       mov r1, r1, LSR #4         /* r1 <- symbol index in .dynsym */
       add r1, r10, r1              /* r1 <- address of symbol in table */
       ldr   r1, [r1, #4]             /* r1 <- symbol value */
       add r1, r1, r9         /* r1 <- relocated sym addr */
       b     fixnext

fixrel:
       /* relative fix: increase location by offset */
       ldr   r1, [r0]                  //r1=33F41020地址处的内容=0x1e0
       add r1, r1, r9                //r1=0x1e0+33F41000= 33F411e0

fixnext:
       str   r1, [r0]             //改变链接地址里的内容, 33F41020=33F411e0  (之前为0x1e0)   
       add r2, r2, #8             //r2等于下一个相对动态信息(0x24)的地址
       cmp r2, r3                //若没到尾部__rel_dyn_end,便继续执行: fixloop
       blo  fixloop                 
#endif

c、设置串口波特率(get_HCLK函数),乱码,查看串口波特率的设置,发现在get_HCLK里没有定义CONFIG_S3C2440宏

 9.清除bss段

处理措施:在include/configs/smdk2440.h中

/*重定位完成后,清除bss段*/
clear_bss:
 #ifndef CONFIG_SPL_BUILD
       ldr   r0, _bss_start_ofs                        //获取flash上的bss段起始位置
       ldr   r1, _bss_end_ofs                          //获取flash上的bss段结束位置
       mov r4, r6                    /* reloc addr */     //获取r6(SDRAM上的uboot基地址)
       add r0, r0, r4                                  //加上重定位偏移值,得到SDRAM上的bss段起始位置
       add r1, r1, r4                                     //得到SDRAM上的bss段结束位置
       mov r2, #0x00000000           /* clear*/

clbss_l:
    str    r2, [r0]           /* clear loop...       */                 //开始清除SDRAM上的bss段
       add r0, r0, #4
       cmp r0, r1
       bne  clbss_l
       bl coloured_LED_init
       bl red_led_on
#endif
//#define CONFIG_S3C2410        /* specifically a SAMSUNG S3C2410 SoC */
//#define CONFIG_SMDK2410        /* on a SAMSUNG SMDK2410 Board */
#define CONFIG_S3C2440        /* specifically a SAMSUNG S3C2440 SoC */
#define CONFIG_SMDK2440        /* on a SAMSUNG SMDK2440 Board */

9.1继续往下分析

d、修改UBOOT支持NAND启动,原来的代码在链接时加了”-pie”选项,
使得u-boot.bin里多了”*(.rel*)”, “*(.dynsym)”

#ifdef CONFIG_NAND_SPL                   //未定义,所以不执行
  ... ...                          
#else                                   //执行else

       ldr   r0, _board_init_r_ofs         //r0=flash上的board_init_r()函数地址偏移值
       adr  r1, _start                    //0
       add lr, r0, r1                     //返回地址lr=flash上的board_init_r()函数
       add lr, lr, r9                     //加上重定位偏移值(r9)后,lr=SDRAM上的board_init_r()函数

       /* setup parameters for board_init_r */
       mov r0, r5             /* gd_t */              //r0=id值
       mov r1, r6             /* dest_addr */         //r1=uboot重定位地址
       /* jump to it ... */
       mov pc, lr              //跳转:  board_init_r()函数

_board_init_r_ofs:
       .word board_init_r - _start        //获取在flash上的board_init_r()函数地址偏移值

#endif

    使得程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K)

从上面代码看出,
接下来便会进入uboot的board_init_r()函数,该函数会对各个外设初始化、环境变量初始化等.

arch/arm/config.mk:75:LDFLAGS_u-boot += -pie 去掉这行

 

把init.c放入board/samsung/smdk2440目录,修改Makefile,使init.c编译进去

uboot的启动过程到此便结束了.

修改smdk2440.h ,修改CONFIG_SYS_TEXT_BASE为0x33f80000

下一章便来修改uboot,添加2440板卡,实现nor启动,nand启动

#define CONFIG_SYS_TEXT_BASE    0x33f00000

 

 

 

init.c

图片 16图片 7

/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))

/* GPIO */
#define GPHCON              (*(volatile unsigned long *)0x56000070)
#define GPHUP               (*(volatile unsigned long *)0x56000078)

/* UART registers*/
#define ULCON0              (*(volatile unsigned long *)0x50000000)
#define UCON0               (*(volatile unsigned long *)0x50000004)
#define UFCON0              (*(volatile unsigned long *)0x50000008)
#define UMCON0              (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
#define UTXH0               (*(volatile unsigned char *)0x50000020)
#define URXH0               (*(volatile unsigned char *)0x50000024)
#define UBRDIV0             (*(volatile unsigned long *)0x50000028)

#define TXD0READY   (1<<2)


void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);


int isBootFromNorFlash(void)
{
    volatile int *p = (volatile int *)0;
    int val;

    val = *p;
    *p = 0x12345678;
    if (*p == 0x12345678)
    {
        /* 写成功, 是nand启动 */
        *p = val;
        return 0;
    }
    else
    {
        /* NOR不能像内存一样写 */
        return 1;
    }
}

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{    
    int i = 0;

    /* 如果是NOR启动 */
    if (isBootFromNorFlash())
    {
        while (i < len)
        {
            dest[i] = src[i];
            i++;
        }
    }
    else
    {
        //nand_init();
        nand_read((unsigned int)src, dest, len);
    }
}

void clear_bss(void)
{
    extern int __bss_start, __bss_end;
    int *p = &__bss_start;

    for (; p < &__bss_end; p++)
        *p = 0;
}

void nand_init(void)
{
#define TACLS   0
#define TWRPH0  1
#define TWRPH1  0
    /* 设置时序 */
    NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
    /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
    NFCONT = (1<<4)|(1<<1)|(1<<0);    
}

void nand_select(void)
{
    NFCONT &= ~(1<<1);    
}

void nand_deselect(void)
{
    NFCONT |= (1<<1);    
}

void nand_cmd(unsigned char cmd)
{
    volatile int i;
    NFCMMD = cmd;
    for (i = 0; i < 10; i++);
}

void nand_addr(unsigned int addr)
{
    unsigned int col  = addr % 2048;
    unsigned int page = addr / 2048;
    volatile int i;

    NFADDR = col & 0xff;
    for (i = 0; i < 10; i++);
    NFADDR = (col >> 8) & 0xff;
    for (i = 0; i < 10; i++);

    NFADDR  = page & 0xff;
    for (i = 0; i < 10; i++);
    NFADDR  = (page >> 8) & 0xff;
    for (i = 0; i < 10; i++);
    NFADDR  = (page >> 16) & 0xff;
    for (i = 0; i < 10; i++);    
}

void nand_wait_ready(void)
{
    while (!(NFSTAT & 1));
}

unsigned char nand_data(void)
{
    return NFDATA;
}

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
    int col = addr % 2048;
    int i = 0;

    /* 1. 选中 */
    nand_select();

    while (i < len)
    {
        /* 2. 发出读命令00h */
        nand_cmd(0x00);

        /* 3. 发出地址(分5步发出) */
        nand_addr(addr);

        /* 4. 发出读命令30h */
        nand_cmd(0x30);

        /* 5. 判断状态 */
        nand_wait_ready();

        /* 6. 读数据 */
        for (; (col < 2048) && (i < len); col++)
        {
            buf[i] = nand_data();
            i++;
            addr++;
        }

        col = 0;
    }

    /* 7. 取消选中 */        
    nand_deselect();
}

#define PCLK            50000000    // init.c中的clock_init函数设置PCLK为50MHz
#define UART_CLK        PCLK        //  UART0的时钟源设为PCLK
#define UART_BAUD_RATE  115200      // 波特率
#define UART_BRD        ((UART_CLK  / (UART_BAUD_RATE * 16)) - 1)

/*
 * 初始化UART0
 * 115200,8N1,无流控
 */
void uart0_init(void)
{
    GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
    GPHUP   = 0x0c;     // GPH2,GPH3内部上拉

    ULCON0  = 0x03;     // 8N1(8个数据位,无较验,1个停止位)
    UCON0   = 0x05;     // 查询方式,UART时钟源为PCLK
    UFCON0  = 0x00;     // 不使用FIFO
    UMCON0  = 0x00;     // 不使用流控
    UBRDIV0 = UART_BRD; // 波特率为115200
}

/*
 * 发送一个字符
 */
void putc(unsigned char c)
{
    /* 等待,直到发送缓冲区中的数据已经全部发送出去 */
    while (!(UTRSTAT0 & TXD0READY));

    /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
    UTXH0 = c;
}

void puts(char *str)
{
    int i = 0;
    while (str[i])
    {
        putc(str[i]);
        i++;
    }
}

void puthex(unsigned int val)
{
    /* 0x1234abcd */
    int i;
    int j;

    puts("0x");

    for (i = 0; i < 8; i++)
    {
        j = (val >> ((7-i)*4)) & 0xf;
        if ((j >= 0) && (j <= 9))
            putc('0' + j);
        else
            putc('A' + j - 0xa);

    }

}

View Code

 

 修改start.S

    修改board_init_f, 把relocate_code去掉

    修改链接脚本: 把start.S, init.c, lowlevel.S等文件放在最前面,

    在./arch/arm/cpu/u-boot.lds文件中

修改为

board/samsung/smdk2440/libsmdk2440.o

e、代码重定位

    修改board.c文件中的board_init_f函数如下

    /*
     * reserve memory for U-Boot code, data & bss
     * round down to next 4 kB limit
     */
    //addr -= gd->mon_len;
    //addr &= ~(4096 - 1);
    addr = CONFIG_SYS_TEXT_BASE;

    base_sp = addr_sp;
    //relocate_code(addr_sp, id, addr);
    return ( unsigned int )id;
    /* NOTREACHED - relocate_code() does not return */

f、支持NOR-FLASH:
在drivers\mtd\jedec_flash.c 加上新的型号, jedec_table[]
中增加一项匹配板子上的NOR-Flash厂商ID和设备ID

图片 18图片 7

static const struct amd_flash_info jedec_table[] = {
#ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8
    {
        .mfr_id        = (u16)SST_MANUFACT,
        .dev_id        = SST39LF020,
        .name        = "SST 39LF020",
        .uaddr        = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_256KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x01000,64),
        }
    },
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV040B,
        .name        = "AMD AM29LV040B",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000,8),
        }
    },
    {
        .mfr_id        = (u16)SST_MANUFACT,
        .dev_id        = SST39LF040,
        .name        = "SST 39LF040",
        .uaddr        = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x01000,128),
        }
    },
    {
        .mfr_id        = (u16)STM_MANUFACT,
        .dev_id        = STM_ID_M29W040B,
        .name        = "ST Micro M29W040B",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000,8),
        }
    },
    {
        .mfr_id        = (u16)MX_MANUFACT,
        .dev_id        = MX29LV040,
        .name        = "MXIC MX29LV040",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id        = (u16)WINB_MANUFACT,
        .dev_id        = W39L040A,
        .name        = "WINBOND W39L040A",
        .uaddr        = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id        = (u16)AMIC_MANUFACT,
        .dev_id        = A29L040,
        .name        = "AMIC A29L040",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id        = (u16)EON_MANUFACT,
        .dev_id        = EN29LV040A,
        .name        = "EON EN29LV040A",
        .uaddr        = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29F400BB,
        .name        = "AMD AM29F400BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 7),
        }
    },
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV400BB,
        .name        = "AMD AM29LV400BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000,1),
            ERASEINFO(0x02000,2),
            ERASEINFO(0x08000,1),
            ERASEINFO(0x10000,7),
        }
    },
    {
        .mfr_id        = (u16)AMD_MANUFACT,
        .dev_id        = AM29LV800BB,
        .name        = "AMD AM29LV800BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_1MiB,
        .CmdSet        = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 15),
        }
    },
    {
        .mfr_id        = (u16)STM_MANUFACT,
        .dev_id        = STM29F400BB,
        .name        = "ST Micro M29F400BB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize        = SIZE_512KiB,
        .CmdSet            = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions    = 4,
        .regions        = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 7),
        }
    },
#endif

    //JZ2440
    {
        .mfr_id        = (u16)MX_MANUFACT,  
        .dev_id        = 0x2249,
        .name        = "MXIC MX29LV160DB",
        .uaddr        = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_2MiB,
        .CmdSet        = P_ID_AMD_STD,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(16*1024,1),
            ERASEINFO(8*1024,2),
            ERASEINFO(32*1024,1),
            ERASEINFO(64*1024,31),
        }
    }

};

View Code

 

在上面代码中最后增加JZ2440的Nor flash

在smdk2440.h 中修改

#define CONFIG_SYS_MAX_FLASH_SECT    (128)

验证是否支持Nor flash

flinfo : 查看flash信息,RO块通过"protect off all"指令后擦写。

    测试一下norflash能否正确读写,用以下u-boot命令:

    cp.b 0 30000000 80
    cmp.b 0 30000000 80 
    发现读norflash没有问题。再用以下几条命令测试写norflash:
    mw.b 30000000 12 3
    protect off all
    erase 0 ffff
    cp.b 30000000 0 3
    md.b 0 3
    发现也是121212;因此写norflash成功,至此u-boot已经支持JZ2440开发板的norflash。

 

g、修改UBOOT支持NAND FLASH

修复了重定时留下来的BUG:SP要重新设置,在start.S文件中做如下修改

/* Set stackpointer in internal RAM to call board_init_f */

call_board_init_f:

    ldr    r0,=0x00000000
    bl    board_init_f

/* unsigned int的值存在r0,正好给board_init_r作为参数用 */
    ldr r1,_TEXT_BASE
    ldr sp,base_sp
/* 调用第二阶段的代码 */
    bl board_init_r

.globl base_sp
base_sp:
    .long 0

启动cache后就初始化nandflash

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl    cpu_init_crit
#endif
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

bl nand_init_ll

修改:include/configs/smdk2440.h: #define
CONFIG_CMD_NAND,把drivers\mtd\nand\s3c2410_nand.c复制为s3c2440_nand.c

修改此文件里代码如下:将以s3c2410开头函数名或变量名修改为以s3c2440开头

static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
    struct nand_chip *chip = mtd->priv;
    struct s3c2440_nand *nand = s3c2440_get_base_nand();
    if( ctrl&NAND_CLE)
    {
        /* 发命令 */
        writeb(cmd,&nand->nfcmd);
    }
    else if( ctrl&NAND_ALE)
    {
        /* 发地址 */
        writeb(cmd,&nand->nfaddr);
    }

}

图片 20图片 7

int board_nand_init(struct nand_chip *nand)
{
    u_int32_t cfg;
    u_int8_t tacls, twrph0, twrph1;
    struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
    struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();

    debug("board_nand_init()\n");

    writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);

    /* initialize hardware */
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
    tacls  = CONFIG_S3C24XX_TACLS;
    twrph0 = CONFIG_S3C24XX_TWRPH0;
    twrph1 =  CONFIG_S3C24XX_TWRPH1;
#else
    tacls = 4;
    twrph0 = 8;
    twrph1 = 8;
#endif
#if 0
    cfg = S3C2410_NFCONF_EN;
    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
#endif
    /* 设置时序 */
    cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);    
    writel(cfg, &nand_reg->nfconf);
    /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
    writel((1<<4)|(1<<1)|(1<<0), &nand_reg->nfcont);

    /* initialize nand_chip data structure */
    nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
    nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

    nand->select_chip = s3c2440_nand_select;

    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
    nand->read_buf = nand_read_buf;
#endif

    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c2440_hwcontrol;

    nand->dev_ready = s3c2440_dev_ready;

#ifdef CONFIG_S3C2410_NAND_HWECC
    nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
    nand->ecc.calculate = s3c2410_nand_calculate_ecc;
    nand->ecc.correct = s3c2410_nand_correct_data;
    nand->ecc.mode = NAND_ECC_HW;
    nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
    nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
#else
    nand->ecc.mode = NAND_ECC_SOFT;
#endif

#ifdef CONFIG_S3C2410_NAND_BBT
    nand->options = NAND_USE_FLASH_BBT;
#else
    nand->options = 0;
#endif

    debug("end of nand_init\n");

    return 0;
}

View Code

 

h、支持DM9000网卡

启动uboot,打印出Net:
CS8900-0,而我们的网卡是DM9000,于是在代码中搜索“Net:”,定位到common/board_r.c的initr_net函数,一路追踪eth_initialize,
eth_common_init,一直到
board\samsung\smdk2440\smdk2440.c的board_eth_init函数,这里是对CS8900进行了初始化,我们要对DM9000进行初始化,通过查看drivers/net/Makefile,发现要包含dm9000x.c的文件,要定义CONFIG_DRIVER_DM9000这个宏,我们也要注释掉CONFIG_CS8900宏。同时查看dm9000x.c,里面有一个dm9000_initialize函数,于是仿照cs8900来写dm9000的初始化函数。

#ifdef CONFIG_CMD_NET
int board_eth_init(bd_t *bis)
{
    int rc = 0;
#ifdef CONFIG_CS8900
    rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
#endif
#ifdef CONFIG_DRIVER_DM9000
    rc = dm9000_initialize(&bis);
#endif
    return rc;
}
#endif

配置文件smdk2440.h修改如下:

/*
 * Hardware drivers
 */

#if 0
#define CONFIG_CS8900        /* we have a CS8900 on-board */
#define CONFIG_CS8900_BASE    0x19000300
#define CONFIG_CS8900_BUS16    /* the Linux driver does accesses as shorts */
#else
#define CONFIG_DRIVER_DM9000
#define CONFIG_DM9000_BASE 0x20000000
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA CONFIG_DM9000_BASE + 4

#endif

设置CONFIG_ETHADDR宏,根据自己情况配置

#define CONFIG_ETHADDR 00:0c:29:8d:73:b1

保存,编译,烧写,启动Uboot,网卡正常启动。

四、nand flash 分区

在smdk2440.h文件中,修改以下代码

#if 0
#define CONFIG_ENV_ADDR            (CONFIG_SYS_FLASH_BASE + 0x070000)
#define CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_SIZE            0x10000
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#endif
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00040000
#define CONFIG_ENV_SIZE 0x20000
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE

#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define MTDIDS_DEFAULT        "nand0=jz2440-0" /* 哪一个设备 */

#define MTDPARTS_DEFAULT    "mtdparts=jz2440-0:256k(bootloader),"    \
                        "128k(params),"        \
                        "4m(kernel),"    \
                        "-(rootfs)"        \

至此u-boot的移植基本完成。

相关文章