赞
踩
选项 | 内容 |
---|---|
编译主机 | UbuntuLTS 16.04 |
目标板 | ATK I.MX6ULL- Mini (512MB DDR3 + 8GB EMMC) |
移植的u-boot版本 | 2021.01 [下载地址] |
交叉编译工具 | arm-linux-gnueabihf-gcc 6.5.0 [下载地址] |
注:如果移植过程有不懂的步骤可以先看这篇文章:[点击跳转]
查看configs目录下有2个关于mx6ull的单板配置:
mx6ull_14x14_evk_defconfig
mx6ull_14x14_evk_plugin_defconfig
这里选用mx6ull_14x14_evk_defconfig
,所以u-boot整个编译步骤如下:
tar xjvf packet/u-boot-2021.01.tar.bz2
cd u-boot-2021.01/
make mx6ull_14x14_evk_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
编译后得到u-boot-dtb.imx
文件,将它烧写查看是否能正常使用,烧录的方法有多种,其中就包含使用官方的Mfgtools工具和u-boot的自我更新。这里推荐使用官方工具,因为如果移植的uboot网卡没有配置好的话就用不了tftp等下载命令。
对于imx6ull,烧录的脚本是mfgtool2-yocto-mx-evk-emmc.vbs
,其中烧录的文件对应于mfgtools\Profiles\Linux\OS Firmware\files
目录下的几个文件:
u-boot-imx6ull14x14evk_emmc.imx
zImage
zImage-imx6ull-14x14-evk-emmc.dtb
rootfs_nogpu.tar.bz2
这里将编译后得到的u-boot-dtb.imx
文件重命名为u-boot-imx6ull14x14evk_emmc.imx
替换进去即可烧录。
烧录后查看现象:
U-Boot 2021.01-ge963177 (Mar 16 2021 - 21:52:11 +0800) CPU: Freescale i.MX6ULL rev1.1 792 MHz (running at 396 MHz) CPU: Industrial temperature grade (-40C to 105C) at 44C Reset cause: POR Model: Freescale i.MX6 UltraLiteLite 14x14 EVK Board Board: MX6ULL 14x14 EVK DRAM: 512 MiB MMC: FSL_SDHC: 0, FSL_SDHC: 1 Loading Environment from MMC... *** Warning - bad CRC, using default environment In: serial Out: serial Err: serial Net: Could not get PHY for FEC1: addr 1 Could not get PHY for FEC1: addr 1 Could not get PHY for FEC0: addr 2 Could not get PHY for FEC0: addr 2 No ethernet found. Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc1(part 0) is current device switch to partitions #0, OK mmc1(part 0) is current device Failed to load 'boot.scr' 5582616 bytes read in 239 ms (22.3 MiB/s) Booting from mmc ... 38376 bytes read in 4 ms (9.1 MiB/s) Kernel image @ 0x82000000 [ 0x000000 - 0x552f18 ] ## Flattened Device Tree blob at 83000000 Booting using the fdt blob at 0x83000000 Using Device Tree in place at 83000000, end 8300c5e7 Starting kernel ... // .... Welcome to imx6ull! imx6ull login: root Password: [root@imx6ull]:~#
可以看到CPU、Board、DRAM、MMC都能正确识别了,而且最最重要的——启动内核也是正常的。如果看到Starting kernel ...
字样之后就没有往下走,那首先知道的一点就是u-boot是可以启动内核的了,只是环境变量可能没有设置正确,参考的设置如下:
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'fatload mmc 1:1 80800000 zImage;fatload mmc 1:1 83000000 imx6ull-14x14-evk.dtb;bootz 80800000 - 83000000'
saveenv
uboot具体命令参考:u-boot:常用命令解释
复位重新进入u-boot检验一下设备:
=> mmc rescan => => mmc list FSL_SDHC: 0 (SD) FSL_SDHC: 1 (eMMC) => mmc dev 0 switch to partitions #0, OK mmc0 is current device => => mmc info Device: FSL_SDHC Manufacturer ID: 83 OEM: 4e43 Name: NCard Bus Speed: 50000000 Mode: SD High Speed (50MHz) Rd Block Len: 512 SD version 3.0 High Capacity: Yes Capacity: 14.9 GiB Bus Width: 4-bit Erase Group Size: 512 Bytes => => mmc dev 1 switch to partitions #0, OK mmc1(part 0) is current device => => mmc info Device: FSL_SDHC Manufacturer ID: 15 OEM: 100 Name: 8GTF4 Bus Speed: 52000000 Mode: MMC High Speed (52MHz) Rd Block Len: 512 MMC version 5.1 High Capacity: Yes Capacity: 7.3 GiB Bus Width: 4-bit Erase Group Size: 512 KiB HC WP Group Size: 8 MiB User Capacity: 7.3 GiB WRREL Boot Capacity: 4 MiB ENH RPMB Capacity: 512 KiB ENH Boot area 0 is not write protected Boot area 1 is not write protected =>
可以看到SD卡和mmc存储都能够正常识别。
根据启动的打印可以看到以下几句:
Net: Could not get PHY for FEC1: addr 1
Could not get PHY for FEC1: addr 1
Could not get PHY for FEC0: addr 2
Could not get PHY for FEC0: addr 2
No ethernet found.
说明网卡还是不能工作。去源码里grep -rn "Could not get PHY for" ./
找一下打印位置,发现在drivers/net/phy/phy.c
文件的phy_connect
函数中,而如果往回追踪它的调用,就会发现它的其中一个调用关系如下:
U_BOOT_DRIVER(fecmxc_gem) /* drivers/net/fec_mxc.c */
.probe = fecmxc_probe,
fec_phy_init
phy_connect /* drivers/net/phy/phy.c */
...
printf("Could not get PHY for %s: addr %d\n", bus->name, addr);
从U_BOOT_DRIVER
关键字也可以知道它是一个驱动(uboot做得越来越像linux了),具体地说它是imx6ull的MAC驱动(使用的是目前较流行的“内置MAC控制器”+“外置PHY芯片”方案,硬件说明),它同样也是支持dts的方式来匹配的,dts文件就在arch/arm/dts/
目录下。
首先先考虑dts节点有没有正确配置,对于Mini开发板的网卡,只引出了一个ENET2,那就参考移植Linux-4.20.9的网卡部分,首先将fec1(ENET1)屏蔽掉:
/* */ /* &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>; phy-mode = "rmii"; phy-handle = <ðphy0>; status = "okay"; }; */ &fec2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet2>; phy-mode = "rmii"; phy-handle = <ðphy1>; status = "okay"; mdio { #address-cells = <1>; #size-cells = <0>; /* ethphy0: ethernet-phy@2 { reg = <2>; micrel,led-mode = <1>; clocks = <&clks IMX6UL_CLK_ENET_REF>; clock-names = "rmii-ref"; }; */ ethphy1: ethernet-phy@1 { reg = <1>; micrel,led-mode = <1>; clocks = <&clks IMX6UL_CLK_ENET2_REF>; clock-names = "rmii-ref"; }; }; };
此时肯定也还启动不了,因为这并不影响驱动程序的流程,这里只是把用不上的ENET1去掉而已。所以还是简单分析probe函数。其中,在获取时钟之后,看到有那么几句话:
#if CONFIG_IS_ENABLED(DM_GPIO)
fec_gpio_reset(priv);
#endif
在默认配置中也定义了CONFIG_DM_GPIO=y
,而fec_gpio_reset(priv);
函数里面要用到reset引脚,但是dts中没有配置,所以参考linux内核的配置继续修改:
&fec2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_reset>; /* 添加引脚配置 */ phy-mode = "rmii"; phy-handle = <ðphy1>; phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; /* 根据硬件连接进行添加 */ phy-reset-duration = <26>; /* 复位时间,单位ms */ status = "okay"; ... // 省略 }; /* pinctrl引脚配置 */ pinctrl_spi4: spi4grp { fsl,pins = < MX6UL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1 MX6UL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1 MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1 //MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000 /* 把重复使用的去掉 */ >; }; /* 复位引脚配置 */ pinctrl_enet2_reset: enet2resetgrp { fsl,pins = < MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0 >; };
重新烧写查看现象。这时,关于网络部分的打印发生了变化:
Net:
Error: ethernet@20b4000 address not set.
Error: ethernet@20b4000 address not set.
No ethernet found.
那就继续grep -rn "address not set"
,找到在net/eth-uclass.c
文件中的eth_post_probe
函数打印的,简单看下函数内容:
static int eth_post_probe(struct udevice *dev) { ... /* Check if the device has a valid MAC address in device tree */ if (!eth_dev_get_mac_address(dev, pdata->enetaddr) || !is_valid_ethaddr(pdata->enetaddr)) ... eth_env_get_enetaddr_by_index("eth", dev->seq, env_enetaddr); if (!is_zero_ethaddr(env_enetaddr)) { ... /* Override the ROM MAC address */ memcpy(pdata->enetaddr, env_enetaddr, ARP_HLEN); } else if (is_valid_ethaddr(pdata->enetaddr)) { eth_env_set_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); } else if (is_zero_ethaddr(pdata->enetaddr) || !is_valid_ethaddr(pdata->enetaddr)) { #ifdef CONFIG_NET_RANDOM_ETHADDR net_random_ethaddr(pdata->enetaddr); printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", dev->name, dev->seq, pdata->enetaddr); #else printf("\nError: %s address not set.\n", dev->name); return -EINVAL; #endif } eth_write_hwaddr(dev); ... };
通过上面也可以知道这是由于没有设置MAC地址导致的,其中eth_dev_get_mac_address
函数是通过读取dts来获取MAC地址:
static bool eth_dev_get_mac_address(struct udevice *dev, u8 mac[ARP_HLEN])
{
...
p = dev_read_u8_array_ptr(dev, "mac-address", ARP_HLEN);
if (!p)
p = dev_read_u8_array_ptr(dev, "local-mac-address", ARP_HLEN);
...
}
而其他还可以支持从环境变量中获取、随机生成(需要配置CONFIG_NET_RANDOM_ETHADDR=y
)等方式。这里还是在直接在uboot命令行里面设置吧,比较快捷方便:
setenv eth1addr 12:34:56:78:9a:bc # 这里是eth1addr,不是ethaddr,因为后面步骤它打印的是eth1
saveenv
保存之后重启,查看现象:
Net: eth1: ethernet@20b4000 [PRIME]
能识别出来了,那就配置一下其他网络信息:
setenv ipaddr 192.168.1.123
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.234
saveenv
然后执行一些ping 192.168.10.234
(该IP地址真实存在),但是会发现并不能工作。注意,因为这里使用的PHY芯片是SMSC公司生产的LAN8720A,而uboot默认自带的是Micrel生产的KSZ804,所以根据.config
文件去make menuconfig
将CONFIG_PHY_MICREL
和CONFIG_PHY_MICREL_KSZ8XXX
去掉,将CONFIG_PHY_SMSC
配置上去,因为drivers/net/phy/smsc.c
中已经包含了LAN8720A的驱动程序,这样才确保uboot能够使用LAN8720A这款PHY芯片(其实uboot里也像linux一样包含了通用的PHY驱动,但不保证能驱动起来)。
配置完成之后重新启动,配置好MAC地址和ip地址之后执行ping测试。啪,打脸了,还是不行…
最后在正点原子的手册里面就说了PHY驱动程序有些问题,将这段代码添加进去,针对于LAN8720进行特殊处理:
--- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -224,6 +224,21 @@ int genphy_update_link(struct phy_device *phydev) { unsigned int mii_reg; +#ifdef CONFIG_PHY_SMSC + static int lan8720_flag = 0; + int bmcr_reg = 0; + + if (lan8720_flag == 0) { + bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) { + udelay(100); + } + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg); + lan8720_flag = 1; + } +#endif + /* * Wait if the link is up, and autonegotiation is in progress * (ie - we're capable and it's not done)
重新编译启动,执行ping测试:
=> ping 192.168.1.234
ethernet@20b4000 Waiting for PHY auto negotiation to complete.... done
Using ethernet@20b4000 device
host 192.168.1.234 is alive
=>
大功告成!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。