移植u-boot到树莓派

u-boot:官网下载的u-boot-2014.4(ftp://ftp.denx.de/pub/u-boot/
单板:树莓派b

1、 添加自己的单板
首先解压uboot源码,进入根目录,在帮助文档README中有如何添加单板的说明:

If the system board that you have is not listed, then you will need
to port U-Boot to your hardware platform. To do this, follow these
steps:

  1. Add a new configuration option for your board to the toplevel
    “boards.cfg” file, using the existing entries as examples.
    Follow the instructions there to keep the boards in order.
  2. Create a new directory to hold your board specific code. Add any
    files you need. In your board directory, you will need at least
    the “Makefile”, a “.c”, “flash.c” and “u-boot.lds”.
  3. Create a new configuration file “include/configs/.h” for
    your board
  4. If you’re porting U-Boot to a new CPU, then also create a new
    directory to hold your CPU specific code. Add any files you need.
  5. Run “make _config” with your new name.
  6. Type “make”, and you should get a working “u-boot.srec” file
    to be installed on your target system.
  7. Debug and solve any problems that might arise.
    [Of course, this last step is much harder than it sounds.]

1)首先在顶层目录下的boards.cfg文件中添加树莓派单板的配置信息,我这里仿造rpi_b:

Status,Arch,CPU:SPLCPU,SoC,Vendor,Board name,Target,Options, Maintainers

Active arm arm1176 bcm2835 raspberrypi rpi_zy rpi_zy - zhangyi

这里从左到右分别表示:
Status : 配置使能状态
Arch:体系架构
CPU:SPLCPU:CPU名称
SoC:SOC芯片名称
Vendor:厂商
Board name:单板名称
Target:配置目标
Options:选项
Maintainers:维护者

2)在顶层board创建一个用于存储单板相关代码文件的目录,这里我直接拷贝board/raspberrypi/rpi_b 目录然后修改里面的文件名和Makefile文件:

$ cp -r /board/raspberrypi/rpi_b  /board/raspberrypi/rpi_b     
$ mv /board/raspberrypi/rpi_b/rpi_b.c  

/board/raspberrypi/rpi_b/rpi_zy.c
然后修改Makefile文件:
- - - obj-y := rpi_b.o
+++ obj-y := rpi_zy.o
3)为自己的单板创建配置文件include/configs/xxxx.h, 我这里也是直接拷贝rpi_b的配置文件:
cp include/configs/rpi_b.h include/configs/rpi_zy.h
4)精简使用不到的uboot源码结构:
(1)在arch目录下只保留arm目录:

[apple@apple u-boot-2014.04]$ cd arch/
[apple@apple arch]$ ls
arm

(2)在arch/arm/目录下只保留如下内容:

[apple@apple arch]$ cd arm/
[apple@apple arm]$ ls
config.mk  cpu  dts  imx-common  include  lib

(3)在arch/arm/cpu目录下只保留如下内容:

[apple@apple arm]$ cd cpu/
[apple@apple cpu]$ ls
arm1176  built-in.o  Makefile  u-boot.lds  u-boot-spl.lds

(4)在arch/arm/include/asm目录下以arch开头的只保留arch-bcm2835
(5)u-boot-2014.04/board 目录下只保留raspberrypi:

[apple@apple u-boot-2014.04]$ cd board
[apple@apple board]$ ls
raspberrypi

(6)u-boot-2014.04/board/raspberrypi目录下只保留rpi_zy:

[apple@apple board]$ cd raspberrypi/
[apple@apple raspberrypi]$ ls
rpi_zy

(7)u-boot-2014.04/include/configs 目录下只保留rpi_zy.h

[apple@apple u-boot-2014.04]$ cd include/configs/
[apple@apple configs]$ ls
rpi_zy.h     

5)修改顶层Makefile文件,添加交叉编译器支持:

318 # Make variables (CC, etc...)
319 CROSS_COMPILE = arm-linux-gnueabihf-
320 AS      = $(CROSS_COMPILE)as
321 # Always use GNU ld

6) 在顶层目录下编写简单的编译脚本文件,执行编译工作:

#!/bin/sh

make distclean
make rpi_zy_config
make all

运行该脚本文件即可在uboot根目录下生成u-boot.bin二进制文件。
7) 安装与运行
将编译出来的u-boot.bin拷贝到SD卡的FAT分区下,然后修改config.txt文件,添加(或修改)以下配置项:

kernel=u-boot.bin

同时需要保证SD卡FAT分区中包含以下文件:bootcode.bin、config.txt、start.elf和u-boot.bin(这些文件的作用见《树莓派的启动引导方式》)。
上电启动,uboot正常启动并能够在终端打印信息。
这里写图片描述
但是此时的uboot尚不能正常读写SD卡、USB和Ethernet(树莓派的Ethernet网络芯片是基于USB的)。

2、 修改并支持SD卡读写
参见http://people.freebsd.org/~gonzo/arm/patches/u-boot-pi-sdhci-hs-workaround.diff
修改drivers/mmc/bcm2835_sdhci.c的182行:
添加SDHCI_QUIRK_NO_HISPD_BIT

181 host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_NO_HISPD_BIT;

修改完成后,该uboot即可正常读写树莓派的SD卡。
例如:读取存放在SD卡FAT分区中的uImage文件到ram中的loadaddr位置处。
这里写图片描述

3、 移植USB-HOST和USB-Ethernet驱动
源文件:https://github.com/gonzoua/u-boot-pi/tree/rpi
这里GitHub上的uboot是国外开发者基于2013.01-rc1版本修改的,并且支持usb和Ethernet。
uboot中usb-host和usb-ethernet的驱动在u-boot-pi-rpi/drivers/usb/eth和u-boot-pi-rpi/drivers/usb/host目录下,树莓派相关的是dwc_otg-hcd.c、dwc_otg.c、dwc_otg_regs.h、dwc_otg_core_if.h和dwc_otg.h这几个host驱动文件以及smsc95xx.c的Ethernet驱动文件。
其中smsc95xx.c在2014.4版的uboot中已经存在了,并且和u-boot-pi-rpi中的并无太大不同,所以主要的工作就在移植usb-host驱动和配置uboot添加usb和ethernet相关的commond。

1)首先将dwc_otg-hcd.c、dwc_otg.c、dwc_otg_regs.h、dwc_otg_core_if.h和dwc_otg.h这几个文件拷贝到u-boot-2014.04/drivers/usb/host目录下,同时修改Makefile:

    [apple@apple host]$ cp dwc* ~/raspberry/build/u-boot-2014.04/drivers/usb/host
    [apple@apple host]$ vim ~/raspberry/build/u-boot-2014.04/drivers/usb/host/Makefile

+++ obj-$(CONFIG_USB_DWC_OTG) += dwc_otg.o dwc_otg-hcd.o

2)修改u-boot-2014.04/include/configs/rpi_zy.h,修改如下:

+++ /* USB Networking options */
+++ #define CONFIG_USB_HOST_ETHER
+++ #define CONFIG_USB_ETHER_SMSC95XX
+++ #define CONFIG_USB_DWC_OTG
+++ #define CONFIG_USB_STORAGE

+++ #define CONFIG_CMD_USB
+++ #define CONFIG_CMD_NET
+++ #define CONFIG_CMD_PING
+++ #define CONFIG_CMD_DHCP

--- #undef CONFIG_CMD_NET
--- #undef CONFIG_CMD_DHCP
--- #undef CONFIG_CMD_NET
--- #undef CONFIG_CMD_PING

3)修改完成后,重新编译并运行
这里有遇到一个问题,在执行usb start时,当uboot检测到ethernet时会出现failed to set MAC address的WARNING,当然后续也无法使用了。
这里写图片描述
通过比较2分smsc95xx.c文件,发现在获取Mac地址的smsc95xx_init_mac_address函数中,会尝试调用smsc95xx_read_eeprom函数从eeprom中获取MAC地址。

287 static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length,
288             u8 *data)
289 {
290     u32 val;
291     int i, ret;
292
293     ret = smsc95xx_eeprom_confirm_not_busy(dev);
294     if (ret)
295         return ret;
296
297     for (i = 0; i < length; i++) {
298         val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
299         smsc95xx_write_reg(dev, E2P_CMD, val);
300
301         ret = smsc95xx_wait_eeprom(dev);
302         if (ret < 0)
303             return ret;
304
305         smsc95xx_read_reg(dev, E2P_DATA, &val);
306         data[i] = val & 0xFF;
307         offset++;
308     }
309     return 0;
400 }

其中在smsc95xx_eeprom_confirm_not_busy函数中增加了如下代码片段:

257     do {
258         smsc95xx_read_reg(dev, E2P_CMD, &val);
259 +++     if (!(val & E2P_CMD_LOADED_)) {
260 +++         debug("No EEPROM present\n");
261 +++         return -1;
262 +++     }

如果smsc95xx_read_reg发现不存在EEPROM,则直接返回失败,同时为了安全起见不会随机生成MAC地址。
将以上代码移植到2014.04的代码段中,同时打开uboot的debug模式,就会打印出No EEPROM present,显然uboot无法从EEPROM中获取到Mac地址,因为在树莓派的9512芯片上并没有接EEPROM。
这里写图片描述
解决方式是手动添加环境变量usbethaddr,同时在uboot的preboot命令为:

#define CONFIG_PREBOOT \
    "if load mmc 0:1 ${loadaddr} /uEnv.txt; then " \
        "env import -t ${loadaddr} ${filesize}; " \
    "fi"

在uboot启动main loop前会执行这条命令从uEnv.txt文件中倒入环境变量,所以在SD卡的FAT分区中添加uEnv.txt文件,同时向里面写入:

usbethaddr=b8:27:eb:b7:b5:2e
ipaddr=192.168.1.25
serverip=192.168.1.17

问题解决,重新运行后打印输出如下:
这里写图片描述

参考文献:
1、《嵌入式Linux学习笔记(基于S5PV210、TQ210).pdf》
2、http://blog.sina.com.cn/s/blog_7cedb56d0102uzye.html
3、http://my.oschina.net/funnky/blog/141982?p=1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章