uboot启动流程webee210启动第二阶段

本文详细介绍了U-Boot在Webee210板子上的启动过程,从低级初始化到环境变量设置,再到波特率、内存布局等的配置。在启动过程中,涉及到了环境变量的加载、串口初始化、LCD帧缓冲区的设定以及自定义命令的添加。通过分析,有助于理解U-Boot的启动逻辑和系统配置。
摘要由CSDN通过智能技术生成

又重新回到原点了,但是此时运行的环境是sdram中,好再次分析.

前面的都是相同的,但是在lowlevel_init中会有不同。

	/* when we already run in ram, we don't need to relocate U-Boot.
	 * and actually, memory controller must be configured before U-Boot
	 * is running in ram.
	 */
	ldr	r0, =0x00ffffff
	bic	r1, pc, r0		/* r0 <- current base addr of code */
	ldr	r2, _TEXT_BASE		/* r1 <- original base addr in ram */
	bic	r2, r2, r0		/* r0 <- current base addr of code */
	cmp     r1, r2                  /* compare r0, r1                  */
	beq     1f			/* r0 == r1 then skip sdram init   */

	/* init system clock */
	bl system_clock_init


	/* Memory initialize */
	bl mem_ctrl_asm_init

1:
	/* for UART */
	bl uart_asm_init

	bl tzpc_init
会判断当前运行的环境是内部的RAM还是外部的RAM,现在运行的环境是外部的RAM,那么会跳过系统时钟的初始化以及内存的初始化,会重新初始化串口,webee210的板子上串口初始化后会打印2次的ok,这一点也验证了这个地方会重新运行。

接着回到调用函数的地方。start.s中:

/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
	bic	sp, sp, #7 /* 8-byte alignment for ABI compliance */
	ldr	r0,=0x00000000
#if defined(CONFIG_WEBEE210) || defined(CONFIG_MINI210)
	adr	r4, _start
	ldr	r5,_TEXT_BASE
	cmp     r5,r4
	beq	board_init_in_ram
此时我们是跑在了外部的ram中,这里还会进行判断,假如是外部的RAM,直接跳转到board_init_in_ram处:

board_init_in_ram:
	bl	board_init_f
好吧,调到board_init_f中了,Board.c (arch\arm\lib)

bd_t *bd;
	init_fnc_t **init_fnc_ptr;
	gd_t *id;
	ulong addr, addr_sp;

	/* Pointer is writable since we allocated a register for it */
	gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);                           //gd webee 210 上的地址是
//	gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
	/* compiler optimization barrier needed for GCC >= 3.4 */
	__asm__ __volatile__("": : :"memory");


	memset((void *)gd, 0, sizeof(gd_t));                                       //清0

	gd->mon_len = _bss_end_ofs;                                               //uboot的长度,bss段的结束地址

	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {      //初始化函数指针
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}

其中init_sequence定义如下:


init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)                                   // 有定义  初始化和CPU相关的ARCH
	arch_cpu_init,		/* basic arch cpu dependent setup */
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)                            //未定义
	board_early_init_f,
#endif
	timer_init,		/* initialize timer */
#ifdef CONFIG_FSL_ESDHC                                                    //未定义
	get_clocks,
#endif
	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 */
	NULL,
};

@1:arch_cpu_init:

#ifdef CONFIG_ARCH_CPU_INIT
int arch_cpu_init(void)
{
	s5p_set_cpu_id();

	return 0;
}
#endif
s5p_set_cpu_id函数从cpu内部读取了相关的id值到 s5p_cpu_id的全局的变量。

@2:

int timer_init(void)
{
	/* PWM Timer 4 */
	pwm_init(4, MUX_DIV_2, 0);
	pwm_config(4, 0, 0);
	pwm_enable(4);

	return 0;
}

初始化了pwm4的定时器,具体细节不讲了。

@3:env_init

int env_init(void)
{
	//carl_Wang add 
#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
	int crc1_ok = 0, crc2_ok = 0;
	env_t *tmp_env1;
	

#ifdef CONFIG_ENV_OFFSET_REDUND
	env_t *tmp_env2;

	tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
	crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
#endif

	tmp_env1 = env_ptr;

	crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);

	if (!crc1_ok && !crc2_ok) {
		gd->env_addr  = 0;
		gd->env_valid = 0;

		return 0;
	} else if (crc1_ok && !crc2_ok) {
		gd->env_valid = 1;
	}
#ifdef CONFIG_ENV_OFFSET_REDUND
	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 == 2)
		env_ptr = tmp_env2;
	else
#endif
	if (gd->env_valid == 1)
		env_ptr = tmp_env1;

	gd->env_addr = (ulong)env_ptr->data;

#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
	gd->env_addr  = (ulong)&default_environment[0];
	gd->env_valid = 1;
#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */

	return (0);
}
看见了一堆的代码,但是经过查找之后,发现没用的很多,有用的是

#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
	gd->env_addr  = (ulong)&default_environment[0];
	gd->env_valid = 1;

gd已经知道了,是一个全局的变量,gd->env_addr 赋值了默认的env 参数表,同时置位env_valid有效。好看一下这个env参数表

gd->env_addr  = (ulong)&default_environment[0];
   gd->env_valid = 1; 

const uchar default_environment[] = {
#ifdef	CONFIG_BOOTARGS
	"bootargs="	CONFIG_BOOTARGS			"\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
	"bootcmd="	CONFIG_BOOTCOMMAND	"nand read 0x30007fc0 0x100000 0x500000;bootm 0x30007fc0\0"
#endif
#ifdef	CONFIG_RAMBOOTCOMMAND
	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_NFSBOOTCOMMAND
	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
	"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
#endif
#ifdef	CONFIG_LOADS_ECHO
	"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
#endif
#ifdef	CONFIG_ETHADDR
	"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
#endif
#ifdef	CONFIG_ETH1ADDR
	"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH2ADDR
	"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH3ADDR
	"eth3addr="	MK_STR(CONFIG_ETH3ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH4ADDR
	"eth4addr="	MK_STR(CONFIG_ETH4ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH5ADDR
	"eth5addr="	MK_STR(CONFIG_ETH5ADDR)		"\0"
#endif
#ifdef	CONFIG_IPADDR
	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
#endif
#ifdef	CONFIG_SERVERIP
	"serverip="	MK_STR(CONFIG_SERVERIP)		"\0"
#endif
#ifdef	CONFIG_SYS_AUTOLOAD
	"autoload="	CONFIG_SYS_AUTOLOAD			"\0"
#endif
#ifdef	CONFIG_PREBOOT
	"preboot="	CONFIG_PREBOOT			"\0"
#endif
#ifdef	CONFIG_ROOTPATH
	"rootpath="	MK_STR(CONFIG_ROOTPATH)		"\0"
#endif
#ifdef	CONFIG_GATEWAYIP
	"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
#endif
#ifdef	CONFIG_NETMASK
	"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
#endif
#ifdef	CONFIG_HOSTNAME
	"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
#endif
#ifdef	CONFIG_BOOTFILE
	"bootfile="	MK_STR(CONFIG_BOOTFILE)		"\0"
#endif
#ifdef	CONFIG_LOADADDR
	"loadaddr="	MK_STR(CONFIG_LOADADDR)		"\0"
#endif
#ifdef  CONFIG_CLOCKS_IN_MHZ
	"clocks_in_mhz=1\0"
#endif
#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"
};
这个有点类似于linux中的devicetree机制,根据“”中的字符串可以取到后面的相应的命令或者参数。注意一下bootcmd 的指令,启动linux时会用到。。。。。

@4:init_baudrate

初始化波特率,看一下env参数表中是否有这个命令,在 Webee210.h (include\configs)  中定义了

#define CONFIG_BAUDRATE 115200 

所以gd->baudrate  = 115200


static int init_baudrate(void)
{
	char tmp[64];	/* long enough for environment variables */
	int i = getenv_f("baudrate", tmp, sizeof(tmp));

	gd->baudrate = (i > 0)
			? (int) simple_strtoul(tmp, NULL, 10)
			: CONFIG_BAUDRATE;

	return (0);
}

@5: serial_init    Serial.c (common)


int serial_init (void)
{
	//carl_wang
	if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
		struct serial_device *dev = default_serial_console ();

		return dev->init ();
	}

	return serial_current->init ();
}
struct serial_device 是一个关于串行设备的一些属性以及方法的(面向对象的思想)结构体,可以使用它构成一个链表。

struct serial_device {
	char name[NAMESIZE];

	int  (*init) (void);
	int  (*uninit) (void);
	void (*setbrg) (void);
	int (*getc) (void);
	int (*tstc) (void);
	void (*putc) (const char c);
	void (*puts) (const char *s);
#if CONFIG_POST & CONFIG_SYS_POST_UART
	void (*loop) (int);
#endif

	struct serial_device *next;
};

dev =  default_serial_console()获取到了关于默认设备的实例,

__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL0)            //定义了串口0
	return &s5p_serial0_device;       //实例化
#elif defined(CONFIG_SERIAL1)
	return &s5p_serial1_device;
#elif defined(CONFIG_SERIAL2)
	return &s5p_serial2_device;
#elif defined(CONFIG_SERIAL3)
	return &s5p_serial3_device;
#else
#error "CONFIG_SERIAL? missing."
#endif
}
这里获取的是s5p_serial0_device,所以调用dev->init则是调用了serial_init_dev,dev_index则是0
/*
 * Initialise the serial port with the given baudrate. The settings
 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 */
int serial_init_dev(const int dev_index)
{
	//carl_wang add
	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);

	/* reset and enable FIFOs, set triggers to the maximum */
	writel(0, &uart->ufcon);
	writel(0, &uart->umcon);
	/* 8N1 */
	writel(0x3, &uart->ulcon);
	/* No interrupts, no DMA, pure polling */
	writel(0x245, &uart->ucon);

	serial_setbrg_dev(dev_index);

	return 0;
}
@6:console_init_f,实际上只是置为标位,此时

gd->have_console = 1;

/* 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;
}
@7:display_banner 哎,就是log输出点版本信息,这里还log输出了uboot的起始地址,bss 段起始地址,bss段的结束地址。

打印出的log如下:

U-Boot 2011.06 (Dec 15 2015 - 22:32:20) for Webee_210_V2

U-Boot code: 33E00000 -> 33E66A30 BSS: -> 33E9CAFC



static int display_banner(void)
{
	printf("\n\n%s\n\n", version_string);
	printf("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
	       _TEXT_BASE,
	       _bss_start_ofs + _TEXT_BASE, _bss_end_ofs + _TEXT_BASE);
#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

	return (0);
}

@8:print_cpuinfo

log出了一点信息,其中你想写的,还有是芯片的频率 。

#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
	char buf[32];
	
	printf("\n");
	printf("##############################################\n");
	printf("#                                            #\n");
	printf("#         i love wunana      #\n");
	printf("#                                            #\n");
	printf("##############################################\n\n");     
	//printf("CPU:\tS5P%X@%sMHz\n",
	//		s5p_cpu_id, strmhz(buf, get_arm_clk()));
	
	printf("CPU:\tS5PV210@%sMHz\n",
			 strmhz(buf, get_arm_clk()));

	return 0;
}
#endif

@9:checkboard:没有特殊的作用,还是log

#ifdef CONFIG_DISPLAY_BOARDINFO
int checkboard(void)
{
	//carl_wang 
	printf("\nBoard:   Webee_210_V2\n");
	return (0);
}
#endif

@10 dram_init  其实是初始化了

gd->ram_size  = 512M

int dram_init(void)
{
	/* Since we have discontinuous RAM configuration, just put
	 * bank1 here for relocation
	 */
        gd->ram_size    = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE+PHYS_SDRAM_2_SIZE);

	return 0;
}

ok,假如中间有任何错误的化都会挂起等待。接着往下走

#if defined(CONFIG_SYS_MEM_TOP_HIDE)
	/*
	 * Subtract specified amount of memory to hide so that it won't
	 * get "touched" at all by U-Boot. By fixing up gd->ram_size
	 * the Linux kernel should now get passed the now "corrected"
	 * memory size and won't touch it either. This should work
	 * for arch/ppc and arch/powerpc. Only Linux board ports in
	 * arch/powerpc with bootwrapper support, that recalculate the
	 * memory size from the SDRAM controller setup will have to
	 * get fixed.
	 */
	gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif

	addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
	/* reserve kernel log buffer */
	addr -= (LOGBUFF_RESERVE);
	debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
		addr);
#endif
#endif

其实就有一句话被编译到了,addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;  其中CONFIG_SYS_SDRAM_BASE 定义是 0x30000000,而ram_size是 536870912

ok 往下


#ifdef CONFIG_PRAM                                                      //未定义
	/* 
	 * reserve protected RAM
	 */
	i = getenv_r("pram", (char *)tmp, sizeof(tmp));
	reg = (i > 0) ? simple_strtoul((const char *)tmp, NULL, 10) :
		CONFIG_PRAM;
	addr -= (reg << 10);		/* size is in kB */
	debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
#endif /* CONFIG_PRAM */

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))                //会编译到
	/* reserve TLB table */
	addr -= (4096 * 4);

	/* round down to next 64 kB limit */
	addr &= ~(0x10000 - 1);

	gd->tlb_addr = addr;
	printf("TLB table at: %08lx\n", addr);
#endif

	/* round down to next 4 kB limit */
	addr &= ~(4096 - 1);
	printf("Top of RAM usable for U-Boot at: %08lx\n", addr);
这个就是给TLB table分出了一些空间,然后禁止访问。

接着往下


#ifdef CONFIG_LCD                                                                                 //未定义
#ifdef CONFIG_FB_ADDR
	gd->fb_base = CONFIG_FB_ADDR;

	debug("Top the fb_base addr is : %08lx\n", gd->fb_base);
#else
	/* reserve memory for LCD display (always full pages) */
	addr = lcd_setmem(addr);
	gd->fb_base = addr;
	debug("Top the fb_base addr is : %08lx\n", gd->fb_base);
#endif /* CONFIG_FB_ADDR */
#endif /* CONFIG_LCD */

	/*
	 * reserve memory for U-Boot code, data & bss
	 * round down to next 4 kB limit
	 */
	addr -= gd->mon_len;
	addr &= ~(4096 - 1);

	debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

这个又是在为uboot预留空间,然后进行4Kb的四舍五入。

往下:

#ifndef CONFIG_SPL_BUILD                                        //会编译到
	/*
	 * reserve memory for malloc() arena
	 */
	addr_sp = addr - TOTAL_MALLOC_LEN;
	debug("Reserving %dk for malloc() at: %08lx\n",
			TOTAL_MALLOC_LEN >> 10, addr_sp);
	/*
	 * (permanently) allocate a Board Info struct
	 * and a permanent copy of the "global" data
	 */
	addr_sp -= sizeof (bd_t);
	bd = (bd_t *) addr_sp;
	gd->bd = bd;
	debug("Reserving %zu Bytes for Board Info at: %08lx\n",
			sizeof (bd_t), addr_sp);

#ifdef CONFIG
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值