copy_uboot_to_ram() 流程:
spl_get_machine_params()
获取从 SERIAL 启动时的参数,仅 spl 编译。(不会使用到)get_boot_mode()
获取启动模式,SD、emmc 等。首先只考虑从 SD 中启动,先分析启动参数:(顺便吐槽一下不知道为什么 u-boot 要把下面的 if 放到 switch 外面,真是人类迷惑行为)
case BOOT_MODE_SD:
offset = BL2_START_OFFSET;
size = BL2_SIZE_BLOC_COUNT;
copy_bl2 = get_irom_func(MMC_INDEX);
if (copy_bl2)
copy_bl2(offset, size, CONFIG_SYS_TEXT_BASE);
break;
计算 u-boot.bin 的偏移,固定拷贝 512 KB 到 RAM。
#define RESERVE_BLOCK_SIZE (512)
#define BL1_SIZE (8 << 10) /*8 K reserved for BL1*/
#define SPL_SIZE (16 << 10) /*8 K reserved for SPL*/
#define COPY_BL2_SIZE 0x80000 // 512 KB
#define BL2_START_OFFSET ((RESERVE_BLOCK_SIZE + BL1_SIZE + SPL_SIZE)/512)
#define BL2_SIZE_BLOC_COUNT (COPY_BL2_SIZE/512)
惊奇的发现,卧槽?原来三星早就固化好了 copy to ram 的程序?仔细想想,也是啊,都能先从这些设备启动 bl1,肯定在 iROM 已经有程序可以操作它们了。
/* IROM Function Pointers Table */
u32 irom_ptr_table[] = {
[MMC_INDEX] = 0x02020030, /* iROM Function Pointer-SDMMC boot */
[EMMC44_INDEX] = 0x02020044, /* iROM Function Pointer-EMMC4.4 boot*/
[EMMC44_END_INDEX] = 0x02020048,/* iROM Function Pointer
-EMMC4.4 end boot operation */
[SPI_INDEX] = 0x02020058, /* iROM Function Pointer-SPI boot */
[USB_INDEX] = 0x02020070, /* iROM Function Pointer-USB boot*/
};
TODO
又到了愉快的点灯时刻。。。
如果 u-boot 加载成功,会执行到 common/main.c
中的 main_loop()
函数中,你懂的。。。
果然,失败了。。开始找原因!顺便看一看 u-boot 的启动流程,和 spl 应该是不一样的。
经过努力看 code,终于找到了问题的根本:板子电源没有插,插上就亮了。。。。愣是看了一小时代码才发现。
不过不看不知道,一看吓一跳,原来 spl 跳转到 ram 中的 u-boot 后,会经过一系列地址无关码到 relocate_code ,该函数会将 ram 中的 u-boot 重新定位一个偏移量,这之后才是重定位结束,再跳转到 u-boot 开始执行(抱歉这一系列汇编操作太骚,没看懂)。
经过上面的实验,已经可以执行到 main_loop() 函数,之后基本都是和架构无关的 code 了,但是为了调试,还要将 UART 初始化。
UART 初始化在文件 arch/arm/mach-exynos/lowlevel_init.c
的 do_lowlevel_init()
函数中:
#ifdef CONFIG_DEBUG_UART
#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL_SUPPORT)) || \
!defined(CONFIG_SPL_BUILD)
exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
debug_uart_init();
#endif
#endif
可以看出需要定义 CONFIG_DEBUG_UART 和 不定义 CONFIG_SPL_BUILD 时才编译,如果想在 spl 阶段就开始 printf 需要定义 CONFIG_SPL_SERIAL_SUPPORT。
打开 > Device Drivers > Serial drivers > Enable an early debug UART for debugging,并将
Base address of UART
设置为 0x13820000,这是寄存器的地址UART input clock
设置为 100000000该函数初始化 gpio,将涉及到的 gpio 配置为 UART。但是默认使用的是 UART3,这里改为 UART2,上面设置的寄存器地址也是 UART2。
#ifdef CONFIG_XHR4412
exynos_pinmux_config(PERIPH_ID_UART2, PINMUX_FLAG_NONE);
#else
exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
#endif
文件为:
不需要更改。
一次成功,没有问题!
不过发现一个让人很不爽的问题,在 u-boot 输入命令,有顿手卡,一卡一卡的,而且输入多个字符可能都不显示,就打开了源码看一看:
static void __maybe_unused s5p_serial_init(struct s5p_uart *uart)
{
/* enable FIFOs, auto clear Rx FIFO */
writel(0x3, &uart->ufcon);
writel(0, &uart->umcon);
/* 8N1 */
writel(0x3, &uart->ulcon);
/* No interrupts, no DMA, pure polling */
writel(0x245, &uart->ucon);
}
= = 卧槽,鬼才,不开中断进行 polling,这个一定要给他改改。
大概分析了一下,想要打开中断主要可能有这些步骤:
应该不算很简单,之后再做。
初始化文件: