jinsy

在at91rm9200上移植u-boot

0
阅读(19411)

1 前言:

   最近写驱动写应用感觉有点乏味了,像玩点新鲜的,于是我拿手里的那块H9200E开发板玩玩移植UBOOT,参考开发板提供的uboot的源码我移植了一个ubot-1.1.1。

   目的是通过移植了解掌握atmel 的at91rm9200的启动流程个uboot的启动流程和移植要点及其方法。我把在移植uboot过程中遇到的问题记录下来,希望能帮助自己在以后的移植过程中更快的找到方向,也希望能帮助初学的朋友少走些弯路。

  开发板的硬件配置

  SDRAM               32M

  NORFLASH             4M       (atmel的AT49BV322A)

  NANDFLASH           64M       (SAMSUNG的K9F1208U0B)

2 移植思路

   我认为要想真正的理解和成功的移植uboot得先弄明白at91rm9200的启动流程和ubot的启动方法

   at91rm9200有片内引导和片外引导2 种启动方式,由一根跳线控制。上电MCU检测BMS的电平,如果是高则选择片内ROM启动, 如果是低则从外部flash启动。

   (1)   片外引导  执行烧在flash上的引导程序。

   (2)   片内引导  at91rm9200内部本身有128k的片内rom,其固化了一个bootloader和uploader,片内引导时启动uploader,uploader开启xmodem协议,等待用户上传程序,上传的程序将载入片内SRAM,重映射,然后pc跳转到片内SRAM执行上传的用户程序。注:片内SRAM只有16k,除去3-4k片内启动程序的占用的部分数据空间,因此下载的程序大小限制在12k内。

   官方at91rm9200DK u-boot Flash Programming Solutions文档提供的解决方案如下。

开发板flash上没有引导程序,于是只能用片内引导方式,载入一个12k以内的小程序到内部SRAM运行,而这个小程序初始化SDRAM后,再把u-boot下载到SDRAM运行(u-boot大于12k),pc跳到SDRAM的u-boot位置运行u-boot,u-boot启动后再用u-boot自己的flash烧写命令把自己烧到flash去,以后就可以片外flash启动了。官方文档中并不是直接烧u-boot.bin,而是烧入了boot.bin和u-boot.gz2个文件。

   Loader.bin 和boot.bin我暂时用的是板子提供的修改好的,这里重点先研究研究uboot的启动和移植。不过我还是了解了一下它们的启动流程,以便更好的去移植uboot。

   loader.bin, boot.bin, u-boot.bin代码执行流分析.

   以上三个文件时at91rm9200启动所需要的三个bin,他们的实现代码并不难。如果是你是采用at91rm9200的评估版,应该能得到其源码。

   loader.bin 执行流程,这个文件主要在片内启动从串口下载代码时会用到

   loader/entry.S       初始化CPU

   b main --->crt0.S

   --> copydata --> clearbss --> b boot

   main.c --> boot -->

   /*Get internel rom service address*/

   /* Init of ROM services structure */

   pAT91 = AT91C_ROM_BOOT_ADDRESS;

   /* Xmodem Initialization */

   --> pAT91->OpenSBuffer

   --> pAT91->OpenSvcXmodem

   /* System Timer initialization */

   ---> AT91F_AIC_ConfigureIt

   /* Enable ST interrupt */

   AT91F_AIC_EnableIt

   AT91F_DBGU_Printk("XMODEM: Download U-BOOT ");

   Jump.S

   // Jump to Uboot BaseAddr exec

   Jump((unsigned int)AT91C_UBOOT_BASE_ADDRESS)

   boot.bin执行流程 该文件会在从片内启动时被下载到板子上,以后还会被烧写到片外Flash中,以便在片外启动时用它来引导并解压u-boot.bin.gz,并跳转到u-boot来执行。

   boot/entry.S

   b main --> crt0.S--> copydata --> clearbss --> b boot

   boot/misc.s/* unzip uboot.bin.gz */

   ----> decompress_image(SRC,DST,LEN) --> gunzip

   //jump to ubootBaseAddr exec 这里跳转到解压u-boot.bin.gz的地址处直接开始执行u-boot

   asm("mov pc,%0" : : "r" (DST));

u-boot.bin执行流程

   u-boot/cpu/at91rm9200/start.S

   start --->reset

   ---> copyex ---> cpu_init_crit

   ---> /* set up the stack */ --> start_armboot

   u-boot/lib_arm/board.c

   init_fnc_t *init_sequence[] = {

   cpu_init, /* basic cpu dependent setup */

   board_init, /* basic board dependent setup */

   interrupt_init, /* set up exceptions */

   env_init, /* initialize environment */

   init_baudrate, /* initialze baudrate settings */

   serial_init, /* serial communications setup */

   console_init_f, /* stage 1 init of console */

   display_banner, /* say that we are here */

   dram_init, /* configure available RAM banks */

   display_dram_config,

   checkboard,

   NULL,

   };

   ---> start_armboot ---> call init_sequence

   ---> flash_init --> display_flash_config

   ---> nand_init ---> AT91F_DataflashInit

   ---> dataflash_print_info --> env_relocate

   ---> drv_vfd_init --> devices_init --> jumptable_init

   ---> console_init_r --> misc_init_r --> enable_interrupts

   ---> cs8900_get_enetaddr --> board_post_init -->

u-boot/common/main.c

   for (;;)

   { /* shell parser */

   main_loop () --> u_boot_hush_start --> readline

   --> abortboot

   -->printf("Hit any key to stop autoboot: %2d ", bootdelay);

   }

   以上是at91rm9200启动并进入u-boot的执行流分析。后面u-boot还会将uImage解压到特定的位置并开始启动内核代码。

3 修改loader boot

    3.1  修改Loader.bin的源码

         1. 修改include/main.h

              #define AT91C_UBOOT_BASE_ADDRESS 0x21f00000

       此开发板SDRAM为32M地址空间为0x20000000—0x22000000   uboot被解压缩后要被拷贝到RAM的高端地址,防治                      与其他地址冲突

        2. 修改init.c中对SDRAM的初始化

           AT91C_BASE_SDRC->SDRC_MR=0x02

           根据具体的SDRAM芯片修改: MR[4]=1(表示16位)

                                     MR[4]=0  (表示32位)  

    3.2   修改Boot.bin的源码

         1. 在main.c中添加两个外部函数的定义

              Extern int deampress_image(void *src,void *dst,unsigned int len); 解压缩函数,用来解压缩UBOOT

              Extern void Jump()    跳转函数

         2. 在main.c中修改宏定义

             #define SRC  0x10010000    uboot在flash中的基地址

             #define DST  0x21f00000    解压缩UBOOT后载入到SDRAM中的地址

             #define LEN  0x20000       uboot的大小(最大大小)             

 

      3 修改main.c中打印语句

           AT91F_DBGU_Pringk()  ………

           AT91F_DBGU_Pringk()  ………

           AT91F_DBGU_Pringk()  ………

              ……

              …

       修改成自己希望的开机文字图样   

4 动手移植uboot

   4.1  从网上下载官方的ubot-1.1.1

         http://sourceforge.net/project/showfiles.php?group_id=65938&package_id=63695&release_id=233851

   4.2   在/board 下建立myboard文件夹,从/board/at91rm9200dk/..下拷贝文件。

               At91rm9200dk.c   flash.c  config.mk  makefile  u-boot.lds

   4.2.1  将at91rm9200dk.c改名为myboard.c,修改其部分代码。由于这个开发板支持nandflash所以需要修改myboard.c下          关于nandflash初始化的部分,nand_init().

      具体修改如下:

      将     *AT91C_PIOC_ASR = AT91C_PC0_BFCK | AT91C_PC1_BFRDY_SMOE |

                         AT91C_PC3_BFBAA_SMWE;

      改为    *AT91C_PIOC_ASR = AT91C_PC1_BFRDY_SMOE |

                         AT91C_PC3_BFBAA_SMWE; //AT91C_PC0_BFCK

 

      将      *AT91C_PIOC_PDR = AT91C_PC0_BFCK | AT91C_PC1_BFRDY_SMOE |

                             AT91C_PC3_BFBAA_SMWE;

      改为   *AT91C_PIOC_PDR = AT91C_PC1_BFRDY_SMOE |

                            AT91C_PC3_BFBAA_SMWE;

      增加两句

      *AT91C_PIOC_PER|= AT91C_PC0_BFCK;

      *AT91C_PIOC_OER = AT91C_PC0_BFCK;

      注:AT91C_PC0_BFCK 是Brust Flash控制器的时钟信号线 。

      AT91C_PC1_BFRDY_SMOE 是Brust Flash 控制器的读信号。

      AT91C_PC3_BFBAA_SMWE  是Brust Flash 控制器的脉冲前沿地址。

      AT91C_PIOC_ASR是外设A寄存器。

      AT91C_PIOC_PDR  是GPIO 禁用寄存器。

      AT91C_PIOC_PER是GPIO 使能寄存器。

      AT91C_PIOC_OER是GPIO 使能输出寄存器。

      上述修改的目的是,使能BFCK信号线的GPIO输出。

      在/*Configure PC2 as input (signal READY of the SmartMedia)*/后增加

      *AT91C_PMC_PCER|=(unsigned int)(1<<4);此句。目的:开启外设时钟。

      4.2.2  修改flash.c

      根据不同的flash芯片采用不同的flash程序接口,本开发板选用的是atmel的AT49BV322A。由于芯片不同所以需要根据datasheet对flash.c进行修改。

     ① 修改扇区大小和数目的定义

         OrgDef OrgAT49BV16x4A[] =

            {

              { 8, 8*1024 }, /* 8 * 8kBytes sectors */

              { 31, 64*1024 } /* 31 * 64kBytes sectors */

            };

         改为

         OrgDef OrgAT49BV16x4A[]=

            {

              { 8,  8*1024 }, /* 8 * 64kBytes sectors */

              { 63,  64*1024 } /* 63 *8kBytes sectors */

      };

      本芯片为71个扇区。

       ② 根据datasheet修改关于地址和读写命令的宏定义。

          #define FLASH_BANK_SIZE 0x200000    /* 2 MB */

          改为 #define FLASH_BANK_SIZE 0x400000  /* 4 MB */

         /* AT49BV1614A Codes */

         #define FLASH_CODE1       0xAA

         #define FLASH_CODE2       0x55

         #define ID_IN_CODE        0x90

         #define ID_OUT_CODE       0xF0

         #define CMD_READ_ARRAY    0x00F0

         #define CMD_UNLOCK1       0x00AA

         #define CMD_UNLOCK2       0x0055

         #define CMD_ERASE_SETUP       0x0080

         #define CMD_ERASE_CONFIRM   0x0030

         #define CMD_PROGRAM          0x00A0

         #define CMD_UNLOCK_BYPASS    0x0020

         #define MEM_FLASH_ADDR1       (*(volatile u16 *)(CFG_FLASH_BASE + (0x00005555<<1)))

         #define MEM_FLASH_ADDR2       (*(volatile u16 *)(CFG_FLASH_BASE + (0x00002AAA<<1)))

         #define IDENT_FLASH_ADDR1(*(volatile u16 *)(CFG_FLASH_BASE + (0x0000555<<1)))

         #define IDENT_FLASH_ADDR2(*(volatile u16 *)(CFG_FLASH_BASE + (0x0000AAA<<1)))

      修改为:

         /* MBM29LV320BE Codes */

         #define FLASH_CODE1       0x00AA00aa

         #define FLASH_CODE2       0x00550055

         #define ID_IN_CODE     0x00900090

         #define ID_OUT_CODE       0x00F000f0

         #define CMD_READ_ARRAY    0x00F000F0

         #define CMD_UNLOCK1       0x00AA

         #define CMD_UNLOCK2       0x0055

         #define CMD_ERASE_SETUP       0x0080

         #define CMD_ERASE_CONFIRM0x0030

         #define CMD_PROGRAM       0x00A0

         #define CMD_UNLOCK_BYPASS0x00200020

         #define MEM_FLASH_ADDR1       (*(volatile u16 *)(CFG_FLASH_BASE + (0x0000555<<1)))

         #define MEM_FLASH_ADDR2       (*(volatile u16 *)(CFG_FLASH_BASE + (0x00002AA<<1)))

         #define IDENT_FLASH_ADDR1(*(volatile u32 *)(CFG_FLASH_BASE + (0x0000555<<2)))

         #define IDENT_FLASH_ADDR2(*(volatile u32 *)(CFG_FLASH_BASE + (0x0000AAA<<2)))

      ③  去掉芯片自动识别,防治出以外错误。

          注视掉if ((flash_info[i].flash_id & FLASH_TYPEMASK)……到else  144行-152行。

      4.2.3  修改config.mk

           将  TEXT_BASE = 0x21f80000   修改为  TEXT_BASE = 0x21f00000

           这个地址是要根一级boot中定义保持一致。

           Boot中的main.c

               #define DST 0x21f00000      //UBOOT被解压缩后载入到SDRAM中的位置。

      4.2.4  修改makefile

      将   OBJS   := at91rm920dk.oflash.o

      修改为   OBJS  := myboard.o flash.o  自己命名的开发板的名字

      4.3  修改include下面的头文件

      ⑴   在/include/configs/下建立myboard.h ,可以复制at91rm9200dk.h改名。

       具体注意修改如下:

         #define CONFIG_MYBOARD1                    //目标板

         #define CONFIG_NR_DRAM_BANKS 1              //SDRAM bank数

         #define PHYS_SDRAM 0x20000000               //基地址

         #define PHYS_SDRAM_SIZE 0x2000000           //大小  32M

         #define PHYS_FLASH_1 0x10000000             //基地址

         #define PHYS_FLASH_SIZE 0x400000            //大小4M

         #define CFG_FLASH_BASE    PHYS_FLASH_1      //别名

         #define CFG_MAX_FLASH_BANKS 1           //总bank数

         #define CFG_MAX_FLASH_SECT 71           //扇区总数

      根据ubot-1.1.1的/include/configs/at91rm9200dk.h修改的比较少,大部分是修改容量和扇区总数及其基地址。

         ⑵  修改/include/cmd_confdefs.h

           修改  #define CFG_CMD_NONSTD (………

                                           …)

           这个宏定义是决定ubot支持的功能,如果需要支持就从括号中删除此行。利于源码支持  CFG_CMD_LOADB

           CFG_CMD_MEMORY 等。我们这里的修改是删除  “CFG_CMD_NAND | \ ” 这行,是uboot支持nandflash。

      4.4  修改根目录下的MAKEALL 和Makefile

      ⑴   修改MAKEALL:

       在   LIST_ARM9="  \

            at91rm9200dk  integratorcp  integratorap\

            omap1510inn   omap1610h2omap1610inn          \

            smdk2400   smdk2410   trab              \

            VCMA9      versatile     myboard           \"     中加入对目标板的定义。

      ⑵   修改Makefile

           修改当前交叉编译器的绝对路径:

           ifeq ($(ARCH),arm)

           CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux-

           添加目标板配置选项

           #########################################################################

           ## AT91RM9200 Systems

           #########################################################################

           at91rm9200dk_config  :   unconfig

              @./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk

           myboard_config    :   unconfig

               @./mkconfig $(@:_config=) arm at91rm9200 myboard

  5 编译,调试

    至此,uboot的修改基本完成,让我们编译下看看吧。

    在纯linux环境下编译(不要在VM里linux和windows的共享目录里编译)

    进入uboot的根目录,键入如下命令

    make clean           (清除过程文件)

    make myboard_config      (生成目标板的配置文件)

    make all             (开始编译)

    我等,我等,我等等等~!

    啊~!出问题了 

   

    从错误中看是提示未定义。

    好吧,那就找错误。这时候就体现出Source Insight的优势了,全工程搜索,快捷的查找任意的函数或者宏的定义位置。

    最后在/include/common.h中添加

    #include <asm/arch-at91rm9200/AT91RM9200.h>包含与硬件相关的寄存器的定义,这个跟uboot版本有关系,比如uboot-1.0.0的include/common.h里就有这句话。

    好了再编译一次吧……

    Make clean

    Make all

    VM虚拟机编译还真是不快,不过这次没出问题,成功了。

    编译结束后在根目录下会生成u-boot.bin 大概104k

    然后将其压缩为gz格式的

    gzip –c u-boot.bin > u-boot.gz

    因为一级boot中的解压缩函数是解压缩的gz格式然后拷贝到RAM的高端地址中去的。