【移植02】修改移植`FSL Yocto Project Community BSP`用到的u-boot源码,使其能适配百问网(100ask)的开发板

前言

在博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145547974 中,我们利用官方提供的BSP(FSL Yocto Project Community BSP)构建了写到SD卡中的完整镜像,然后启动后发现存在不少问题,首要的问题就是u-boot不能识别网卡,在这篇博文中,我们就找到FSL Yocto Project Community BSP用到的u-boot源码,然后进行修改适配。

配置gcc交叉编译器

由于后面我们要自己去对自己修改后的u-boot进行编译,所以需要有gcc交叉编译器。

Buildroot在构建完之后能生成gcc交叉编译器,详情见 https://blog.youkuaiyun.com/wenhao_ir/article/details/145470042 【搜索“生成交叉编译工具链”】。

Ycoto在构建时也能生成,但是由于这里在配置时没有配置生成gcc交叉编译器,所以这里就只有自己去手动操作了。

为了减少这篇博文的长度,所以具体的gcc交叉编译器的下载和配置见下面博文:https://blog.youkuaiyun.com/wenhao_ir/article/details/145649698

找到u-boot源码

从博文https://blog.youkuaiyun.com/wenhao_ir/article/details/145547974构建的完整的SD卡镜像的运行情况来看,公板MCIMX6ULL-EVK(imx6ull14x14evk)的u-boot是不适应百问网的板子,主要就是网卡有问题,我们需要进行修改…

我们需要在FSL Yocto Project Community BSP中找到u-boot源码…

我们需要在在FSL Yocto Project Community BSP中找到对应的仓库地址,然后拉取到本地。

具体方法如下:

由于我们之前的镜像选择的是imx-image-multimedia,Yocto对应的层如下面这个列表:
在这里插入图片描述
所以我们需要在目录/imx-yocto-bsp/sources/meta-imx/中去找其对应的仓库地址信息。打开下面这个文件:

/imx-yocto-bsp/sources/meta-imx/meta-bsp/recipes-kernel/linux/linux-imx_5.4.bb

我们能找到meta-imx层对应的liunx的源码仓库地址:
在这里插入图片描述

git://source.codeaurora.org/external/imx/linux-imx.git

据此,我们可以推断出其u-boot源码的仓库地址为:

https://source.codeaurora.org/external/imx/uboot-imx

如果这个源还有效的话,运行下面的命令就能将u-boot的源码下载下来了:

git clone https://source.codeaurora.org/external/imx/uboot-imx

但很可惜这个源已经无效了,证据如下:

curl https://source.codeaurora.org/

在这里插入图片描述
上面的截图是美国的服务器上运行的,说明是真失效了,那就只有用百问网提供的之前通过仓库地址下载好的u-boot源码了。百度网盘下载链接:https://pan.baidu.com/s/1YgJPge5JMOf2HkKm_gQB7Q?pwd=ytut

下载好之后,先放在那里备用。
在这里插入图片描述

编译找到的u-boot源码

将上一步得到的u-boot的源码复制到Ubuntu中:
在这里插入图片描述
然后解压出来:
在这里插入图片描述
在这里插入图片描述
终端中进入目录/home/book/mybuild/uboot-imx

cd /home/book/mybuild/uboot-imx

不妨先执行一次清除命令:

make distclean

在这里插入图片描述
然后给文件check-config.sh添加执行权限

chmod +x ./scripts/check-config.sh

接着我们需要去查看下有哪些配置文件,配置文件在目录/uboot-imx/configs下:
在这里插入图片描述
可以看到文件非常多,不妨搜索一下关键词mx6ull_14x14_evk*
在这里插入图片描述
上面截图中的几个配置文件介绍如下:

  • mx6ull_14x14_evk_defconfig:imx6ullevk公板默认的配置文件,默认只支持SD卡启动。
  • mx6ull_14x14_evk_emmc_defconfig:支持eMMC启动方式启动的配置文件。
  • mx6ull_14x14_evk_nand_defconfig:支持NAND启动方式启动的配置文件。
  • mx6ull_14x14_evk_optee_defconfig:支持 optee 系统的配置文件。
  • mx6ull_14x14_evk_plugin_defconfig:支持扩展功能的配置文件,主要是烧写功能。
  • mx6ull_14x14_evk_qspi1_defconfig:支持 qspi 启动方式启动的配置文件。

我们这里选择支持eMMC启动方式的配置文件: mx6ull_14x14_evk_emmc_defconfig,运行下面的命令选择这个配置文件:

make mx6ull_14x14_evk_emmc_defconfig

在这里插入图片描述
然后执行下面的命令开始构建编译:

make -j4

命令中的4代表使用4个线程进行编译,当然,如果你的CPU资源够多,可以调大,比如调到68
在这里插入图片描述
编译很快就结束了,u-boot毕竟只是很短的代码。
在这里插入图片描述
从上面的运行结果来看,已经生成了我们想要的u-boot镜像文件u-boot-dtb.imx,现在我们把它写入到eMMC中,然后通eMMC方式来运行u-boot。

镜像文件u-boot-dtb.imx的位置就是在u-boot的根目录下:
在这里插入图片描述
上面这个u-boot镜像的百度网盘下载地址:
https://pan.baidu.com/s/1rmyO7zWG4oDP8neWJtvWjQ?pwd=9d28

u-boot镜像文件烧写到eMMC中

参考下面这篇博文把生成的u-boot镜像文件u-boot-dtb.imx烧写到eMMC中:
https://blog.youkuaiyun.com/wenhao_ir/article/details/145653414

此时我准备烧写的u-boot镜像的百度网盘下载地址:
https://pan.baidu.com/s/1rmyO7zWG4oDP8neWJtvWjQ?pwd=9d28

运行烧写到eMMC中的u-boot并分析运行结果

烧写完成后关闭开发板电源,
烧写完成后关闭开发板电源,
烧写完成后关闭开发板电源,

然后设置开发板为eMMC启动方式,打开串口即可看到终端有u-boot的运行信息了。

在这里插入图片描述
u-boot的运行信息如下:



U-Boot 2020.04-dirty (Feb 15 2025 - 16:43:33 +0800)

CPU:   i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
CPU:   Industrial temperature grade (-40C to 105C) at 31C
Reset cause: POR
Model: i.MX6 ULL 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

[*]-Video Link 0 (480 x 272)
        [0] lcdif@21c8000, video
In:    serial
Out:   serial
Err:   serial
switch to partitions #0, OK
mmc1(part 0) is current device
flash target is MMC:1
Net:   Could not get PHY for FEC1: addr 1
Could not get PHY for FEC1: addr 1
Get shared mii bus on ethernet@2188000
Could not get PHY for FEC1: addr 2
Get shared mii bus on ethernet@2188000
undefined instruction
pc : [<00000084>]          lr : [<9ef9bdaf>]
reloc pc : [<e8888084>]    lr : [<87823daf>]
sp : 9df6d6b8  ip : 00000020     fp : 87800020
r10: 9df955c0  r9 : 9df75ed0     r8 : 9df774b8
r7 : 9df77458  r6 : 00000006     r5 : 00000004  r4 : 9df78748
r3 : 00000048  r2 : 00000006     r1 : 00000004  r0 : 9df78748
Flags: nzCv  IRQs off  FIQs off  Mode SVC_32
Code: 00000000 00000000 00000000 00000011 (79706f43) 
Resetting CPU ...

resetting ...


U-Boot 2020.04-dirty (Feb 15 2025 - 16:43:33 +0800)

CPU:   i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
CPU:   Industrial temperature grade (-40C to 105C) at 32C
Reset cause: POR
Model: i.MX6 ULL 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

[*]-Video Link 0 (480 x 272)
        [0] lcdif@21c8000, video
In:    serial
Out:   serial
Err:   serial
switch to partitions #0, OK
mmc1(part 0) is current device
flash target is MMC:1
Net:   
Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.
FEC: can't find phy-handle

Error: ethernet@20b4000 address not set.
Could not get PHY for FEC0: addr 2

Error: ethernet@20b4000 address not set.
FEC: can't find phy-handle

Error: ethernet@20b4000 address not set.
Could not get PHY for FEC0: addr 2
No ethernet found.

Fastboot: Normal
Normal Boot
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
** Unrecognized filesystem type **
** Unrecognized filesystem type **
Booting from net ...

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.
FEC: can't find phy-handle

Error: ethernet@20b4000 address not set.
Could not get PHY for FEC0: addr 2

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.
No ethernet found.

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.
FEC: can't find phy-handle

Error: ethernet@20b4000 address not set.
Could not get PHY for FEC0: addr 2

Error: ethernet@20b4000 address not set.

Error: ethernet@20b4000 address not set.
No ethernet found.

Error: ethernet@20b4000 address not set.
zimage: Bad magic!
=> 

通过串口终端打印信息可以看出:
uboot 在第一次运行时发生未定义指令异常错误导致uboot自动复位,截图如下:
在这里插入图片描述
结合第二次运行到同样位置时输出Booting from net ...
在这里插入图片描述
我的推测如下:
第一次启动时,U-Boot尝试从MMC或SD卡加载内核镜像,但由于找不到有效的内核镜像,导致了undefined instruction错误。第二次启动时,U-Boot通过网络方式启动内核(Booting from net …),所以没有了第一次的错误。

整个过程中,可以很明显的看出还是网卡的问题,这和我们之前在SD卡中烧写的完整镜像中的u-boot是一样的,所以问题是一样的,所以我们当务之急是要解决网卡的问题。

当网卡的问题解决后,我们还可以使用tftp运行内核,并使用网络文件系统NFS挂载文件系统。

所以,现在就去解决网卡的问题吧。

对比公板和开发板的原理图

公板的以太网实现的原理图及相关引脚分析

关于什么叫以太网,详情见 https://blog.youkuaiyun.com/wenhao_ir/article/details/145691255
从上面这篇博文我们可以看出,以太网的主体是MAC层和物理层,而我们这篇博文涉及到的就是MAC(以太网控制器)与物理层芯片的连接,所以本篇博文我们称我们实现的东西为以太网。

这部分内容很多,所以专门写了一篇博文,链接如下:
https://blog.youkuaiyun.com/wenhao_ir/article/details/145663029

开发板的以太网实现的原理图及相关引脚分析

开发板的原理图的百度网盘下载链接:
https://pan.baidu.com/s/1YUfqZyXACwuNiYB_i5uzSw?pwd=thxh

这部分内容也很多,所以专门写了一篇博文,链接如下:
https://blog.youkuaiyun.com/wenhao_ir/article/details/145699423

开发板与公板不一样而导致要改代码地方

经过在上面两篇博文中仔细分析:发丙两个不同的地方是:

①复位信号来源不一样。
②两个以太网对应的物理层芯片的PHY地址不一样。

具体怎么个不一样法,详情见博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145699423 【搜索“与公板不一样而导致要改代码地方”】

知道了不同的地方后就可以开始改了。

在VScode中打开u-boot的源码

在这里插入图片描述
在这里插入图片描述

修改u-boot使其能实始化成功开发板上的以太网2

修改配置文件configs\mx6ul_14x14_evk_defconfig

文件configs\mx6ul_14x14_evk_defconfig是配置SD卡启动方式的配置文件。

打开文件configs\mx6ul_14x14_evk_defconfig,跳转到第49行:
在这里插入图片描述
把第49行和第50行:

CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ8XXX=y

替换为下面的内容:

CONFIG_PHY_SMSC=y

改好之后的截图如下:
在这里插入图片描述
CONFIG_PHY_SMSC=y这句话的解释如下:

详细解析:

  • CONFIG_PHY_SMSC=y:这条配置项表明,U-Boot 在编译时会启用对 SMSC PHY 驱动的支持。PHY(Physical Layer)是以太网硬件层的一部分,主要负责在物理媒介(如电缆)和高层协议之间传输数据。

    • SMSC PHY 指的是由 SMSC(现在是 Microchip 公司的一个子公司)生产的 PHY 芯片。SMSC 提供了一系列以太网控制器和 PHY 芯片,通常用于嵌入式系统中,以实现网络通信功能。

    • 启用此选项后,U-Boot 会在启动过程中初始化和配置这个 PHY,以便正确地与以太网设备进行通信。

具体作用:

  • 启用 SMSC PHY 驱动:当 U-Boot 启动时,它会初始化 PHY 驱动程序,以确保以太网硬件的物理层能够与上层能正确配合。
  • 配置网络功能:启用此配置后,U-Boot 可以通过网络接口(如以太网)进行更多的操作,比如网络引导(TFTP)或加载文件。

如果没有这个配置,U-Boot 可能无法识别或配置 SMSC PHY 芯片,导致无法正常使用网络接口。

适用场景:

  • 如果你的硬件板子使用了 SMSC PHY 芯片,那么就需要启用这个选项,确保网络功能能够正常工作。

百问网的开发板的物理层芯片LAN8720A的确是 Microchip 公司的,所以咱们这里通过这个设置项启用对 SMSC PHY 驱动的支持。
该芯片旧版的Date sheet的截图如下:
在这里插入图片描述
该芯片新版的Date sheet如下:
在这里插入图片描述
可见,的确是Microchip收购买了SMSC这个公司。

u-boot自身是支持很多处理器芯片以及很多物理层芯片的

从这个修改我们还可以看出,u-boot自身是支持很多处理器芯片以及很多物理层芯片的。

修改配置文件configs\mx6ul_14x14_evk_emmc_defconfig

文件configs\mx6ul_14x14_evk_emmc_defconfig`是配置eMMC启动方式的配置文件。

和文件configs\mx6ul_14x14_evk_defconfig的修改一模一样:

把第49行和第50行:

CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ8XXX=y

替换为下面的内容:

CONFIG_PHY_SMSC=y

改好之后的截图如下:
在这里插入图片描述

两个配置文件的区别

文件configs\mx6ul_14x14_evk_defconfig和文件configs\mx6ul_14x14_evk_emmc_defconfig有何区别?

答案如下:
文件configs\mx6ul_14x14_evk_defconfig是配置SD卡启动方式的配置文件。
文件configs\mx6ul_14x14_evk_emmc_defconfig`是配置eMMC启动方式的配置文件。

修改设备树文件arch\arm\dts\imx6ul-14x14-evk.dtsi

这里只需要以太网2,所以禁用以太网1

我们让u-boot支持网络是为了利用u-boot支持的TFTP将内核下载到我们的eMMC中,所以在u-boot运行的阶段,我们只需要有一个网口能用就是了,这里我们用以太网2,而不用以太网1。

u-boot也有类似于Linux系统的设备树文件,所以我们修改u-boot的设备树文件实现这一点。

以下是修改设备树文件,实现禁用以太网1。
打开设备树文件arch\arm\dts\imx6ul-14x14-evk.dtsi,转到86行:
在这里插入图片描述
把86行的代码由:

status = "okay";

改为:

status = "disabled";

改好之后的截图如下:
在这里插入图片描述
这样就把以太网1给禁用了。

设置复位信号的产生引脚,设置复位过程的持续时间

然后之前我们已经在博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145699423 中分析出了,复位信号的产生不一样,在百问网的开发板中,物理层的芯片的复位信号接收引脚是连接到处理器的 SNVS_TAMPER6引脚的,的,我们可以让IMX6ULL的信号GPIO5_IO6路由到引脚 SNVS_TAMPER6,进而产生复位信号。

在设备树对设备的描述中,还有一个问题我们需要知道,那就是复位过程需要多久的时间?这就需要查阅物理层芯片LAN8720的Data sheet了。
物理层芯片LAN8720的Data sheet的百度网盘下载地址如下:
https://pan.baidu.com/s/1ZCVbzF2QH1SYCKOtnvSUWg?pwd=7i7a

关于复位过程需要多久的时间,我在博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145749489 中进行了详细分析,实际上就是时间tpurstd的最小值加1,我在博文中分析出了,即26毫秒。

根据上面这两点,我们就可以继续修改u-boot的设备树文件了。

打开设备树文件arch\arm\dts\imx6ul-14x14-evk.dtsi
94行左右加入下面的语句:

	phy-reset-gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
	phy-reset-duration = <26>;

加好之后的截图如下:
在这里插入图片描述

设置两个以太网的物理层芯片的地址

因为前面已经禁用了u-boot初始化以太网1,所以其实这里可以只设置以太网2的物理层芯片地址,但是我还是把两个都设置了吧,也就是几行代码的事。

在博文https://blog.youkuaiyun.com/wenhao_ir/article/details/145699423中我们已经分析了以太网1对应的物理层芯片的PHY地址为0,以太网1对应的物理层芯片的PHY地址为2。而公板中以太网1对应的物理层芯片的PHY地址为2,以太网2对应的物理层芯片的PHY地址为1。

另外还要知道,在u-boot中,把以太网1称为叫ethphy0、把以太网2称为叫ethphy1。

据此我们对u-boot修改如下。

打开u-boot的源码文件arch\arm\dts\imx6ul-14x14-evk.dtsi

找到103行左右的代码:

	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";
		};
	};

在这里插入图片描述
从上面这段代码中,我们可以看到,公板中的以太网1(ethphy0)使用的PHY地址为2,而以太网2(ethphy1)使用的PHY地址为1,这与我们之前的分析是吻合的。

现在我们百问网的开发板中,以太网1(ethphy0)使用的PHY地址为0,以太网2(ethphy1)使用的PHY地址为1,所以改为下面这样。

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@2 {
			reg = <0>;
			//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";
		};
	};

在这里插入图片描述
这样,就把两块物理层芯片的PHY地址设置好了,虽然这里没有使用以太网1(ethphy0),但我还是顺便给它改好了。

设置GPIO5_IO06的属性

打开u-boot的源码文件arch\arm\dts\imx6ul-14x14-evk.dtsi,翻到第406行代码左右:

	pinctrl_lcdif_ctrl: lcdifctrlgrp {
		fsl,pins = <
			MX6UL_PAD_LCD_CLK__LCDIF_CLK	    0x79
			MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79
			MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79
			MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79
			/* used for lcd reset */
			MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09  0x79
		>;
	};

在这里插入图片描述
在这里添加下面这行代码:

			MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06 0x79

添加之后的截图如下:
在这里插入图片描述
在这里,为什么配置值为0x79,我猜想这是u-boot的代码定义的,这个配置值会被分解成各个寄存器需要的配置值,然后去配置相关的寄存器。

以下是一种分解猜想(注意:只是一种分解猜想,并不代表真实情况):

  • 0x79 = 0111 1001(二进制)

每一位可以对应以下含义:

  1. 功能选择(前 3 位)
  • 011(前 3位)表示该引脚的复用功能。通常这些位指定该引脚的工作功能,比如是否作为GPIO、I2C、UART等。
    • 011 表示该引脚配置为 GPIO功能(具体取决于映射表,通常是GPIO模式)。
  1. 输入输出类型(接下来的 1 位)
  • 1(第 4 位)表示 推挽输出
    • 推挽输出意味着该引脚的电流方向可以在高电平和低电平之间切换。
  1. 电平驱动能力(接下来的 1 位)
  • 1(第 5 位)表示该引脚的驱动能力为 高驱动能力
    • 高驱动能力可以确保该引脚能够提供较高的输出电流。
  1. 上拉/下拉电阻(接下来的 2 位)
  • 00(第 6 和第 7 位)表示没有配置上拉/下拉电阻。
    • 00 通常表示 无上拉/下拉电阻(即浮空输入)。
  1. 输出电平(接下来的 1 位)
  • 1(第 8 位)表示该引脚是 输出
    • 这个配置保证该引脚在硬件上是一个输出引脚。

注意:以上只是一种分解猜想,并不代表真实情况。

另外,还要注意为什么是在对lcd的引脚控制中去初始化这个GPIO口,你要这样想,干嘛去认那个死理呢,在lcd的引脚控制中去初始化这个GPIO口不还是能达到我们初始化它的目的吗?

对软复位函数phy_reset()的完善

在百问网提供的教程和代码中,还对u-boot的文件drivers\net\phy\phy.c中的软复位函数phy_reset进行了修改完善。

在进行完善前,我们需要先了解下面两个知识点:

①首先我们要了解下物理层芯片LAN8720A的软复位操作的相关知识,这一点我写在另外的博文中了,链接为 https://blog.youkuaiyun.com/wenhao_ir/article/details/145749489 【搜索关键词“物理层芯片LAN8720A的软复位操作”】

②了解了物理层芯片LAN8720A的软复位操作的相关知识后,你还需要知道物理层芯片LAN8720A的软复位操作可能存在的异常是什么?解决方法是什么?关于这些,仍然请看我的另一篇博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145749489 【搜索关键词“软复位操作中存在的异常情况及解决方法”】

了解了上面的两个知识点后:我们再来看百问网教程中提供的对软复位函数phy_reset()的完善是怎么操作的。

百问网教程中提供的对软复位函数phy_reset()的完善方法如下:

打开文件 \uboot-imx\drivers\net\phy\phy.c

然后搜索genphy_config_aneg,跳转到函数phy_reset()所在的大约863行或874处:
在这里插入图片描述
在while循环中的代码:

reg = phy_read(phydev, devad, MII_BMCR);

的前面加上下面这两行代码:

	    phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
		udelay(1000);

修改之后的代码如下:
在这里插入图片描述
所以while循环就变成了下面的代码:

	while ((reg & BMCR_RESET) && timeout--) {
	    phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
		udelay(1000);

		reg = phy_read(phydev, devad, MII_BMCR);

		if (reg < 0) {
			debug("PHY status read failed\n");
			return -1;
		}
		udelay(1000);
	}

这段代码的解释如下:

这段代码是 PHY 复位操作 中的一个循环部分,主要用于监控 基本控制寄存器(BMCR) 中的 复位位(BMCR_RESET),直到复位完成或者超时。下面是对这段代码的详细解释:

  1. while 循环条件
while ((reg & BMCR_RESET) && timeout--) {
  • reg & BMCR_RESET:这是在检查 BMCR_RESET 位 是否仍然为 1,表示 PHY 是否仍在复位过程中。如果该位为 1,表示 PHY 还在复位中,循环会继续。
  • timeout--:这是一个超时机制,timeout 初始值为 500,每次循环时会递减。如果 timeout 减少到 0,表示复位操作超时,循环结束。

因此,while 循环的目的是:每次检查复位位是否仍然为 1(表示复位未完成),并通过 timeout 机制确保不会无限等待复位完成。

  1. 重新写入复位位
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
  • 如果复位位 (BMCR_RESET) 仍然为 1,代码会再次写入 BMCR_RESET 位,强制 PHY 继续保持复位状态。
  • 这种操作是为了确保 PHY 继续执行复位操作,某些 PHY 芯片可能会出现复位位一直为1的异常,此时就需要反复写入复位命令才能保证复位完成。详情请查看我的另一篇博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145749489 【搜索关键词“软复位操作中存在的异常情况及解决方法”】
  1. 延时等待
udelay(1000);
  • udelay(1000) 会引入 1 毫秒的延时。
  • 这个延时的作用是为了给 PHY 足够的时间完成复位操作,避免在复位过程中频繁读取寄存器而导致问题。复位操作需要一定的时间,延时确保复位过程中的状态能被正确读取。
  1. 读取 PHY 状态
reg = phy_read(phydev, devad, MII_BMCR);
  • phy_read(phydev, devad, MII_BMCR) 会读取 BMCR 寄存器 的值,并将其存储在 reg 变量中。这个值包含了当前 PHY 的控制状态,包括复位位。
  • 通过读取 BMCR 寄存器,程序检查 PHY 复位是否完成。
  1. 错误检查
if (reg < 0) {
    debug("PHY status read failed\n");
    return -1;
}
  • 如果读取寄存器时出现错误(reg < 0),则打印调试信息 "PHY status read failed",并返回错误代码 -1,表示读取失败。
  1. 再次延时
udelay(1000);
  • 在每次读取和判断后,再次引入 1 毫秒的延时,以确保操作的稳定性。
  1. 退出条件:超时检查
if (reg & BMCR_RESET) {
    puts("PHY reset timed out\n");
    return -1;
}
  • 如果在 timeout 次循环后,BMCR_RESET 位 仍然为 1,表示复位操作没有在规定时间内完成,程序会打印 "PHY reset timed out",并返回错误代码 -1

小结:
这段代码的目的是确保 PHY 在复位操作过程中按预期完成复位。它会反复检查 BMCR_RESET 位,并在超时前重新写入复位命令,直到复位位被清除(表示复位完成),或者达到超时次数。通过这个机制,函数能够可靠地等待 PHY 复位完成,或者在复位失败时报告超时错误。

完善物理层芯片在软复位后的自动协商配置

在博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145699423 中,我们知道了百问网的开发板中在物理层芯片LAN8720A硬复位后,是启用了自动协商模式(Auto-negotiation)的【通过MODE[2:0] 配置带实现的】,也就是说我们是希望使用自动协商模式(Auto-negotiation)的。但是自动协商模式(Auto-negotiation)不是光通过MODE[2:0] 配置带就能实现的,它还需要进行进一步配置(比如广告自己能支持的双工模式和速率信息)。

在u-boot的驱动文件drivers\net\phy\phy.c中,提供了对自动协商模式(Auto-negotiation)的进一步配置。这个函数在公板提供的u-boot中的源代码如下:

/**
 * genphy_config_aneg - restart auto-negotiation or write BMCR
 * @phydev: target phy_device struct
 *
 * Description: If auto-negotiation is enabled, we configure the
 *   advertising, and then restart auto-negotiation.  If it is not
 *   enabled, then we write the BMCR.
 */
int genphy_config_aneg(struct phy_device *phydev)
{
	int result;

	if (phydev->autoneg != AUTONEG_ENABLE)
		return genphy_setup_forced(phydev);

	result = genphy_config_advert(phydev);

	if (result < 0) /* error */
		return result;

	if (result == 0) {
		/*
		 * Advertisment hasn't changed, but maybe aneg was never on to
		 * begin with?  Or maybe phy was isolated?
		 */
		int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);

		if (ctl < 0)
			return ctl;

		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
			result = 1; /* do restart aneg */
	}

	/*
	 * Only restart aneg if we are advertising something different
	 * than we were before.
	 */
	if (result > 0)
		result = genphy_restart_aneg(phydev);

	return result;
}

其注释摘取如下:

/**
 * genphy_config_aneg - restart auto-negotiation or write BMCR
 * @phydev: target phy_device struct
 *
 * Description: If auto-negotiation is enabled, we configure the
 *   advertising, and then restart auto-negotiation.  If it is not
 *   enabled, then we write the BMCR.
 */

这段注释的解释如下:

这段注释是对 genphy_config_aneg 函数的简要说明,描述了该函数的功能以及根据是否启用了自动协商(auto-negotiation)来执行不同操作的逻辑。下面是详细解释:

  1. 函数功能说明

    genphy_config_aneg - restart auto-negotiation or write BMCR
    @phydev: target phy_device struct
    
    • 函数名称genphy_config_aneg
    • 参数@phydev 是一个指向 phy_device 结构体的指针,表示目标 PHY 设备。
    • 简要描述:该函数的功能是根据当前的自动协商配置,执行两种操作之一:
      • 如果启用了自动协商,则配置广告信息并重新启动自动协商。
      • 如果未启用自动协商,则直接写入 基本控制寄存器(BMCR)
  2. 详细描述

Description: If auto-negotiation is enabled, we configure the
advertising, and then restart auto-negotiation. If it is not
enabled, then we write the BMCR.
  • 如果启用了自动协商
    • 首先,配置 PHY 广告信息。广告信息通常包括 PHY 支持的速率、双工模式等,这些信息将用于自动协商过程。
    • 配置完广告信息后,重新启动自动协商。这意味着 PHY 会开始与对端设备协商,决定最佳的速率和双工模式。
  • 如果未启用自动协商
    • 如果自动协商被禁用,函数会直接写入 BMCR(基本控制寄存器)。BMCR 寄存器控制PHY的一些基本功能,如速率、双工模式、复位等。

总结:

  • genphy_config_aneg 函数的目的是根据是否启用自动协商,选择适当的操作:
    1. 启用自动协商时,配置广告信息并重启自动协商。
    2. 未启用自动协商时,直接写入控制寄存器 BMCR 来配置固定的速率和模式。

该注释简要地概括了该函数的两个主要功能路径,并清晰地指出了自动协商启用和禁用时的不同处理方式。

但是这个函数还需要完善一下,才能适配物理层芯片LAN8720A的自动协商设置,具体来说,就是经实践证明,在运行函数 genphy_config_aneg 前,还需先执行一次软复位操作才能确保配置没问题。注意,在执行软复位之前,之前的配置信息早已保存在函数的参数struct phy_device *phydev中了,之前的某些配置信息应该是通过由引脚MDIO 和引脚MDC构成的“SMI(Serial Management Interface)”接口来读取的。

了解了我们要干什么和为什么要这么干后,我们我们就容易理解下面对u-boot的代码的修改和添加了。

打开文件 \uboot-imx\drivers\net\phy\phy.c

然后搜索genphy_config_aneg,跳转到大约176行:
在这里插入图片描述
在函数genphy_config_aneg的开头添加下面的代码:

    int rc;

    do{
        phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
        udelay(1000);
        rc=phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
        udelay(1000);

    }while(rc&BMCR_RESET);

加上上面的代码之后的截图如下:
在这里插入图片描述
这段代码的解释我实际上已经在博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145749489 中解释得很清楚了,详情请搜索关键词“软复位操作中存在的异常情况及解决方法”。

设置以太网2的MAC地址

如果这里不设置MAC地址,那么在u-boot启动后,会出现下面的提示:
在这里插入图片描述
当然你可以在u-boot启动后,运行下面的命令手动设置以太网的MAC地址,并保存到eMMC中,

setenv eth1addr 00:01:3f:2d:3e:4d
saveenv
reset

这里要说明下,为什么是eth1addr,而不是eth2addr,原因是在u-boot中eth0对应IMX6ULL的以太网1,eth1对应IMX6ULL的以太网2。

但是我们不希望每次烧写了u-boot后都这样去设置,所以不妨把MAC写到u-boot中。

修改方法如下:

打开文件 include\configs\mx6ullevk.h,定位到115行左右:
在这里插入图片描述
在代码

	"ip_dyn=yes\0" \

的后面加上代码:

	"eth1addr=00:01:3f:2d:3e:4d\0" \

加上之后的代码截图如下:
在这里插入图片描述

重新编译u-boot

把修改后的u-boot源码打包复制到Ubuntu中:
在这里插入图片描述
然后解压出来:
在这里插入图片描述
然后打开终端,按上面第一次编译时的步骤,执行下面的命令进行编译:

make distclean

在这里插入图片描述

chmod +x ./scripts/check-config.sh

在这里插入图片描述

make mx6ull_14x14_evk_emmc_defconfig

在这里插入图片描述

make -j4

在这里插入图片描述
此时生成的u-boot镜像文件的百度网盘下载地址如下:
https://pan.baidu.com/s/1_Wyk36d3dnABZMK4R-MaFg?pwd=ik1k

u-boot镜像文件再次烧写到eMMC中

烧写工具的原理和详细使用见下面这篇博文:
https://blog.youkuaiyun.com/wenhao_ir/article/details/145653414

由于之前已经把驱动这些安装好了,所以可以像下面这样操作。

把目录100ask_imx6ull_pro开发板系统烧写工具\files下的文件u-boot-dtb.imx替换为编译u-boot时生成的镜像文件u-boot-dtb.imx

此时准备烧写的u-boot镜像文件的百度网盘下载地址如下:
https://pan.baidu.com/s/1_Wyk36d3dnABZMK4R-MaFg?pwd=ik1k

在这里插入图片描述
在这里插入图片描述
把板子设置为USB启动的方式如下:
在这里插入图片描述
打开板子的电源…

打开板子的烧写工具…
在这里插入图片描述
在这里插入图片描述
切换到专业版界面上,然后点击运行按钮:
在这里插入图片描述
运行之后由于之前已经完成了相关设备驱动的安装,所以马上显示为“固件已运行”。

在这里插入图片描述
切换到“基础版”界面,因为是对百问网的IMX6ULL_PRO开发板作操作嘛,然后点击下图中的“更新 Uboot”:
在这里插入图片描述
烧写成功后的界面如下:
在这里插入图片描述
烧写完成后请按下面的步骤顺序操作:
①关闭Winows上百问网提供的烧写工具;
②关闭开发板的电源;
③开发板设为eMMC启动方式;
④打开串口终端;
⑤启动开发板,观察u-boot的运行情况。

烧写完成后首先关闭烧写工具,然后关闭开发板电源,烧写完成后关闭开发板电源,烧写完成后关闭开发板电源,,然后关闭烧写工具,接着设置开发板为eMMC启动方式,打开串口即可看到终端有u-boot的运行信息了。

把开发板的网线插好

我们需要找到我们该把网线插到哪个网口上,我们用的是以太网2,我们查看原理图,发现以太网2的插座是J7,相关原理图如下:
在这里插入图片描述
然后我们通丝印图查看J7在板子上的哪里:
在这里插入图片描述
可见如果人面向两个网口,那么右边那个网口是以太网2,即下面图中的13:
在这里插入图片描述
把网线插到编号为13的这个网口上。
在这里插入图片描述

运行第二次烧写到烧写到eMMC中的u-boot,并观察分析运行情况

在上上一部中烧写u-boot到eMMC成功后,请按下面的步骤顺序操作:

1、关闭Winows上百问网提供的烧写工具;

2、关闭开发板的电源;

3、开发板设为eMMC启动方式;
在这里插入图片描述

4、确认USB网口按下图进行了设置:
在这里插入图片描述
5、确认网线的一端插到USB网口上了:
在这里插入图片描述

6、确认网线的另一端插到开发板的网口2上了;
在这里插入图片描述

7、打开串口终端;

8、启动开发板,观察u-boot的运行情况。

运行情况如下:

U-Boot 2020.04-dirty (Feb 21 2025 - 15:50:48 +0800)

CPU:   i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
CPU:   Industrial temperature grade (-40C to 105C) at 29C
Reset cause: POR
Model: i.MX6 ULL 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

[*]-Video Link 0 (480 x 272)
        [0] lcdif@21c8000, video
In:    serial
Out:   serial
Err:   serial
switch to partitions #0, OK
mmc1(part 0) is current device
flash target is MMC:1
Net:   eth1: ethernet@20b4000 [PRIME]
Fastboot: Normal
Normal Boot
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
** Unrecognized filesystem type **
** Unrecognized filesystem type **
Booting from net ...
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
BOOTP broadcast 5
BOOTP broadcast 6
BOOTP broadcast 7
BOOTP broadcast 8
BOOTP broadcast 9
BOOTP broadcast 10
BOOTP broadcast 11
BOOTP broadcast 12
BOOTP broadcast 13
BOOTP broadcast 14
BOOTP broadcast 15
BOOTP broadcast 16
BOOTP broadcast 17

Retry time exceeded; starting again
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
BOOTP broadcast 5
BOOTP broadcast 6
BOOTP broadcast 7
BOOTP broadcast 8
BOOTP broadcast 9
BOOTP broadcast 10
BOOTP broadcast 11
BOOTP broadcast 12
BOOTP broadcast 13
BOOTP broadcast 14
BOOTP broadcast 15
BOOTP broadcast 16
BOOTP broadcast 17

Retry time exceeded; starting again
zimage: Bad magic!
=> 

异常情况如下图中红框所示:
在这里插入图片描述
出现这个原因是此时咱们的USB网卡与开发板之间的网络连接并不支持用BOOTP协议(即后来的DHCP协议)来动态获取IP、网关等网络配置信息。
如果你把开发板连接到路由器的LAN口,路由器里是有DHCP服务的,所以是可以通过BOOTP协议(即后来的DHCP协议)来动态获取IP、子网掩码、网关等网络配置信息。把开发板连接到路由器的LAN口的u-boot启动截图如下:
在这里插入图片描述
我们这里不用管这个异常,仍然保持我们的开发板直接与USB网卡相连即可,因为后面我们可以通过u-boot的命令行手动设置IP地址、子网掩码、网关地址、TFTP服务器地址等,接下来的内容我们就来进行手动设置。

手动设置u-boot的以太网的IP地址、子网掩码、网关信息、TFTP服务器地址

请按照博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/145814363 记录的方法进行设置和测试。

当最终测试TFTP能成功下载文件到指定内存位置时,便证明测试成功了。

测试成功的截图如下:
在这里插入图片描述

这样我们的u-boot便移植完成了。

附整个过程中各阶段的u-boot压缩文件

FSL Yocto Project Community BSP中提取出的u-boot源码

百度网盘下载链接:
https://pan.baidu.com/s/1YgJPge5JMOf2HkKm_gQB7Q?pwd=ytut

将从FSL Yocto Project Community BSP中提取出的u-boot源码在未修改前进行了编译构建

百度网盘下载链接:
https://pan.baidu.com/s/1yqTSAfMVJ8VwQy1jFz0JHA?pwd=b2es

自己修改好的u-boot源码

百度网盘下载链接:
https://pan.baidu.com/s/1lvOsiapS0lx_Z42nHbsmVg?pwd=57qe

将自己修改好的u-boot源码进行了编译构建

百度网盘下载链接:
https://pan.baidu.com/s/1LT5NJlbUy6MKAhDqmeYBTg?pwd=ar4y

百问网提供的修改好的u-boot源码

百度网盘下载链接:
https://pan.baidu.com/s/1EXF8OxPOBDGE0UnPqQr-Qg?pwd=p9a1

两个阶段的u-boot镜像文件

FSL Yocto Project Community BSP中的u-boot代码生成的镜像的百度网盘下载地址:
https://pan.baidu.com/s/1rmyO7zWG4oDP8neWJtvWjQ?pwd=9d28

自己对u-boot进行修改后生成的u-boot镜像的百度网盘下载地址:
https://pan.baidu.com/s/1_Wyk36d3dnABZMK4R-MaFg?pwd=ik1k

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昊虹AI笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值