Chinaunix首页 | 论坛 | 博客
  • 博客访问: 309544
  • 博文数量: 60
  • 博客积分: 1451
  • 博客等级: 上尉
  • 技术积分: 710
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-23 23:55
文章分类

全部博文(60)

文章存档

2017年(9)

2014年(1)

2013年(1)

2011年(9)

2010年(35)

2009年(5)

我的朋友

分类: 嵌入式

2009-10-07 11:42:23

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,
#if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)  /*smdk2410没有定义*/
 checkboard,
#endif
 NULL,
};
谭浩强的书上写着,一维指针数组的定义形式为: 类型名  * 数组名[数组长度];
可见,这里的init_sequence也是指针数组,数组名为init_sequence,数组的每一个元素都为指针类型,在这里每个元素是指向函数的指针。init_fnc_ptr即为指向init_sequence指针数组的指针,结合起这里来就可以理解了.
下面就跳到数组的第一个函数cpu_init去执行:
int cpu_init (void)
{
#ifdef CONFIG_USE_IRQ
 DECLARE_GLOBAL_DATA_PTR;
 IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
 FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
 return 0;
}
实际上这里只是什么都不干,因为在u-boot-1.1.4\include\configs\smdk2410.h里没有定义CONFIG_USE_IRQ
#undef CONFIG_USE_IRQ   /* we don't need IRQ/FIQ stuff */
接下来是board_init函数,先贴出代码稍后再分析:
int board_init (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
 /* to reduce PLL lock time, adjust the LOCKTIME register */
 clk_power->LOCKTIME = 0xFFFFFF;
 /* configure MPLL */
 clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
 /* some delay between MPLL and UPLL */
 delay (4000);
 /* configure UPLL */
 clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
 /* some delay between MPLL and UPLL */
 delay (8000);
 /* set up the I/O ports */
 gpio->GPACON = 0x007FFFFF;
 gpio->GPBCON = 0x00044555;
 gpio->GPBUP = 0x000007FF;
 gpio->GPCCON = 0xAAAAAAAA;
 gpio->GPCUP = 0x0000FFFF;
 gpio->GPDCON = 0xAAAAAAAA;
 gpio->GPDUP = 0x0000FFFF;
 gpio->GPECON = 0xAAAAAAAA;
 gpio->GPEUP = 0x0000FFFF;
 gpio->GPFCON = 0x000055AA;
 gpio->GPFUP = 0x000000FF;
 gpio->GPGCON = 0xFF95FFBA;
 gpio->GPGUP = 0x0000FFFF;
 gpio->GPHCON = 0x002AFAAA;
 gpio->GPHUP = 0x000007FF;
 /* arch number of SMDK2410-Board */
 gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
 /* adress of boot parameters */
 gd->bd->bi_boot_params = 0x30000100;
 icache_enable();
 dcache_enable();
 return 0;
}
首先这里有S3C24X0_CLOCK_POWER结构体类型,搜索到它是在u-boot-1.1.4\include\s3c24x0.h中定义的
/* CLOCK & POWER MANAGEMENT (see S3C2400 manual chapter 6) */
/*                          (see S3C2410 manual chapter 7) */
typedef struct {
 S3C24X0_REG32 LOCKTIME;
 S3C24X0_REG32 MPLLCON;
 S3C24X0_REG32 UPLLCON;
 S3C24X0_REG32 CLKCON;
 S3C24X0_REG32 CLKSLOW;
 S3C24X0_REG32 CLKDIVN;
} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
其中S3C24X0_REG32在同一个文件中有定义:
typedef volatile u32 S3C24X0_REG32;
S3C24X0_GetBase_CLOCK_POWER在u-boot-1.1.4\include\s3c2410.h中定义如下:
static inline S3C24X0_CLOCK_POWER * const S3C24X0_GetBase_CLOCK_POWER(void)
{
 return (S3C24X0_CLOCK_POWER * const)S3C24X0_CLOCK_POWER_BASE;
}
S3C24X0_CLOCK_POWER_BASE也在同一个文件中定义:
#define S3C24X0_CLOCK_POWER_BASE 0x4C000000
这里的意思是所有寄存器都通过结构体变量来存取,而不像我们裸机编程是各个寄存器一个个的定义。S3C24X0_GPIO结构体同S3C24X0_CLOCK_POWER,这里不再详述.
接着设置时钟频率,设置I/O口,接下来,
 /* arch number of SMDK2410-Board */
 gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
这里回到我们的bd_t中,那里有个成员:bi_arch_number;
定义是这样的的:ulong         bi_arch_number; /* unique id for this board */
这里给它赋值.在u-boot-1.1.4\include\asm-arm\mach-types.h中#define MACH_TYPE_SMDK2410             193
这里的MACH_TYPE_SMDK2410应该到时传递给内核以用来识别开发板类型的.
 /* adress of boot parameters */
 gd->bd->bi_boot_params = 0x30000100;
bi_boot_params为传递给内核的参数的地址.
接着设置指令cache,数据cache:
 icache_enable();
 dcache_enable();
这两个函数定义在u-boot-1.1.4\cpu\arm920t\cpu.c中
void icache_enable (void)
{
 ulong reg;
 reg = read_p15_c1 ();  /* get control reg. */
 cp_delay ();
 write_p15_c1 (reg | C1_IC);
}
void dcache_enable (void)
{
 ulong reg;
 reg = read_p15_c1 ();
 cp_delay ();
 write_p15_c1 (reg | C1_DC);
}
其中read_p15_c1在同一个文件中定义,mrc指令用英文这样记:mov cp to reg,这里是把cp15的寄存器1读到%0(不太清楚这个内嵌语法).
/* read co-processor 15, register #1 (control register) */
static unsigned long read_p15_c1 (void)
{
 unsigned long value;
 __asm__ __volatile__(
  "mrc p15, 0, %0, c1, c0, 0   @ read control reg\n"
  : "=r" (value)
  :
  : "memory");
#ifdef MMU_DEBUG
 printf ("p15/c1 is = %08lx\n", value);
#endif
 return value;
}
write_p15_c1 (reg | C1_IC);是设置指令cache,其中C1_IC在同一文件中定义#define C1_IC  (1<<12)  /* icache off/on */
write_p15_c1 (reg | C1_DC);是设置数据cache,其中C1_DC在同一文件中定义#define C1_DC  (1<<2)  /* dcache off/on */
/* write to co-processor 15, register #1 (control register) */
static void write_p15_c1 (unsigned long value)
{
#ifdef MMU_DEBUG
 printf ("write %08lx to p15/c1\n", value);
#endif
 __asm__ __volatile__(
  "mcr p15, 0, %0, c1, c0, 0   @ write it back\n"
  :
  : "r" (value)
  : "memory");
 read_p15_c1 ();             /*这里read_p15_c1应该纯粹是为了支持*/
}
board_init函数到这里就分析完了,实际上就是设置了一些寄存器,如时钟,IO口,串口,机器类型,启动参数,指令cache,数据cache.

然后到interrupt_init了,
int interrupt_init (void)
{
 S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();
 /* use PWM Timer 4 because it has no output */
 /* prescaler for Timer 4 is 16 */
 timers->TCFG0 = 0x0f00;
 if (timer_load_val == 0)
 {
  /*
   * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
   * (default) and prescaler = 16. Should be 10390
   * @33.25MHz and 15625 @ 50 MHz
   */
  timer_load_val = get_PCLK()/(2 * 16 * 100);
 }
 /* load value for 10 ms timeout */
 lastdec = timers->TCNTB4 = timer_load_val;
 /* auto load, manual update of Timer 4 */
 timers->TCON = (timers->TCON & ~0x0700000) | 0x600000;
 /* auto load, start Timer 4 */
 timers->TCON = (timers->TCON & ~0x0700000) | 0x500000;
 timestamp = 0;
 return (0);
}
结构体S3C24X0_TIMERS同前面的S3C24X0_CLOCK_POWER一样,也在u-boot-1.1.4\include\s3c24x0.h中定义
typedef struct {
 S3C24X0_REG32 TCFG0;
 S3C24X0_REG32 TCFG1;
 S3C24X0_REG32 TCON;
 S3C24X0_TIMER ch[4];
 S3C24X0_REG32 TCNTB4;
 S3C24X0_REG32 TCNTO4;
} /*__attribute__((__packed__))*/ S3C24X0_TIMERS;
这里的寄存器没什么,对照2410数据手册就知道怎么设置了.其中的S3C24X0_GetBase_TIMERS函数在u-boot-1.1.4\include\s3c2410.h中定义
static inline S3C24X0_TIMERS * const S3C24X0_GetBase_TIMERS(void)
{
 return (S3C24X0_TIMERS * const)S3C24X0_TIMER_BASE;
}
S3C24X0_TIMER_BASE也在同一个文件中定义:
#define S3C24X0_TIMER_BASE  0x51000000
timers->TCFG0 = 0x0f00; 这里用到timer4,只用到预分频器1,这里设置TCFG0[15:8]=0x0f,[7:0]=0(没用到).
在u-boot-1.1.4\cpu\arm920t\s3c24x0\interrupts.c中定义了int timer_load_val = 0;
timer_load_val = get_PCLK()/(2 * 16 * 100);
/*TCFG1没有设置,默认为2分频,定时器4的计数值可以由get_PCLK()/(2 * 16 * 100)算得*/
get_PCLK这个函数在u-boot-1.1.4\cpu\arm920t\s3c24x0\speed.c中:
/* return PCLK frequency */
ulong get_PCLK(void)
{
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
    return((clk_power->CLKDIVN & 0x1) ? get_HCLK()/2 : get_HCLK());
}
这里又从PCLK根据分频设置又从get_HCLK()/2或get_HCLK()中得到:
/* return HCLK frequency */
ulong get_HCLK(void)
{
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
    return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
}
而这里HCLK又根据分频设置get_FCLK/2或get_FCLK中得到:
/* return FCLK frequency */
ulong get_FCLK(void)
{
    return(get_PLLCLK(MPLL));
}
static ulong get_PLLCLK(int pllreg)
{
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
    ulong r, m, p, s;
    if (pllreg == MPLL)
 r = clk_power->MPLLCON;
    else if (pllreg == UPLL)
 r = clk_power->UPLLCON;
    else
 hang();
    m = ((r & 0xFF000) >> 12) + 8;
    p = ((r & 0x003F0) >> 4) + 2;
    s = r & 0x3;
    return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
}
在u-boot-1.1.4\include\configs\smdk2410.h中定义有:
/* input clock of PLL */
#define CONFIG_SYS_CLK_FREQ 12000000/* the SMDK2410 has 12MHz input clock */
我们的板子也是这个频率,所以很多和时钟有关的参数都不用修改.
接着设置timer4定时器的计数值,手动加载,设置自动重载,开启定时器,具体设置就不详细分析了.
 /* load value for 10 ms timeout */
 lastdec = timers->TCNTB4 = timer_load_val;
 /* auto load, manual update of Timer 4 */
 timers->TCON = (timers->TCON & ~0x0700000) | 0x600000;
 /* auto load, start Timer 4 */
 timers->TCON = (timers->TCON & ~0x0700000) | 0x500000;
到这里interrupt_init分析结束

下面到env_init函数,搜索到u-boot有很多个env_init,在u-boot-1.1.4\common\env_flash.c中有这么一句:
#if defined(CFG_ENV_IS_IN_FLASH) /* Environment is in Flash */
正是因为在u-boot-1.1.4\include\configs\smdk2410.h中定义了CFG_ENV_IS_IN_FLASH,而其他的CFG_ENV_IS_IN_NAND等没有被定义,所以只有env_flash.c被编译
#define CFG_ENV_IS_IN_FLASH 1
下面就跳到env_flash.c中的env_init去分析,这个文件里也有两个env_init函数,第一个是在CFG_ENV_ADDR_REDUND有定义的情况才去编译的,而u-boot-1.1.4\include\configs\smdk2410.h没有定义这个宏,所以只有第二个env_init会实际被执行:
int  env_init(void)
{
 DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_OMAP2420H4
 int flash_probe(void);
 if(flash_probe() == 0)
  goto bad_flash;
#endif
 if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
  gd->env_addr  = (ulong)&(env_ptr->data);
  gd->env_valid = 1;
  return(0);
 }
#ifdef CONFIG_OMAP2420H4
bad_flash:
#endif
 gd->env_addr  = (ulong)&default_environment[0];
 gd->env_valid = 0;
 return (0);
}
对于smdk2410开发板,CONFIG_OMAP2420H4这个宏没有被定义,所以中间那段跳过.
这里是设置了gd_t类型的指针变量gd,这里是用env_addr变量来存放default_environment数组的地址.
env_valid为CRD校验标志,这里设置为无效.default_environment在u-boot-1.1.4\common\env_common.c中定义:
uchar default_environment[] = {
#ifdef CONFIG_BOOTARGS   /*smdk2410开发板中没有定义*/
 "bootargs=" CONFIG_BOOTARGS   "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND  /*smdk2410开发板中没有定义*/
 "bootcmd=" CONFIG_BOOTCOMMAND  "\0"
#endif
#ifdef CONFIG_RAMBOOTCOMMAND   /*smdk2410开发板中没有定义*/
 "ramboot=" CONFIG_RAMBOOTCOMMAND  "\0"
#endif
#ifdef CONFIG_NFSBOOTCOMMAND   /*smdk2410开发板中没有定义*/
 "nfsboot=" CONFIG_NFSBOOTCOMMAND  "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)               /*smdk2410中有定义*/
 "bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
#endif         /*smdk2410中有定义*/
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
 "baudrate=" MK_STR(CONFIG_BAUDRATE)  "\0"
#endif     /*smdk2410开发板中没有定义*/
#ifdef CONFIG_LOADS_ECHO
 "loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
#endif
#ifdef CONFIG_ETHADDR   /*smdk2410开发板中没有定义*/
 "ethaddr=" MK_STR(CONFIG_ETHADDR)  "\0"
#endif
#ifdef CONFIG_ETH1ADDR   /*smdk2410开发板中没有定义*/
 "eth1addr=" MK_STR(CONFIG_ETH1ADDR)  "\0"
#endif
#ifdef CONFIG_ETH2ADDR   /*smdk2410开发板中没有定义*/
 "eth2addr=" MK_STR(CONFIG_ETH2ADDR)  "\0"
#endif
#ifdef CONFIG_ETH3ADDR   /*smdk2410开发板中没有定义*/
 "eth3addr=" MK_STR(CONFIG_ETH3ADDR)  "\0"
#endif
#ifdef CONFIG_IPADDR       /*smdk2410中有定义*/
 "ipaddr=" MK_STR(CONFIG_IPADDR)  "\0"
#endif
#ifdef CONFIG_SERVERIP       /*smdk2410中有定义*/
 "serverip=" MK_STR(CONFIG_SERVERIP)  "\0"
#endif
#ifdef CFG_AUTOLOAD   /*smdk2410开发板中没有定义*/
 "autoload=" CFG_AUTOLOAD   "\0"
#endif
#ifdef CONFIG_PREBOOT   /*smdk2410开发板中没有定义*/
 "preboot=" CONFIG_PREBOOT   "\0"
#endif
#ifdef CONFIG_ROOTPATH   /*smdk2410开发板中没有定义*/
 "rootpath=" MK_STR(CONFIG_ROOTPATH)  "\0"
#endif
#ifdef CONFIG_GATEWAYIP  /*smdk2410开发板中没有定义*/
 "gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
#endif
#ifdef CONFIG_NETMASK       /*smdk2410中有定义*/
 "netmask=" MK_STR(CONFIG_NETMASK)  "\0"
#endif
#ifdef CONFIG_HOSTNAME   /*smdk2410开发板中没有定义*/
 "hostname=" MK_STR(CONFIG_HOSTNAME)  "\0"
#endif
#ifdef CONFIG_BOOTFILE   /*smdk2410开发板中没有定义*/
 "bootfile=" MK_STR(CONFIG_BOOTFILE)  "\0"
#endif
#ifdef CONFIG_LOADADDR   /*smdk2410开发板中没有定义*/
 "loadaddr=" MK_STR(CONFIG_LOADADDR)  "\0"
#endif
#ifdef  CONFIG_CLOCKS_IN_MHZ  /*smdk2410开发板中没有定义*/
 "clocks_in_mhz=1\0"
#endif     /*smdk2410开发板中没有定义*/
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
 "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
#endif
#ifdef  CONFIG_EXTRA_ENV_SETTINGS
 CONFIG_EXTRA_ENV_SETTINGS
#endif
 "\0"
};
MK_STR宏的作用是将一个字符串转化为一个值,这个宏在其他文件中也有定义,但ENV_IS_EMBEDDED没有被定义,所以Environment.c中MK_STR宏也就没有定义.只有在u-boot-1.1.4\common\env_common.c里定义了.
env_init分析完,接下来到init_baudrate了:
static int init_baudrate (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 uchar tmp[64]; /* long enough for environment variables */
 int i = getenv_r ("baudrate", tmp, sizeof (tmp));
 gd->bd->bi_baudrate = gd->baudrate = (i > 0)
   ? (int) simple_strtoul (tmp, NULL, 10)
   : CONFIG_BAUDRATE;
 return (0);
}
getenv_r在u-boot-1.1.4\common\cmd_nvedit.c里面,这个函数有一点点复杂,大概意思是取出和name匹配的参数的值,存放到tmp里去
int getenv_r (char *name, char *buf, unsigned len)
{
 int i, nxt;
 for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
  int val, n;
  for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
   if (nxt >= CFG_ENV_SIZE) {
    return (-1);
   }
  }
  if ((val=envmatch((uchar *)name, i)) < 0)
   continue;
  /* found; copy out */
  n = 0;
  while ((len > n++) && (*buf++ = env_get_char(val++)) != '\0') /*这个循环是把等号后面的参数值拷贝到buf中*/
   ;
  if (len == n)
   *buf = '\0';
  return (n);
 }
 return (-1);
}
env_get_char在u-boot-1.1.4\common\env_common.c中定义如下:
uchar (*env_get_char)(int) = env_get_char_init;
继续搜索env_get_char_init,也在同一文件中:
static uchar env_get_char_init (int index)
{
 DECLARE_GLOBAL_DATA_PTR;
 uchar c;
 /* if crc was bad, use the default environment */
 if (gd->env_valid)     /*刚才设置了env_valid=0,所以这里采用默认的值*/
 {
  c = env_get_char_spec(index);
 } else {
  c = default_environment[index];
 }
 return (c);
}
envmatch((uchar *)name, i)在u-boot-1.1.4\common\cmd_nvedit.c中定义,表示从i位置开始查找和name匹配的字符串
static int envmatch (uchar *s1, int i2)
{
 while (*s1 == env_get_char(i2++))
  if (*s1++ == '=')    /*如果等号前面的字符串都匹配,则取出等号前面的字符串*/
   return(i2);
 if (*s1 == '\0' && env_get_char(i2-1) == '=')  /*这种情况应该极少出现吧*/
  return(i2);
 return(-1);
}
继续执行init_baudrate,这里如果参数值不为0则设置为对应值,为0则采用默认值.
 gd->bd->bi_baudrate = gd->baudrate = (i > 0)
   ? (int) simple_strtoul (tmp, NULL, 10)
   : CONFIG_BAUDRATE;
simple_strtoul 这个函数在u-boot-1.1.4\lib_generic\vsprintf.c下面定义,从字面上看,这个函数的意思是str to ul(unsigned long),但它的实现有点复杂,就不去分析了.
接下来到u-boot-1.1.4\cpu\arm920t\s3c24x0\serial.c看下serial_init,这个函数很简单,就是调用了serial_setbrg();
int serial_init (void)
{
 serial_setbrg ();
 return (0);
}
在同一个文件中定义了serial_setbrg,主要是设置串口控制寄存器,模块时钟,波特率等
void serial_setbrg (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
 int i;
 unsigned int reg = 0;
 /* value is calculated so : (int)(PCLK/16./baudrate) -1 */
 reg = get_PCLK() / (16 * gd->baudrate) - 1;
 /* FIFO enable, Tx/Rx FIFO clear */
 uart->UFCON = 0x07;
 uart->UMCON = 0x0;
 /* Normal,No parity,1 stop,8 bit */
 uart->ULCON = 0x3;
 /*
  * tx=level,rx=edge,disable timeout int.,enable rx error int.,
  * normal,interrupt or polling
  */
 uart->UCON = 0x245;
 uart->UBRDIV = reg;
#ifdef CONFIG_HWFLOW
 uart->UMCON = 0x1; /* RTS up */
#endif
 for (i = 0; i < 100; i++);
}
接下来分析console_init_f,这个函数也比较简单
/* Called before relocation - use serial functions */
int console_init_f (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 gd->have_console = 1;    /*设置串口初始化标志,应该是表示串口已可用*/
#ifdef CONFIG_SILENT_CONSOLE    /*CONFIG_SILENT_CONSOLE这个宏smdk2410没有定义到,所以这里跳过*/
 if (getenv("silent") != NULL)
  gd->flags |= GD_FLG_SILENT;
#endif
 return (0);
}
接下来继续看display_banner这个函数,printf不是从标准C库里调用的,这里是重复定义了这个函数,它的调用顺序是printf->vsprintf->puts->serial_puts.最后是把一些信息直接输出到串口上.
static int display_banner (void)
{
 printf ("\n\n%s\n\n", version_string);
 printf ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
  _armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MODEM_SUPPORT    /*smdk2410没有定义CONFIG_MODEM_SUPPORT这个宏,这里跳过*/
 puts ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ     /*这个smdk2410也没有定义*/
 printf ("IRQ Stack: %08lx\n", IRQ_STACK_START);
 printf ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif
 return (0);
}
搜索到version_string的定义,其中U_BOOT_VERSION定义为"U-Boot 1.1.4",即把这个字符串打印到串口上.
const char version_string[] =
 U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;
然后输出_armboot_start, _bss_start, _bss_end等地址信息.
按照顺序下来,下面是dram_init,这个函数比较简单,就是初始化板子的sdram起始地址及容量大小.
int dram_init (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
 gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
 return 0;
}
在smdk2410.h中定义了下面两个宏
#define PHYS_SDRAM_1  0x30000000 /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
回到之前的bd_t结构体里,其成员里有个bi_dram结构体数组,其中CONFIG_NR_DRAM_BANKS表示板子的dram的数目,这里我们只用到了一个sdram,所以只初始化了bi_dram[0].
struct    /* RAM configuration */
    {
 ulong start;
 ulong size;
    }    bi_dram[CONFIG_NR_DRAM_BANKS];
初始化完dram,下面就打印dram有关的信息:
static int display_dram_config (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 int i;
 puts ("RAM Configuration:\n");
 for(i=0; i  printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
  print_size (gd->bd->bi_dram[i].size, "\n");
 }
 return (0);
}
回到之前的循环,执行完之后继续运行下去,下面是flash_init().
 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  if ((*init_fnc_ptr)() != 0) {
   hang ();
  }
 }
 /* configure available FLASH banks */
 size = flash_init ();
 display_flash_config (size);
这里的flash_init是在u-boot-1.1.4\board\smdk2410\flash.c里面的,对于smdk2410,它只实现了AMD_LV400/AMD_LV800的flash操作,对于我们板子的SST39VF1601,在移植的时候这个需要改写,这里先分析smdk2410是怎么实现的.
ulong flash_init (void)
{
 int i, j;
 ulong size = 0;
 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
  ulong flashbase = 0;    /*flashbase是flash的物理起始地址*/
  flash_info[i].flash_id =
#if defined(CONFIG_AMD_LV400)
   (AMD_MANUFACT & FLASH_VENDMASK) |
   (AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
   (AMD_MANUFACT & FLASH_VENDMASK) |
   (AMD_ID_LV800B & FLASH_TYPEMASK);
#else
#error "Unknown flash configured"
#endif
   flash_info[i].size = FLASH_BANK_SIZE;  /*flash的容量大小*/
  flash_info[i].sector_count = CFG_MAX_FLASH_SECT; /*flash的总扇区数*/
  memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); /*flash的保护标志*/
  if (i == 0)
   flashbase = PHYS_FLASH_1;
  else
   panic ("configured too many flash banks!\n");
  for (j = 0; j < flash_info[i].sector_count; j++) {
   if (j <= 3) {
    /* 1st one is 16 KB */
    if (j == 0) {
     flash_info[i].start[j] = /*flash的扇区起始地址*/
      flashbase + 0;
    }
    /* 2nd and 3rd are both 8 KB */
    if ((j == 1) || (j == 2)) {
     flash_info[i].start[j] =
      flashbase + 0x4000 + (j -
              1) *
      0x2000;
    }
    /* 4th 32 KB */
    if (j == 3) {
     flash_info[i].start[j] =
      flashbase + 0x8000;
    }
   } else {
    flash_info[i].start[j] =
     flashbase + (j - 3) * MAIN_SECT_SIZE;
   }
  }
  size += flash_info[i].size;
 }
 flash_protect (FLAG_PROTECT_SET,   /*FLAG_PROTECT_SET在include\flash.h中定义为0x01*/
         CFG_FLASH_BASE,
         CFG_FLASH_BASE + monitor_flash_len - 1,
         &flash_info[0]);
 flash_protect (FLAG_PROTECT_SET,
         CFG_ENV_ADDR,
         CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
 return size;
}
这里有个FLASH Info,搜索到它的定义在u-boot-1.1.4\include\flash.h中
 * FLASH Info: contains chip specific data, per FLASH bank
 */
typedef struct {
 ulong size;   /* total bank size in bytes  */
 ushort sector_count;  /* number of erase units  */
 ulong flash_id;  /* combined device & manufacturer code */
 ulong start[CFG_MAX_FLASH_SECT];   /* physical sector start addresses */
 uchar protect[CFG_MAX_FLASH_SECT]; /* sector protection status */
#ifdef CFG_FLASH_CFI
 uchar portwidth;  /* the width of the port  */
 uchar chipwidth;  /* the width of the chip  */
 ushort buffer_size;  /* # of bytes in write buffer  */
 ulong erase_blk_tout;  /* maximum block erase timeout  */
 ulong write_tout;  /* maximum write timeout  */
 ulong buffer_write_tout; /* maximum buffer write timeout  */
 ushort vendor;   /* the primary vendor id  */
 ushort cmd_reset;  /* Vendor specific reset command */
 ushort interface;  /* used for x8/x16 adjustments  */
#endif
} flash_info_t;
而在smdk2410.h中有如下定义:
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];   /*其中CFG_MAX_FLASH_BANKS为flash的数目,smdk2410定义为0,所以只有一个flash_info,就是flash_info[0]*/
#define FLASH_BANK_SIZE PHYS_FLASH_SIZE
PHYS_FLASH_SIZE在u-boot-1.1.4\include\configs\smdk2410.h中定义了为512K大小.而SST39VF1601为2M大小的,CFG_MAX_FLASH_SECT为flash的总扇区数,
#define PHYS_FLASH_SIZE  0x00080000 /* 512KB */
#define CFG_MAX_FLASH_SECT (11) /* max number of sectors on one chip */
对于SST39VF1601,可以采用sector的方法也可以采用block的方法,其中
1 sector=2k word=4k byte,
1 block=32k word=64k byte,
所以共有2048k/64k个block,即32个block,这些移植的时候需要修改.
上面flash_init()里面有个flash_protect(),把它找出来了,看看它都干了些什么
/*-----------------------------------------------------------------------
 * Set protection status for monitor sectors
 *
 * The monitor is always located in the _first_ Flash bank.
 * If necessary you have to map the second bank at lower addresses.
 */
void flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
{
 ulong b_end = info->start[0] + info->size - 1; /* bank end address */
 short s_end = info->sector_count - 1; /* index of last sector */
 int i;
/*------------------------(开始)实际上这里没有被定义----------------------*/
 debug ("flash_protect %s: from 0x%08lX to 0x%08lX\n",
  (flag & FLAG_PROTECT_SET) ? "ON" :
   (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",
  from, to);
/*------------------------(结束)实际上这里没有被定义----------------------*/
 /* Do nothing if input data is bad. */
 if (info->sector_count == 0 || info->size == 0 || to < from) {
  return;
 }
 /* There is nothing to do if we have no data about the flash
  * or the protect range and flash range don't overlap.
  */
 if (info->flash_id == FLASH_UNKNOWN ||
     to < info->start[0] || from > b_end) {
  return;
 }
 for (i=0; isector_count; ++i) {
  ulong end;  /* last address in current sect */
  end = (i == s_end) ? b_end : info->start[i + 1] - 1;
  /* Update protection if any part of the sector
   * is in the specified range.
   */
  if (from <= end && to >= info->start[i]) {
   if (flag & FLAG_PROTECT_CLEAR) {
#if defined(CFG_FLASH_PROTECTION)     /*这个宏没有被定义,跳过*/
    flash_real_protect(info, i, 0);
#else
    info->protect[i] = 0;
#endif /* CFG_FLASH_PROTECTION */
    debug ("protect off %d\n", i);
   }
   else if (flag & FLAG_PROTECT_SET) {
#if defined(CFG_FLASH_PROTECTION)     /*这个宏没有被定义,跳过*/
    flash_real_protect(info, i, 1);
#else
    info->protect[i] = 1;
#endif /* CFG_FLASH_PROTECTION */
    debug ("protect on %d\n", i);
   }
  }
 }
}
原来实际上在smdk2410中它等于什么都不干,看来白费我工夫了.
继续分析flash_init后面的display_flash_config,size为所有flash的总大小,这里只有一个flash,所以size=flash_info[0]
static void display_flash_config (ulong size)
{
 puts ("Flash: ");
 print_size (size, "\n");
}
继续回到start_armboot(),
#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
#   define PAGE_SIZE 4096
# endif
 /*
  * reserve memory for VFD display (always full pages)
  */
 /* bss_end is defined in the board-specific linker script */
 addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
 size = vfd_setmem (addr);
 gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
# ifndef PAGE_SIZE
#   define PAGE_SIZE 4096
# endif
 /*
  * reserve memory for LCD display (always full pages)
  */
 /* bss_end is defined in the board-specific linker script */
 addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
 size = lcd_setmem (addr);
 gd->fb_base = addr;
#endif /* CONFIG_LCD */
这两段没有被定义,跳过.
 /* armboot_start is defined in the board-specific linker script */
 mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);   /*_armboot_start等于连接时_start的地址,即为0x33f80000*/
其中mem_malloc_init的定义如下,主要是清除内存区域.
static void mem_malloc_init (ulong dest_addr)
{
 mem_malloc_start = dest_addr;
 mem_malloc_end = dest_addr + CFG_MALLOC_LEN;
 mem_malloc_brk = mem_malloc_start;
 memset ((void *) mem_malloc_start, 0,
   mem_malloc_end - mem_malloc_start);
}
接着继续回到start_armboot(),
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
 puts ("NAND:");
 nand_init();  /* go init the NAND */
#endif
从下面可以看到,u-boot-1.1.4\include\configs\smdk2410.h中没有定义CFG_CMD_NAND,所以这段也跳过
#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)
#ifdef CONFIG_HAS_DATAFLASH    /*没有被定义*/
 AT91F_DataflashInit();
 dataflash_print_info();
#endif
 /* initialize environment */
 env_relocate ();
看看这个env_relocate:
void env_relocate (void)
{
 DECLARE_GLOBAL_DATA_PTR;
/*----------------------(开始)实际上这里没有被定义--------------------------*/
 DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
  gd->reloc_off);
/*----------------------(结束)实际上这里没有被定义--------------------------*/
#ifdef CONFIG_AMIGAONEG3SE    /*这个宏没有被定义*/
 enable_nvram();
#endif
#ifdef ENV_IS_EMBEDDED     /*这个应该是没有被定义*/
 /*
  * The environment buffer is embedded with the text segment,
  * just relocate the environment pointer
  */
 env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
 DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
 /*
  * We must allocate a buffer for the environment
  */
 env_ptr = (env_t *)malloc (CFG_ENV_SIZE); /*CFG_ENV_SIZE在configs\smdk2410.h中定义64k*/
 DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif
 /*
  * After relocation to RAM, we can always use the "memory" functions
  */
 env_get_char = env_get_char_memory;
 if (gd->env_valid == 0) {
#if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */  /* 这两个宏都没有被定义*/
  puts ("Using default environment\n\n");
#else
  puts ("*** Warning - bad CRC, using default environment\n\n");   /*所以当env_valid为0的时候,打印校验出错信息*/
  SHOW_BOOT_PROGRESS (-1); /*这个函数被定义为空*/
#endif
  if (sizeof(default_environment) > ENV_SIZE)
  {
   puts ("*** Error - default environment is too large\n\n");
   return;
  }
  memset (env_ptr, 0, sizeof(env_t)); 
  memcpy (env_ptr->data,   /*使用默认的环境变量参数*/
   default_environment,
   sizeof(default_environment));
#ifdef CFG_REDUNDAND_ENVIRONMENT   /*冗余校验*/
  env_ptr->flags = 0xFF;
#endif
  env_crc_update ();   /*取得CRC校验结果*/
  gd->env_valid = 1;   /*env_valid定义了为1,所以第二次启动的时候就不会出现bad crc了*/
 }
 else {
  env_relocate_spec ();
 }
 gd->env_addr = (ulong)&(env_ptr->data);  /*设置gd所指向的gd_t结构体类型的成员env_addr*/
#ifdef CONFIG_AMIGAONEG3SE
 disable_nvram();
#endif
}
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);这里有个env_t,它在include\environment.h中定义:
typedef struct environment_s {
 unsigned long crc;  /* CRC32 over data bytes */
#ifdef CFG_REDUNDAND_ENVIRONMENT   /*smdk2410中没有定义*/
 unsigned char flags;  /* active/obsolete flags */
#endif
 unsigned char data[ENV_SIZE]; /* Environment data  */
} env_t;
#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE)
#define CFG_ENV_SIZE  0x10000 /* Total Size of Environment Sector */
# define ENV_HEADER_SIZE (sizeof(unsigned long))
所以ENV_SIZE=64k-(sizeof(unsigned long))

uchar env_get_char_memory (int index)
{
 DECLARE_GLOBAL_DATA_PTR;
 if (gd->env_valid) {
  return ( *((uchar *)(gd->env_addr + index)) );
 } else {
  return ( default_environment[index] );
 }
}
void env_crc_update (void)
{
 env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
}
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
#ifdef CFG_ENV_ADDR_REDUND     /*在smdk2410中应该是没有被定义*/
 DECLARE_GLOBAL_DATA_PTR;
 if (gd->env_addr != (ulong)&(flash_addr->data)) {
  env_t * etmp = flash_addr;
  ulong ltmp = end_addr;
  flash_addr = flash_addr_new;
  flash_addr_new = etmp;
  end_addr = end_addr_new;
  end_addr_new = ltmp;
 }
 if (flash_addr_new->flags != OBSOLETE_FLAG &&
     crc32(0, flash_addr_new->data, ENV_SIZE) ==
     flash_addr_new->crc) {
  char flag = OBSOLETE_FLAG;
  gd->env_valid = 2;
  flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
  flash_write(&flag,
       (ulong)&(flash_addr_new->flags),
       sizeof(flash_addr_new->flags));
  flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
 }
 if (flash_addr->flags != ACTIVE_FLAG &&
     (flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG) {
  char flag = ACTIVE_FLAG;
  gd->env_valid = 2;
  flash_sect_protect (0, (ulong)flash_addr, end_addr);
  flash_write(&flag,
       (ulong)&(flash_addr->flags),
       sizeof(flash_addr->flags));
  flash_sect_protect (1, (ulong)flash_addr, end_addr);
 }
 if (gd->env_valid == 2)
  puts ("*** Warning - some problems detected "
        "reading environment; recovered successfully\n\n");
#endif /* CFG_ENV_ADDR_REDUND */
 memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE);   /*这个函数相当于只实行了这一行,就是把env的存放地址赋给指针env_ptr*/
#endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */
}
这里flash_addr其实就是CFG_ENV_ADDR,也就是在0x0F0000处.
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#define CFG_ENV_ADDR  (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */
到这里为止,我们了解了env操作的流程大概是这样的,第一次启动是分配一段内存来存放env的信息,然后把内存的指针赋给env_ptr,第二次启动的时候就把存放在flash上的env的地址赋给了env_ptr.
继续回到start_armboot()中:
#ifdef CONFIG_VFD
 /* must do this after the framebuffer is allocated */
 drv_vfd_init();
#endif /* CONFIG_VFD */
 /* IP Address */
 gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");   /*取得env中的ipaddr环境变量的值*/
 /* MAC Address */
 {
  int i;
  ulong reg;
  char *s, *e;
  uchar tmp[64];
  i = getenv_r ("ethaddr", tmp, sizeof (tmp));
  s = (i > 0) ? tmp : NULL;
  for (reg = 0; reg < 6; ++reg) {
   gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
   if (s)
    s = (*e) ? e + 1 : e;
  }
 }
这里有几层调用,
IPaddr_t getenv_IPaddr (char *var)
{
 return (string_to_ip(getenv(var)));    /*getenv和之前的getenv_r作用类似,看起来有点晕.*/
}
IPaddr_t string_to_ip(char *s)
{
 IPaddr_t addr;
 char *e;
 int i;
 if (s == NULL)
  return(0);
 for (addr=0, i=0; i<4; ++i) {
  ulong val = s ? simple_strtoul(s, &e, 10) : 0;
  addr <<= 8;
  addr |= (val & 0xFF);
  if (s) {
   s = (*e) ? e+1 : e;
  }
 }
 return (htonl(addr));
}
继续分析start_armboot(),
int devices_init (void)
{
#ifndef CONFIG_ARM     /* already relocated for current ARM implementation */
 DECLARE_GLOBAL_DATA_PTR;
 ulong relocation_offset = gd->reloc_off;   /*reloc_off没有定义过,默认应该为0*/
 int i;
 /* relocate device name pointers */
 for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
  stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
      relocation_offset);
 }
#endif
 /* Initialize the list */
 devlist = ListCreate (sizeof (device_t));
 if (devlist == NULL) {
  eputs ("Cannot initialize the list of devices!\n");
  return -1;
 }
/*----------------------(开始)这里的宏都没有定义-----------------*/
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
 i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD
 drv_lcd_init ();
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
 drv_video_init ();
#endif
#ifdef CONFIG_KEYBOARD
 drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
 drv_logbuff_init ();
#endif
/*----------------------(结束)这里的宏都没有定义-----------------*/
 drv_system_init ();
/*----------------------(开始)这里的宏都没有定义-----------------*/
#ifdef CONFIG_SERIAL_MULTI
 serial_devices_init ();
#endif
#ifdef CONFIG_USB_TTY
 drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
 drv_nc_init ();
#endif
/*----------------------(结束)这里的宏都没有定义-----------------*/
 return (0);
}
下面列出这里会调用到的结构体和函数:
/* Device information */
typedef struct {
 int flags;   /* Device flags: input/output/system */
 int ext;   /* Supported extensions   */
 char name[16];  /* Device name    */
list_t ListCreate (int elementSize)
{
 list_t list;
 list = (list_t) (NewHandle (sizeof (ListStruct)));  /* create empty list */
 if (list) {
  (*list)->signature = LIST_SIGNATURE;
  (*list)->numItems = 0;
  (*list)->listSize = 0;
  (*list)->itemSize = elementSize;
  (*list)->percentIncrease = kDefaultAllocationPercentIncrease; /*kDefaultAllocationPercentIncrease=10*/
  (*list)->minNumItemsIncrease =
    kDefaultAllocationminNumItemsIncrease;  /*kDefaultAllocationminNumItemsIncrease=4*/
 }
 return list;
}
/********************************************************************/
Handle NewHandle (unsigned int numBytes)
{
 void *memPtr;
 HandleRecord *hanPtr;
 memPtr = calloc (numBytes, 1);
 hanPtr = (HandleRecord *) calloc (sizeof (HandleRecord), 1);
 if (hanPtr && (memPtr || numBytes == 0)) {
  hanPtr->ptr = memPtr;
  hanPtr->size = numBytes;
  return (Handle) hanPtr;
 } else {
  free (memPtr);
  free (hanPtr);
  return NULL;
 }
}
/********************************************************************/
typedef struct ListStructTag
    {
    int signature;              /* debugging aid */
    int percentIncrease;        /* %of current size to increase by when list is out of space */
    int minNumItemsIncrease;    /* fixed number of items to increase by when list is out of space */
    int listSize;               /* number of items than can fit in the currently allocated memory */
    int itemSize;               /* the size of each item in the list (same for every item) */
    int numItems;               /* number of items currently in the list */
    unsigned char itemList[1];  /* resizable array of list elements */
    } ListStruct;
/*==================start_armboot()====================*/
#ifdef CONFIG_CMC_PU2   /*没有被定义*/
 load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */
 jumptable_init ();
void jumptable_init (void)  /*网上查到说做登记函数地址用,似乎没有什么用*/
{
 DECLARE_GLOBAL_DATA_PTR;
 int i;
 gd->jt = (void **) malloc (XF_MAX * sizeof (void *));
 for (i = 0; i < XF_MAX; i++)
  gd->jt[i] = (void *) dummy;
 gd->jt[XF_get_version] = (void *) get_version;
 gd->jt[XF_malloc] = (void *) malloc;
 gd->jt[XF_free] = (void *) free;
 gd->jt[XF_get_timer] = (void *)get_timer;
 gd->jt[XF_udelay] = (void *)udelay;
#if defined(CONFIG_I386) || defined(CONFIG_PPC)
 gd->jt[XF_install_hdlr] = (void *) irq_install_handler;
 gd->jt[XF_free_hdlr] = (void *) irq_free_handler;
#endif /* I386 || PPC */
#if (CONFIG_COMMANDS & CFG_CMD_I2C)
 gd->jt[XF_i2c_write] = (void *) i2c_write;
 gd->jt[XF_i2c_read] = (void *) i2c_read;
#endif /* CFG_CMD_I2C */
}
/*==================start_armboot()====================*/
 console_init_r (); /* fully init console as a device */
/* Called after the relocation - use desired console functions */
int console_init_r (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 device_t *inputdev = NULL, *outputdev = NULL;
 int i, items = ListNumItems (devlist);
/*---------------------(开始)没有被定义------------------------------*/
#ifdef CONFIG_SPLASH_SCREEN
 /* suppress all output if splash screen is enabled and we have
    a bmp to display                                            */
 if (getenv("splashimage") != NULL)
  outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");
#endif
#ifdef CONFIG_SILENT_CONSOLE
 /* Suppress all output if "silent" mode requested  */
 if (gd->flags & GD_FLG_SILENT)
  outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");
#endif
/*---------------------(结束)没有被定义------------------------------*/
 /* Scan devices looking for input and output devices */
 for (i = 1;
      (i <= items) && ((inputdev == NULL) || (outputdev == NULL));
      i++
     ) {
  device_t *dev = ListGetPtrToItem (devlist, i);
  if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
   inputdev = dev;
  }
  if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
   outputdev = dev;
  }
 }
 /* Initializes output console first */
 if (outputdev != NULL) {
  console_setfile (stdout, outputdev);
  console_setfile (stderr, outputdev);
 }
 /* Initializes input console */
 if (inputdev != NULL) {
  console_setfile (stdin, inputdev);
 }
 gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
/*---------------------(开始)没有被定义------------------------------*/
#ifndef CFG_CONSOLE_INFO_QUIET
 /* Print information */
 puts ("In:    ");
 if (stdio_devices[stdin] == NULL) {
  puts ("No input devices available!\n");
 } else {
  printf ("%s\n", stdio_devices[stdin]->name);
 }
 puts ("Out:   ");
 if (stdio_devices[stdout] == NULL) {
  puts ("No output devices available!\n");
 } else {
  printf ("%s\n", stdio_devices[stdout]->name);
 }
 puts ("Err:   ");
 if (stdio_devices[stderr] == NULL) {
  puts ("No error devices available!\n");
 } else {
  printf ("%s\n", stdio_devices[stderr]->name);
 }
#endif /* CFG_CONSOLE_INFO_QUIET */
/*---------------------(结束)没有被定义------------------------------*/
 /* Setting environment variables */
 for (i = 0; i < 3; i++) {
  setenv (stdio_names[i], stdio_devices[i]->name);
 }
#if 0
 /* If nothing usable installed, use only the initial console */
 if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
  return (0);
#endif
 return (0);
}
/****************************下面这段是从网上摘抄下来的*************************/
console_init_r ();后期控制台初始化
     主要过程:查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称,再按照环境指定的名称搜索devlist,将搜到的设备指针赋给标准IO数组stdio_devices[]。置gd->flag标志GD_FLG_DEVINIT。这个标志影响putc,getc函数的实现,未定义此标志时直接由串口serial_getc和serial_putc实现,定义以后通过标准设备数组stdio_devices[]中的putc和getc来实现IO。
 下面是相关代码:
    void putc (const char c)
         {
         #ifdef CONFIG_SILENT_CONSOLE
          if (gd->flags & GD_FLG_SILENT)//GD_FLG_SILENT无输出标志
           return;
         #endif
          if (gd->flags & GD_FLG_DEVINIT) {//设备list已经初始化
           /* Send to the standard output */
           fputc (stdout, c);
          } else {
           /* Send directly to the handler */
           serial_putc (c);//未初始化时直接从串口输出。
          }
         }
       void fputc (int file, const char c)
        {
         if (file < MAX_FILES)
          stdio_devices[file]->putc (c);
        }
为什么要使用devlist,std_device[]?
为了更灵活地实现标准IO重定向,任何可以作为标准IO的设备,如USB键盘,LCD屏,串口等都可以对应一个device_t的结构体变量,只需要实现getc和putc等函数,就能加入到devlist列表中去,也就可以被assign为标准IO设备std_device中去。如函数
int console_assign (int file, char *devname); /* Assign the console 重定向标准输入输出*/
这个函数功能就是把名为devname的设备重定向为标准IO文件file(stdin,stdout,stderr)。其执行过程是在devlist中查找devname的设备,返回这个设备的device_t指针,并把指针值赋给std_device[file]。
/****************************上面这段是从网上摘抄下来的*************************/

/*==================start_armboot()====================*/
#if defined(CONFIG_MISC_INIT_R)  /*没有被定义*/
 /* miscellaneous platform dependent initialisations */
 misc_init_r ();
#endif
 /* enable exceptions */
 enable_interrupts ();
#ifdef CONFIG_USE_IRQ   /*CONFIG_USE_IRQ没有被定义,所以这段跳过*/
/* enable IRQ interrupts */
void enable_interrupts (void)
{
 unsigned long temp;
 __asm__ __volatile__("mrs %0, cpsr\n"
        "bic %0, %0, #0x80\n"
        "msr cpsr_c, %0"
        : "=r" (temp)
        :
        : "memory");
}
/*==================start_armboot()====================*/
 /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
 cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif
网络部分不懂,暂时不看,等看完cs8900的datasheet再看
void cs8900_get_enetaddr (uchar * addr)
{
 int i;
 unsigned char env_enetaddr[6];
 char *tmp = getenv ("ethaddr");
 char *end;
 for (i=0; i<6; i++) {
  env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
  if (tmp)
   tmp = (*end) ? end+1 : end;
 }
 /* verify chip id */
 if (get_reg_init_bus (PP_ChipID) != 0x630e)
  return;
 eth_reset ();
 if ((get_reg (PP_SelfST) & (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) ==
   (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) {
  /* Load the MAC from EEPROM */
  for (i = 0; i < 6 / 2; i++) {
   unsigned int Addr;
   Addr = get_reg (PP_IA + i * 2);
   addr[i * 2] = Addr & 0xFF;
   addr[i * 2 + 1] = Addr >> 8;
  }
  if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6) != 0 &&
      memcmp(env_enetaddr, addr, 6) != 0) {
   printf ("\nWarning: MAC addresses don't match:\n");
   printf ("\tHW MAC address:  "
    "%02X:%02X:%02X:%02X:%02X:%02X\n",
    addr[0], addr[1],
    addr[2], addr[3],
    addr[4], addr[5] );
   printf ("\t\"ethaddr\" value: "
    "%02X:%02X:%02X:%02X:%02X:%02X\n",
    env_enetaddr[0], env_enetaddr[1],
    env_enetaddr[2], env_enetaddr[3],
    env_enetaddr[4], env_enetaddr[5]) ;
   debug ("### Set MAC addr from environment\n");
   memcpy (addr, env_enetaddr, 6);
  }
  if (!tmp) {
   char ethaddr[20];
   sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
     addr[0], addr[1],
     addr[2], addr[3],
     addr[4], addr[5]) ;
   debug ("### Set environment from HW MAC addr = \"%s\"\n",    ethaddr);
   setenv ("ethaddr", ethaddr);
  }
 }
}
/*--------------------------这些似乎都没有用到-----------------------*/
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
 if (getenv ("ethaddr")) {
  smc_set_mac_addr(gd->bd->bi_enetaddr);
 }
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
 /* Initialize from environment */
 if ((s = getenv ("loadaddr")) != NULL) {
  load_addr = simple_strtoul (s, NULL, 16);
 }
#if (CONFIG_COMMANDS & CFG_CMD_NET)
 if ((s = getenv ("bootfile")) != NULL) {
  copy_filename (BootFile, s, sizeof (BootFile));
 }
#endif /* CFG_CMD_NET */
#ifdef BOARD_LATE_INIT
 board_late_init ();
#endif
/*--------------------------这些似乎都没有用到-----------------------*/
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)   /*CONFIG_NET_MULTI有被间接定义到*/
 puts ("Net:   ");
#endif
 eth_initialize(gd->bd);
eth_initialize()有两个,第二个没有被编译,只用到第一个
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)
 int eth_initialize(bd_t *bis)
#elif (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_NET_MULTI)
 int eth_initialize(bd_t *bis)
终于到main_loop了,真是开心
 /* main_loop() can return to retry autoboot, if so just run it again. */
 for (;;) {
  main_loop ();
 }
 /* NOTREACHED - no way out of command loop except booting */
}
这个函数也非常长,这里讲有效代码贴出来:
void main_loop (void)
{
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
 char *s;
 int bootdelay;
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
 s = getenv ("bootdelay");
 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);

  s = getenv ("bootcmd");
 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
 if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
 
  parse_string_outer(s, FLAG_PARSE_SEMICOLON |
        FLAG_EXIT_FROM_LOOP);
 }
#endif /* CONFIG_BOOTDELAY */

 /*
  * Main Loop for Monitor Command Processing
  */
#ifdef CFG_HUSH_PARSER
 parse_file_outer();
 /* This point is never reached */
 for (;;);
#else
 for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
  if (rc >= 0) {
   /* Saw enough of a valid command to
    * restart the timeout.
    */
   reset_cmd_timeout();
  }
#endif
  len = readline (CFG_PROMPT);
  flag = 0; /* assume no special flags for now */
  if (len > 0)
   strcpy (lastcommand, console_buffer);
  else if (len == 0)
   flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
  else if (len == -2) {
   /* -2 means timed out, retry autoboot
    */
   puts ("\nTimed out waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
   /* Reinit board to run initialization code again */
   do_reset (NULL, 0, 0, NULL);
# else
   return;  /* retry autoboot */
# endif
  }
#endif
  if (len == -1)
   puts ("\n");
  else
   rc = run_command (lastcommand, flag);
  if (rc <= 0) {
   /* invalid command or not repeatable, forget it */
   lastcommand[0] = 0;
  }
 }
#endif /*CFG_HUSH_PARSER*/
}
阅读(3499) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~