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_BOOTARGS
在 s5p_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;
}