X-007-UBOOT-DDR的初始化(Bubblegum-96平台)
作者:wowo 发布于:2016-7-21 22:47
分类:X Project
1. 前言
到目前为止,“X Project”在Bubblegum-96平台上的代码,都是运行在SRAM中。由于SRAM的size很小(最多也就96KB),如果要做更多的事情,就必须把DDR跑起来。不过,关于Bubblegum-96平台的DDR driver,我和codingbelief同学折腾了很久,试图找出一个最佳的方法,给大家呈现出DDR driver的开发方法和开发步骤。最终,受限于“资源”的短缺,还是失败了。
根据Bubblegum-96公开的资料,只知道它包含了一个2GB的、单bank的LPDDR,除此之外,找不到任何技术有关的细节,如LPDDR的datasheet、S900 DDR controller的说明、DDR时钟的配置等等。没有这些东西,我们根本无法完成DDR的配置,更不用说以此介绍、分析DDR driver了。
但是,虽然困难重重,“X Project”还是要进行下去,既然常规方法走不通,我们就采用一些非常规的手段,无论如何,还是能把DDR成功的初始化起来的。由于是非常规手段,当然就无法开源,也无法给大家讲解了。
因此,本文关于DDR的技术细节不多,主要目的是结合DDR的初始化,进一步介绍嵌入式linux开发的基本过程,包括如下知识点:
嵌入式Linux的启动过程。
u-boot SPL的使用场景。
u-boot启动过程中DDR初始化的流程。
2. Bubblegum-96的启动过程
由于RAM资源的短缺,嵌入式系统的启动过程是相当繁琐的,以Bubblegum-96为例:
CPU启动时,只有96KB的SRAM可用。
CPU启动时,ROM code只会从外部存储介质中(NAND、MMC、SD等)拷贝并执行2KB的代码。
首先与上面两个条件,Bubblegum-96的启动代码必须具备如下的特点。
1)软件从外部存储介质加载并执行的时候
a)第一个被执行的image,必须小于2KB(我们暂时称它为SPL,Secondary Program Loader)。
b)SPL在有限的size中,必须完成两个事情:初始化DDR;将后续的启动代码(如u-boot)从存储介质中copy到DDR中执行。
c)u-boot在DDR中运行(不再受限于系统资源),进行必要的初始化之后,将linux kernel copy到DDR中并执行。
d)linux kernel执行,并加载rootfs。
2)固件更新的时候(这里提供一种方案,将借助Android的fastboot,不唯一)
a)第一个被执行的image(SPL),必须小于SRAM的size(根据经验,Bubblegum-96平台,要小于70KB)。
b)通过ROM code的DFU程序,将SPL上传到SRAM并执行。
c)SPL初始化DDR,并将控制权重新交给ROM code的DFU程序。
d)通过ROM code的DFU程序,将u-boot(size不再受限)上传到DDR并执行。
e)u-boot中启动fastboot服务,通过fastboot协议,更新固件。
本文将基于“X Project”前面的成果,介绍通过将SPL上传到SRAM并执行、初始化DDR,然后再把u-boot上传到DDR并执行的过程。
3. 初始化过程介绍
3.1 编写DDR driver,正确初始化DDR
由于非技术的原因,这里无法多说,感兴趣的同学,可以在资料充足的情况下,在自己的板子上尝试。最终的结果,就是导出一个类似于xxx_ddr_init()的接口,该接口会被SPL调用。
3.2 在SPL的初始化代码中,调用DDR的init接口,初始化DDR,然后将控制权交回给ROM code
基于“X-003-UBOOT-基于Bubblegum-96平台的u-boot移植说明”的成果,我们已经可以在SPL的board_init_f接口中点亮一盏LED灯,现在要做的,就是调用DDR的初始化接口,如下:
void board_init_f(ulong bootflag)
{
bubblegum_early_debug(1);
#ifdef HAS_DDR_SOURCE_CODE
s900_ddr_init();
#endif
reboot_to_adfu();
}
注1:这里之所以要加一个宏定义,是因为源代码中没有DDR的source code,避免编译错误而已。
DDR初始化完成后,需要把控制权交回给ROM code的DFU程序,这可要费一番心思,如下:
static void reboot_to_adfu(void)
{
void (*call_adfu)(void);
//call_adfu = (void (*)(void))0xffff5a00;
call_adfu = (void (*)(void))0xffff0400;
call_adfu();
while (1);
}
我这里用了一个比较笨的方法,直接跳转到S900 ROM code的起始地址了,大家可以根据自己平台的实际情况,自行处理。
以上SPL并没有source code提供,我把编译出来的bin文件共享出来了,可参考:
3.3 修改u-boot的代码,完善dram_init接口,告诉u-boot当前DDR的size
int dram_init(void)
{
printf("dram_init\n");
bubblegum_early_debug(11);
/* no need do dram init in here, we have done it in SPL */
gd->ram_size = 2 * 1024 * 1024 * 1024; /* 2GB, TODO */
printf("dram_init OK\n");
return 0;
}
由于SPL已经完成了DDR初始化,这里什么事情都不需要做,只要通过gd->ram_size告知u-boot DDR的size(这里是2GB)即可。当然,这里的赋值有点粗暴,后续再完善吧。
3.4 修改u-boot的配置项,将u-boot编译到DDR中,从DDR执行
改动如下:
-#define CONFIG_SYS_TEXT_BASE CONFIG_SPL_TEXT_BASE
-#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SPL_STACK
+#define CONFIG_SYS_TEXT_BASE 0x11000000
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7ff00)
/* Some commands use this as the default load address, TODO */
-#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE)
+#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7ffc0)
S900 DDR的地址映射是从0x0开始的,我们随便找一个地址(这里是0x11000000)。编译生成新的bin文件后,进行简单的测试,具体如下。
以上可参考如下patch:
4. 测试
在build目录编译完成后,按照如下的步骤执行:
1)按住Bubblegum-96的ADFU键,使板子进入DFU模式
2)按住Bubblegum-96的ADFU键不松开,将splboot.bin(就是我们的SPL image)上传到SRAM并执行
sudo ../tools/dfu/dfu bubblegum 0xe406b200 ../tools/actions/splboot.bin 1
3)执行完毕后,会重新进入DFU模式,进入后,可以松开ADFU按键。
4)将u-boot上传到DDR并执行(注意上传位置和CONFIG_SYS_TEXT_BASE 一致)
sudo ../tools/dfu/dfu bubblegum 0x11000000 out/u-boot/u-boot-dtb.bin 1
5)检查串口打印,执行成功。
原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。
评论:
ary
2016-08-07 20:06
我觉得wowo可以考虑先在一个成熟的开源板子上做一遍移植,一是通用的板子大家都能买到,另外就是开源板子硬件公开程度更高,资料更全,移植更方便
2016-08-07 20:27
@ary:多谢提议,其实不用太在意板子,大家可以用不同的板子,思路一样就可以了。
另外不成熟的板子,会遇到一些问题,有问题也是学习的过程。
现在有同学在tiny210上面移植了(比较成熟了),可以参看:
http://www.wowotech.net/forum/viewtopic.php?id=52
2016-07-25 19:39
wowo:
Bubblegum-96这个板子你们是买的还是?
2016-07-26 08:52
@pingchangxin:我们手上的是厂家送的。
发表评论:
昵称
邮件地址 (选填)
个人主页 (选填)