- U-Boot启动流程概要
- 跳转到_main
- 跳转到board_init_f
- do_lowlevel_init()
- 修改set_ps_hold_ctrl
- copy_uboot_to_ram()
- 分析修改spl_boot.c的原因
- 修改arch/arm/mach-exynos/spl_boot.c支持copy_uboot_to_ram
- (*uboot)();
2022版u-boot启动分析笔记之一(start.S与lowlevel_init.S)
跳转到_main_main函数在arch/arm/lib/crt0.S中,没有需要移植的。main函数的作用在注释中有详细的说明,可以自己翻译:
跳转到board_init_f
移植uboot先做一个最精简版本,很多配置选项都没有打开,比如fb mmc等硬件都默认不打开,只配置基本的ddr serial,这样先保证uboot能正常启动进入命令行,然后再去添加其他。
我们这里分析就是按最精简版本来,这样可以更加简洁的说明uboot的启动流程。
在arch/arm/lib/目录下有spl.c,其中定义了弱函数board_init_f(),是空函数,代码如下:
void __weak board_init_f(ulong dummy)
{
}
在arch/arm/mach-exynos/目录下的spl_boot.c中,定义了函数board_init_f(),board_init_f()函数主要是根据配置对全局信息结构体gd进行初始化。代码如下:
static void setup_global_data(gd_t *gdp)
{
set_gd(gdp);
memzero((void *)gd, sizeof(gd_t));
gd->flags |= GD_FLG_RELOC;
gd->baudrate = CONFIG_BAUDRATE;
gd->have_console = 1;
}
void board_init_f(unsigned long bootflag)
{
__aligned(8) gd_t local_gd;
__attribute__((noreturn)) void (*uboot)(void);
setup_global_data(&local_gd);
if (do_lowlevel_init())
power_exit_wakeup();
copy_uboot_to_ram();
uboot = (void *)CONFIG_SYS_TEXT_base;
(*uboot)();
}
do_lowlevel_init()
在arch/arm/mach-exynos/目录下的lowlevel_init.c中,定义了do_lowlevel_init(void)函数,代码如下:
int do_lowlevel_init(void)
{
uint32_t reset_status;
int actions = 0;
arch_cpu_init();
reset_status = get_reset_status();
switch (reset_status) {
case S5P_CHECK_SLEEP:
actions = DO_CLOCKS | DO_WAKEUP;
break;
case S5P_CHECK_DIDLE:
case S5P_CHECK_LPA:
actions = DO_WAKEUP;
break;
default:
actions = DO_CLOCKS | DO_MEM_RESET | DO_POWER;
}
if (actions & DO_POWER)
set_ps_hold_ctrl();
if (actions & DO_CLOCKS) {
system_clock_init();
#ifdef CONFIG_DEBUG_UART
#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL)) ||
!defined(CONFIG_SPL_BUILD)
#ifdef CONFIG_CBT4412
exynos_pinmux_config(PERIPH_ID_UART0, PINMUX_FLAG_NONE);
#else
exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
#endif
debug_uart_init();
#endif
#endif
mem_ctrl_init(actions & DO_MEM_RESET);
tzpc_init();
}
return actions & DO_WAKEUP;
}
1)get_reset_status()函数获取复位之后的状态.该函数在archarmmach-exynospower.c中定义。
2)判断复位的类型1
复位分为多种情况,如冷启动、休眠唤醒等。
判断复位类型的意义在于:冷启动需要重新初始化DDR,而休眠唤醒不需要再次初始化DDR。
3)set_ps_hold_ctrl()拉高电源管理芯片引脚
4)system_clock_init()系统时钟初始化
该函数在archarmmach-exynosclock_init_exynos4.c中定义。
5)mem_ctrl_init()初始化DMC
该函数在archarmmach-exynosdmc_init_exynos4.c中定义。
6)tzpc_init()
该函数在archarmmach-exynostzpc.c中定义。
set_ps_hold_ctrl()函数在arch/arm/mach-exynos/power.c中。2
ps_hold引脚为电源管理芯片引脚,需要拉高,否则会掉电。power.c代码如下:
#ifdef CONFIG_CBT4412
static void exynos4x12_set_ps_hold_ctrl(void)
{
struct exynos4x12_power *power =
(struct exynos4x12_power *)samsung_get_base_power();
setbits_le32(&power->ps_hold_control, EXYNOS_PS_HOLD_CONTROL_DATA_HIGH);
writel(0x3, (unsigned int *)0x11000c08);
}
#endif
void set_ps_hold_ctrl(void)
{
if (cpu_is_exynos5())
exynos5_set_ps_hold_ctrl();
#ifdef CONFIG_CBT4412
else if (cpu_is_exynos4())
exynos4x12_set_ps_hold_ctrl();
#endif
}
static uint32_t exynos4_get_reset_status(void)
{
#ifdef CONFIG_CBT4412
struct exynos4x12_power *power =
(struct exynos4x12_power *)samsung_get_base_power();
#else
struct exynos4_power *power =
(struct exynos4_power *)samsung_get_base_power();
#endif
return power->inform1;
}
还没修改完,对应的4x12寄存器结构体也得对应上。
修改 arch/arm/mach-exynos/include/mach/power.h
添加4x12的电源芯片结构体定义
power.h代码如下:
struct exynos4x12_power {
unsigned int om_stat;
unsigned char res1[0xc];
unsigned int rtc_clko_sel;
unsigned int gnss_rtc_out_ctrl;
unsigned int lpi_denial_mask0;
unsigned int lpi_denial_mask1;
unsigned int lpi_denial_mask2;
unsigned int c2c_ctrl;
unsigned char res2[0x1d8];
unsigned int central_seq_config;
unsigned int res3;
unsigned int central_seq_option;
unsigned char res4[0x1f4];
unsigned int swreset;
unsigned int rst_stat;
unsigned int auto_wdt_reset_disable;
unsigned int mask_wdt_reset_request;
unsigned char res5[0x1f0];
unsigned int wakeup_stat;
unsigned int eint_wakeup_mask;
unsigned int wakeup_mask;
unsigned char res6[0xf4];
unsigned int hdmi_phy_control;
unsigned int usbdevice_phy_control;
unsigned int hsic_1_phy_control;
unsigned int hsic_2_phy_control;
unsigned int mipi_phy0_control;
unsigned int mipi_phy1_control;
unsigned int adc_phy_control;
unsigned char res7[0x64];
unsigned int body_bias_con0;
unsigned int body_bias_con1;
unsigned int body_bias_con2;
unsigned int body_bias_con3;
unsigned char res8[0x70];
unsigned int inform0;
unsigned int inform1;
unsigned int inform2;
unsigned int inform3;
unsigned int inform4;
unsigned int inform5;
unsigned int inform6;
unsigned int inform7;
unsigned char res9[0x1e0];
unsigned int pmu_debug;
unsigned char res10[0x5fc];
unsigned int arm_core0_sys_pwr_reg;
unsigned char res11[0xc];
unsigned int arm_core1_sys_pwr_reg;
unsigned char res12[0x6c];
unsigned int arm_common_sys_pwr_reg;
unsigned char res13[0x3c];
unsigned int arm_cpu_l2_0_sys_pwr_reg;
unsigned int arm_cpu_l2_1_sys_pwr_reg;
unsigned char res14[0x38];
unsigned int cmu_aclkstop_sys_pwr_reg;
unsigned int cmu_sclkstop_sys_pwr_reg;
unsigned char res15[0x4];
unsigned int cmu_reset_sys_pwr_reg;
unsigned char res16[0x10];
unsigned int apll_sysclk_sys_pwr_reg;
unsigned int mpll_sysclk_sys_pwr_reg;
unsigned int vpll_sysclk_sys_pwr_reg;
unsigned int epll_sysclk_sys_pwr_reg;
unsigned char res17[0x8];
unsigned int cmu_clkstop_gps_alive_sys_pwr_reg;
unsigned int cmu_reset_gps_alive_sys_pwr_reg;
unsigned int cmu_clkstop_cam_sys_pwr_reg;
unsigned int cmu_clkstop_tv_sys_pwr_reg;
unsigned int cmu_clkstop_mfc_sys_pwr_reg;
unsigned int cmu_clkstop_g3d_sys_pwr_reg;
unsigned int cmu_clkstop_lcd0_sys_pwr_reg;
unsigned int cmu_clkstop_isp_sys_pwr_reg;
unsigned int cmu_clkstop_maudio_sys_pwr_reg;
unsigned int cmu_clkstop_gps_sys_pwr_reg;
unsigned int cmu_reset_cam_sys_pwr_reg;
unsigned int cmu_reset_tv_sys_pwr_reg;
unsigned int cmu_reset_mfc_sys_pwr_reg;
unsigned int cmu_reset_g3d_sys_pwr_reg;
unsigned int cmu_reset_lcd0_sys_pwr_reg;
unsigned int cmu_reset_isp_sys_pwr_reg;
unsigned int cmu_reset_maudio_sys_pwr_reg;
unsigned int cmu_reset_gps_sys_pwr_reg;
unsigned int top_bus_sys_pwr_reg;
unsigned int top_retention_sys_pwr_reg;
unsigned int top_pwr_sys_pwr_reg;
unsigned char res18[0x14];
unsigned int logic_reset_sys_pwr_reg;
unsigned char res19[0x1c];
unsigned int onenandxl_mem_sys_pwr_reg;
unsigned int hsi_mem_sys_pwr_reg;
unsigned char res20[0x4];
unsigned int usbotg_mem_sys_pwr_reg;
unsigned int sdmmc_mem_sys_pwr_reg;
unsigned int cssys_mem_sys_pwr_reg;
unsigned int secss_mem_sys_pwr_reg;
unsigned int potator_mem_sys_pwr_reg;
unsigned char res21[0x20];
unsigned int pad_retention_dram_sys_pwr_reg;
unsigned int pad_retention_maudio_sys_pwr_reg;
unsigned char res22[0x18];
unsigned int pad_retention_gpio_sys_pwr_reg;
unsigned int pad_retention_uart_sys_pwr_reg;
unsigned int pad_retention_mmca_sys_pwr_reg;
unsigned int pad_retention_mmcb_sys_pwr_reg;
unsigned int pad_retention_ebia_sys_pwr_reg;
unsigned int pad_retention_ebib_sys_pwr_reg;
unsigned char res23[0x8];
unsigned int pad_isolation_sys_pwr_reg;
unsigned char res24[0x1c];
unsigned int pad_alv_sel_sys_pwr_reg;
unsigned char res25[0x1c];
unsigned int xusbxti_sys_pwr_reg;
unsigned int xxti_sys_pwr_reg;
unsigned char res26[0x38];
unsigned int ext_regulator_sys_pwr_reg;
unsigned char res27[0x3c];
unsigned int gpio_mode_sys_pwr_reg;
unsigned char res28[0x3c];
unsigned int gpio_mode_maudio_sys_pwr_reg;
unsigned char res29[0x3c];
unsigned int cam_sys_pwr_reg;
unsigned int tv_sys_pwr_reg;
unsigned int mfc_sys_pwr_reg;
unsigned int g3d_sys_pwr_reg;
unsigned int lcd0_sys_pwr_reg;
unsigned int isp_sys_pwr_reg;
unsigned int maudio_sys_pwr_reg;
unsigned int gps_sys_pwr_reg;
unsigned int gps_alive_sys_pwr_reg;
unsigned char res30[0xc5c];
unsigned int arm_core0_configuration;
unsigned int arm_core0_status;
unsigned int arm_core0_option;
unsigned char res31[0x74];
unsigned int arm_core1_configuration;
unsigned int arm_core1_status;
unsigned int arm_core1_option;
unsigned char res32[0x37c];
unsigned int arm_common_option;
unsigned char res33[0x1f4];
unsigned int arm_cpu_l2_0_configuration;
unsigned int arm_cpu_l2_0_status;
unsigned char res34[0x18];
unsigned int arm_cpu_l2_1_configuration;
unsigned int arm_cpu_l2_1_status;
unsigned char res35[0xa00];
unsigned int pad_retention_maudio_option;
unsigned char res36[0xdc];
unsigned int pad_retention_gpio_option;
unsigned char res37[0x1c];
unsigned int pad_retention_uart_option;
unsigned char res38[0x1c];
unsigned int pad_retention_mmca_option;
unsigned char res39[0x1c];
unsigned int pad_retention_mmcb_option;
unsigned char res40[0x1c];
unsigned int pad_retention_ebia_option;
unsigned char res41[0x1c];
unsigned int pad_retention_ebib_option;
unsigned char res42[0x160];
unsigned int ps_hold_control;
unsigned char res43[0xf0];
unsigned int xusbxti_configuration;
unsigned int xusbxti_status;
unsigned char res44[0x14];
unsigned int xusbxti_duration;
unsigned int xxti_configuration;
unsigned int xxti_status;
unsigned char res45[0x14];
unsigned int xxti_duration;
unsigned char res46[0x1dc];
unsigned int ext_regulator_duration;
unsigned char res47[0x5e0];
unsigned int cam_configuration;
unsigned int cam_status;
unsigned int cam_option;
unsigned char res48[0x14];
unsigned int tv_configuration;
unsigned int tv_status;
unsigned int tv_option;
unsigned char res49[0x14];
unsigned int mfc_configuration;
unsigned int mfc_status;
unsigned int mfc_option;
unsigned char res50[0x14];
unsigned int g3d_configuration;
unsigned int g3d_status;
unsigned int g3d_option;
unsigned char res51[0x14];
unsigned int lcd0_configuration;
unsigned int lcd0_status;
unsigned int lcd0_option;
unsigned char res52[0x14];
unsigned int isp_configuration;
unsigned int isp_status;
unsigned int isp_option;
unsigned char res53[0x34];
unsigned int gps_configuration;
unsigned int gps_status;
unsigned int gps_option;
unsigned char res54[0x14];
unsigned int gps_alive_configuration;
unsigned int gps_alive_status;
unsigned int gps_alive_option;
};
struct exynos4412_power {
unsigned char res1[0x0704];
unsigned int usbhost_phy_control;
unsigned int hsic1_phy_control;
unsigned int hsic2_phy_control;
};
copy_uboot_to_ram()
该函数在archarmmach-exynosspl_boot.c中定义。
分析修改spl_boot.c的原因假设需要从SD卡启动U-Boot,保留SD卡启动的代码如下:
enum index {
MMC_INDEX,
EMMC44_INDEX,
EMMC44_END_INDEX,
SPI_INDEX,
USB_INDEX,
};
u32 irom_ptr_table[] = {
[MMC_INDEX] = 0x02020030,
[EMMC44_INDEX] = 0x02020044,
[EMMC44_END_INDEX] = 0x02020048,
[SPI_INDEX] = 0x02020058,
[USB_INDEX] = 0x02020070,
};
void *get_irom_func(int index)
{
return (void *)*(u32 *)irom_ptr_table[index];
}
void copy_uboot_to_ram(void)
{
unsigned int bootmode = BOOT_MODE_OM;
u32 (*copy_bl2)(u32 offset, u32 nblock, u32 dst) = NULL;
u32 offset = 0, size = 0;
if (bootmode == BOOT_MODE_OM)
bootmode = get_boot_mode();
switch (bootmode) {
case BOOT_MODE_SD:
offset = BL2_START_OFFSET;
size = BL2_SIZE_BLOC_COUNT;
copy_bl2 = get_irom_func(MMC_INDEX);
break;
if (copy_bl2)
copy_bl2(offset, size, CONFIG_SYS_TEXT_base);
}
由代码可以看出,复制BL2到iRAM的源代码是固化在iROM中的,并且将函数接口的函数指针存放到irom_ptr_table[]数组中,通过调用get_irom_func()函数调用复制BL2函数。所以,不知道也不能修改iROM中是如何实现复制BL2的。
有博主已经说明该代码不能实现复制BL23,并修改了spl_bool.c。基本原理是:先将U-Boot从SD卡复制到iRAM的保留地址区,再从iRAM复制到DRAM中。
如果有大牛分享Exynos4412-iROM-ApplicationNote之类的文档就更好了!
修改arch/arm/mach-exynos/spl_boot.c支持copy_uboot_to_ram修改spl_boot.c代码如下:4
- if (copy_bl2)
+#ifdef CONFIG_TARGET_CBT4412
+ if (copy_bl2) {
+
+ unsigned int i, count = 0;
+ unsigned char *buffer = (unsigned char *)0x02050000;
+ unsigned char *dst = (unsigned char *)CONFIG_SYS_TEXT_base;
+ unsigned int step = (0x10000 / 512);
+
+ for (count = 0; count < BL2_SIZE_BLOC_COUNT; count += step) {
+
+ copy_bl2((u32)(BL2_START_OFFSET+count), (u32)step, (u32)buffer);
+
+ for (i = 0; i < 0x10000; i++) {
+ *dst++ = buffer[i];
+ }
+ }
+ }
+#else
+ if (copy_bl2) {
copy_bl2(offset, size, CONFIG_SYS_TEXT_base);
+ }
+#endif
(*uboot)();
uboot = (void *)CONFIG_SYS_TEXT_base;
// uboot函数设置为BL2的加载地址上
(*uboot)();
// 调用uboot函数,也就跳转到BL2的代码中
到此,SPL的任务就完成了,也已经跳到了BL2也就是uboot里面去了。
uboot的启动过程分析 ↩︎
ITOP4412----Uboot2020移植记录 ↩︎
基于tiny4412的u-boot移植(二) ↩︎
基于iTop-4412的U-Boot 2017移植 ↩︎



