问题现象
PHY 已识别后,含 1000baseT 的自协商失败(carrier=0);
ethtool -s eth0 autoneg off speed 100 duplex full 可通。
问题根因
phy-mode=rgmii 未让 PHY 加 RX delay,RGMII RX 采样窗口不对;
强制 MDI-X 也常导致部分交换机/网线 aneg 失败。
解决方案
-
DTS phy-mode = "rgmii-rxid"
-
max-speed = <1000>(不要用旧的 max-speed=<100> 绕过)
-
驱动侧(已在 an8801-phy-driver.patch 的 an8801.c):
-
rgmii-rxid 时写 RX delay: 0x1021C02C = 0x01000003 (BIT(24)|STEP_3, 无 ALIGN)
-
AUTO-MDIX
代码实现
修改a5_a113x2_av400_1g_spk.dts
--- a/common_drivers/arch/arm64/boot/dts/amlogic/a5_a113x2_av400_1g_spk.dts
+++ b/common_drivers/arch/arm64/boot/dts/amlogic/a5_a113x2_av400_1g_spk.dts
@@ -1331,19 +1331,22 @@
&external_phy {
/*
* Sole owner of GPIOZ_15: AN8801 probe pulses RESET_N.
* Must NOT also appear in ðmac pinctrl (pin claim conflict).
+ * max-speed=1000: rgmii-rxid + PHY RX delay (0x1021C02C=0x01000003)
+ * makes 1000baseT autoneg work (do not cap at 100).
*/
an8801-reset-gpios = <&gpio GPIOZ_15 GPIO_ACTIVE_LOW>;
+ max-speed = <1000>;
};
ðmac {
pinctrl-0 = <ð_pins>, <ð_rgmii_pins>;
pinctrl-names = "default";
status = "okay";
- phy-mode = "rgmii";
+ phy-mode = "rgmii-rxid";
phy-handle = <&external_phy>;
amlogic,tx-delay-ns = <2>;
/* No snps,reset-gpio / no eth_phy_reset_pins: avoid claiming Z15 */
};
修改meson-a5.dtsi
--- a/common_drivers/arch/arm64/boot/dts/amlogic/meson-a5.dtsi
+++ b/common_drivers/arch/arm64/boot/dts/amlogic/meson-a5.dtsi
@@ -1046,14 +1046,16 @@
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
/*
* Airoha AN8801R RESET_N = GPIOZ_15, owned by PHY driver.
* Board DTS: an8801-reset-gpios only (probe-time pulse).
* No snps,reset-gpio / reset-gpios (avoid boot re-assert).
+ * Board phy-mode must be "rgmii-rxid" so PHY applies
+ * RX delay 0x1021C02C=0x01000003 and 1000M aneg can pass.
*/
external_phy: ethernet-phy@1 {
compatible = "ethernet-phy-idc0ff.0421";
reg = <1>;
max-speed = <1000>;
};
};
修改驱动common/drivers/net/phy/an8801.c
static int an8801r_rgmii_rxdelay(struct phy_device *phydev, u16 delay, u8 align)
{
- u32 reg_val = delay & RGMII_DELAY_STEP_MASK;
+ u32 reg_val;
- /* align */
- if (align) {
- reg_val |= RGMII_RXDELAY_ALIGN;
- dev_info(phydev_dev(phydev), "Rxdelay align\n");
- }
- reg_val |= RGMII_RXDELAY_FORCE_MODE;
+ /*
+ * Equivalent to userspace MDIO sequence (page 4 PBUS write):
+ * wr 0x1f,4; 0x10=0; 0x11=0x1021; 0x12=0xc02c;
+ * 0x13=0x0100; 0x14=0x0003; restore 0x1f
+ * â†' 0x1021C02C = 0x01000003 (BIT(24)|step), no RGMII_RXDELAY_ALIGN
+ */
+ (void)align;
+ reg_val = BIT(24) | (delay & RGMII_DELAY_STEP_MASK);
air_buckpbus_reg_write(phydev, 0x1021C02C, reg_val);
reg_val = 0;
air_buckpbus_reg_read(phydev, 0x1021C02C, ®_val);
dev_info(phydev_dev(phydev),
- "Force rxdelay = %d(0x%x)\n", delay, reg_val);
+ "Force rxdelay step=%d reg=0x%x (expect force|step)\n",
+ delay, reg_val);
return 0;
}
@@ -588,11 +591,12 @@
an8801r_rgmii_txdelay(phydev, AIR_RGMII_DELAY_STEP_4);
break;
case PHY_INTERFACE_MODE_RGMII_RXID:
- an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_NOSTEP, TRUE);
+ /* Board validated: 0x1021C02C = 0x01000003 */
+ an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_STEP_3, FALSE);
break;
case PHY_INTERFACE_MODE_RGMII_ID:
an8801r_rgmii_txdelay(phydev, AIR_RGMII_DELAY_STEP_4);
- an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_NOSTEP, TRUE);
+ an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_STEP_3, FALSE);
break;
case PHY_INTERFACE_MODE_RGMII:
default: