2393258_ja-JP

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

2393258_ja-JP

2393258_ja-JP

i.MX6ULLの6.12カーネルにおけるイーサネットクロックバグ

デバイスツリーの例は、6.12のハードコードで、このバグを修正する代わりにイーサネット物理を使いました。NXP 5.15カーネルには存在しませんでした。

最終的にパッチを作成することになったのは、fecモジュールで不具合が生じているPHY検出の柔軟性をカーネルに求めたかったからです。このパッチにより、デバイスツリー内の回避ではなく、ドライバがロードされた際にphyレジスタが読み込まれるようになっています。

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 kernel

こんにちは、

分析結果とパッチを共有していただきありがとうございます。

NXP EVKボードでこれを検証できましたか?

よろしくお願いいたします。

Re: i.MX6ULL Ethernet Clock Bug in 6.12 kernelデバイスツリーの変更を見れば、新しいFECドライバが手抜きし、クロックがなくなり、物理レジスタが最初に読み取れないことがわかります。PHY に複数のベンダーを使用する予定がない場合は、これで問題ありません。互換性のある行は、クロック信号がない場合に不正な値を持つPHYレジスタを指定するために必要です。

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

古いカーネル(デバイスツリーの起源)では、phy の互換性ラインは存在しませんでした。この修正により、物理を読み取る前にクロックをオンにしてレジスタを正しく読み取ることが可能になり、互換性のあるラインは不要になります。以前のデバイスツリーにはなかったためです。

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

自社の基板の動作確認に追われているため、御社の基板をテストする時間がありませんでした。これはカーネルの退行だと考えています。
Tags (1)
No ratings
Version history
Last update:
2 weeks ago
Updated by: