tiny210 uboot源码分析

u-boot-2012.10
tiny210

board_init_f

arch/arm/lib/board.c/board_init_f

void board_init_f(ulong bootflag)			arch/arm/lib/board.c
{
    ...
    ...
   	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
	{
		if ((*init_fnc_ptr)() != 0)
		{
			hang();
		}
	}
    ...
    ...
}

其中 init_sequence 实现为如下代码,上面的代码会逐个执行 init_sequence 中的初始化函数。其中 board_early_init_f / fdtdec_check_fdt / board_postclk_init / get_clocks 没有用到。

init_fnc_t *init_sequence[] = {
	arch_cpu_init, /* basic arch cpu dependent setup.  arch/arm/cpu/armv7/s5p-common/cpu_info.c  */

#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
#ifdef CONFIG_OF_CONTROL
	fdtdec_check_fdt,
#endif
	timer_init, /* initialize timer  arch/arm/cpu/armv7/s5p-common/timer.c */
#ifdef CONFIG_BOARD_POSTCLK_INIT
	board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
	get_clocks,
#endif
	env_init,		/* initialize environment 默认环境变量 #define CONFIG_ENV_IS_NOWHERE 1 使用env_nowhere.c中的 */
	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,
};

下面挨个说明 init_sequence 各个初始化函数的实现与作用

arch_cpu_init

arch/arm/cpu/armv7/s5p-common/cpu_info.c/arch_cpu_init

arch_cpu_init
	s5p_set_cpu_id
		s5p_cpu_id = readl(S5PC100_PRO_ID);	/* readl io.h中的142行 */
		s5p_cpu_id = 0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12);

include/asm/io.h

#ifdef __KERNEL__	

#define __arch_getl(a)			(*(volatile unsigned int *)(a))

#define dmb()		__asm__ __volatile__ ("" : : : "memory")	//制造一个内存屏障,实际读内存的动作,不要优化
#define __iormb()	dmb()

#define readl(c)	({ u32 __v = __arch_getl(c); __iormb(); __v; })

#endif

其中 __KERNEL__ 在编译时传入

arm-linux-gcc -g -Os -fno-common -ffixed-r8 -msoft-float -D__KERNEL__ -DCONFIG_SYS_TEXT_BASE=0x34800000 -I/home/peich/share/u-boot-2012.10/include -fno-builtin -ffreestanding -nostdinc -isystem /usr/local/arm/4.5.1/bin/…/lib/gcc/arm-none-linux-gnueabi/4.5.1/include -pipe -DCONFIG_ARM -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -march=armv7-a -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder -o hello_world.o hello_world.c -c

timer_init

arch/arm/cpu/armv7/s5p-common/timer.c/timer_init

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

	reset_timer_masked();

	return 0;
}

env_init

追踪可以发现有好多文件中都定义了该函数,表明环境变量所在的位置。例如 如果我们使用配置将环境变量在远程端,则使用 env_remote.c 中的env_init。
请添加图片描述

其中我们使用的是 common/env_nowhere.c 中的定义。因为在配置文件 include/configs/s5p_goni.h中有如下定义,表明使用默认的环境变量。

#define CONFIG_ENV_IS_NOWHERE    1

common/env_nowhere.c/env_init

int env_init(void)
{
	gd->env_addr	= (ulong)&default_environment[0];
	gd->env_valid	= 0;

	return 0;
}

common/env_common.c

const uchar default_environment[] = {
#ifdef	CONFIG_BOOTARGS
	"bootargs="	CONFIG_BOOTARGS			"\0"
#endif
.....
.....
}

"bootargs=" CONFIG_BOOTARGS "\0"表示将字符串 "bootargs="CONFIG_BOOTARGS 进行拼接

其中 CONFIG_BOOTARGSs5p_goni.h 定义。

init_baudrate

arch/arm/lib/board.c/init_baudrate

static int init_baudrate(void)
{
	/* 从环境变量 default_environment 中以10为基底取"baudrate", 如果取不到则返回 CONFIG_BAUDRATE s5p_goni.h */
	gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
	return 0;
}

我们可以在 default_environment 中没有定义 “baudrate”,所以会使用 s5p_goni.h 中默认 CONFIG_BAUDRATE

serial_init

common/serial.c

int serial_init()
	get_current()->init()
static struct serial_device *get_current(void)
{
	struct serial_device *dev;

	if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
		dev = default_serial_console();

		/* We must have a console device */
		if (!dev)
			panic("Cannot find console");
	} else
		dev = serial_current;
	return dev;
}

drivers/serial/serial_s5p.c/default_serial_console

__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL0)		// #define CONFIG_SERIAL0 1	 /* use SERIAL0   s5p_goni.h  */
	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
}

drivers/serial/serial_s5p.c

/* Multi serial device functions */
#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \
    int s5p_serial##port##_init(void) { return serial_init_dev(port); } \
    void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \
    int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \
    int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \
    void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \
    void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); }

#define INIT_S5P_SERIAL_STRUCTURE(port, name) { \
	name, \
	s5p_serial##port##_init, \
	NULL, \
	s5p_serial##port##_setbrg, \
	s5p_serial##port##_getc, \
	s5p_serial##port##_tstc, \
	s5p_serial##port##_putc, \
	s5p_serial##port##_puts, \
}

DECLARE_S5P_SERIAL_FUNCTIONS(0);

struct serial_device s5p_serial0_device =
	INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0");

其中 DECLARE_S5P_SERIAL_FUNCTIONS(0)展开为

int s5p_serial0_init(void)
{
	return serial_init_dev(0);
}

void s5p_serial0_setbrg(void)
{
    serial_setbrg_dev(0);
}

.....

其中 struct serial_device s5p_serial0_device = INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0");展开为结构体 serial_device s5p_serial0_devic 的实现:

struct serial_device s5p_serial0_device =
{
	"s5pser0",
	s5p_serial0_init,
    NULL,
	s5p_serial0_setbrg,
	....
};

include/serial.h

struct serial_device {
	/* enough bytes to match alignment of following func pointer */
	char name[16];

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

所以在 serial_init 时会调用drivers/serial/serial_s5p.c中的 serial_init_dev(0)

serial_init_dev

int serial_init_dev(const int dev_index)
{
    /* 返回uart起始地址 0xE2900000并强制转换struct s5p_uart */
	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;
}
static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
{
	u32 offset = dev_index * sizeof(struct s5p_uart);
	return (struct s5p_uart *)(samsung_get_base_uart() + offset);
}

arch/arm/include/asm/arch-s5pc1xx/cpu.h

#define SAMSUNG_BASE(device, base)				\
    static inline unsigned int samsung_get_base_##device(void)	\
    {								\
        if (cpu_is_s5pc100())					\
            return S5PC100_##base;				\	// #define S5PC110_UART_BASE	0xE2900000
        else if (cpu_is_s5pc110())				\
            return S5PC110_##base;				\
        else							\
            return 0;					\
    }
    
SAMSUNG_BASE(uart, UART_BASE)

其中 SAMSUNG_BASE(uart, UART_BASE) 展开为

static inline unsigned int samsung_get_base_uart(void)
{
	if (cpu_is_s5pc100())
		return S5PC100_UART_BASE;	// #define S5PC110_UART_BASE	0xE2900000
	else if (cpu_is_s5pc110())
		return S5PC110_UART_BASE;
	else
		return 0;
}

console_init_f

serial_init 主要是驱动层初始化,console_init_f 为终端层,全是抽象结构。

common/console.c

int console_init_f(void)
{
	gd->have_console = 1;

#ifdef CONFIG_SILENT_CONSOLE		// 没有定义 CONFIG_SILENT_CONSOLE
	if (getenv("silent") != NULL)
		gd->flags |= GD_FLG_SILENT;
#endif

	print_pre_console_buffer();		// 没有使用pre_console缓存

	return 0;
}

display_banner

arch/arm/lib/board.c

static int display_banner(void)
{
	printf("\n\n%s\n\n", version_string);
	debug("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);
}

print_cpuinfo

int print_cpuinfo(void)
{
	char buf[32];

	printf("CPU:\t%s%X@%sMHz\n",
			s5p_get_cpu_name(), s5p_cpu_id,
			strmhz(buf, get_arm_clk()));

	return 0;
}

checkboard

#ifdef CONFIG_DISPLAY_BOARDINFO
int checkboard(void)
{
	puts("Board:\tGoni\n");
	return 0;
}
#endif

init_func_i2c

有些开发板是需要iic启动或者其他操作。goni开发板 include/configs/s5p_goni.h中定义了 \#define CONFIG_SOFT_I2C 1,soft 表示用GPIO模拟。终端上会打印 I2C:ready。

arch/arm/lib/board.c

#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
static int init_func_i2c(void)
{
	puts("I2C:   ");
	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
	puts("ready\n");
	return (0);
}
#endif

dram_init

board/samsung/goni/goni.c

int dram_init(void)
{
	gd->ram_size = PHYS_SDRAM_1_SIZE;
	//gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE +
	//		PHYS_SDRAM_3_SIZE;

	return 0;
}

终端上的 DRAM: 512 MiB 是在 display_dram_config 中打印出来的。

relocate_code

arm-linux-readelf -r u-boot | less

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PLogTpb2-1629642529633)(/home/peich/share/typora/images/Screenshot from 2021-08-22 10-29-08.png)]

一个入口占8个字节,offset表示需要重定位的代码所在的地址,info表示需要重定位代码的类型属性,Type info翻译

	/*
	 * fix .rel.dyn relocations
	 */
	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
	sub	r9, r6, r0		/* r9 <- relocation offset */
	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
	add	r10, r10, r0		/* r10 <- sym table in FLASH */
	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
fixloop:
	ldr	r0, [r2]		/* r0 <- location to fix up, IN FLASH! */
	add	r0, r0, r9		/* r0 <- location to fix up in RAM */
	ldr	r1, [r2, #4]
	and	r7, r1, #0xff
	cmp	r7, #23			/* relative fixup? */
	beq	fixrel
	cmp	r7, #2			/* absolute fixup? */
	beq	fixabs
	/* ignore unknown type of fixup */
	b	fixnext
fixabs:
	/* absolute fix: set location to (offset) symbol value */
	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
	add	r1, r10, r1		/* r1 <- address of symbol in table */
	ldr	r1, [r1, #4]		/* r1 <- symbol value */
	add	r1, r1, r9		/* r1 <- relocated sym addr */
	b	fixnext
fixrel:
	/* relative fix: increase location by offset */
	ldr	r1, [r0]
	add	r1, r1, r9
fixnext:
	str	r1, [r0]
	add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */
	cmp	r2, r3
	blo	fixloop
	b	clear_bss
fixloop:
	ldr	r0, [r2]		/* r0 <- location to fix up, IN FLASH! */
	add	r0, r0, r9		/* r0 <- location to fix up in RAM */
	ldr	r1, [r2, #4]

board_init_r

enable_caches

/*
 * Default implementation of enable_caches()
 * Real implementation should be in platform code
 */
void __enable_caches(void)
{
	puts("WARNING: Caches not enabled\n");
}
void enable_caches(void)
	__attribute__((weak, alias("__enable_caches")));

board_init

board/samsung/goni/goni.c

int board_init(void)
{
	/* Set Initial global variables */
	s5pc110_gpio = (struct s5pc110_gpio *)S5PC110_GPIO_BASE;

	gd->bd->bi_arch_number = MACH_TYPE_GONI;
	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;

#if defined(CONFIG_PMIC)
	pmic_init();
#endif
	return 0;
}

serial_initialize

common/serial.c

void serial_initialize(void)
{
	//...
	serial_register(&s5p_serial0_device);
	serial_register(&s5p_serial1_device);
	serial_register(&s5p_serial2_device);
	serial_register(&s5p_serial3_device);
	//...
    
    serial_assign(default_serial_console()->name);	//将serial0设置为终端串口
}
void serial_register(struct serial_device *dev)
{
    //...
	dev->next = serial_devices;
	serial_devices = dev;
}
int serial_assign(const char *name)
{
	struct serial_device *s;

	for (s = serial_devices; s; s = s->next) {
		if (strcmp(s->name, name) == 0) {
			serial_current = s;
			return 0;
		}
	}

	return 1;
}

drivers/serial/serial_s5p.c/default_serial_console

__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL0)
	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
}

请添加图片描述

mem_malloc_init

	malloc_start = dest_addr - TOTAL_MALLOC_LEN;	// TOTAL_MALLOC_LEN   15M
	mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN);
void mem_malloc_init(ulong start, ulong size)
{
	mem_malloc_start = start;
	mem_malloc_end = start + size;
	mem_malloc_brk = start;

	memset((void *)mem_malloc_start, 0, size);
}

mmc_initialize

int mmc_initialize(bd_t *bis)
{
	INIT_LIST_HEAD (&mmc_devices);
	cur_dev_num = 0;

	if (board_mmc_init(bis) < 0)
		cpu_mmc_init(bis);

	print_mmc_devices(',');

	return 0;
}

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值