移植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

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