Linux-uboot-学习笔记(10):移植三星官方uboot

Linux-uboot-学习笔记(10):移植三星官方uboot

前言:当我们在使用某个板卡之前,首先要找到与它对应匹配的uboot,将uboot移植到板卡上,从而实现板卡的一系列启动。这里我们将三星官方开发板的SMDKV210的uboot源代码移植到S5PV210上,从而实现引到210启动各种外设和启动内核。

一、移植前的准备

当拿到源代码时,首先要在window下利用SourceInsight创建一个工程,并将uboot源代码加载到SI中,方便修改和查看函数调用。
项目->新项目->设置项目名、工程路径->选择整个uboot文件->添加树 项目->同步文件(全打钩)

接着要在linux下创建一份,因为配置和编译过程都需要在Linux下进行。将压缩包通过winshare复制到linux下,并在/root/porting_x210/uboot_samsung/下解压开,得到u-boot-samsung-dev。
在这里插入图片描述
这样做的目的是为了利用windows方便查找函数调用,并且方便修改。移植的时候是在windows中这一份中去看代码、改代码;在linux中这一份去编译烧写。这种做法需要在windows中和linux中2份代码之间保持同步(直白点说就是windows中改过了后要把改过的源代码复制到linux中那一份去覆盖linux中那一份里面的同目录同文件)。

二、移植过程

1、关闭PMIC

问题描述: 第一,串口无输出;第二,开发板供电锁存成功。
问题分析: uboot中串口最早的输出在"OK",在lowlevel_init.S中初始化串口时打印出来的;串口无输出"O"说明在打印"O"之前代码已经死掉了;开发板供电锁存在lowlevel_init.S中,开发板供电锁存成功说明这个代码之前的部分是没问题的。两个结合起来得到结论:错误在开发板供电锁存代码和串口初始化打印"O"代码之间。
在这里插入图片描述
解决方法: 将电源管理的宏关闭。
在这里插入图片描述
结果: 正常启动。

2、确认时钟设置

在这里插入图片描述
三星移植时已经把210常用的各种时钟配置全都计算好用宏开关来控制了。只要打开相应的宏开关就能将系统配置为各种不同的频率。

3、修改DDR配置

问题描述: 从运行信息以及bdinfo命令看到的结果,显示DRAM bank0和1的size值都设置错了。并且内存地址不连续,bank0是20000000,bank1是40000000。

问题分析: 使用md和mw命令测试内存,发现20000000和40000000开头的内存都是可以用的,说明代码中DDR初始化部分是正确的,只是size错了。而且DDR端口0的地址应该为30000000开头,这样两个bank0的地址就可以和bank1连接起来,从而得到地址连续的512MB内存。根据裸机中讲DDR初始化部分的课程,和uboot前面分析uboot中DDR初始化部分的代码的课程,得出结论就是:DDR的初始化代码部分是在lowlevel_init.S中写的,是不动的。代码部分就是对相应寄存器做相应值的初始化;要动的是值,而uboot为了具有可移植性把值都宏定义在include/configs/==smdkv210single.h中了。因此我们只需要去这个配置头文件中更改配置值即可。

解决方法:

(1)修改DDR的大小。
在这里插入图片描述
(2)修改每片DDR的起始位置(涉及到虚拟地址映射问题)。
在这里插入图片描述
(3)附加:修改两处打印信息:
在这里插入图片描述
(4)编写配置编译脚本,并烧录。
在这里插入图片描述
结果:
在这里插入图片描述

4、inand驱动解决

问题描述: 从运行信息来看,SD卡驱动和iNand驱动设置有误,SD卡打印出无法识别的版本信息,iNand打印出来0MB。
在这里插入图片描述

问题分析: 从打印出来的错误信息中挑选一个关键词EXT_CSD,然后去源代码中搜索这个关键字,通过这种搜索的方法定位问题。通过搜索将问题定位在drivers/mmc/mmc.c的818行。初步的解决方案是自己先浏览一遍这个问题点周边代码上下文。通过浏览代码上下文,发现这个函数是在读取SD/iNand的ext_csd寄存器的值。通过浏览代码结合出错地方,可以判断出:从卡端读取ext_csd寄存器是成功的,并且从读取结果中拿到了卡的版本号信息。然后代码对版本号进行了判断,并且如果版本号大于5就会报错并且函数错误退出。这就是问题所正。

解决方法: 修改uboot中的代码,把判断的5改成更大的数字。譬如8,然后跳过这个错误。
在这里插入图片描述
同时在cp.sh脚本中,将该文件所在位置添加进去。
在这里插入图片描述
结果: 卡初始化成功。我们这里SD0接的是iNand,SD2接的是SD卡,因此这里SD/MMC打印出来的是iNand的信息。
在这里插入图片描述

4、修改环境变量中的网络IP地址

问题描述: 通过在uboot中print打印出环境变量来看,IP地址信息是正确的,我们需要先破坏掉原始环境变量,并通过uboot将新的环境变量自动加载上去。

问题分析: 为什么启动后环境变量是对的?这是因为原来通过save将正确的环境变量保存到iNand中的ENV分区去了,uboot启动后校验时iNand的ENV分区中的环境变量是正确的,因此会优先加载。我们在uboot源代码中修改的只是默认的环境变量。解决方案是通过mmc write 0 30000000 11# 32(将DDR的0x30000000开头的一段内存中的内容写入iNand中的第17个扇区开始的32个扇区内,写入长度是32个扇区长度(16KB))擦除掉iNand中的那一份环境变量,然后迫使uboot启动时使用uboot代码中自带的默认的这一份环境变量,就可以看到了。

解决方法: 修改配置头文件smdkv210single.h中的CONFIG_IPADDR等宏,则可以修改uboot的默认环境变量。
在这里插入图片描述
结果: print打印出了正确信息,即uboot提供了正确的环境变量。
在这里插入图片描述

5、网卡驱动移植

首先简单介绍一下网卡驱动知识:

网卡芯片与开发板的连接方式
SoC的SROMController其实就是SoC提供的对外总线式连接SRAM/ROM的接口。如果SoC要外部外接一些SRAM/ROM类的存储芯片(或者伪装成SROM接口的芯片,譬如网卡芯片)就要通过SROM Controller来连接。网卡接在SROM中好处就是网卡芯片好像一个存储芯片一样被扩展在SoC的一个地址空间中,主机SoC可以直接用一个地址来访问网卡芯片内部寄存器

网卡芯片内部寄存器使用相对地址访问。网卡芯片内部很多寄存器有一个地址,这个地址是从00开始的,但是实际上我们SoC不能用0地址去访问这个网卡的芯片内部寄存器。SoC访问网卡芯片某个寄存器时的地址应该是:对应SROM bankn中的bankn对应的基地址+网卡寄存器相对于00的偏移量

主机SoC上网,其实就是通过操控网卡芯片内部的寄存器、缓冲区等资源来上网的。也就是说其实SoC是通过网卡芯片来间接上网的。实际上也是一种总线式连接方式。优势是SoC内部不需要内置网卡控制器,所有的SFR全都在外部网卡芯片中,而且还可以通过地址直接访问(IO与内存统一编址),不用像Nand/SD接口一样使用时序来访问。
在这里插入图片描述
210的SROM控制器允许8/16bit的接口,我们实际使用的是16位接口。
网线有8根线,但是实际只有4根有效通信线,另外4根都是GND,用来抗干扰的。4根通信线中管发送的有2根(Tx-和Tx+),管接收的有2根(Rx+和Rx-)。因为网线上传输的是差分信号
网卡芯片有个CS引脚,(CS就是chip select,片选信号,主机向CS发送有效信号则从机芯片工作,主机向CS发送无效信号则从机芯片不工作。),这个引脚要接主机SoC的片选信号引脚,主机S5PV210的每一个SROM bank中有一个片选信号CSn(n=0-5),从原理图可以看出,我们X210上将DM9000的CS引脚接到了CSn1上,对应SROM bank1(推断出DM9000的总线地址基地址是0x88000000)。
DM9000的CMD引脚接到了S5PV210的ADDR2引脚上。DM9000为了减少芯片引脚数,数据线和地址线是复用的(DATA0到DATA15这16根线是有时候做数据线传输数据,有时候做地址线传输地址的。什么时候做什么用就由CMD引脚决定。)通过查询数据手册知道:当CMD为高电平时对应传输是DATA,当CMD为低电平时对应传输为INDEX(offset,寄存器地址)。

问题描述: 修改三星工程师对于三星开发板SMDKV210的uboot,使其能够让网卡在我们的开发板上工作。

问题分析: uboot在第二阶段init_sequences中进行了一系列的初始化,其中就有网卡芯片的初始化。这个初始化就是关键,在这里的初始化中只要将网卡芯片正确的初始化了,则网卡芯片就能工作(意思是网卡驱动dm9000x.c和dm9000x.h依赖于这里的初始化而工作)。

解决方法: 找到对应初始化网卡部分,在dm9000_pre_init函数下,对应数据手册来修改网卡的初始化参数。
#define DM9000_16BIT_DATA这个宏用来表示DM9000工作在16位总线模式下。根据上节课的硬件原理图的分析,可以看到我们开发板上DM9000确实工作在16位模式下。
从三星版本的代码中可以看出,它操作的是bit20-bit23,对照数据手册中寄存器定义,可以看出三星的开发板DM9000是接在Bank5上的。而我们接在bank1上的,因此我们需要操作的bit位是bit4-bit7
在这里插入图片描述
CONFIG_DM9000_BASE是DM9000网卡通过SROM bank映射到SoC中地址空间中的地址。这个地址的值取决于硬件接到了哪个bank,这个bank的基地址是SoC自己定义好的。譬如我们这里接到了bank1上,bank1的基地址是0x88000000.
DM9000_IO表示访问芯片IO的基地址,直接就是CONFIG_DM9000_BASE;DM9000_DATA表示我们访问数据时的基地址,因为DM9000芯片的CMD引脚接到了ADDR2,因此这里要+4(0b100,对应ADDR2)。
通过调试发现CONFIG_DM9000_BASE改成0x88000300就工作了。这个0x300从哪里来的?我得出的感觉最靠谱的解释是:跟DM9000网卡芯片型号版本有关,我认为这个0x300是DM9000网卡本身的问题,他本身的内部寄存器就有一个0x300的一个偏移量。
在这里插入图片描述
结果: 通过ping虚拟机ubuntu和主机,发现都能ping通,证明网卡驱动工作正常。
在这里插入图片描述

补充:网卡驱动如何工作
在linux系统中,网卡算是一个设备,这个设备驱动工作后会生成一个设备名叫ethn(n是0、1、2、····)(无线网卡名字一般叫wlan0、wlan1····)。然后linux系统用一些专用命令来操作网卡,譬如ifconfig命令。
linux下的应用程序如何使用网卡驱动来进行网络通信?最通用的方法就是socket接口。linux系统中有一系列的API和库函数,提供了一个socket编程接口,linux下的应用程序都是通过socket来实现上网的,socket内部就是间接调用的网卡驱动实现网络通信的。

linux设计是非常完备的,应用层和驱动层是严格分离的。也就是说写网络编程应用层的人根本不用管驱动,只要会用socket接口即可;写底层驱动的人根本不用管应用层,只要面向linux的网络驱动框架模型即可。
然而在uboot中没有分层。按照逻辑来说,ping这样的命令实现的代码就是网络应用的应用程序,像dm9000x.c和dm9000x.h这样的代码属于驱动程序。所以在uboot中这些东西是揉在一起的,应用是直接调用驱动实现的。也就是说ping命令内部是直接调用了dm9000的网卡驱动中的函数来实现自己的。

6、启动内核

问题描述: 将内核镜像通过tftp加载到DDR的30008000位置(tftp 30008000 zImage-qt),而在启动内核时(bootm 0x30008000),发现内核无法启动。

问题分析: 做基本检查:首先怀疑是机器码不对。经过和九鼎移植版本的uboot对比发现machid都是2456,说明机器码没错。如何内核没有启动,是smdkv210single.h中没有定义bootm传参需要的那几个宏造成的。
在这里插入图片描述

解决方法: 查看.h文件中是否有那几个宏。
结果: 成功启动内核。

在这里插入图片描述

发布了75 篇原创文章 · 获赞 99 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_42826337/article/details/105191989