前面分析了 [38]_uboot启动第一阶阶段分析,主要是关注start.S和lowlevel_init.S 这两个文件即可
现在分析它的第二阶段,从start_armboot函数开始分析,这个函数非常长,足足有400多行,还没包括中间要调用的其它函数,分析文件是board.c文件:
1.先来看看这两个结构体,一个是关于uboot全局变量的结构体gd_t,一个是关于板级信息的结构体bd_t,代码如下:
typedef struct global_data {
bd_t *bd; // 存放开发板相关的信息 ,譬如波特率、IP地址、网卡地址、机器码、启动参数
unsigned long flags;
unsigned long baudrate; //通信的波特率
unsigned long have_console; /* serial_init() was called */ //控制台
unsigned long reloc_off; /* Relocation Offset */ //重定位偏移量
unsigned long env_addr; /* Address of Environment struct */ //环境变量的地址
unsigned long env_valid; /* Checksum of Environment valid? */ //内存中的那份环境变量的值,原来的环境变量可能存在其它启动介质中
unsigned long fb_base; /* base address of frame buffer */ //LCD缓存的起始地址
#ifdef CONFIG_VFD
unsigned char vfd_type; /* display type */
#endif
#if 0
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
phys_size_t ram_size; /* RAM size */
unsigned long reset_status; /* reset status register at boot */
#endif
void **jt; /* jump table */
} gd_t; // 根据结构体内存对齐特性,这个结构体的大小为36字节
------------------------------------------
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */ //串口控制台波特率
unsigned long bi_ip_addr; /* IP Address */ //板子上的ip地址
unsigned char bi_enetaddr[6]; /* Ethernet adress */ //网卡ip地址
struct environment_s *bi_env;
ulong bi_arch_number; /* unique id for this board */ //uboot机器码
ulong bi_boot_params; /* where this board expects params */ //uboot启动参数
struct /* RAM configuration */
{
ulong start;
ulong size;
} bi_dram[CONFIG_NR_DRAM_BANKS]; //内存信息,板子有几块内存、内存分布、大小等。
#ifdef CONFIG_HAS_ETH1
/* second onboard ethernet port */
unsigned char bi_enet1addr[6];
#endif
} bd_t; // 根据结构体内存对齐特性,这个结构体的大小为44字节
2.因为上面两个结构体定义时在内存中是没有被分配内存,还有此时目前还是处于uboot的启动阶段,不能使用malloc去申请内存,只能是手工分配gd_base:
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
ulong gd_base; //gd_base是DDR
//内存排布:uboot的起始地址(0xc3e00000)、uboot的大小2M、堆大小912KB、栈大小512KB、gd_t大小36字节
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
#ifdef CONFIG_USE_IRQ
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif
3.内存排布总结如下:
(6)内存间隔 为了防止高版本的gcc的优化造成错误。譬如在uboot中使用C语言内嵌汇编的方式来实现
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory"); //“ __asm__ ”表示在C语言中内嵌汇编,防止高版本gcc优化它
//这里一个for循环,主要是为了去遍历函数指针数组init_sequence,目的是依次执行init_sequence这个函数指针数组中元素
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) { //如果遍历执行的这些函数的结果不等于0,则初始化就会失败被挂起
hang (); //挂起
}
}
4.关于init_sequence函数指针数组的定义如:
init_fnc_t *init_sequence[] = { /* 这些函数指针数组 */
cpu_init, /* basic cpu dependent setup */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)
reloc_init, /* Set the relocation done flag, must
do this AFTER cpu_init(), but as soon
as possible */
#endif
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 */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */ /*bank的个数配置*/
display_dram_config,
NULL,
};
init_sequence这个函数指针数组里面囊括了一个个的函数,我们很多工作都是在这些函数中展开的,譬如CPU初始化(cpu_init)、板级初始化(board_init)、中断初始化(interrupt_init)、环境变量初始化(env_init) ...........等等。所以这个函数指针数组是我们需要分析的关键。
-----------------------------------------------------------------------------------------------------------------------
int cpu_init (void)
{
/*
* setup up stacks if necessary
*/
#ifdef CONFIG_USE_IRQ / /
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;
}
解析:CONFIG_USE_IRQ没有被定义,所以这里不成立,cpu_init是空函数,原因是该做的事在start.S中都做了。
--------------------------------------------------
/*
* This routine sets the relocation done flag, because even if
* relocation is skipped, the flag is used by other generic code.
*/
static int reloc_init(void)
{
gd->flags |= GD_FLG_RELOC;
return 0;
}
#endif
解析:reloc_init这个函数只是对gd_t结构体中的flag标志位进行置位,表示介质中的uboot的BL2部分已经被拷贝到DDR中了。
-----------------------------------------------------
int board_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_DRIVER_SMC911X
smc9115_pre_init(); //网卡相关
#endif
#ifdef CONFIG_DRIVER_DM9000
dm9000_pre_init();
#endif
gd->bd->bi_arch_number = MACH_TYPE; //机器码
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100); //uboot启动参数:0x30000000 + 0x100 = 0x30000100
//uboot启动内核后,内核在bi_boot_params内存内地址(0x30000100)处读取uboot传给它的参数
return 0;
}
解析:1.DECLARE_GLOBAL_DATA_PTR 这个宏定义的作用是把gd这个全局变量存放在r8寄存器中,这是gcc编译器的一种用法,具体定义:#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
2.dm9000_pre_init(); 这个函数是板级网卡的初始化,网卡的移植工作是就是修改这里,
static void dm9000_pre_init(void)
{
unsigned int tmp;
#if defined(DM9000_16BIT_DATA)
SROM_BW_REG &= ~(0xf << 4);
SROM_BW_REG |= (1<<7) | (1<<6) | (1<<5) | (1<<4);
#else
SROM_BW_REG &= ~(0xf << 4);
SROM_BW_REG |= (0<<6) | (0<<5) | (0<<4);
#endif
SROM_BC1_REG = ((0<<28)|(1<<24)|(5<<16)|(1<<12)|(4<<8)|(6<<4)|(0<<0));//uboot
//SROM_BC1_REG = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0));//kernel
tmp = MP01CON_REG;
tmp &=~(0xf<<4);
tmp |=(2<<4);
MP01CON_REG = tmp;
}
3. 填充bd_t中两个元素,譬如机器码和启动参数 (bi_arch_number、bi_boot_params )
------------------------------------------------------------
int interrupt_init(void)
{
S5PC11X_TIMERS *const timers = S5PC11X_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 @ 66 MHz
*/
timer_load_val = get_PCLK() / (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 & ~0x00700000) | TCON_4_AUTO | TCON_4_UPDATE;
/* auto load, start Timer 4 */
timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON;
timestamp = 0;
解析:interrupt_init是中断相关的初始化,具体设置需要查soc的用户手册。
---------------------------------------------------
int env_init(void)
{
#if defined(ENV_IS_EMBEDDED)
ulong total;
int crc1_ok = 0, crc2_ok = 0;
env_t *tmp_env1, *tmp_env2;
total = CFG_ENV_SIZE;
tmp_env1 = env_ptr;
tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);
crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
if (!crc1_ok && !crc2_ok)
gd->env_valid = 0;
else if(crc1_ok && !crc2_ok)
gd->env_valid = 1;
else if(!crc1_ok && crc2_ok)
gd->env_valid = 2;
else {
/* both ok - check serial */
if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
gd->env_valid = 2;
else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
gd->env_valid = 1;
else if(tmp_env1->flags > tmp_env2->flags)
gd->env_valid = 1;
else if(tmp_env2->flags > tmp_env1->flags)
gd->env_valid = 2;
else /* flags are equal - almost impossible */
gd->env_valid = 1;
}
if (gd->env_valid == 1)
env_ptr = tmp_env1;
else if (gd->env_valid == 2)
env_ptr = tmp_env2;
#else /* ENV_IS_EMBEDDED */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
#endif /* ENV_IS_EMBEDDED */
return (0);
}
解析:环境变量相关的初始化,因为uboot支持多中启动介质,每种介质中都有自己维护的一份环境变量。
-----------------------------------------------------
static int init_baudrate (void)
{
char 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) //simple_strtoul函数将字符串转成数字格式的波特率
: CONFIG_BAUDRATE; //读取不成功则使用x210_sd.h中的的CONFIG_BAUDRATE的值作为波特率
return (0);
}
解析:见函数上的解析语句。
-------------------------------------------------------
int serial_init(void)
{
serial_setbrg();
return (0);
}
void serial_setbrg(void)
{
DECLARE_GLOBAL_DATA_PTR;
int i;
for (i = 0; i < 100; i++);
}
解析:这些函数中没做什么,原因是串口在uboot启动的第一阶段已经做了相应的初始化了.
----------------------------------------------------
/* Called before relocation - use serial functions */
int console_init_f (void)
{
gd->have_console = 1;
#ifdef CONFIG_SILENT_CONSOLE
if (getenv("silent") != NULL)
gd->flags |= GD_FLG_SILENT;
#endif
return (0);
}
解析:控制台初始化分两部分完成,这里是第一部分(console_init_f ),第二部分使用(console_init_r函数)去初始化。
------------------------------------------------
static int display_banner (void)
{}
解析:这个函数仅仅是开启的背光灯(open_backlight)
--------------------------------------------------------
int print_cpuinfo(void)
{
uint set_speed;
uint tmp;
uchar result_set;
#if defined(CONFIG_CLK_533_133_100_100)
set_speed = 53300;
#elif defined(CONFIG_CLK_667_166_166_133)
set_speed = 66700;
#elif defined(CONFIG_CLK_800_200_166_133)
set_speed = 80000;
#elif defined(CONFIG_CLK_1000_200_166_133)
set_speed = 100000;
#elif defined(CONFIG_CLK_1200_200_166_133)
set_speed = 120000;
#else
set_speed = 100000;
printf("Any CONFIG_CLK_XXX is not enabled\n");
#endif
tmp = (set_speed / (get_ARMCLK()/1000000));
if((tmp < 105) && (tmp > 95)){
result_set = 1;
} else {
result_set = 0;
}
#ifdef CONFIG_MCP_SINGLE
printf("\nCPU: S5PV210@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));
#else
printf("\nCPU: S5PC110@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));
#endif
printf(" APLL = %ldMHz, HclkMsys = %ldMHz, PclkMsys = %ldMHz\n",
get_FCLK()/1000000, get_HCLK()/1000000, get_PCLK()/1000000);
#if 1
printf(" MPLL = %ldMHz, EPLL = %ldMHz\n",
get_MPLL_CLK()/1000000, get_PLLCLK(EPLL)/1000000);
printf(" HclkDsys = %ldMHz, PclkDsys = %ldMHz\n",
get_HCLKD()/1000000, get_PCLKD()/1000000);
printf(" HclkPsys = %ldMHz, PclkPsys = %ldMHz\n",
get_HCLKP()/1000000, get_PCLKP()/1000000);
printf(" SCLKA2M = %ldMHz\n", get_SCLKA2M()/1000000);
#endif
puts("Serial = CLKUART ");
return 0;
}
解析:这个函数主要打印cpu相关的信息,我们在串口中看到有关cpu信息就是这里打印出来的。譬如:
CPU: S5PV210@1000MHz(OK)
APLL = 1000MHz, HclkMsys = 200MHz, PclkMsys = 100MHz
MPLL = 667MHz, EPLL = 96MHz
HclkDsys = 166MHz, PclkDsys = 83MHz
HclkPsys = 133MHz, PclkPsys = 66MHz
SCLKA2M = 200MHz
Serial = CLKUART
---------------------------------------------------------
int checkboard(void)
{
#ifdef CONFIG_MCP_SINGLE
#if defined(CONFIG_VOGUES)
printf("\nBoard: VOGUESV210\n");
#else
printf("\nBoard: lixianling\n"); //打印的是这句:Board: lixianling
#endif //CONFIG_VOGUES
#else
printf("\nBoard: lixianling\n"); //这句不会被打印,通过仔细分析可以知道2017-09-04
#endif
return (0);
}
解析:打印板子的信息,譬如Board: lixianling
-------------------------------------------
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
static int init_func_i2c (void)
{
puts ("I2C: ");
i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
puts ("ready\n");
return (0);
}
#endif
解析:i2c相关的初始化
----------------------------------------------
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;
#if defined(PHYS_SDRAM_2)
gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
#endif
#if defined(PHYS_SDRAM_3) //这个没定义
gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;
#endif
return 0;
}
解析:这个函数主要是配置DDR的bank信息,就是有多少片内存,因为内存是可以有8位并联成16位、8位并联成32位这几种情况。
------------------------------------------------------
static int display_dram_config (void)
{
int i;
#ifdef DEBUG
puts ("RAM Configuration:\n");
for(i=0; i
print_size (gd->bd->bi_dram[i].size, "\n");
}
#else
ulong size = 0;
for (i=0; i
}
puts("DRAM: ");
print_size(size, "\n");
#endif
return (0);
}
解析:这里主要把上一步中的内存配置信息通过串口打印出来。,譬如:
Serial = CLKUART
Board: lixianling
DRAM: 512 MB
Flash: 8 MB
SD/MMC: 3776MB
init_sequence总结
(1)init_sequence这个结构体中做了板级硬件的初始化以及gd、gd->bd中的数据结构的初始化。譬如:
[1]_网卡初始化、机器码(gd->bd->bi_arch_number)、内核传参DDR地址(gd->bd->bi_boot_params)、Timer4初始化为10ms一次;
[2]_波特率设置(gd->bd->bi_baudrate和gd->baudrate)、console第一阶段初始化(gd->have_console设置为1)、打印uboot的启动信息;
[3]_打印cpu相关设置信息、检查并打印当前开发板名字、DDR配置信息初始化(gd->bd->bi_dram)、打印DDR总容量。
-------------------------------------------------------------------------------------------------------
最后....这里是start_armboot函数的详细分析:
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr; /* init_fnc_t 是函数类型,init_fnc_ptr是二重函数指针 */
char *s;
int mmc_exist = 0;
#if !defined(CFG_NO_FLASH) || defined (CONFIG_VFD) || defined(CONFIG_LCD)
ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
#if defined(CONFIG_BOOT_MOVINAND)
uint *magic = (uint *) (PHYS_SDRAM_1);
#endif
/* Pointer is writable since we allocated a register for it */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
ulong gd_base; //gd_base是DDRgd_t的起始地址
//内存排布:uboot的起始地址(0xc3e00000)、uboot的大小2M、堆大小912KB、栈大小512KB、gd_t大小36字节
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
#ifdef CONFIG_USE_IRQ
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif
gd = (gd_t*)gd_base; // 实例化,就是gd_base指针和实际的内存绑定
#else
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
#endif
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory"); //“ __asm__ ”表示在C语言中内嵌汇编,防止高版本gcc优化它
//赵炯
memset ((void*)gd, 0, sizeof (gd_t)); //gd全局变量全部清干净
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); //(char*)gd指针的运算是跟指针的类型有关
memset (gd->bd, 0, sizeof (bd_t)); //bd全局变量全部清干净
monitor_flash_len = _bss_start - _armboot_start;
//for循环,主要是为了去遍历函数指针数组init_sequence,目的是依次执行init_sequence这个函数指针数组中元素
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) { //
hang (); //挂起
}
}
#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init (); // norflash的初始化
display_flash_config (size); //打印norflash的大小
#endif /* CFG_NO_FLASH */
#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
/* board init may have inited fb_base */
if (!gd->fb_base) {
# 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 */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */ //初始化uboot的堆管理器
mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE); //具体长度如下:
#else // 0xc3e00000 + (2*1024*1024) - (0x400 + 896*1024) - (512*1024)
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#endif
//******************************//
// Board Specific
// #if defined(CONFIG_SMDKXXXX)
//******************************//
#if defined(CONFIG_SMDK6410)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd); //初始化SOC内部的MMC控制器
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
puts("SD/MMC: ");
if (INF_REG3_REG == 0)
movi_ch = 0;
else
movi_ch = 1;
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
#endif
#endif
if (INF_REG3_REG == BOOT_ONENAND) {
#if defined(CONFIG_CMD_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/
} else {
puts("NAND: ");
nand_init();
if (INF_REG3_REG == 0 || INF_REG3_REG == 7)
setenv("bootcmd", "movi read kernel c0008000;movi read rootfs c0800000;bootm c0008000");
else
setenv("bootcmd", "nand read c0008000 80000 380000;bootm c0008000");
}
#endif /* CONFIG_SMDK6410 */
#if defined(CONFIG_SMDKC100)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#endif
#if defined(CONFIG_CMD_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init();
#endif
#endif /* CONFIG_SMDKC100 */
#if defined(CONFIG_X210)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
#ifdef CONFIG_CHECK_X210CV3
check_flash_flag=0;//check inand error!
#endif
}
#ifdef CONFIG_CHECK_X210CV3
else
{
check_flash_flag=1;//check inand ok!
}
#endif
#endif
#if defined(CONFIG_MTD_ONENAND)
puts("OneNAND: ");
onenand_init();
/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/
#else
//puts("OneNAND: (FSR layer enabled)\n");
#endif
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init();
#endif
#endif /* CONFIG_X210 */
#if defined(CONFIG_SMDK6440)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
if (INF_REG3_REG == 1) { /* eMMC_4.3 */
puts("eMMC: ");
movi_ch = 1;
movi_emmc = 1;
movi_init();
movi_set_ofs(0);
} else if (INF_REG3_REG == 7 || INF_REG3_REG == 0) { /* SD/MMC */
if (INF_REG3_REG & 0x1)
movi_ch = 1;
else
movi_ch = 0;
puts("SD/MMC: ");
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
} else {
}
#endif
#endif
if (INF_REG3_REG == 2) {
/* N/A */
} else {
puts("NAND: ");
nand_init();
//setenv("bootcmd", "nand read c0008000 80000 380000;bootm c0008000");
}
#endif /* CONFIG_SMDK6440 */
#if defined(CONFIG_SMDK6430)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
puts("SD/MMC: ");
if (INF_REG3_REG == 0)
movi_ch = 0;
else
movi_ch = 1;
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
#endif
#endif
if (INF_REG3_REG == BOOT_ONENAND) {
#if defined(CONFIG_CMD_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/
} else if (INF_REG3_REG == BOOT_NAND) {
puts("NAND: ");
nand_init();
} else {
}
if (INF_REG3_REG == 0 || INF_REG3_REG == 7)
setenv("bootcmd", "movi read kernel c0008000;movi read rootfs c0800000;bootm c0008000");
else
setenv("bootcmd", "nand read c0008000 80000 380000;bootm c0008000");
#endif /* CONFIG_SMDK6430 */
#if defined(CONFIG_SMDK6442)
#if defined(CONFIG_GENERIC_MMC)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
if (mmc_exist != 0)
{
puts ("0 MB\n");
}
#else
#if defined(CONFIG_MMC)
puts("SD/MMC: ");
movi_set_capacity();
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
#endif
#endif
#if defined(CONFIG_CMD_ONENAND)
if (INF_REG3_REG == BOOT_ONENAND) {
puts("OneNAND: ");
onenand_init();
}
#endif
#endif /* CONFIG_SMDK6442 */
#if defined(CONFIG_SMDK2416) || defined(CONFIG_SMDK2450)
#if defined(CONFIG_NAND)
puts("NAND: ");
nand_init();
#endif
#if defined(CONFIG_ONENAND)
puts("OneNAND: ");
onenand_init();
#endif
#if defined(CONFIG_BOOT_MOVINAND)
puts("SD/MMC: ");
if ((0x24564236 == magic[0]) && (0x20764316 == magic[1])) {
printf("Boot up for burning\n");
} else {
movi_init();
movi_set_ofs(MOVI_TOTAL_BLKCNT);
}
#endif
#endif /* CONFIG_SMDK2416 CONFIG_SMDK2450 */
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
env_relocate (); /* 环境变量的重新加载 */
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize(); //串口初始化
#endif
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); //IP地址被维护在gd->bd结构体中,IP地址是从环境变量中获取
/* MAC Address */
{
int i;
ulong reg;
char *s, *e;
char tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp)); //从环境变量中获取MAC,然后维护在gd->bd结构体中作为全局变量
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;
}
#ifdef CONFIG_HAS_ETH1
i = getenv_r ("eth1addr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
#endif
}
devices_init (); /* get the devices list going. */ //硬件设备相关的初始化
#ifdef CONFIG_CMC_PU2
load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */
jumptable_init ();
#if !defined(CONFIG_SMDK6442)
console_init_r (); /* fully init console as a device */ // 控制台第二阶段的真正初始化
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
enable_interrupts (); /*空壳子*/
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
extern void dm644x_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
dm644x_eth_set_mac_addr(gd->bd->bi_enetaddr);
}
#endif
#ifdef CONFIG_DRIVER_CS8900
cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif
#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) { /*和内核启动相关的环境变量:loadaddr*/
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) { /*和内核启动相关的环境变量:bootfile*/
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd); //网卡本身初始化,不是网卡于soc之间的初始化
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
#if defined(CONFIG_CMD_IDE)
puts("IDE: ");
ide_init();
#endif
/****************lxg added**************/
#ifdef CONFIG_MPAD
extern int x210_preboot_init(void);
x210_preboot_init(); // x210 (LCD和logo显示)
#endif
/****************end**********************/
/* check menukey to update from sd */
extern void update_all(void);
if(check_menu_update_from_sd()==0)// update mode //uboot的最后阶段支持SD卡自动更新的功能
{
puts ("[LEFT DOWN] update mode\n");
run_command("fdisk -c 0",0);
update_all();
}
else
puts ("[LEFT UP] boot mode\n");
/* 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 hang (void)
{
puts ("### ERROR ### Please RESET the board ###\n");
for (;;); //死循环
}