u-boot-1.2.0 移植粗解

 经过几周的折腾,终于搞定了 u-boot-1.2.0,写这篇粗解希望能给后来的朋友一些启示和帮助。下面就从以下几个方面写粗一些 u-boot-1.2.0方面的知识:
·启动流程
·各命令简解
·移植步骤
·nor flash底层驱动的修改
·cs8900网络驱动与tftp
·Linuxtftp-server的安装与配置
开饭板资源说明:
处理器:S3C2410A
内存:SDRAM 64M
Flashnor flash sst39vf1601
网卡芯片:CS8900A,映射到nGCS3
1. u-boot启动流程
关于u-boot的启动流程网上也有很多资料描述,这里再赘述一番。S3c2410采用ARM920T核,u-boot就从<yourpath>/cpu/arm920t下的Start.S启动。Start.S主要完成了以下一些工作:安装中断,设置时钟,cpu的初始化,将自身搬运到目的地(0x3ff80000处),设置堆栈,清除bss段,最后跳转到start_armboot
Start.S中,cpu的初始化由cpu_init_crit实现,它完成以下功能:flush v4 I/D caches, 关闭MMU stuff,关闭caches和调用lowlevel_init初始化BWSCONlowlevel_init<yourpath>/board/yourboard中实现。
Start.S中实现代码如下:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
             bl     cpu_init_crit
#endif
从上面可以看到cpu_init_crit是条件编译的,这主要用于调试阶段。如果是通过其他bootloader加载u-boot并调试的话,那么,#define CONFIG_SKIP_LOWLEVEL_INIT一下是很有必要的。假设通过viviu-boot.bin加载到RAM中执行,如果没有定义CONFIG_SKIP_LOWLEVEL_INIT那么在终端上我们什么也看不到。原因是u-boot.bin本来就在RAM中了,而u-boot.bin运行到cpu_init_crit后,CPU被初始化了一番,u-boot.bin也就全部在RAM中消失了。所以在调试阶段记住#define CONFIG_SKIP_LOWLEVEL_INIT(我在<yourpath>/include/configs/xxxx.h中定义它)。
Start.S完成了自己底层方面初始化的历史使命后,将自己的接力棒就交给了start_armboot。我们可以在<yourpath>/lib_arm/board.c文件中找到它的踪迹。这个函数实现了什么东西呢?相信下面这个网址比我说得清楚。当然有些地方还是要读读源代码,说到读源代码,有些功能强大的编辑器还是值得提一下,source insightsourcenav,当然还有uedit,这些都是很好的编辑器。
对于执行流程呢,u-bootstart_armboot中就会死执行main_loop ()函数,这个函数就会捕捉从控制台传来的数据,然后u-boot根据这些数据采取相应的动作,如执行u-boot命令等。
2. u-boot命令简解
u-boot提供了丰富的命令,这些命令总共有60个左右。但这些命令有些可选择的,也就是用户可以选择自己相关的命令,这些命令在网上可以找到它们的详细解释和用法, http://www.freescale.com/files/32bit/doc/quick_ref_guide/LITE5200BUBPG/LITE5200BUBPG.pdf。当然u-boot也提供了良好的命令扩展,用户可以添加自己需要的命令。如果用户想自己添加一些自己的私房命令,不妨看看下面文字。
u-boot 中,每个命令都用一个命令结构体来描述,这个结构体定义在<yourpath>/include/command.h 中。
struct cmd_tbl_s {
       char *name;           /* Command Name               */
       int   maxargs;        /* maximum number of arguments       */
       int    repeatable;      /* autorepeat allowed?           */
                                   /* Implementation function    */
       Int   (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
       char *usage;          /* Usage message   (short)    */
#ifdef      CFG_LONGHELP
       char *help;             /* Help  message   (long)      */
#endif
#ifdef CONFIG_AUTO_COMPLETE
              /* do auto completion on the arguments */
       int    (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
其中Cmd 就是实际需要调用的命令函数!name 为该命令名字符串(比如go bootm 等)。 command.h 里面还一个叫U_BOOT_CMD 的宏。
#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))
#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}
这段代码的意思是说,对于U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) 来说,就是定义一个cmd_tbl_t cmd_tbl_t 就是struct cmd_tbl_s )类型的__u_boot_cmd_name 变量,并将此变量放到.u_boot_cmd 段,.u_boot_cmd 的定义可以在board/yourboard/u-boot.lds 找到。在U-boot 中的shell 中,根据用户输入的命令,就会在.u_boot_cmd 这个内存区域中查找,当.u_boot_cmd 中某一个cmd_tbl_s 命令结构体的cmd_tbl_s.name 和输入的命令字符串相符时,就调用该命令。
下面以添加mycmd 命令为例说明方法。
1). include/configs/xxxx.h 中的CONFIG_COMMDNDS 中增加一项CFG_ CMD_MYCMD
CFG_CMD_USBLOAD,
/***********************************************************
* Command definition
***********************************************************/
#define CONFIG_COMMANDS /
(  CONFIG_CMD_DFL | /
   CFG_CMD_CACHE | /
   CFG_CMD_NET | /
   CFG_CMD_ENV | /
   CFG_CMD_FLASH | /
   CFG_CMD_PING | /
   CFG_CMD_NAND | /
   /*CFG_CMD_EEPROM |*/ /
   /*CFG_CMD_I2C |*/ /
   /*CFG_CMD_USB |*/ /
   CFG_CMD_REGINFO  | /
   CFG_CMD_DATE | /
   CFG_CMD_ELF |/
   CFG_ CMD_MYCMD
)
2). include/cmd_confdefs.h 中加入命令标志位
#define CFG_CMD_MYCMD  0x000055AAULL ( 可以是任意值,只要不和其他命令冲突)
3). common/ 下面加入mycmd.c
大体结构如下:
#If CONFIG_COMMANDS & CFG_CMD_ELF
int my-cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[ ] ){
    ………………….
}
U_BOOT_CMD{
      mycmd,
      2,
      1,
      1,
      my-cmd,
      “……”,          /* write some words to describe usage of this command */
      “……”           /* describe help messages of my command*/
};
#endif
4). <yourpath>/common/Makefile 文件中的COBJS 后加上mycmd.o
5). 重新编译u-boot ,就OK
3. u-boot的移植步骤
总的来说u-boot的移植步骤比较简单主要以下几个步骤:
1). <yourpath>/board/下建立一个自己的文件夹,我在此目录下建立了foolish这个文件夹,foolish的内容是从smdk2410copy过来的,因为我的板子和smdk2410差不多。在foolish中主要有两个文件很重要,它们是flash.cfoolish.cfoolish.c是和我选择的名字有关,在smdk2410中叫smdk2410.c),flash.c是关于开发板中flash的最底层的驱动程序,它主要实现了对flash的基本操作,如读、写、擦除等操作,这也是需要修改的文件。foolish.c实际上和smdk2410.c一样,因为我的板子和smdk2410差不多。
2). <yourpath>/board/foolish中的Makefile文件的COBJSSOBJS修改成下面的值。
COBJS    := foolish.o flash.o
SOBJS    := lowlevel_init.o
3). 修改存放在<yourpath>/include/foolish.h文件,这个文件需要自己添加。当然它也是由同目录下的smdk2410.h修改而来。我的foolish配置如下:
#ifndef __CONFIG_H
#define __CONFIG_H
 
//#define CONFIG_SKIP_LOWLEVEL_INIT
/*
 * High Level Configuration Options
 * (easy to change)
 */
#define CONFIG_ARM920T        1     /* This is an ARM920T Core */
#define    CONFIG_S3C2410              1     /* in a SAMSUNG S3C2410 SoC     */
#define CONFIG_SMDK2410      1     /* on a SAMSUNG SMDK2410 Board  */
 
/* input clock of PLL */
#define CONFIG_SYS_CLK_FREQ  12000000/* the SMDK2410 has 12MHz input clock */
 
#define USE_920T_MMU            1
#undef CONFIG_USE_IRQ                 /* we don't need IRQ/FIQ stuff */
 
/* Size of malloc() pool */
#define CFG_MALLOC_LEN              (CFG_ENV_SIZE + 128*1024)
#define CFG_GBL_DATA_SIZE    128  /* size in bytes reserved for initial data */
 
/* Hardware drivers  */
#define CONFIG_DRIVER_CS8900     1     /* we have a CS8900 on-board */
#define CS8900_BASE          0x19000300
#define CS8900_BUS16        1 /* the Linux driver does accesses as shorts */
 
/* select serial console configuration  */
#define CONFIG_SERIAL1          1    /* we use SERIAL 1 on SMDK2410 */
 
/************************************************************
 * RTC
 ************************************************************/
#define    CONFIG_RTC_S3C24X0     1
 
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
 
#define CONFIG_BAUDRATE             115200
 
/***********************************************************
 * Command definition
 ***********************************************************/
#define CONFIG_COMMANDS /
                     (CONFIG_CMD_DFL   | /
                     CFG_CMD_CACHE      | /
                     /*CFG_CMD_NAND     |*/ /
                     /*CFG_CMD_EEPROM |*/ /
                     /*CFG_CMD_I2C  |*/ /
                     /*CFG_CMD_USB |*/ /
                     CFG_CMD_REGINFO  | /
                     CFG_CMD_DATE  | /
                    CFG_CMD_ELF      | /
                    CFG_CMD_PING)
 
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
 
#define CONFIG_BOOTDELAY   10
#define CONFIG_BOOTARGS         "root=ramfs devfs=mount console=ttySAC0,115200"
#define CONFIG_ETHADDR           08:00:3e:26:0a:5b
#define CONFIG_NETMASK       255.255.255.0
#define CONFIG_IPADDR            202.192.248.147
#define CONFIG_SERVERIP              202.192.248.46
#define CONFIG_BOOTFILE          "zImage"
#define CONFIG_BOOTCOMMAND   "tftp; bootm"
 
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
#define CONFIG_KGDB_BAUDRATE  115200           /* speed to run kgdb serial port */
/* what's this ? it's not used anywhere */
#define CONFIG_KGDB_SER_INDEX       1            /* which serial port to use */
#endif
 
/*
 * Miscellaneous configurable options
 */
#define    CFG_LONGHELP                       /* undef to save memory              */
#define    CFG_PROMPT             "foolish # "     /* Monitor Command Prompt       */
#define    CFG_CBSIZE        256         /* Console I/O Buffer Size     */
#define    CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
#define    CFG_MAXARGS          16           /* max number of command args  */
#define CFG_BARGSIZE             CFG_CBSIZE /* Boot Argument Buffer Size       */
 
#define CFG_MEMTEST_START 0x30000000    /* memtest works on     */
#define CFG_MEMTEST_END           0x33F00000   /* 63 MB in DRAM       */
 
#undef  CFG_CLKS_IN_HZ              /* everything, incl board info, in Hz */
 
#define    CFG_LOAD_ADDR             0x30200000    /* default load address   */
 
/* the PWM TImer 4 uses a counter of 15625 for 10 ms, so we need */
/* it to wrap 100 times (total 1562500) to get 1 sec. */
#define    CFG_HZ               1562500
 
/* valid baudrates */
#define CFG_BAUDRATE_TABLE       { 9600, 19200, 38400, 57600, 115200 }
 
/*-----------------------------------------------------------------------
 * Stack sizes
 *
 * The stack sizes are set up in start.S using the settings below
 */
#define CONFIG_STACKSIZE     (128*1024)     /* regular stack */
#ifdef CONFIG_USE_IRQ
#define CONFIG_STACKSIZE_IRQ    (4*1024) /* IRQ stack */
#define CONFIG_STACKSIZE_FIQ     (4*1024) /* FIQ stack */
#endif
 
/*-----------------------------------------------------------------------
 * Physical Memory Map
 */
#define CONFIG_NR_DRAM_BANKS 1        /* we have 1 bank of DRAM */
#define PHYS_SDRAM_1            0x30000000 /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE   0x04000000 /* 64 MB */
 
#define PHYS_FLASH_1              0x00000000 /* Flash Bank #1 */
 
#define CFG_FLASH_BASE         PHYS_FLASH_1
 
/*-----------------------------------------------------------------------
 * FLASH and environment organization
 */
 
#define CONFIG_AMD_LV400    1     /* uncomment this if you have a LV400 flash */
#if 0
#define CONFIG_AMD_LV800    1     /* uncomment this if you have a LV800 flash */
#endif
 
#define CFG_MAX_FLASH_BANKS    1     /* max number of memory banks */
#ifdef CONFIG_AMD_LV800
#define PHYS_FLASH_SIZE        0x00100000 /* 1MB */
#define CFG_MAX_FLASH_SECT      (19) /* max number of sectors on one chip */
#define CFG_ENV_ADDR    (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */
#endif
#ifdef CONFIG_AMD_LV400
#define PHYS_FLASH_SIZE        0x00200000 /* 2MB */
#define CFG_MAX_FLASH_SECT      (32) /* max number of sectors on one chip */
#define CFG_ENV_ADDR           (CFG_FLASH_BASE + 0x20000) /* addr of environment */
#endif
 
/* timeout values are in ticks */
#define CFG_FLASH_ERASE_TOUT   (5*CFG_HZ) /* Timeout for Flash Erase */
#define CFG_FLASH_WRITE_TOUT  (5*CFG_HZ) /* Timeout for Flash Write */
 
#define    CFG_ENV_IS_IN_FLASH    1
#define CFG_ENV_SIZE              0x10000  /* Total Size of Environment Sector */
 
#endif     /* __CONFIG_H */
对于该文件中的选项就不一一描述了,这些选项在<yourpath>/readme文件中有详细的说明。
4). <yourpath>/Makefile文件中添加下面的两行,
foolish_config:              unconfig
       @$(MKCONFIG) $(@:_config=) arm arm920t foolish NULL s3c24x0
OK!现在可以编译u-boot了!
make foolish_config
make ARCH=arm CROSS_COMIPE=arm-linux-
最后是否就生成了u-boot.bin等文件了呢?到这里算是成功1/4了。
4. nor flash底层驱动的修改
下载u-boot.bin到板子里(当然定义了CONFIG_SKIP_LOWLEVEL_INIT,要不然没反应就不好了),u-boot是不是给我们打印一个CRC错误的消息,这主要由于没有将env变量存到flash中,所以u-boot给我们警告。试试saveenv命令将env变量存到flash,居然不行。原来smdk2410nor flashAMDLV400,而我的却是sst39vf1601。仔细看看才发现它们的写时序不同,这可以参考两中芯片的datasheet。最后我改写<yourpath>/board/foolish/flash.c文件中flash_erasewrite_hword函数。
flash_erase函数中改写了从“if (info->protect[sect] == 0) {      /* not protected */”到“if (ctrlc ())”之间的代码,这些代码如下:
              ……
if (info->protect[sect] == 0) {      /* not protected */
                     vu_short *addr = (vu_short *) (info->start[sect]);
                     MEM_FLASH_ADDR1 = CMD_UNLOCK1;
                     MEM_FLASH_ADDR2 = CMD_UNLOCK2;
                     MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
 
                     MEM_FLASH_ADDR1 = CMD_UNLOCK1;
                     MEM_FLASH_ADDR2 = CMD_UNLOCK2;
                     *addr = CMD_ERASE_CONFIRM;
 
                     /* wait until flash is ready */
                     while(1){
                            unsigned short i;
                            i = *((volatile unsigned short *)addr)&0x40;
                            if(i!=*((volatile unsigned short *)addr)&0x40)
                                   continue;
                            if(*((volatile unsigned short *)addr)&0x80) 
                                   break;
                     }
                     printf ("ok./n");
              } else {   /* it was protected */
                     printf ("protected!/n");
              }
       }
       if (ctrlc ())
       ……
对于write_hword函数如下面的代码所示:
volatile static int write_hword (flash_info_t * info, ulong dest, ushort data)
{
       vu_short *addr = (vu_short *) dest;
       ushort result;
       int rc = ERR_OK;
       int cflag, iflag;
       int chip;
 
       /*
        * Check if Flash is (sufficiently) erased
        */
       result = *addr;
       if ((result & data) != data)
              return ERR_NOT_ERASED;
 
       /*
        * Disable interrupts which might cause a timeout here. Remember that our exception
* vectors are at address 0 in the flash, and we don't want a (ticker) exception to happen
* while the flash chip is in programming mode.
        */
       cflag = icache_status ();
       icache_disable ();
       iflag = disable_interrupts ();
 
       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
       MEM_FLASH_ADDR1 = CMD_PROGRAM;
       *addr = data;
 
       /* arm simple, non interrupt dependent timer */
       reset_timer_masked ();
 
       /* wait until flash is ready */
       while(1){
              unsigned short i = *(volatile unsigned short *)addr & 0x40;
              if(i != *(volatile unsigned short *)addr & 0x40)   //D6 == D6
                     continue;
              if((*(volatile unsigned short *)addr & 0x80)==(data & 0x80)){
                     rc = ERR_OK;
                     break;     //D7 == D7
              }
       }
       if (iflag)
              enable_interrupts ();
       if (cflag)
              icache_enable ();
       return rc;
}
到现在位置整个关于nor flash sst39vf1601就差不多搞定了,但还有一个比较烦人的地方是,在打开u-boot时的时候,居然打印的是AMD的信息,这可不行得让u-boot打印sst39vf1601的信息,为了达到这个小小的要求,就需要改写flash_print_info(也在flash.c中)函数了,将该函数中
case (AMD_MANUFACT & FLASH_VENDMASK):
printf ("AMD: ");
case (AMD_ID_LV400B & FLASH_TYPEMASK):
              printf ("1x Amd29LV400BB (4Mbit)/n");
分别修改为:
       case (AMD_MANUFACT & FLASH_VENDMASK):
              printf ("SST: ");
       case (AMD_ID_LV400B & FLASH_TYPEMASK):
printf ("1x 39VF1601 (2Mbit)/n");
这样整个flash部分就算完毕了,但有一点小小的毛病,就是在saveenv命令时,速度有点慢,还希望高手改改。接下来应该是网络部分了。
5. cs8900网络驱动与tftp
       之所以利用u-boot其中最重要的原因之一是它的tftp功能。对于网络部分,板子上的网络芯片是cs8900,幸运的是这和smdk2410一样。使得网络部分移植太简单了。根本就不需要什么大的修改就ok了,不过这还是花了n多时间才搞定。主要问题有两个:一是错误是CS8900 Ethernet chip not found?!错误;二是为什么地址是0x19000000
后面这个看来原理图后发现cs8900nGCS3,也就是说基地址应该从0x18000000开始,但是发现cs8900用了地址线A24作为I/O方式和MEMORY方式,smdk2410使用了I/O方式,所以处理器在送出基地址时要考虑A24,并且I/O方式A24=1,从这里可知cs8900的基地址应该是0x180000001<<240x19000000
对于CS8900 Ethernet chip not found?!错误这个问题,就困惑了很久,网上都说不用修改就可以使用,后来发现每次u-boot探测到的ID都不一样,这说明片选是正确的,可能是处理器Bank3时序问题,后来仔细查看发现Bank3的参数没有配置正确。通过修改<yourpath>/board/foolish/ lowlevel_init.S文件中的Bank3参数搞定了第一个错误,Bank3的配置如下:
#define B3_Tacs                 0x0  /*  0clk  */
#define B3_Tcos                0x3  /*  4clk  */
#define B3_Tacc                0x7  /*  14clk */
#define B3_Tcoh                0x1  /*  1clk  */
#define B3_Tah                  0x3  /*  4clk  */
#define B3_Tacp                0x3  /*  6clk  */
#define B3_PMC                0x0  /*  normal */
到此网络方面就Ok了!试试tftp,嘿嘿!OK!
5. Linuxtftp-server的安装与配置
       将系统切换到linuxfedora core 6)下,发现fc6下面还没有装tftp-server,在网上下载一个tftp-hpa-0.42,下载地址为http://www.kernel.org/pub/software/network/tftp/。装上此server后,将在/etc/xinetd.d/下产生tftp文件,我们需要配置此文件完成tftp sever正确运行。Tftp文件的配置如下:
service tftp
{
  disable = no
  socket_type = dgram
  protocol = udp
  wait = yes
  user = root
  server = /usr/sbin/in.tftpd
  server_args = -s /tftpboot
  per_source = 11
  cps = 100 2
  flags = IPv4
}
server_args项的-s参数指定了tftp server的根目录地址,这可以根据自己的需要修改。好了,tftp server已经配置完成,迫不及待的试试u-bootlinux之间的tftp怎么样?打开u-boot输入tftp,理想中应该是一群可爱的“#”符号,但现实和理想总有那么一段距离,没办法!迎接我的却是一帮不怎么可爱的“T”形字母。为什么呢?????在windows下,不是成功了吗?难道linux真的不行吗?这个问题一个困惑就是几个昼夜啊,网上也没找到什么蛛丝马迹,到底该怎么办呢?离胜利就只有一步之遥了,光明就在前方啊!真是功夫不负好心人,朋友当你出现上面的问题时,请你在fc6的防火墙与安全中把udp69号端口(tftp使用的端口)放行吧,要不然白白的郁闷就不好玩了。
好了,ladies and gentlemenu-boot节目到此结束,祝各位晚安!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值