U-boot原厂版本移植流程

U-boot原厂版本移植流程

今天开始移植三星原厂的U-boot,做一下笔记,以备日后所需
移植的时候有一点感想,就是最好别注释掉不对的源码,定义的地方千万别动,尽量修改调用的地方,这样可以极大的避免出错

1. 先烧录看现象

先烧到板子里试试看,看看有什么现象,再做分析

  • 解压源码后,先看看Makefile中的交叉编译工具链有没有问题。根据 U-boot配置及编译阶段流程宏观分析可知,交叉编译工具链配置在主Makefile的前端。查看后发现里面的工具链和我装的一样,没有问题
  • 正式开始编译之前需要配置,那么Makefile中关于配置的伪目标是什么呢?根据 U-boot配置及编译阶段流程宏观分析可知,伪目标在主Makefile的非常后面,而且名字应该是开发板的名字。但是问题来了,三星原厂的评估板叫smdkv210,但是Makefile后面的伪目标有5个名字差不多的,这样的话,相应的.h文件也有5个…..怎么办?
    U-boot原厂版本移植流程_第1张图片
    先不管了,选第一个吧,第一个名字看上去最正常,那以后头文件就要选smdkv210single.h了….然后开始配置阶段了,输入make smdkv210single_config
  • 配置完之后直接make,发现并没有报错,编译一切顺利
  • 烧录前,先看看烧录脚本有没有错,打开sd_fusing目录下的sd_fusing.sh,重点关注
    这里写图片描述这两行,确定BL1和U-boot整体的烧录扇区无误,其中,U-boot的烧录扇区由smdkv210single.h中的宏MOVI_BL2_POS指定。然后保险起见,防止原厂编译出来的sd_fdisk不能用,先在sd_fusing目录make clean一下,再make,得到全新的sd_fdisk。最后执行 ./sd_fusing.sh /dev/sdb 烧录一切顺利
  • 插入SD卡,开机,发现
    这里写图片描述,此外,开发板供电锁存成功了
  • 根据现象分析可知,我们并不能证明SD卡中U-boot彻底失败,因为SD卡正常引导的时候也会输出SD checksum Error,因为x210这块板开机后inand通道的检测优先级是大于SD卡所在的通道的所以这句话指的是inand中校验失败。此外本应在lowlevel_init中最先打印的”OK“却没有正常打印,但是lowlevel_init中的供电锁存却成功了
    所以得出结论,可能有两种情况:1.程序在供电锁存和打印”OK”之间的某处挂掉了;2.串口进行了错误的初始化(可能性不大,因为BL0中初始化过了)

2.解决串口的问题

由于串口打印对于调试非常重要,所以重点先要把串口问题解决

  • 根据之前分析,先去lowlevel_init中检查串口的初始化是否正确,结果发现串口的寄存器设置完全符合我们板子,所以能排除掉串口初始化错误的可能性了
  • 如果原厂的选用的串口不是我们板子上的串口,那么就需要修改了,一般来说,选用哪一个串口还是使用宏定义来决定的,通常没有硬编码,以210为例,只需要将smdkv210single.h中 #define CONFIG_SERIAL3 改为需要的串口即可
  • 然后检查供电锁存和打印”OK”之间的代码
    U-boot原厂版本移植流程_第2张图片
    发现问题会在 PMIC、时钟、内存初始化中。由于时钟是SOC内部的,和板级无关,故不会有问题。同样,lowlevel_init中的代码还没重定位,用不到DDR,故也不会有问题。那么问题可能出在设置PMIC中。另外此处也可以利用连续点灯定位bootloader的错误这个方法定位错误
  • 查资料可知, PMIC是一种电源管理芯片,而我们板子上没用到;再看看PMIC_InitIp这个函数,发现里面都是I2C的通信代码….果然是在这里挂掉了….由于我们没有用PMIC,I2C的通信便会失败,一直处在某一个while(1)中
  • 烧录,尝试,发现整个U-boot居然启动起来了,但是里面的初始化有挺多的错误
    U-boot原厂版本移植流程_第3张图片
    可知,DRAM、SD、网卡、fastboot之类的全部有问题,接下来开始根据U-boot初始化阶段流程的顺序来整改

3.检查供电锁存、时钟、内存、串口配置

这几部分的初始化都在lowlevel_init中

  • 关于供电锁存,由现象可知并没有问题
  • 关于时钟,由U-boot打印信息可知,没有问题。不过如果要修改的话,直接改smdkv210single.h中的宏即可,无需修改代码
  • 关于内存,由U-boot打印信息可知,内存大小是有问题的,板子上只有512M(每片256,一片位于0x20000000,一片位于0x40000000),打印出来总共却有1G。那么内存本身的初始化(即时序、驱动强度等)有没有问题呢?输入md命令查看内存信息
    U-boot原厂版本移植流程_第4张图片
    发现内存可以正常工作,则内存本身的初始化(即时序、驱动强度等)是正确的,错误是在内存的部署上面。那么进入smdkv210single.h修改DDR相关的宏
    U-boot原厂版本移植流程_第5张图片
    将SDRAM_BANK_SIZE(单片SDRAM大小) 改为0x10000000 ,即256MB。改为再检查检查后面几行,SDRAM1起始物理地址是正确的;单片SDRAM大小也是正确的;但是,SDRAM2的物理地址是有问题的,其值为MEMORY_BASE_ADDRESS + SDRAM_BANK_SIZE,即SDRAM1起始物理地址加上单片SDRAM的大小,这样算下来就不对了。我们根据板子上的部署,将其改成0x40000000
    U-boot原厂版本移植流程_第6张图片
    上电后,发现打印出来的DDR相关的设置都正确了~

  • 关于串口,由现象可知并没有问题

4.检查虚拟地址映射

默认的原厂U-boot的虚拟地址映射是不用改的,除非修改了内存从部署和配置

  • (可选步骤)接下来尝试修改内存的部署和配置,把内存的部署改为0x30000000~0x4FFFFFFF,目的是为了熟悉并演示修改U-boot的参数的流程。首先,我们假设原厂的代码写的都挺好的,不存在硬编码,那么只需要修改smdkv210single.h内的宏即可。进入查看和内存有关的宏,首先根据条件编译确定了我们使用的宏为
    U-boot原厂版本移植流程_第7张图片U-boot原厂版本移植流程_第8张图片U-boot原厂版本移植流程_第9张图片
    分析可知,内存本身的初始化(即时序、驱动强度等)应该不用改,需要改的是DMC0控制器的起始位置,仔细查询寄存器可知,只需修改DMC0_MEMCONFIG_0 值为 0x30F01323;此外,还需修改MEMORY_BASE_ADDRESS 值为 0x30000000,这个宏被引用了多次,指导了很多代码的运行。
  • 然后来检查和内存有关的虚拟地址映射表,进入lowlevel_init
    U-boot原厂版本移植流程_第10张图片
    发现0xc0000000被映射到了0x20000000,而我们内存的起始地址为0x30000000,故把第一行改为.set __base,0x300即可
  • 此外,还需要检查一下smdkv210single.h内有关虚拟地址的宏,发现
    这里写图片描述
    看来必须要修改这个虚拟地址转换为物理地址的函数,定位后发现U-boot原厂版本移植流程_第11张图片
    这个函数写的也是无语,居然硬编码…..我们直接把0x20000000改成0x30000000即可…..
    上电,发现修改成功

5.检查MMC配置

  • 由U-boot打印信息可知,mmc的配置是有问题的U-boot原厂版本移植流程_第12张图片
    但是由于mmc的初始化利用了linux的驱动,比较庞大,排查起来较为不便。所以,U-boot的打印信息是定位问题的关键,我们可以利用编辑器的搜索功能来搜索打印信息中的关键字。
  • 我们在源码中搜索 EXT_CSD,在此我用了slickedit的搜素功能,操作如下
    U-boot原厂版本移植流程_第13张图片
    搜索可得结果在mmc.c中U-boot原厂版本移植流程_第14张图片
    由此定位了错误之所在,但是还是不明白发生了什么……
  • 先观察这几句的上下文,发现整个函数是在读取所谓的“拓展CSD寄存器”,从拓展CSD寄存器读取到了mmc的版本号信息,但是版本号大于5,就导致了程序错误并退出。问题的根节就在于我们用的mmc太新式,而这个U-boot并不认得太新潮的mmc……
  • 解决之道只有两种,要么换mmc,要么强行改代码。换mmc不现实,至于怎么改,因为太难,就只能上网查了。上网查了之后发现解决方法倒是很简单,直接把判断的数字5改为8,跳过这个错误即可。修改,上电,测试,发现确实解决了这个问题
  • 问题解决了,但还有一个问题,此处U-boot初始化的是接在通道0的inand还是接在通道1的SD卡呢?其实还是函数int mmc_initialize(bd_t *bis)初始化的时候 有一句代码:mmc = find_mmc_device(0); 所指定的,故此处初始化的不是SD而是inand,并且我们可以通过把0改成1来改为初始化SD卡

6.检查环境变量配置

  • 首先,在U-boot命令行下尝试环境变量的设置,设置后发现能断电保存,说明环境变量功能成功,但是我们还是要检查一下,环境变量存放的扇区是否安全,会不会和其他内容发生冲突
  • 关于环境变量分区的检查,以及默认环境变量的修改详见U-boot对启动介质的空间分配

7.检查网卡配置

根据U-boot打印信息可知,网卡初始化显然是失败的。由于网卡驱动是从linux驱动拿过来的,所以无需修改,只需要确保U-boot中网卡初始化成功即可。

  • 关于这个网卡,其实是通过s5pv210的SROM接口来直接挂载在总线上的,所谓的SROM接口其实是一种对外部开放总线的方式,通过这个接口,网卡芯片内的寄存器可以直接通过总线访问,对于程序员来说就仿佛在访问SOC内部的SFR,网卡芯片与SOC直接的通信过程就可以不用关心了。简而言之,这个网卡芯片就像集成在SOC内部一样。s5pv210的内存映射表有关SROM的部分:
    U-boot原厂版本移植流程_第15张图片

  • 接下来看看我们板子上网卡的具体接法:
    U-boot原厂版本移植流程_第16张图片
    首先,要清楚一点,dm9000的地址接口和数据接口是复用的!CMD接在了ADDR2(一根地址总线),当CMD为1时data0-data15传输的是数据,而当CMD为0时传输的是地址,也就是说,如果要访问dm9000的寄存器,data0-data15要先传输地址再传输数据。由接口data0-data15可知,SROM接口使用了16位宽度。由接口CSn1可知,网卡接了SROM的bank1的片选脚,所以网卡处在SROM的bank1。

  • 关于网卡的初始化,具体是在U-boot初始化第二阶段的board_init函数中,里面有调用网卡初始化函数(和SROM接口有关),我们板子上的网卡是dm9000,所以真正的初始化函数是dm9000_pre_init,我们需要检查
    1.初始化函数
    2.smdkv210single.h中网卡相关的宏定义
    具体修改需要根据网卡芯片的接法(SROM接口)来定,以x210为例,板载的是dm9000,先来看看原厂代码的初始化流程
    U-boot原厂版本移植流程_第17张图片
    上来先根据宏来配置SROM_BW_REG,查手册得知SROM_BW寄存器主要负责各个bank的数据总线的宽度设置,不同的位分别设置不同的bank,由于定义了宏DM9000_16BIT_DATA,故此寄存器配置为16位模式,并且配置的是bank5,byteenable位设置成0(不使用UB/LB),waitenable位设成0(禁止等待),addrmode设为0(半字对齐)。我们修改为bank1,此外,原厂的很多设置都是有问题的,必须修改为byteenable位设置成1(使用UB/LB),waitenable位设成1(使能等待),addrmode设为1(字节对齐),至于这些参数到底怎么选择,其实都是一些约定俗成的套路,特别是dm9000作为一款历史悠久的老芯片,很多设置的方法都已经固化了,通过网络可以很轻松查到。综上所述,我们把代码修改为:SROM_BW_REG &= ~(0xf << 4); SROM_BW_REG |= (0<<7) | (0<<6) | (0<<5) | (1<<4);
    随后原厂设置了SROM_BC5_REG,查手册得知SROM_BC*寄存器负责第*个bank的控制,寄存器的内容本身倒是不用改,只需把SROM_BC5_REG改为SROM_BC1_REG即可。
    最后原厂配置了MP01CON_REG这个寄存器,利用了临时变量tmp先读后改,这个寄存器其实就是配置了引脚MP01,原厂将其设为复用功能————SROM接口中的bank5片选引脚,而我们应将其改为bank1片选引脚,查询手册后,将其改为tmp &=~(0xf<<4); tmp |=(2<<4);

  • 接下来看看smdkv210single.h中相关宏定义:U-boot原厂版本移植流程_第18张图片
    由s5pv210的内存映射表可知,宏 CONFIG_DM9000_BASE将dm9000地址接口的基地址设置在了bank5(0xA8000000),我们应将其改为bank1,根据内存映射理论上是0x88000000但此处有坑,很玄学,居然有可能不工作,需要改成0x88000300才行,至于原因的话网上众说纷纭,一种比较合理的说法是:DM9000有不同的版本,其中有的内部自带0x300的偏移量…故只用bank的基地址是不行的,需要加上0x300。接下来看后面,DM9000_DATA(数据接口)的地址应改为CONFIG_DM9000_BASE+4,这是因为CMD接在了ADDR2(地址总线),当CMD为1时data0-data15传输的是数据,而当CMD为0时传输的是地址。修改后上电,测试,发现网卡成功运行,可以ping通主机

8.检查内核引导部分

  • 当前U-boot还无法启动内核,但是首先需要确定到底是U-boot的问题还是kernel的问题,如果手头存在着其他确定正确的U-boot或者kernel,那么就有可能排除掉一种情况。但是一般来说,手头是没有这个条件的,那么就需要多方位的去诊断

  • 首先,在U-boot命令行设置正确的环境变量bootcmd和bootargs,具体详见 U-boot引导内核流程分析 ,设置完发现无法启动

  • 接着,试试看使用tftp导入内核镜像至内存,发现仍然无法启动

  • 根据 U-boot引导内核流程分析 末尾的论述,我们来做基本的检测,首先怀疑机器码不对,此处要对比U-boot和kernel源码中的机器码,U-boot的部分在smdkv210single.h中的#define
    MACH_TYPE,对比kernel源码中的机器码发现相同,说明机器码没问题。再来看看和传参有关的宏是否正确定义,发现好像#define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_CMDLINE_TAG #define CONFIG_INITRD_TAG 这三个宏没有定义,定义完之后上电发现能够正常运行

    至此,整个移植过程正式结束,总体来说,原厂的U-boot需要修改的地方不是很多

你可能感兴趣的:(【U-boot开发】)