日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

U-Boot 移植

發(fā)布時間:2023/12/10 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 U-Boot 移植 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

  • NXP官方開發(fā)板uboot編譯測試
    • 查找NXP官方的開發(fā)板默認配置文件_defconfig
    • 配置編譯NXP官方開發(fā)板對應的uboot
    • 燒寫驗證與驅(qū)動測試(定位缺少的驅(qū)動)
  • 在NXP官方U-Boot 中添加自己的開發(fā)板
    • 添加開發(fā)板默認配置文件
    • 添加開發(fā)板對應的頭文件(mx6ull_alientek_emmc.h)
    • 添加開發(fā)板對應的板級文件夾
    • 修改U-Boot 圖形界面配置文件
    • 使用新添加的板子配置編譯uboot
    • LCD驅(qū)動修改
    • 網(wǎng)絡驅(qū)動修改
    • 其他需要修改的地方
  • bootcmd和bootargs環(huán)境變量(修改mx6ull_alientek_emmc.h)
    • 環(huán)境變量bootcmd(啟動內(nèi)核命令)
    • 環(huán)境變量bootargs(內(nèi)核傳參)
  • uboot 啟動Linux 測試
    • 從EMMC 啟動Linux 系統(tǒng)
    • 從網(wǎng)絡啟動Linux 系統(tǒng)
  • DDR初始化參數(shù)修改
  • 總結(jié)

上一章節(jié)我們詳細的分析了uboot 的啟動流程,對uboot 有了一個初步的了解。

前兩章我們都是使用的正點原子提供的uboot,本章我們就來學習如何將NXP 官方的uboot 移植到正點原子的I.MX6ULL 開發(fā)板上,學習如何在uboot 中添加我們自己的板子。

NXP官方開發(fā)板uboot編譯測試

查找NXP官方的開發(fā)板默認配置文件_defconfig

uboot 的移植并不是說我們完完全全的從零開始將uboot 移植到我們現(xiàn)在所使用的開發(fā)板或者開發(fā)平臺上,這個工作一般是半導體廠商做的,半導體廠商負責將uboot 移植到他們的芯片上,因此半導體廠商都會自己做一個開發(fā)板,這個開發(fā)板就叫做原廠開發(fā)板,比如大家學習STM32 的時候聽說過的discover 開發(fā)板就是ST 自己做的。

半導體廠商會將uboot 移植到他們自己的原廠開發(fā)板上,測試好以后就會將這個uboot 發(fā)布出去,這就是大家常說的原廠BSP 包。我們一般做產(chǎn)品的時候就會參考原廠的開發(fā)板做硬件,然后在原廠提供的BSP 包上做修改,將uboot 或者linux kernel 移植到我們的硬件上。這個就是uboot 移植的一般流程:

①、在uboot 中找到參考的開發(fā)平臺,一般是原廠的開發(fā)板。
②、參考原廠開發(fā)板移植uboot 到我們所使用的開發(fā)板上。

正點原子的I.MX6ULL 開發(fā)板參考的是NXP 官方的I.MX6ULL EVK 開發(fā)板做的硬件,因此我們在移植uboot 的時候就可以以NXP 官方的I.MX6ULL EVK 開發(fā)板為藍本。

本章我們是將NXP 官方的uboot 移植到正點原子的I.MX6ULL 開發(fā)板上,NXP 官方的uboot 放到了開發(fā)板光盤中,路徑為:1、例程源碼->4、NXP 官方原版Uboot 和Linux->uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2。將uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2 發(fā)送到Ubuntu中并解壓,然后創(chuàng)建VSCode 工程。

configs 目錄下有很多跟I.MX6UL/6ULL 有關的配置如圖33.1.1.1 所示,

從圖33.1.1.1 可以看出有很多的默認配置文件,其中以mx6ul 開頭的是I.MX6UL 芯片的,mx6ull 開頭的是I.MX6ULL 開發(fā)板的。I.MX6UL/6ULL 有9x9mm 和14x14mm 兩種尺寸的,所以我們可以看到會有mx6ull_9x9 和mx6ull_14x14 開頭的默認配置文件。

我們使用的是14x14mm的芯片,所以關注mx6ull_14x14 開頭的默認配置文件。正點原子的I.MX6ULL 有EMMC 和NAND 兩個版本的,因此我們最終只需要關注mx6ull_14x14_evk_emmc_defconfig 和
mx6ull_14x14_evk_nand_defconfig 這兩個配置文件就行了。本章我們講解EMMC 版本的移植(NAND 版本移植很多類似),所以使用mx6ull_14x14_evk_emmc_defconfig 作為默認配置文件。

配置編譯NXP官方開發(fā)板對應的uboot

找到NXP 官方I.MX6ULL EVK 開發(fā)板對應的默認配置文件以后就可以配置和編譯了,使用如下命令配置uboot:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig

配置完成會生成.config文件,然后進行編譯

make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

編譯完成以后結(jié)果如圖33.1.2.1 所示,官方提供的uboot就編譯成功了。

修改Makefile文件簡化操作:

從圖33.1.2.1 可以看出,編譯成功。我們在編譯的時候需要輸入ARCH 和CORSS_COMPILE這兩個變量的值,這樣太麻煩了。我們可以直接在頂層Makefile 中直接給ARCH 和CORSS_COMPILE 賦值,修改如圖33.1.2.2 所示(視頻里命令多一個問號):

圖33.1.2.2 中的250、251 行就是直接給ARCH 和CROSS_COMPILE 賦值,這樣我們就可以使用如下簡短的命令來編譯uboot 了:

make mx6ull_14x14_evk_emmc_defconfig make V=1 -j16

創(chuàng)建shell腳本簡化操作:

如果既不想修改uboot 的頂層Makefile,又想編譯的時候不用輸入那么多,那么就直接創(chuàng)建個shell 腳本就行了,shell 腳本名為mx6ull_14x14_emmc.sh,然后在shell 腳本里面輸入如下內(nèi)容:

#!/bin/bash make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

記得給mx6ull_14x14_emmc.sh 這個文件可執(zhí)行權(quán)限,使用mx6ull_14x14_emmc.sh 腳本編譯uboot 的時候每次都會清理一下工程,然后全部重新編譯,編譯的時候直接執(zhí)行這個腳本就行了,命令如下:

./mx6ull_14x14_evk_emmc.sh

編譯完成以后會生成u-boot.bin、u-boot.imx 等文件,但是這些文件是NXP 官方I.MX6ULL EVK 開發(fā)板。能不能用到正點原子的I.MX6ULL 開發(fā)板上呢?試一下不就知道了!

燒寫驗證與驅(qū)動測試(定位缺少的驅(qū)動)

將imxdownload 軟件拷貝到uboot 源碼根目錄下,然后使用imxdownload 軟件將u-boot.bin燒寫到SD卡中(和前面的裸機一樣),燒寫命令如下:

chmod 777 imxdownload //給予imxdownload 可執(zhí)行權(quán)限 ./imxdownload u-boot.bin /dev/sdd //燒寫到SD 卡中,不能燒寫到/dev/sda 或sda1 里面

燒寫完成以后將SD 卡插入I.MX6U-ALPHA 開發(fā)板的TF卡槽中,最后設置開發(fā)板從SD卡啟動。打開SecureCRT,設置好開發(fā)板所使用的串口并打開,復位開發(fā)板,SecureCRT 接收到如下圖33.1.3.1 所示信息:

從圖33.1.3.1 可以看出,uboot 啟動正常,雖然我們用的是NXP 官方I.MX6ULL 開發(fā)板的uboot,但是在正點原子的I.MX6ULL 開發(fā)板上是可以正常啟動的。而且DRAM 識別正確,為512MB,
注意:如果用的NAND 版本的核心版的話uboot 啟動會失敗!因為NAND 核心版用的256MB的DRAM。

1、SD 卡和EMMC 驅(qū)動檢查

檢查一下SD 卡和EMMC 驅(qū)動是否正常,使用命令mmc list 列出當前的MMC 設備,結(jié)果如圖33.1.3.2 所示:

從圖33.1.3.2 可以看出當前有兩個MMC 設備,檢查每個MMC 設備信息,先檢查MMC 設備0,輸入如下命令:

mmc dev 0 mmc info

結(jié)果如圖33.1.3.3 所示:

從圖33.1.3.3 可以看出,mmc 設備0 是SD 卡,SD 卡容量為14.8GB,這個和我所使用的SD 卡信息相符,說明SD 卡驅(qū)動正常。再來檢查MMC 設備1,輸入如下命令:

mmc dev 1 mmc info

結(jié)果如圖33.1.3.4 所示:

從圖33.1.3.4 可以看出,mmc 設備1 為EMMC,容量為3.6GB,說明EMMC 驅(qū)動也成功,SD 卡和EMMC 的驅(qū)動都沒問題。

2、LCD 驅(qū)動檢查

如果uboot 中的LCD 驅(qū)動正確的話,啟動uboot 以后LCD 上應該會顯示出NXP 的logo,如下圖33.1.3.5 所示:

如果你用的不是正點原子的4.3 寸480x272 分辨率的屏幕的話,那么LCD 就不會顯示33.1.3.5 所示logo 界面。因為NXP 官方I.MX6ULL 開發(fā)板的屏幕就是4.3 寸480x272 分辨率的,所以uboot 默認LCD 驅(qū)動是4.3 寸480x272 分辨率的。如果使用其他分辨率的LCD 就需要修改LCD 驅(qū)動,這里我們先不修改LCD 驅(qū)動,稍后我們在講解如何修改uboot 中的LCD驅(qū)動,我們只需要記得,uboot 的LCD 需要修改就行了。

3、網(wǎng)絡驅(qū)動

uboot 啟動的時候提示“Board Net Initialization Failed”和“No ethernet found.”這兩行,說明網(wǎng)絡驅(qū)動也有問題,正常情況下應該是如圖33.1.3.6 所示提示:

現(xiàn)在沒有圖33.1.3.6 中的信息,那更別說ping 一下ubuntu 主機了,說明當前uboot 的網(wǎng)絡部驅(qū)動也是有問題的,這是因為正點原子開發(fā)板的網(wǎng)絡芯片復位引腳和NXP 官方開發(fā)板不一樣,因此需要修改驅(qū)動。

總結(jié)一下NXP 官方I.MX6ULL EVK 開發(fā)板的ubootx在正點原子EMMC版本I.MX6ULL開發(fā)板上的運行情況:

  • ①、uboot 啟動正常,DRAM 識別正確,SD 卡和EMMC 驅(qū)動正常。
  • ②、uboot 里面的LCD 驅(qū)動默認是給4.3 寸480x272 分辨率的,如果使用的其他分辨率的屏幕需要修改驅(qū)動。
  • ③、網(wǎng)絡不能工作,識別不出來網(wǎng)絡信息,需要修改驅(qū)動。

接下來我們要做的工作如下:

  • ①、前面我們一直使用著NXP 官方開發(fā)板的uboot 配置,接下來需要在uboot 中添加我們自己的開發(fā)板,也就是正點原子的I.MX6ULL 開發(fā)板。
  • ②、解決LCD 驅(qū)動和網(wǎng)絡驅(qū)動的問題。

在NXP官方U-Boot 中添加自己的開發(fā)板

NXP 官方uboot 中默認都是NXP 自己的開發(fā)板,雖說我們可以直接在官方的開發(fā)板上直接修改,使uboot 可以完整的運行在我們的板子上。但是從學習的角度來講,這樣我們就不能了解到uboot 是如何添加新平臺的。接下來我們就參考NXP 官方的I.MX6ULL EVK 開發(fā)板,學習如何在uboot 中添加我們的開發(fā)板或者開發(fā)平臺。

添加開發(fā)板默認配置文件

先在configs 目錄下創(chuàng)建默認配置文件,復制mx6ull_14x14_evk_emmc_defconfig,然后重
命名為mx6ull_alientek_emmc_defconfig,命令如下:

cd configs cp mx6ull_14x14_evk_emmc_defconfig mx6ull_alientek_emmc_defconfig

然后將文件mx6ull_alientek_emmc_defconfig 中的內(nèi)容改成下面的:

CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK" CONFIG_ARM=y CONFIG_ARCH_MX6=y CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y CONFIG_CMD_GPIO=y

可以看出,mx6ull_alientek_emmc_defconfig 基本和mx6ull_14x14_evk_emmc_defconfig 中的內(nèi)容一樣,只是第1 行和第4 行做了修改(改成正點原子ALIENTEK板子自己定義的名字)。

添加開發(fā)板對應的頭文件(mx6ull_alientek_emmc.h)

前面講的_defconfig配置文件的配置項很少,就5行,配置的還不夠,重點是mx6ull_alientek_emmc.h里面對應的配置文件。每一個板子都有一個這樣對應的 .h和 .c 配置文件。

在目錄include/configs 下添加I.MX6ULL-ALPHA 開發(fā)板對應的頭文件,復制
include/configs/mx6ullevk.h,并重命名為mx6ull_alientek_emmc.h,命令如下:

cp include/configs/mx6ullevk.h mx6ull_alientek_emmc.h

拷貝完成以后將:

#ifndef __MX6ULLEVK_CONFIG_H #define __MX6ULLEVK_CONFIG_H

改為:

#ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H #define __MX6ULL_ALIENTEK_EMMC_CONFIG_H

mx6ull_alientek_emmc.h 里面有很多宏定義,這些宏定義基本用于配置uboot,也有一些I.MX6ULL 的配置項目。如果我們自己要想使能或者禁止uboot 的某些功能,那就在mx6ull_alientek_emmc.h 里面做修改即可。mx6ull_alientek_emmc.h 里面的內(nèi)容比較多,去掉一些用不到的配置,精簡后的內(nèi)容如下:

1 /* 2 * Copyright (C) 2016 Freescale Semiconductor, Inc. 3 * 4 * Configuration settings for the Freescale i.MX6UL 14x14 EVK board. 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 #ifndef __MX6ULL_ALEITENK_EMMC_CONFIG_H 9 #define __MX6ULL_ALEITENK_EMMC_CONFIG_H 10 11 12 #include <asm/arch/imx-regs.h> 13 #include <linux/sizes.h> 14 #include "mx6_common.h" 15 #include <asm/imx-common/gpio.h> 16 ...... 28 29 #define is_mx6ull_9x9_evk() CONFIG_IS_ENABLED(TARGET_MX6ULL_9X9_EVK) 30 31 #ifdef CONFIG_TARGET_MX6ULL_9X9_EVK 32 #define PHYS_SDRAM_SIZE SZ_256M 33 #define CONFIG_BOOTARGS_CMA_SIZE "cma=96M " 34 #else 35 #define PHYS_SDRAM_SIZE SZ_512M 36 #define CONFIG_BOOTARGS_CMA_SIZE "" 37 /* DCDC used on 14x14 EVK, no PMIC */ 38 #undef CONFIG_LDO_BYPASS_CHECK 39 #endif 40 41 /* SPL options */ 42 /* We default not support SPL 43 * #define CONFIG_SPL_LIBCOMMON_SUPPORT 44 * #define CONFIG_SPL_MMC_SUPPORT 45 * #include "imx6_spl.h" 46 */ 47 48 #define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 49 50 #define CONFIG_DISPLAY_CPUINFO 51 #define CONFIG_DISPLAY_BOARDINFO 52 53 /* Size of malloc() pool */ 54 #define CONFIG_SYS_MALLOC_LEN (16 * SZ_1M) 55 56 #define CONFIG_BOARD_EARLY_INIT_F 57 #define CONFIG_BOARD_LATE_INIT 58 59 #define CONFIG_MXC_UART 60 #define CONFIG_MXC_UART_BASE UART1_BASE 61 62 /* MMC Configs */ 63 #ifdef CONFIG_FSL_USDHC 64 #define CONFIG_SYS_FSL_ESDHC_ADDR USDHC2_BASE_ADDR 65 66 /* NAND pin conflicts with usdhc2 */ 67 #ifdef CONFIG_SYS_USE_NAND 68 #define CONFIG_SYS_FSL_USDHC_NUM 1 69 #else 70 #define CONFIG_SYS_FSL_USDHC_NUM 2 71 #endif 72 #endif 73 74 /* I2C configs */ 75 #define CONFIG_CMD_I2C 76 #ifdef CONFIG_CMD_I2C 77 #define CONFIG_SYS_I2C 78 #define CONFIG_SYS_I2C_MXC 79 #define CONFIG_SYS_I2C_MXC_I2C1 /* enable I2C bus 1 */ 80 #define CONFIG_SYS_I2C_MXC_I2C2 /* enable I2C bus 2 */ 81 #define CONFIG_SYS_I2C_SPEED 100000 82 ...... 89 90 #define CONFIG_SYS_MMC_IMG_LOAD_PART 1 91 92 #ifdef CONFIG_SYS_BOOT_NAND 93 #define CONFIG_MFG_NAND_PARTITION "mtdparts=gpmi-nand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs) " 94 #else 95 #define CONFIG_MFG_NAND_PARTITION "" 96 #endif 97 98 #define CONFIG_MFG_ENV_SETTINGS \ 99 "mfgtool_args=setenv bootargs console=${console},${baudrate} " \ ...... 111 "bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr} ${fdt_addr};\0" \ 112 113 #if defined(CONFIG_SYS_BOOT_NAND) 114 #define CONFIG_EXTRA_ENV_SETTINGS \ 115 CONFIG_MFG_ENV_SETTINGS \ 116 "panel=TFT43AB\0" \ ...... 126 "bootz ${loadaddr} - ${fdt_addr}\0" 127 128 #else 129 #define CONFIG_EXTRA_ENV_SETTINGS \ 130 CONFIG_MFG_ENV_SETTINGS \ 131 "script=boot.scr\0" \ ...... 202 "fi;\0" \ 203 204 #define CONFIG_BOOTCOMMAND \ 205 "run findfdt;" \ ...... 216 "else run netboot; fi" 217 #endif 218 219 /* Miscellaneous configurable options */ 220 #define CONFIG_CMD_MEMTEST 221 #define CONFIG_SYS_MEMTEST_START 0x80000000 222 #define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + 0x8000000) 223 224 #define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR 225 #define CONFIG_SYS_HZ 1000 226 227 #define CONFIG_STACKSIZE SZ_128K 228 229 /* Physical Memory Map */ 230 #define CONFIG_NR_DRAM_BANKS 1 231 #define PHYS_SDRAM MMDC0_ARB_BASE_ADDR 232 233 #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM 234 #define CONFIG_SYS_INIT_RAM_ADDR IRAM_BASE_ADDR 235 #define CONFIG_SYS_INIT_RAM_SIZE IRAM_SIZE 236 237 #define CONFIG_SYS_INIT_SP_OFFSET \ 238 (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) 239 #define CONFIG_SYS_INIT_SP_ADDR \ 240 (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET) 241 242 /* FLASH and environment organization */ 243 #define CONFIG_SYS_NO_FLASH 244 ...... 255 256 #define CONFIG_SYS_MMC_ENV_DEV 1 /* USDHC2 */ 257 #define CONFIG_SYS_MMC_ENV_PART 0 /* user area */ 258 #define CONFIG_MMCROOT "/dev/mmcblk1p2" /* USDHC2 */ 259 260 #define CONFIG_CMD_BMODE 261 ...... 275 276 /* NAND stuff */ 277 #ifdef CONFIG_SYS_USE_NAND 278 #define CONFIG_CMD_NAND 279 #define CONFIG_CMD_NAND_TRIMFFS 280 281 #define CONFIG_NAND_MXS 282 #define CONFIG_SYS_MAX_NAND_DEVICE 1 283 #define CONFIG_SYS_NAND_BASE 0x40000000 284 #define CONFIG_SYS_NAND_5_ADDR_CYCLE 285 #define CONFIG_SYS_NAND_ONFI_DETECTION 286 287 /* DMA stuff, needed for GPMI/MXS NAND support */ 288 #define CONFIG_APBH_DMA 289 #define CONFIG_APBH_DMA_BURST 290 #define CONFIG_APBH_DMA_BURST8 291 #endif 292 293 #define CONFIG_ENV_SIZE SZ_8K 294 #if defined(CONFIG_ENV_IS_IN_MMC) 295 #define CONFIG_ENV_OFFSET (12 * SZ_64K) 296 #elif defined(CONFIG_ENV_IS_IN_SPI_FLASH) 297 #define CONFIG_ENV_OFFSET (768 * 1024) 298 #define CONFIG_ENV_SECT_SIZE (64 * 1024) 299 #define CONFIG_ENV_SPI_BUS CONFIG_SF_DEFAULT_BUS 300 #define CONFIG_ENV_SPI_CS CONFIG_SF_DEFAULT_CS 301 #define CONFIG_ENV_SPI_MODE CONFIG_SF_DEFAULT_MODE 302 #define CONFIG_ENV_SPI_MAX_HZ CONFIG_SF_DEFAULT_SPEED 303 #elif defined(CONFIG_ENV_IS_IN_NAND) 304 #undef CONFIG_ENV_SIZE 305 #define CONFIG_ENV_OFFSET (60 << 20) 306 #define CONFIG_ENV_SECT_SIZE (128 << 10) 307 #define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE 308 #endif 309 310 311 /* USB Configs */ 312 #define CONFIG_CMD_USB 313 #ifdef CONFIG_CMD_USB 314 #define CONFIG_USB_EHCI 315 #define CONFIG_USB_EHCI_MX6 316 #define CONFIG_USB_STORAGE 317 #define CONFIG_EHCI_HCD_INIT_AFTER_RESET 318 #define CONFIG_USB_HOST_ETHER 319 #define CONFIG_USB_ETHER_ASIX 320 #define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW) 321 #define CONFIG_MXC_USB_FLAGS 0 322 #define CONFIG_USB_MAX_CONTROLLER_COUNT 2 323 #endif 324 325 #ifdef CONFIG_CMD_NET 326 #define CONFIG_CMD_PING 327 #define CONFIG_CMD_DHCP 328 #define CONFIG_CMD_MII 329 #define CONFIG_FEC_MXC 330 #define CONFIG_MII 331 #define CONFIG_FEC_ENET_DEV 1 332 333 #if (CONFIG_FEC_ENET_DEV == 0) 334 #define IMX_FEC_BASE ENET_BASE_ADDR 335 #define CONFIG_FEC_MXC_PHYADDR 0x2 336 #define CONFIG_FEC_XCV_TYPE RMII 337 #elif (CONFIG_FEC_ENET_DEV == 1) 338 #define IMX_FEC_BASE ENET2_BASE_ADDR 339 #define CONFIG_FEC_MXC_PHYADDR 0x1 340 #define CONFIG_FEC_XCV_TYPE RMII 341 #endif 342 #define CONFIG_ETHPRIME "FEC" 343 344 #define CONFIG_PHYLIB 345 #define CONFIG_PHY_MICREL 346 #endif 347 348 #define CONFIG_IMX_THERMAL 349 350 #ifndef CONFIG_SPL_BUILD 351 #define CONFIG_VIDEO 352 #ifdef CONFIG_VIDEO 353 #define CONFIG_CFB_CONSOLE 354 #define CONFIG_VIDEO_MXS 355 #define CONFIG_VIDEO_LOGO 356 #define CONFIG_VIDEO_SW_CURSOR 357 #define CONFIG_VGA_AS_SINGLE_DEVICE 358 #define CONFIG_SYS_CONSOLE_IS_IN_ENV 359 #define CONFIG_SPLASH_SCREEN 360 #define CONFIG_SPLASH_SCREEN_ALIGN 361 #define CONFIG_CMD_BMP 362 #define CONFIG_BMP_16BPP 363 #define CONFIG_VIDEO_BMP_RLE8 364 #define CONFIG_VIDEO_BMP_LOGO 365 #define CONFIG_IMX_VIDEO_SKIP 366 #endif 367 #endif 368 369 #define CONFIG_IOMUX_LPSR 370 ...... 375 #endif

從示例代碼33.2.2.1 可以看出,mx6ull_alientek_emmc.h 文件中基本都是“CONFIG_”開頭的宏定義,這也說明mx6ull_alientek_emmc.h 文件的主要功能就是配置或者裁剪uboot。如果需要某個功能的話就在里面添加這個功能對應的CONFIG_XXX 宏即可,如果不需要某個功能的話就刪除掉對應的宏即可。我們以示例代碼33.2.2.1 為例,詳細的看一下mx6ull_alientek_emmc.h
中這些宏都是什么功能。

第14 行,添加了頭文件mx6_common.h,如果在mx6ull_alientek_emmc.h 中沒有發(fā)現(xiàn)有配置某個功能或命令,但是實際卻存在的話,可以到mx6_common.h 文件里面去找一下。

第29~39 行,設置DRAM的大小,宏PHYS_SDRAM_SIZE 就是板子上DRAM 的大小,如果用的NXP 官方的9X9 EVK 開發(fā)板的話DRAM 大小就為256MB。否則的話默認為512MB,正點原子的I.MX6U-ALPHA 開發(fā)板用的是512MB DDR3。

第50 行,定義宏CONFIG_DISPLAY_CPUINFO,uboot 啟動的時候可以輸出CPU信息

第51 行,定義宏CONFIG_DISPLAY_BOARDINFO,uboot 啟動的時候可以輸出板子信息

第54 行,CONFIG_SYS_MALLOC_LEN 為malloc內(nèi)存池大小,這里設置為16MB。

第56 行,定義宏CONFIG_BOARD_EARLY_INIT_F,這樣board_init_f 函數(shù)就會調(diào)用board_early_init_f 函數(shù)。

第57 行,定義宏CONFIG_BOARD_LATE_INIT ,這樣board_init_r 函數(shù)就會調(diào)用board_late_init 函數(shù)。

第59、60 行,使能I.MX6ULL 的串口功能,宏CONFIG_MXC_UART_BASE 表示串口寄存器基地址,這里使用的串口1,基地址為UART1_BASE,UART1_BASE 定義在文件arch/arm/include/asm/arch-mx6/imx-regs.h 中,imx-regs.h 是I.MX6ULL 寄存器描述文件,根據(jù)imx-regs.h 可得到UART1_BASE 的值如下:

UART1_BASE= (ATZ1_BASE_ADDR + 0x20000)=AIPS1_ARB_BASE_ADDR + 0x20000=0x02000000 + 0x20000=0X02020000

查閱I.MX6ULL 參考手冊,UART1 的寄存器基地址正是0X02020000,如圖33.2.2.1 所示:

第63、64 行,EMMC 接在I.MX6ULL 的USDHC2 上,宏CONFIG_SYS_FSL_ESDHC_ADDR為EMMC 所使用接口的寄存器基地址,也就是USDHC2(EMMC)的基地址,查看核心板如下圖所示:

第67~72 行,跟NAND 相關的宏,因為NAND 和USDHC2 的引腳是共用的,因此如果使用NAND 的只能使用一個USDHC 設備(SD 卡)。如果沒有使用NAND,那么就有兩個USDHC 設備(EMMC 和SD 卡),宏CONFIG_SYS_FSL_USDHC_NUM 表示USDHC 數(shù)量。EMMC 版本的
核心版沒有用到NAND,所以CONFIG_SYS_FSL_USDHC_NUM=2。

第75~81,和I2C有關的宏定義,用于控制使能哪個I2C,I2C 的速度為多少。

第92~96 行,NAND 的分區(qū)設置,如果使用NAND 的話,默認的NAND 分區(qū)為:"mtdparts=gpmi-nand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs) ",分區(qū)結(jié)果如表33.2.2.1所示:

NAND 的分區(qū)是可以調(diào)整的,比如boot 分區(qū)我們用不了64M 這么大,因此可以將其改小,其他的分區(qū)一樣的。

第98~111 行,宏CONFIG_MFG_ENV_SETTINGS 定義了一些環(huán)境變量,使用MfgTool 燒寫系統(tǒng)時候會用到這里面的環(huán)境變量。

第113~202 行,通過條件編譯來設置宏CONFIG_EXTRA_ENV_SETTINGS ,宏CONFIG_EXTRA_ENV_SETTINGS 也是設置一些環(huán)境變量,此宏會設置bootargs 這個環(huán)境變量,后面我們會詳細分析這個宏定義。

第204~217 行,設置宏CONFIG_BOOTCOMMAND,此宏就是設置環(huán)境變量bootcmd 的值。后面會詳細的分析這個宏定義。

第220~222 行,設置命令memtest 相關宏定義,比如使能命令memtest,設置memtest 測試的內(nèi)存起始地址和內(nèi)存大小。

第224 行,宏CONFIG_SYS_LOAD_ADDR 表示linux kernel 在DRAM 中的加載地址,也就是linux kernel 在DRAM 中的存儲首地址,CONFIG_LOADADDR=0X80800000。

第225 行,宏CONFIG_SYS_HZ 為系統(tǒng)時鐘頻率,這里為1000Hz。

第227 行,宏CONFIG_STACKSIZE 為棧大小,這里為128KB。

第230 行,宏CONFIG_NR_DRAM_BANKS 為DRAM BANK 的數(shù)量,I.MX6ULL 只有一個DRAM BANK,我們也只用到了一個BANK,所以為1。

第231 行,宏PHYS_SDRAM 為I.MX6ULL 的DRAM 控制器MMDC0 所管轄的DRAM 范圍起始地址,也就是0X80000000。

第233 行,宏CONFIG_SYS_SDRAM_BASE 為DRAM 的起始地址。

第234 行,宏CONFIG_SYS_INIT_RAM_ADDR 為I.MX6ULL 內(nèi)部IRAM 的起始地址(也就是OCRAM 的起始地址),為0X00900000。

第235 行,宏CONFIG_SYS_INIT_RAM_SIZE 為I.MX6ULL 內(nèi)部IRAM 的大小(OCRAM的大小),為0X00040000=128KB。

第237~240 行,宏CONFIG_SYS_INIT_SP_OFFSET 和CONFIG_SYS_INIT_SP_ADDR 與初始SP 有關,第一個為初始SP 偏移,第二個為初始SP 地址。

第256 行,宏CONFIG_SYS_MMC_ENV_DEV 為默認的MMC 設備,這里默認為USDHC2,也就是EMMC。

第257 行,宏CONFIG_SYS_MMC_ENV_PART 為模式分區(qū),默認為第0 個分區(qū)。

第258 行,宏CONFIG_MMCROOT 設置進入linux 系統(tǒng)的根文件系統(tǒng)所在的分區(qū),這里設置為"/dev/mmcblk1p2",也就是EMMC 設備的第2 個分區(qū)。第0 個分區(qū)保存uboot,第1 個分區(qū)保存linux 鏡像和設備樹,第2 個分區(qū)為Linux 系統(tǒng)的根文件系統(tǒng)。

第277~291 行,與NAND 有關的宏定義,如果使用NAND 的話。

第293 行,宏CONFIG_ENV_SIZE 為環(huán)境變量大小,默認為8KB。

第294~308 行,宏CONFIG_ENV_OFFSET 為環(huán)境變量偏移地址,這里的偏移地址是相對于存儲器的首地址。如果環(huán)境變量保存在EMMC 中的話,環(huán)境變量偏移地址為12* 64KB。如果環(huán)境變量保存在SPI FLASH 中的話,偏移地址為768*1024。如果環(huán)境變量保存在NAND 中的話,偏移地址為60<<20(60MB),并且重新設置環(huán)境變量的大小為128KB。

第312~323 行,與USB 相關的宏定義。

第325~342 行,與網(wǎng)絡相關的宏定義,比如使能dhcp、ping 等命令。第331 行的宏CONFIG_FEC_ENET_DEV 指定uboot 所使用的網(wǎng)口,I.MX6ULL 有兩個網(wǎng)口,為0 的時候使用ENET1,為1 的時候使用ENET2。宏IMX_FEC_BASE 為ENET 接口的寄存器首地址,宏
CONFIG_FEC_MXC_PHYADDR 為網(wǎng)口PHY 芯片的地址。宏CONFIG_FEC_XCV_TYPE 為PHY 芯片所使用的接口類型,I.MX6U-ALPHA 開發(fā)板的兩個PHY 都使用的RMII 接口。

第344~END,剩下的都是一些配置宏,比如CONFIG_VIDEO 宏用于開啟LCD,CONFIG_VIDEO_LOGO 使能LOGO 顯示,CONFIG_CMD_BMP 使能BMP 圖片顯示指令。這樣就可以在uboot 中顯示圖片了,一般用于顯示logo

關于mx6ull_alientek_emmc.h 就講解到這里,其中以CONFIG_CMD 開頭的宏都是用于使能相應命令的,其他的以CONFIG 開頭的宏都是完成一些配置功能的。以后會頻繁的和mx6ull_alientek_emmc.h 這個文件打交道。

添加開發(fā)板對應的板級文件夾

uboot 中每個板子都有一個對應的文件夾來存放板級文件,比如開發(fā)板上外設驅(qū)動文件等等。NXP 的I.MX 系列芯片的所有板級文件夾都存放在board/freescale 目錄下,在這個目錄下有個名為mx6ullevk 的文件夾,這個文件夾就是NXP 官方I.MX6ULL EVK 開發(fā)板的板級文件夾。復制mx6ullevk,將其重命名為mx6ull_alientek_emmc,命令如下:

cd board/freescale/ cp mx6ullevk/ -r mx6ull_alientek_emmc

進入mx6ull_alientek_emmc 目錄中,將其中的mx6ullevk.c 文件重命名為
mx6ull_alientek_emmc.c,命令如下:

cd mx6ull_alientek_emmc mv mx6ullevk.c mx6ull_alientek_emmc.c

我們還需要對mx6ull_alientek_emmc 目錄下的文件做一些修改:

1、修改mx6ull_alientek_emmc 目錄下的Makefile 文件
將mx6ull_alientek_emmc 下的Makefile 文件內(nèi)容改為如下所示:

1 # (C) Copyright 2015 Freescale Semiconductor, Inc. 2 # 3 # SPDX-License-Identifier: GPL-2.0+ 4 # 5 6 obj-y := mx6ull_alientek_emmc.o 7 8 extra-$(CONFIG_USE_PLUGIN) := plugin.bin 9 $(obj)/plugin.bin: $(obj)/plugin.o 10 $(OBJCOPY) -O binary --gap-fill 0xff $< $@

重點是第6 行的obj-y,改為mx6ull_alientek_emmc.o,這樣才會編譯mx6ull_alientek_emmc.c這個文件。

2、修改mx6ull_alientek_emmc 目錄下的imximage.cfg 文件
將imximage.cfg 中的下面一句:

PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000

改為:

PLUGIN board/freescale/mx6ull_alientek_emmc /plugin.bin 0x00907000

3、修改mx6ull_alientek_emmc 目錄下的Kconfig 文件
修改Kconfig 文件,修改后的內(nèi)容如下:

1 if TARGET_MX6ULL_ALIENTEK_EMMC 2 3 config SYS_BOARD 4 default "mx6ull_alientek_emmc" 5 6 config SYS_VENDOR 7 default "freescale" 8 9 config SYS_SOC 10 default "mx6" 11 12 config SYS_CONFIG_NAME 13 default "mx6ull_alientek_emmc" 14 15 endif

4、修改mx6ull_alientek_emmc 目錄下的MAINTAINERS 文件修改MAINTAINERS 文件,修改后的內(nèi)容如下:

1 MX6ULL_ALIENTEK_EMMC BOARD 2 M: Peng Fan <peng.fan@nxp.com> 3 S: Maintained 4 F: board/freescale/mx6ull_alientek_emmc/ 5 F: include/configs/mx6ull_alientek_emmc.h

修改U-Boot 圖形界面配置文件

uboot 是支持圖形界面配置,關于uboot 的圖形界面配置下一章會詳細的講解。修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的I.MX6UL 的話,應該修改arch/arm/Kconfig 這個文件),在207 行加入如下內(nèi)容:

1 config TARGET_MX6ULL_ALIENTEK_EMMC 2 bool "Support mx6ull_alientek_emmc" 3 select MX6ULL 4 select DM 5 select DM_THERMAL

在最后一行的endif 的前一行添加如下內(nèi)容:

source "board/freescale/mx6ull_alientek_emmc/Kconfig"

添加完成以后的Kconfig 文件如圖33.2.4.1 所示:

到此為止,I.MX6U-ALPHA 開發(fā)板就已經(jīng)添加到uboot 中了,接下來就是編譯這個新添加的開發(fā)板。

使用新添加的板子配置編譯uboot

在uboot 根目錄下新建一個名為mx6ull_alientek_emmc.sh 的shell 腳本,在這個shell 腳本里面輸入如下內(nèi)容:

1 #!/bin/bash 2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean 3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- (加空格) mx6ull_alientek_emmc_defconfig 4 make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

第3 行我們使用的默認配置文件就是33.2.1 節(jié)中新建的mx6ull_alientek_emmc_defconfig 這個配置文件。給予mx6ll_alientek_emmc.sh 可執(zhí)行權(quán)限,然后運行腳本來完成編譯,命令如下:

chmod 777 mx6ull_alientek_emmc.sh //給予可執(zhí)行權(quán)限,一次即可 ./mx6ull_alientek_emmc.sh //運行腳本編譯uboot

等待編譯完成,編譯完成以后輸入如下命令,查看一下33.2.2 小節(jié)中添加的
mx6ull_alientek_emmc.h 這個頭文件有沒有被引用。

grep -nR "mx6ull_alientek_emmc.h"

如果有很多文件都引用了mx6ull_alientek_emmc.h 這個頭文件,那就說明新板子添加成功,如圖33.2.5.1 所示:

編譯完成以后就使用imxdownload 將新編譯出來的u-boot.bin 燒寫到SD 卡中測試,SecureCRT 輸出結(jié)果如圖33.2.5.2 所示:

從圖33.2.5.1 可以看出,此時的Board 還是“MX6ULL 14x14 EVK”,因為我們參考的NXP官方的I.MX6ULL 開發(fā)板來添加自己的開發(fā)板。如果接了LCD 屏幕的話會發(fā)現(xiàn)LCD 屏幕并沒有顯示NXP 的logo,而且從圖33.2.5.1 可以看出此時的網(wǎng)絡同樣也沒識別出來。前面已經(jīng)說了,默認uboot 中的LCD 驅(qū)動和網(wǎng)絡驅(qū)動在正點原子的I.MX6U-ALPHA 開發(fā)板上是有問題的,需要修改。

LCD驅(qū)動修改

一般uboot 中修改驅(qū)動基本都是在xxx.h 和xxx.c 這兩個文件中進行的,xxx 為板子名稱,比如mx6ull_alientek_emmc.h 和mx6ull_alientek_emmc.c 這兩個文件。

一般修改LCD 驅(qū)動重點注意以下幾點:

  • ①、LCD 所使用的GPIO,查看uboot中LCD 的IO 配置是否正確。
  • ②、LCD 背光引腳GPIO 的配置。
  • ③、LCD 配置參數(shù)是否正確。

正點原子的I.MX6U-ALPHA 開發(fā)板LCD 原理圖和NXP 官方I.MX6ULL 開發(fā)板一致,也就是LCD 的IO 和背光IO 都一樣的,所以IO部分就不用修改了。

需要修改的之后LCD參數(shù),打開文件mx6ull_alientek_emmc.c,找到如下所示內(nèi)容:

struct display_info_t const displays[] = {{.bus = MX6UL_LCDIF1_BASE_ADDR,.addr = 0,.pixfmt = 24,.detect = NULL,.enable = do_enable_parallel_lcd,.mode = {.name = "TFT43AB",.xres = 480,.yres = 272,.pixclock = 108695,.left_margin = 8,.right_margin = 4,.upper_margin = 2,.lower_margin = 4,.hsync_len = 41,.vsync_len = 10,.sync = 0,.vmode = FB_VMODE_NONINTERLACED} } };

示例代碼33.2.6.1 中定義了一個變量displays,類型為display_info_t,這個結(jié)構(gòu)體是LCD信息結(jié)構(gòu)體,其中包括了LCD 的分辨率像素格式,LCD 的各個參數(shù)等。display_info_t 定義在文件arch/arm/include/asm/imx-common/video.h 中,定義如下:

struct display_info_t {int bus;int addr;int pixfmt;int (*detect)(struct display_info_t const *dev);void (*enable)(struct display_info_t const *dev);struct fb_videomode mode;};

pixfmt 是像素格式,也就是一個像素點是多少位,如果是RGB565 的話就是16 位,如果是888 的話就是24 位,一般使用RGB888。
結(jié)構(gòu)體display_info_t 還有個mode 成員變量,此成員變量也是個結(jié)構(gòu)體,為fb_videomode,定義在文件include/linux/fb.h 中,定義如下:

struct fb_videomode {const char *name; /* optional */u32 refresh; /* optional */u32 xres;u32 yres;u32 pixclock;u32 left_margin;u32 right_margin;u32 upper_margin;u32 lower_margin;u32 hsync_len;u32 vsync_len;u32 sync;u32 vmode;u32 flag;};

結(jié)構(gòu)體fb_videomode 里面的成員變量為LCD 的參數(shù),這些成員變量函數(shù)如下(和前面裸機一致):

  • name:LCD 名字,要和環(huán)境變量中的panel 相等。
  • xres、yres:LCD X 軸和Y 軸像素數(shù)量。
  • pixclock:像素時鐘,每個像素時鐘周期的長度,單位為皮秒。
  • left_margin:HBP,水平同步后肩。
  • right_margin:HFP,水平同步前肩。
  • upper_margin:VBP,垂直同步后肩。
  • lower_margin:VFP,垂直同步前肩。
  • hsync_len:HSPW,行同步脈寬。
  • vsync_len:VSPW,垂直同步脈寬。
  • vmode:大多數(shù)使用FB_VMODE_NONINTERLACED,也就是不使用隔行掃描。

可以看出,這些參數(shù)和我們第二十四章講解裸機RGB LCD 的時候參數(shù)基本一樣,唯一不同的像素時鐘pixclock 的含義不同,以正點原子的7 寸1024*600 分辨率的屏幕(ATK7016)為例,屏幕要求的像素時鐘為51.2MHz,因此:

pixclock=(1/51200000)*10^12=19531

在根據(jù)其他的屏幕參數(shù),可以得出ATK7016 屏幕的配置參數(shù)如下:

struct display_info_t const displays[] = {{.bus = MX6UL_LCDIF1_BASE_ADDR,.addr = 0,.pixfmt = 24,.detect = NULL,.enable = do_enable_parallel_lcd,.mode = {.name = "TFT7016",//名字可自定義.xres = 1024,.yres = 600,.pixclock = 19531,.left_margin = 140, //HBPD.right_margin = 160, //HFPD.upper_margin = 20, //VBPD.lower_margin = 12, //VFBD.hsync_len = 20, //HSPW.vsync_len = 3, //VSPW.sync = 0,.vmode = FB_VMODE_NONINTERLACED} } };

使用示例代碼33.2.6.4 中的屏幕參數(shù)替換掉mx6ull_alientek_emmc.c 中uboot 默認的屏幕參數(shù)。
打開mx6ull_alientek_emmc.h,找到所有如下語句:

panel=TFT43AB

將其改為:

panel=TFT7016

也就是設置panel 為TFT7016,panel 的值要與示例代碼33.2.6.4 中的.name 成員變量的值一致。修改完成以后重新編譯一遍uboot 并燒寫到SD 中啟動。

重啟以后LCD 驅(qū)動一般就會工作正常了,LCD 上回顯示NXP 的logo。但是有可能會遇到LCD 并沒有工作,還是黑屏,這是什么原因呢?在uboot 命令模式輸入“print”來查看環(huán)境變量panel 的值,會發(fā)現(xiàn)panel 的值要是TFT43AB(或其他的,反正不是TFT7016),如圖33.2.6.1所示:

這是因為之前有將環(huán)境變量保存到EMMC 中,uboot 啟動以后會先從EMMC 中讀取環(huán)境變量,如果EMMC 中沒有環(huán)境變量的話才會使用mx6ull_alientek_emmc.h 中的默認環(huán)境變量。

如果EMMC 中的環(huán)境變量panel 不等于TFT7016,那么LCD 顯示肯定不正常,我們只需要在uboot 中修改panel 的值為TFT7016 即可,在uboot 的命令模式下輸入如下命令:

setenv panel TFT7016 saveenv

上述命令修改環(huán)境變量panel 為TFT7016,然后保存,重啟uboot,此時LCD 驅(qū)動就工作正常了。如果LCD 還是沒有正常工作的,那就要檢查自己哪里有沒有改錯,或者還有哪里沒有修改。

網(wǎng)絡驅(qū)動修改

1、I.MX6U-ALPHA 開發(fā)板網(wǎng)絡簡介

I.MX6UL/ULL 內(nèi)部有個以太網(wǎng)MAC 外設,也就是ENET,需要外接一個PHY 芯片來實現(xiàn)有線網(wǎng)絡通信功能,也就是內(nèi)部MAC+外部PHY芯片的方案。

大家可能聽過DM9000 這個網(wǎng)絡芯片,在一些沒有內(nèi)部MAC 的CPU 中,比如三星的2440,4412 等,就會采用DM9000 來實現(xiàn)聯(lián)網(wǎng)功能。DM9000 提供了一個類似SRAM 的訪問接口,主控CPU 通過這個接口即可與DM9000 進行通信,DM9000就是一個MAC+PHY 芯片。這個方案就相當于外部MAC+外部PHY。

那么I.MX6U 這樣的內(nèi)部MAC+PHY 芯片與DM9000 方案比有什么優(yōu)勢嗎?那優(yōu)勢大了去了!首先就是通信效率和速度,一般SOC 內(nèi)部的MAC 是帶有一個專用DMA 的,專門用于處理網(wǎng)絡數(shù)據(jù)包,采用SRAM 來讀寫DM9000 的速度是壓根就沒法和內(nèi)部MAC+外部PHY 芯片的速度比。采用外部DM9000 完全是無奈之舉,誰讓2440,4412 這些芯片內(nèi)部沒有以太網(wǎng)外設呢,現(xiàn)在又想用有線網(wǎng)絡,沒有辦法只能找個DM9000 的方案。從這里也可以看出,三星的2440、4412 這些芯片設計之初就不是給工業(yè)產(chǎn)品用的,他們是給消費類電子使用的,比如手機、平板等,手機或平板要上網(wǎng),可以通過WIFI 或者4G,我是沒有見過哪個手機或者平板上網(wǎng)是要接根網(wǎng)線的。正點原子的I.MX6U-ALPHA 開發(fā)板也可以通過WIFI 或者4G 上網(wǎng),這個是后話了。

I.MX6UL/ULL 有兩個網(wǎng)絡接口ENET1 和ENET2,正點原子的I.MX6U-ALPHA 開發(fā)板提供了這兩個網(wǎng)絡接口,其中ENET1 和ENET2 都使用LAN8720A作為PHY 芯片。NXP 官方的I.MX6ULL EVK 開發(fā)板使用KSZ8081 這顆PHY 芯片,LAN8720A 相比KSZ8081 具有體積小、外圍器件少、價格便宜等優(yōu)點。

直接使用KSZ8081 固然可以,但是我們在實際的產(chǎn)品中不一定會使用KSZ8081,有時候為了降低成本會選擇其他的PHY 芯片,這個時候就有個問題:換了PHY 芯片以后網(wǎng)絡驅(qū)動怎么辦?為此,正點原子的I.MX6U-ALPHA 開發(fā)板將ENET1 和ENET2的PHY 換成了LAN8720A,這樣就可以給大家講解更換PHY 芯片以后如何調(diào)整網(wǎng)絡驅(qū)動,使網(wǎng)絡工作正常。

  • 先來看一下I.MX6U-ALPHA 開發(fā)板ENET1 的網(wǎng)絡原理圖如圖33.2.7.1 所示:

    ENET1 的網(wǎng)絡PHY 芯片為LAN8720A,通過RMII 接口與I.MX6ULL 相連,正點原子I.MX6U-ALPHA 開發(fā)板的ENET1 引腳與NXP 官方的I.MX6ULL EVK 開發(fā)板基本一樣,唯獨復位引腳不同。從圖33.2.7.1 可以看出,正點原子I.MX6U-ALPHA 開發(fā)板的ENET1 復位引腳ENET1_RST 接到了I.M6ULL 的SNVS_TAMPER7 這個引腳上。

LAN8720A 內(nèi)部是有寄存器的,I.MX6ULL 會讀取LAN8720 內(nèi)部寄存器來判斷當前的物理鏈接狀態(tài)、連接速度(10M 還是100M)和雙工狀態(tài)(半雙工還是全雙工)。I.MX6ULL 通過MDIO接口來讀取PHY 芯片的內(nèi)部寄存器,MDIO 接口有兩個引腳,ENET_MDC 和ENET_MDIO,ENET_MDC 提供時鐘,ENET_MDIO 進行數(shù)據(jù)傳輸。

一個MDIO 接口可以管理32 個PHY 芯片,同一個MDIO 接口下的這些PHY 使用不同的器件地址來做區(qū)分,MIDO 接口通過不同的器件地址即可訪問到相應的PHY 芯片。I.MX6U-ALPHA 開發(fā)板ENET1 上連接的LAN8720A器件地址為0X0(引腳接下拉即可確定),所示我們要修改ENET1 網(wǎng)絡驅(qū)動的話重點就三點:

①、ENET1 復位引腳初始化(每個LAN8720A都有一個復位引腳)。
②、LAN8720A 的器件ID。
③、LAN8720 驅(qū)動

  • 再來看一下ENET2 的原理圖,如圖33.2.7.2 所示:

    關于ENET2 網(wǎng)絡驅(qū)動的修改也注意一下三點:
    ①、ENET2 的復位引腳,從圖33.2.7.2 可以看出,ENET2 的復位引腳ENET2_RST 接到了I.MX6ULL 的SNVS_TAMPER8 上。
    ②、ENET2 所使用的PHY 芯片器件地址,從圖33.2.7.2 可以看出,PHY 器件地址為0X1。
    ③、LAN8720 驅(qū)動,ENET1 和ENET2 都使用的LAN8720,所以驅(qū)動肯定是一樣的(一般國際規(guī)定所有的PHY芯片前16寄存器都要一樣,所以驅(qū)動都是通用的,Linux內(nèi)核通用驅(qū)動也是如此)。

2、網(wǎng)絡PHY地址修改

首先修改uboot 中的ENET1 和ENET2 的PHY 地址和驅(qū)動,打開mx6ull_alientek_emmc.h這個文件,找到如下代碼:

325 #ifdef CONFIG_CMD_NET 326 #define CONFIG_CMD_PING 327 #define CONFIG_CMD_DHCP 328 #define CONFIG_CMD_MII 329 #define CONFIG_FEC_MXC 330 #define CONFIG_MII 331 #define CONFIG_FEC_ENET_DEV 1 332 333 #if (CONFIG_FEC_ENET_DEV == 0) 334 #define IMX_FEC_BASE ENET_BASE_ADDR 335 #define CONFIG_FEC_MXC_PHYADDR 0x2 336 #define CONFIG_FEC_XCV_TYPE RMII 337 #elif (CONFIG_FEC_ENET_DEV == 1) 338 #define IMX_FEC_BASE ENET2_BASE_ADDR 339 #define CONFIG_FEC_MXC_PHYADDR 0x1 340 #define CONFIG_FEC_XCV_TYPE RMII 341 #endif 342 #define CONFIG_ETHPRIME "FEC" 343 344 #define CONFIG_PHYLIB 345 #define CONFIG_PHY_MICREL 346 #endif

第331 行的宏CONFIG_FEC_ENET_DEV 用于選擇使用哪個網(wǎng)口,默認為1,也就是選擇ENET2。第335 行為ENET1 的PHY 地址,默認是0X2,第339 行為ENET2 的PHY 地址,默認為0x1。根據(jù)前面的分析可知,正點原子的I.MX6U-ALPHA 開發(fā)板ENET1 的PHY 地址為0X0,ENET2 的PHY 地址為0X1,所以需要將第335 行的宏CONFIG_FEC_MXC_PHYADDR改為0x0。

第345 行定了一個宏CONFIG_PHY_MICREL,此宏用于使能uboot 中Micrel 公司的PHY驅(qū)動,KSZ8081 這顆PHY 芯片就是Micrel 公司生產(chǎn)的,不過Micrel 已經(jīng)被Microchip 收購了。

如果要使用LAN8720A,那么就得將CONFIG_PHY_MICREL 改為CONFIG_PHY_SMSC,也就是使能uboot 中的SMSC 公司中的PHY 驅(qū)動,因為LAN8720A 就是SMSC 公司生產(chǎn)的。所以示例代碼33.2.7.1 有三處要修改:

①、修改ENET1 網(wǎng)絡PHY 的地址。
②、修改ENET2 網(wǎng)絡PHY 的地址。
③、使能SMSC 公司的PHY 驅(qū)動。

修改后的網(wǎng)絡PHY 地址參數(shù)如下所示:

325 #ifdef CONFIG_CMD_NET 326 #define CONFIG_CMD_PING 327 #define CONFIG_CMD_DHCP 328 #define CONFIG_CMD_MII 329 #define CONFIG_FEC_MXC 330 #define CONFIG_MII 331 #define CONFIG_FEC_ENET_DEV 1 332 333 #if (CONFIG_FEC_ENET_DEV == 0) 334 #define IMX_FEC_BASE ENET_BASE_ADDR 335 #define CONFIG_FEC_MXC_PHYADDR 0x0 336 #define CONFIG_FEC_XCV_TYPE RMII 337 #elif (CONFIG_FEC_ENET_DEV == 1) 338 #define IMX_FEC_BASE ENET2_BASE_ADDR 339 #define CONFIG_FEC_MXC_PHYADDR 0x1 340 #define CONFIG_FEC_XCV_TYPE RMII 341 #endif 342 #define CONFIG_ETHPRIME "FEC" 343 344 #define CONFIG_PHYLIB 345 #define CONFIG_PHY_SMSC 346 #endif

3、刪除uboot 中74LV595 的驅(qū)動代碼

uboot 中網(wǎng)絡PHY 芯片地址修改完成以后就是網(wǎng)絡復位引腳的驅(qū)動修改了,打開mx6ull_alientek_emmc.c,找到如下代碼:

#define IOX_SDI IMX_GPIO_NR(5, 10) #define IOX_STCP IMX_GPIO_NR(5, 7) #define IOX_SHCP IMX_GPIO_NR(5, 11) #define IOX_OE IMX_GPIO_NR(5, 8)

示例代碼33.2.7.3 中以IOX 開頭的宏定義是74LV595 的相關GPIO,因為NXP 官方I.MX6ULL EVK 開發(fā)板使用74LV595 來擴展IO,兩個網(wǎng)絡的復位引腳就是由74LV595 來控制的。正點原子的I.MX6U-ALPHA 開發(fā)板并沒有使用74LV595,因此我們將示例代碼33.2.7.3 中的代碼刪除掉,替換為如下所示代碼:

#define ENET1_RESET IMX_GPIO_NR(5, 7) #define ENET2_RESET IMX_GPIO_NR(5, 8)

ENET1 的復位引腳連接到SNVS_TAMPER7 上,對應GPIO5_IO07,ENET2 的復位引腳連接到SNVS_TAMPER8 上,對應GPIO5_IO08。

繼續(xù)在mx6ull_alientek_emmc.c 中找到如下代碼:

static iomux_v3_cfg_t const iox_pads[] = {/* IOX_SDI */MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),/* IOX_SHCP */MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),/* IOX_STCP */MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),/* IOX_nOE */MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL), };

同理,示例代碼33.2.7.5 是74LV595 的IO 配置參數(shù)結(jié)構(gòu)體,將其刪除掉。繼續(xù)在mx6ull_alientek_emmc.c 中找到函數(shù)iox74lv_init,如下所示:

static void iox74lv_init(void) {int i;gpio_direction_output(IOX_OE, 0);for (i = 7; i >= 0; i--) {gpio_direction_output(IOX_SHCP, 0);gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);udelay(500);gpio_direction_output(IOX_SHCP, 1);udelay(500);} ...... /* * shift register will be output to pins */gpio_direction_output(IOX_STCP, 1); }; void iox74lv_set(int index) {int i;for (i = 7; i >= 0; i--) {gpio_direction_output(IOX_SHCP, 0);if (i == index)gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);elsegpio_direction_output(IOX_SDI, seq[qn_output[i]][1]);udelay(500);gpio_direction_output(IOX_SHCP, 1);udelay(500);} ...... /* * shift register will be output to pins */ gpio_direction_output(IOX_STCP, 1); };

iox74lv_init 函數(shù)是74LV595 的初始化函數(shù),iox74lv_set 函數(shù)用于控制74LV595 的IO 輸出電平,將這兩個函數(shù)全部刪除掉!

在mx6ull_alientek_emmc.c 中找到board_init 函數(shù),此函數(shù)是板子初始化函數(shù),會被board_init_r 調(diào)用,board_init 函數(shù)內(nèi)容如下:

int board_init(void) {......imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));iox74lv_init();......return 0; }

board_init 會調(diào)用imx_iomux_v3_setup_multiple_pads 和iox74lv_init 這兩個函數(shù)來初始化74lv595 的GPIO,將這兩行刪除掉。

至此,mx6ull_alientek_emmc.c 中關于74LV595 芯片的驅(qū)動代碼都刪除掉了,接下來就是添加I.MX6U-ALPHA 開發(fā)板兩個網(wǎng)絡復位引腳了。

4、添加I.MX6U-ALPHA 開發(fā)板網(wǎng)絡復位引腳驅(qū)動

在mx6ull_alientek_emmc.c 中找到如下所示代碼:

640 static iomux_v3_cfg_t const fec1_pads[] = { 641 MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 642 MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), ...... 649 MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 650 MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 651 }; 652 653 static iomux_v3_cfg_t const fec2_pads[] = { 654 MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 655 MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), ...... 664 MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 665 MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 666 };

結(jié)構(gòu)體數(shù)組fec1_pads 和fec2_pads 是ENET1 和ENET2 這兩個網(wǎng)口的IO 配置參數(shù),在這兩個數(shù)組中添加兩個網(wǎng)口的復位IO 配置參數(shù),完成以后如下所示:

640 static iomux_v3_cfg_t const fec1_pads[] = { 641 MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 642 MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), ...... 649 MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 650 MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 651 MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), 652 }; 653 654 static iomux_v3_cfg_t const fec2_pads[] = { 655 MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 656 MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), ...... 665 MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 666 MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 667 MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL), 668 };

示例代碼33.2.7.9 中,第651 行和667 行分別是ENET1 和ENET2 的復位IO 配置參數(shù)。

繼續(xù)在文件mx6ull_alientek_emmc.c 中找到函數(shù)setup_iomux_fec,此函數(shù)默認代碼如下:

668 static void setup_iomux_fec(int fec_id) 669 { 670 if (fec_id == 0) 671 imx_iomux_v3_setup_multiple_pads(fec1_pads, 672 ARRAY_SIZE(fec1_pads)); 673 else 674 imx_iomux_v3_setup_multiple_pads(fec2_pads, 675 ARRAY_SIZE(fec2_pads)); 676 }

函數(shù)setup_iomux_fec 就是根據(jù)fec1_pads 和fec2_pads 這兩個網(wǎng)絡IO 配置數(shù)組來初始化I.MX6ULL 的網(wǎng)絡IO。

我們需要在其中添加網(wǎng)絡復位IO 的初始化代碼,并且復位一下PHY 芯片,修改后的setup_iomux_fec 函數(shù)如下:

668 static void setup_iomux_fec(int fec_id) 669 { 670 if (fec_id == 0) 671 { 672 673 imx_iomux_v3_setup_multiple_pads(fec1_pads, 674 ARRAY_SIZE(fec1_pads)); 675 676 gpio_direction_output(ENET1_RESET, 1); 677 gpio_set_value(ENET1_RESET, 0); 678 mdelay(20); 679 gpio_set_value(ENET1_RESET, 1); 680 } 681 else 682 { 683 imx_iomux_v3_setup_multiple_pads(fec2_pads, 684 ARRAY_SIZE(fec2_pads)); 685 gpio_direction_output(ENET2_RESET, 1); 686 gpio_set_value(ENET2_RESET, 0); 687 mdelay(20); 688 gpio_set_value(ENET2_RESET, 1); 689 } 690 }

示例代碼33.2.7.11 中第676 行~679 行和第685 行~688 行分別對應ENET1 和ENET2 的復位IO 初始化,將這兩個IO 設置為輸出并且硬件復位一下LAN8720A,這個硬件復位很重要!否則可能導致uboot 無法識別LAN8720A。

5、修改drivers/net/phy/phy.c 文件中的函數(shù)genphy_update_link

大功基本上告成,還差最后一步,uboot 中的LAN8720A 驅(qū)動有點問題,打開文件drivers/net/phy/phy.c,找到函數(shù)genphy_update_link,這是個通用PHY 驅(qū)動函數(shù),此函數(shù)用于更新PHY 的連接狀態(tài)和速度。使用LAN8720A 的時候需要在此函數(shù)中添加一些代碼,修改后的函數(shù)genphy_update_link 如下所示:

221 int genphy_update_link(struct phy_device *phydev) 222 { 223 unsigned int mii_reg; 224 225 #ifdef CONFIG_PHY_SMSC 226 static int lan8720_flag = 0; 227 int bmcr_reg = 0; 228 if (lan8720_flag == 0) { 229 bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 230 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 231 while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) { 232 udelay(100); 233 } 234 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg); 235 lan8720_flag = 1; 236 } 237 #endif 238 239 /* 240 * Wait if the link is up, and autonegotiation is in progress 241 * (ie - we're capable and it's not done) 242 */ 243 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); ...... 291 292 return 0; 293 }

225 行~ 237 行就是新添加的代碼,為條件編譯代碼段,只有使用SMSC 公司的PHY 這段代碼才會執(zhí)行(目前只測試了LAN8720A,SMSC 公司其他的芯片還未測試)。第229 行讀取LAN8720A 的BMCR 寄存器(寄存器地址為0),此寄存器為LAN8720A 的配置寄存器,這里先讀取此寄存器的默認值并保存起來。230 行向寄存器BMCR 寄存器寫入BMCR_RESET(值為0X8000),因為BMCR 的bit15 是軟件復位控制位,因此230 行就是軟件復位(軟復位)LAN8720A,復位完成以后此位會自動清零。第231~233 行等待LAN8720A 軟件復位完成,也就是判斷BMCR的bit15 位是否為1,為1 的話表示還沒有復位完成。第234 行重新向BMCR 寄存器寫入以前的值,也就是229 行讀出的那個值。

至此網(wǎng)絡的復位引腳驅(qū)動修改完成,重新編譯uboot,然后將u-boot.bin 燒寫到SD 卡中并啟動,uboot 啟動信息如圖33.2.7.3 所示:

從圖33.2.6.4 中可以看到“Net:FEC1”這一行,提示當前使用的FEC1 這個網(wǎng)口,也就是ENET2。在uboot 中使用網(wǎng)絡之前要先設置幾個環(huán)境變量,命令如下:

setenv ipaddr 192.168.1.55 //開發(fā)板IP 地址 setenv ethaddr b8:ae:1d:01:00:00 //開發(fā)板網(wǎng)卡MAC 地址 setenv gatewayip 192.168.1.1 //開發(fā)板默認網(wǎng)關 setenv netmask 255.255.255.0 //開發(fā)板子網(wǎng)掩碼 setenv serverip 192.168.1.250 //服務器地址,也就是Ubuntu 地址 saveenv //保存環(huán)境變量

設置好環(huán)境變量以后就可以在uboot 中使用網(wǎng)絡了,用網(wǎng)線將I.MX6U-ALPHA 上的ENET2與電腦或者路由器連接起來,保證開發(fā)板和電腦在同一個網(wǎng)段內(nèi),通過ping 命令來測試一下網(wǎng)絡連接,命令如下:

ping 192.168.1.250

結(jié)果如圖33.2.7.4 所示:

從圖33.2.7.4 可以看出,有“host 192.168.1.250 is alive”這句,說明ping 主機成功,說明ENET2 網(wǎng)絡工作正常。

再來測試一下ENET1 的網(wǎng)絡是否正常工作,打開mx6ull_alientek_emmc.h,將CONFIG_FEC_ENET_DEV 改為0,然后重新編譯一下uboot 并燒寫到SD 卡中重啟。重啟開發(fā)板,uboot 輸出信息如圖33.2.7.5 所示:

從圖33.2.7.5 可以出,有“Net:FEC0”這一行,說明當前使用的FEC0 這個網(wǎng)卡,也就是ENET1,同樣的ping 一下主機,結(jié)果如圖33.2.7.5 所示:

從圖33.2.7.6 可以看出,ping 主機也成功,說明ENET1 網(wǎng)絡也工作正常,至此,I.MX6U-ALPHA 開發(fā)板的兩個網(wǎng)絡都工作正常了,建議大家將ENET2 設置為uboot 的默認網(wǎng)卡!也就是將宏CONFIG_FEC_ENET_DEV 設置為1。

其他需要修改的地方

在uboot 啟動信息中會有“Board: MX6ULL 14x14 EVK”這一句,也就是說板子名字為“MX6ULL 14x14 EVK”,要將其改為我們所使用的板子名字,比如“MX6ULL ALIENTEKEMMC”或者“MX6ULL ALIENTEK NAND”。打開文件mx6ull_alientek_emmc.c,找到函數(shù)checkboard,將其改為如下所示內(nèi)容:

int checkboard(void) {if (is_mx6ull_9x9_evk())puts("Board: MX6ULL 9x9 EVK\n");elseputs("Board: MX6ULL ALIENTEK EMMC\n");return 0; }

修改完成以后重新編譯uboot 并燒寫到SD 卡中驗證,uboot 啟動信息如圖33.2.8.1 所示:

從圖33.2.8.1 可以看出,Board 變成了“MX6ULL ALIENTEK EMMC”。至此uboot 的驅(qū)動部分就修改完成了,uboot 移植也完成了。

uboot 的最終目的就是啟動Linux 內(nèi)核,所以需要通過啟動Linux 內(nèi)核來判斷uboot 移植是否成功。在啟動Linux 內(nèi)核之前我們先來學習兩個重要的環(huán)境變量bootcmd 和bootargs。

bootcmd和bootargs環(huán)境變量(修改mx6ull_alientek_emmc.h)

uboot 中有兩個非常重要的環(huán)境變量bootcmd 和bootargs,接下來看一下這兩個環(huán)境變量。

bootcmd 和bootagrs 是采用類似shell 腳本語言編寫的,里面有很多的變量引用,這些變量其實都是環(huán)境變量,有很多是NXP 自己定義的。

文件mx6ull_alientek_emmc.h 中的宏CONFIG_EXTRA_ENV_SETTINGS 保存著這些環(huán)境變量的默認值,內(nèi)容如下:

前面講的_defconfig配置文件的配置項很少,就5行,配置的還不夠,重點是mx6ull_alientek_emmc.h里面對應的配置文件。每一個板子都有一個這樣對應的 .h和 .c 配置文件,上一節(jié)添加開發(fā)板對應的頭文件已經(jīng)講過了。

113 #if defined(CONFIG_SYS_BOOT_NAND) 114 #define CONFIG_EXTRA_ENV_SETTINGS \ 115 CONFIG_MFG_ENV_SETTINGS \ 116 "panel=TFT43AB\0" \ 117 "fdt_addr=0x83000000\0" \ 118 "fdt_high=0xffffffff\0" \ ...... 126 "bootz ${loadaddr} - ${fdt_addr}\0" 127 128 #else 129 #define CONFIG_EXTRA_ENV_SETTINGS \ 130 CONFIG_MFG_ENV_SETTINGS \ 131 "script=boot.scr\0" \ 132 "image=zImage\0" \ 133 "console=ttymxc0\0" \ 134 "fdt_high=0xffffffff\0" \ 135 "initrd_high=0xffffffff\0" \ 136 "fdt_file=undefined\0" \ ...... 194 "findfdt="\ 195 "if test $fdt_file = undefined; then " \ 196 "if test $board_name = EVK && test $board_rev = 9X9; then " \ 197 "setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \ 198 "if test $board_name = EVK && test $board_rev = 14X14; then " \ 199 "setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \ 200 "if test $fdt_file = undefined; then " \ 201 "echo WARNING: Could not determine dtb to use; fi; " \ 202 "fi;\0" \

宏CONFIG_EXTRA_ENV_SETTINGS 是個條件編譯語句,使用NAND 和EMMC 的時候宏CONFIG_EXTRA_ENV_SETTINGS 的值是不同的。

環(huán)境變量bootcmd(啟動內(nèi)核命令)

bootcmd 在前面已經(jīng)說了很多次了,bootcmd 保存著uboot 默認命令,uboot 倒計時結(jié)束以后就會執(zhí)行bootcmd 中的命令。這些命令一般都是用來啟動Linux 內(nèi)核的,比如讀取EMMC 或者NAND Flash 中的Linux 內(nèi)核鏡像文件和設備樹文件到DRAM 中,然后啟動Linux 內(nèi)核。

可以在uboot 啟動以后進入命令行設置bootcmd 環(huán)境變量的值。如果EMMC 或者NAND 中沒有保存bootcmd 的值,那么uboot 就會使用默認的值,板子第一次運行uboot 的時候都會使用默認值來設置bootcmd 環(huán)境變量。打開文件include/env_default.h,在此文件中有如下所示內(nèi)容(之所以內(nèi)容這么多,是為了兼容性):

13 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED 14 env_t environment __PPCENV__ = { 15 ENV_CRC, /* CRC Sum */ 16 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 17 1, /* Flags: valid */ 18 #endif 19 { 20 #elif defined(DEFAULT_ENV_INSTANCE_STATIC) 21 static char default_environment[] = { 22 #else 23 const uchar default_environment[] = { 24 #endif 25 #ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT 26 ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0" 27 #endif 28 #ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT 29 ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0" 30 #endif 31 #ifdef CONFIG_BOOTARGS 32 "bootargs=" CONFIG_BOOTARGS "\0" 33 #endif 34 #ifdef CONFIG_BOOTCOMMAND 35 "bootcmd=" CONFIG_BOOTCOMMAND "\0" 36 #endif 37 #ifdef CONFIG_RAMBOOTCOMMAND 38 "ramboot=" CONFIG_RAMBOOTCOMMAND "\0" 39 #endif 40 #ifdef CONFIG_NFSBOOTCOMMAND 41 "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0" 42 #endif 43 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 44 "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0" 45 #endif 46 #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0) 47 "baudrate=" __stringify(CONFIG_BAUDRATE) "\0" 48 #endif 49 #ifdef CONFIG_LOADS_ECHO 50 "loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0" 51 #endif 52 #ifdef CONFIG_ETHPRIME 53 "ethprime=" CONFIG_ETHPRIME "\0" 54 #endif 55 #ifdef CONFIG_IPADDR 56 "ipaddr=" __stringify(CONFIG_IPADDR) "\0" 57 #endif 58 #ifdef CONFIG_SERVERIP 59 "serverip=" __stringify(CONFIG_SERVERIP) "\0" 60 #endif 61 #ifdef CONFIG_SYS_AUTOLOAD 62 "autoload=" CONFIG_SYS_AUTOLOAD "\0" 63 #endif 64 #ifdef CONFIG_PREBOOT 65 "preboot=" CONFIG_PREBOOT "\0" 66 #endif 67 #ifdef CONFIG_ROOTPATH 68 "rootpath=" CONFIG_ROOTPATH "\0" 69 #endif 70 #ifdef CONFIG_GATEWAYIP 71 "gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0" 72 #endif 73 #ifdef CONFIG_NETMASK 74 "netmask=" __stringify(CONFIG_NETMASK) "\0" 75 #endif 76 #ifdef CONFIG_HOSTNAME

第13~23 行,這段代碼是個條件編譯,由于沒有定義
DEFAULT_ENV_INSTANCE_EMBEDDED 和CONFIG_SYS_REDUNDAND_ENVIRONMENT,
因此uchar default_environment[]數(shù)組保存環(huán)境變量。

在示例代碼33.3.1.1 中指定了很多環(huán)境變量的默認值,比如bootcmd 的默認值就是CONFIG_BOOTCOMMAND ,bootargs 的默認值就是CONFIG_BOOTARGS。我們可以在mx6ull_alientek_emmc.h 文件中通過設置宏CONFIG_BOOTCOMMAND 來設置bootcmd 的默認值,NXP 官方設置的CONFIG_BOOTCOMMAND 值如下:

204 #define CONFIG_BOOTCOMMAND \ 205 "run findfdt;" \ 206 "mmc dev ${mmcdev};" \ 207 "mmc dev ${mmcdev}; if mmc rescan; then " \ 208 "if run loadbootscript; then " \ 209 "run bootscript; " \ 210 "else " \ 211 "if run loadimage; then " \ 212 "run mmcboot; " \ 213 "else run netboot; " \ 214 "fi; " \ 215 "fi; " \ 216 "else run netboot; fi"

看起來很復雜的樣子!因為uboot 使用了類似shell 腳本語言的方式來編寫的,我們一行一行來分析。

第205 行,run findfdt;使用的是uboot 的run 命令來運行findfdt,findfdt 是NXP 自行添加的環(huán)境變量。findfdt 是用來查找開發(fā)板對應的設備樹文件(.dtb)。IMX6ULL EVK 的設備樹文件為imx6ull-14x14-evk.dtb,findfdt 內(nèi)容如下:

"findfdt="\ "if test $fdt_file = undefined; then " \ "if test $board_name = EVK && test $board_rev = 9X9; then " \ "setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \ "if test $board_name = EVK && test $board_rev = 14X14; then " \ "setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \ "if test $fdt_file = undefined; then " \ "echo WARNING: Could not determine dtb to use; fi; " \ "fi;\0" \

findfdt 里面用到的變量有fdt_file,board_name,board_rev,這三個變量內(nèi)容如下(啟動UBOOT就會顯示這些環(huán)境變量):

fdt_file=undefined,board_name=EVK,board_rev=14X14

findfdt 做的事情就是判斷,fdt_file 是否為undefined,如果fdt_file 為undefined 的話那就要根據(jù)板子信息得出所需的.dtb 文件名。此時fdt_file 為undefined,所以根據(jù)board_name 和board_rev 來判斷實際所需的.dtb 文件,如果board_name 為EVK 并且board_rev=9x9 的話fdt_file
就為imx6ull-9x9-evk.dtb。如果board_name 為EVK 并且board_rev=14x14 的話fdt_file 就設置為imx6ull-14x14-evk.dtb。因此IMX6ULL EVK 板子的設備樹文件就是imx6ull-14x14-evk.dtb,因此run findfdt 的結(jié)果就是設置fdt_file 為imx6ull-14x14-evk.dtb。

第206 行,mmc dev ${mmcdev}用于切換mmc 設備,mmcdev 為1,因此這行代碼就是:mmc dev 1,也就是切換到EMMC 上。

第207 行,先執(zhí)行mmc dev ${mmcdev}切換到EMMC 上,然后使用命令mmc rescan 掃描看有沒有SD 卡或者EMMC 存在,如果沒有的話就直接跳到216 行,執(zhí)行run netboot,netboot也是一個自定義的環(huán)境變量,這個變量是從網(wǎng)絡啟動Linux 的。如果mmc 設備存在的話就從mmc 設備啟動

第208 行,運行l(wèi)oadbootscript 環(huán)境變量,此環(huán)境變量內(nèi)容如下:

loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};

其中mmcdev=1,mmcpart=1,loadaddr=0x80800000,script= boot.scr,因此展開以后就是:

loadbootscript=fatload mmc 1:1 0x80800000 boot.scr;

loadbootscript 就是從mmc1 的分區(qū)1 中讀取文件boot.src 到DRAM 的0X80800000 處。但是mmc1 的分區(qū)1 中沒有boot.src 這個文件,可以使用命令“l(fā)s mmc 1:1”查看一下mmc1 分區(qū)1 中的所有文件,看看有沒有boot.src 這個文件。

第209 行,如果加載boot.src 文件成功的話就運行bootscript 環(huán)境變量,bootscript 的內(nèi)容如下:

bootscript=echo Running bootscript from mmc ...; source

因為boot.src 文件不存在,所以bootscript 也就不會運行。

第211 行,如果loadbootscript 沒有找到boot.src 的話就運行環(huán)境變量loadimage,環(huán)境變量loadimage 內(nèi)容如下:

loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}

其中mmcdev=1,mmcpart=1,loadaddr=0x80800000,image = zImage,展開以后就是:

loadimage=fatload mmc 1:1 0x80800000 zImage

可以看出loadimage 就是從mmc1 的分區(qū)中讀取zImage 到內(nèi)存的0X80800000 處,而mmc1的分區(qū)1 中存在zImage。

第212 行,加載linux 鏡像文件zImage 成功以后就運行環(huán)境變量mmcboot,否則的話運行netboot 環(huán)境變量。mmcboot 環(huán)境變量如下:

154 "mmcboot=echo Booting from mmc ...; " \ 155 "run mmcargs; " \ 156 "if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \ 157 "if run loadfdt; then " \ 158 "bootz ${loadaddr} - ${fdt_addr}; " \ 159 "else " \ 160 "if test ${boot_fdt} = try; then " \ 161 "bootz; " \ 162 "else " \ 163 "echo WARN: Cannot load the DT; " \ 164 "fi; " \ 165 "fi; " \ 166 "else " \ 167 "bootz; " \ 168 "fi;\0" \

第154 行,輸出信息“Booting from mmc …”。

第155 行,運行環(huán)境變量mmcargs,mmcargs 用來設置bootargs,后面分析bootargs 的時候在學習。

第156 行,判斷boot_fdt 是否為yes 或者try,根據(jù)uboot 輸出的環(huán)境變量信息可知boot_fdt=try。因此會執(zhí)行157 行的語句。

第157 行,運行環(huán)境變量loadfdt,環(huán)境變量loadfdt 定義如下:

loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}

展開以后就是:

loadfdt=fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb

因此loadfdt 的作用就是從mmc1 的分區(qū)1 中讀取imx6ull-14x14-evk.dtb 文件并放到0x83000000處。

第158 行,如果讀取.dtb 文件成功的話那就調(diào)用命令bootz 啟動linux,調(diào)用方法如下:

bootz ${loadaddr} - ${fdt_addr};

展開就是:

bootz 0x80800000 - 0x83000000 (注意‘-’前后要有空格)

至此Linux 內(nèi)核啟動,如此復雜的設置就是為了從EMMC 中讀取zImage 鏡像文件和設備樹文件。經(jīng)過分析,濃縮出來的僅僅是4 行精華:

mmc dev 1 //切換到EMMC fatload mmc 1:1 0x80800000 zImage //讀取zImage 到0x80800000 處 fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb //讀取設備樹到0x83000000 處 bootz 0x80800000 - 0x83000000 //啟動Linux

NXP 官方將CONFIG_BOOTCOMMAND 寫的這么復雜只有一個目的:為了兼容多個板子,所以寫了個很復雜的腳本。

當我們明確知道我們所使用的板子的時候就可以大幅簡化宏CONFIG_BOOTCOMMAND 的設置,比如我們要從EMMC 啟動,那么宏CONFIG_BOOTCOMMAND 就可簡化為:

#define CONFIG_BOOTCOMMAND \"mmc dev 1;" \"fatload mmc 1:1 0x80800000 zImage;" \"fatload mmc 1:1 0x83000000 imx6ull-alientek-emmc.dtb;" \"bootz 0x80800000 - 0x83000000;"

或者可以直接在uboot 中設置bootcmd 的值,這個值就是保存到EMMC 中的,命令如下:

setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'

環(huán)境變量bootargs(內(nèi)核傳參)

bootargs 保存著uboot 傳遞給Linux 內(nèi)核的參數(shù),在上一小節(jié)講解bootcmd 的時候說過,bootargs 環(huán)境變量是由mmcargs 設置的,mmcargs 環(huán)境變量如下:

mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}

其中console=ttymxc0,baudrate=115200,mmcroot=/dev/mmcblk1p2 rootwait rw,因此將mmcargs 展開以后就是:

mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw

可以看出環(huán)境變量mmcargs 就是設置bootargs 的值為“console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw”,bootargs 就是設置了很多的參數(shù)的值,這些參數(shù)Linux 內(nèi)核會使用到,常用的參數(shù)有:

1、console(控制臺)
console 用來設置linux 終端(或者叫控制臺),也就是通過什么設備來和Linux 進行交互,是串口還是LCD 屏幕?如果是串口的話應該是串口幾等等。一般設置串口作為Linux 終端,這樣我們就可以在電腦上通過SecureCRT 來和linux 交互了。這里設置console 為ttymxc0,因為linux啟動以后I.MX6ULL 的串口1 在linux 下的設備文件就是/dev/ttymxc0,在Linux 下,一切皆文件。

ttymxc0 后面有個“,115200”,這是設置串口的波特率,console=ttymxc0,115200 綜合起來就是設置ttymxc0(也就是串口1)作為Linux 的終端,并且串口波特率設置為115200。

2、root
root 用來設置根文件系統(tǒng)的位置,root=/dev/mmcblk1p2 用于指明根文件系統(tǒng)存放在mmcblk1 設備的分區(qū)2 中。
EMMC 版本的核心板啟動linux 以后會存在/dev/mmcblk0、
/dev/mmcblk1、/dev/mmcblk0p1、/dev/mmcblk0p2、/dev/mmcblk1p1 和/dev/mmcblk1p2 這樣的文件:

/dev/mmcblkx(x=0~ n)表示mmc 設備, /dev/mmcblkxpy(x=0~ n,y=1~n)表示mmc 設備x 的分區(qū)y。

在I.MX6U-ALPHA 開發(fā)板中/dev/mmcblk1 表示EMMC,而/dev/mmcblk1p2 表示EMMC 的分區(qū)2。

root 后面有“rootwait rw”,rootwait 表示等待mmc 設備初始化完成以后再掛載,否則的話mmc 設備還沒初始化完成就掛載根文件系統(tǒng)會出錯的。rw 表示根文件系統(tǒng)是可讀可寫的,不加rw 的話可能無法在根文件系統(tǒng)中進行寫操作,只能進行讀操作。

3、rootfstype
此選項一般配置root 一起使用,rootfstype 用于指定根文件系統(tǒng)類型,如果根文件系統(tǒng)為ext 格式的話此選項無所謂。如果根文件系統(tǒng)是yaffs、jffs 或ubifs 的話就需要設置此選項,指定根文件系統(tǒng)的類型。

bootargs 常設置的選項就這三個,后面遇到其他選項的話再講解。

uboot 啟動Linux 測試

uboot 已經(jīng)移植好了,bootcmd 和bootargs 這兩個重要的環(huán)境變量也講解了,接下來就要測試一下uboot 能不能完成它的工作:啟動Linux 內(nèi)核。
我們測試兩種啟動Linux 內(nèi)核的方法,一種是直接從EMMC 啟動,一種是從網(wǎng)絡啟動。

從EMMC 啟動Linux 系統(tǒng)

上面是手動方式一行一行命令實現(xiàn)的,下面的是使用環(huán)境變量命令自定執(zhí)行的。

從EMMC 啟動也就是將編譯出來的Linux 鏡像文件zImage 和設備樹文件保存在EMMC中,uboot 從EMMC 中讀取這兩個文件并啟動,這個是我們產(chǎn)品最終的啟動方式。

EMMC一共三個分區(qū):
第一個分區(qū):UBOOT
第二個分區(qū):zImage和.dtb設備樹(FAT文件系統(tǒng))
第三個分區(qū):根文件系統(tǒng)

但是我們目前還沒有講解如何移植linux 和設備樹文件,以及如何將zImage 和設備樹文件保存到EMMC中。不過大家拿到手的I.MX6U-ALPHA 開發(fā)板(EMMC 版本)已經(jīng)將zImage 文件和設備樹(.dtb)文件燒寫到了EMMC 中,所以我們可以直接讀取來測試。

設置從EMMC啟動:

mmc dev 1

檢查一下EMMC 的分區(qū)1 中有沒有zImage 文件和設備樹文件,輸入命令“l(fā)s mmc 1:1”,結(jié)果如圖33.4.1.1 所示:


從圖33.4.1.1 中可以看出,此時EMMC 分區(qū)1 中存在zimage 和imx6ull-alientek-emmc.dtb這兩個文件,所以我們可以測試新移植的uboot 能不能啟動linux 內(nèi)核。

設置bootargs 和bootcmd這兩個環(huán)境變量,設置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;' saveenv

設置好以后直接輸入boot,或者run bootcmd 即可啟動Linux 內(nèi)核,如果Linux 內(nèi)核啟動成功的話就會輸出如圖33.4.1.2 所示的啟動信息:

從網(wǎng)絡啟動Linux 系統(tǒng)

從網(wǎng)絡啟動linux 系統(tǒng)的唯一目的就是為了方便調(diào)試!不管是為了調(diào)試linux 系統(tǒng)還是linux 下的驅(qū)動。每次修改linux 系統(tǒng)文件或者linux 下的某個驅(qū)動以后都要將其燒寫到EMMC 中去測試,這樣太麻煩了。

我們可以設置linux 從網(wǎng)絡啟動,也就是將linux 鏡像文件和根文件系統(tǒng)都放到Ubuntu 下某個指定的文件夾中,這樣每次重新編譯linux 內(nèi)核或者某個linux 驅(qū)動以后只需要使用cp 命令將其拷貝到這個指定的文件夾中即可,這樣就不用需要頻繁的燒寫EMMC,這樣就加快了開發(fā)速度。

我們可以通過nfs 或者tftp 從Ubuntu 中下載zImage 和設備樹文件,根文件系統(tǒng)的話也可以通過nfs 掛載,不過本小節(jié)我們不講解如何通過nfs 掛載根文件系統(tǒng),這個在講解根文件系統(tǒng)移植的時候再講解。這里我們使用tftp 從Ubuntu 中下載zImage 和設備樹文件,前提是要將zImage 和設備樹文件放到Ubuntu 下的tftp 目錄中,具體方法在30.4.4 小節(jié)講解tftp 命令的時候已經(jīng)詳細的介紹過了。

設置bootargs 和bootcmd 這兩個環(huán)境變量,設置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000' saveenv

一開始是通過tftp 下載zImage 和imx6ull-alientek-emmc.dtb 這兩個文件,過程如下圖33.4.2.1所示:

下載完成以后就是啟動Linux 內(nèi)核,啟動過程如圖33.4.2.2 所示:

DDR初始化參數(shù)修改



具體校準方法參照前面裸機部分。

總結(jié)

uboot 移植到此結(jié)束,簡單總結(jié)一下uboot 移植的過程:

①、不管是購買的開發(fā)板還是自己做的開發(fā)板,基本都是參考半導體廠商的dmeo 板,而半導體廠商會在他們自己的開發(fā)板上移植好uboot、linux kernel 和rootfs 等,最終制作好BSP包提供給用戶。我們可以在官方提供的BSP 包的基礎上添加我們的板子,也就是俗稱的移植。
②、我們購買的開發(fā)板或者自己做的板子一般都不會原封不動的照抄半導體廠商的demo板,都會根據(jù)實際的情況來做修改,既然有修改就必然涉及到uboot 下驅(qū)動的移植。
③、一般uboot 中需要解決串口、NAND、EMMC 或SD 卡、網(wǎng)絡和LCD 驅(qū)動,因為uboot的主要目的就是啟動Linux 內(nèi)核,所以不需要考慮太多的外設驅(qū)動。
④、在uboot 中添加自己的板子信息,根據(jù)自己板子的實際情況來修改uboot 中的驅(qū)動。

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的U-Boot 移植的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。