Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Alastair D'Silva <alastair@d-silva.org>
To: Andrew Lunn <andrew+netdev@lunn.ch>,
	Heiner Kallweit <hkallweit1@gmail.com>,
	Russell King <linux@armlinux.org.uk>,
	Alexandre Torgue <alexandre.torgue@foss.st.com>,
	Maxime Chevallier <maxime.chevallier@bootlin.com>,
	"David S . Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>
Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-sunxi@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org,
	Chen-Yu Tsai <wens@kernel.org>,
	Jernej Skrabec <jernej.skrabec@gmail.com>,
	Samuel Holland <samuel@sholland.org>,
	Alastair D'Silva <alastair@d-silva.org>
Subject: [PATCH net-next 4/4] net: stmmac: dwmac-sun8i: Add Allwinner H616 EMAC clock index and internal PHY support
Date: Wed, 16 Sep 2026 14:41:19 +1000	[thread overview]
Message-ID: <20260916044119.475666-5-alastair@d-silva.org> (raw)
In-Reply-To: <20260916044119.475666-1-alastair@d-silva.org>

Support EMAC1 and the internal Fast Ethernet PHY (AC300) on Allwinner
H616 and H618 SoCs:
- Allow reading a register index from the syscon property to offset the
  regmap field for EMAC1's dedicated clock control register.
- Add emac_variant_h616_internal with support for internal PHY, MII,
  RMII, and RGMII modes.
- Delay the MAC software reset until sun8i_dwmac_init() when using the
  internal PHY, ensuring the PHY has powered on and begun generating
  the receive clock before the MAC attempts to reset.
- Skip setting H3_EPHY_SELECT for H616 internal EMAC, which does not
  use the H3-style EPHY select bit.
- Handle -EPROBE_DEFER cleanly during clock and reset control acquisition
  in get_ephy_nodes().

Assisted-by: LLM
Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
---

Notes:
    Tested on Mellow Fly-C5 (Allwinner H618) under Armbian, verifying stable
    EMAC1 probe, deferred soft reset with the internal AC300 EPHY, and 100M full
    duplex operation under load.

 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 65 ++++++++++++++++---
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 48c52eb96233..1728893589a6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -130,6 +130,16 @@ static const struct emac_variant emac_variant_a64 = {
 	.tx_delay_max = 7,
 };
 
+static const struct emac_variant emac_variant_h616_internal = {
+	.syscon_field = &sun8i_syscon_reg_field,
+	.soc_has_internal_phy = true,
+	.support_mii = true,
+	.support_rmii = true,
+	.support_rgmii = true,
+	.rx_delay_max = 31,
+	.tx_delay_max = 7,
+};
+
 static const struct emac_variant emac_variant_h6 = {
 	.syscon_field = &sun8i_syscon_reg_field,
 	/* The "Internal PHY" of H6 is not on the die. It's on the
@@ -570,6 +580,7 @@ static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = {
 };
 
 static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv);
+static int sun8i_dwmac_reset(struct stmmac_priv *priv);
 
 static int sun8i_dwmac_init(struct device *dev, void *priv)
 {
@@ -589,6 +600,10 @@ static int sun8i_dwmac_init(struct device *dev, void *priv)
 		ret = sun8i_dwmac_power_internal_phy(netdev_priv(ndev));
 		if (ret)
 			goto err_disable_regulator;
+
+		ret = sun8i_dwmac_reset(netdev_priv(ndev));
+		if (ret)
+			goto err_disable_regulator;
 	}
 
 	return 0;
@@ -784,16 +799,23 @@ static int get_ephy_nodes(struct stmmac_priv *priv)
 	/* Seek for internal PHY */
 	for_each_child_of_node_scoped(mdio_internal, iphynode) {
 		gmac->ephy_clk = of_clk_get(iphynode, 0);
-		if (IS_ERR(gmac->ephy_clk))
-			continue;
+		if (IS_ERR(gmac->ephy_clk)) {
+			ret = PTR_ERR(gmac->ephy_clk);
+			if (ret == -EPROBE_DEFER) {
+				of_node_put(mdio_internal);
+				return ret;
+			}
+			gmac->ephy_clk = NULL;
+		}
 		gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL);
 		if (IS_ERR(gmac->rst_ephy)) {
 			ret = PTR_ERR(gmac->rst_ephy);
 			if (ret == -EPROBE_DEFER) {
+				clk_put(gmac->ephy_clk);
 				of_node_put(mdio_internal);
 				return ret;
 			}
-			continue;
+			gmac->rst_ephy = NULL;
 		}
 		dev_info(priv->device, "Found internal PHY node\n");
 		of_node_put(mdio_internal);
@@ -871,7 +893,9 @@ static int mdio_mux_syscon_switch_fn(int current_child, int desired_child,
 		switch (desired_child) {
 		case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID:
 			dev_info(priv->device, "Switch mux to internal PHY");
-			val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT;
+			val = (reg & ~H3_EPHY_MUX_MASK);
+			if (gmac->variant != &emac_variant_h616_internal)
+				val |= H3_EPHY_SELECT;
 			gmac->use_internal_phy = true;
 			break;
 		case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID:
@@ -892,10 +916,13 @@ static int mdio_mux_syscon_switch_fn(int current_child, int desired_child,
 		} else {
 			sun8i_dwmac_unpower_internal_phy(gmac);
 		}
-		/* After changing syscon value, the MAC need reset or it will
+		/* After changing syscon value, the MAC needs reset or it will
 		 * use the last value (and so the last PHY set).
+		 * For internal PHY, the MAC reset will timeout because the PHY
+		 * is not yet enabled/clocked. Delay the reset to dwmac_init.
 		 */
-		ret = sun8i_dwmac_reset(priv);
+		if (!gmac->use_internal_phy)
+			ret = sun8i_dwmac_reset(priv);
 	}
 	return ret;
 }
@@ -1000,9 +1027,13 @@ static int sun8i_dwmac_set_syscon(struct device *dev,
 
 static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac)
 {
-	if (gmac->variant->soc_has_internal_phy)
-		regmap_field_write(gmac->regmap_field,
-				   (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT));
+	if (gmac->variant->soc_has_internal_phy) {
+		u32 val = H3_EPHY_SHUTDOWN;
+
+		if (gmac->variant != &emac_variant_h616_internal)
+			val |= H3_EPHY_SELECT;
+		regmap_field_write(gmac->regmap_field, val);
+	}
 }
 
 static void sun8i_dwmac_exit(struct device *dev, void *priv)
@@ -1111,6 +1142,7 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
 	struct stmmac_priv *priv;
 	struct net_device *ndev;
 	struct regmap *regmap;
+	u32 syscon_idx = 0;
 	int ret;
 
 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
@@ -1163,8 +1195,15 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1,
+					 &syscon_idx);
 	gmac->regmap_field = devm_regmap_field_alloc(dev, regmap,
-						     *gmac->variant->syscon_field);
+						     (const struct reg_field) {
+							.reg = gmac->variant->syscon_field->reg +
+							       syscon_idx * sizeof(u32),
+							.lsb = gmac->variant->syscon_field->lsb,
+							.msb = gmac->variant->syscon_field->msb,
+						     });
 	if (IS_ERR(gmac->regmap_field)) {
 		ret = PTR_ERR(gmac->regmap_field);
 		dev_err(dev, "Unable to map syscon register: %d\n", ret);
@@ -1278,6 +1317,12 @@ static const struct of_device_id sun8i_dwmac_match[] = {
 		.data = &emac_variant_a64 },
 	{ .compatible = "allwinner,sun50i-h6-emac",
 		.data = &emac_variant_h6 },
+	{ .compatible = "allwinner,sun50i-h616-emac",
+		.data = &emac_variant_h6 },
+	{ .compatible = "allwinner,sun50i-h616-emac1",
+		.data = &emac_variant_h6 },
+	{ .compatible = "allwinner,sun50i-h616-internal-emac",
+		.data = &emac_variant_h616_internal },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, sun8i_dwmac_match);
-- 
2.53.0



  parent reply	other threads:[~2026-09-16  4:42 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-16  4:41 [PATCH net-next 0/4] net: Add Allwinner H616/H618 EMAC1 and AC300 EPHY support Alastair D'Silva
2026-09-16  4:41 ` [PATCH net-next 1/4] dt-bindings: net: phy: Add Allwinner AC300 EPHY binding Alastair D'Silva
2026-09-16 14:49   ` Andrew Lunn
2026-09-16 15:22   ` Rob Herring (Arm)
2026-09-16  4:41 ` [PATCH net-next 2/4] net: phy: Add Allwinner AC300 EPHY driver Alastair D'Silva
2026-09-16 15:05   ` Andrew Lunn
2026-09-16  4:41 ` [PATCH net-next 3/4] dt-bindings: net: allwinner,sun8i-a83t-emac: Add Allwinner H616 EMAC1 and syscon index Alastair D'Silva
2026-09-16 15:22   ` Rob Herring (Arm)
2026-09-16  4:41 ` Alastair D'Silva [this message]
2026-09-16  6:24   ` [PATCH net-next 4/4] net: stmmac: dwmac-sun8i: Add Allwinner H616 EMAC clock index and internal PHY support Maxime Chevallier
2026-09-16  6:29     ` James Hilliard
2026-09-16  6:45     ` Alastair D'Silva
2026-09-16  6:47     ` Andre Przywara
2026-09-16  4:56 ` [PATCH net-next 0/4] net: Add Allwinner H616/H618 EMAC1 and AC300 EPHY support Chen-Yu Tsai
2026-09-16  5:12   ` James Hilliard
2026-09-16  6:49     ` Alastair D'Silva
2026-09-16  7:06       ` Maxime Chevallier
2026-09-16  8:02         ` Alastair D'Silva

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260916044119.475666-5-alastair@d-silva.org \
    --to=alastair@d-silva.org \
    --cc=alexandre.torgue@foss.st.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=conor+dt@kernel.org \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=edumazet@google.com \
    --cc=hkallweit1@gmail.com \
    --cc=jernej.skrabec@gmail.com \
    --cc=krzk+dt@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sunxi@lists.linux.dev \
    --cc=linux@armlinux.org.uk \
    --cc=maxime.chevallier@bootlin.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=robh@kernel.org \
    --cc=samuel@sholland.org \
    --cc=wens@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox