デバイスツリーの例は、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);こんにちは、
分析結果とパッチを共有していただきありがとうございます。
NXP EVKボードでこれを検証できましたか?
よろしくお願いいたします。