IMX6UL无Bootloader预配置时FEC1的PHY无法被MDIO识别问题
解决IMX6UL双FEC共享MDIO总线时FEC1 PHY识别问题
问题背景
在IMX6UL设备上使用FEC1和FEC2,二者各连接一个PHY,且两个PHY的管理接口共享FEC2子节点下的同一MDIO总线:FEC1的PHY在MDIO总线上地址为0,FEC2的PHY地址为1。
启动时出现以下异常:
- MDIO搜索无法找到FEC1连接的PHY,日志提示
[ 3.701404] mdio_bus 20b4000.ethernet-1: MDIO device at address 0 is missing. - 后续出现
[ 24.683268] fec 2188000.ethernet eth1: Unable to connect to phy
若通过U-Boot或Barebox等Bootloader在Linux启动前预先配置FEC,系统可正常工作。经排查原因如下:
未通过Bootloader预配置时,FEC2的设备树节点地址低于FEC1,Linux会优先探测FEC2;此时FEC1的pinmux未配置,导致FEC1的复用功能未设置,PHY无时钟;后续探测FEC1时时钟才开启,但MDIO已判定该PHY不可达;重启Linux后,复用功能已配置,FEC1的PHY可被正常识别。
解决方案
方法1:调整设备树节点顺序,让FEC1先初始化
Linux按设备树中节点的先后顺序初始化设备,将&fec1节点放在&fec2节点之前,这样FEC1的pinmux和时钟会先被配置,MDIO扫描时FEC1的PHY已经具备工作时钟。
修改后的设备树节点顺序示例:
&fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>, <&pinctrl_enet1_gpio>; phy-mode = "rmii"; phy-handle = <ðphy0>; phy-supply = <®_fec_3v3>; status = "okay"; }; &fec2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet2>, <&pinctrl_enet2_mdio>, <&pinctrl_enet2_gpio>; phy-mode = "rmii"; phy-supply = <®_fec_3v3>; phy-handle = <ðphy1>; status = "okay"; mdio { #address-cells = <1>; #size-cells = <0>; ethphy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0>; max-speed = <100>; clocks = <&clks IMX6UL_CLK_ENET_REF>; reset-gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; reset-assert-us = <200>; reset-deassert-us = <1000>; reset-names = "phy-reset1"; }; ethphy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; max-speed = <100>; clocks = <&clks IMX6UL_CLK_ENET2_REF_125M>; reset-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>; reset-assert-us = <200>; reset-deassert-us = <1000>; reset-names = "phy-reset2"; }; }; };
注意:将FEC2的pinctrl_enet1_gpio移到FEC1的pinctrl-0中,让FEC1自行管理自身PHY的复位引脚配置。
方法2:显式配置FEC1的时钟,确保初始化时开启
在FEC1节点中添加clocks和clock-names属性,强制内核在初始化FEC1时启用必要的时钟,避免依赖后续初始化流程:
&fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>, <&pinctrl_enet1_gpio>; phy-mode = "rmii"; phy-handle = <ðphy0>; phy-supply = <®_fec_3v3>; // 显式指定并启用FEC1的参考时钟、IPG时钟和AHB时钟 clocks = <&clks IMX6UL_CLK_ENET_REF>, <&clks IMX6UL_CLK_ENET1_IPG>, <&clks IMX6UL_CLK_ENET1_AHB>; clock-names = "enet_ref", "ipg", "ahb"; status = "okay"; };
方法3:增加MDIO扫描延迟,给FEC1时钟启动留足时间
在FEC2的MDIO节点中添加mdio-delay-us属性,增加MDIO扫描时的延迟,确保FEC1的时钟有足够时间完成启动:
&fec2 { ... mdio { #address-cells = <1>; #size-cells = <0>; mdio-delay-us = <100>; // 增加扫描延迟,单位微秒 ethphy0: ethernet-phy@0 { ... }; ethphy1: ethernet-phy@1 { ... }; }; };
附加信息
原设备树片段
&fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>/*, <&pinctrl_enet1_mdio>, <&pinctrl_enet1_gpio>*/; phy-mode = "rmii"; phy-handle = <ðphy0>; phy-supply = <®_fec_3v3>; status = "okay"; }; &fec2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet2>, <&pinctrl_enet2_mdio>, <&pinctrl_enet1_gpio>, <&pinctrl_enet2_gpio>; phy-mode = "rmii"; phy-supply = <®_fec_3v3>; phy-handle = <ðphy1>; status = "okay"; /* * The MDIO bus is shared between ENET1 and ENET2. If you only want * to enable ENET1, this node must be moved to fec1 node, and the * pinctrl-0 of fec1 must contain the IOMUX for the MDIO bus on ENET1 * (pintrl_enet1_mdio). */ mdio { #address-cells = <1>; #size-cells = <0>; /* mdio address "0" */ ethphy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0>; max-speed = <100>; clocks = <&clks IMX6UL_CLK_ENET_REF>; reset-gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; reset-assert-us = <200>; reset-deassert-us = <1000>; reset-names = "phy-reset1"; }; /* mdio address "1" */ ethphy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; max-speed = <100>; clocks = <&clks IMX6UL_CLK_ENET2_REF_125M>; reset-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>; reset-assert-us = <200>; reset-deassert-us = <1000>; reset-names = "phy-reset2"; }; }; }; &iomuxc { pinctrl_enet1: enet1grp { fsl,pins = < MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0 MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0 MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0 MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b0a8 >; }; pinctrl_enet2: enet2grp { fsl,pins = < MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0 MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0 MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0 MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0 MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0a0 MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0a0 MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0 MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b0a8 >; }; pinctrl_enet2_mdio: mdioenet2grp { fsl,pins = < /* mdio */ MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0 MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0 >; }; pinctrl_enet1_gpio: enet1gpiogrp { fsl,pins = < /* PHY reset */ MX6UL_PAD_LCD_DATA04__GPIO3_IO09 0x1b0b0 /* ENET1_RESET */ >; }; pinctrl_enet2_gpio: enet2gpiogrp { fsl,pins = < /* PHY reset */ MX6UL_PAD_LCD_DATA05__GPIO3_IO10 0x1b0b0 /* ENET2_RESET */ >; }; };
启动日志(精简版)
[ 0.000000] Booting Linux on physical CPU 0x0 ... [ 0.000000] Kernel command line: bootchooser.active=system0 console=ttymxc0,115200n8 systemd.machine_id=61f6da2724f38d0f1c202fb743ec3557 root=/dev/mmcblk0p3 rauc.slot=system0 rootwait ... [ 3.361074] mdio_bus 20b4000.ethernet-1: MDIO device at address 0 is missing. [ 3.383677] fec 20b4000.ethernet eth0: registered PHC device 0 [ 3.408859] pps pps1: new PPS source ptp1 [ 4.002064] fec 2188000.ethernet eth1: registered PHC device 1 ... [ 20.108429] systemd[1]: Started Network Configuration. [ OK ] Started Network Configuration. [ 21.529085] Generic PHY 20b4000.ethernet-1:01: attached PHY driver (mii_bus:phy_addr=20b4000.ethernet-1:01, irq=POLL) [ 21.686217] fec 20b4000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx [ 21.851450] fec 2188000.ethernet eth1: Unable to connect to phy [ 22.000309] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready ...
引脚组输出
user@myboard:~# cat /sys/kernel/debug/pinctrl/20e0000.pinctrl/pingroups registered pin groups: ... group: enet2grp pin 59 (MX6UL_PAD_ENET2_RX_EN) pin 64 (MX6UL_PAD_ENET2_RX_ER) pin 57 (MX6UL_PAD_ENET2_RX_DATA0) pin 58 (MX6UL_PAD_ENET2_RX_DATA1) pin 60 (MX6UL_PAD_ENET2_TX_DATA0) pin 61 (MX6UL_PAD_ENET2_TX_DATA1) pin 62 (MX6UL_PAD_ENET2_TX_EN) pin 63 (MX6UL_PAD_ENET2_TX_CLK) group: mdioenet2grp pin 30 (MX6UL_PAD_GPIO1_IO07) pin 29 (MX6UL_PAD_GPIO1_IO06) group: enet1gpiogrp pin 20 (MX6UL_PAD_JTAG_TDI) group: enet2gpiogrp pin 22 (MX6UL_PAD_JTAG_TRST_B) ... group: enet1grp pin 51 (MX6UL_PAD_ENET1_RX_EN) pin 56 (MX6UL_PAD_ENET1_RX_ER) pin 49 (MX6UL_PAD_ENET1_RX_DATA0) pin 50 (MX6UL_PAD_ENET1_RX_DATA1) pin 52 (MX6UL_PAD_ENET1_TX_DATA0) pin 53 (MX6UL_PAD_ENET1_TX_DATA1) pin 54 (MX6UL_PAD_ENET1_TX_EN) pin 55 (MX6UL_PAD_ENET1_TX_CLK) group: mdioenet1grp pin 30 (MX6UL_PAD_GPIO1_IO07) pin 29 (MX6UL_PAD_GPIO1_IO06) ...
内容的提问来源于stack exchange,提问作者RScAut
相关产品推荐
相关产品推荐

