[39]_uboot启动第二阶段分析

本文详细分析了UBoot启动的第二阶段,从start_armboot函数开始,涉及CPU初始化、板级初始化、中断初始化、环境变量初始化等多个关键步骤。通过解析各个初始化函数,如cpu_init、board_init、interrupt_init、env_init等,揭示了UBoot如何进行硬件资源的配置和系统的准备工作。同时,介绍了内存分配、环境变量校验、串口设置等相关操作。
摘要由CSDN通过智能技术生成

前面分析了  [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.内存排布总结如下:
  (1)uboot区 CFG_UBOOT_BASE-xx (长度为uboot的实际长度CFG_UBOOT_SIZE )
  (2)堆区 长度为CFG_MALLOC_LEN,实际为912KB,包括环境变量的大小。
  (3)栈区 长度为CFG_STACK_SIZE,实际为512KB
  (4)gd 长度为sizeof(gd_t),实际36字节
  (5)bd 长度为sizeof(bd_t),实际为44字节左右

  (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;


return (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)

{
printf ("\n\n%s\n\n", version_string);
debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
      _armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
debug("\t\bMalloc and Stack is above the U-Boot Code.\n");
#else
debug("\t\bMalloc and Stack is below the U-Boot Code.\n");
#endif
#ifdef CONFIG_MODEM_SUPPORT
debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif
open_backlight();//
//open_gprs();


return (0);

}

解析:这个函数仅仅是开启的背光灯(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<CONFIG_NR_DRAM_BANKS; i++) {
printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
print_size (gd->bd->bi_dram[i].size, "\n");
}
#else
ulong size = 0;


for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
size += gd->bd->bi_dram[i].size;
}


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 (;;);	//死循环
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值