赞
踩
在 移植 u-boot-2020.07 到 iTOP-4412(一)地址无关码点灯 文中,因为三星比较恶心的 boot 方式(对学习而言),使用了 MOV 等地址无关指令点灯成功,因为不知道 bl2.bin 最终将 u-boot-spl 重定位在哪里,始终无法使用 ldr 等指令点灯。
对讯为提供的资料经行一番搜索查找发现,讯为有帮助把 bl1 中的安全校验等恶心人的地方去掉,这方便了学习,并且可以看出 spl 的链接地址。所以才能有这一篇文章。
本文主要讲 spl 的方面。
这绝对是一个大坑,最开始我是在 build.sh
中 export 环境变量,第一次编译没有问题,然后发现需要 make menuconfig
或是想手动 make
时发生了错误,肯定是编译器不对,胡乱编译后 make distclean
也不起效果。
只好用 Beyond Compare 手动和原 u-boot 文件对比一个一个修改后才能正常编译,所以很有必要使用同一的脚本初始化环境变量。
. init_env.sh
为了方便,build.sh
主要实现这几个功能:
反汇编非常重要,调试的时候需要分析。
用于制作 tf 启动卡:
文件流程:
vectors 中的其他 arm 向量不去关心。
跳转到 reset 后,又跳转了几次看起来是无用功,应该是设计来增加函数的,还没研究怎么添加。最后由 save_boot_params_ret
跳转到 _main
。
_main
中会根据 CONFIG_SPL_STACK
的值设置 SP,最后跳转到 board_init_f
。
函数定义在:
arch/arm/mach-exynos/spl_boot.c
该初始化函数主要作用:
定义在 arch/arm/mach-exynos/spl_boot.c
初始化结构体 __aligned(8) gd_t local_gd;
,该结构体存放在堆栈中,具体什么用处还没搞懂。
定义在 arch/arm/mach-exynos/lowlevel_init.c
首先调用 get_reset_status()
获取 reset 状态,根据 reset 状态来判断需要完成哪些初始化操作。如果是正常启动,要做如下操作:
set_ps_hold_ctrl()
system_clock_init()
mem_ctrl_init(actions & DO_MEM_RESET)
如果配置了 UART ,将会初始化 UART,需要注意初始化哪一个 UART。最后初始化 TrustZone,这里修改代码,添加宏,不编译它。
#ifndef CONFIG_XHR4412
tzpc_init();
#endif
定义在:arch/arm/mach-exynos/power.c
该函数在 do_lowlevel_init() 返回非零时执行。
调用 get_boot_mode()
函数判断从哪里 boot,然后将代码重定位。
最后直接跳转到重定位的 u-boot 上执行。
嵌入式大神鲁迅曾经说过:没有什么是点灯不能解决的,如果有,那就点两个流水灯。
没想到这么简单的点灯程序仍然不简单。
void led_test(void)
{
volatile unsigned long * GPL2CON;
volatile unsigned long * GPL2DAT;
GPL2CON = (volatile unsigned long *)0x11000100;
GPL2DAT = (volatile unsigned long *)0x11000104;
*GPL2CON = 1;
*GPL2DAT = 1;
while (1) ;
}
在 out/spl/
目录中会自动生成 xhr4412-spl.bin
,一开始没弄懂这个文件怎么来的,不过就是普通的 u-boot-spl.bin
,加了 header 和 padding。
因为这个 header,导致 spl 被 bl1 重定位后无法执行到 reset
,一直没能点灯成功。
对整个 u-boot 文件夹搜索 grep -nr xhr4412
,发现了之前添加的 board 文件夹中有 mkxhr4412spl.c
源文件,应该就是该文件编译后制作的 xhr4412-spl.bin
,所以对它进行修改,注释掉 header 部分。
并且仿造讯为提供的 u-boot 添加 checksum,可能 bl1 还是会对 xhr4412-spl.bin
进行简单校验。
注意:需要 make distclean
后才能使上述修改生效。
最开始以为是 watchdog 的原因导致 cpu reset,但是关闭 watchdog 后也是这样的现象。
后来发现 4412 比简单的 2440 复杂很多,需要电源管理芯片供电,看来应该是设置不对,供电断开了。
设置 PS_HOLD_CONTROL 寄存器,并且我发现不能在设置该寄存器前 disable watchdog,不然灯完全不会亮,具体原因还没分析出来。
设置了 PS_HOLD 后仍然是有问题的,现在可以亮一阵子,但是 6 7 秒后会熄灭重新亮,具体是 watchdog 还是电源管理芯片引起的还未分析出来,下一篇文章再研究这个问题,这里就先闪一闪灯吧。
void led_test(void) { volatile unsigned long i; // volatile 不会被优化 volatile unsigned long * GPL2CON; volatile unsigned long * GPL2DAT; volatile unsigned long * PS_HOLD; GPL2CON = (volatile unsigned long *)0x11000100; GPL2DAT = (volatile unsigned long *)0x11000104; PS_HOLD = (volatile unsigned long *)0x1002330C; *GPL2CON = 1; *GPL2DAT = 0; *PS_HOLD |= 0x300; while (1) { *GPL2DAT ^= 1; for (i = 0; i < 500000; i++) ; } }
只是为了之后点灯不用去翻原理图和芯片手册。。。
static void doled1(int en) { unsigned long x; if (en) x = 1; else x = 0; *(volatile unsigned long *)0x11000100 = 1; // GPL2CON *(volatile unsigned long *)0x11000104 = x; // GPL2DAT } static void doled2(int en) { unsigned long x; if (en) x = 2; else x = 0; *(volatile unsigned long *)0x11000068 = 0; // GPK1PUD *(volatile unsigned long *)0x11000060 = 0x10; // GPK1CON *(volatile unsigned long *)0x11000064 = x; // GPK1DAT }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。