I.MX6ULL 网络外设设备树的配置与移植使用。
一、I.MX6ULL 网络硬件基础
I.MX6ULL 芯片内部自带两个百兆以太网 MAC 控制器,分别叫 ENET1 和 ENET2。它们负责和外部 PHY 芯片(比如常见的 LAN8720A、KSZ8081 等)通信,实现上网功能。
但要让 Linux 系统跑起这两个网口,光有硬件不行,必须通过设备树(Device Tree)告诉内核:“我的网口在哪儿、怎么接线、用哪些引脚、接的是哪颗 PHY,怎么复位……”
二、设备树配置核心:三个关键部分
1. 先声明两个网口的基本节点
在 `imx6ull.dtsi` 中,NXP 官方已经定义了两个网口的基础框架,比如:
```dts
fec1: ethernet@02188000 {
compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";
reg = <0x02188000 0x4000>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
...
status = "disabled"; // 默认关闭!实际要用时必须在板级 .dts 中开启
};
fec2: ethernet@020b4000 {
compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";
reg = <0x020b4000 0x4000>;
interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
...
status = "disabled";
};
```
注意:默认是 `status = "disabled"`,意思是这两个网口还没启用,必须在你的板级 `.dts`(比如 `imx6ull-alientek-emmc.dts`)里重新“打开”并配置详细参数。
2. 在板级 .dts 中,为网口“定制”参数
你需要在自己的板级设备树中,对 `fec1` 和 `fec2` 做个性化配置,告诉内核:
- 用哪种接口模式(MII 还是 RMII)?
- PHY 芯片是哪个?地址是多少?
- 复位引脚是谁?
- 是否支持魔术包唤醒?
- 用哪个引脚组?
例如,典型配置如下(以 RMII 模式为例):
(1)ENET1 配置(不配 MDIO,复用 ENET2 的 MDIO)
```dts
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1_rmii>; // 指定 RMII 所需引脚配置
phy-mode = "rmii"; // 接口模式:RMII
phy-handle = <ðphy0>; // 指向 PHY 节点
phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>; // PHY 复位引脚
phy-reset-duration = <2>; // 复位持续 2ms
status = "okay"; // 开启网口!
};
```
(2)ENET2 配置(同时挂载 MDIO 总线,管理两个 PHY)
```dts
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2_rmii>;
phy-mode = "rmii";
phy-handle = <ðphy1>; // ENET2 对应的 PHY
phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
phy-reset-duration = <2>;
status = "okay";
mdio { // MDIO 总线节点,挂载所有 PHY
address-cells = <1>;
size-cells = <0>;
ethphy0: ethernet-phy@0 { // ENET1 的 PHY,地址 0
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
ethphy1: ethernet-phy@1 { // ENET2 的 PHY,地址 1
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
};
};
```
核心要点:
> - 两个网口共用一个 MDIO 总线(由 ENET2 提供),一个 MDIO 最多管 32 个 PHY,所以完全够用。
> - `phy-handle` 指向对应 PHY 节点,比如 ENET1 用 `ethphy0`,ENET2 用 `ethphy1`。
> - `phy-mode = "rmii"` 是最常用的百兆精简接口,省引脚。
> - `phy-reset-gpios` 必须和硬件原理图一致,比如 ENET1 复位用的是 `GPIO5_IO7`,那就要写成 `&gpio5 7 ...`。
3. 配置所有用到的引脚(pinctrl)
I.MX6ULL 的引脚复用非常复杂,必须通过 pinctrl 告诉系统每个引脚的功能。通常分为两部分:
(1)常规 RMII 引脚(在 iomuxc 节点下)
```dts
pinctrl_enet1_rmii: 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_EN__ENET1_TX_EN 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b009
>;
};
pinctrl_enet2_rmii: 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_EN__ENET2_TX_EN 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x40016009
>;
};
```
(2)复位引脚(在 iomuxc_snvs 节点下,因为接的是 SNVS 域 GPIO)
```dts
pinctrl_enet1_reset: enet1resetgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10b0
>;
};
pinctrl_enet2_reset: enet2resetgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10b0
>;
};
```
>注意:
> - `GPIO5_IO07` 对应的是 `SNVS_TAMPER7`,属于 SNVS 域,所以必须放到 `iomuxc_snvs` 的 pinctrl 里,不能混到普通 iomuxc 里。
> - 实际使用时,在 `phy-reset-gpios` 中引用的就是这些 pinctrl 对应的 GPIO 控制节点(如 `&gpio5 7`)。
三、为什么 ENET1 不单独配 MDIO?
你可能会疑惑:为什么 ENET1 不配自己的 MDIO,而要用 ENET2 的?
答案是:一个 MDIO 总线可以管理最多 32 个 PHY 芯片。所以只要让 ENET2 提供 MDIO,就能同时管理 ENET1 和 ENET2 的 PHY。
而且实测发现:如果给 ENET1 也单独配 MDC/MDIO,两个网口同时开启时反而不稳定。所以推荐方案是:
> 只用 ENET2 的 MDIO 总线,统一管理两个 PHY(ethphy0 和 ethphy1)。
这也正是上面示例代码的逻辑:ENET1 只配 phy-handle 指向 ethphy0,但 ethphy0 定义在 ENET2 的 mdio 子节点里。
四、调试要点
1. 必须设置 `status = "okay"`,否则设备树里写了也白写,内核不启用。
2. PHY 地址一定要和硬件一致:看原理图,确认 PHYADDR 引脚接 GND 还是 VCC,决定地址是 0 还是 1。
3. 复位引脚必须正确:用错 GPIO,复位信号发不出去,PHY 起不来,链路永远不通。
4. RMII 模式下,时钟源要正确:
I.MX6ULL 的 RMII 时钟通常来自外部晶振或 PHY 提供,必须确认 ENETx_REF_CLK 引脚连接无误。
5. 查看启动日志:
```bash
dmesg | grep fec
```
如果看到 `fec fec1: phy found` 和 `fec fec2: phy found`,说明设备树配对了。
五、一句话总结
> I.MX6ULL 的网络设备树,核心就是:在板级 .dts 中打开 fec1/fec2,设置正确的 phy-mode、引脚、复位引脚,并通过一个由 ENET2 提供的 mdio 节点统一管理两个 PHY,最后让它们的状态为 "okay"。
只要这几点对齐硬件,驱动就能自动加载,网口就能正常上网!