2393258_en-US

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

2393258_en-US

2393258_en-US

i.MX6ULL Ethernet Clock Bug in 6.12 kernel

The device tree example in 6.12 hard codes the Ethernet Phy rather than fixing this bug which did not exist in the NXP 5.15 kernel we were using.

We ended up writing a patch because we would like the flexibility of the kernel detecting the PHY which is broken in the fec module.  This patch causes the phy registers to be read when the driver is loaded, rather than circumvention in device tree.

On i.MX6UL boards that hang both RMII PHYs on FEC2's MDIO bus, PHY@0
uses the FEC1 (ENET1) RMII reference clock.  Kernel 6.12 routes that
clock through ENET1_REF_SEL, which may not be active when FEC2 reads
PHY@0's ID during of_mdiobus_register(), yielding a bogus ID (0x01080108)
and binding the generic PHY driver.

Briefly enable FEC1's enet_clk_ref (looked up from DT, not via probe
defer) around of_mdiobus_register() so the PHY ID read succeeds without
changing FEC probe order and breaking FEC_QUIRK_SINGLE_MDIO.

---
 drivers/net/ethernet/freescale/fec_main.c | 59 +++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 811a66062..46f37be0c 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2540,6 +2540,39 @@ static int fec_enet_mii_probe(struct net_device *ndev)
 	return 0;
 }
 
+static bool fec_enet_mdio_has_phy_addr0(struct device_node *mdio)
+{
+	struct device_node *child;
+	u32 reg;
+
+	for_each_available_child_of_node(mdio, child) {
+		if (of_property_read_u32(child, "reg", ®))
+			continue;
+		if (reg == 0) {
+			of_node_put(child);
+			return true;
+		}
+	}
+	return false;
+}
+
+static struct clk *fec_enet_get_rmii_master_refclk(void)
+{
+	struct device_node *np = NULL;
+	struct clk *clk;
+
+	while ((np = of_find_compatible_node(np, NULL, "fsl,imx6ul-fec"))) {
+		if (of_get_child_by_name(np, "mdio")) {
+			of_node_put(np);
+			continue;
+		}
+		clk = of_clk_get_by_name(np, "enet_clk_ref");
+		of_node_put(np);
+		return clk;
+	}
+	return NULL;
+}
+
 static int fec_enet_mii_init(struct platform_device *pdev)
 {
 	static struct mii_bus *fec0_mii_bus;
@@ -2553,6 +2586,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
 	u32 mii_speed, holdtime;
 	u32 bus_freq;
 	int addr;
+	struct clk *rmii_master_refclk = NULL;
+	bool peer_ref_enabled = false;
 
 	/*
 	 * The i.MX28 dual fec interfaces are not equal.
@@ -2662,7 +2697,26 @@ static int fec_enet_mii_init(struct platform_device *pdev)
 	fep->mii_bus->priv = fep;
 	fep->mii_bus->parent = &pdev->dev;
 
+	if (node && fec_enet_mdio_has_phy_addr0(node)) {
+		rmii_master_refclk = fec_enet_get_rmii_master_refclk();
+		if (IS_ERR(rmii_master_refclk)) {
+			err = PTR_ERR(rmii_master_refclk);
+			goto err_out_free_mdiobus;
+		}
+		if (rmii_master_refclk) {
+			err = clk_prepare_enable(rmii_master_refclk);
+			if (err)
+				goto err_out_free_mdiobus;
+			peer_ref_enabled = true;
+			usleep_range(100, 200);
+		}
+	}
+
 	err = of_mdiobus_register(fep->mii_bus, node);
+	if (peer_ref_enabled)
+		clk_disable_unprepare(rmii_master_refclk);
+	if (!IS_ERR_OR_NULL(rmii_master_refclk))
+		clk_put(rmii_master_refclk);
 	if (err)
 		goto err_out_free_mdiobus;
 	of_node_put(node);
Re: i.MX6ULL Ethernet Clock Bug in 6.12 kernelYou only need to look at device tree changes to see that the new fec driver cuts corners and no longer has a clock, so the phy registers do not read initially. This is fine if you do not plan on having multiple vendors for the phy. The compatible line is needed to specify the phy register which has a bad value when there is no clock:

https://github.com/nxp-imx/linux-imx/blob/lf-6.12.y/arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk.dtsi#...

In older kernels (the heritage of our device tree) the compatible line was not present for the phy. This fix allows the clock to be turned on before reading the phy so registers can be read properly, so the compatible line is not required, as it was not there in older device trees:

https://github.com/nxp-imx/linux-imx/blob/lf-5.4.y/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi#L224

I have not had time to test your boards as I am busy getting our boards to work. I consider this to be a regression in the kernel.
Re: i.MX6ULL Ethernet Clock Bug in 6.12 kernel

Hello,

Thanks for sharing the analysis and patch.

Have you been able to validate this on an NXP EVK board?

Best regards.

タグ(1)
評価なし
バージョン履歴
最終更新日:
2 週間前
更新者: