Chinaunix首页 | 论坛 | 博客
  • 博客访问: 140241
  • 博文数量: 24
  • 博客积分: 672
  • 博客等级: 上士
  • 技术积分: 330
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-29 09:28
文章分类

全部博文(24)

文章存档

2011年(24)

我的朋友

分类: LINUX

2011-07-06 21:14:28

转自:http://chenyunguo0317.blog.163.com/blog/static/4204559220080952947629/

经过几周的折腾,终于搞定了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就从\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\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(我在\include\configs\xxxx.h中定义它)。

Start.S完成了自己底层方面初始化的历史使命后,将自己的接力棒就交给了start_armboot。我们可以在\lib_arm\board.c文件中找到它的踪迹。这个函数实现了什么东西呢?相信下面这个网址比我说得清楚。当然有些地方还是要读读源代码,说到读源代码,有些功能强大的编辑器还是值得提一下,source insightsourcenav,当然还有uedit,这些都是很好的编辑器。

http://blog.chinaunix.net/u/5192/showart_245427.html

http://www.cublog.cn/u/5192/showart_247608.html

对于执行流程呢,u-bootstart_armboot中就会死执行main_loop ()函数,这个函数就会捕捉从控制台传来的数据,然后u-boot根据这些数据采取相应的动作,如执行u-boot命令等。

2. u-boot命令简解

u-boot提供了丰富的命令,这些命令总共有60个左右。但这些命令有些可选择的,也就是用户可以选择自己相关的命令,这些命令在网上可以找到它们的详细解释和用法, 。当然u-boot也提供了良好的命令扩展,用户可以添加自己需要的命令。如果用户想自己添加一些自己的私房命令,不妨看看下面文字。

u-boot中,每个命令都用一个命令结构体来描述,这个结构体定义在\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为该命令名字符串(比如gobootm等)。 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_tcmd_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

大体结构如下

#IfCONFIG_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). \common\Makefile文件中的COBJS后加上mycmd.o

5). 重新编译u-bootOK

3. u-boot的移植步骤

总的来说u-boot的移植步骤比较简单主要以下几个步骤:

1). \board\下建立一个自己的文件夹,我在此目录下建立了foolish这个文件夹,foolish的内容是从smdk2410copy过来的,因为我的板子和smdk2410差不多。在foolish中主要有两个文件很重要,它们是flash.cfoolish.cfoolish.c是和我选择的名字有关,在smdk2410中叫smdk2410.c),flash.c是关于开发板中flash的最底层的驱动程序,它主要实现了对flash的基本操作,如读、写、擦除等操作,这也是需要修改的文件。foolish.c实际上和smdk2410.c一样,因为我的板子和smdk2410差不多。

2). \board\foolish中的Makefile文件的COBJSSOBJS修改成下面的值。

COBJS    := foolish.o flash.o
SOBJS    := lowlevel_init.o

3). 修改存放在\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

#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 */

对于该文件中的选项就不一一描述了,这些选项在\readme文件中有详细的说明。

4). \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。最后我改写\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的参数没有配置正确。通过修改\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,下载地址为。装上此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使用的端口)放行吧,要不然白白的郁闷就不好玩了。

阅读(1999) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~