2、以太网MAC控制器概述:常见SoC中的GMAC/EMAC控制器及其在设备树中的节点表示
以太网MAC(Media Access Control)控制器是SoC内部实现数据链路层功能的核心硬件模块。在嵌入式Linux系统中,常见的MAC控制器包括Synopsys DesignWare GMAC/EMAC、Cadence GEM、TI CPSW、NXP FEC以及Rockchip GMAC等。这些控制器在设备树中通过特定的compatible字符串和寄存器资源进行描述,是驱动与硬件绑定的关键入口。
2.1 主流MAC控制器架构对比
不同SoC厂商的MAC控制器在内部架构、DMA引擎、描述符管理以及PHY接口类型上存在差异。下表总结了常见控制器的关键特性:
| 控制器类型 | 常见SoC | PHY接口支持 | DMA引擎 | 设备树compatible |
|---|---|---|---|---|
| Synopsys DW GMAC | ST/Allwinner/Rockchip | GMII/RGMII/MII/RMII | 独立DMA,支持多描述符 | snps,dwmac-* |
| Cadence GEM | Xilinx Zynq/Microchip SAMA5 | GMII/RGMII/SGMII | 集成DMA,支持TDES/RDES | cdns,zynq-gem |
| TI CPSW | TI AM335x/AM437x | MII/RMII/RGMII | 双端口共享DMA | ti,cpsw |
| NXP FEC | i.MX6/i.MX8 | MII/RMII | 简单DMA,环形描述符 | fsl,imx6q-fec |
| Rockchip GMAC | RK3288/RK3399 | RGMII/RMII | Synopsys衍生DMA | rockchip,rk3288-gmac |
关键概念: 设备树中的
compatible 属性是驱动匹配的"身份证"。内核通过该字符串查找对应的 of_match_table,从而加载正确的MAC驱动。
2.2 MAC控制器的设备树节点结构
一个典型的MAC设备树节点包含寄存器基址、中断号、时钟、复位控制以及PHY绑定信息。以下以Synopsys DW GMAC为例展示其标准结构:
gmac0: ethernet@ff290000 {
compatible = "snps,dwmac-4.20a", "snps,dwmac";
reg = <0x0 0xff290000 0x0 0x10000>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
clocks = <&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
clock-names = "stmmaceth", "pclk";
resets = <&cru SRST_GMAC_A>;
reset-names = "stmmaceth";
phy-mode = "rgmii";
phy-handle = <&phy0>;
mdio0: mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@1 {
reg = <1>;
compatible = "ethernet-phy-id004d.d074";
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
};
};
};
节点解析:
reg:MAC控制器的寄存器地址空间,通常为64KB。interrupts:MAC中断号,用于通知驱动数据收发完成或错误状态。phy-mode:声明MAC与PHY之间的接口协议,如rgmii、rmii、gmii。phy-handle:指向MDIO子节点中PHY设备的phandle,建立MAC到PHY的绑定关系。mdio子节点:内部MDIO总线控制器,用于扫描和访问外部PHY寄存器。
2.3 MAC控制器内部架构与设备树映射
为了更直观地理解MAC控制器各模块与设备树属性的对应关系,下图展示了Synopsys DW GMAC的内部架构及其在设备树中的映射:
2.4 不同SoC的MAC节点实例
以下列举三种典型SoC的MAC设备树节点,展示不同厂商的命名习惯和属性差异:
2.4.1 TI AM335x CPSW
&mac {
compatible = "ti,cpsw";
reg = <0x4a100000 0x800>;
interrupts = <40 41 42>;
cpdma_channels = <8>;
ale_entries = <1024>;
bd_ram_size = <0x2000>;
mac_control = <0x20>;
slaves = <1>;
cpsw_emac0: slave@0 {
phy-mode = "rmii";
phy-handle = <&phy0>;
};
mdio: mdio@4a101000 {
compatible = "ti,cpsw-mdio";
reg = <0x4a101000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@0 {
reg = <0>;
};
};
};
2.4.2 Xilinx Zynq Cadence GEM
&gem0 {
compatible = "cdns,zynq-gem", "cdns,gem";
reg = <0xe000b000 0x1000>;
interrupts = <0 22 4>;
clocks = <&clkc 30>, <&clkc 30>, <&clkc 31>;
clock-names = "pclk", "hclk", "tx_clk";
phy-mode = "rgmii-id";
phy-handle = <&phy0>;
mdio: mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@7 {
reg = <7>;
ti,rx-internal-delay = <0x8>;
ti,tx-internal-delay = <0xa>;
};
};
};
2.4.3 Rockchip RK3399 GMAC
&gmac {
compatible = "rockchip,rk3399-gmac";
reg = <0x0 0xfe300000 0x0 0x10000>;
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>;
clock-names = "stmmaceth", "mac_clk_rx", "mac_clk_tx";
phy-mode = "rgmii";
phy-handle = <&phy0>;
mdio: mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@0 {
reg = <0>;
compatible = "ethernet-phy-id1234.d567";
reset-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
};
};
};
常见陷阱:
phy-mode必须与硬件连线严格一致。例如,如果实际使用RGMII但配置为RMII,驱动将无法正确配置接口延迟和时钟极性。- MDIO子节点的
#address-cells和#size-cells必须正确设置,否则PHY扫描会失败。 - 多个MAC控制器共享同一个MDIO总线时,MDIO节点应放在外部,避免重复注册。
2.5 MAC节点中的关键属性速查表
下表汇总了MAC设备树节点中最常用的属性及其含义,供开发者在编写或调试设备树时快速参考:
| 属性名 | 类型 | 必选/可选 | 说明 |
|---|---|---|---|
compatible |
字符串列表 | 必选 | 驱动匹配标识,通常包含SoC特定和通用版本 |
reg |
地址/长度对 | 必选 | MAC控制器寄存器基址和地址范围 |
interrupts |
中断描述 | 必选 | MAC中断号,通常为SPI类型 |
phy-mode |
字符串 | 必选 | MAC与PHY之间的接口协议 |
phy-handle |
phandle | 必选 | 指向PHY设备节点的引用 |
clocks |
时钟列表 | 可选 | MAC工作时钟,通常包含AXI/APB时钟 |
resets |
复位列表 | 可选 | MAC复位信号,用于驱动初始化时复位硬件 |
mac-address |
字节数组 | 可选 | 预设MAC地址,若未提供则驱动从EEPROM或随机生成 |
local-mac-address |
字节数组 | 可选 | 与mac-address类似,某些SoC使用此属性 |
snps,reset-gpio |
GPIO描述 | 可选 | Synopsys专用:PHY复位GPIO |
2.6 驱动适配流程概览
从设备树节点到驱动加载的完整流程可以概括为以下步骤:
- 内核解析设备树:启动时,内核遍历所有节点,将
compatible属性与驱动注册的of_match_table进行匹配。 - 驱动probe调用:匹配成功后,内核调用驱动的
probe()函数,传入struct platform_device指针。 - 资源获取:驱动通过
platform_get_resource()获取寄存器地址和中断号;通过of_property_read_*系列函数读取时钟、复位、phy-mode等属性。 - PHY绑定:驱动解析
phy-handle属性,通过MDIO总线找到对应的PHY设备,并调用phy_connect()建立连接。 - 网络设备注册:完成硬件初始化和PHY协商后,驱动调用
register_netdev()将网络设备注册到内核网络栈。
实践要点: 在调试MAC驱动时,建议首先检查设备树节点是否被内核正确识别。可以通过
ls /sys/firmware/devicetree/base/ 查看设备树内容,或使用 dtc -I fs -O dts /sys/firmware/devicetree/base/ 反编译当前设备树进行验证。