From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f43.google.com (mail-ot1-f43.google.com [209.85.210.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F24A931E84F for ; Mon, 3 Aug 2026 05:15:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734124; cv=none; b=YN1WtbbVyUa0tQNHXTLRftZksGjvbRx6VfT12fBS+ojmct92DuQxUhAUHpDq43EnB54qBsPj1gXQp5OlbGrSj268Roa1vVvx1y3sulwIVAjvsptMJdOkx9zFvQHgIoMFB6BVhD8jlLzRzxtdDJ55592YQPgsdhf39a6HJY5nIZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734124; c=relaxed/simple; bh=n3evcqugoeKkN8mct7F9d78wCyor72fP/A5f+80l5jE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=CdiiLGUf5vUxFW3IQq12+h6wOK9uBneyiM9PQ8ZyqR4aDGxLnx/6t5QzZgTqmyuBJHxelvOlT03O7Cn7QAeoO7/A/UMoQafNS2xQT3bAmwYAXdtAEf+lYL7z/F5QkQd8Z5f8nTv4d5kxhy/OvXXpuqUhfzz6oUKd++Hqa48NZZ4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FaR+wWi6; arc=none smtp.client-ip=209.85.210.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FaR+wWi6" Received: by mail-ot1-f43.google.com with SMTP id 46e09a7af769-7e9d7464b71so1367418a34.0 for ; Sun, 02 Aug 2026 22:15:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734122; x=1786338922; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=LDt8py0RwqfKJ99qa00T7ayi3DardBnaCg62Nlf4UJY=; b=FaR+wWi6UhUqKEIX53WQXfc/1eP4OYnxbayHoUgSKSjkQjvp8ZxHwQSDe3zsLXHBBG 62wxSOPS+x0uCk3zz1RUg4OMugJK18WcDarGsdN8hqp6LKs1gQ9bxtYB5kiV+X/W45o4 QIZsqVkh+lyOVjOcO+FuXkLcwjaek92zjlFAqtDaNP0z0wydU0yt8TUMvxiXzwgr8MYk 17IALm0/6PvkbDYl4EbVQjOU0PJw+lFCat6uqhZbYv78umvW6g0P0Gc9zIJTiP4W+dW2 T2/qXCJl1G/bnG1ql1QFKDw0JBJKzgJ5+TMfMWdbM3jVabI0IhqAmxiMRrdC3QuT/Mi1 Raow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734122; x=1786338922; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=LDt8py0RwqfKJ99qa00T7ayi3DardBnaCg62Nlf4UJY=; b=gHhzFf2DHSdsrrFokajcD/mGSNLD64DkXWP9cwomZwY4kDTaWa4Z/iAkwQM58wQUFF LeztqKBnFYfyPfRfyRKTUcKC/rhBKwT9kIk0wuf1swCrd3TMJ2mMxM4cBRfBSROtcZsS JyN/Pwkdm0se/Hcysd/6882LXa9ghnsaNXZhfFqdqIpWUjj/CTadLM7zj8a6aAgiCePr FARgC0wreOCIELK6/wRaMY8HiCih/lpX9Sh4jhlsWFH/0qb+9wvl4GnL64cZH2CyGm3o cpyLjeFm5f53UsNlrNERB9PRev96IgbaKD2QP27/FAKcPFVpoPOeW+oMakqlWcGAR+sS qzBw== X-Forwarded-Encrypted: i=1; AHgh+RpYcBk8O3Qmuu5yHPakK8zbUbd959X+pp3C8Xz0lviayUV1UXuwb4/63YfTot204bYiP3NrpOQphF3oqec=@vger.kernel.org X-Gm-Message-State: AOJu0YysVcURGueOxtgg5OWF38xBehQner2lzaJ343Hr/10o3tNYJdWK sC2jZr15rmwETOGh6eermK1rVYNIzCBlPWKsm5GmnmQIhysx+2mCnIIT X-Gm-Gg: AR+sD13K1ssWAHAwiA7EMZ/JS394pGtu4CKOZckoj1FQbIezP/YP/hco9aBaLh101QQ tWChmI43rP0T9bRwzKmfMZQMPwAFa2AbAlR7VCBu4AS7vslrhxc1NEGzrURPBu3rTFMEtVOR2CG oLoivxFf1HGtjYek6byYfNEM9lzuPNre/anKgkfdVcZyAXBXb9j/IAPvyxoLuiwpNWa1yFH9vlx L/zLVYK1MD3fxRV0EzueKXM3ipB6NaqbTN3CRDjZNUMG5LGLoTGDlDoyfCOYmwe5Vwi5bOxz9Mv MYUIVbCBOYcpdJMOaFf2CyMNJhd2XCrmjGSzHryX4zCMaFlLJyEtbr06+4xYtynruRx883yf5Kl txWJqZvlKGMyuG6Vn9R2qlORubMQEZWmeU7uDSqsgArThRomh5meX9CY/o8UyAHM9IAPfqPwU0Y +WPSUfDTTWQmH+AGNBtuo/eY4I0C6f3ryA6laFipAnrQKc030A8B9IXcebSzDtomNoHbBeTVcbu uUp++nXyMmyNOy4HLkTKfO0yDxaA02ZFiDiPBbjliejh5dALpEkFZUBV89BqzoEkhJphuvk868w whv56XOlJyI77KPKNNWpwrDMSiusuglelVcvYoRUceA38vuBPyAo6Y4BSEdbVP98jH9iI+nRxQ2 ISegNM5jQBDuHl3uicQZonblDRdLXM7mg0Dl8 X-Received: by 2002:a05:6830:83b8:b0:7e9:d277:6e2e with SMTP id 46e09a7af769-7f196cae28amr13872954a34.7.1785734121347; Sun, 02 Aug 2026 22:15:21 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:20 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:11 -0600 Subject: [PATCH 01/21] dt-bindings: net: allwinner: add H616 EMAC1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-1-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 From: Richard Genoud The H616 secondary EMAC uses a separate system-control clock register and supports only RMII at 10/100 Mbps. Add its distinct compatible without an older fallback, since using the primary EMAC clock register would not work. Constrain the PHY interface mode to RMII, matching the hardware. The EMAC1 clock register also retains the three-bit TX and five-bit RX delay chains, so allow the existing Allwinner delay properties for this compatible. Signed-off-by: Richard Genoud Signed-off-by: James Hilliard --- .../bindings/net/allwinner,sun8i-a83t-emac.yaml | 18 ++++++++++++++= ++-- Documentation/devicetree/bindings/net/snps,dwmac.yaml | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-ema= c.yaml b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.ya= ml index 323a669fa982..34def84e6c21 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml @@ -21,6 +21,7 @@ select: - allwinner,sun8i-r40-gmac - allwinner,sun8i-v3s-emac - allwinner,sun50i-a64-emac + - allwinner,sun50i-h616-emac1 - allwinner,sun55i-a523-gmac200 required: - compatible @@ -33,6 +34,7 @@ properties: - const: allwinner,sun8i-r40-gmac - const: allwinner,sun8i-v3s-emac - const: allwinner,sun50i-a64-emac + - const: allwinner,sun50i-h616-emac1 - items: - enum: - allwinner,sun20i-d1-emac @@ -91,6 +93,17 @@ required: =20 allOf: - $ref: snps,dwmac.yaml# + - if: + properties: + compatible: + contains: + const: allwinner,sun50i-h616-emac1 + + then: + properties: + phy-mode: + const: rmii + - if: properties: compatible: @@ -100,6 +113,7 @@ allOf: - allwinner,sun8i-h3-emac - allwinner,sun8i-v3s-emac - allwinner,sun50i-a64-emac + - allwinner,sun50i-h616-emac1 =20 then: properties: @@ -109,7 +123,7 @@ allOf: maximum: 700 multipleOf: 100 description: - External RGMII PHY TX clock delay chain value in ps. + PHY interface TX clock delay chain value in ps. =20 allwinner,rx-delay-ps: default: 0 @@ -117,7 +131,7 @@ allOf: maximum: 3100 multipleOf: 100 description: - External RGMII PHY TX clock delay chain value in ps. + PHY interface RX clock delay chain value in ps. =20 - if: properties: diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Docume= ntation/devicetree/bindings/net/snps,dwmac.yaml index 2449311c6d28..102ec98ac2a0 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -57,6 +57,7 @@ properties: - allwinner,sun8i-r40-gmac - allwinner,sun8i-v3s-emac - allwinner,sun50i-a64-emac + - allwinner,sun50i-h616-emac1 - amlogic,meson6-dwmac - amlogic,meson8b-dwmac - amlogic,meson8m2-dwmac @@ -622,6 +623,7 @@ allOf: - allwinner,sun8i-r40-gmac - allwinner,sun8i-v3s-emac - allwinner,sun50i-a64-emac + - allwinner,sun50i-h616-emac1 - loongson,ls2k-dwmac - loongson,ls7a-dwmac - ingenic,jz4775-mac --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f50.google.com (mail-ot1-f50.google.com [209.85.210.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 134AF38A70A for ; Mon, 3 Aug 2026 05:15:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734125; cv=none; b=KglzI/fyWzAty5l1cM8CRduqKZLu9qhP2tBb3WZaaSOIrdJdevr799Ue4GPliON15yE55NHhOacVvXgz95S9/71KENRM5UF0eB5wqfq85+lfPRHKfiTdk/+QvcEsVne7x++PfEbpkojp7B07MjFEy62kuZqSaNTQApNkTv2PRsI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734125; c=relaxed/simple; bh=LuLd1Fgsqz/EvyuQmaammKLeRagaqJ0vM3tIyUpmvMk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZC2ReVB3BkppNfdQ51LMGGkkOwkW3vhPCNFBj6uZvt7oTJ3uu4kfwOAW2Xu5+EWVMUmo8mUbaa9Tn+2VGofhhwDjeSnn5Dqy5jay4UteILBMKzlmX0VQ/BWSwlRtDhE+UdYNmji+QiwXvz7Yhxe+zg6VMt25DHaHNjzPD4ki310= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=THNU5m/D; arc=none smtp.client-ip=209.85.210.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="THNU5m/D" Received: by mail-ot1-f50.google.com with SMTP id 46e09a7af769-7e6b554044fso2627191a34.0 for ; Sun, 02 Aug 2026 22:15:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734123; x=1786338923; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=SlcJviNfe1A7bPODjwx5akEOsNAeWr5kscTUhAqnE8U=; b=THNU5m/DbyL2C5YgFvkOystoO7+9oc8243fKg4VTDyzaaplIAInaDjMIupW0W7XQm2 KLR5mVBSOJo7u1cDjbsNCjURaxLPQFs6/2+zyndJFu5cizi9ZYtt2sw6UPRkhfFFK7U3 opt6JkWw+Ik+Diz7nq0z6cY/I4y8KT6jk3e5+184SC50jZOI4mmOO3vSh+pzGYGdyr+u DosNFliKkVhFv261bnNQ8mVANAO7N7Y7rZUofKPZYaiTyMmIk9vHJKljH/QmpofgQsxy nSwattgzzKpMrX7ZWvJRsDOY39ueLD8fO+3jKxABPZuQeuhZdxq+cK3mK8h9Oq5m0dRr Pilg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734123; x=1786338923; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=SlcJviNfe1A7bPODjwx5akEOsNAeWr5kscTUhAqnE8U=; b=b587eRXo07c9XRmLKm3G6fSPGYF0o3Jmy41oJAjCJnIQDw6lC3znnmmmfyYDHnqlho bIiHLODJNzNv0Av2o04Xhl1mX6x2yBFkW32iJ8vb7jdxTCcgNO2+UbtqI4eSu480JtzV oYsitoV+FD61cN05zuZPlT1eZYmXGbVKTVZ7jBXqyGTiCX00aXA6+A2mW8cYFLJJvoB0 e0keq8QqVr915w1vYb+1Q4DJMjRaECZknXy5Pa7S6K6gRvf0vjuIru4MpnFmRNu4dsj6 H6oi0mU+JXwCyMAe4XV1ct9wjjAGtQeaiokzOS6Ap5fK57X6ulCV2DBiupJrC6XPci9i 6VTg== X-Forwarded-Encrypted: i=1; AHgh+RqhOXrDVrP6OQ26Ibe33xaS+iyXOqTa4sXBTeiPviUybsF1eCdvng/kCDxGthg3iBkrGno4liaDIaFUbqk=@vger.kernel.org X-Gm-Message-State: AOJu0YzBXkYFbmtP3AKlM/Nyy9cK2YP6nFvVDjdZKi4DHoR6FzmPUAZ9 rRmNmKnNWOBkh+Hvz4FLDBdF3BYYRsWU999sJNJDuomm9+cFTa7LZ+i8 X-Gm-Gg: AR+sD10YysygXWNpQy82RoqWsN1CEqw+P+8oI/OjjEeX+gAfoGkAhd0fe8ScH1f4W6d eXJf+2Zm2dWWfAM/+/4WJdqFANjhCCDk32PYY98Sc0eHpuXov3Tdro7hxVZDLeaza0b/JulnSwn dtqS2BUyJD4iGJ8rRQwuSUN2N7UOO8oSCP81OPqbxQ5xPvibem+CYq96ITXb2wMwlvRf6VcbkGU tSYqPWRF4MJi5EBA+xJIu3VGINsgN9OU7Y18/38jWmCSKMTC2nZHZbMCD575jMbFWXV7ZGUfuw9 3hSr1q6mpWoCEyZUD2lLc9KwBgYqiSPtrfmEBifHxDxwG/Ap3S8KYxC/Ah11OMKsiFi1C1BWRF9 amhbRsnJF6XGPPEbbKKyEBESupIV0FL/5ve7diUzDlQgHu6ju4jjO9vAjjwjId62RhlVhIXwy2f zitY3M2ARq3I6E7el3oVjGgncxhCBZoWvjQhuhCqwAe7hzlGvXnSEwVS2oH4SWUn2Czz9iXJ5zi 8DwFCeQXEgndk3NBDu2K84kO9qujjNDnReE9xJw5lV79dLwXloBdoBm9yYxasfEucCeLvOmt9UC t5T7GOE8qITAVaPaHgwYMQnb0/GpY4vL5Y5VfIUKIHmWi3Cg0+yqTXra+tUl0h0FySoDBjB6h7P 64bgq6HNukH82ksjT X-Received: by 2002:a05:6830:211b:b0:7e9:c102:333d with SMTP id 46e09a7af769-7f196f8ad8cmr14493591a34.9.1785734122667; Sun, 02 Aug 2026 22:15:22 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:22 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:12 -0600 Subject: [PATCH 02/21] net: stmmac: sun8i: add support for Allwinner H616 EMAC1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-2-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 From: Richard Genoud The H616 secondary EMAC uses a separate system-control clock register and supports only RMII at 10/100 Mbps. Its EPHY is provided by a companion AC200 or AC300 package rather than an internal PHY block. Add an EMAC1 variant using the dedicated register and mark the PHY as external. The register retains the standard five-bit RX and three-bit TX clock delay chains, so expose their supported ranges to the shared syscon setup. Signed-off-by: Richard Genoud Signed-off-by: James Hilliard --- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 21 +++++++++++++++++++= ++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/ne= t/ethernet/stmicro/stmmac/dwmac-sun8i.c index 48c52eb96233..fdc0c3384af8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -81,6 +81,13 @@ static const struct reg_field sun8i_syscon_reg_field =3D= { .msb =3D 31, }; =20 +/* EMAC1 clock register @ 0x34 in the "system control" address range */ +static const struct reg_field sun8i_syscon_reg_field_emac1 =3D { + .reg =3D 0x34, + .lsb =3D 0, + .msb =3D 31, +}; + /* EMAC clock register @ 0x164 in the CCU address range */ static const struct reg_field sun8i_ccu_reg_field =3D { .reg =3D 0x164, @@ -143,6 +150,18 @@ static const struct emac_variant emac_variant_h6 =3D { .tx_delay_max =3D 7, }; =20 +static const struct emac_variant emac_variant_h616_emac1 =3D { + .syscon_field =3D &sun8i_syscon_reg_field_emac1, + /* + * The "internal PHY" is in a companion AC200 or AC300 package, + * rather than on the H616 die. + */ + .soc_has_internal_phy =3D false, + .support_rmii =3D true, + .rx_delay_max =3D 31, + .tx_delay_max =3D 7, +}; + #define EMAC_BASIC_CTL0 0x00 #define EMAC_BASIC_CTL1 0x04 #define EMAC_INT_STA 0x08 @@ -1278,6 +1297,8 @@ static const struct of_device_id sun8i_dwmac_match[] = =3D { .data =3D &emac_variant_a64 }, { .compatible =3D "allwinner,sun50i-h6-emac", .data =3D &emac_variant_h6 }, + { .compatible =3D "allwinner,sun50i-h616-emac1", + .data =3D &emac_variant_h616_emac1 }, { } }; MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f45.google.com (mail-ot1-f45.google.com [209.85.210.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C5D40394470 for ; Mon, 3 Aug 2026 05:15:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734127; cv=none; b=e2CpQvj50IQF4dUty7YZ0Sqw0CYY1kUT0gS/Yslxdbvyltf5vrEpyZFIXSENzTTXsX2f1E1v8bFtTst6o0FH8iOoh10+lcW3CA6OIQMV6rtY8VKbA0EaE0dy+esNWa2z1m3EBmKXN6SYpqpenRreENWwDSf8iuKiHEKm/+a5Ehw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734127; c=relaxed/simple; bh=zKmrq4Io78YBlcSoFkA6zgzyWtU0hC2kx2tv6Vt1nvQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KNoM80efZesYcxLmB5SdwWrtzvX9lMcb5tLRnb88gCNG7ZxEk2Uu3PvnEgGKgBpnJTAzu48BOfU/YK2ZDkSPtNBq962d+Abzd3UYnAyrTfpZ8yq3iGz0OocHDnRu3w7w0yUG2SBEADjjQxB/3RixhA+4oEq0lnZfF073ptmvPfo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=OcUyBTb+; arc=none smtp.client-ip=209.85.210.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OcUyBTb+" Received: by mail-ot1-f45.google.com with SMTP id 46e09a7af769-7e9f1f24cbcso2864733a34.0 for ; Sun, 02 Aug 2026 22:15:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734125; x=1786338925; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=gb4LPnphqc1DtduXOsyl640sXOpfiOxS2LbjD6EtoY4=; b=OcUyBTb+IsVTddm4rsemLEj85G6IrBXOL6D10illYE2gPVN2e9VhriVSKAf0Kgm9PK A5Wks3/evRitsX/YBXGdlB1Ax5lAVpPLH2ovk+oArWH5ccIsVPp8aIE+pvr/1+SU0ZPd NeDg6jocHG0LyQtI5CT4HDvc108ubt7KP+NGUsU5VPg0y8001yibPvbwH72iT3JmUVPp GlR5hA99dv/1VUHUUP737b4ZKOuk2ueTvm4PYvJr0S+sqD0FdZhkEVssBMRR2dlI/Vu+ jUDJxMwr4wJRqftTfElMM4Hy64M2NiLg3J+PYOny18JcEPb+E7lBnaCcTm2Xstljw8kl JYRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734125; x=1786338925; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=gb4LPnphqc1DtduXOsyl640sXOpfiOxS2LbjD6EtoY4=; b=XQXmPPObFxzau9CeYNmzSe7f5soDDkcBvY7uWk5st9yF0mQfZDLH4rGwlmfd6HvLet eYegEWGNUX71DFvPgY+NrJJEcOg8b4ySkhIiR66+TGxwa+nC4Ifb85dPA6VglTLGrY8n 1Tuv98LHccIYNUqavE4KcDDarKmKHrziyV1GH8HZoT1S1XaSJATcjuQvsmQryK7YWLYI fBVLqKxqRVUZSsKrbN6p4lc1Bm3/2TQwuuJrQJl4F+9mmDFEiNRavWd7b7tfugDL4rGF brugARGIUwcUfipbisPJmUEBqmPVZZf6XmT1dsnYfYK9LVs3ibn8bEkH2yGGkrTEZWWl rX2A== X-Forwarded-Encrypted: i=1; AHgh+RodLowoLzT551dfjIXSr6aZFuE5jQuZj/zp3Lr0HbdHg3FVGMeG9+02GN2RcykYTB4tP+l6J3lMImPQ+vE=@vger.kernel.org X-Gm-Message-State: AOJu0Ywk8jxKMr/NDOlwfcnJ9UW6NQ/pq+05vYmAy2ijcOlKanfoQJQt jELQYy/sq8vkZiBe0Rg6Tp0ueRbUaygDHHXTJFIy+K/9O2KgJ1/XKIwD X-Gm-Gg: AR+sD11GdCdlTAusTETTIoRj6zoJxM2FL5uiD054LKi8DAbEEKvW0sBny7GFXPwKpr2 F5Av/BqAJ+7a4N6lwkv57XhbNWVVunNBwvOcymyLhYuMgJyJjjgUKoAb8n+PoiIl7epgai5Q61m VnSW/COznHtPL/lppevYefNTHrtTS5BhOCMLS6J+ddXlq4AdD7c0vMBzgCGILUdAmm8OsM148tO RijC+umC6t5DT5/+SYgcXZE6xpufL7HgHoquWiT2fLgUiYO8sljYp1DS0UIuP0RkzqbYMFb2gXf oZKBFacbE1DnCFBFhwo3uPw66/NlIRBix8Q9vHUo+VrFGmnYuvz+sbAwlOlVflMRil3qX0wL7OM k5qWczWzuKZLkogpQEozvm039AeH8Bav652YMIh7/Y0F2DUJ0g6+k8N8AMRHPluMSRVFdB9pBop 6opEfl7U993hbjDavTBLLO5E0QssXJ+2lO1CxSPaSB0YKBiyaujGOVo8OM0+k+SZ+ACaU8H0HSq MIXx5VfHNPuq4st7Ud7TQZNtk/G0rGT11f3LtBCU5jYvTlJOobkZ8odyHm71nkM/L1CTuxZsEGT QByAIuunYE29/zB4o2s5iFXOpLC0UJEGrc8jrYulMM5Xwkygr6Y29NSBlWLYGWr71SSrpYhnEVY rpNkpNPZZmPyZ4Osukyr5xZnasA== X-Received: by 2002:a05:6830:7086:10b0:7db:a297:9e62 with SMTP id 46e09a7af769-7f1892c8017mr4283606a34.8.1785734124209; Sun, 02 Aug 2026 22:15:24 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:23 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:13 -0600 Subject: [PATCH 03/21] arm64: dts: allwinner: h616: add EMAC1 controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-3-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 From: Richard Genoud The H616 has a secondary EMAC controller that supports only RMII at 10/100 Mbps. It connects through PA0-PA9 to an EPHY in a companion AC200 or AC300 package. Add the EMAC1 controller and RMII pin group. Leave the controller disabled for boards to enable when the companion Ethernet hardware is present. Signed-off-by: Richard Genoud Signed-off-by: James Hilliard --- arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi | 30 ++++++++++++++++++++++= ++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/bo= ot/dts/allwinner/sun50i-h616.dtsi index 90fe56a1d3cd..6879f27c2b2b 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi @@ -432,6 +432,14 @@ pwm5_pin: pwm5-pin { function =3D "pwm5"; }; =20 + /omit-if-no-ref/ + rmii_emac1_pins: rmii-emac1-pins { + pins =3D "PA0", "PA1", "PA2", "PA3", "PA4", + "PA5", "PA6", "PA7", "PA8", "PA9"; + function =3D "emac1"; + drive-strength =3D <40>; + }; + /omit-if-no-ref/ spi0_pins: spi0-pins { pins =3D "PC0", "PC2", "PC4"; @@ -789,6 +797,28 @@ mdio0: mdio { }; }; =20 + emac1: ethernet@5030000 { + compatible =3D "allwinner,sun50i-h616-emac1"; + reg =3D <0x05030000 0x10000>; + interrupts =3D ; + interrupt-names =3D "macirq"; + clocks =3D <&ccu CLK_BUS_EMAC1>; + clock-names =3D "stmmaceth"; + resets =3D <&ccu RST_BUS_EMAC1>; + reset-names =3D "stmmaceth"; + syscon =3D <&syscon>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&rmii_emac1_pins>; + phy-mode =3D "rmii"; + status =3D "disabled"; + + mdio1: mdio { + compatible =3D "snps,dwmac-mdio"; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; + }; + gpadc: adc@5070000 { compatible =3D "allwinner,sun50i-h616-gpadc", "allwinner,sun20i-d1-gpadc"; --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f42.google.com (mail-ot1-f42.google.com [209.85.210.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5F5A538E8B2 for ; Mon, 3 Aug 2026 05:15:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734129; cv=none; b=M2ZpTAOhxVN+jSywddVXn7f/nha55tUonQggPOsAv/LYnsG5d3zR52k8ynXmjTCO7Of2CpwKYI/ph+Z3N/9caFQeEcEVRUNNiW1ZrZYAmKO9qdZio8F/L4v+WbrlLFfr4YuYXvEEn65zBCvvZLg0FvZb0TEZuovdKeW2KJ1bzms= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734129; c=relaxed/simple; bh=APfgpJTVA4pOI91gbDaanL4SMg80qg6DwGibNA5NVGQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sksvJ78MXQiwpyzpaiY2FuO8S5nAbAb/yv0voN/fzxFs9aL+Lcmp4UQdNS+OVWUPrsw7oxL5JZpwymo+OfaEYuYQSc73GHAWYD5iA1paUU6coRK/aRMdlIwbYoIaYSA+e6BoBZlewURjqN8pVUK3Cg7iVtcFal6IpGBnMdXA5bU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=XDHdkEZd; arc=none smtp.client-ip=209.85.210.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XDHdkEZd" Received: by mail-ot1-f42.google.com with SMTP id 46e09a7af769-7ebd88be784so1889288a34.2 for ; Sun, 02 Aug 2026 22:15:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734126; x=1786338926; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=fkDHET87UFExhpdvkNx3ant78q307rzdUT3zfbIoItk=; b=XDHdkEZdvzQfxCnplBGuU+kQYf1S11Qng9ussEFMuE6mG9NJC441s1IJ3/SCFYLhQB ZgO2nEVzP1zrlkPSRTEvT2TDCb0hGA3Gb+FwvQGfR+RaSJRIRPJGQfp6997KVl7xvqMH Ic7CHVR6Q9VFTJRI9IzSRLsbs+5pQSO46cVxxoTiwdZFA4eUgdnqTjrZBR9j2AKaNPdM 59CrBpYTvY0jn+oX5axSmDtWM0BUWyouYsLwhTGjYrAxedPjNFjir2bE92hLptkE2YHn QMjT0YElC5xkoEGHUombxzE6wPsSrFmNCL7IgXlXhzUPsDY3qYJffjlW4/pTs0f5vrv4 qyug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734126; x=1786338926; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=fkDHET87UFExhpdvkNx3ant78q307rzdUT3zfbIoItk=; b=B7gDei9lcjt/3tqT4dfErpSLvfHj5nZSaikRNiIFG3tse8FwCS/yho0+2IU2l0kfFa 9Wj3l2QANiRay8v7J9AMPtNa/+nbEYvUg+v5eHdwFbs+KroMv/MsEVZ23M6LFtlZruzB K+9YublHBuE898WTzAHSI+MiryM4NR/jkCreMo/j5tdd684FFsq1B0PR1aQPHJKrF8Me fpgWp3u9DCgNeZfskYdLXPWxN7Z5H+kS0P06PiccyN0k0A2pOvFRElWBH/truwSkT2uR AoBAEuB5iV+S5OeRloPHa92jJfehfsFBXK0v3pPfrlKe0sqo2TJHuAhcd0oRZD79jgNn YGdg== X-Forwarded-Encrypted: i=1; AHgh+Ro9Ah6QZsz4ngeaJjFA+P351GcQuAI0WytDc5Er+hHD8v67QtRxEfEBR84ge/45P3GXYctCPC6j4wNUpG0=@vger.kernel.org X-Gm-Message-State: AOJu0YzWg7ITRBmcGAkScEwrxn0aCJyQxt7c/sOK1fKFfMZBes7J+4SS D6W1zKXSTmCkXbndH+rztp96oXW34hFbtQb0ApZnagrsdogcxe2ILuhA X-Gm-Gg: AR+sD114rvYhAhYKN+N+DTS7qXtB7eboKkt0Xeo+xNNjprHT2wLwG8GTNbe/3c6eBU6 6stOV0aeLFT63mrG1778dePlB7ZfpA2nKMBJ8sfbtSAO5EvBOCYmzhWGeBhPNVmA1V3k2/+GSMA rVHklznS080MbeaLkfGIXb7uKaSgULl6x781BmBveSSwJ7M2Fhhk2UEb4222aO//6ZIcW3r8Nb8 ThXR7uBY8dx/XI7ybZ8Lns756atd473G2PlJv2k93dcdpZJrMdm9C08DG2R7LsudScVMPViZrWK w9Tcbd/+ZpghWl4vg5ZG0h+UZVA7UtL4QwYaWV/1pvl/ZWwIYukx4vbEj8EF/MRVTYgR40VDoIQ /co7S57uuPJQI3oTIbWubGm92UP9HACsZnLMNKP8EGPHwnv/1qt0V2HLvEOdgqApKeLJku2zLcW MxQlVsIdjYERVf25RT+kYy+qMQow1z6M1NRjBD80nOAxEj4m9qRur6BbwB/dlNsfYeUjxt0qGL9 grejUJtOIBFHJmIUIHtGrij0tyzL2BhD3d+7YActiZ/gNa5dAKtvCN3Pu+56UH7eWRG6fuVG1xg PPNmj8epizkjL26n+MKyuhZeA2gIHjUEVE6CGP0KH+nsNIu43G0MyqB5x8I90xkMfBnM4FwOEY7 mS7j5tFfQcX7PzJkhWypH2NPO+hBF1QHt6AFbbQ== X-Received: by 2002:a05:6830:8389:b0:7e9:e709:44f6 with SMTP id 46e09a7af769-7f196ea3b40mr13694676a34.12.1785734125552; Sun, 02 Aug 2026 22:15:25 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:25 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:14 -0600 Subject: [PATCH 04/21] net: mdio: factor out OF child registration helpers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-4-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 Live OF reconfiguration needs to create the same PHY and generic MDIO devices as initial bus population, including legacy PHY nodes that need address scanning. Factor fixed-address child registration and PHY address scanning into helpers. The old scan loop also visited every free address for a child without a reg property even when the child was not a PHY. Reject that case before scanning while preserving enumeration of valid PHY and generic MDIO children. Signed-off-by: James Hilliard --- drivers/net/mdio/of_mdio.c | 66 ++++++++++++++++++++++++++++--------------= ---- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/net/mdio/of_mdio.c b/drivers/net/mdio/of_mdio.c index b8d298c04d3f..051e449bbe7c 100644 --- a/drivers/net/mdio/of_mdio.c +++ b/drivers/net/mdio/of_mdio.c @@ -77,6 +77,15 @@ static int of_mdiobus_register_device(struct mii_bus *md= io, return 0; } =20 +static int of_mdiobus_register_child(struct mii_bus *mdio, + struct device_node *child, u32 addr) +{ + if (of_mdiobus_child_is_phy(child)) + return of_mdiobus_register_phy(mdio, child, addr); + + return of_mdiobus_register_device(mdio, child, addr); +} + /* The following is a list of PHY compatible strings which appear in * some DTBs. The compatible string is never matched against a PHY * driver, so is pointless. We only expect devices which are not PHYs @@ -136,6 +145,32 @@ bool of_mdiobus_child_is_phy(struct device_node *child) } EXPORT_SYMBOL(of_mdiobus_child_is_phy); =20 +static int of_mdiobus_scan_phy(struct mii_bus *mdio, + struct device_node *child) +{ + int addr, rc; + + if (!of_mdiobus_child_is_phy(child)) + return -ENODEV; + + for (addr =3D 0; addr < PHY_MAX_ADDR; addr++) { + if (mdiobus_is_registered_device(mdio, addr)) + continue; + + dev_info(&mdio->dev, "scan phy %pOFn at address %i\n", + child, addr); + + /* -ENODEV means that scanning should continue. */ + rc =3D of_mdiobus_register_child(mdio, child, addr); + if (!rc) + return 0; + if (rc !=3D -ENODEV) + return rc; + } + + return -ENODEV; +} + static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_nod= e *np, bool *scanphys) { @@ -164,10 +199,7 @@ static int __of_mdiobus_parse_phys(struct mii_bus *mdi= o, struct device_node *np, continue; } =20 - if (of_mdiobus_child_is_phy(child)) - rc =3D of_mdiobus_register_phy(mdio, child, addr); - else - rc =3D of_mdiobus_register_device(mdio, child, addr); + rc =3D of_mdiobus_register_child(mdio, child, addr); =20 if (rc =3D=3D -ENODEV) dev_err(&mdio->dev, @@ -197,7 +229,7 @@ int __of_mdiobus_register(struct mii_bus *mdio, struct = device_node *np, { struct device_node *child; bool scanphys =3D false; - int addr, rc; + int rc; =20 if (!np) return __mdiobus_register(mdio, owner); @@ -238,27 +270,9 @@ int __of_mdiobus_register(struct mii_bus *mdio, struct= device_node *np, of_node_name_eq(child, "ethernet-phy-package")) continue; =20 - for (addr =3D 0; addr < PHY_MAX_ADDR; addr++) { - /* skip already registered PHYs */ - if (mdiobus_is_registered_device(mdio, addr)) - continue; - - /* be noisy to encourage people to set reg property */ - dev_info(&mdio->dev, "scan phy %pOFn at address %i\n", - child, addr); - - if (of_mdiobus_child_is_phy(child)) { - /* -ENODEV is the return code that PHYLIB has - * standardized on to indicate that bus - * scanning should continue. - */ - rc =3D of_mdiobus_register_phy(mdio, child, addr); - if (!rc) - break; - if (rc !=3D -ENODEV) - goto put_unregister; - } - } + rc =3D of_mdiobus_scan_phy(mdio, child); + if (rc && rc !=3D -ENODEV) + goto put_unregister; } =20 return 0; --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f47.google.com (mail-ot1-f47.google.com [209.85.210.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A6D8B1A5B9D for ; Mon, 3 Aug 2026 05:15:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734137; cv=none; b=l4kB50UzGQ0yutzu23ndbC8ByojkEjcZkaMKWoX0PvbuUO31mpba9+MdPXeY3wepspOUHSrH4+OwX0VMELOTJZyl5wG59x4ayko5aMIh2wtjua24tiwybyK1rYnS6t5p8dYubHexP8wj4IbgbeohKmKlFu4xp0xVXAjjVPKYvhY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734137; c=relaxed/simple; bh=06Ndjp2qmfFDz4dq/1g4wiH9y+i9NX4WqoGE7f9jRYQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rvu8WFQ573CV8PuC1Y1HPiPoKDTOGW8jlJTw+vpF/uYneNKLmHOmPQn0q67luH8pNLQOw6uLujBBHE5eONsbbBZR1REJGQUIP1+II/fTSSKYS6v7bz9V9Vx0N1M0oOxuOG1SbCq/U7OTSlEteeSptjVi960gUGNJ/P0cSV0GpFs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=LLQuYF+J; arc=none smtp.client-ip=209.85.210.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="LLQuYF+J" Received: by mail-ot1-f47.google.com with SMTP id 46e09a7af769-7eb6573bd52so2068108a34.3 for ; Sun, 02 Aug 2026 22:15:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734132; x=1786338932; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=wwVnovEquKlLXg/zw4hAH7SWHSDxoW5mo3oFAsopbqY=; b=LLQuYF+JvzQf5HzS6vEqxu8/lhBeQDGzlTGwUCQ7CZfsS9X52AUQc3b3U59HkhtPi9 epG3VFDsLpZMVahhSrFtdtD5J3+uhbsgd0RjHJYkzNPDxmGUT7rDoRi1l6tfNadg1rlT /ivSPmVNtxCnwC4xdyP2uZkSQ0LF8LI5A5uzTCDQx6CCNuuQERAMi6FL1MfnFYzz7yDQ xKBQT1cxSTcloewYZMn1E95PckmlL1X6UOJLVjqh/JFSLKDVn54TnGdDXWvBfbCq2daQ 0Q8ssllkgBVkv84vlTEeiHRPmmhQFQQWygno2gVloVeJMiEUXdWIgaX+xn4GVxVt9eif gF5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734132; x=1786338932; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=wwVnovEquKlLXg/zw4hAH7SWHSDxoW5mo3oFAsopbqY=; b=libRM2XHUn23mg63r2F8XFvvD0R64AzdC1XLE72rp9U7Ftr++AaMPzsZ+Gd95tocQi fi7lCvwDmdifSOJxd3ouoTnstq/ryRW1sEalxnGXYGBpUxgICWwxsSDTgzur9PQBOpSw 05ozsr6vc2XHKUYAsnngdfto1XN3qdSCBxMppat7PlXBGYGgRbtcKz3EB2JGfYWmijio sF7c+WHRjBoxw/eJi0EkrqbkdC3U9COtPpM5u6gRqEATvO4xsy9LmDB+Yzktu+3sAqSC pSvP0DQEoql8oef6H9WbiJ9TR5yoWDG4uBDtmQsaE9d0GbtZxKB3oD4beZtPPC34JS4S zbZg== X-Forwarded-Encrypted: i=1; AHgh+RoaZ7FXpRE5jBCxRHUYi1iUPnc5hiqLJebrEqZ9bwJ2SDH56pjzZ5mJmkr3JNOPkap9OJq8KZCy2MHOfzg=@vger.kernel.org X-Gm-Message-State: AOJu0YxLqEFZComdRqsz0PT+r+cZTN8dGJgouQx9UndDk4eUmqtz64gL rO9qKOfaWxCvwQ00XT8S3DkhrVQ05JPb6aAfEo52sGmChMvfQycTnNKH X-Gm-Gg: AR+sD12xzwyD2Xue7+a4McV4o9cbJhcRvOVXeiTpvhSlqRZgAxMwPa7NaBjAyp/0rfP go2ZvycZDXe0rfCg7uFg83O/FFvn/2QHS5nR34C3ondOeW51KE7dbIIDA2RnSbr45qxgg4tTi24 aKO6nWngotBsg4xj8BUdHnmzBC0AIAQaT1EmCaWhbaGC15v9x9qa6Gji5gGTH+cdWywRnJFnFZT qPVowJ/pxEoY8JCFhM0LrniGxsjncNbOn48io8MmMJKSe4P51EwUh+wepWEq6R2cPa29T22CiPj 7+dveAy8jZKjXaDajfR0phjfDzv4d25aWlWH8Vw5AgYJsquEArCOBnTsa6yHyJtegmeZ1TX0uim 37OrfXQanKtFhPXC/uta/HcC/PYAtaz6mm+Ox9PA7AG8ixc/HD1NfEktJvCQl88aHsibOREdq1+ MfPKWKj4HRZ77u/oExw4Zv9OzGtjar+0lTzWfpqy/fl+5X1i5HoVBrozR2K9Bt4MfZ4QMZkP+Se y3TGiNctzViKzFpW4jV1v/9+Zum2JKWbiIaRFec3b4M/+ZheOIiF9kflrzaaqCALrVxZMzVcezG zoWTrW6p7WFMY/8uOPEddC9Ne2MK+z0JoxqHPiJJEIJyI62nVJmbuG/mDqE6L5cir4NYAH3L4Au 9AjEb84wuIlgyzIZe1ySSDHwkHxA= X-Received: by 2002:a05:6830:601b:b0:7e9:c72e:e5d6 with SMTP id 46e09a7af769-7f197075663mr13841824a34.14.1785734126952; Sun, 02 Aug 2026 22:15:26 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:26 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:15 -0600 Subject: [PATCH 05/21] net: mdio: make device map changes hotplug-safe Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-5-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 MDIO device registration currently publishes directly into mdio_map without serializing address ownership, and removal frees the object immediately. That is sufficient while bus population is static, but dynamic firmware changes can race registration, PHY attachment and bus teardown. It also cannot safely preserve mdiobus_get_phy()'s borrowed-pointer convention. Serialize device-map state and reserve addresses while registration is in progress. Track active scans, registrations and firmware changes so bus teardown first blocks new work and waits for existing work before consuming the final map. Block new registrations and PHY attachment while a firmware removal owns the map. Publish initialized devices with release ordering and make PHY attachment atomic with map removal, including standalone PHY users. Have address scans atomically claim a matching OF node as well, so explicit OF population cannot instantiate the same device concurrently. Keep dynamically removed devices pinned until the MDIO bus is torn down so existing borrowed pointers cannot become use-after-free references. Drop their firmware-node reference after device_del() so this does not keep an overlay node alive. Normal MDIO removal and driver APIs remain unchanged, and consumers do not need to adopt a new refcounting API. Signed-off-by: James Hilliard --- drivers/net/phy/mdio_bus.c | 14 ++- drivers/net/phy/mdio_bus_provider.c | 140 +++++++++++++++------ drivers/net/phy/mdio_device.c | 235 ++++++++++++++++++++++++++++++++= ---- drivers/net/phy/phy_device.c | 102 ++++++++++++---- drivers/net/phy/phylib-internal.h | 4 +- include/linux/mdio.h | 6 + include/linux/phy.h | 18 +++ 7 files changed, 434 insertions(+), 85 deletions(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 00d0e4159e9b..f45c936fe5aa 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -34,7 +34,8 @@ static struct mdio_device *mdiobus_find_device(struct mii= _bus *bus, int addr) if (WARN_ONCE(!addr_valid, "addr %d out of range\n", addr)) return NULL; =20 - return bus->mdio_map[addr]; + /* Pair with map publication in mdiobus_register_device(). */ + return smp_load_acquire(&bus->mdio_map[addr]); } =20 struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr) @@ -54,7 +55,16 @@ EXPORT_SYMBOL(mdiobus_get_phy); =20 bool mdiobus_is_registered_device(struct mii_bus *bus, int addr) { - return mdiobus_find_device(bus, addr) !=3D NULL; + bool addr_valid =3D addr >=3D 0 && addr < ARRAY_SIZE(bus->mdio_map); + bool registered; + + if (WARN_ONCE(!addr_valid, "addr %d out of range\n", addr)) + return false; + + registered =3D READ_ONCE(bus->mdio_map[addr]) || + (READ_ONCE(bus->mdio_map_pending) & BIT(addr)); + + return registered; } EXPORT_SYMBOL(mdiobus_is_registered_device); =20 diff --git a/drivers/net/phy/mdio_bus_provider.c b/drivers/net/phy/mdio_bus= _provider.c index ce3a607a40cb..b83a0a7a4235 100644 --- a/drivers/net/phy/mdio_bus_provider.c +++ b/drivers/net/phy/mdio_bus_provider.c @@ -330,6 +330,9 @@ struct mii_bus *mdiobus_alloc_size(size_t size) return NULL; =20 bus->state =3D MDIOBUS_ALLOCATED; + mutex_init(&bus->mdio_map_lock); + init_waitqueue_head(&bus->mdio_map_wait); + INIT_LIST_HEAD(&bus->mdio_map_retired); if (size) bus->priv =3D (void *)bus + aligned_size; =20 @@ -360,18 +363,21 @@ static int of_mdiobus_find_phy(struct device *dev, st= ruct mdio_device *mdiodev, int addr; =20 if (of_node_name_eq(child, "ethernet-phy-package")) { + int ret; + /* Validate PHY package reg presence */ if (!of_property_present(child, "reg")) { of_node_put(child); return -EINVAL; } =20 - if (!of_mdiobus_find_phy(dev, mdiodev, child)) { + ret =3D of_mdiobus_find_phy(dev, mdiodev, child); + if (ret !=3D -ENODEV) { /* The refcount for the PHY package will be * incremented later when PHY join the Package. */ of_node_put(child); - return 0; + return ret; } =20 continue; @@ -382,6 +388,11 @@ static int of_mdiobus_find_phy(struct device *dev, str= uct mdio_device *mdiodev, continue; =20 if (addr =3D=3D mdiodev->addr) { + if (of_node_test_and_set_flag(child, OF_POPULATED)) { + of_node_put(child); + return -EBUSY; + } + device_set_node(dev, of_fwnode_handle(child)); /* The refcount on "child" is passed to the mdio * device. Do _not_ use of_node_put(child) here. @@ -393,22 +404,26 @@ static int of_mdiobus_find_phy(struct device *dev, st= ruct mdio_device *mdiodev, return -ENODEV; } =20 -static void of_mdiobus_link_mdiodev(struct mii_bus *bus, - struct mdio_device *mdiodev) +static int of_mdiobus_link_mdiodev(struct mii_bus *bus, + struct mdio_device *mdiodev) { struct device *dev =3D &mdiodev->dev; =20 if (dev->of_node || !bus->dev.of_node) - return; + return 0; =20 - of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node); + return of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node); } #endif =20 -static struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr, bool= c45) +static struct phy_device *__mdiobus_scan(struct mii_bus *bus, int addr, + bool c45) { struct phy_device *phydev =3D ERR_PTR(-ENODEV); struct fwnode_handle *fwnode; +#if IS_ENABLED(CONFIG_OF_MDIO) + bool of_node_populated =3D false; +#endif char node_name[16]; int err; =20 @@ -420,7 +435,12 @@ static struct phy_device *mdiobus_scan(struct mii_bus = *bus, int addr, bool c45) /* For DT, see if the auto-probed phy has a corresponding child * in the bus node, and set the of_node pointer in this case. */ - of_mdiobus_link_mdiodev(bus, &phydev->mdio); + err =3D of_mdiobus_link_mdiodev(bus, &phydev->mdio); + if (err =3D=3D -EBUSY) { + phy_device_free(phydev); + return ERR_PTR(-ENODEV); + } + of_node_populated =3D !!phydev->mdio.dev.of_node; #endif =20 /* Search for a swnode for the phy in the swnode hierarchy of the bus. @@ -437,6 +457,11 @@ static struct phy_device *mdiobus_scan(struct mii_bus = *bus, int addr, bool c45) =20 err =3D phy_device_register(phydev); if (err) { +#if IS_ENABLED(CONFIG_OF_MDIO) + if (of_node_populated) + of_node_clear_flag(phydev->mdio.dev.of_node, + OF_POPULATED); +#endif phy_device_free(phydev); return ERR_PTR(-ENODEV); } @@ -458,7 +483,17 @@ static struct phy_device *mdiobus_scan(struct mii_bus = *bus, int addr, bool c45) */ struct phy_device *mdiobus_scan_c22(struct mii_bus *bus, int addr) { - return mdiobus_scan(bus, addr, false); + struct phy_device *phydev; + int err; + + err =3D mdiobus_device_change_begin(bus, false); + if (err) + return ERR_PTR(err); + + phydev =3D __mdiobus_scan(bus, addr, false); + mdiobus_device_change_end(bus, false); + + return phydev; } EXPORT_SYMBOL(mdiobus_scan_c22); =20 @@ -476,7 +511,7 @@ EXPORT_SYMBOL(mdiobus_scan_c22); */ static struct phy_device *mdiobus_scan_c45(struct mii_bus *bus, int addr) { - return mdiobus_scan(bus, addr, true); + return __mdiobus_scan(bus, addr, true); } =20 static int mdiobus_scan_bus_c22(struct mii_bus *bus) @@ -487,7 +522,7 @@ static int mdiobus_scan_bus_c22(struct mii_bus *bus) if ((bus->phy_mask & BIT(i)) =3D=3D 0) { struct phy_device *phydev; =20 - phydev =3D mdiobus_scan_c22(bus, i); + phydev =3D __mdiobus_scan(bus, i, false); if (IS_ERR(phydev) && (PTR_ERR(phydev) !=3D -ENODEV)) return PTR_ERR(phydev); } @@ -504,7 +539,7 @@ static int mdiobus_scan_bus_c45(struct mii_bus *bus) struct phy_device *phydev; =20 /* Don't scan C45 if we already have a C22 device */ - if (bus->mdio_map[i]) + if (mdiobus_is_registered_device(bus, i)) continue; =20 phydev =3D mdiobus_scan_c45(bus, i); @@ -536,6 +571,44 @@ static bool mdiobus_prevent_c45_scan(struct mii_bus *b= us) return false; } =20 +static void mdiobus_stop_device_changes(struct mii_bus *bus) +{ + mutex_lock(&bus->mdio_map_lock); + bus->state =3D MDIOBUS_UNREGISTERING; + mutex_unlock(&bus->mdio_map_lock); + + wait_event(bus->mdio_map_wait, !READ_ONCE(bus->mdio_map_ops)); +} + +static void mdiobus_remove_devices(struct mii_bus *bus) +{ + LIST_HEAD(removed); + struct mdio_device *mdiodev, *next; + int i; + + for (i =3D 0; i < PHY_MAX_ADDR; i++) { + mdiodev =3D bus->mdio_map[i]; + if (!mdiodev) + continue; + + mdiodev->device_remove(mdiodev); + mdiodev->device_free(mdiodev); + } + + mutex_lock(&bus->mdio_map_lock); + list_splice_init(&bus->mdio_map_retired, &removed); + mutex_unlock(&bus->mdio_map_lock); + + list_for_each_entry_safe(mdiodev, next, &removed, retired_node) { + list_del_init(&mdiodev->retired_node); + mdio_device_put(mdiodev); + } + + mutex_lock(&bus->mdio_map_lock); + bus->state =3D MDIOBUS_UNREGISTERED; + mutex_unlock(&bus->mdio_map_lock); +} + /** * __mdiobus_register - bring up all the PHYs on a given bus and attach th= em to bus * @bus: target mii_bus @@ -552,10 +625,9 @@ static bool mdiobus_prevent_c45_scan(struct mii_bus *b= us) */ int __mdiobus_register(struct mii_bus *bus, struct module *owner) { - struct mdio_device *mdiodev; struct gpio_desc *gpiod; bool prevent_c45_scan; - int i, err; + int err; =20 if (!bus || !bus->name) return -EINVAL; @@ -596,7 +668,9 @@ int __mdiobus_register(struct mii_bus *bus, struct modu= le *owner) * * State will be updated later in this function in case of success */ + mutex_lock(&bus->mdio_map_lock); bus->state =3D MDIOBUS_UNREGISTERED; + mutex_unlock(&bus->mdio_map_lock); =20 err =3D device_register(&bus->dev); if (err) { @@ -613,8 +687,7 @@ int __mdiobus_register(struct mii_bus *bus, struct modu= le *owner) err =3D dev_err_probe(&bus->dev, PTR_ERR(gpiod), "mii_bus %s couldn't get reset GPIO\n", bus->id); - device_del(&bus->dev); - return err; + goto error_reset_gpiod; } else if (gpiod) { bus->reset_gpiod =3D gpiod; fsleep(bus->reset_delay_us); @@ -629,6 +702,10 @@ int __mdiobus_register(struct mii_bus *bus, struct mod= ule *owner) goto error_reset_gpiod; } =20 + mutex_lock(&bus->mdio_map_lock); + bus->state =3D MDIOBUS_REGISTERING; + mutex_unlock(&bus->mdio_map_lock); + if (bus->read) { err =3D mdiobus_scan_bus_c22(bus); if (err) @@ -643,20 +720,17 @@ int __mdiobus_register(struct mii_bus *bus, struct mo= dule *owner) goto error; } =20 + mutex_lock(&bus->mdio_map_lock); bus->state =3D MDIOBUS_REGISTERED; + mutex_unlock(&bus->mdio_map_lock); dev_dbg(&bus->dev, "probed\n"); return 0; =20 error: - for (i =3D 0; i < PHY_MAX_ADDR; i++) { - mdiodev =3D bus->mdio_map[i]; - if (!mdiodev) - continue; - - mdiodev->device_remove(mdiodev); - mdiodev->device_free(mdiodev); - } error_reset_gpiod: + mdiobus_stop_device_changes(bus); + mdiobus_remove_devices(bus); + /* Put PHYs in RESET to save power */ if (bus->reset_gpiod) gpiod_set_value_cansleep(bus->reset_gpiod, 1); @@ -668,21 +742,11 @@ EXPORT_SYMBOL(__mdiobus_register); =20 void mdiobus_unregister(struct mii_bus *bus) { - struct mdio_device *mdiodev; - int i; - if (WARN_ON_ONCE(bus->state !=3D MDIOBUS_REGISTERED)) return; - bus->state =3D MDIOBUS_UNREGISTERED; - - for (i =3D 0; i < PHY_MAX_ADDR; i++) { - mdiodev =3D bus->mdio_map[i]; - if (!mdiodev) - continue; =20 - mdiodev->device_remove(mdiodev); - mdiodev->device_free(mdiodev); - } + mdiobus_stop_device_changes(bus); + mdiobus_remove_devices(bus); =20 /* Put PHYs in RESET to save power */ if (bus->reset_gpiod) @@ -702,8 +766,11 @@ EXPORT_SYMBOL(mdiobus_unregister); */ void mdiobus_free(struct mii_bus *bus) { + mutex_lock(&bus->mdio_map_lock); + /* For compatibility with error handling in drivers. */ if (bus->state =3D=3D MDIOBUS_ALLOCATED) { + mutex_unlock(&bus->mdio_map_lock); kfree(bus); return; } @@ -711,6 +778,7 @@ void mdiobus_free(struct mii_bus *bus) WARN(bus->state !=3D MDIOBUS_UNREGISTERED, "%s: not in UNREGISTERED state\n", bus->id); bus->state =3D MDIOBUS_RELEASED; + mutex_unlock(&bus->mdio_map_lock); =20 put_device(&bus->dev); } diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c index 56080d3d2d25..49092045831f 100644 --- a/drivers/net/phy/mdio_device.c +++ b/drivers/net/phy/mdio_device.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -38,8 +39,12 @@ static int mdio_device_register_reset(struct mdio_device= *mdiodev) /* Deassert the optional reset signal */ mdiodev->reset_gpio =3D gpiod_get_optional(&mdiodev->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(mdiodev->reset_gpio)) - return PTR_ERR(mdiodev->reset_gpio); + if (IS_ERR(mdiodev->reset_gpio)) { + int err =3D PTR_ERR(mdiodev->reset_gpio); + + mdiodev->reset_gpio =3D NULL; + return err; + } =20 if (mdiodev->reset_gpio) gpiod_set_consumer_name(mdiodev->reset_gpio, "PHY reset"); @@ -117,6 +122,13 @@ static void mdio_device_release(struct device *dev) kfree(to_mdio_device(dev)); } =20 +static int __mdio_device_remove(struct mdio_device *mdiodev, bool dynamic); + +static int mdio_device_remove_dynamic(struct mdio_device *mdiodev) +{ + return __mdio_device_remove(mdiodev, true); +} + struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr) { struct mdio_device *mdiodev; @@ -131,9 +143,11 @@ struct mdio_device *mdio_device_create(struct mii_bus = *bus, int addr) mdiodev->dev.bus =3D &mdio_bus_type; mdiodev->device_free =3D mdio_device_free; mdiodev->device_remove =3D mdio_device_remove; + mdiodev->device_remove_dynamic =3D mdio_device_remove_dynamic; mdiodev->bus =3D bus; mdiodev->addr =3D addr; mdiodev->reset_state =3D -1; + INIT_LIST_HEAD(&mdiodev->retired_node); =20 dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr); =20 @@ -160,19 +174,27 @@ int mdio_device_register(struct mdio_device *mdiodev) return err; =20 err =3D device_add(&mdiodev->dev); - if (err) { + if (err) pr_err("MDIO %d failed to add\n", mdiodev->addr); - goto out; - } - - return 0; =20 - out: - mdiobus_unregister_device(mdiodev); - return err; + return mdiobus_registration_done(mdiodev, err); } EXPORT_SYMBOL(mdio_device_register); =20 +static int __mdio_device_remove(struct mdio_device *mdiodev, bool dynamic) +{ + int err; + + err =3D mdiobus_begin_remove(mdiodev, dynamic); + if (err) + return err; + + device_del(&mdiodev->dev); + mdiobus_finish_remove(mdiodev, dynamic); + + return 0; +} + /** * mdio_device_remove - Remove a previously registered mdio device from the * MDIO bus @@ -184,42 +206,211 @@ EXPORT_SYMBOL(mdio_device_register); */ void mdio_device_remove(struct mdio_device *mdiodev) { - device_del(&mdiodev->dev); - mdiobus_unregister_device(mdiodev); + __mdio_device_remove(mdiodev, false); } EXPORT_SYMBOL(mdio_device_remove); =20 int mdiobus_register_device(struct mdio_device *mdiodev) { + struct mii_bus *bus =3D mdiodev->bus; int err; =20 - if (mdiodev->bus->mdio_map[mdiodev->addr]) - return -EBUSY; + mutex_lock(&bus->mdio_map_lock); + if (bus->state !=3D MDIOBUS_REGISTERING && + bus->state !=3D MDIOBUS_REGISTERED) { + err =3D -ENODEV; + goto out_unlock; + } + if (bus->mdio_map_removals) { + err =3D -EBUSY; + goto out_unlock; + } + + if (bus->mdio_map[mdiodev->addr] || + bus->mdio_map_pending & BIT(mdiodev->addr)) { + err =3D -EBUSY; + goto out_unlock; + } + + bus->mdio_map_pending |=3D BIT(mdiodev->addr); + bus->mdio_map_ops++; + mutex_unlock(&bus->mdio_map_lock); =20 if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) { err =3D mdio_device_register_reset(mdiodev); - if (err) + if (err) { + mdiobus_registration_done(mdiodev, err); return err; + } =20 /* Assert the reset signal */ mdio_device_reset(mdiodev, 1); } =20 - mdiodev->bus->mdio_map[mdiodev->addr] =3D mdiodev; + mutex_lock(&bus->mdio_map_lock); + /* Teardown waits for this registration before consuming the map. */ + smp_store_release(&bus->mdio_map[mdiodev->addr], mdiodev); + mutex_unlock(&bus->mdio_map_lock); =20 return 0; + +out_unlock: + mutex_unlock(&bus->mdio_map_lock); + return err; } =20 -int mdiobus_unregister_device(struct mdio_device *mdiodev) +/** + * mdiobus_device_change_begin - start changing devices on a registered bus + * @bus: MDIO bus that will be scanned or changed + * @removing: whether PHY attachment must be blocked during the change + * + * Return: zero on success or a negative error code when the bus is unavai= lable + */ +int mdiobus_device_change_begin(struct mii_bus *bus, bool removing) { - if (mdiodev->bus->mdio_map[mdiodev->addr] !=3D mdiodev) - return -EINVAL; + int err =3D 0; + + mutex_lock(&bus->mdio_map_lock); + if (bus->state !=3D MDIOBUS_REGISTERED) { + err =3D -ENODEV; + } else { + bus->mdio_map_ops++; + if (removing) + bus->mdio_map_removals++; + } + mutex_unlock(&bus->mdio_map_lock); + + return err; +} +EXPORT_SYMBOL_GPL(mdiobus_device_change_begin); =20 - mdio_device_unregister_reset(mdiodev); +static void mdiobus_operation_done_locked(struct mii_bus *bus) +{ + lockdep_assert_held(&bus->mdio_map_lock); =20 - mdiodev->bus->mdio_map[mdiodev->addr] =3D NULL; + if (WARN_ON_ONCE(!bus->mdio_map_ops)) + return; + bus->mdio_map_ops--; + if (!bus->mdio_map_ops) + wake_up_all(&bus->mdio_map_wait); +} =20 - return 0; +/** + * mdiobus_device_change_end - finish changing devices on an MDIO bus + * @bus: MDIO bus previously passed to mdiobus_device_change_begin() + * @removing: value passed to mdiobus_device_change_begin() + */ +void mdiobus_device_change_end(struct mii_bus *bus, bool removing) +{ + mutex_lock(&bus->mdio_map_lock); + if (removing) { + if (!WARN_ON_ONCE(!bus->mdio_map_removals)) + bus->mdio_map_removals--; + } + mdiobus_operation_done_locked(bus); + mutex_unlock(&bus->mdio_map_lock); +} +EXPORT_SYMBOL_GPL(mdiobus_device_change_end); + +static void mdiobus_operation_done(struct mii_bus *bus) +{ + mutex_lock(&bus->mdio_map_lock); + mdiobus_operation_done_locked(bus); + mutex_unlock(&bus->mdio_map_lock); +} + +static void mdiobus_unpublish_device(struct mdio_device *mdiodev) +{ + struct mii_bus *bus =3D mdiodev->bus; + + lockdep_assert_held(&bus->mdio_map_lock); + + if (bus->mdio_map[mdiodev->addr] =3D=3D mdiodev) + WRITE_ONCE(bus->mdio_map[mdiodev->addr], NULL); + if (mdiodev->dev.of_node) + of_node_clear_flag(mdiodev->dev.of_node, OF_POPULATED); +} + +int mdiobus_registration_done(struct mdio_device *mdiodev, int err) +{ + struct mii_bus *bus =3D mdiodev->bus; + + mutex_lock(&bus->mdio_map_lock); + if (WARN_ON_ONCE(!(bus->mdio_map_pending & BIT(mdiodev->addr)))) + goto out_unlock; + + if (err) + mdiobus_unpublish_device(mdiodev); + else + WARN_ON_ONCE(bus->mdio_map[mdiodev->addr] !=3D mdiodev); + + bus->mdio_map_pending &=3D ~BIT(mdiodev->addr); + +out_unlock: + mutex_unlock(&bus->mdio_map_lock); + if (err) { + if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) { + mdio_device_reset(mdiodev, 1); + mdio_device_unregister_reset(mdiodev); + } + } + mdiobus_operation_done(bus); + + return err; +} + +int mdiobus_begin_remove(struct mdio_device *mdiodev, bool dynamic) +{ + struct mii_bus *bus =3D mdiodev->bus; + int err =3D 0; + + mutex_lock(&bus->mdio_map_lock); + if (dynamic && (bus->state =3D=3D MDIOBUS_UNREGISTERED || + bus->state =3D=3D MDIOBUS_RELEASED)) { + err =3D -ENODEV; + goto out_unlock; + } + if (bus->mdio_map_pending & BIT(mdiodev->addr)) { + err =3D -EBUSY; + goto out_unlock; + } + + if (bus->mdio_map[mdiodev->addr] !=3D mdiodev) { + err =3D -ENODEV; + goto out_unlock; + } + + if (dynamic && mdiodev->flags & MDIO_DEVICE_FLAG_PHY && + to_phy_device(&mdiodev->dev)->attached) { + err =3D -EBUSY; + goto out_unlock; + } + + mdiobus_unpublish_device(mdiodev); + + if (dynamic) { + mdio_device_get(mdiodev); + list_add_tail(&mdiodev->retired_node, &bus->mdio_map_retired); + } + +out_unlock: + mutex_unlock(&bus->mdio_map_lock); + return err; +} + +void mdiobus_finish_remove(struct mdio_device *mdiodev, bool dynamic) +{ + struct fwnode_handle *fwnode; + + if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) + mdio_device_unregister_reset(mdiodev); + + /* Do not keep an overlay node alive with the retired device. */ + if (dynamic) { + fwnode =3D dev_fwnode(&mdiodev->dev); + device_set_node(&mdiodev->dev, NULL); + fwnode_handle_put(fwnode); + } } =20 /** diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 0615228459ef..f7472a743185 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -227,6 +227,8 @@ static void phy_device_release(struct device *dev) kfree(to_phy_device(dev)); } =20 +static int __phy_device_remove(struct phy_device *phydev, bool dynamic); + static void phy_mdio_device_remove(struct mdio_device *mdiodev) { struct phy_device *phydev; @@ -235,6 +237,14 @@ static void phy_mdio_device_remove(struct mdio_device = *mdiodev) phy_device_remove(phydev); } =20 +static int phy_mdio_device_remove_dynamic(struct mdio_device *mdiodev) +{ + struct phy_device *phydev; + + phydev =3D container_of(mdiodev, struct phy_device, mdio); + return __phy_device_remove(phydev, true); +} + static struct phy_driver genphy_driver; =20 static LIST_HEAD(phy_fixup_list); @@ -768,7 +778,9 @@ struct phy_device *phy_device_create(struct mii_bus *bu= s, int addr, u32 phy_id, mdiodev->flags =3D MDIO_DEVICE_FLAG_PHY; mdiodev->device_free =3D phy_mdio_device_free; mdiodev->device_remove =3D phy_mdio_device_remove; + mdiodev->device_remove_dynamic =3D phy_mdio_device_remove_dynamic; mdiodev->reset_state =3D -1; + INIT_LIST_HEAD(&mdiodev->retired_node); =20 dev->speed =3D SPEED_UNKNOWN; dev->duplex =3D DUPLEX_UNKNOWN; @@ -1121,25 +1133,40 @@ int phy_device_register(struct phy_device *phydev) err =3D phy_scan_fixups(phydev); if (err) { phydev_err(phydev, "failed to initialize\n"); - goto out; + return mdiobus_registration_done(&phydev->mdio, err); } =20 err =3D device_add(&phydev->mdio.dev); - if (err) { + if (err) phydev_err(phydev, "failed to add\n"); - goto out; - } =20 - return 0; + return mdiobus_registration_done(&phydev->mdio, err); +} +EXPORT_SYMBOL(phy_device_register); + +static int __phy_device_remove(struct phy_device *phydev, bool dynamic) +{ + int err; + + err =3D mdiobus_begin_remove(&phydev->mdio, dynamic); + if (dynamic && err =3D=3D -EBUSY) + dev_warn(&phydev->mdio.dev, + "cannot remove a PHY while it is attached or being registered\n"); + if (err) + return err; + + unregister_mii_timestamper(phydev->mii_ts); + pse_control_put(phydev->psec); + + device_del(&phydev->mdio.dev); =20 - out: /* Assert the reset signal */ phy_device_reset(phydev, 1); =20 - mdiobus_unregister_device(&phydev->mdio); - return err; + mdiobus_finish_remove(&phydev->mdio, dynamic); + + return 0; } -EXPORT_SYMBOL(phy_device_register); =20 /** * phy_device_remove - Remove a previously registered phy device from the = MDIO bus @@ -1151,15 +1178,7 @@ EXPORT_SYMBOL(phy_device_register); */ void phy_device_remove(struct phy_device *phydev) { - unregister_mii_timestamper(phydev->mii_ts); - pse_control_put(phydev->psec); - - device_del(&phydev->mdio.dev); - - /* Assert the reset signal */ - phy_device_reset(phydev, 1); - - mdiobus_unregister_device(&phydev->mdio); + __phy_device_remove(phydev, false); } EXPORT_SYMBOL(phy_device_remove); =20 @@ -1734,6 +1753,36 @@ static bool phy_drv_supports_irq(const struct phy_dr= iver *phydrv) return phydrv->config_intr && phydrv->handle_interrupt; } =20 +static int phy_claim(struct phy_device *phydev) +{ + struct mdio_device *mdiodev =3D &phydev->mdio; + struct mii_bus *bus =3D mdiodev->bus; + int err =3D 0; + + mutex_lock(&bus->mdio_map_lock); + if (bus->state !=3D MDIOBUS_REGISTERED || + bus->mdio_map_removals || + bus->mdio_map[mdiodev->addr] !=3D mdiodev || + (bus->mdio_map_pending & BIT(mdiodev->addr))) + err =3D -ENODEV; + else if (phydev->attached) + err =3D -EBUSY; + else + phydev->attached =3D true; + mutex_unlock(&bus->mdio_map_lock); + + return err; +} + +static void phy_release(struct phy_device *phydev) +{ + struct mii_bus *bus =3D phydev->mdio.bus; + + mutex_lock(&bus->mdio_map_lock); + phydev->attached =3D false; + mutex_unlock(&bus->mdio_map_lock); +} + /** * phy_attach_direct - attach a network device to a given PHY device point= er * @dev: network device to attach @@ -1755,6 +1804,7 @@ int phy_attach_direct(struct net_device *dev, struct = phy_device *phydev, struct mii_bus *bus =3D phydev->mdio.bus; struct device *d =3D &phydev->mdio.dev; struct module *ndev_owner =3D NULL; + bool claimed =3D false; int err; =20 /* For Ethernet device drivers that register their own MDIO bus, we @@ -1770,6 +1820,13 @@ int phy_attach_direct(struct net_device *dev, struct= phy_device *phydev, } =20 get_device(d); + err =3D phy_claim(phydev); + if (err =3D=3D -EBUSY) + phydev_err(phydev, "PHY already attached\n"); + if (!err) + claimed =3D true; + if (err) + goto error_put_device; =20 /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. @@ -1798,12 +1855,6 @@ int phy_attach_direct(struct net_device *dev, struct= phy_device *phydev, goto error_module_put; } =20 - if (phydev->attached_dev) { - dev_err(&dev->dev, "PHY already attached\n"); - err =3D -EBUSY; - goto error; - } - phydev->phy_link_change =3D phy_link_change; if (dev) { phydev->attached_dev =3D dev; @@ -1899,6 +1950,8 @@ int phy_attach_direct(struct net_device *dev, struct = phy_device *phydev, phydev->is_genphy_driven =3D 0; d->driver =3D NULL; error_put_device: + if (claimed) + phy_release(phydev); put_device(d); if (ndev_owner !=3D bus->owner) module_put(bus->owner); @@ -1977,6 +2030,7 @@ void phy_detach(struct phy_device *phydev) * a use-after-free bug by reading the underlying bus first. */ bus =3D phydev->mdio.bus; + phy_release(phydev); =20 put_device(&phydev->mdio.dev); if (dev) diff --git a/drivers/net/phy/phylib-internal.h b/drivers/net/phy/phylib-int= ernal.h index 664ed7faa518..7e9161fcdd90 100644 --- a/drivers/net/phy/phylib-internal.h +++ b/drivers/net/phy/phylib-internal.h @@ -25,7 +25,9 @@ int phy_speed_down_core(struct phy_device *phydev); void phy_check_downshift(struct phy_device *phydev); =20 int mdiobus_register_device(struct mdio_device *mdiodev); -int mdiobus_unregister_device(struct mdio_device *mdiodev); +int mdiobus_registration_done(struct mdio_device *mdiodev, int err); +int mdiobus_begin_remove(struct mdio_device *mdiodev, bool dynamic); +void mdiobus_finish_remove(struct mdio_device *mdiodev, bool dynamic); =20 int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv); =20 diff --git a/include/linux/mdio.h b/include/linux/mdio.h index f4f9d9609448..41c60798fa0e 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -8,6 +8,7 @@ =20 #include #include +#include #include =20 struct gpio_desc; @@ -33,6 +34,9 @@ struct mdio_device { int (*bus_match)(struct device *dev, const struct device_driver *drv); void (*device_free)(struct mdio_device *mdiodev); void (*device_remove)(struct mdio_device *mdiodev); + int (*device_remove_dynamic)(struct mdio_device *mdiodev); + /* Entry in mii_bus::mdio_map_retired. */ + struct list_head retired_node; =20 /* Bus address of the MDIO device (0-31) */ int addr; @@ -690,6 +694,8 @@ static inline int mdiodev_c45_write(struct mdio_device = *mdiodev, u32 devad, =20 bool mdiobus_is_registered_device(struct mii_bus *bus, int addr); struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr); +int mdiobus_device_change_begin(struct mii_bus *bus, bool removing); +void mdiobus_device_change_end(struct mii_bus *bus, bool removing); =20 /** * mdio_module_driver() - Helper macro for registering mdio drivers diff --git a/include/linux/phy.h b/include/linux/phy.h index fc680901275b..2eba54e068f6 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -391,7 +392,9 @@ struct mii_bus { /** @state: State of bus structure */ enum { MDIOBUS_ALLOCATED =3D 1, + MDIOBUS_REGISTERING, MDIOBUS_REGISTERED, + MDIOBUS_UNREGISTERING, MDIOBUS_UNREGISTERED, MDIOBUS_RELEASED, } state; @@ -401,6 +404,18 @@ struct mii_bus { =20 /** @mdio_map: list of all MDIO devices on bus */ struct mdio_device *mdio_map[PHY_MAX_ADDR]; + /** @mdio_map_pending: addresses with registration in progress */ + u32 mdio_map_pending; + /** @mdio_map_lock: protects the MDIO device map and bus state */ + struct mutex mdio_map_lock; + /** @mdio_map_wait: wait for active map operations during teardown */ + wait_queue_head_t mdio_map_wait; + /** @mdio_map_ops: active registrations and firmware changes */ + unsigned int mdio_map_ops; + /** @mdio_map_removals: firmware removals blocking PHY attachment */ + unsigned int mdio_map_removals; + /** @mdio_map_retired: removed devices pinned until bus teardown */ + struct list_head mdio_map_retired; =20 /** @phy_mask: PHY addresses to be ignored when probing */ u32 phy_mask; @@ -652,6 +667,8 @@ struct phy_oatc14_sqi_capability { * @n_ports: Number of ports currently attached to the PHY * @max_n_ports: Max number of ports this PHY can expose * @lock: Mutex for serialization access to PHY + * @attached: Whether a network device or standalone user attached the PHY; + * protected by the MDIO bus map lock * @state_queue: Work queue for state machine * @link_down_events: Number of times link was lost * @shared: Pointer to private data shared by phys in one package @@ -781,6 +798,7 @@ struct phy_device { struct delayed_work state_queue; =20 struct mutex lock; + bool attached; =20 /* This may be modified under the rtnl lock */ bool sfp_bus_attached; --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f46.google.com (mail-ot1-f46.google.com [209.85.210.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 873803932FF for ; Mon, 3 Aug 2026 05:15:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734131; cv=none; b=qbHkI9G9gVCLmA1b8qY/rZiTEUfmVYFe2NpClEW+zzSi2zJhi+SPd26jsJZjybKs0Q5lSe9lRdMr5HSPZNxYF8sbEGrK0LcJb3Ke6opG2WSGXuENXe/lDcb4sOegs77i3qWlmVTib2NBZQ2KdThGK7i1jUb18vW6zmjrucpNots= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734131; c=relaxed/simple; bh=Tw9U9x3x5olXZaLQIjQpOA/JFbVYSe4nj6Dx94hoQbg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DNYzoKctFr1tINGRsy8uJi8zwLIYHd3SGdWVCidob1oOz/FQpDowS7LmFfOEh+2s0AM4Dvd9zyyaPAViVL2iMvA81Y0/l/5L06QA0eIMQcABg0ZmNYBruWLpelSvZaZQXkekXcZEMVHWoTdF8dOUvy8b7S5K11vzwZKhHfM5lyM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=PI3ynZKA; arc=none smtp.client-ip=209.85.210.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PI3ynZKA" Received: by mail-ot1-f46.google.com with SMTP id 46e09a7af769-7eb64371a2aso1680072a34.0 for ; Sun, 02 Aug 2026 22:15:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734128; x=1786338928; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=maRxG9UiuybqBbIKlnDyAqHdPuODzpVicj9v0akXa2o=; b=PI3ynZKApwksDItDns6PLbbyXFU6wL/sIXX+zoPwPPNUOHOdjJ/MJ3R5JeNqnTAGFX J3+op47O/+RyRObhsul/oebbXra1UdwzK9qRgs6tyKvVFXUY/UoIJezahUiwuVKtflYu YTqXtVUfWkJuCVNmQ42a87V09dV7mbjWxweordsjhKZ2Z0wCulQ/CzNMwwtKUw0G9DXm vZ8S0FB4aoNADSG9fwzXnevXXE87fyEBAuZ1paz6fBxFV/2bNxIGR8119aW9Kr8+jMpV n8xe0J1TT0ET3dWSurUZPb5AX5e700bA1FCFmCxMH4S7fYVNb+DU9QSE9iMzJ6L9WQcM Ne2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734128; x=1786338928; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=maRxG9UiuybqBbIKlnDyAqHdPuODzpVicj9v0akXa2o=; b=A0NOST6ax3TaTOLNOznUAsXDUq56o/OagzVKtYS9l0f6Idtkjif+9+wSz3GghXGRtt 46HaWu5a9zUGGfT7URx3x1UxEOtbQDWYGcycE11ZRNUXzEGmKez3L5z9UAOLzDpkl24l YiO0z2NDzhNU2I2zfdWZSTMO/HtPDZHMsoHi0Wqhk5oAaPaj46OV9d9u5m8VSj88itOb 0uOo93TJPSIxPVDVdiwHgS+UtPp2dOYZ8es/yK3XYSVdWani6CIp9pZKuJW0I/kU4qlZ YKTpXVV9l9bsuz/oi6VkAM6aoLfdqwwWDtKPToH4SnsZK6kV4h0Nh6HZtlyDltPzHIuA Xh9A== X-Forwarded-Encrypted: i=1; AHgh+RrVG6p9YM3Hksag7jhISU12BiZ7Gf8+smyswZNeJlIoBdbJwff5blrpLP8hsNzB5dnlfwbk3saC9zOruvI=@vger.kernel.org X-Gm-Message-State: AOJu0YzygQQoqpxyfQVp31jzC2NlpCUJ0OEtukkpe6v0Calgv7GqsijF 4tjnXuG27li89V5F8LXdlsfh6Jr8JLH55rEuVq+15Zh4z132Dimy2g5C X-Gm-Gg: AR+sD12bFqi/MWLuTeAcn18ZzcZ1NRb7Z2MYm0Fj0jbvqbObeOHYXOMKPo+urD5AfWZ 0Bgt8N1NHOx/uE8pHSCb/Eygehkp4ieO3cmMi2wovXZtHpwKB29amaoGJU+Eju7FHV6eUwjpPmz rdvj06uD0/fbqoKINM57vcFgPF6NLrgUZIq/YB0vyw+ePcy9OoGzdxDdphf3A4eFCp3tr6PFrMo Bw7iOWEbZUvwWIiBomR9D0x/JAitCWO1BZhIIBpe+WmO2RC7xtEzhU4qQfTpvPjQtWIFR4Ii1q9 3JThQpjYyJV8PNfyNrg/mINR0Ym1lv4SODL0zUjXMy1I00B+8qK0IQdVCa5nAAboHDZy5A/ja34 ta25aHw3xDW91Ttmz1VnhyCyKW2Bai+D/5XVr+zmzee2Av3UoXKAVd4FC9lOrncbck6LZ7ZXQdm JVjh/YX3RkjCHU2rmTihMCpQk7NEF+JDtdvsXh+wSUnNIcEIW3VwgP6E+nQvmbQ26+JYMMmorfg QYmw1+42xTFPVwrJ3hJ23D+GrXymoXLwU3oGtOXwVYLB/jBjJBfEUdNiDXSdlX/WVTrFP8srCR7 0keZoJ0C2WWGFxo751YGmYT6L++ZCl6kksfe31zNctpkYRQLOaEDSahdI6DzQ5+4YIHtsNfF8Kh dBfclnUMQmLAmFmbB X-Received: by 2002:a05:6830:61ce:b0:7dc:3db6:f02 with SMTP id 46e09a7af769-7f196d51885mr15457605a34.9.1785734128311; Sun, 02 Aug 2026 22:15:28 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:27 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:16 -0600 Subject: [PATCH 06/21] net: mdio: support dynamic OF device changes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-6-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 MDIO buses enumerate firmware children only when the bus is registered. A later DT overlay or status transition is ignored, unlike I2C and SPI. Add an OF reconfiguration notifier. On addition, create fixed-address PHYs and generic MDIO devices, scan free addresses for legacy PHY nodes without reg, and recurse into Ethernet PHY packages. Track populated nodes so static enumeration, address scanning and notifier-driven enumeration cannot create duplicates. Walk every package child and report the first population error without undoing devices which may already have acquired consumers. Serialize static and notifier-driven population while allowing a PHY probe to enable another node on the same bus. Check the node's current state after taking that lock so an older notification cannot override a newer status change. On removal, reject attached or in-flight PHYs and unregister the object found by its OF node. This also covers PHYs found by address scanning. Treat all PHYs in a package as one removal scope, so removing one member cannot invalidate state used by an attached peer. Preflight overlay removal while it can still be refused; normal changeset errors are propagated so the caller can restore the previous state. Hold a core MDIO change transaction across discovery and registration so bus teardown cannot race the MDIO reads used to identify a PHY. Compile the notifier only with CONFIG_OF_DYNAMIC and the overlay preflight only with CONFIG_OF_OVERLAY. Signed-off-by: James Hilliard --- drivers/net/mdio/of_mdio.c | 448 +++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 438 insertions(+), 10 deletions(-) diff --git a/drivers/net/mdio/of_mdio.c b/drivers/net/mdio/of_mdio.c index 051e449bbe7c..a8313b3721f6 100644 --- a/drivers/net/mdio/of_mdio.c +++ b/drivers/net/mdio/of_mdio.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,8 @@ #include #include #include +#include +#include =20 #define DEFAULT_GPIO_RESET_DELAY 10 /* in microseconds */ =20 @@ -27,6 +30,52 @@ MODULE_AUTHOR("Grant Likely "= ); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("OpenFirmware MDIO bus (Ethernet PHY) accessors"); =20 +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +/* + * OF changes can nest when probing one MDIO device enables another node on + * the same bus. Serialize independent changes while allowing that nesting. + */ +static DEFINE_MUTEX(of_mdio_reconfig_mutex); +static struct task_struct *of_mdio_reconfig_owner; +static unsigned int of_mdio_reconfig_depth; + +static void of_mdio_reconfig_lock(void) +{ + if (!mutex_trylock(&of_mdio_reconfig_mutex)) { + if (of_mdio_reconfig_owner =3D=3D current) { + of_mdio_reconfig_depth++; + return; + } + mutex_lock(&of_mdio_reconfig_mutex); + } + + WARN_ON_ONCE(of_mdio_reconfig_owner); + WARN_ON_ONCE(of_mdio_reconfig_depth); + of_mdio_reconfig_owner =3D current; + of_mdio_reconfig_depth =3D 1; +} + +static void of_mdio_reconfig_unlock(void) +{ + WARN_ON_ONCE(of_mdio_reconfig_owner !=3D current); + WARN_ON_ONCE(!of_mdio_reconfig_depth); + + if (--of_mdio_reconfig_depth) + return; + + of_mdio_reconfig_owner =3D NULL; + mutex_unlock(&of_mdio_reconfig_mutex); +} +#else +static inline void of_mdio_reconfig_lock(void) +{ +} + +static inline void of_mdio_reconfig_unlock(void) +{ +} +#endif + /* Extract the clause 22 phy ID from the compatible string of the form * ethernet-phy-idAAAA.BBBB */ static int of_get_phy_id(struct device_node *device, u32 *phy_id) @@ -44,7 +93,7 @@ int of_mdiobus_phy_device_register(struct mii_bus *mdio, = struct phy_device *phy, EXPORT_SYMBOL(of_mdiobus_phy_device_register); =20 static int of_mdiobus_register_phy(struct mii_bus *mdio, - struct device_node *child, u32 addr) + struct device_node *child, u32 addr) { return fwnode_mdiobus_register_phy(mdio, of_fwnode_handle(child), addr); } @@ -80,10 +129,20 @@ static int of_mdiobus_register_device(struct mii_bus *= mdio, static int of_mdiobus_register_child(struct mii_bus *mdio, struct device_node *child, u32 addr) { + int rc; + + if (of_node_test_and_set_flag(child, OF_POPULATED)) + return 0; + if (of_mdiobus_child_is_phy(child)) - return of_mdiobus_register_phy(mdio, child, addr); + rc =3D of_mdiobus_register_phy(mdio, child, addr); + else + rc =3D of_mdiobus_register_device(mdio, child, addr); =20 - return of_mdiobus_register_device(mdio, child, addr); + if (rc) + of_node_clear_flag(child, OF_POPULATED); + + return rc; } =20 /* The following is a list of PHY compatible strings which appear in @@ -255,13 +314,21 @@ int __of_mdiobus_register(struct mii_bus *mdio, struc= t device_node *np, if (rc) return rc; =20 + of_mdio_reconfig_lock(); + rc =3D mdiobus_device_change_begin(mdio, false); + if (rc) { + of_mdio_reconfig_unlock(); + mdiobus_unregister(mdio); + return rc; + } + /* Loop over the child nodes and register a phy_device for each phy */ rc =3D __of_mdiobus_parse_phys(mdio, np, &scanphys); if (rc) - goto unregister; + goto out_change; =20 if (!scanphys) - return 0; + goto out_change; =20 /* auto scan for PHYs with empty reg property */ for_each_available_child_of_node(np, child) { @@ -272,19 +339,380 @@ int __of_mdiobus_register(struct mii_bus *mdio, stru= ct device_node *np, =20 rc =3D of_mdiobus_scan_phy(mdio, child); if (rc && rc !=3D -ENODEV) - goto put_unregister; + goto put_child; + rc =3D 0; } =20 - return 0; +out_change: + mdiobus_device_change_end(mdio, false); + of_mdio_reconfig_unlock(); + if (!rc) + return 0; =20 -put_unregister: - of_node_put(child); -unregister: mdiobus_unregister(mdio); return rc; + +put_child: + of_node_put(child); + goto out_change; } EXPORT_SYMBOL(__of_mdiobus_register); =20 +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +static bool of_mdiobus_node_is_available(struct device_node *node) +{ + return !of_node_check_flag(node, OF_DETACHED) && + of_device_is_available(node); +} + +static int of_mdiobus_add_node(struct mii_bus *mdio, + struct device_node *node) +{ + struct device_node *child; + int addr, rc, ret =3D 0; + + if (!of_mdiobus_node_is_available(node)) + return 0; + + if (of_node_name_eq(node, "ethernet-phy-package")) { + if (!of_property_present(node, "reg")) + return 0; + + for_each_available_child_of_node(node, child) { + rc =3D of_mdiobus_add_node(mdio, child); + if (rc && rc !=3D -ENODEV && !ret) + ret =3D rc; + } + + return ret; + } + + addr =3D of_mdio_parse_addr(&mdio->dev, node); + if (addr < 0) + rc =3D of_mdiobus_scan_phy(mdio, node); + else + rc =3D of_mdiobus_register_child(mdio, node, addr); + + if (rc =3D=3D -ENODEV && addr >=3D 0) + dev_err(&mdio->dev, + "MDIO device at address %d is missing.\n", addr); + + return rc; +} + +static bool of_mdiobus_node_is_busy(struct mii_bus *mdio, + struct device_node *node) +{ + struct mdio_device *mdiodev; + bool busy =3D false; + + if (of_node_name_eq(node, "ethernet-phy-package")) { + for_each_child_of_node_scoped(node, child) { + if (of_mdiobus_node_is_busy(mdio, child)) + return true; + } + + return false; + } + + if (!of_node_check_flag(node, OF_POPULATED)) + return false; + + mdiodev =3D of_mdio_find_device(node); + if (!mdiodev) + return true; + if (mdiodev->bus !=3D mdio) { + put_device(&mdiodev->dev); + return false; + } + + mutex_lock(&mdio->mdio_map_lock); + busy =3D mdio->mdio_map[mdiodev->addr] !=3D mdiodev || + (mdio->mdio_map_pending & BIT(mdiodev->addr)); + if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) { + struct phy_device *phydev =3D to_phy_device(&mdiodev->dev); + + if (phydev->attached) { + busy =3D true; + dev_warn(&mdiodev->dev, + "cannot remove an attached PHY; remove its consumer first\n"); + } + } + mutex_unlock(&mdio->mdio_map_lock); + put_device(&mdiodev->dev); + + return busy; +} + +static struct device_node * +of_mdiobus_get_removal_scope(struct device_node *node) +{ + struct device_node *parent; + + if (of_node_name_eq(node, "ethernet-phy-package")) + return of_node_get(node); + + parent =3D of_get_parent(node); + if (of_node_name_eq(parent, "ethernet-phy-package")) + return parent; + + of_node_put(parent); + return of_node_get(node); +} + +static int of_mdiobus_remove_node(struct mii_bus *mdio, + struct device_node *node) +{ + struct mdio_device *mdiodev; + struct device_node *child; + int ret; + + if (of_node_name_eq(node, "ethernet-phy-package")) { + for_each_child_of_node(node, child) { + ret =3D of_mdiobus_remove_node(mdio, child); + if (ret) { + of_node_put(child); + return ret; + } + } + return 0; + } + + if (!of_node_check_flag(node, OF_POPULATED)) + return 0; + + /* The OF node lookup also covers PHYs found by address scanning. */ + mdiodev =3D of_mdio_find_device(node); + if (!mdiodev) + return -EBUSY; + if (mdiodev->bus !=3D mdio) { + put_device(&mdiodev->dev); + return -ENODEV; + } + + ret =3D mdiodev->device_remove_dynamic(mdiodev); + if (!ret) + mdiodev->device_free(mdiodev); + put_device(&mdiodev->dev); + + return ret =3D=3D -ENODEV ? 0 : ret; +} + +static struct mii_bus *of_mdiobus_find_parent(struct device_node *node) +{ + struct device_node *parent, *bus_node; + struct mii_bus *mdio; + + parent =3D of_get_parent(node); + if (!parent) + return NULL; + + if (of_node_name_eq(parent, "ethernet-phy-package")) { + if (!of_device_is_available(parent) || + !of_property_present(parent, "reg")) { + of_node_put(parent); + return NULL; + } + + bus_node =3D of_get_parent(parent); + of_node_put(parent); + } else { + bus_node =3D parent; + } + + mdio =3D of_mdio_find_bus(bus_node); + of_node_put(bus_node); + + return mdio; +} + +#if IS_ENABLED(CONFIG_OF_OVERLAY) +/* Overlay entry notifier errors cannot stop removal after the tree change= d. */ +static bool of_mdiobus_live_node_is_busy(struct device_node *node) +{ + struct device_node *scope; + struct mii_bus *mdio; + bool busy =3D true; + + scope =3D of_mdiobus_get_removal_scope(node); + mdio =3D of_mdiobus_find_parent(scope); + if (!mdio) + goto out_put_scope; + + if (!mdiobus_device_change_begin(mdio, true)) { + busy =3D of_mdiobus_node_is_busy(mdio, scope); + mdiobus_device_change_end(mdio, true); + } + put_device(&mdio->dev); + +out_put_scope: + of_node_put(scope); + return busy; +} + +static struct device_node * +of_mdiobus_overlay_target_child(struct device_node *target, + struct device_node *overlay_child) +{ + const char *name =3D kbasename(overlay_child->full_name); + struct device_node *child; + + for_each_child_of_node(target, child) { + if (!of_node_cmp(kbasename(child->full_name), name)) + return child; + } + + return NULL; +} + +static bool of_mdiobus_overlay_node_is_busy(struct device_node *overlay, + struct device_node *target, + bool added) +{ + struct device_node *overlay_child, *target_child; + bool busy, child_added; + + if ((added || of_property_present(overlay, "status")) && + of_mdiobus_live_node_is_busy(target)) + return true; + + for_each_child_of_node(overlay, overlay_child) { + target_child =3D of_mdiobus_overlay_target_child(target, + overlay_child); + if (!target_child) + continue; + + child_added =3D of_node_check_flag(target_child, OF_OVERLAY); + busy =3D of_mdiobus_overlay_node_is_busy(overlay_child, + target_child, child_added); + of_node_put(target_child); + if (busy) { + of_node_put(overlay_child); + return true; + } + } + + return false; +} + +static int of_mdiobus_overlay_notify(struct notifier_block *nb, + unsigned long action, void *arg) +{ + struct of_overlay_notify_data *nd =3D arg; + bool busy; + + if (action !=3D OF_OVERLAY_PRE_REMOVE) + return NOTIFY_OK; + + of_mdio_reconfig_lock(); + busy =3D of_mdiobus_overlay_node_is_busy(nd->overlay, nd->target, + false); + of_mdio_reconfig_unlock(); + + return busy ? notifier_from_errno(-EBUSY) : NOTIFY_OK; +} + +static struct notifier_block of_mdio_overlay_notifier =3D { + .notifier_call =3D of_mdiobus_overlay_notify, +}; +#endif + +static int of_mdiobus_notify(struct notifier_block *nb, unsigned long acti= on, + void *arg) +{ + struct of_reconfig_data *rd =3D arg; + struct device_node *scope; + struct mii_bus *mdio; + enum of_reconfig_change change; + bool removing; + int rc, ret =3D NOTIFY_OK; + + of_mdio_reconfig_lock(); + change =3D of_reconfig_get_state_change(action, rd); + switch (change) { + case OF_RECONFIG_CHANGE_ADD: + /* A newer change may have made this notification stale. */ + if (!of_mdiobus_node_is_available(rd->dn)) + goto out_unlock; + removing =3D false; + break; + case OF_RECONFIG_CHANGE_REMOVE: + /* A newer change may have made this notification stale. */ + if (of_mdiobus_node_is_available(rd->dn)) + goto out_unlock; + removing =3D true; + break; + default: + goto out_unlock; + } + + mdio =3D of_mdiobus_find_parent(rd->dn); + if (!mdio) + goto out_unlock; + + rc =3D mdiobus_device_change_begin(mdio, removing); + if (rc) { + if (!removing) + ret =3D notifier_from_errno(-EPROBE_DEFER); + goto out_put_mdio; + } + + if (!removing) { + rc =3D of_mdiobus_add_node(mdio, rd->dn); + } else { + /* The node may already be detached from its parent hierarchy. */ + scope =3D of_mdiobus_get_removal_scope(rd->dn); + if (of_mdiobus_node_is_busy(mdio, scope)) + rc =3D -EBUSY; + else + rc =3D of_mdiobus_remove_node(mdio, rd->dn); + of_node_put(scope); + } + + mdiobus_device_change_end(mdio, removing); + if (rc && (removing || rc !=3D -ENODEV)) + ret =3D notifier_from_errno(rc); + +out_put_mdio: + put_device(&mdio->dev); +out_unlock: + of_mdio_reconfig_unlock(); + + return ret; +} + +static struct notifier_block of_mdio_notifier =3D { + .notifier_call =3D of_mdiobus_notify, +}; + +static int __init of_mdio_init(void) +{ + int ret; + + ret =3D of_reconfig_notifier_register(&of_mdio_notifier); + if (ret) + return ret; + +#if IS_ENABLED(CONFIG_OF_OVERLAY) + ret =3D of_overlay_notifier_register(&of_mdio_overlay_notifier); + if (ret) + of_reconfig_notifier_unregister(&of_mdio_notifier); +#endif + + return ret; +} +module_init(of_mdio_init); + +static void __exit of_mdio_exit(void) +{ +#if IS_ENABLED(CONFIG_OF_OVERLAY) + of_overlay_notifier_unregister(&of_mdio_overlay_notifier); +#endif + of_reconfig_notifier_unregister(&of_mdio_notifier); +} +module_exit(of_mdio_exit); +#endif /* CONFIG_OF_DYNAMIC */ + /** * of_mdio_find_device - Given a device tree node, find the mdio_device * @np: pointer to the mdio_device's device tree node --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f44.google.com (mail-ot1-f44.google.com [209.85.210.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 600C0394470 for ; Mon, 3 Aug 2026 05:15:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734134; cv=none; b=TafTeJPQG8tMw0Ppn/SmzG1yXdNj/+JXsVjkXY7+Xb9bAkqs6dSf0TTwfkAWs7fSQlDDnFCPiHVvjfX1EwE78JX/fAs9Efcagyu9G6M9jgIXcnGT1WS68x7CE+uufBKiGXqa/yhhnh4ieT3FxBrJK8maVYPu5PXRDtATCJNbfjw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734134; c=relaxed/simple; bh=vV8lMZbs024nEM6mXjaIv6nOjnfVCGoiA5FCDI8jrNk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LEACKHgvD8kiWYfF85VoSO+uUzP6iTsQl+fgIPYB5DBzj7abeE7k40Je6OwMgZ+605EX0KOkOSZnoYxHq9NiipyxYDb2sJHLCq4ACm5a442PpY7evgwRLrAZwAmj31ys9I8i0jF+WrF178qr9+wsHERWjQVyh6JQQNSKUTaX0FQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Sfbjh3oy; arc=none smtp.client-ip=209.85.210.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Sfbjh3oy" Received: by mail-ot1-f44.google.com with SMTP id 46e09a7af769-7eb4d532e65so1138644a34.0 for ; Sun, 02 Aug 2026 22:15:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734130; x=1786338930; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ufELgsZA/AuhdmDVFD2N+JzOSgNytpSBYv7TBEiLCKU=; b=Sfbjh3oyaoEsE9+InTii9WpDet+Fq1zhOpdjiV70hWzaIYHb/8RirXYyvwcto4uLD5 nzNNry4SjVMVav5+BrZOqamYstY7octMOrhSQFXpech5OcdwXoKdMEXnsIZ+nwjVO5Aw Api7tDacZoVqER+CfYlgqOyHJxK/roVP/ObD8AgqL1ZA61qgl5F3mGjmRVqqlJlND2A5 AEuLbycVdpGiMv+pVX3+VcC7V14foxm8Bt2j6fsZLxNdMLoFpgkjIt4Z6vK8doXkUcQQ wyccMhfb/psg3ZJvDUEI533yMkY+VcxGawp9xWshVUtZ165EHcDzmecCrHnhBmNnOLws hDmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734130; x=1786338930; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ufELgsZA/AuhdmDVFD2N+JzOSgNytpSBYv7TBEiLCKU=; b=P5A5KKqTpj7QH47wX8gzhLRWhVepGSI7zu4C1H2yES+iInI8jf3MECNW5EUtKCzDNL qsrXNgaLLY04QOcmSnFws2kWBQlioF18gOjFvOLA5MMbN8ev9k6QXhjsmm2lo6ekFrHf P1bWZmOodBO7WwcIEPBRSH15CIdRAwnGAA3BqpFVKMDV97SxkBkQXs4FJxIRHmSCJwEY n8mF3C4sj4kUt5uH1UM9aORAYqUtDa+a67f0GQ9onk4GTuI8QsIkImk2c4DfbV2QK+ie a34RXMjwG3srkq2lJZON69n014kVTQ/lqxj94Udwn1jSno46Gpw/8s6+PCHLOAL4i4SL JBkg== X-Forwarded-Encrypted: i=1; AHgh+Rr+p61pthVuVpwvkP0tXS4UUJ3fpdN7vARBfV7N0ryn5K92pDRC9NVCadB4YxqFqES4t0g1Y8A6S4BMSZs=@vger.kernel.org X-Gm-Message-State: AOJu0YzVjC8dMHY9CGPDkjkF5qIEc5oFfUKocUrayahvvVNZArtgxALt 9sDH4TV8Oo7+t7fmBIc8/UJS1k0KpsuZ/8G9UUp6z3MaI2lzigxAaTqP X-Gm-Gg: AR+sD110poUM3AR8K311/Xg3VRvjO9+aHyPHmp9sLWNlChoEZWXsg4GDMqrvsX37TcN 6ZGD0ULXhMMLkmXfqozoStD8EyFs/zRmJuzxDkK6ipCmqqjWybF2ivWWvROORkNwJtX1GVHxe29 Uw9OtcSkuGc4SMyrEZRdET8p2oWpTpnt0Do0AilXpHHlAGYX3Rsj/dyJ1CGrU33W4x+Vpqq8pfF Jd/oJ9idIcBPe+bGS9dQa5ksV0jexKef/AI6Ue8/xwjMxAq2e5kcVpGB1Gr/9fp5v+EH4/sw/6I CWqjbS/q7BdNJhQ1/JqM+2n+Ye8eWTL3MX74PgjdBT4IFkosEYRobwKYGTbXHp9FLhPj7O7reeW 6rpX+3slXnBLixBGtjbWbNduJuQ+wzWGIct8Ahj/8QgkWQvVaY8e0MS8bdYfqn+KnD0tmeocKAd 23AAQ4YuRKYV25xuc6YyeP0j1VlcqTAatwKiWKLc/YXoXPsc/QBHS90skiBMzRgUFUIpANBaohU jyyPEIK25I7j98WvvNfNHgGu/yDrVONFb8c0K1B6LBcke5wawjeLAg53r6BOIqc1Tz4yfCU4XIn 4WDQcFnYHOAHQWsqhtEqcjn07QzUttYq0Kffk4cF5dq0RObwgVq/fLXEupw8e2IaBln2mhJkVBK u+OHDAC2QuGUBn1AWMPJ3B5Nib2yN X-Received: by 2002:a05:6830:81f0:b0:7e9:cad9:4bd0 with SMTP id 46e09a7af769-7f196b1550cmr14686937a34.3.1785734130353; Sun, 02 Aug 2026 22:15:30 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:29 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:17 -0600 Subject: [PATCH 07/21] dt-bindings: net: x-powers: add AC200 EPHY control Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-7-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC200 companion IC contains a Fast Ethernet PHY controlled through the parent AC200 I2C regmap. Describe its control function, including the interface mode and optional SoC SID calibration cell. The vendor sequence adds three to the calibration value modulo 16 before writing the BPS_EFFUSE field. If the SID cell is omitted, the driver can use the AC200's internal copy of the calibration eFuse. The link-PHY driver supplies its Clause 22 address when enabling the control function. Signed-off-by: James Hilliard --- .../bindings/net/x-powers,ac200-ephy-ctl.yaml | 46 ++++++++++++++++++= ++++ 1 file changed, 46 insertions(+) diff --git a/Documentation/devicetree/bindings/net/x-powers,ac200-ephy-ctl.= yaml b/Documentation/devicetree/bindings/net/x-powers,ac200-ephy-ctl.yaml new file mode 100644 index 000000000000..b3337c3aa62a --- /dev/null +++ b/Documentation/devicetree/bindings/net/x-powers,ac200-ephy-ctl.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/x-powers,ac200-ephy-ctl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: X-Powers AC200 Ethernet PHY control + +maintainers: + - James Hilliard + +description: + The AC200 Ethernet PHY control function configures and powers the Fast + Ethernet PHY in the AC200. Its registers are accessed through the parent + AC200 I2C regmap. + +properties: + compatible: + const: x-powers,ac200-ephy-ctl + + nvmem-cells: + maxItems: 1 + description: + Optional SoC SID cell containing the Ethernet PHY calibration value + written to the AC200 BPS_EFFUSE field after adding 3 modulo 16, as + prescribed by the vendor initialization sequence. If omitted, the + driver reads the AC200's internal copy of the calibration eFuse. + + nvmem-cell-names: + const: calibration + + phy-mode: + enum: + - mii + - rmii + +required: + - compatible + - phy-mode + +dependentRequired: + nvmem-cells: [ nvmem-cell-names ] + nvmem-cell-names: [ nvmem-cells ] + +additionalProperties: false +... --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f49.google.com (mail-ot1-f49.google.com [209.85.210.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5950A3955FC for ; Mon, 3 Aug 2026 05:15:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734137; cv=none; b=XeABNKiM7UIR+cAtlOjnli6JtSKJUklGbR09dUdfOGcBFO/4Ek4dT8dRQqa1cSewywm/eHGQH5Bd4ahLDNSa7SAFzGuWBksW/IKB3EErrEQtRRZwbnC5oexdPkDxhoqTKvLlfflPb0mt2GojQVKj2PkaVxxJ4C1d6t1/MBHJcNs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734137; c=relaxed/simple; bh=6OQnGRpMnyrb+bp+bGTn43xoUYsbGDK19SjrvuCzOUU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=B3eLlJzFzg+Ch3zlU8k9Lfa5bejtnPp33aIjbQYQVuVy6utdCjFL9oYQraVGe1ECy/+FR9013tiwTFt1ugnj4w7oU0DeTMHC7512aq6FaRoNcWPKckswQ5efo+G7MEF3pP3qSmxio+SsPUIW5nk7tQowQ/Ci2FZ+0ge5zsIeKDk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=SDjhpxR3; arc=none smtp.client-ip=209.85.210.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="SDjhpxR3" Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-7e9ecb1e13cso3366343a34.3 for ; Sun, 02 Aug 2026 22:15:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734132; x=1786338932; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ws0LFhZuUjZTnhwPoD3ztO16rIL3gtosandi83LBFNY=; b=SDjhpxR3kx142aDUpjMnFbokm/w3UeqG99CJjTHkfyVyaD0P9IMlzXUR20PNiKb+1q WzwPNy+Y/RmtfHmrsIm2CWxZuZpKnWiMCopETwwpMqK+PgRLP2dAkqsMX2zwIAlliKFs ju7Z7TURQ/bieQbD+/1zJYrPpSw02FNwbA776y/Vnp2iudCWalzax5hsFabhYCDMaQF1 x13IKsriMuImKnQ9PtFjGToirlS/DOar1lp2Zi0Ly358e7FYnnaNZ0YOc7iJPd6aph6c s1daHjD9jRW4as5VScCySSUfhIjm9u5HDmd9NGj0sG6AhPay1myibcrTP0/aPtcoF4O0 GmEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734132; x=1786338932; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ws0LFhZuUjZTnhwPoD3ztO16rIL3gtosandi83LBFNY=; b=LxXqlCQ//dB/QVStQZeMLfcXkGplzYEP7H/5oS3GX+1kMNin9Vor9a0xewN5aEQUJZ 2PYmCmqfdtjUuRTE93QfLTvlBT9LKCeRdhanTuomTElB5SCTjSAO5vzwV6Qiglq8KXNR luS+/5rUKgh3Ev/TxJS1YOe/WSxg/pW1yTMPvhENynO3clzspict/OMaYAzpEUfwh35R bVm5rmicOe/eTcrnLK0/YFh1vuUzi8ZzaVWAjEweqVd6CDmvrIhVZTG1ahwz4RyGX6C6 5tjBB35h+stixNV0F8NC1uhsQ/1tNkke9cCM4jAwsoV4mYS0gyqVYMBgMoM8pJLDVtk7 NOkw== X-Forwarded-Encrypted: i=1; AHgh+RqyI//LxsGVbB9qTOFRLktAqAeM+Ih+of2GSrqqOp6BI8kcI+++3RGAMMTtNbBQRXfCux+TTdBBRQfZdyc=@vger.kernel.org X-Gm-Message-State: AOJu0YwYdQcQ5YpxRov4MwEDvk8PFFxLMJoK3mlCF/odXDVlmkmpVPYi PvslnpLzx3UcyEOMPE7ZIHFEfrRtjg9/bd368GyP4Kzoi8DGWvBzsJmo X-Gm-Gg: AR+sD11TQ47+/gIg+RwrtxrnKX9PmZBIc3sj3nAREvMhUvyxB3thJT3w4etSl83Lhj5 hCRxYf9IfoZeyDOMNAiUfX9osAagEGt23aR78K8/0E+sw3BJMhbMLTIHEln634zKbDPQN/Dbw0H VO5B/jvxF0V7kMq0O8ChxZlMeRRSJ+neb8+BULfOX7S28l7iVF7hEvH5SPhw0pDUm5srKA1DwnQ y+nEaSxwd0P9qdfBe6Lqinh6rT53PywnEs+7kXX0PTbpmWxyHkugFa2Qlay7arVyUqd7wXaOfl6 5obcOm6CKvvOqYwlkdw37fogBwAxjCqZ2/v5sakVSabCDYQcX0Mcl7YPvFkItC6I9Bkvlwd48xp WGwoMGuemXFsPEMMIlNRc7A4S6Do8vJXqijcMBTpBf/f3jrbeLRp46sRGeOL7MpaZ777ifv07y2 9WehAQQzD9ZfoSOooq4/YmNlyyV0qbIIr91Re19VE/3a5RxqIlGtVs/8nhZv+vIWVFRMvaBwNwx QceNDRdsKnBu3O0ZhwIvkQFS4bXWYW6hasQYfJipuWtKz9nVZSrJ5RL5PrM4u0iioF6sVu0u09f WmZYPTdqEWXd09FqWeDU4/BZ7EtVphUmX761pCiP7Unsw1gzfJAKsy5uedhJ6bDkwuXT4L1cWiO 39n24Zl4UpbTIYpN3 X-Received: by 2002:a05:6830:6737:b0:7dc:df37:844b with SMTP id 46e09a7af769-7f196baee6fmr14985696a34.4.1785734132204; Sun, 02 Aug 2026 22:15:32 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:31 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:18 -0600 Subject: [PATCH 08/21] dt-bindings: mfd: x-powers: add AC200 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-8-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC200 is an I2C-controlled mixed-signal companion IC containing audio, video, RTC and Fast Ethernet PHY functions. Describe the parent device, its input clock, required function supplies, the optional SID bandgap calibration cell used by the vendor initialization sequence, and its optional Ethernet PHY control child. Document the 24 and 27 MHz rates encoded by the public EPHY clock selector. Also describe the optional open-drain, level-triggered INTB output and the nested interrupt controller which exposes the TV encoder, Ethernet PHY and RTC sources. Define the interrupt source numbers for child consumers. Signed-off-by: James Hilliard --- .../devicetree/bindings/mfd/x-powers,ac200.yaml | 118 +++++++++++++++++= ++++ include/dt-bindings/mfd/x-powers,ac200.h | 13 +++ 2 files changed, 131 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/x-powers,ac200.yaml b/Do= cumentation/devicetree/bindings/mfd/x-powers,ac200.yaml new file mode 100644 index 000000000000..017629cca73c --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/x-powers,ac200.yaml @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/x-powers,ac200.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: X-Powers AC200 mixed-signal IC + +maintainers: + - James Hilliard + +description: + The AC200 is a mixed-signal companion IC containing audio, video, RTC and + Fast Ethernet PHY functions. Its control registers are accessed over I2C. + +properties: + compatible: + const: x-powers,ac200 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: + AC200 input clock. When using the Ethernet PHY, its configured rate = must + be 24 or 27 MHz, matching the rates encoded by the documented EPHY c= lock + selector. + + interrupts: + maxItems: 1 + description: + The INTB pin, which is a shared open-drain, level-triggered output f= or + the TV encoder, Ethernet PHY and RTC interrupt sources. + + interrupt-controller: true + + '#interrupt-cells': + const: 1 + description: + The interrupt number, as defined in + include/dt-bindings/mfd/x-powers,ac200.h. + + ac-ldoin-supply: + description: 3.3 V supply for the audio-codec LDO input + + ephy-vcc-supply: + description: 3.3 V supply for the Ethernet PHY analog front end + + rtc-vcc-supply: + description: 3.3 V supply for the RTC + + tv-vcc-supply: + description: 3.3 V supply for the TV encoder DAC + + nvmem-cells: + maxItems: 1 + description: + Optional SoC SID cell containing the AC200 bandgap calibration value. + The trim is used by the TV encoder; the public AC200 datasheet does = not + document the corresponding register fields. + + nvmem-cell-names: + const: bandgap + + ethernet-phy-control: + $ref: /schemas/net/x-powers,ac200-ephy-ctl.yaml# + +required: + - compatible + - reg + - clocks + - ac-ldoin-supply + - ephy-vcc-supply + - rtc-vcc-supply + - tv-vcc-supply + +dependencies: + interrupts: [ interrupt-controller ] + interrupt-controller: [ '#interrupt-cells', interrupts ] + '#interrupt-cells': [ interrupt-controller ] + nvmem-cells: [ nvmem-cell-names ] + nvmem-cell-names: [ nvmem-cells ] + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + mixed-signal@10 { + compatible =3D "x-powers,ac200"; + reg =3D <0x10>; + clocks =3D <&pwm 5>; + ac-ldoin-supply =3D <®_3v3>; + ephy-vcc-supply =3D <®_3v3>; + rtc-vcc-supply =3D <®_3v3>; + tv-vcc-supply =3D <®_3v3>; + interrupt-parent =3D <&pio>; + interrupts =3D <1 20 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells =3D <1>; + nvmem-cells =3D <&ac200_bandgap>; + nvmem-cell-names =3D "bandgap"; + + ethernet-phy-control { + compatible =3D "x-powers,ac200-ephy-ctl"; + nvmem-cells =3D <&ephy_calibration>; + nvmem-cell-names =3D "calibration"; + phy-mode =3D "rmii"; + }; + }; + }; +... diff --git a/include/dt-bindings/mfd/x-powers,ac200.h b/include/dt-bindings= /mfd/x-powers,ac200.h new file mode 100644 index 000000000000..cc59e2ab4912 --- /dev/null +++ b/include/dt-bindings/mfd/x-powers,ac200.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Interrupt numbers of the X-Powers AC200 interrupt controller. + */ + +#ifndef _DT_BINDINGS_MFD_X_POWERS_AC200_H +#define _DT_BINDINGS_MFD_X_POWERS_AC200_H + +#define AC200_IRQ_TVE 0 +#define AC200_IRQ_EPHY 1 +#define AC200_IRQ_RTC 2 + +#endif /* _DT_BINDINGS_MFD_X_POWERS_AC200_H */ --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f48.google.com (mail-ot1-f48.google.com [209.85.210.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 64BC138A70A for ; Mon, 3 Aug 2026 05:15:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734138; cv=none; b=TN9GQzzcc1z8fDhk5XFPDuBGwUNQlmF/auwqeNKH/zZp42UC+cOJzSZgwSUjBpI4Zp8RlYGdKjfeVGF9aczrkvWxvYaun5RVG7tUk8ZvUtBvEptFAtVdBsO5Vrl675gnIhAoO9MlO3DPiYujGW/aGNNijBRETcCMdJp79TbK/gk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734138; c=relaxed/simple; bh=MqlazHFPg7A93Yw8yIBqrOlNXVcT4LqcT4gU0kTc88M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eG3yaA3KZE4THyDwVm+tgjsZzOpvTZjBOM0toK8OfW5sBYX/uGb3KSY7ZNz6AZaST1nuRRj1Vdo05RzsCNFTnRM9QR2NMdMfDJhxJ6RUtt9cPLgDkAU4qy1QnZTyOSMxJESzr9vFrMHWDG0XOkfF5Uyj0Kiwd75/pd6q5K70d18= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=SF4vPD/K; arc=none smtp.client-ip=209.85.210.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="SF4vPD/K" Received: by mail-ot1-f48.google.com with SMTP id 46e09a7af769-7ee4399c423so1835934a34.0 for ; Sun, 02 Aug 2026 22:15:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734134; x=1786338934; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=o3n69SozBgBa42qBZUQe+SN94PjOayvFQRwUM8nAj08=; b=SF4vPD/KJIK7MR120CzUcEXEs29/tzR4NEeYt5GgNmunekCqFLCfLiWi9qmEYWsuAT HH+LOlS/KUzh//auFLKsRyZM+M2HZCMWnMjMZtQPnw1iD4sEMOBHTJ7Jrv+QF50bZGj+ rbphowpnF0MjpOTDq24TLa+HXHcbEv/zYei3AlCjfFIHQjKd/HygrS5H/eTGA0hjH/Ae Yx9scooG4PS7AKthGuJeTajU8TkfqCbil/zNWbgLwVsiZjyTLfx/gygqnke4ZR5u1kCF CXUZK5VNAcl1+0m57BXgUM3pzGMO25Hhk0QHiM6hAJ6gTuckVRKbIcSRoa6l79IC3nuW EVbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734134; x=1786338934; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=o3n69SozBgBa42qBZUQe+SN94PjOayvFQRwUM8nAj08=; b=IFgKGAMrsON3Rc1/ybnKMmd9E6ALaAmCDy7k5YOAeldmSXU6OoOgMh/TCBd3xXJp3A bRWTip+7Jd351CuSTyxWD1gO2ByvlsC1IbyO/F7ZM63pAsXD7neJpUSxWo6nbVVAzJMf NxGsSxxHTa+ce+Xm6/uupG1JE4xnoM4w7qwWbS8PCutXqiFWqHARd8y3pXmbduOZI4iw VTQEnLJ9OO6BiMD7rkbFD8vV8BAGp96oHc/2TGqqcR1srQJnV75dXHXisl1TQZZOet24 DbhzjBPfwlWFEGjKj7Fx/JufNXXmomChUqlkvpRtGhHw+EM6Iabg7ZIJkMmZQbmQg3HK QsvQ== X-Forwarded-Encrypted: i=1; AHgh+Rr5asCb7RgMkaKRh8Uo3pBC269VVvtyENL/iBGkOW1P+0JZRWSeavvWOsgDeTwIDs9NxtZa24J3sYO2f1o=@vger.kernel.org X-Gm-Message-State: AOJu0YxFlf+Qe0f0aQ1EAgpfQXK7XkteLFBY85kOnSU0H5bnZqoOAW9s UPJvUfg275qnt3wumhahhFV3pni77ZAO6LnepiVYmovR6Qmw57zvm3QI X-Gm-Gg: AR+sD10HsTx8vDcyS001stniHJ4hApkrMc49BQZ8Y2TsYiLPnbEoRIm6f1MGGO0g9Dp jZaKKJRY5Cfdcx83lal8/AKpbXRSr/YwqEVvaQU4PNa15j0UyBrY8MRu/E1gE5TzE8Fls/W2x5N LgC+RCkV0T+XJAuS6+Y3+zNxt7CTjfZKeUXc+FkRNHE7IMI12BAHeHDOPfMLH0upbbseYznId+x LDDwlbauuH5V0fP2gQQQz874jYoGRh933ZNsjcJ2F/RRdtSb19NAZyIcng6na/fGyQRhBs9mM6b cRMajI9xtIXtvH2yKGcf7Wq+pdIQ6+l7WmHWcpWXoz8K+7boU7AUlg41FKo4C78vXoj3jkPm1mu 8jyqdBAgT14lgui/bv+QvIkBAws/VP0Il9P+JWD9eueJWtWkitbRiWJiG20Bj4EUJIrY/ypuEfv ylTDrnA+3kM/CQEONuSq9J4F9stfiZR9av/8MC+B7db2n28426xwW3XaM4CCAfBihge7imkiO3G crLeppA5+3lVe/AXRl/Z/JzsrV0aYDcWiDIh8r+R8tK+FoC87ak6lDSFdc2k/e5G71fiZIVzK// nEvu1qP7dTHq9vKqMGDQXmNoo+q/EVkpE0zMtjySIg1gpW0SjP5iAAqeHV4yfA+t/S7UFE7Azad Y+Ye23rDrXrW5ubw+ X-Received: by 2002:a05:6830:7003:b0:7e9:e288:2b60 with SMTP id 46e09a7af769-7f196b465fcmr14384631a34.1.1785734134150; Sun, 02 Aug 2026 22:15:34 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:33 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:19 -0600 Subject: [PATCH 09/21] mfd: add X-Powers AC200 support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-9-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The X-Powers AC200 is a mixed-signal companion IC with a paged register map accessed over I2C. Enable its required supplies and board-configured input clock, lock the clock rate, and wait for the settling interval used by the vendor initialization sequence before accessing the device. Initialize the common control interface, report the chip and package revision, and populate the Ethernet PHY control child when firmware describes it. Cache only the common page selector because individual function resets can invalidate functional registers without regmap's knowledge. Optionally apply the SoC SID bandgap calibration using the opaque fixed bits from the vendor sequence. The public manual marks that register as reserved. Boards which do not use the affected TV encoder path may omit the calibration cell. When firmware describes INTB, register a regmap IRQ domain for the TV encoder, Ethernet PHY and RTC sources. Program the shared output enable and requested level polarity while preserving the independently managed source enables. Systems without a routed interrupt remain unchanged. The AC200 and its children cannot initiate DMA. Mark the parent as DMA-incapable before adding the MFD cells so OF DMA setup does not synthesize a mask for the child. Register a managed action that disables the AC200 control block before adding the MFD children. Managed resources unwind in reverse order, so the children are removed before their parent control block is disabled on driver removal or a later probe failure. Disable the block during system shutdown as well. Signed-off-by: James Hilliard --- drivers/mfd/Kconfig | 13 +++ drivers/mfd/Makefile | 1 + drivers/mfd/ac200.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 316 insertions(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 763ce6a34782..a71870bcf868 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -205,6 +205,19 @@ config MFD_AC100 This driver include only the core APIs. You have to select individual components like codecs or RTC under the corresponding menus. =20 +config MFD_AC200 + tristate "X-Powers AC200" + depends on I2C + depends on OF + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + Support for the X-Powers AC200 mixed-signal companion IC. The AC200 + contains audio, video, RTC and Fast Ethernet PHY functions and is + co-packaged with some Allwinner H6 and H616 SoCs. This driver provides + the shared register access used by the individual function drivers. + config MFD_AXP20X tristate select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index dd4bb7e77c33..890e76a9ad00 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -150,6 +150,7 @@ obj-$(CONFIG_MFD_DA9052_SPI) +=3D da9052-spi.o obj-$(CONFIG_MFD_DA9052_I2C) +=3D da9052-i2c.o =20 obj-$(CONFIG_MFD_AC100) +=3D ac100.o +obj-$(CONFIG_MFD_AC200) +=3D ac200.o obj-$(CONFIG_MFD_AXP20X) +=3D axp20x.o obj-$(CONFIG_MFD_AXP20X_I2C) +=3D axp20x-i2c.o obj-$(CONFIG_MFD_AXP20X_RSB) +=3D axp20x-rsb.o diff --git a/drivers/mfd/ac200.c b/drivers/mfd/ac200.c new file mode 100644 index 000000000000..bd9930a02cb2 --- /dev/null +++ b/drivers/mfd/ac200.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MFD core driver for the X-Powers AC200 + * + * Copyright (C) 2026 James Hilliard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AC200_SYS_VERSION_REG 0x0000 +#define AC200_SYS_VERSION_PACKAGE_MASK GENMASK(15, 14) +#define AC200_SYS_VERSION_CHIP_MASK GENMASK(11, 0) + +#define AC200_SYS_CONTROL_REG 0x0002 +#define AC200_SYS_CONTROL_CHIP_RESET_DEASSERT BIT(0) + +#define AC200_SYS_IRQ_ENABLE_REG 0x0004 +#define AC200_SYS_IRQ_INTB_ENABLE BIT(15) +#define AC200_SYS_IRQ_INTB_ACTIVE_HIGH BIT(14) +#define AC200_SYS_IRQ_RTC_ENABLE BIT(12) +#define AC200_SYS_IRQ_EPHY_ENABLE BIT(8) +#define AC200_SYS_IRQ_TVE_ENABLE BIT(4) + +#define AC200_SYS_IRQ_STATUS_REG 0x0006 + +#define AC200_SYS_BG_CTL_REG 0x0050 +/* + * The vendor initialization sequence composes this as SID data | BIT(15) | + * (0xa << 6). The public datasheet marks the whole register reserved and + * does not name the fixed fields. + */ +#define AC200_SYS_BG_CTL_FIXED_BITS (BIT(15) | (0xa << 6)) + +/* Interface register accessible from every register page. */ +#define AC200_TWI_REG_ADDR_H 0x00fe +#define AC200_MAX_REG 0xa1f2 + +struct ac200 { + struct regmap *regmap; +}; + +static const char * const ac200_supplies[] =3D { + "ac-ldoin", + "ephy-vcc", + "rtc-vcc", + "tv-vcc", +}; + +static const struct regmap_range_cfg ac200_range_cfg[] =3D { + { + .range_max =3D AC200_MAX_REG, + .selector_reg =3D AC200_TWI_REG_ADDR_H, + .selector_mask =3D 0xff, + .window_len =3D 256, + }, +}; + +/* + * Each AC200 sub-block can reset independently, invalidating its register + * contents without regmap's knowledge. Cache only the common page selecto= r; + * this avoids a selector read-modify-write for every access on the same p= age + * without ever returning stale functional-register values. + */ +static bool ac200_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg !=3D AC200_TWI_REG_ADDR_H; +} + +static const struct regmap_config ac200_regmap_config =3D { + .name =3D "ac200", + .reg_bits =3D 8, + .reg_stride =3D 2, + .val_bits =3D 16, + .ranges =3D ac200_range_cfg, + .num_ranges =3D ARRAY_SIZE(ac200_range_cfg), + .max_register =3D AC200_MAX_REG, + .volatile_reg =3D ac200_volatile_reg, + .cache_type =3D REGCACHE_MAPLE, +}; + +static const struct regmap_irq ac200_irqs[] =3D { + REGMAP_IRQ_REG(AC200_IRQ_TVE, 0, AC200_SYS_IRQ_TVE_ENABLE), + REGMAP_IRQ_REG(AC200_IRQ_EPHY, 0, AC200_SYS_IRQ_EPHY_ENABLE), + REGMAP_IRQ_REG(AC200_IRQ_RTC, 0, AC200_SYS_IRQ_RTC_ENABLE), +}; + +/* + * SYS_IRQ_ENABLE is an enable register rather than a mask register, hence + * unmask_base. The INTB output enable and polarity bits share the registe= r, + * but regmap-irq only updates the bits described by ac200_irqs. + * + * SYS_IRQ_STATUS follows the state of each source block and is read-only. + * Interrupts must therefore be acknowledged in the source block itself. + */ +static const struct regmap_irq_chip ac200_irq_chip =3D { + .name =3D "ac200", + .status_base =3D AC200_SYS_IRQ_STATUS_REG, + .unmask_base =3D AC200_SYS_IRQ_ENABLE_REG, + .num_regs =3D 1, + .irqs =3D ac200_irqs, + .num_irqs =3D ARRAY_SIZE(ac200_irqs), +}; + +static const struct mfd_cell ac200_cells[] =3D { + { + .name =3D "ac200-ephy-ctl", + .of_compatible =3D "x-powers,ac200-ephy-ctl", + }, +}; + +static int ac200_disable(struct ac200 *ac200) +{ + return regmap_write(ac200->regmap, AC200_SYS_CONTROL_REG, 0); +} + +static void ac200_disable_action(void *data) +{ + ac200_disable(data); +} + +static int ac200_init_irq(struct ac200 *ac200, int irq) +{ + struct device *dev =3D regmap_get_device(ac200->regmap); + struct regmap_irq_chip_data *irq_data; + u16 value =3D AC200_SYS_IRQ_INTB_ENABLE; + u32 trigger; + int ret; + + trigger =3D irq_get_trigger_type(irq); + switch (trigger) { + case IRQ_TYPE_LEVEL_HIGH: + value |=3D AC200_SYS_IRQ_INTB_ACTIVE_HIGH; + break; + case IRQ_TYPE_NONE: + case IRQ_TYPE_LEVEL_LOW: + break; + default: + return dev_err_probe(dev, -EINVAL, + "INTB requires a level interrupt, not type %u\n", + trigger); + } + + ret =3D regmap_update_bits(ac200->regmap, AC200_SYS_IRQ_ENABLE_REG, + AC200_SYS_IRQ_INTB_ENABLE | + AC200_SYS_IRQ_INTB_ACTIVE_HIGH, value); + if (ret) + return ret; + + ret =3D devm_regmap_add_irq_chip(dev, ac200->regmap, irq, IRQF_ONESHOT, + 0, &ac200_irq_chip, &irq_data); + if (ret) + return dev_err_probe(dev, ret, + "failed to add interrupt controller\n"); + + return 0; +} + +static int ac200_probe(struct i2c_client *client) +{ + struct device *dev =3D &client->dev; + struct device_node *ephy_node __free(device_node) =3D NULL; + struct ac200 *ac200; + struct clk *clk; + unsigned int version; + u16 bandgap_calibration =3D 0; + int ret; + + ac200 =3D devm_kzalloc(dev, sizeof(*ac200), GFP_KERNEL); + if (!ac200) + return -ENOMEM; + + ret =3D devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ac200_supplies), + ac200_supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to enable supplies\n"); + + clk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to enable input clock\n"); + + ret =3D devm_clk_rate_exclusive_get(dev, clk); + if (ret) + return dev_err_probe(dev, ret, "failed to lock clock rate\n"); + + ac200->regmap =3D devm_regmap_init_i2c(client, &ac200_regmap_config); + if (IS_ERR(ac200->regmap)) + return dev_err_probe(dev, PTR_ERR(ac200->regmap), + "failed to initialize regmap\n"); + + i2c_set_clientdata(client, ac200); + + if (device_property_present(dev, "nvmem-cells")) { + ret =3D nvmem_cell_read_u16(dev, "bandgap", + &bandgap_calibration); + if (ret) + return dev_err_probe(dev, ret, + "failed to read bandgap data\n"); + } + + /* + * No minimum delay is documented. Match the vendor driver's 40 ms delay + * before its first AC200 register access after enabling the input clock. + */ + msleep(40); + + ret =3D regmap_read(ac200->regmap, AC200_SYS_VERSION_REG, &version); + if (ret) + return dev_err_probe(dev, ret, + "failed to read chip version\n"); + + dev_info(dev, "AC200 revision %#lx in package %lu\n", + FIELD_GET(AC200_SYS_VERSION_CHIP_MASK, version), + FIELD_GET(AC200_SYS_VERSION_PACKAGE_MASK, version)); + + /* Run after the MFD children have been removed. */ + ret =3D devm_add_action_or_reset(dev, ac200_disable_action, ac200); + if (ret) + return ret; + + ret =3D regmap_write(ac200->regmap, AC200_SYS_CONTROL_REG, 0); + if (ret) + return ret; + + ret =3D regmap_write(ac200->regmap, AC200_SYS_CONTROL_REG, + AC200_SYS_CONTROL_CHIP_RESET_DEASSERT); + if (ret) + return ret; + + if (bandgap_calibration) { + ret =3D regmap_write(ac200->regmap, AC200_SYS_BG_CTL_REG, + AC200_SYS_BG_CTL_FIXED_BITS | + bandgap_calibration); + if (ret) + return ret; + } + + if (client->irq > 0) { + ret =3D ac200_init_irq(ac200, client->irq); + if (ret) + return ret; + } + + /* Neither the AC200 nor its child devices can perform DMA. */ + dev->coherent_dma_mask =3D 0; + dev->dma_mask =3D &dev->coherent_dma_mask; + ephy_node =3D of_get_compatible_child(dev->of_node, + "x-powers,ac200-ephy-ctl"); + if (!ephy_node) + return 0; + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, ac200_cells, + ARRAY_SIZE(ac200_cells), NULL, 0, NULL); +} + +static void ac200_shutdown(struct i2c_client *client) +{ + struct ac200 *ac200 =3D i2c_get_clientdata(client); + + ac200_disable(ac200); +} + +static const struct of_device_id ac200_of_match[] =3D { + { .compatible =3D "x-powers,ac200" }, + { } +}; +MODULE_DEVICE_TABLE(of, ac200_of_match); + +static const struct i2c_device_id ac200_i2c_ids[] =3D { + { "ac200" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ac200_i2c_ids); + +static struct i2c_driver ac200_driver =3D { + .driver =3D { + .name =3D "ac200", + .of_match_table =3D ac200_of_match, + }, + .probe =3D ac200_probe, + .shutdown =3D ac200_shutdown, + .id_table =3D ac200_i2c_ids, +}; +module_i2c_driver(ac200_driver); + +MODULE_AUTHOR("James Hilliard "); +MODULE_DESCRIPTION("X-Powers AC200 MFD core driver"); +MODULE_LICENSE("GPL"); --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f48.google.com (mail-ot1-f48.google.com [209.85.210.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 47777399D00 for ; Mon, 3 Aug 2026 05:15:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734142; cv=none; b=egIRRRa9NF6Teg9Fn+LeX3xRucAfTEGlAUzsJB0GYRjExi5eX1wdJ0Qxs4vc+cEoReeDV7Idaz/BgV/nwapT9aFwoUADrkvUuLg4nOE4d5hM0luLaYnijuPNehbsX0CVAy95NLN1nQ8WC+gGPa0FO19/DgGHmicTPhup2fUcMjA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734142; c=relaxed/simple; bh=FJxa6pnlwH8NOKl4g0tgsIa3AWI3yPSDz31JZnSznJk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fN5TeGzPS3/kzGqSTWQbtbeYCSSoDiacSf6boaC+KrNCXuTJ4/k1WIQ+NRmLrLHOwfCarhdQo8lILA8UukdBkDrYGFQDt5LTpyYIvpXhVIz05zMMLRvcBwyaNTMtvhLTVIAxr0oEPkykRq9hAB0k3KPalNIdW82a7WzIC633QsQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ooBynu1M; arc=none smtp.client-ip=209.85.210.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ooBynu1M" Received: by mail-ot1-f48.google.com with SMTP id 46e09a7af769-7e9eaf04bfaso1038898a34.1 for ; Sun, 02 Aug 2026 22:15:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734138; x=1786338938; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=DdvS6JgS1wsN4XXB/DPlHPE/KXR5tqJa5L67sBE8VSE=; b=ooBynu1MCvJ8bq7I1w5MHtcPAcvspvDQ5MjqJs8bLv/oR1ibMnU5HSnj0mOdyvxIf+ UguX5vpSLkPyQNlmmPLF6k/hNiWEmqdy1NSdcYGFVBzQ+c0jQOm/zf/s/P15JPJSxKv1 2NyJYhgz2HeE/f1nBzOH5CJHvFX/wss7sL/dM4fd9adjHJSV0ZiH4eNh31q53QUJxjZX CVz8ScGQAAG4FkfoS1bobHnqQGOZXzp3PdCM5hlmFVLqBX6nny6afIo6aj73k+Wz+YZu ymdRliFrhiJVrd1mP7F/FakeRWJRvO8K3kOZ/pNYbD02Sphei/RZPil50ilVcFLm+V/2 xpow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734138; x=1786338938; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=DdvS6JgS1wsN4XXB/DPlHPE/KXR5tqJa5L67sBE8VSE=; b=nX87POC8gImD2hiwOPNJ677z2OSK/QNuDCJ0qR054hci4omkdbK/3tVZNew0TJZBLb 3661n7SdrSbxhrTmXGaFeowwWUEL/mAOM7dM9iUOL43LIawvlbQBe+ZWQXDE3U7PpnuM Kd/8xsa4P6AYWSLzLrWKHyP22ooMCJ3i2ipII/vm1Tos/ZrDvEmyi3QLQbVg4DbOcN3R f+JERGxMEvPMVinsjBI8zsORXfrhrtKsyxyHsYtppE2M41cSCK7trr2ZyAUEgU8LIUg6 X/Lapv8AaOaw0E96THxvw1MZWnVU3CGhbAitOzLcP/ucyQP1GeuPdA1DSlIGceoqn5My mGKg== X-Forwarded-Encrypted: i=1; AHgh+Rr8fBqFtPImFmb0igjA3cqDV7R2i39Wf1aMWlyxH0/3F5J0OTsxzGr32kMPXJCm27IGqCiWLj17u9c0xJk=@vger.kernel.org X-Gm-Message-State: AOJu0Ywn9IXnhw9OYgQIKyed6OV36Hav8F8eNkwS4ay2oXrPrcqBOzm5 QVuS+GhfRh/2de3HhO6+4fyYr7MRFcHeen73YQ4LbXJ8bzwM7SpQ4Ak9 X-Gm-Gg: AR+sD12AtuYWpB69MuY41MajwUUO3zuZPaPTv11YfmnGgfkTtIqr/cLkn1tGFmA5ZnL YSou6UqSpkrVB19sherKqWM1BsKwIRHy4K77sFoJMZu+2G1L/sCjbAMM82w7DlkPmMOIUbbvi71 t6Hehv5EC0Shy1/EgZHdGTGh0gESQFUh64+0PNhSUK8UeFnAklq3V1l2obGvZWMKnsHp1ayQ2qH GFTzGMYhLRNGFqfKAcQc+VXkFmTSy45FEeAVfMkAj1igXyc2RoRFjjLGcUrgxgMRBC3XLsIy7jY ZLEq++ibyf0jMAUFidXbk1Bkzpk24V6yt6DJlrL/eVSOU0UA5rHEhjWIb7pizlx13omtOt+NqLI O1DRRQeq+kvGJCgheLmx9UT2QdnaMIgqg2hGSLgNPCWVmJwbopLtflFJS3xUKlrO+ATEHskteSH nGh0UiVvE2AfXaiE5cJrDPJV5MORTnls6whkHoXzqBUftpMngkKiMUAbimQSp4jGl/nhbof4dsq ZnTKDHaTitriBnNgGpRHN+JIN8a4hx+RgL9VkK+MqEZU6f3ZFRqdLB+T7wCT17wDfcQBwLCRvPO U2g3ldfJ3q/xR4xKHWb7BqMQY0c2JLoxf6+Iju05HddjVcjuTkNB5W9AtQwc6BmHp0lRji86c+J SI8SGu/sAzjqfueCq X-Received: by 2002:a05:6830:3814:b0:7e6:ca29:9609 with SMTP id 46e09a7af769-7f196d82b85mr13995078a34.13.1785734136211; Sun, 02 Aug 2026 22:15:36 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:35 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:20 -0600 Subject: [PATCH 10/21] net: phy: add X-Powers AC200 EPHY control driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-10-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC200 Fast Ethernet PHY is powered and configured through registers in the parent I2C regmap before its Clause 22 link registers become usable. Add a control driver that prepares the calibration value and vendor offset, interface mode and input-clock selection. Use an optional SoC SID cell when supplied, otherwise read the AC200's internal calibration eFuse. Derive the documented 24 or 27 MHz selector from the actual locked clock rate. Although the feature summary also mentions 25 MHz, EPHY_CTL provides no encoding for it, so reject that rate rather than silently selecting 27 MHz. Program the link PHY MDIO address into EPHY_CTL.PHY_ADDR before bringing the PHY out of its disabled state using the vendor initialization sequence. Expose serialized, idempotent power-on and power-off operations so the link-PHY driver can sequence the control block across resets and system sleep. Also expose operations for the global LED polarity and package pad enables. Initialize all three outputs active-low as in the vendor kernel, while allowing an explicit link-PHY LED topology to replace that fallback. Quiesce the block during probe failures, driver removal and system shutdown. Signed-off-by: James Hilliard --- drivers/net/phy/Kconfig | 9 + drivers/net/phy/Makefile | 1 + drivers/net/phy/xpowers-ac200-ctl.c | 330 ++++++++++++++++++++++++++++++++= ++++ drivers/net/phy/xpowers-acx00.h | 25 +++ 4 files changed, 365 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 099f25dceabb..e059bd6c5eda 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -469,6 +469,15 @@ config VITESSE_PHY help Currently supports the vsc8244 =20 +config XPOWERS_AC200_PHY_CTL + tristate "X-Powers AC200 Ethernet PHY control" + depends on MFD_AC200 + help + Enable the control driver for the Fast Ethernet PHY function in + the X-Powers AC200 mixed-signal companion IC. It programs the PHY + address, interface mode, calibration and I/O controls through the + parent AC200 I2C regmap. + config XILINX_GMII2RGMII tristate "Xilinx GMII2RGMII converter driver" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index de660ae94945..e53ca319f9c4 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -99,4 +99,5 @@ obj-$(CONFIG_SMSC_PHY) +=3D smsc.o obj-$(CONFIG_STE10XP) +=3D ste10Xp.o obj-$(CONFIG_TERANETICS_PHY) +=3D teranetics.o obj-$(CONFIG_VITESSE_PHY) +=3D vitesse.o +obj-$(CONFIG_XPOWERS_AC200_PHY_CTL) +=3D xpowers-ac200-ctl.o obj-$(CONFIG_XILINX_GMII2RGMII) +=3D xilinx_gmii2rgmii.o diff --git a/drivers/net/phy/xpowers-ac200-ctl.c b/drivers/net/phy/xpowers-= ac200-ctl.c new file mode 100644 index 000000000000..c2a37f958565 --- /dev/null +++ b/drivers/net/phy/xpowers-ac200-ctl.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * X-Powers AC200 Ethernet PHY control driver + * + * Copyright (C) 2026 James Hilliard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xpowers-acx00.h" + +#define AC200_EPHY_BPS_EFFUSE_OFFSET 3 + +#define AC200_SYS_EPHY_CTL0_REG 0x0014 +#define AC200_EPHY_RESET_DEASSERT BIT(0) +#define AC200_EPHY_SYSCLK_ENABLE BIT(1) + +#define AC200_SYS_EPHY_CTL1_REG 0x0016 +#define AC200_EPHY_MII_IO_ENABLE BIT(0) +#define AC200_EPHY_LINK_LED_IO_ENABLE BIT(1) +#define AC200_EPHY_SPEED_LED_IO_ENABLE BIT(2) +#define AC200_EPHY_DUPLEX_LED_IO_ENABLE BIT(3) +#define AC200_EPHY_LED_IO_ENABLE_MASK \ + (AC200_EPHY_LINK_LED_IO_ENABLE | AC200_EPHY_SPEED_LED_IO_ENABLE | \ + AC200_EPHY_DUPLEX_LED_IO_ENABLE) + +/* AC200-internal copy of the Ethernet PHY calibration eFuse. */ +#define AC200_EFUSE_EPHY_REG 0x8004 + +#define AC200_EPHY_CTL_REG 0x6000 +#define AC200_EPHY_SHUTDOWN BIT(0) +#define AC200_EPHY_LED_ACTIVE_LOW BIT(1) +#define AC200_EPHY_CLK_SEL_24_MHZ BIT(2) +#define AC200_EPHY_PHY_ADDR_MASK GENMASK(8, 4) +#define AC200_EPHY_RMII_SEL BIT(11) +#define AC200_EPHY_BPS_EFFUSE_MASK GENMASK(15, 12) + +struct ac200_ephy_ctl { + struct acx00_ephy_control control; + struct regmap *regmap; + struct mutex lock; /* Serializes power sequencing and state. */ + u16 ephy_ctl; + u16 led_io_enable; + unsigned int phy_addr; + bool powered; +}; + +static int +ac200_ephy_ctl_set_led_outputs(struct acx00_ephy_control *control, + unsigned long outputs) +{ + struct ac200_ephy_ctl *priv =3D + container_of(control, struct ac200_ephy_ctl, control); + u16 led_io_enable; + int ret =3D 0; + + if (outputs & ~GENMASK(ACX00_EPHY_LED_COUNT - 1, 0)) + return -EINVAL; + + led_io_enable =3D (outputs << 1) & AC200_EPHY_LED_IO_ENABLE_MASK; + + mutex_lock(&priv->lock); + if (priv->powered) + ret =3D regmap_update_bits(priv->regmap, AC200_SYS_EPHY_CTL1_REG, + AC200_EPHY_LED_IO_ENABLE_MASK, + led_io_enable); + if (!ret) + priv->led_io_enable =3D led_io_enable; + mutex_unlock(&priv->lock); + + return ret; +} + +static int +ac200_ephy_ctl_set_led_polarity(struct acx00_ephy_control *control, + bool active_low) +{ + struct ac200_ephy_ctl *priv =3D + container_of(control, struct ac200_ephy_ctl, control); + u16 value =3D active_low ? AC200_EPHY_LED_ACTIVE_LOW : 0; + int ret =3D 0; + + mutex_lock(&priv->lock); + if (priv->powered) + ret =3D regmap_update_bits(priv->regmap, AC200_EPHY_CTL_REG, + AC200_EPHY_LED_ACTIVE_LOW, value); + if (!ret) { + priv->ephy_ctl &=3D ~AC200_EPHY_LED_ACTIVE_LOW; + priv->ephy_ctl |=3D value; + } + mutex_unlock(&priv->lock); + + return ret; +} + +static int ac200_ephy_ctl_power_off_locked(struct ac200_ephy_ctl *priv) +{ + int err; + int ret; + + if (!priv->powered) + return 0; + + ret =3D regmap_write(priv->regmap, AC200_EPHY_CTL_REG, + priv->ephy_ctl | + FIELD_PREP(AC200_EPHY_PHY_ADDR_MASK, + priv->phy_addr) | + AC200_EPHY_SHUTDOWN); + err =3D regmap_write(priv->regmap, AC200_SYS_EPHY_CTL1_REG, 0); + if (!ret) + ret =3D err; + err =3D regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0_REG, 0); + if (!ret) + ret =3D err; + + priv->powered =3D false; + + return ret; +} + +static int ac200_ephy_ctl_power_off(struct acx00_ephy_control *control) +{ + struct ac200_ephy_ctl *priv =3D + container_of(control, struct ac200_ephy_ctl, control); + int ret; + + mutex_lock(&priv->lock); + ret =3D ac200_ephy_ctl_power_off_locked(priv); + mutex_unlock(&priv->lock); + + return ret; +} + +static int ac200_ephy_ctl_power_on(struct acx00_ephy_control *control, + unsigned int phy_addr) +{ + struct ac200_ephy_ctl *priv =3D + container_of(control, struct ac200_ephy_ctl, control); + u16 ephy_ctl; + int ret; + + if (phy_addr > FIELD_MAX(AC200_EPHY_PHY_ADDR_MASK)) + return -EINVAL; + + mutex_lock(&priv->lock); + if (priv->powered && priv->phy_addr =3D=3D phy_addr) { + ret =3D 0; + goto out_unlock; + } + if (priv->powered) { + ret =3D ac200_ephy_ctl_power_off_locked(priv); + if (ret) + goto out_unlock; + } + + ephy_ctl =3D priv->ephy_ctl | + FIELD_PREP(AC200_EPHY_PHY_ADDR_MASK, phy_addr); + + /* Start from a disabled state before applying the configuration. */ + ret =3D regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0_REG, 0); + if (ret) + goto err_disable; + + ret =3D regmap_write(priv->regmap, AC200_SYS_EPHY_CTL1_REG, + AC200_EPHY_MII_IO_ENABLE | + priv->led_io_enable); + if (ret) + goto err_disable; + + ret =3D regmap_write(priv->regmap, AC200_EPHY_CTL_REG, + ephy_ctl | AC200_EPHY_SHUTDOWN); + if (ret) + goto err_disable; + + ret =3D regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0_REG, + AC200_EPHY_RESET_DEASSERT | + AC200_EPHY_SYSCLK_ENABLE); + if (ret) + goto err_disable; + + fsleep(10000); + + ret =3D regmap_write(priv->regmap, AC200_EPHY_CTL_REG, ephy_ctl); + if (ret) + goto err_disable; + + priv->phy_addr =3D phy_addr; + priv->powered =3D true; + goto out_unlock; + +err_disable: + /* Mark it active so the cleanup sequence is always attempted. */ + priv->phy_addr =3D phy_addr; + priv->powered =3D true; + ac200_ephy_ctl_power_off_locked(priv); +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static int ac200_ephy_ctl_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct ac200_ephy_ctl *priv; + phy_interface_t interface; + struct clk *clk; + unsigned long clk_rate; + unsigned int calibration; + u8 nvmem_calibration; + u8 bps_effuse_code; + u16 ephy_ctl; + int ret; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + mutex_init(&priv->lock); + + priv->regmap =3D dev_get_regmap(dev->parent, NULL); + if (!priv->regmap) + return dev_err_probe(dev, -EPROBE_DEFER, + "parent regmap is not ready\n"); + + if (device_property_present(dev, "nvmem-cells")) { + ret =3D nvmem_cell_read_u8(dev, "calibration", + &nvmem_calibration); + if (ret) + return dev_err_probe(dev, ret, + "failed to read calibration data\n"); + calibration =3D nvmem_calibration; + } else { + ret =3D regmap_read(priv->regmap, AC200_EFUSE_EPHY_REG, + &calibration); + if (ret) + return dev_err_probe(dev, ret, + "failed to read on-chip calibration data\n"); + } + + ret =3D device_get_phy_mode(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read PHY mode\n"); + interface =3D ret; + + /* The vendor driver supplies no transfer function beyond this offset. */ + bps_effuse_code =3D (calibration + AC200_EPHY_BPS_EFFUSE_OFFSET) & + FIELD_MAX(AC200_EPHY_BPS_EFFUSE_MASK); + ephy_ctl =3D FIELD_PREP(AC200_EPHY_BPS_EFFUSE_MASK, bps_effuse_code) | + AC200_EPHY_LED_ACTIVE_LOW; + /* EPHY_MODE and BIST_CLK_EN stay clear for normal operation. */ + + switch (interface) { + case PHY_INTERFACE_MODE_MII: + break; + case PHY_INTERFACE_MODE_RMII: + ephy_ctl |=3D AC200_EPHY_RMII_SEL; + break; + default: + return dev_err_probe(dev, -EINVAL, + "unsupported PHY mode %s\n", + phy_modes(interface)); + } + + clk =3D clk_get(dev->parent, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get input clock\n"); + + clk_rate =3D clk_get_rate(clk); + clk_put(clk); + + switch (clk_rate) { + case 24000000: + ephy_ctl |=3D AC200_EPHY_CLK_SEL_24_MHZ; + break; + case 27000000: + break; + default: + return dev_err_probe(dev, -EINVAL, + "unsupported input clock rate %lu Hz\n", + clk_rate); + } + + priv->control.power_on =3D ac200_ephy_ctl_power_on; + priv->control.power_off =3D ac200_ephy_ctl_power_off; + priv->control.set_led_outputs =3D ac200_ephy_ctl_set_led_outputs; + priv->control.set_led_polarity =3D ac200_ephy_ctl_set_led_polarity; + priv->control.interface =3D interface; + priv->ephy_ctl =3D ephy_ctl; + priv->led_io_enable =3D AC200_EPHY_LED_IO_ENABLE_MASK; + platform_set_drvdata(pdev, &priv->control); + return 0; +} + +static void ac200_ephy_ctl_remove(struct platform_device *pdev) +{ + struct acx00_ephy_control *control =3D platform_get_drvdata(pdev); + + control->power_off(control); +} + +static const struct of_device_id ac200_ephy_ctl_of_match[] =3D { + { .compatible =3D "x-powers,ac200-ephy-ctl" }, + { } +}; +MODULE_DEVICE_TABLE(of, ac200_ephy_ctl_of_match); + +static struct platform_driver ac200_ephy_ctl_driver =3D { + .probe =3D ac200_ephy_ctl_probe, + .remove =3D ac200_ephy_ctl_remove, + .shutdown =3D ac200_ephy_ctl_remove, + .driver =3D { + .name =3D "ac200-ephy-ctl", + .of_match_table =3D ac200_ephy_ctl_of_match, + }, +}; +module_platform_driver(ac200_ephy_ctl_driver); + +MODULE_AUTHOR("James Hilliard "); +MODULE_DESCRIPTION("X-Powers AC200 Ethernet PHY control driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/xpowers-acx00.h b/drivers/net/phy/xpowers-acx0= 0.h new file mode 100644 index 000000000000..8cf6fe616137 --- /dev/null +++ b/drivers/net/phy/xpowers-acx00.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DRIVERS_NET_PHY_XPOWERS_ACX00_H +#define __DRIVERS_NET_PHY_XPOWERS_ACX00_H + +#include + +enum acx00_ephy_led { + ACX00_EPHY_LED_LINK_ACTIVITY, + ACX00_EPHY_LED_SPEED, + ACX00_EPHY_LED_DUPLEX, + ACX00_EPHY_LED_COUNT, +}; + +struct acx00_ephy_control { + phy_interface_t interface; + int (*power_on)(struct acx00_ephy_control *control, + unsigned int phy_addr); + int (*power_off)(struct acx00_ephy_control *control); + int (*set_led_outputs)(struct acx00_ephy_control *control, + unsigned long outputs); + int (*set_led_polarity)(struct acx00_ephy_control *control, + bool active_low); +}; + +#endif --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f42.google.com (mail-ot1-f42.google.com [209.85.210.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E66F5397341 for ; Mon, 3 Aug 2026 05:15:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734141; cv=none; b=Ujk/p9AMrSnYQQoksVmujSWGuRil0RQ8vlJVeZgeIFkD2EAd0aZKs80wxnFIEnc0WfpaXqEy6sRGB9zsASV6jdK4CPvrdXEfPHLASrY6Nu2CD+T+Mc8UDgLlvve8Futm3A04wM0u9s41+L9wIxGp982MShfzXzKthqWQMQa86xk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734141; c=relaxed/simple; bh=2SOkuuUqffJAqXcEW7ZDhEaFHvF0SZKllJC1Nh5E8zo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZCuBFz81O8rq70+PNDz166aR5hHJxFH+4lvPy5Vw3zfftFw7R/s7zyLKRSSYczzuv+4+oOLvQrICXJw5ZLaFUf0mwYda3b0foPgoVYF08tbailHCB6Hn49SQUoTSHlOfEWLueEwixsa1zo5KmZ6lzNo7V336f0Hi2YWMjpubZ54= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=XiIWB36y; arc=none smtp.client-ip=209.85.210.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XiIWB36y" Received: by mail-ot1-f42.google.com with SMTP id 46e09a7af769-7e9eaf04bfaso1038890a34.1 for ; Sun, 02 Aug 2026 22:15:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734138; x=1786338938; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=GTwjTV5MzEj5mt/lgWMCGvinpE29xZysk84NZ5krcS8=; b=XiIWB36y+ctp2h/vcBxuJgrrd7pGCplgyG69UMP9K2TEDFvjAsmcU/8p0nlafeR6tx q8uf5vA2LFoysoiCU7Dh/atuC74pkqQgJf/9982ta7Imms7jkD84Xm1F0L+YJ64PLrMK m/ISqcRZoQA3bucxpfW70OSOkYXg7MkZMeDVULK/UH7rztYYXPoYehziikXwrY9dMgoX oV7ppK5H1T/aQPhxB1kKwGCvGwDgsFbRtHT+5nonuPQqMTOOBicASamXYyLUAFhsU/Ap pyh8JCTS9kdLeLMfaKFhTCy/n6zcO5r+NEgl66x4zNdnNvg1XMiyjQIEUBSTilhbTaq0 YINA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734138; x=1786338938; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=GTwjTV5MzEj5mt/lgWMCGvinpE29xZysk84NZ5krcS8=; b=L5fvmv3wL720HZKVfgRLMQoucycXI0kD1h3iIugp5WfZuVoHEPUCmlL3T5NZ5mkUZb db3tsob9R8ytyaL5tT7VBVlwyPPZz82rmEn0VjMKLSParIjvIBxhlRbccLEsfQPHOMfi 1Rnt2ib6nGE8zQsV0XdW/fquSdMKbu1F2v8qgJMtURwJSOr7bINS63m4f3HTfyMKt+jv t7RQnCEP3754lpJVBM++zf3KH2ScPPhWUZzoukE9z/SK8X8nWTErNgGzNwixXh0Raogu WdEtAL9OEI2IbeABcARa4W0OETQY2U36pjlKV6CkFnizLqgkcwXovm5/C3GvyM5gYUw2 +Pzg== X-Forwarded-Encrypted: i=1; AHgh+RpPdjx/ZZrFi0jOuModassln5eCZnK+/WvNZTULjg4aTRM9LV1uWYVeT6Bkeob76RXkMjqsXCCadu59XZs=@vger.kernel.org X-Gm-Message-State: AOJu0YyCuWUKIWb0InNH3Ww3g/FW7DGs2KF6Hv1W+CwFVQ8zmc6KNpve pIq++HS9B1nt6wEsfklKUv89Jm2DBjrjYL44Rf49Zt3KLUO87d6SqCYO X-Gm-Gg: AR+sD13CPqmBIWKFU2/YM3XP+Z/DM3vUJEexuDtFrfnW8/Z42BgmOve4NaCU9oEGbGp jhcJ5SCvxidzidrAHv7ajWStki3XK90VASvoHR1M2yXbUSyQCFFDutUx24/cGgCD/cp6ulLQsOq gdlvotsIO1cKPBkxEitkfGajem8OXHgV5zogaaVg8VoJ05/c6+oP/LCobATq80yWHKTtyyjKjak 53I7jm89CXYPYY6eQbPe2NPiM3zBD2u7SOCblsLUlfCsYJy5JVqoigziy+9B0rUyPhgM7CtR+VU Ba4wvlEHqInC+ascMPSAuq3VgrTDe3jtYi0uKkvpIiyuMnmnhs+ZOwE4qDgymeCcIocGFizHLeJ zb49y/mCGnOmvpwZ84zRmMA5clTt4CV95olxC+ZnJfqm7W8FR7H5E7FgdL2wE6yYBViHWk0mEAH fVX+efU3r8UHW8quUntQ80w6QwV6VrAUMM6kS4Zm4F/9vNMHAL8MEwbXeC80jKVk9rbqoT4A8Ox 722QVzqw89LFObujAwfIXtaSxGvdhVlbp8JIma8ruQ5SYHdN2X/v2W2fthMwiMvwGpHQTQyZGvf z9dNKRwVwVgO5D37YZ5lnRJXe3KkDKm2tDB2ffLOpZF1Znb/Ex4iojmvZ+ILesRTlYXgd5Z88hf coVOw7gbWIhAJMPpE X-Received: by 2002:a05:6830:4489:b0:7e9:cddb:142a with SMTP id 46e09a7af769-7f196bd63a9mr15354948a34.7.1785734137863; Sun, 02 Aug 2026 22:15:37 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:37 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:21 -0600 Subject: [PATCH 11/21] dt-bindings: net: x-powers: add AC300 EPHY control Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-11-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC300 companion IC exposes the Fast Ethernet PHY control registers through a separate non-PHY Clause 22 address. The manual defines the control address as the link-PHY address plus 16, giving address ranges of 16-23 and 0-7 respectively. Describe the control endpoint, its required VCC1 supply, its 24, 25 or 27 MHz input clock, interface mode and calibration cell. Signed-off-by: James Hilliard --- .../bindings/net/x-powers,ac300-ephy-ctl.yaml | 77 ++++++++++++++++++= ++++ 1 file changed, 77 insertions(+) diff --git a/Documentation/devicetree/bindings/net/x-powers,ac300-ephy-ctl.= yaml b/Documentation/devicetree/bindings/net/x-powers,ac300-ephy-ctl.yaml new file mode 100644 index 000000000000..a6634fcfafd4 --- /dev/null +++ b/Documentation/devicetree/bindings/net/x-powers,ac300-ephy-ctl.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/x-powers,ac300-ephy-ctl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: X-Powers AC300 Ethernet PHY control interface + +maintainers: + - James Hilliard + +description: + The AC300 Fast Ethernet PHY has a separate control interface accessed as= a + non-PHY Clause 22 device. Its address is 16 plus the address of the link= PHY. + +properties: + compatible: + const: x-powers,ac300-ephy-ctl + + reg: + minimum: 16 + maximum: 23 + + clocks: + maxItems: 1 + description: + AC300 input clock. Its configured rate must be 24, 25, or 27 MHz and + determines the corresponding EPHY_CLK_SEL value. + + vcc1-supply: + description: + 3.3 V supply for the AC300 I/O, bandgap, Ethernet PHY analog front e= nd, + and internal digital LDO + + nvmem-cells: + maxItems: 1 + description: + SoC SID cell containing the Ethernet PHY calibration value written to + the AC300 BGS_EFFUSE field after adding 3 modulo 16, as prescribed by + the vendor initialization sequence. + + nvmem-cell-names: + const: calibration + + phy-mode: + enum: + - mii + - rmii + +required: + - compatible + - reg + - clocks + - vcc1-supply + - nvmem-cells + - nvmem-cell-names + - phy-mode + +additionalProperties: false + +examples: + - | + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy-control@10 { + compatible =3D "x-powers,ac300-ephy-ctl"; + reg =3D <0x10>; + clocks =3D <&pwm 5>; + vcc1-supply =3D <®_3v3>; + nvmem-cells =3D <&ephy_calibration>; + nvmem-cell-names =3D "calibration"; + phy-mode =3D "rmii"; + }; + }; +... --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f50.google.com (mail-ot1-f50.google.com [209.85.210.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8082339B975 for ; Mon, 3 Aug 2026 05:15:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734144; cv=none; b=gQ04Z+Q/+FQx1kyDwYnnnGCbgKozjXd/n+O2JTwME981rzmvNuu/Aj6pw9B/8gZtlRyvqh1cSI00K0L/cbPkZmILCr84OlWmgXEOxwqx07z58W2AejGwNOO23HbJPF3pjgdx7QVP/g81aVqRE8EUEYghl6V9p1bgbty8A1jacCI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734144; c=relaxed/simple; bh=ivlB4EsccJlR8c56XVzqea+fP0pw7c0V38csFjkA2GA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ts4Z30Ag7XhmtsHs8jl69cMc/MLYiScjA/bFquJDgo8C7L4d7m9UUA5Hsm48skqslajj8V6sTqbkeZQcgQqebKAM5H4gxXFUuy1/fWvClG55dAnsLuZPr3S+lz+7uBnDxmQ5+V5f9VcTp0fi89Mp4TiZFZIZXknQMwEpgpviCdk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=lgTMMGYX; arc=none smtp.client-ip=209.85.210.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lgTMMGYX" Received: by mail-ot1-f50.google.com with SMTP id 46e09a7af769-7ebd88be784so1889375a34.2 for ; Sun, 02 Aug 2026 22:15:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734140; x=1786338940; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=qMpLqvLPj4rvPj5SZvuQI1CV6P3xEdk1nLLBNVxHBq8=; b=lgTMMGYXAXacOBgAvqTIGSRwce0xxTzm6K9g3qRv3n2huWDXm5PJ89rpothYHZNJ17 YpLJeVbOPfL7viytHz8N51ooUfud2QhVrXsHnXi/8vxciASnmTrdUTahDOQDi65fC/A3 e1i6FnHzdG+UbCbWB08xCiksSfegyWXd54QWdeeuwyGtGdC76TdNWIt69ZlS5tBHE1dX JwYebkKXZ6avy0XJWSKxVfJrZ4tHFhK6JYTc3SiB6Bo8aGCyb20giGkad00PHsK9YpJ9 XArT730PDs18gL0O35fyt1pjoFck36lLCjZ40QUYpMbZBEVYcC2SSRc3oVmvKgXDDgHS dbWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734140; x=1786338940; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=qMpLqvLPj4rvPj5SZvuQI1CV6P3xEdk1nLLBNVxHBq8=; b=NmQibwPzZGOxaOslRvcIbv6nLWtqKISr8aWNAS2RWOggKvuuPN9RFZHNP/2Dtb/dAz n+jAcnIzPVh4pkAPLleKI1R46RyEQND3KcSgUCEJH6EDXQA0UpaVQTpLY+ESBsdMR4AJ nKE2+NtFJz+LiVeD0SkPm4CFXrniGkO2AFEdRZIMUCFf4xmUV5xCs9EHdhUOrByUiXvn 6D0sHSmg3PJPETrtgtdU+yhmQJ8g9wKQsaMy/m3fy3XLc3eGHfWOemU1jsa8m6ajH5n3 /Xqc439AWDYMlzbccrH14e07ftXbe7CtQziSK0k+BxvbQHjmLg4FEzn7vgbgWMmZL7Vi bKYQ== X-Forwarded-Encrypted: i=1; AHgh+RrQoZDL67eaoiO6rBtBqLIm+rJBae5hoNRDgCdN9E3jg+Nc+/HrichGJk1TkcUc0D6LZtB7mysqHunGVHs=@vger.kernel.org X-Gm-Message-State: AOJu0YxXxrdXthGaPuXZS5ivXCVs/rvURxuOWKe4E652MkeShVJu2yhg XBXv+81iXd/XpbFPNDOJDvt6VU4WO4FUQllFllYqa/hWVVzHHzdm7tyA X-Gm-Gg: AR+sD11WdgHq2HZVGakUZKdombwXKYyEC/2d4RXMnlvzZ9imWSKLA6oxzgwXIHiWpFD T/0XeN9Lforbrp+r8OVi8+sU/QNWNfLBfWq4Ji7kCghLIsHJb0l4izvQ2foU35XvL7FGfj0dJer kfla6Fr+uY0YrIgJVSDGovlgqra1R+VH0kEGwOTjaOZ9oRPRoVYnFebHEEvLvKg4UNMdiswL3UJ dvT2iQtJMq9Hpfd/dLdiCXSte+lQe9rf1WJ3mERNfpPwlZ+V/d7GsBvh1+/VWscgkrSGPovA5NK lPRcwCytyaQADSf9BxHWDXaEXl6W2agnUaLLmBZ9O1lGm32BwAzpzJB0vM0OVJH8XbpTS79FbyE ltl2ZzpfE2W6E+AcJk+5LCd4S114rFNJhozVnPo/EIoroMw/F42qlYFIIY38kB5IqCWbsOiZRMA grANRvnwjt5ER8OwHUpxoOMKp/rM3/3JOyabXDOltozn5XGxyxU067QKb3neGp3MY8CvI6Pinqa jlF4gG5kK2ZQJQLFxNGk4XDpZCFFBWkJ/dOgRNetW9G+EWjZSdqQZawFJX4CbFQltUEHjogw/Z8 5sMgGHsJvA11DxDBvxqMPKw6VXI7C6zqL0gFYj4sLL6FwretnRzKme0AqwPRfofR1GrNt8IxTBx sZcoAmMCJn/KerKv58g== X-Received: by 2002:a05:6830:67f6:b0:7e6:e022:4b44 with SMTP id 46e09a7af769-7f196f1c52bmr14209690a34.15.1785734139942; Sun, 02 Aug 2026 22:15:39 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:39 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:22 -0600 Subject: [PATCH 12/21] net: phy: add X-Powers AC300 EPHY control driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-12-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC300 Fast Ethernet PHY uses a non-PHY Clause 22 endpoint for the power-up and configuration sequence required before its link registers become usable. Enable the required VCC1 supply and wait the manual's 10 ms power-on-reset interval before accessing the device. Accept the configured 24, 25 or 27 MHz input clock and program its corresponding selector, apply the SoC SID calibration value and vendor offset, select the interface mode, configure the I/O drive controls, and follow the manual reset-before-clock power-up sequence. Retain the vendor eFuse and register-clock enable settings. Validate the control address and supply configuration against the package strap state. Clear a latched MDIO error after reset and fail power-up if it remains asserted. Enable the internal digital LDO only for the corresponding package and preserve the external-supply configuration across later power cycles. Report the chip, mask and package revisions. Expose serialized, idempotent power-on and power-off operations so the link-PHY driver can sequence the input clock and control block across resets and system sleep. Also expose operations for the global LED polarity and package pad enables, retaining the documented default drive strength. Initialize all three outputs active-low as in the vendor kernel, while allowing an explicit link-PHY LED topology to replace that fallback. Signed-off-by: James Hilliard --- drivers/net/phy/Kconfig | 9 + drivers/net/phy/Makefile | 1 + drivers/net/phy/xpowers-ac300-ctl.c | 454 ++++++++++++++++++++++++++++++++= ++++ drivers/net/phy/xpowers-acx00.h | 2 + 4 files changed, 466 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index e059bd6c5eda..9b202072d5a0 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -478,6 +478,15 @@ config XPOWERS_AC200_PHY_CTL address, interface mode, calibration and I/O controls through the parent AC200 I2C regmap. =20 +config XPOWERS_AC300_PHY_CTL + tristate "X-Powers AC300 Ethernet PHY control" + depends on COMMON_CLK && NVMEM && OF_MDIO + help + Enable the MDIO control driver for the Fast Ethernet PHY in the + X-Powers AC300 companion IC. It programs the PHY calibration, + interface mode, clock and I/O controls through the separate MDIO + control address. + config XILINX_GMII2RGMII tristate "Xilinx GMII2RGMII converter driver" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e53ca319f9c4..2d22d5a4c93d 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -100,4 +100,5 @@ obj-$(CONFIG_STE10XP) +=3D ste10Xp.o obj-$(CONFIG_TERANETICS_PHY) +=3D teranetics.o obj-$(CONFIG_VITESSE_PHY) +=3D vitesse.o obj-$(CONFIG_XPOWERS_AC200_PHY_CTL) +=3D xpowers-ac200-ctl.o +obj-$(CONFIG_XPOWERS_AC300_PHY_CTL) +=3D xpowers-ac300-ctl.o obj-$(CONFIG_XILINX_GMII2RGMII) +=3D xilinx_gmii2rgmii.o diff --git a/drivers/net/phy/xpowers-ac300-ctl.c b/drivers/net/phy/xpowers-= ac300-ctl.c new file mode 100644 index 000000000000..eb3faaab9337 --- /dev/null +++ b/drivers/net/phy/xpowers-ac300-ctl.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * X-Powers AC300 Ethernet PHY control driver + * + * Copyright (C) 2026 James Hilliard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xpowers-acx00.h" + +#define AC300_EPHY_BGS_EFFUSE_OFFSET 3 + +#define AC300_SYS_CONTROL_REG 0x00 +#define AC300_CHIP_VERSION_MASK GENMASK(15, 12) +#define AC300_PACKAGE_STATUS_MASK GENMASK(11, 8) +#define AC300_EPHY_CLK_SEL_MASK GENMASK(7, 6) +#define AC300_EPHY_CLK_SEL_25_MHZ FIELD_PREP(AC300_EPHY_CLK_SEL_MASK, 0) +#define AC300_EPHY_CLK_SEL_27_MHZ FIELD_PREP(AC300_EPHY_CLK_SEL_MASK, 1) +#define AC300_EPHY_CLK_SEL_24_MHZ FIELD_PREP(AC300_EPHY_CLK_SEL_MASK, 2) +#define AC300_EFUSE_CLK_ENABLE BIT(5) +#define AC300_EPHY_REG_CLK_ENABLE BIT(4) +#define AC300_MDIO_ERROR BIT(3) +#define AC300_CLKIN_GATING_ENABLE BIT(2) +#define AC300_EPHY_RESET_DEASSERT BIT(1) +#define AC300_CHIP_RESET_DEASSERT BIT(0) + +#define AC300_MASK_VERSION_REG 0x04 +#define AC300_MASK_VERSION_MASK GENMASK(2, 0) + +#define AC300_PACKAGE_POR_INTERNAL_DLDO BIT(3) +#define AC300_PACKAGE_PHY_ADDR_MASK GENMASK(2, 0) + +#define AC300_SYS_BIAS1_REG 0x02 +#define AC300_INTERNAL_DLDO_ENABLE BIT(15) + +#define AC300_SYS_IO_REG 0x05 +#define AC300_MDIO_DRV_MASK GENMASK(15, 14) +#define AC300_LED_DRV_MASK GENMASK(13, 12) +#define AC300_MII_DRV_MASK GENMASK(11, 10) +#define AC300_IO_DRV_LEVEL_2 2 +#define AC300_CLKIN_PAD_ENABLE BIT(4) +#define AC300_DUPLEX_LED_IO_ENABLE BIT(3) +#define AC300_SPEED_LED_IO_ENABLE BIT(2) +#define AC300_LINK_LED_IO_ENABLE BIT(1) +#define AC300_EPHY_MII_IO_ENABLE BIT(0) +#define AC300_LED_IO_ENABLE_MASK \ + (AC300_DUPLEX_LED_IO_ENABLE | AC300_SPEED_LED_IO_ENABLE | \ + AC300_LINK_LED_IO_ENABLE) + +#define AC300_EPHY_CONFIG_REG 0x06 +#define AC300_EPHY_BGS_EFFUSE_MASK GENMASK(15, 12) +#define AC300_EPHY_RMII_SEL BIT(11) +#define AC300_EPHY_LED_ACTIVE_LOW BIT(1) +#define AC300_EPHY_SHUTDOWN BIT(0) + +#define AC300_SYS_CONTROL_ENABLE_BITS \ + (AC300_EFUSE_CLK_ENABLE | AC300_EPHY_REG_CLK_ENABLE | \ + AC300_CLKIN_GATING_ENABLE | \ + AC300_EPHY_RESET_DEASSERT | AC300_CHIP_RESET_DEASSERT) + +#define AC300_SYS_IO_BASE_VALUE \ + (FIELD_PREP(AC300_MDIO_DRV_MASK, AC300_IO_DRV_LEVEL_2) | \ + FIELD_PREP(AC300_LED_DRV_MASK, AC300_IO_DRV_LEVEL_2) | \ + FIELD_PREP(AC300_MII_DRV_MASK, AC300_IO_DRV_LEVEL_2) | \ + AC300_CLKIN_PAD_ENABLE | AC300_EPHY_MII_IO_ENABLE) + +struct ac300_ephy_ctl { + struct acx00_ephy_control control; + struct mdio_device *mdiodev; + struct clk *clk; + struct mutex lock; /* Serializes power sequencing and state. */ + u16 sys_control; + u16 ephy_config; + u16 led_io_enable; + bool package_known; + bool internal_dldo; + bool powered; +}; + +static unsigned int +ac300_ephy_ctl_link_addr(const struct ac300_ephy_ctl *priv) +{ + return priv->mdiodev->addr - AC300_EPHY_CONTROL_ADDR_OFFSET; +} + +static int +ac300_ephy_ctl_set_led_outputs(struct acx00_ephy_control *control, + unsigned long outputs) +{ + struct ac300_ephy_ctl *priv =3D + container_of(control, struct ac300_ephy_ctl, control); + u16 led_io_enable; + int ret =3D 0; + + if (outputs & ~GENMASK(ACX00_EPHY_LED_COUNT - 1, 0)) + return -EINVAL; + + led_io_enable =3D (outputs << 1) & AC300_LED_IO_ENABLE_MASK; + + mutex_lock(&priv->lock); + if (priv->powered) + ret =3D mdiodev_modify(priv->mdiodev, AC300_SYS_IO_REG, + AC300_LED_IO_ENABLE_MASK, led_io_enable); + if (!ret) + priv->led_io_enable =3D led_io_enable; + mutex_unlock(&priv->lock); + + return ret; +} + +static int +ac300_ephy_ctl_set_led_polarity(struct acx00_ephy_control *control, + bool active_low) +{ + struct ac300_ephy_ctl *priv =3D + container_of(control, struct ac300_ephy_ctl, control); + u16 value =3D active_low ? AC300_EPHY_LED_ACTIVE_LOW : 0; + int ret =3D 0; + + mutex_lock(&priv->lock); + if (priv->powered) + ret =3D mdiodev_modify(priv->mdiodev, AC300_EPHY_CONFIG_REG, + AC300_EPHY_LED_ACTIVE_LOW, value); + if (!ret) { + priv->ephy_config &=3D ~AC300_EPHY_LED_ACTIVE_LOW; + priv->ephy_config |=3D value; + } + mutex_unlock(&priv->lock); + + return ret; +} + +static int ac300_ephy_ctl_power_off_locked(struct ac300_ephy_ctl *priv) +{ + int err; + int ret; + + if (!priv->powered) + return 0; + + ret =3D mdiodev_write(priv->mdiodev, AC300_EPHY_CONFIG_REG, + priv->ephy_config | AC300_EPHY_SHUTDOWN); + err =3D mdiodev_write(priv->mdiodev, AC300_SYS_IO_REG, 0); + if (!ret) + ret =3D err; + err =3D mdiodev_write(priv->mdiodev, AC300_SYS_CONTROL_REG, + priv->package_known && !priv->internal_dldo ? + AC300_CHIP_RESET_DEASSERT : 0); + if (!ret) + ret =3D err; + + clk_disable_unprepare(priv->clk); + priv->powered =3D false; + + return ret; +} + +static int ac300_ephy_ctl_power_off(struct acx00_ephy_control *control) +{ + struct ac300_ephy_ctl *priv =3D + container_of(control, struct ac300_ephy_ctl, control); + int ret; + + mutex_lock(&priv->lock); + ret =3D ac300_ephy_ctl_power_off_locked(priv); + mutex_unlock(&priv->lock); + + return ret; +} + +static int ac300_ephy_ctl_power_on(struct acx00_ephy_control *control, + unsigned int phy_addr) +{ + struct ac300_ephy_ctl *priv =3D + container_of(control, struct ac300_ephy_ctl, control); + u8 package_status; + int sys_control; + u16 reset_value; + int ret; + + if (phy_addr !=3D ac300_ephy_ctl_link_addr(priv)) + return -EINVAL; + + mutex_lock(&priv->lock); + if (priv->powered) { + ret =3D 0; + goto out_unlock; + } + + ret =3D clk_prepare_enable(priv->clk); + if (ret) + goto out_unlock; + priv->powered =3D true; + + /* Keep the external-supply configuration across subsequent resets. */ + reset_value =3D priv->package_known && !priv->internal_dldo ? + AC300_CHIP_RESET_DEASSERT : 0; + ret =3D mdiodev_write(priv->mdiodev, AC300_SYS_CONTROL_REG, reset_value); + if (ret) + goto err_power_off; + + /* The manual requires both resets to be released before the clocks. */ + ret =3D mdiodev_write(priv->mdiodev, AC300_SYS_CONTROL_REG, + AC300_EPHY_RESET_DEASSERT | + AC300_CHIP_RESET_DEASSERT); + if (ret) + goto err_power_off; + + /* Retain the vendor clock-enable defaults, including the eFuse clock. */ + ret =3D mdiodev_write(priv->mdiodev, AC300_SYS_CONTROL_REG, + priv->sys_control); + if (ret) + goto err_power_off; + + sys_control =3D mdiodev_read(priv->mdiodev, AC300_SYS_CONTROL_REG); + if (sys_control < 0) { + ret =3D sys_control; + goto err_power_off; + } + if (sys_control & AC300_MDIO_ERROR) { + ret =3D mdiodev_write(priv->mdiodev, AC300_SYS_CONTROL_REG, + priv->sys_control | AC300_MDIO_ERROR); + if (ret) + goto err_power_off; + + sys_control =3D mdiodev_read(priv->mdiodev, AC300_SYS_CONTROL_REG); + if (sys_control < 0) { + ret =3D sys_control; + goto err_power_off; + } + if (sys_control & AC300_MDIO_ERROR) { + ret =3D -EIO; + goto err_power_off; + } + } + + package_status =3D FIELD_GET(AC300_PACKAGE_STATUS_MASK, sys_control); + if ((~package_status & AC300_PACKAGE_PHY_ADDR_MASK) !=3D + ac300_ephy_ctl_link_addr(priv)) { + ret =3D -EINVAL; + goto err_power_off; + } + + priv->internal_dldo =3D package_status & + AC300_PACKAGE_POR_INTERNAL_DLDO; + priv->package_known =3D true; + ret =3D mdiodev_modify(priv->mdiodev, AC300_SYS_BIAS1_REG, + AC300_INTERNAL_DLDO_ENABLE, + priv->internal_dldo ? + AC300_INTERNAL_DLDO_ENABLE : 0); + if (ret) + goto err_power_off; + + /* Keep the documented default drive level and leave the IRQ disabled. */ + ret =3D mdiodev_write(priv->mdiodev, AC300_SYS_IO_REG, + AC300_SYS_IO_BASE_VALUE | priv->led_io_enable); + if (ret) + goto err_power_off; + + fsleep(10000); + + ret =3D mdiodev_write(priv->mdiodev, AC300_EPHY_CONFIG_REG, + priv->ephy_config | AC300_EPHY_SHUTDOWN); + if (ret) + goto err_power_off; + + fsleep(10000); + + ret =3D mdiodev_write(priv->mdiodev, AC300_EPHY_CONFIG_REG, + priv->ephy_config); + if (ret) + goto err_power_off; + + goto out_unlock; + +err_power_off: + ac300_ephy_ctl_power_off_locked(priv); +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static int ac300_ephy_ctl_probe(struct mdio_device *mdiodev) +{ + struct device *dev =3D &mdiodev->dev; + struct ac300_ephy_ctl *priv; + phy_interface_t interface; + u8 calibration; + u8 bgs_effuse_code; + u8 package_status; + u16 ephy_config; + struct clk *clk; + int mask_version; + int sys_control; + unsigned long clk_rate; + int ret; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + if (mdiodev->addr < AC300_EPHY_CONTROL_ADDR_OFFSET || + mdiodev->addr > AC300_EPHY_CONTROL_ADDR_OFFSET + + FIELD_MAX(AC300_PACKAGE_PHY_ADDR_MASK)) + return dev_err_probe(dev, -EINVAL, + "control address is outside the package range\n"); + priv->mdiodev =3D mdiodev; + mutex_init(&priv->lock); + + ret =3D devm_regulator_get_enable(dev, "vcc1"); + if (ret) + return dev_err_probe(dev, ret, + "failed to enable VCC1 supply\n"); + + /* Wait for the power-on reset interval specified by the manual. */ + fsleep(10000); + + clk =3D devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get input clock\n"); + priv->clk =3D clk; + + ret =3D devm_clk_rate_exclusive_get(dev, clk); + if (ret) + return dev_err_probe(dev, ret, "failed to lock clock rate\n"); + + clk_rate =3D clk_get_rate(clk); + switch (clk_rate) { + case 24000000: + priv->sys_control =3D AC300_EPHY_CLK_SEL_24_MHZ; + break; + case 25000000: + priv->sys_control =3D AC300_EPHY_CLK_SEL_25_MHZ; + break; + case 27000000: + priv->sys_control =3D AC300_EPHY_CLK_SEL_27_MHZ; + break; + default: + return dev_err_probe(dev, -EINVAL, + "unsupported input clock rate %lu Hz\n", + clk_rate); + } + priv->sys_control |=3D AC300_SYS_CONTROL_ENABLE_BITS; + + ret =3D nvmem_cell_read_u8(dev, "calibration", &calibration); + if (ret) + return dev_err_probe(dev, ret, + "failed to read calibration data\n"); + + ret =3D device_get_phy_mode(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read PHY mode\n"); + interface =3D ret; + + /* The vendor driver supplies no transfer function beyond this offset. */ + bgs_effuse_code =3D (calibration + AC300_EPHY_BGS_EFFUSE_OFFSET) & + FIELD_MAX(AC300_EPHY_BGS_EFFUSE_MASK); + ephy_config =3D FIELD_PREP(AC300_EPHY_BGS_EFFUSE_MASK, bgs_effuse_code) | + AC300_EPHY_LED_ACTIVE_LOW; + /* EPHY_MODE and BIST_CLK_EN stay clear for normal operation. */ + + switch (interface) { + case PHY_INTERFACE_MODE_MII: + break; + case PHY_INTERFACE_MODE_RMII: + ephy_config |=3D AC300_EPHY_RMII_SEL; + break; + default: + return dev_err_probe(dev, -EINVAL, + "unsupported PHY mode %s\n", + phy_modes(interface)); + } + + priv->control.power_on =3D ac300_ephy_ctl_power_on; + priv->control.power_off =3D ac300_ephy_ctl_power_off; + priv->control.set_led_outputs =3D ac300_ephy_ctl_set_led_outputs; + priv->control.set_led_polarity =3D ac300_ephy_ctl_set_led_polarity; + priv->control.interface =3D interface; + priv->ephy_config =3D ephy_config; + priv->led_io_enable =3D AC300_LED_IO_ENABLE_MASK; + mdiodev_set_drvdata(mdiodev, &priv->control); + + ret =3D ac300_ephy_ctl_power_on(&priv->control, + ac300_ephy_ctl_link_addr(priv)); + if (ret) + goto err_disable; + + sys_control =3D mdiodev_read(mdiodev, AC300_SYS_CONTROL_REG); + if (sys_control < 0) { + ret =3D sys_control; + goto err_disable; + } + package_status =3D FIELD_GET(AC300_PACKAGE_STATUS_MASK, sys_control); + + mask_version =3D mdiodev_read(mdiodev, AC300_MASK_VERSION_REG); + if (mask_version < 0) { + ret =3D mask_version; + goto err_disable; + } + + dev_info(dev, "chip version %u, mask version %u, package %#x, %s supplies= , PHY %u, %lu Hz clock\n", + (unsigned int)FIELD_GET(AC300_CHIP_VERSION_MASK, sys_control), + (unsigned int)FIELD_GET(AC300_MASK_VERSION_MASK, mask_version), + package_status, + package_status & AC300_PACKAGE_POR_INTERNAL_DLDO ? + "POR/internal DLDO" : "reset pin/external VDD", + ac300_ephy_ctl_link_addr(priv), clk_rate); + + return 0; + +err_disable: + ac300_ephy_ctl_power_off(&priv->control); + return ret; +} + +static void ac300_ephy_ctl_remove(struct mdio_device *mdiodev) +{ + struct acx00_ephy_control *control =3D mdiodev_get_drvdata(mdiodev); + + control->power_off(control); +} + +static const struct of_device_id ac300_ephy_ctl_of_match[] =3D { + { .compatible =3D "x-powers,ac300-ephy-ctl" }, + { } +}; +MODULE_DEVICE_TABLE(of, ac300_ephy_ctl_of_match); + +static struct mdio_driver ac300_ephy_ctl_driver =3D { + .probe =3D ac300_ephy_ctl_probe, + .remove =3D ac300_ephy_ctl_remove, + .shutdown =3D ac300_ephy_ctl_remove, + .mdiodrv.driver =3D { + .name =3D "ac300-ephy-ctl", + .of_match_table =3D ac300_ephy_ctl_of_match, + }, +}; + +mdio_module_driver(ac300_ephy_ctl_driver); + +MODULE_AUTHOR("James Hilliard "); +MODULE_DESCRIPTION("X-Powers AC300 Ethernet PHY control driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/xpowers-acx00.h b/drivers/net/phy/xpowers-acx0= 0.h index 8cf6fe616137..8ed15bc4eed5 100644 --- a/drivers/net/phy/xpowers-acx00.h +++ b/drivers/net/phy/xpowers-acx00.h @@ -4,6 +4,8 @@ =20 #include =20 +#define AC300_EPHY_CONTROL_ADDR_OFFSET 16 + enum acx00_ephy_led { ACX00_EPHY_LED_LINK_ACTIVITY, ACX00_EPHY_LED_SPEED, --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f47.google.com (mail-ot1-f47.google.com [209.85.210.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA770395D8B for ; Mon, 3 Aug 2026 05:15:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734145; cv=none; b=cva7fhSbxXQF2ZxX8Uhzn+dz8gpdiLEvZyB1nArPU4ZMa0S8JdjenvCXOtQ6lfSYtOSabZT4dqGbJeB4rCeNqwT/m87UO6+w7JuflcaXng2WO4QajqICLLkRvRlt3UY8MYMG3UtDC0wXIoNqFhj4fXUwwFXHy7tVjaDqkL9kUQA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734145; c=relaxed/simple; bh=DTn/pnAwjoqAyUd80mDT7MV7oTEK5ffPq/Jme8VHnRg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cmpDHLYabXJXDnx3bcpQ55fsNHh+kTaq8Ov90oXREZXx18ko6Q/+S4uX+EksGnM9hljostSENheWNqNcOnaBqOFnJvBl9uj7hNERooSRchGakMS0wNXMPWXu3s0KlyGh41jDxphBe5nR/xrVofZSO98Low/VfmbGoBjlkBCfihY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=q316WcA8; arc=none smtp.client-ip=209.85.210.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="q316WcA8" Received: by mail-ot1-f47.google.com with SMTP id 46e09a7af769-7e9f69ee6f4so2714705a34.2 for ; Sun, 02 Aug 2026 22:15:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734142; x=1786338942; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Jidbxiox7dX03nOKASiwvW/wC69oSzUN52btxDpp97E=; b=q316WcA8v72PzRic2zxv8ou7FCtD9wInxSBdYdOeV3f15ICzn7mP/+kBrshXd2G6xC /Kd/ZvtEI93uFfwJBWUV4XNOa+3oRR03EwfBiDRvY0oKJ39MsoM6OOCKKJ6HxP9AzIQo SlExCbg54uJNaAev7l+bhplWdvA068IypIXRa0kTCVoGKB5T5DaHsXpO9PvwUIf85gJy YK/x/AFVSKnkSdGyOqRrKVpP6MNZCJRloICUsZ3lFsOYA3m/gecXwZTmPS7DbUkJ1xmD EdTBmKnq1NGVa1JixF8KiKFuomnkitGZ/7f62b43XW207T5lJJB996rTG2tLZFVjpgip GFEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734142; x=1786338942; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Jidbxiox7dX03nOKASiwvW/wC69oSzUN52btxDpp97E=; b=dEQxtUTcARx27tTdRj3/QpmKCK04vM9u08aKktScys2SviMdP1EyTnaPRPqaWuDEFK 5Vk9CzSCN/DOneQhUe2tj6zJ3DblJwqjF1xnUO1HDZqfTzd0Opfyvu/Jm76EgxylKxQR ngfHdPNm7GfqKWLv6wJf332PgkByYUxzFNg5Ao61LCtMZt4GCStmeHaeq8qC4kRP3avN LU9brp2Vrn0xvDlvQo5egR19t65+kclDo1HasqHBoxKBS6AWQRyiFSU7ro/0wWJV/dkE VM9vvroKJDY3SwPkrj/71ccvdTRvgNde9qVuhqYDeGCe4Z8TCmePtKVIOo2RrAavGMG3 2P5g== X-Forwarded-Encrypted: i=1; AHgh+RpLRWPvuuwdFryiukIxrqRlgHG22JkEekOeOSqLbF/xQxg3ob2iL9KugrhnFlnpfl2D4ZJVRp1UQxVuYRE=@vger.kernel.org X-Gm-Message-State: AOJu0YzS31S55EBHCQZ6ZrKKJNUKw7+fe1L2dmdD9bLosGmuhApAhPg7 QvaS/xZAcZGnot/BOcnN9dYjcwf/S5aeTGWQy/tUXhEerNOWA1nmwbjv X-Gm-Gg: AR+sD10YUVDR2Y7Gtw1SZ/0mElIY7NJilLcfVmLt+V9DwCp4kzgW5k9TnDDUQanoltJ WNYucRn59HHubMPuoYdCUJE+1XdmOsxYuFnKd3SDRdEhV6jQsBN4PMOdmCfZa2zlQ2iAohkrXbi L8euVneSoWnl/crarh4xl/L5Offgt+9sogzwTXBPIAjjyp/F7SDF0/syC9Akv2Mw9Qx1jdJ6OZa 1TXlVjgNV45cQ14jz1twiNFp+kbO9TzudzVDGYNBJdAnYZeeD8sYU5xb4IfE2qr4A38XYbAnZII 05pMfBoKGlwBZrXHIi+z15/YaT7HDJsX3IGxJHAyvXMUcTSMRq6EPMtuJmGr2B8lLxb7QEt8eZU PzeUWpVFcorYOKlOtEIKDV5+qiPszAxyHTkLD3Tdrd3gQsqtWtXnFqyIwnVIjPyfw6RndquvPnl unAz4rJ/6jCOC9Y+XtRFPDWt7eFK7TSszUiUv1K5uXfNI2rcJJb6MpyCbU9lZEIu6RcqeZ7lAJP WSjgGNUJqDnFmDF1hZl2ZPiKk9ck02yrhOrR6uHwXIfmg5PN7k4yEpMGWgemrc24Q08yFavb22E e7qgZmjls8j9wgiZLX9E9soOudhmh7MzWCHHHHDijUJtHFPXGEJtQ8h9ChkLBIhEYUleWN4gWe4 cK3EiycuDAOcawrGV X-Received: by 2002:a05:6830:411d:b0:7d9:f50f:9691 with SMTP id 46e09a7af769-7f1968c88e1mr15370101a34.0.1785734141726; Sun, 02 Aug 2026 22:15:41 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:40 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:23 -0600 Subject: [PATCH 13/21] dt-bindings: net: x-powers: add AC200/AC300 EPHY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-13-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 AC200 and AC300 companion ICs contain compatible Fast Ethernet link-PHY implementations which report the same PHY ID but use different control interfaces. Describe the forced-ID link PHY and its control-device references. Fixed systems reference one already enabled control interface. A fixed AC300 system may optionally provide the configuration field for its calibration-range bit; omitting it selects the normal range. Systems which can contain either companion reference both candidates and require a logical two-bit NVMEM field for variant selection and AC300 calibration- range tuning. The link node reg value is programmed through the AC200 control interface, while AC300 requires it to match the package-strapped address. A control reference is required to distinguish this integration from other PHYs which report the same ID. Also describe the optional xMII receive-clock inversion required by some integrations. Describe the three fixed-function package LED outputs using standard PHY LED children. Their functions are link/activity, 100 Mbps speed and duplex, and their polarity is shared. Omitting the container retains the vendor fallback with all outputs active-low; an explicit container enables only the outputs it describes and may select the shared polarity. Allow a PHY with a routed interrupt to be marked as a wakeup source for magic-packet and link-change Wake-on-LAN. Signed-off-by: James Hilliard --- .../bindings/net/x-powers,acx00-ephy.yaml | 217 +++++++++++++++++= ++++ 1 file changed, 217 insertions(+) diff --git a/Documentation/devicetree/bindings/net/x-powers,acx00-ephy.yaml= b/Documentation/devicetree/bindings/net/x-powers,acx00-ephy.yaml new file mode 100644 index 000000000000..3e01f6b44006 --- /dev/null +++ b/Documentation/devicetree/bindings/net/x-powers,acx00-ephy.yaml @@ -0,0 +1,217 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/x-powers,acx00-ephy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: X-Powers AC200 and AC300 Ethernet PHY + +maintainers: + - James Hilliard + +description: + The AC200 and AC300 contain compatible Fast Ethernet link-PHY + implementations which report the same PHY ID, but use different control + interfaces. Systems with a fixed companion IC describe one control + interface, which must already be enabled. A fixed AC300 system may provi= de + an NVMEM configuration field to select its calibration range; omitting t= he + field selects the normal range. Systems that can contain either companio= n IC + describe both control interfaces and require the field to select the + matching one before the PHY identification registers are accessible. In + that dual-control topology, the AC200 I2C controller and AC300 control + device may use status "fail-needs-probe" so the selected one can be enab= led + dynamically. The PHY node's reg value is programmed through the AC200 + control interface. For AC300, it must match the address selected by the + package straps. + +select: + properties: + compatible: + contains: + const: ethernet-phy-id0044.1400 + required: + - compatible + anyOf: + - required: + - x-powers,ac200-control + - required: + - x-powers,ac300-control + +properties: + compatible: + const: ethernet-phy-id0044.1400 + + nvmem-cells: + maxItems: 1 + description: + Logical SoC SID field whose bit 0 selects the AC300 control interfac= e in + a dual-control topology and whose bit 1 selects its low-calibration + tuning sequence. + + nvmem-cell-names: + description: + In a dual-control topology the configuration field uses bit 0 to sel= ect + AC200 (zero) or AC300 (one). Bit 1 selects the AC300 vendor sequence= for + a low-level calibration value in both dual and fixed AC300 topologie= s. + const: configuration + + x-powers,ac200-control: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AC200 Ethernet PHY control function + + x-powers,ac300-control: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AC300 MDIO Ethernet PHY control device + + x-powers,xmii-rx-clock-inverted: + type: boolean + description: + Invert the xMII receive clock inside the PHY. This is required by so= me + SoC integrations, including the Allwinner H6 AC200 connection. + + wakeup-source: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicates that the PHY interrupt is routed to a wake-capable interru= pt + controller and may be used for magic-packet or link-change Wake-on-L= AN. + + leds: + type: object + description: | + Package LED outputs. Output 0 indicates link and flashes for transmi= t or + receive activity, output 1 indicates a 100 Mbps link, and output 2 + indicates full duplex and flashes on a half-duplex collision. The + polarity setting is shared by all outputs, so active-high or active-= low + declarations on different children must agree. Without an leds + container, all three outputs are enabled active-low to match the ven= dor + initialization. An explicit container replaces that fallback: only + outputs described by available child nodes are enabled, with active-= low + used when no child specifies a polarity. + + properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + patternProperties: + '^led@[0-2]$': + type: object + $ref: /schemas/leds/common.yaml# + + properties: + reg: + enum: [0, 1, 2] + + inactive-high-impedance: false + + required: + - reg + + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + +oneOf: + - properties: + nvmem-cells: false + nvmem-cell-names: false + x-powers,ac300-control: false + required: + - x-powers,ac200-control + - properties: + x-powers,ac200-control: false + required: + - x-powers,ac300-control + - required: + - nvmem-cells + - nvmem-cell-names + - x-powers,ac200-control + - x-powers,ac300-control + +dependentRequired: + nvmem-cells: [ nvmem-cell-names ] + nvmem-cell-names: [ nvmem-cells ] + +allOf: + - $ref: ethernet-phy.yaml# + - if: + required: + - x-powers,ac300-control + then: + properties: + reg: + maximum: 7 + +unevaluatedProperties: false + +examples: + - | + #include + + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy@0 { + compatible =3D "ethernet-phy-id0044.1400"; + reg =3D <0>; + nvmem-cells =3D <&ephy_config>; + nvmem-cell-names =3D "configuration"; + x-powers,ac300-control =3D <&ac300_ephy_ctl>; + + leds { + #address-cells =3D <1>; + #size-cells =3D <0>; + + led@0 { + reg =3D <0>; + color =3D ; + function =3D LED_FUNCTION_LAN; + active-low; + default-state =3D "keep"; + }; + + led@1 { + reg =3D <1>; + color =3D ; + function =3D LED_FUNCTION_LAN; + function-enumerator =3D <1>; + active-low; + default-state =3D "keep"; + }; + }; + }; + }; + + - | + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy@0 { + compatible =3D "ethernet-phy-id0044.1400"; + reg =3D <0>; + x-powers,ac200-control =3D <&ac200_ephy_ctl>; + }; + }; + + - | + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy@0 { + compatible =3D "ethernet-phy-id0044.1400"; + reg =3D <0>; + nvmem-cells =3D <&ephy_config>; + nvmem-cell-names =3D "configuration"; + x-powers,ac200-control =3D <&ac200_ephy_ctl>; + x-powers,ac300-control =3D <&ac300_ephy_ctl>; + }; + }; +... --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f51.google.com (mail-ot1-f51.google.com [209.85.210.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF25939D6FD for ; Mon, 3 Aug 2026 05:15:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734147; cv=none; b=ZZz7vyxM3w+MUfm2VsBzD+u8Vv1My8Grt3cdjE0+MRuOTtI00Gz1yB7CCM3A4t8ZViU8ELYVrSZ3hAthiSMH2EsYWl97hc41qRGDDGm0drjmKNzfHNkxHnJYHdw6wFhTxhP2BJhvsiLyA3oizCglkDC9dEzQnSIE1L5oujViWL8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734147; c=relaxed/simple; bh=z1D09xijThRsRnsDX/ozKwmhi7sR7kyQDCuYiAXqUqg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YGkVLxubUw2TqM2Cw+wlHNTYFcYjI3zNxxXn97NG5AEvbzV64rntS+mAIc6HESnnf5f3e4hwSRcN+1HiKrJh9Au9wwGBGKk0Yj/ZVN7nY5+Svvr6T45JOLNor59A8VPscm7Bjlgm3+X7z1u49NIhYAMRGIeCD7/ZCerzEnfpJu8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=SY7X+RxD; arc=none smtp.client-ip=209.85.210.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="SY7X+RxD" Received: by mail-ot1-f51.google.com with SMTP id 46e09a7af769-7eb61bbeb25so2152012a34.1 for ; Sun, 02 Aug 2026 22:15:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734143; x=1786338943; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=S/5/uq1wl03WMsz5ualIqMKCury9OUeuYtebMNsXO2w=; b=SY7X+RxDKLHFH6BT0SgLRCAqP4C+ANphgxQFOP0bvcu2efhASBb3mDR0cj9lZ6KVkC EdzQL36GTA3zjACos8uxwlJxDMWQfqW35NMr5nUNYAm7aJGJQjUN4fXVOz4NLCdmQcW+ NHtzgl0gjtJXQxr4K1S5s4uJZWgMb2Aq+H0IgGwplvODnemZcA4Y9GJantlt9w93hUvP E0835B7x1R06ezVsPUeQLQrz2XCe500ULbe0RauTutn47hARQQ0b5ZF6ZuLQYSWCmK7t koPp022MxvB6AZcEoQT4a1NyHmno+Svxh1ZMkw2fRyh1qKPx8WL1/T7v60SbSpcdRoiO XSdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734143; x=1786338943; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=S/5/uq1wl03WMsz5ualIqMKCury9OUeuYtebMNsXO2w=; b=Ii1IbeknBSErVgOazkd5K3R2T2bdyDniI1T0U7PqdxJIL5IESshG4YyjX0GWLsWs/j i/h8cgRYxJml845OT+0T4t2Tl06QjxfzTetZ1ofBYI4WQV5jtbqT9da6IWDsuhjrg+vY DaA567ZbbNjaIAOLQAlW/voV9EmXOj/UAB5M8rDyuqWJVkOZQ1npIakVTA6nKP399fYQ vSwwnpy4XK1T0PF0leIb2v9tG0MK9sYhDYPN8eL/NVwJgDOgVDJ4+wyJyz1+Kuvtllww W4f05KEChM5oFfX2GkxkWosqPntDiXhqf2vRAIxcFJEuAgWXrgGhnW7jd5QpqiV28v2q M6sw== X-Forwarded-Encrypted: i=1; AHgh+RrHkXI7Ab5syN7CJ8QuHxdPTbFMHvki9nHjNItB8UJV+FHKdhLYM376HRsfqzyNi4KCEKXzi48Kbkqfn2E=@vger.kernel.org X-Gm-Message-State: AOJu0YzkPiDdcsecZJEGXZMIMNzBsMEQSwe0MB/PH4VLF7cdD+KDbMsH 6WFZJFqQEFflNweol2F6hqnh00hkd67QaJ2OlPetX4WnOBajbJ7EZprR X-Gm-Gg: AR+sD12fZkL0NGze/XHExpFj6r31KP+Q3EcLFQzViToUM714mX8TqrUPz26O46R34sJ gAV/cRsyjkc3ywxrjO2+N6/EGrYON2IUGxE0PM+PHnpObJnKcd+41fZIZBzfBYl/KePCXRzuffR g6EmA2hlk+2vgq16hYYsMbmdXCtRS3yP2eLlE4UjjRrxCp7K7XjLW6tlmewAUGB1K3mOoyqcY49 bxp9Z4hsIgKmcNWXvh9D3iT0yUa4vAVR7lGZEjNwSbmw/zLD5XgQpB2vksgxHmAAxgb7oVP8pGA WE/O0XExKeFfo0WrkbKaUwkLyAuQF942N854IUXi41ogJo2hNipAIEUH+D5Xk05b4rbDh1C1Dtv cS30zzyTg98CtnUoz6Zh50ECwVtAm1FlGfKBgwHucKxbqwtzMJFyAgYNB0NzJ71Yv25VIdFYCq+ ov09xs5hc8EO6OB76CqwRzJq/awLW6Kbu38GVtwe9+ZV2EMRZTGerQ9iU2LIZ6XnSIIM90xKeki HCn9MTKUAPTL9dkKQUYXOUoCEAGjK0G1G/+dGOBvgW5KEsiENsS/JCdrMX4Pg8nD273oMrhCZhf fNxQP5dKxOM3UZpbfO7K2U/ksntmw+7yM4wJpBcgSUO2jsHTX7+CC8poe1/NktcgVGRfEucHTK3 8wLqPoGqrQ+cCYv6X X-Received: by 2002:a05:6830:4114:b0:7e9:bd00:c6ad with SMTP id 46e09a7af769-7f196f29291mr14805744a34.16.1785734143562; Sun, 02 Aug 2026 22:15:43 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:42 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:24 -0600 Subject: [PATCH 14/21] net: phy: support configuring PHY-autonomous Tx LPI Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-14-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The ethtool Tx LPI fields currently update phylib software state and notify an attached MAC, but they do not configure PHYs which generate LPI autonomously. This can make a successful ethtool request leave the PHY hardware unchanged. Add a PHY driver callback for applying the Tx LPI enable state and timer. Call it before updating EEE advertisement, and attempt to restore the old hardware state if either the callback itself or the advertisement update fails. Use the callback to disable autonomous LPI when phy_support_eee() hands LPI control to the MAC, and reapply that state after PHY reset. Drivers without the new callback retain the existing behavior in which the Tx LPI fields configure phylib and the attached MAC. Existing drivers which only implement disable_autonomous_eee() therefore need no changes. Signed-off-by: James Hilliard --- drivers/net/phy/phy.c | 35 +++++++++++++++++++++++++++++++++-- drivers/net/phy/phy_device.c | 25 ++++++++++++++++++++----- include/linux/phy.h | 18 ++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index fce9bc7be330..c76d5baa1f84 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1996,6 +1996,8 @@ static void phy_ethtool_set_eee_noneg(struct phy_devi= ce *phydev, int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *da= ta) { struct eee_config old_cfg; + bool tx_lpi_cfg_attempted =3D false; + bool tx_lpi_cfg_changed; int ret; =20 if (!phydev->drv) @@ -2005,16 +2007,45 @@ int phy_ethtool_set_eee(struct phy_device *phydev, = struct ethtool_keee *data) =20 old_cfg =3D phydev->eee_cfg; eee_to_eeecfg(&phydev->eee_cfg, data); + tx_lpi_cfg_changed =3D phydev->eee_cfg.tx_lpi_enabled !=3D + old_cfg.tx_lpi_enabled || + phydev->eee_cfg.tx_lpi_timer !=3D + old_cfg.tx_lpi_timer; + + if (tx_lpi_cfg_changed && !phydev->autonomous_eee_disabled && + phydev->drv->set_tx_lpi) { + ret =3D phydev->drv->set_tx_lpi(phydev, &phydev->eee_cfg); + tx_lpi_cfg_attempted =3D true; + if (ret) + goto restore_tx_lpi; + } =20 ret =3D genphy_c45_ethtool_set_eee(phydev, data); if (ret =3D=3D 0) phy_ethtool_set_eee_noneg(phydev, &old_cfg); else if (ret < 0) - phydev->eee_cfg =3D old_cfg; + goto restore_tx_lpi; =20 mutex_unlock(&phydev->lock); =20 - return ret < 0 ? ret : 0; + return 0; + +restore_tx_lpi: + if (tx_lpi_cfg_attempted) { + int rollback_ret; + + rollback_ret =3D phydev->drv->set_tx_lpi(phydev, &old_cfg); + if (rollback_ret) + phydev_warn(phydev, + "Failed to restore autonomous Tx LPI: %pe\n", + ERR_PTR(rollback_ret)); + } + + phydev->eee_cfg =3D old_cfg; + + mutex_unlock(&phydev->lock); + + return ret; } EXPORT_SYMBOL(phy_ethtool_set_eee); =20 diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index f7472a743185..30929b0354b6 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1357,6 +1357,21 @@ static int phy_poll_reset(struct phy_device *phydev) return 0; } =20 +static int phy_disable_autonomous_tx_lpi(struct phy_device *phydev) +{ + struct eee_config config =3D phydev->eee_cfg; + + if (phydev->drv->set_tx_lpi) { + config.tx_lpi_enabled =3D false; + return phydev->drv->set_tx_lpi(phydev, &config); + } + + if (phydev->drv->disable_autonomous_eee) + return phydev->drv->disable_autonomous_eee(phydev); + + return 0; +} + int phy_init_hw(struct phy_device *phydev) { int ret =3D 0; @@ -1395,9 +1410,8 @@ int phy_init_hw(struct phy_device *phydev) } =20 /* Re-apply autonomous EEE disable after soft reset */ - if (phydev->autonomous_eee_disabled && - phydev->drv->disable_autonomous_eee) { - ret =3D phydev->drv->disable_autonomous_eee(phydev); + if (phydev->autonomous_eee_disabled) { + ret =3D phy_disable_autonomous_tx_lpi(phydev); if (ret) return ret; } @@ -2973,8 +2987,9 @@ void phy_support_eee(struct phy_device *phydev) * manage LPI signaling instead. The flag is stored so it can be * re-applied after a PHY soft reset (e.g. suspend/resume). */ - if (phydev->drv && phydev->drv->disable_autonomous_eee) { - int ret =3D phydev->drv->disable_autonomous_eee(phydev); + if (phydev->drv && (phydev->drv->set_tx_lpi || + phydev->drv->disable_autonomous_eee)) { + int ret =3D phy_disable_autonomous_tx_lpi(phydev); =20 if (ret) phydev_warn(phydev, "Failed to disable autonomous EEE: %pe\n", diff --git a/include/linux/phy.h b/include/linux/phy.h index 2eba54e068f6..55053b914144 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1391,6 +1391,24 @@ struct phy_driver { */ int (*disable_autonomous_eee)(struct phy_device *dev); =20 + /** + * @set_tx_lpi: Configure PHY-autonomous Tx LPI + * @dev: PHY device to configure + * @config: Requested Tx LPI enable state and idle timer + * + * The presence of this callback advertises that the driver supports + * configuring PHY-autonomous LPI through the ethtool EEE Tx LPI fields. + * It is not used for userspace configuration after phylib has handed LPI + * control to the MAC. Drivers without this callback retain the legacy + * behavior in which those fields only configure phylib and the attached + * MAC. A request with Tx LPI disabled must be accepted regardless of the + * timer, since the timer has no meaning while the transmitter is disable= d. + * + * Return: 0 on success, negative errno on failure. + */ + int (*set_tx_lpi)(struct phy_device *dev, + const struct eee_config *config); + /* Get and Set PHY tunables */ /** @get_tunable: Return the value of a tunable */ int (*get_tunable)(struct phy_device *dev, --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f52.google.com (mail-ot1-f52.google.com [209.85.210.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 629463A0E80 for ; Mon, 3 Aug 2026 05:15:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734154; cv=none; b=RlIgdPU90/6fM/NTxKnHhT0TxiYKdEFkoj7kai9R90q5dZaL8A6ctSZ457WaqjBR0y0wRwtK6fgu1sdCcmY2HxUFXm2FxKn1UEIrNLS7pejIjG2XbRokkPeB5GAdXAuxIKFJCaUb8segqIKaK7+uUXpu/kjOD3tnJCXru9kjuIY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734154; c=relaxed/simple; bh=okw70boujGKEoFWervTiqut+PCDZlczcehiMArR7er0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BNFF6nlCalKLFuVTmFKsT4vcPzbkf191D7VK5A8ickQRrbefO642qhOM+hoSMRqcnJ7IRewHNj25qK/xlxl1ImUq7Pi2QSnMAlDDhkWvbuddIC/epLzWKuBeuQxO/ziVHqt3lGpYMiBJ21lclWVTeS7Gf0L70ndlnkPOn909Agg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ZTx93BX8; arc=none smtp.client-ip=209.85.210.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZTx93BX8" Received: by mail-ot1-f52.google.com with SMTP id 46e09a7af769-7eb68bdf53aso1091852a34.3 for ; Sun, 02 Aug 2026 22:15:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734150; x=1786338950; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=GBn8+Hx956XQS2N8rfelEGrUn9IDXjKs/rR491vlUQk=; b=ZTx93BX8A3VUz+c5B7f6Ob5nj9meWWc2UAGhzp35b3ZuUz5RzB2PxQViuHHCiFjtGF CrX9f9i5/iHsiGT6v3RVMxjN+hBSaMCkcUX+tH+WSnjFVfhYblnnfqkZfrVj/13J4DCX z8nZpTft6VuP0M5cvF3q2dsCyYuSHHGQem1QzoNLyRfpBUmB6esuY6vbpjPUvaxkuneg NHokaddfoUBojW8C8vF+lmW/vFfaLcQfeQjnnRh3tyWTwQn+SiZDKNORWF7Q76hJ6zlp ov0Eur+sGya4VcB6OKQVBjhpdWNeknPRk6ReNUUg3zgJ/ou+d4vV6nZrThBpm/gTjvB2 V4lQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734150; x=1786338950; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=GBn8+Hx956XQS2N8rfelEGrUn9IDXjKs/rR491vlUQk=; b=g4Ntpi9ZjBktuXa3CFvqh0KFH6KDd87ySBacniAoGkDIq2azTaDVaH2/VR2wIVPmbN 00V+V5hNp4mGsZZDVyLyLQ5VlmQ8Qa9xoWlA94eniXx5qb3rFkA9MmvZbFQ5p843k+T6 eU/qHmP7to5g5rwiJF6/3CqVUIvACEdZxuJIJ5AoO44xGC289Ixb8wsfHPRJlqERLmkc Y9KvNhxRIO38Rv9zBiS9N7Kz7uD1VlUSsAE1zJQLqo+05JY0MAXO1gts0pHQMy3pD4FH KUdp3hgV5j4AmbzraW8Z2qReOhb+J0mlUyVo3xRpEDtZ4s9Op6sH3+ulnsY3OH+5sPp8 M5KQ== X-Forwarded-Encrypted: i=1; AHgh+RpfGDvoUMVm+oOeh7gGkWlZSxKx9sgSIjj4/Sv5KUyO4eTa1tDZFzJgT1SfnEI/x9hoD5pXT/S6XzHca+I=@vger.kernel.org X-Gm-Message-State: AOJu0YzgH/vAAFNcptpMLMWp/KJGxUiG/65D/6PzdtfGaEHBi0Kbm3KU wim0nprBa32ApaNDf8e14cTb+/Cu4duYxsFC6JVZzzPgIUfaIoNmT79G X-Gm-Gg: AR+sD135TJb/5iDgz2S3QwsE/c72W+uTbZlhiNtDzlW/mCntcEHbD3p9RNceWWo9cLa bfCibXEuzZDZBMFeSnTh1iid6TABe5g8UCJwjKl5dwAnPmtXW/G6jwFD0R35jbEWoyeAAJ9joOr tPIuG1trQlpEGe11aNiFP0luSdj5cyl/YtwfxktQtO6YdaFuhrDelS3FmpIEnI2knU809Ea5cDC BNElpP7WWUU77mdSphSHVcaI6DfwhIcRWKn048hAbhhwfzRX3Lx6BA8OmbeCqf7K6lef5jFtghg RWtD477I3NvpQIxUevey1Jumy6QVXLdfPH+/YPWofoGh1GFtuLJ86PCFyt5R3Jsf46BB3jSFV2Z +Ckq7cQqfFgCPjfNdukSLS2Uz8yTYbjr/tvpBL0Fe4x/e/32yHEDxqZNDYvxk34SFC/AYOFaspb IgjdTemFdNtM5UG3tp1KrWoyc+2hDvOhAZLd96MJ9OXSGT8BAe6mkwvks3NFpl6n05Qef7Q7gFD Z5Oo0OSM9NL2Lgi7D5hgzE4bLqDJ/CETeMYNA/Z4750cN8RPUMvfOe9dbuHoYa3CcjvY5FCwBnI oSuGQ9MFmYSPyTi/l/ptlxMFEQCz53nM8/hG56ptDw9M5lhUvqGzI7czN1b2pDjqQsU7jRSDppN MR5SGzgdIe/O6B9O1rw== X-Received: by 2002:a05:6830:f95:b0:7dc:4947:36a1 with SMTP id 46e09a7af769-7f19714f993mr12573380a34.12.1785734145466; Sun, 02 Aug 2026 22:15:45 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:44 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:25 -0600 Subject: [PATCH 15/21] net: phylink: allow PHY-autonomous EEE without MAC LPI Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-15-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 Phylink treats a MAC which implements its LPI operations but advertises no LPI capability as incapable of EEE. It disables PHY EEE during attach and rejects ethtool EEE requests. The same problem occurs when the MAC supports LPI on another interface but not on the interface currently connected to the PHY. Both cases are incorrect when the attached PHY can generate LPI autonomously without help from the MAC. Recognize the PHY autonomous-EEE capability, preserve its EEE advertisement, and allow ethtool EEE requests in that configuration. Evaluate MAC LPI support for the active interface, and restrict EEE modes to the MAC capability mask only when the MAC actually manages LPI. Signed-off-by: James Hilliard --- drivers/net/phy/phylink.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 18d2ead97aa5..e64f72793aa0 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1512,6 +1512,19 @@ static void phylink_deactivate_lpi(struct phylink *p= l) } } =20 +static bool phylink_phy_supports_autonomous_eee(struct phy_device *phy) +{ + return phy && phy->drv && phy->drv->set_tx_lpi; +} + +static bool +phylink_mac_supports_eee_interface(struct phylink *pl, + phy_interface_t interface) +{ + return pl->mac_supports_eee && + test_bit(interface, pl->config->lpi_interfaces); +} + static void phylink_activate_lpi(struct phylink *pl) { int err; @@ -2090,6 +2103,7 @@ static int phylink_bringup_phy(struct phylink *pl, st= ruct phy_device *phy, { struct phylink_link_state config; __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); + bool mac_eee; char *irq_str; int ret; =20 @@ -2106,6 +2120,7 @@ static int phylink_bringup_phy(struct phylink *pl, st= ruct phy_device *phy, linkmode_copy(supported, phy->supported); linkmode_copy(config.advertising, phy->advertising); config.interface =3D interface; + mac_eee =3D phylink_mac_supports_eee_interface(pl, interface); =20 ret =3D phylink_validate_phy(pl, phy, supported, &config); if (ret) { @@ -2144,7 +2159,7 @@ static int phylink_bringup_phy(struct phylink *pl, st= ruct phy_device *phy, /* If the MAC supports phylink managed EEE, restrict the EEE * advertisement according to the MAC's LPI capabilities. */ - if (pl->mac_supports_eee) { + if (mac_eee) { /* If EEE is enabled, then we need to call phy_support_eee() * to ensure that the advertising mask is appropriately set. * This also enables EEE at the PHY. @@ -2165,7 +2180,8 @@ static int phylink_bringup_phy(struct phylink *pl, st= ruct phy_device *phy, */ linkmode_and(phy->advertising_eee, phy->advertising_eee, pl->supported_lpi); - } else if (pl->mac_supports_eee_ops) { + } else if (pl->mac_supports_eee_ops && + !phylink_phy_supports_autonomous_eee(phy)) { /* MAC supports phylink EEE, but wants EEE always disabled. */ phy_disable_eee(phy); } @@ -3300,17 +3316,20 @@ EXPORT_SYMBOL_GPL(phylink_get_eee_err); */ int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_keee *eee) { + bool mac_eee; int ret =3D -EOPNOTSUPP; =20 ASSERT_RTNL(); + mac_eee =3D phylink_mac_supports_eee_interface(pl, pl->cur_interface); =20 - if (pl->mac_supports_eee_ops && !pl->mac_supports_eee) + if (pl->mac_supports_eee_ops && !mac_eee && + !phylink_phy_supports_autonomous_eee(pl->phydev)) return ret; =20 if (pl->phydev) { ret =3D phy_ethtool_get_eee(pl->phydev, eee); /* Restrict supported linkmode mask */ - if (ret =3D=3D 0 && pl->mac_supports_eee_ops) + if (ret =3D=3D 0 && mac_eee) linkmode_and(eee->supported, eee->supported, pl->supported_lpi); } @@ -3326,10 +3345,11 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee); */ int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_keee *eee) { - bool mac_eee =3D pl->mac_supports_eee; + bool mac_eee; int ret =3D -EOPNOTSUPP; =20 ASSERT_RTNL(); + mac_eee =3D phylink_mac_supports_eee_interface(pl, pl->cur_interface); =20 phylink_dbg(pl, "mac %s phylink EEE%s, adv %*pbl, LPI%s timer %uus\n", mac_eee ? "supports" : "does not support", @@ -3337,12 +3357,13 @@ int phylink_ethtool_set_eee(struct phylink *pl, str= uct ethtool_keee *eee) __ETHTOOL_LINK_MODE_MASK_NBITS, eee->advertised, eee->tx_lpi_enabled ? " enabled" : "", eee->tx_lpi_timer); =20 - if (pl->mac_supports_eee_ops && !mac_eee) + if (pl->mac_supports_eee_ops && !mac_eee && + !phylink_phy_supports_autonomous_eee(pl->phydev)) return ret; =20 if (pl->phydev) { /* Restrict advertisement mask */ - if (pl->mac_supports_eee_ops) + if (mac_eee) linkmode_and(eee->advertised, eee->advertised, pl->supported_lpi); ret =3D phy_ethtool_set_eee(pl->phydev, eee); --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f48.google.com (mail-ot1-f48.google.com [209.85.210.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA8143A5E6F for ; Mon, 3 Aug 2026 05:15:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734154; cv=none; b=cawkJGP8z6h+48tARiYBZ4uz/TCyFrvPhVrj/u6Xtl1A+rB2VlRxyTX9fPNiWdom9dx5EvKsZ2/n4vuVLHc4ycUgPxlwen0/QJdBzBOemVYWBIJuXNVucnkzzbbfstPk52BTe06UxFDgrkDp4wqRmOpHpEAdKY2nwrsru6LIBwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734154; c=relaxed/simple; bh=bnher73HZdEx/bFsEwg8sn4H6jH4c9JplUY8GfqkPZg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Sj8TQKmsOeQo9lZwgna6rc6PRLksO0+yjoExiuSdor8/ty2UveAfAC0P9p3zb2zi/9Bm58GEC4ZvrNN8+SvVpgVYI9qz7XyFPie/C1hO/AY2EyZu1j1hymePGRlmXEMp1k3XiLbsEngfqAVcYdhD8WqXyAj8Ho+xlm+4ARGXpIE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=sCu8vImI; arc=none smtp.client-ip=209.85.210.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="sCu8vImI" Received: by mail-ot1-f48.google.com with SMTP id 46e09a7af769-7eb1dc6bd53so1828695a34.2 for ; Sun, 02 Aug 2026 22:15:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734149; x=1786338949; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=9HocqQSvZ/shIczHi/ecOhIrdfwufvBQyfBRX301nvk=; b=sCu8vImIvIpNu49zfKYME3fSyBoMx2q51tMk47JoRGbPhE5B7GsXYdkIBGIIY4NeCT hfdOH9EO/p+ospdMic+dcKD7QR6Dsb9jJ30m3e/Y2Dlfmier5XOBR9aZJLFs+ptJ95FQ h0UulEi2n37RAyjp6e+uIr5RFdXj6JdQk0Io/8Ubs2ROtdieB6Dz/4DuMygVfRYSS9Uo TFJCxkq/sHu/H638Wcu6UGTqqeK5y68l0cMDJqQgb4M1QukNkRsPruzGATeo1UT3UQTN JRXT7Q+7tyr/QWpcSyyY/VvQm/a7mi96qdNEKMgOulVOjwpAgYQOnh5voc0G1tPJuKPI 9Aiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734149; x=1786338949; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=9HocqQSvZ/shIczHi/ecOhIrdfwufvBQyfBRX301nvk=; b=OCEpnuH1O0zh0uGxCKyuImEWTzYAfxAai/WxVb8yBRgtIfAPrAP09YENC/sFzPNR3B wcxkSiL1C9EGbshYe/vrY4uG4T7Tq3HE7kMS4qPCHWNZX02kutiWD2m972dk60iwGXZm 9w/2eP1dTh1aV4K8xb5wZqsXDqbwM0jQzVL40vUHmW6p+JUxfq7ELwvxCXslz35cbEDh RJfdF7eRuZI0k0nG8pp3vB/a+K6NoLJjF8h49irBHvs3b03UOPAlQ6WeYVaprenpO5VV XIXx3C6SKXOf16WVaiTIov7dXUWw3S40zQyT+WmNXSsnS4qjGEcya7JIDCmerZay+0GC OEaQ== X-Forwarded-Encrypted: i=1; AHgh+RrjV7R1KF1hC+SGirwCFTsvsfWUslA7t1aNIoSjO4VE/XbKUSdsDMZj3KnDuAnA2Gr90Ic10awdZMehIEc=@vger.kernel.org X-Gm-Message-State: AOJu0Yx3CVAD3QhOMI2VOsANugF+wUUgDwp1qit2lCw/R1ishoDdUidY jmRENFsl8KOQD0T5L4ClQFYX0Di8VakaE0s4T2afzB4FztJn7j7r3G6d X-Gm-Gg: AR+sD11HGaqZkD3gbIB+57lDkoELhEDE3bMwe+6ThZJIEtD35CTmM8wx34bhPhfXQXO dXutqeEW+jSoZ1y6OX6qzX5dlidS9EnGYdNDQ2boF0ceedaxQX9CpGR2Jr8GQlPjNpRvqWbtIXW rI9C16Y8KP1CGOhtR2wgY7AAXrFqTpiXdJRR9h87ZnjJg71xQU2qg5DXkAuKH5VxusY7zDoXk10 83F/4WcSkIUP12cwRLmSSdAyZ46xNuiTasF3yUGbcIX5suaNurFzyjcSFOkg4fUIhAPv7qCeFn8 vtZ1rs3fkMvAS1bfa+MdLJXUlDyqI3EUH+0lSBvSQVg/ph2/7Fiw03/5kwDrOG0TIvXdVcArN2J URv6VMLaiE+Zs3pH1YOhPIwse5Mlg9dhCaHPJAWDdI5cHQBhVLyNoVxktzjycfOPMtsWeLE+3ul gMaefJi+Ez7myFb0RV3v+Lh7bgpse8uzlFntL8EcwaoY0TfgocqEAjEsyjcqoW56C3h2FYUQrxQ qsykZydvj0yzJqHO7UPj+W6rrdX9jVpBDkL/qGHm2eEYFw0QSQ4cUrWHZmnPVNeT8nX7WWLLQWn h8H7PE3RTCy2+ulk7iAzqPvVfx9m/rt0gSgq02XMqKAqKLP7NxI/ThQH+AzSCmIca5vRqh3NH66 geMUzHwHvZWA2ilwCAbAKbWGlnA== X-Received: by 2002:a05:6830:3155:b0:7e6:eb9c:3781 with SMTP id 46e09a7af769-7f19701bb7dmr14624186a34.12.1785734147064; Sun, 02 Aug 2026 22:15:47 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:46 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:26 -0600 Subject: [PATCH 16/21] net: phy: add X-Powers AC200/AC300 EPHY driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-16-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 AC200 and AC300 contain compatible Fast Ethernet link-PHY implementations which report the same ID, but their identification registers are not accessible until the companion-specific control interface completes its power-up sequence. Match the ID supplied by firmware and require an X-Powers control reference because the Rockchip RK630 PHY reports the same ID. On fixed hardware, reference one already enabled control device. A fixed AC300 system may optionally read the configuration field for calibration- range tuning; its absence selects the normal range. On systems which may contain either companion, require a logical two-bit NVMEM field to select the control interface and the AC300 calibration range. Enable a selected fail-needs-probe node when CONFIG_OF_DYNAMIC is available; otherwise the same topology works when both candidate providers are already enabled. Validate that each phandle references the expected control-device type and restore the selector's status changeset if dynamic device creation fails. Keep a device link to the selected provider and defer until its driver binds. Verify that the MAC interface agrees with the provider's phy-mode before resetting the hardware. Power the control block before each PHY reset, shut it down during PHY suspend, and restore the vendor configuration after resume. If control power-off fails during suspend, attempt to power the PHY back on and restore its link configuration before returning the error. Pass the link address to the AC200 provider for EPHY_CTL.PHY_ADDR programming; the AC300 provider instead validates its package-strapped address relationship. Apply the common vendor analog initialization and SID-derived tuning while preserving unrelated register fields. Support a board-selected xMII receive-clock inversion and report and configure forced or automatic MDI/MDI-X state. Expose UAPS through the ethtool energy-detect power-down tunable as its no-transmit mode. Accumulate the hardware receive-byte, receive-packet and receive-CRC-error counters across PHY resets, expose all three as driver statistics and map CRC errors to the standardized PHY receive-error counter. Treat counter snapshots as best-effort telemetry so a read failure cannot prevent PHY recovery. Start both standard EEE advertisement and the PHY-autonomous Intelligent EEE transmitter disabled, matching the vendor configuration. Preserve the supported modes so ethtool can enable and configure both at runtime. The PHY has no documented programmable LPI timer, so reject a nonzero timer when enabling Tx LPI while accepting any timer value when disabling it. Clear BMCR_PDOWN before soft reset because ACx00 can acknowledge reset while powered down without restarting its link logic. Use the shared PHY interrupt for link changes when firmware provides one; otherwise retain the normal phylib polling fallback. On wakeup-source systems with a routed interrupt, expose magic-packet and link-change Wake-on-LAN, program the detector MAC address for magic wake, and arm the nested IRQ as a wake source. Keep the PHY powered while either PHY or MAC Wake-on-LAN is active. During suspend, leave only requested PHY wake events unmasked, then restore normal link monitoring on resume. Do not advertise either wake mode in polling mode because the CPU cannot poll while suspended. Register standard PHY LEDs for the described package outputs and expose their fixed link/activity, 100 Mbps speed and duplex rules to the netdev trigger. Use the vendor fallback of all three outputs active-low when no LED topology is provided; otherwise apply the described output set and shared polarity. Quiesce the provider if PHY probing or removal tears down the link device. Signed-off-by: James Hilliard --- drivers/net/phy/Kconfig | 12 + drivers/net/phy/Makefile | 1 + drivers/net/phy/xpowers-acx00.c | 1457 +++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 1470 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 9b202072d5a0..e3796a2b7be4 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -487,6 +487,18 @@ config XPOWERS_AC300_PHY_CTL interface mode, clock and I/O controls through the separate MDIO control address. =20 +config XPOWERS_ACX00_PHY + tristate "X-Powers AC200/AC300 Ethernet PHY" + depends on OF_MDIO + help + Enable the Fast Ethernet PHY driver shared by the X-Powers AC200 + and AC300 companion ICs. This driver configures the common link PHY + and can select the matching control device at runtime on systems which + contain either variant. Runtime variant detection requires NVMEM + support. Dynamically enabling a control device which is not already + available requires OF_DYNAMIC support. Fixed-function package LED + outputs can be exposed through the PHY LED framework. + config XILINX_GMII2RGMII tristate "Xilinx GMII2RGMII converter driver" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 2d22d5a4c93d..c4b17e1965aa 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -101,4 +101,5 @@ obj-$(CONFIG_TERANETICS_PHY) +=3D teranetics.o obj-$(CONFIG_VITESSE_PHY) +=3D vitesse.o obj-$(CONFIG_XPOWERS_AC200_PHY_CTL) +=3D xpowers-ac200-ctl.o obj-$(CONFIG_XPOWERS_AC300_PHY_CTL) +=3D xpowers-ac300-ctl.o +obj-$(CONFIG_XPOWERS_ACX00_PHY) +=3D xpowers-acx00.o obj-$(CONFIG_XILINX_GMII2RGMII) +=3D xilinx_gmii2rgmii.o diff --git a/drivers/net/phy/xpowers-acx00.c b/drivers/net/phy/xpowers-acx0= 0.c new file mode 100644 index 000000000000..98d0ee3937ef --- /dev/null +++ b/drivers/net/phy/xpowers-acx00.c @@ -0,0 +1,1457 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * X-Powers AC200/AC300 Ethernet PHY driver + * + * Copyright (C) 2026 James Hilliard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xpowers-acx00.h" + +#define ACX00_EPHY_ID 0x00441400 + +#define ACX00_EPHY_CONFIG_VARIANT_AC300 BIT(0) +#define ACX00_EPHY_CONFIG_CALIBRATION_LOW BIT(1) + +#define ACX00_PAGE_SELECT_REG 0x1f +#define ACX00_PAGE_SELECT_MASK GENMASK(12, 8) +#define ACX00_PAGE_0 0 +#define ACX00_PAGE_1 1 +#define ACX00_PAGE_2 2 +#define ACX00_PAGE_6 6 +#define ACX00_PAGE_8 8 +#define ACX00_PAGE_9 9 + +#define ACX00_PAGE0_INTERRUPT_STATUS_REG 0x10 +#define ACX00_PAGE0_INTERRUPT_MASK_REG 0x11 +#define ACX00_PAGE0_INTERRUPT_LINK_CHANGE BIT(15) +#define ACX00_PAGE0_INTERRUPT_MAGIC_PACKET BIT(14) +#define ACX00_PAGE0_INTERRUPT_MANAGED_EVENTS \ + (ACX00_PAGE0_INTERRUPT_LINK_CHANGE | \ + ACX00_PAGE0_INTERRUPT_MAGIC_PACKET) +#define ACX00_PAGE0_GLOBAL_CONFIG_REG 0x13 +#define ACX00_PAGE0_XMII_RX_CLOCK_INVERT BIT(12) +#define ACX00_PAGE0_MAGIC_PACKET_WAKE_ENABLE BIT(10) +#define ACX00_PAGE0_MAGIC_PACKET_BROADCAST_ENABLE BIT(8) +#define ACX00_PAGE0_MAGIC_PACKET_PASSWORD_ENABLE BIT(7) +#define ACX00_PAGE0_MDI_MODE_MASK GENMASK(1, 0) +#define ACX00_PAGE0_MDI_MODE_MDI 0 +#define ACX00_PAGE0_MDI_MODE_MDIX 1 +#define ACX00_PAGE0_MDI_MODE_AUTO 2 +#define ACX00_PAGE0_STATUS_REG 0x19 +#define ACX00_PAGE0_STATUS_MDIX BIT(7) +#define ACX00_PAGE0_MAGIC_PACKET_MAC_REG(_index) (0x16 + (_index)) + +#define ACX00_PAGE1_APS_CONTROL_REG 0x12 +#define ACX00_PAGE1_APS_DISABLED_4S_VALUE 0x4824 +#define ACX00_PAGE1_UAPS_CONTROL_REG 0x13 +#define ACX00_PAGE1_UAPS_ENABLE BIT(15) +#define ACX00_PAGE1_INTELLIGENT_EEE_CONTROL_REG 0x17 +#define ACX00_PAGE1_INTELLIGENT_EEE_ENABLE BIT(3) + +#define ACX00_PAGE2_TX_DATA_CONTROL_REG 0x18 +#define ACX00_PAGE2_10BT_FIR_SELECT_MASK GENMASK(14, 12) +#define ACX00_PAGE2_10BT_FIR_SELECT_DEFAULT 0 + +#define ACX00_PAGE6_ADC_CONTROL_REG 0x10 +#define ACX00_PAGE6_ADC_CONTROL_LOW_CAL_VALUE 0x5523 +#define ACX00_PAGE6_AFE_RX_CONTROL_REG 0x13 +#define ACX00_PAGE6_AFE_RX_CONTROL_VALUE 0xf000 +#define ACX00_PAGE6_AFE_EQ_RX_DETECT_CONTROL_REG 0x14 +#define ACX00_PAGE6_AFE_EQ_RX_DETECT_VALUE 0x708b +#define ACX00_PAGE6_AFE_EQ_RX_DETECT_LOW_CAL_VALUE 0x7809 +#define ACX00_PAGE6_TX_LEVEL_REG 0x15 +#define ACX00_PAGE6_TX_LEVEL_100M_MASK GENMASK(15, 8) +#define ACX00_PAGE6_TX_LEVEL_10M_MASK GENMASK(7, 0) +#define ACX00_PAGE6_TX_LEVEL_VALUE(_100m, _10m) \ + (FIELD_PREP(ACX00_PAGE6_TX_LEVEL_100M_MASK, (_100m)) | \ + FIELD_PREP(ACX00_PAGE6_TX_LEVEL_10M_MASK, (_10m))) +#define ACX00_PAGE6_TX_LEVEL_100M_DEFAULT 0x15 +#define ACX00_PAGE6_TX_LEVEL_10M_DEFAULT 0x30 +#define ACX00_PAGE6_TX_LEVEL_100M_LOW_CAL 0x35 +#define ACX00_PAGE6_TX_LEVEL_10M_LOW_CAL 0x33 +#define ACX00_PAGE6_TX_LEVEL_DEFAULT_VALUE \ + ACX00_PAGE6_TX_LEVEL_VALUE(ACX00_PAGE6_TX_LEVEL_100M_DEFAULT, \ + ACX00_PAGE6_TX_LEVEL_10M_DEFAULT) +#define ACX00_PAGE6_TX_LEVEL_LOW_CAL_VALUE \ + ACX00_PAGE6_TX_LEVEL_VALUE(ACX00_PAGE6_TX_LEVEL_100M_LOW_CAL, \ + ACX00_PAGE6_TX_LEVEL_10M_LOW_CAL) + +#define ACX00_PAGE8_AFE_CONTROL_REG 0x18 +#define ACX00_PAGE8_AFE_CONTROL_VALUE 0x00bc +#define ACX00_PAGE8_AUTO_CAL_CONTROL_REG 0x1d +#define ACX00_PAGE8_AUTO_CAL_TX_LEVEL_ADJUST_BYPASS BIT(11) +#define ACX00_PAGE8_AUTO_CAL_LOW_CAL_OPAQUE_BITS 0x0044 +#define ACX00_PAGE8_AUTO_CAL_LOW_VALUE \ + (ACX00_PAGE8_AUTO_CAL_TX_LEVEL_ADJUST_BYPASS | \ + ACX00_PAGE8_AUTO_CAL_LOW_CAL_OPAQUE_BITS) + +#define ACX00_PAGE9_EPGC_COMMAND_REG 0x10 +#define ACX00_PAGE9_EPC_CLEAR_COUNTERS BIT(3) +#define ACX00_PAGE9_EPG_CLEAR_COUNTERS BIT(2) +#define ACX00_PAGE9_RX_BYTES_HIGH_REG 0x19 +#define ACX00_PAGE9_RX_BYTES_LOW_REG 0x1a +#define ACX00_PAGE9_RX_PACKETS_HIGH_REG 0x1b +#define ACX00_PAGE9_RX_PACKETS_LOW_REG 0x1c +#define ACX00_PAGE9_RX_CRC_ERRORS_HIGH_REG 0x1d +#define ACX00_PAGE9_RX_CRC_ERRORS_LOW_REG 0x1e + +enum acx00_ephy_stat { + ACX00_STAT_RX_BYTES, + ACX00_STAT_RX_PACKETS, + ACX00_STAT_RX_CRC_ERRORS, + ACX00_STAT_COUNT, +}; + +static const char acx00_ephy_stat_names[][ETH_GSTRING_LEN] =3D { + [ACX00_STAT_RX_BYTES] =3D "phy_rx_bytes", + [ACX00_STAT_RX_PACKETS] =3D "phy_rx_packets", + [ACX00_STAT_RX_CRC_ERRORS] =3D "phy_rx_crc_errors", +}; + +/* + * Another integration of this exact-ID PHY documents its digital vendor + * register map, which also matches the observed ACx00 reset values. The A= Cx00 + * analog-page field encodings remain unpublished, so keep those as opaque + * vendor initialization values instead of inventing bit definitions. + */ + +struct acx00_ephy_priv { + struct acx00_ephy_control *control; + bool is_ac300; + bool use_low_calibration_tuning; + bool xmii_rx_clock_inverted; + bool eee_initialized; + bool uaps_enabled; + bool stats_valid; + bool wol_irq_enabled; + bool wol_suspended; + unsigned long led_outputs; + int led_polarity_mode; + u32 wolopts; + u32 stats_last[ACX00_STAT_COUNT]; + u64 stats[ACX00_STAT_COUNT]; +}; + +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +static int acx00_enable_node(struct device *dev, struct device_node *node) +{ + struct of_changeset ocs; + const char *status; + int revert_ret; + int ret; + + ret =3D of_property_read_string(node, "status", &status); + if (ret || strcmp(status, "fail-needs-probe")) + return dev_err_probe(dev, -EINVAL, + "%pOF must use status fail-needs-probe\n", + node); + + of_changeset_init(&ocs); + ret =3D of_changeset_update_prop_string(&ocs, node, "status", "okay"); + if (!ret) { + ret =3D of_changeset_apply(&ocs); + if (ret && of_device_is_available(node)) { + revert_ret =3D of_changeset_revert(&ocs); + if (revert_ret) + dev_err(dev, + "failed to restore %pOF after enable error: %pe\n", + node, ERR_PTR(revert_ret)); + } + } + of_changeset_destroy(&ocs); + + return ret; +} +#endif + +static int acx00_prepare_node(struct device *dev, struct device_node *node, + bool runtime_selection) +{ + if (of_device_is_available(node)) + return 0; + + if (!runtime_selection) + return dev_err_probe(dev, -ENODEV, + "%pOF must be enabled for static control selection\n", + node); + +#if IS_ENABLED(CONFIG_OF_DYNAMIC) + return acx00_enable_node(dev, node); +#else + return dev_err_probe(dev, -EOPNOTSUPP, + "enabling %pOF requires CONFIG_OF_DYNAMIC\n", node); +#endif +} + +static struct device_node * +acx00_ac200_get_enable_node(struct device *dev, struct device_node *contro= l) +{ + struct device_node *parent; + struct device_node *enable_node; + + if (!of_device_is_available(control)) { + dev_err(dev, "%pOF must be enabled\n", control); + return ERR_PTR(-ENODEV); + } + + parent =3D of_get_parent(control); + if (!parent) + return ERR_PTR(-EINVAL); + + if (!of_device_is_compatible(parent, "x-powers,ac200")) { + dev_err(dev, "%pOF is not an AC200 control function\n", control); + of_node_put(parent); + return ERR_PTR(-EINVAL); + } + if (!of_device_is_available(parent)) { + dev_err(dev, "%pOF must be enabled\n", parent); + of_node_put(parent); + return ERR_PTR(-ENODEV); + } + + enable_node =3D of_get_parent(parent); + of_node_put(parent); + if (!enable_node) + return ERR_PTR(-EINVAL); + + return enable_node; +} + +static struct device * +acx00_find_supplier(struct device_node *control, bool is_ac300) +{ + struct platform_device *pdev; + struct mdio_device *mdiodev; + + if (is_ac300) { + mdiodev =3D of_mdio_find_device(control); + return mdiodev ? &mdiodev->dev : NULL; + } + + pdev =3D of_find_device_by_node(control); + return pdev ? &pdev->dev : NULL; +} + +static int acx00_select_control(struct phy_device *phydev, bool is_ac300, + bool runtime_selection, + unsigned long led_outputs, + bool led_active_low, + struct acx00_ephy_control **selected_control) +{ + struct acx00_ephy_control *ephy_control; + struct device *dev =3D &phydev->mdio.dev; + struct device_node *control; + struct device_node *enable_node; + struct device *supplier; + struct device_link *link; + const char *control_compatible; + const char *control_property; + u32 configured_addr; + int ret; + + control_property =3D is_ac300 ? "x-powers,ac300-control" : + "x-powers,ac200-control"; + control_compatible =3D is_ac300 ? "x-powers,ac300-ephy-ctl" : + "x-powers,ac200-ephy-ctl"; + control =3D of_parse_phandle(dev->of_node, control_property, 0); + if (!control) + return dev_err_probe(dev, -EINVAL, + "missing %s phandle\n", control_property); + if (!of_device_is_compatible(control, control_compatible)) { + ret =3D dev_err_probe(dev, -EINVAL, + "%s does not reference a %s device\n", + control_property, control_compatible); + goto out_put_control; + } + + if (is_ac300) { + ret =3D of_property_read_u32(control, "reg", &configured_addr); + if (ret || configured_addr !=3D phydev->mdio.addr + + AC300_EPHY_CONTROL_ADDR_OFFSET) { + ret =3D dev_err_probe(dev, -EINVAL, + "AC300 control address does not match PHY address\n"); + goto out_put_control; + } + + enable_node =3D of_node_get(control); + } else { + enable_node =3D acx00_ac200_get_enable_node(dev, control); + if (IS_ERR(enable_node)) { + ret =3D PTR_ERR(enable_node); + goto out_put_control; + } + } + + ret =3D acx00_prepare_node(dev, enable_node, runtime_selection); + of_node_put(enable_node); + if (ret) + goto out_put_control; + + supplier =3D acx00_find_supplier(control, is_ac300); + if (!supplier) { + ret =3D -EPROBE_DEFER; + goto out_put_control; + } + + link =3D device_link_add(dev, supplier, DL_FLAG_AUTOPROBE_CONSUMER); + if (!link) { + ret =3D -EINVAL; + } else { + device_lock(supplier); + if (!device_is_bound(supplier)) { + ret =3D -EPROBE_DEFER; + } else { + ephy_control =3D dev_get_drvdata(supplier); + if (!ephy_control || !ephy_control->power_on || + !ephy_control->power_off || + !ephy_control->set_led_outputs || + !ephy_control->set_led_polarity) { + ret =3D -EINVAL; + } else { + ret =3D ephy_control->set_led_polarity(ephy_control, + led_active_low); + if (!ret) + ret =3D ephy_control->set_led_outputs(ephy_control, + led_outputs); + if (!ret) + ret =3D ephy_control->power_on(ephy_control, + phydev->mdio.addr); + if (!ret) { + *selected_control =3D ephy_control; + } else { + ephy_control->set_led_outputs(ephy_control, 0); + ephy_control->set_led_polarity(ephy_control, + false); + } + } + } + device_unlock(supplier); + } + + put_device(supplier); + if (ret && ret !=3D -EPROBE_DEFER) + ret =3D dev_err_probe(dev, ret, + "failed to enable %s control\n", + is_ac300 ? "AC300" : "AC200"); + +out_put_control: + of_node_put(control); + return ret; +} + +static int acx00_ephy_parse_leds(struct phy_device *phydev, + unsigned long *led_outputs, + int *led_polarity_mode) +{ + struct device_node *leds; + u32 index; + int ret =3D 0; + + /* Match the vendor fallback when firmware provides no LED topology. */ + *led_outputs =3D GENMASK(ACX00_EPHY_LED_COUNT - 1, 0); + *led_polarity_mode =3D 1; + + leds =3D of_get_child_by_name(phydev->mdio.dev.of_node, "leds"); + if (!leds) + return 0; + + /* An explicit container replaces the fallback package configuration. */ + *led_outputs =3D 0; + *led_polarity_mode =3D -1; + + for_each_available_child_of_node_scoped(leds, led) { + bool active_high =3D of_property_read_bool(led, "active-high"); + bool active_low =3D of_property_read_bool(led, "active-low"); + int polarity_mode; + + ret =3D of_property_read_u32(led, "reg", &index); + if (ret) + break; + if (index >=3D ACX00_EPHY_LED_COUNT || + (*led_outputs & BIT(index))) { + ret =3D -EINVAL; + break; + } + *led_outputs |=3D BIT(index); + + if (active_high && active_low) { + ret =3D -EINVAL; + break; + } + if (of_property_read_bool(led, "inactive-high-impedance")) { + ret =3D -EOPNOTSUPP; + break; + } + if (!active_high && !active_low) + continue; + + polarity_mode =3D active_low; + if (*led_polarity_mode >=3D 0 && + *led_polarity_mode !=3D polarity_mode) { + ret =3D -EINVAL; + break; + } + *led_polarity_mode =3D polarity_mode; + } + + of_node_put(leds); + if (ret) + return dev_err_probe(&phydev->mdio.dev, ret, + "invalid EPHY LED description\n"); + if (*led_polarity_mode < 0) + *led_polarity_mode =3D 1; + + return 0; +} + +static void acx00_ephy_power_off(void *data) +{ + struct phy_device *phydev =3D data; + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + ret =3D priv->control->set_led_outputs(priv->control, 0); + if (ret) + phydev_warn(phydev, "failed to disable LED outputs: %pe\n", + ERR_PTR(ret)); + + ret =3D priv->control->set_led_polarity(priv->control, false); + if (ret) + phydev_warn(phydev, "failed to restore LED polarity: %pe\n", + ERR_PTR(ret)); + + ret =3D priv->control->power_off(priv->control); + if (ret) + phydev_warn(phydev, "failed to power off control block: %pe\n", + ERR_PTR(ret)); +} + +static int acx00_ephy_probe(struct phy_device *phydev) +{ + struct device *dev =3D &phydev->mdio.dev; + struct acx00_ephy_priv *priv; + bool has_ac200_control; + bool has_ac300_control; + bool runtime_selection; + u32 configuration =3D 0; + int led_polarity_mode; + unsigned long led_outputs; + int ret; + + has_ac200_control =3D of_property_present(dev->of_node, + "x-powers,ac200-control"); + has_ac300_control =3D of_property_present(dev->of_node, + "x-powers,ac300-control"); + if (!has_ac200_control && !has_ac300_control) + return -ENODEV; + runtime_selection =3D has_ac200_control && has_ac300_control; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ret =3D acx00_ephy_parse_leds(phydev, &led_outputs, + &led_polarity_mode); + if (ret) + return ret; + + if (has_ac300_control && + (runtime_selection || + of_property_present(dev->of_node, "nvmem-cells"))) { + ret =3D nvmem_cell_read_variable_le_u32(dev, "configuration", + &configuration); + if (ret) + return dev_err_probe(dev, ret, + "failed to read PHY configuration\n"); + } + + if (runtime_selection) { + priv->is_ac300 =3D configuration & + ACX00_EPHY_CONFIG_VARIANT_AC300; + } else { + priv->is_ac300 =3D has_ac300_control; + } + if (priv->is_ac300) + priv->use_low_calibration_tuning =3D configuration & + ACX00_EPHY_CONFIG_CALIBRATION_LOW; + priv->xmii_rx_clock_inverted =3D + device_property_read_bool(dev, + "x-powers,xmii-rx-clock-inverted"); + + ret =3D acx00_select_control(phydev, priv->is_ac300, + runtime_selection, + led_outputs, led_polarity_mode > 0, + &priv->control); + if (ret) + return ret; + + priv->led_outputs =3D led_outputs; + priv->led_polarity_mode =3D led_polarity_mode; + phydev->priv =3D priv; + ret =3D devm_add_action_or_reset(dev, acx00_ephy_power_off, phydev); + if (ret) + return ret; + + phydev->mdix_ctrl =3D ETH_TP_MDI_AUTO; + + /* + * The Wake-on-LAN events use the normal PHY interrupt. Only advertise + * wake support when firmware describes a routed interrupt. + */ + if (device_property_read_bool(dev, "wakeup-source") && + phy_interrupt_is_valid(phydev)) + device_set_wakeup_capable(dev, true); + + return 0; +} + +static int acx00_ephy_led_rules(u8 index, unsigned long *rules) +{ + switch (index) { + case ACX00_EPHY_LED_LINK_ACTIVITY: + *rules =3D BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) | + BIT(TRIGGER_NETDEV_RX); + break; + case ACX00_EPHY_LED_SPEED: + *rules =3D BIT(TRIGGER_NETDEV_LINK_100); + break; + case ACX00_EPHY_LED_DUPLEX: + /* Half-duplex collision flashing is fixed and has no rule bit. */ + *rules =3D BIT(TRIGGER_NETDEV_FULL_DUPLEX); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int acx00_ephy_led_hw_is_supported(struct phy_device *phydev, u8 in= dex, + unsigned long rules) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + unsigned long supported_rules; + int ret; + + if (index >=3D ACX00_EPHY_LED_COUNT || + !test_bit(index, &priv->led_outputs)) + return -EINVAL; + + ret =3D acx00_ephy_led_rules(index, &supported_rules); + if (ret) + return ret; + + return rules =3D=3D supported_rules ? 0 : -EOPNOTSUPP; +} + +static int acx00_ephy_led_hw_control_set(struct phy_device *phydev, u8 ind= ex, + unsigned long rules) +{ + return acx00_ephy_led_hw_is_supported(phydev, index, rules); +} + +static int acx00_ephy_led_hw_control_get(struct phy_device *phydev, u8 ind= ex, + unsigned long *rules) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + + if (index >=3D ACX00_EPHY_LED_COUNT || + !test_bit(index, &priv->led_outputs)) + return -EINVAL; + + return acx00_ephy_led_rules(index, rules); +} + +static int acx00_ephy_led_polarity_set(struct phy_device *phydev, int inde= x, + unsigned long modes) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + bool active_high; + bool active_low; + int polarity_mode; + int ret; + + if (index < 0 || index >=3D ACX00_EPHY_LED_COUNT || + !test_bit(index, &priv->led_outputs)) + return -EINVAL; + + active_high =3D test_bit(PHY_LED_ACTIVE_HIGH, &modes); + active_low =3D test_bit(PHY_LED_ACTIVE_LOW, &modes); + if (modes & ~(BIT(PHY_LED_ACTIVE_HIGH) | + BIT(PHY_LED_ACTIVE_LOW))) + return -EOPNOTSUPP; + if (active_high =3D=3D active_low) + return -EINVAL; + + polarity_mode =3D active_low; + if (priv->led_polarity_mode !=3D polarity_mode) { + phydev_err(phydev, + "LED polarity is global and must match for all outputs\n"); + return -EINVAL; + } + + ret =3D priv->control->set_led_polarity(priv->control, active_low); + + return ret; +} + +static int acx00_ephy_read_counter(struct phy_device *phydev, u32 high_reg, + u32 low_reg, u32 *counter) +{ + int high; + int high_check; + int low; + + do { + high =3D __phy_read(phydev, high_reg); + if (high < 0) + return high; + + low =3D __phy_read(phydev, low_reg); + if (low < 0) + return low; + + high_check =3D __phy_read(phydev, high_reg); + if (high_check < 0) + return high_check; + } while (high !=3D high_check); + + *counter =3D (u32)high << 16 | low; + + return 0; +} + +static int acx00_ephy_update_stats(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + u32 counters[ACX00_STAT_COUNT]; + int oldpage; + int ret; + int i; + + oldpage =3D phy_select_page(phydev, ACX00_PAGE_9); + if (oldpage < 0) + return phy_restore_page(phydev, oldpage, 0); + + ret =3D acx00_ephy_read_counter(phydev, + ACX00_PAGE9_RX_BYTES_HIGH_REG, + ACX00_PAGE9_RX_BYTES_LOW_REG, + &counters[ACX00_STAT_RX_BYTES]); + if (ret) + goto out_restore_page; + + ret =3D acx00_ephy_read_counter(phydev, + ACX00_PAGE9_RX_PACKETS_HIGH_REG, + ACX00_PAGE9_RX_PACKETS_LOW_REG, + &counters[ACX00_STAT_RX_PACKETS]); + if (ret) + goto out_restore_page; + + ret =3D acx00_ephy_read_counter(phydev, + ACX00_PAGE9_RX_CRC_ERRORS_HIGH_REG, + ACX00_PAGE9_RX_CRC_ERRORS_LOW_REG, + &counters[ACX00_STAT_RX_CRC_ERRORS]); + +out_restore_page: + ret =3D phy_restore_page(phydev, oldpage, ret); + if (ret) + return ret; + + if (priv->stats_valid) { + for (i =3D 0; i < ACX00_STAT_COUNT; i++) + priv->stats[i] +=3D counters[i] - priv->stats_last[i]; + } + + memcpy(priv->stats_last, counters, sizeof(counters)); + priv->stats_valid =3D true; + + return 0; +} + +static void acx00_ephy_snapshot_and_invalidate_stats(struct phy_device *ph= ydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + if (!priv->stats_valid) + return; + + ret =3D acx00_ephy_update_stats(phydev); + if (ret) + phydev_dbg(phydev, "failed to snapshot statistics: %pe\n", + ERR_PTR(ret)); + priv->stats_valid =3D false; +} + +static int acx00_ephy_validate_interface(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + + if (phydev->interface =3D=3D priv->control->interface) + return 0; + + phydev_err(phydev, "MAC uses %s but control device is configured for %s\n= ", + phy_modes(phydev->interface), + phy_modes(priv->control->interface)); + + return -EINVAL; +} + +static int acx00_ephy_soft_reset(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + ret =3D acx00_ephy_validate_interface(phydev); + if (ret) + return ret; + + /* The control sequence below may reset the hardware counters. */ + acx00_ephy_snapshot_and_invalidate_stats(phydev); + + ret =3D priv->control->power_on(priv->control, phydev->mdio.addr); + if (ret) + return ret; + + /* + * ACx00 acknowledges reset while powered down but does not restart. + * This can happen when reattaching a previously suspended PHY. + */ + ret =3D genphy_resume(phydev); + if (ret) + return ret; + + return genphy_soft_reset(phydev); +} + +static int acx00_ephy_read_page(struct phy_device *phydev) +{ + int ret; + + ret =3D __phy_read(phydev, ACX00_PAGE_SELECT_REG); + if (ret < 0) + return ret; + + return FIELD_GET(ACX00_PAGE_SELECT_MASK, ret); +} + +static int acx00_ephy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, ACX00_PAGE_SELECT_REG, + FIELD_PREP(ACX00_PAGE_SELECT_MASK, page)); +} + +static int __acx00_ephy_ack_interrupt(struct phy_device *phydev) +{ + int status; + + status =3D __phy_read(phydev, ACX00_PAGE0_INTERRUPT_STATUS_REG); + if (status < 0) + return status; + + /* All interrupt status bits are write-one-to-clear. */ + return __phy_write(phydev, ACX00_PAGE0_INTERRUPT_STATUS_REG, status); +} + +static int __acx00_ephy_config_interrupts(struct phy_device *phydev, + u32 wolopts, bool wake_only) +{ + u16 disable; + u16 mask =3D 0; + int ret; + + if ((!wake_only && phydev->interrupts =3D=3D PHY_INTERRUPT_ENABLED) || + (wolopts & WAKE_PHY)) + mask |=3D ACX00_PAGE0_INTERRUPT_LINK_CHANGE; + if (wolopts & WAKE_MAGIC) + mask |=3D ACX00_PAGE0_INTERRUPT_MAGIC_PACKET; + + /* Mask sources being removed before clearing their latched status. */ + disable =3D ACX00_PAGE0_INTERRUPT_MANAGED_EVENTS & ~mask; + if (disable) { + ret =3D __phy_modify(phydev, ACX00_PAGE0_INTERRUPT_MASK_REG, + disable, 0); + if (ret) + return ret; + } + + ret =3D __acx00_ephy_ack_interrupt(phydev); + if (ret) + return ret; + + return __phy_modify(phydev, ACX00_PAGE0_INTERRUPT_MASK_REG, + ACX00_PAGE0_INTERRUPT_MANAGED_EVENTS, mask); +} + +static int acx00_ephy_config_interrupts(struct phy_device *phydev, + u32 wolopts, bool wake_only) +{ + int oldpage; + int ret; + + oldpage =3D phy_select_page(phydev, ACX00_PAGE_0); + if (oldpage < 0) + return phy_restore_page(phydev, oldpage, 0); + + ret =3D __acx00_ephy_config_interrupts(phydev, wolopts, wake_only); + + return phy_restore_page(phydev, oldpage, ret); +} + +static int acx00_ephy_config_intr(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + + return acx00_ephy_config_interrupts(phydev, priv->wolopts, + priv->wol_suspended); +} + +static irqreturn_t acx00_ephy_handle_interrupt(struct phy_device *phydev) +{ + unsigned int active =3D 0; + int oldpage; + int enabled; + int status; + int ret =3D 0; + + oldpage =3D phy_select_page(phydev, ACX00_PAGE_0); + if (oldpage < 0) { + ret =3D phy_restore_page(phydev, oldpage, 0); + goto out_error; + } + + enabled =3D __phy_read(phydev, ACX00_PAGE0_INTERRUPT_MASK_REG); + if (enabled < 0) { + ret =3D enabled; + goto out_restore_page; + } + + status =3D __phy_read(phydev, ACX00_PAGE0_INTERRUPT_STATUS_REG); + if (status < 0) { + ret =3D status; + goto out_restore_page; + } + + active =3D status & enabled; + if (active) + /* Clear every event latched in the write-one-to-clear register. */ + ret =3D __phy_write(phydev, ACX00_PAGE0_INTERRUPT_STATUS_REG, + status); + +out_restore_page: + ret =3D phy_restore_page(phydev, oldpage, ret); + if (ret) + goto out_error; + + if (!active) + return IRQ_NONE; + + if (active & ACX00_PAGE0_INTERRUPT_LINK_CHANGE) + phy_trigger_machine(phydev); + + return IRQ_HANDLED; + +out_error: + phy_error(phydev); + return IRQ_NONE; +} + +/* + * Arm the nested interrupt as a wake source immediately. The AC200 is on = an + * I2C bus, so deferring this until the noirq suspend phase could require = an + * I2C register update after the controller has already been suspended. + */ +static int acx00_ephy_set_wake_irq(struct phy_device *phydev, bool enable) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + if (priv->wol_irq_enabled =3D=3D enable) + return 0; + if (!phy_interrupt_is_valid(phydev)) + return enable ? -EOPNOTSUPP : 0; + + if (enable) + ret =3D enable_irq_wake(phydev->irq); + else + ret =3D disable_irq_wake(phydev->irq); + if (ret) + return ret; + + priv->wol_irq_enabled =3D enable; + + return 0; +} + +static void acx00_ephy_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + struct device *dev =3D &phydev->mdio.dev; + + wol->supported =3D 0; + wol->wolopts =3D 0; + + if (!device_can_wakeup(dev) || !phy_interrupt_is_valid(phydev)) + return; + + wol->supported =3D WAKE_MAGIC | WAKE_PHY; + wol->wolopts =3D priv->wolopts; +} + +static int acx00_ephy_config_wol(struct phy_device *phydev, u32 wolopts) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + struct net_device *ndev =3D phydev->attached_dev; + const u8 *mac; + int oldpage; + int ret =3D 0; + int i; + + if (wolopts & WAKE_MAGIC && !ndev) + return -ENODEV; + + oldpage =3D phy_select_page(phydev, ACX00_PAGE_0); + if (oldpage < 0) + return phy_restore_page(phydev, oldpage, 0); + + if (wolopts & WAKE_MAGIC) { + /* The detector stores the MAC address big-endian in three registers. */ + mac =3D ndev->dev_addr; + for (i =3D 0; i < ETH_ALEN / 2; i++) { + ret =3D __phy_write(phydev, + ACX00_PAGE0_MAGIC_PACKET_MAC_REG(i), + mac[2 * i] << 8 | mac[2 * i + 1]); + if (ret) + goto out_restore_page; + } + } + + ret =3D __phy_modify(phydev, ACX00_PAGE0_GLOBAL_CONFIG_REG, + ACX00_PAGE0_MAGIC_PACKET_WAKE_ENABLE | + ACX00_PAGE0_MAGIC_PACKET_BROADCAST_ENABLE | + ACX00_PAGE0_MAGIC_PACKET_PASSWORD_ENABLE, + wolopts & WAKE_MAGIC ? + ACX00_PAGE0_MAGIC_PACKET_WAKE_ENABLE | + ACX00_PAGE0_MAGIC_PACKET_BROADCAST_ENABLE : 0); + if (ret) + goto out_restore_page; + + ret =3D __acx00_ephy_config_interrupts(phydev, wolopts, + priv->wol_suspended); + +out_restore_page: + return phy_restore_page(phydev, oldpage, ret); +} + +static int acx00_ephy_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + struct device *dev =3D &phydev->mdio.dev; + u32 old_wolopts =3D priv->wolopts; + bool enable =3D !!wol->wolopts; + bool old_enable =3D !!old_wolopts; + int rollback_ret; + int ret; + + if (wol->wolopts & ~(WAKE_MAGIC | WAKE_PHY)) + return -EOPNOTSUPP; + if (enable && (!device_can_wakeup(dev) || + !phy_interrupt_is_valid(phydev))) + return -EOPNOTSUPP; + + ret =3D acx00_ephy_config_wol(phydev, wol->wolopts); + if (ret) + goto out_rollback; + + ret =3D acx00_ephy_set_wake_irq(phydev, enable); + if (ret) + goto out_rollback; + + ret =3D device_set_wakeup_enable(dev, enable); + if (ret) + goto out_rollback; + + priv->wolopts =3D wol->wolopts; + + return 0; + +out_rollback: + rollback_ret =3D acx00_ephy_config_wol(phydev, old_wolopts); + if (rollback_ret) + phydev_warn(phydev, + "failed to restore Wake-on-LAN configuration: %pe\n", + ERR_PTR(rollback_ret)); + + rollback_ret =3D acx00_ephy_set_wake_irq(phydev, old_enable); + if (rollback_ret) + phydev_warn(phydev, + "failed to restore wake IRQ state: %pe\n", + ERR_PTR(rollback_ret)); + + rollback_ret =3D device_set_wakeup_enable(dev, old_enable); + if (rollback_ret) + phydev_warn(phydev, + "failed to restore device wake state: %pe\n", + ERR_PTR(rollback_ret)); + + return ret; +} + +static int acx00_ephy_config_init(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + bool use_low_calibration_tuning =3D priv->use_low_calibration_tuning; + bool is_ac300 =3D priv->is_ac300; + u16 afe_eq_rx_detect =3D ACX00_PAGE6_AFE_EQ_RX_DETECT_VALUE; + u16 tx_level_value =3D ACX00_PAGE6_TX_LEVEL_DEFAULT_VALUE; + int oldpage; + int ret; + bool tx_lpi_enabled; + + /* Configuration clears the hardware counters below. */ + acx00_ephy_snapshot_and_invalidate_stats(phydev); + + if (!priv->eee_initialized) { + /* The vendor configuration starts with both EEE modes disabled. */ + phydev->eee_cfg.eee_enabled =3D false; + phydev->eee_cfg.tx_lpi_enabled =3D false; + priv->eee_initialized =3D true; + } + tx_lpi_enabled =3D phydev->eee_cfg.tx_lpi_enabled && + !phydev->autonomous_eee_disabled; + + ret =3D phy_modify_paged(phydev, ACX00_PAGE_0, + ACX00_PAGE0_GLOBAL_CONFIG_REG, + ACX00_PAGE0_XMII_RX_CLOCK_INVERT, + priv->xmii_rx_clock_inverted ? + ACX00_PAGE0_XMII_RX_CLOCK_INVERT : 0); + if (ret) + return ret; + + if (is_ac300) { + if (use_low_calibration_tuning) { + afe_eq_rx_detect =3D + ACX00_PAGE6_AFE_EQ_RX_DETECT_LOW_CAL_VALUE; + tx_level_value =3D ACX00_PAGE6_TX_LEVEL_LOW_CAL_VALUE; + } + } + + oldpage =3D phy_select_page(phydev, ACX00_PAGE_1); + if (oldpage < 0) + return phy_restore_page(phydev, oldpage, 0); + + ret =3D __phy_write(phydev, ACX00_PAGE1_APS_CONTROL_REG, + ACX00_PAGE1_APS_DISABLED_4S_VALUE); + if (ret) + goto out_restore_page; + ret =3D __phy_modify(phydev, ACX00_PAGE1_UAPS_CONTROL_REG, + ACX00_PAGE1_UAPS_ENABLE, + priv->uaps_enabled ? ACX00_PAGE1_UAPS_ENABLE : 0); + if (ret) + goto out_restore_page; + /* Intelligent EEE lets the PHY generate LPI without MAC support. */ + ret =3D __phy_modify(phydev, ACX00_PAGE1_INTELLIGENT_EEE_CONTROL_REG, + ACX00_PAGE1_INTELLIGENT_EEE_ENABLE, + tx_lpi_enabled ? + ACX00_PAGE1_INTELLIGENT_EEE_ENABLE : 0); + if (ret) + goto out_restore_page; + + ret =3D acx00_ephy_write_page(phydev, ACX00_PAGE_2); + if (ret) + goto out_restore_page; + ret =3D __phy_modify(phydev, ACX00_PAGE2_TX_DATA_CONTROL_REG, + ACX00_PAGE2_10BT_FIR_SELECT_MASK, + FIELD_PREP(ACX00_PAGE2_10BT_FIR_SELECT_MASK, + ACX00_PAGE2_10BT_FIR_SELECT_DEFAULT)); + if (ret) + goto out_restore_page; + + ret =3D acx00_ephy_write_page(phydev, ACX00_PAGE_6); + if (ret) + goto out_restore_page; + ret =3D __phy_write(phydev, ACX00_PAGE6_AFE_EQ_RX_DETECT_CONTROL_REG, + afe_eq_rx_detect); + if (ret) + goto out_restore_page; + ret =3D __phy_write(phydev, ACX00_PAGE6_AFE_RX_CONTROL_REG, + ACX00_PAGE6_AFE_RX_CONTROL_VALUE); + if (ret) + goto out_restore_page; + if (is_ac300 && use_low_calibration_tuning) { + ret =3D __phy_write(phydev, ACX00_PAGE6_ADC_CONTROL_REG, + ACX00_PAGE6_ADC_CONTROL_LOW_CAL_VALUE); + if (ret) + goto out_restore_page; + } + ret =3D __phy_write(phydev, ACX00_PAGE6_TX_LEVEL_REG, tx_level_value); + if (ret) + goto out_restore_page; + + ret =3D acx00_ephy_write_page(phydev, ACX00_PAGE_8); + if (ret) + goto out_restore_page; + if (is_ac300 && use_low_calibration_tuning) { + ret =3D __phy_write(phydev, ACX00_PAGE8_AUTO_CAL_CONTROL_REG, + ACX00_PAGE8_AUTO_CAL_LOW_VALUE); + if (ret) + goto out_restore_page; + } + ret =3D __phy_write(phydev, ACX00_PAGE8_AFE_CONTROL_REG, + ACX00_PAGE8_AFE_CONTROL_VALUE); + if (ret) + goto out_restore_page; + + ret =3D acx00_ephy_write_page(phydev, ACX00_PAGE_9); + if (ret) + goto out_restore_page; + ret =3D __phy_write(phydev, ACX00_PAGE9_EPGC_COMMAND_REG, + ACX00_PAGE9_EPC_CLEAR_COUNTERS | + ACX00_PAGE9_EPG_CLEAR_COUNTERS); + if (!ret) { + memset(priv->stats_last, 0, sizeof(priv->stats_last)); + priv->stats_valid =3D true; + } + +out_restore_page: + ret =3D phy_restore_page(phydev, oldpage, ret); + if (ret) + return ret; + + /* Apply the retained Linux EEE policy after every hardware reset. */ + ret =3D genphy_c45_an_config_eee_aneg(phydev); + if (ret < 0) + return ret; + + /* A soft reset also clears the retained Wake-on-LAN configuration. */ + return acx00_ephy_config_wol(phydev, priv->wolopts); +} + +static int acx00_ephy_set_intelligent_eee(struct phy_device *phydev, + bool enable) +{ + return phy_modify_paged(phydev, ACX00_PAGE_1, + ACX00_PAGE1_INTELLIGENT_EEE_CONTROL_REG, + ACX00_PAGE1_INTELLIGENT_EEE_ENABLE, + enable ? ACX00_PAGE1_INTELLIGENT_EEE_ENABLE : 0); +} + +static int acx00_ephy_set_tx_lpi(struct phy_device *phydev, + const struct eee_config *config) +{ + if (config->tx_lpi_enabled && config->tx_lpi_timer) + return -EOPNOTSUPP; + + return acx00_ephy_set_intelligent_eee(phydev, + config->tx_lpi_enabled); +} + +static int acx00_ephy_config_aneg(struct phy_device *phydev) +{ + u16 mode; + int ret; + + switch (phydev->mdix_ctrl) { + case ETH_TP_MDI: + mode =3D ACX00_PAGE0_MDI_MODE_MDI; + break; + case ETH_TP_MDI_X: + mode =3D ACX00_PAGE0_MDI_MODE_MDIX; + break; + case ETH_TP_MDI_AUTO: + mode =3D ACX00_PAGE0_MDI_MODE_AUTO; + break; + default: + return -EINVAL; + } + + ret =3D phy_modify_paged_changed(phydev, ACX00_PAGE_0, + ACX00_PAGE0_GLOBAL_CONFIG_REG, + ACX00_PAGE0_MDI_MODE_MASK, + FIELD_PREP(ACX00_PAGE0_MDI_MODE_MASK, + mode)); + if (ret < 0) + return ret; + + return __genphy_config_aneg(phydev, ret > 0); +} + +static int acx00_ephy_read_status(struct phy_device *phydev) +{ + int ret; + + ret =3D genphy_read_status(phydev); + if (ret) + return ret; + + if (!phydev->link) { + phydev->mdix =3D ETH_TP_MDI_INVALID; + return 0; + } + + ret =3D phy_read_paged(phydev, ACX00_PAGE_0, ACX00_PAGE0_STATUS_REG); + if (ret < 0) + return ret; + + phydev->mdix =3D ret & ACX00_PAGE0_STATUS_MDIX ? ETH_TP_MDI_X : + ETH_TP_MDI; + + return 0; +} + +static int acx00_ephy_get_sset_count(struct phy_device *phydev) +{ + return ACX00_STAT_COUNT; +} + +static void acx00_ephy_get_strings(struct phy_device *phydev, u8 *data) +{ + unsigned int i; + + for (i =3D 0; i < ACX00_STAT_COUNT; i++) + ethtool_puts(&data, acx00_ephy_stat_names[i]); +} + +static void acx00_ephy_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + unsigned int i; + int ret; + + ret =3D acx00_ephy_update_stats(phydev); + for (i =3D 0; i < ACX00_STAT_COUNT; i++) + data[i] =3D ret ? U64_MAX : priv->stats[i]; +} + +static void acx00_ephy_get_phy_stats(struct phy_device *phydev, + struct ethtool_eth_phy_stats *eth_stats, + struct ethtool_phy_stats *stats) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + + stats->rx_errors =3D priv->stats[ACX00_STAT_RX_CRC_ERRORS]; +} + +static int acx00_ephy_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tunable, void *data) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + if (tunable->id !=3D ETHTOOL_PHY_EDPD) + return -EOPNOTSUPP; + + ret =3D phy_read_paged(phydev, ACX00_PAGE_1, + ACX00_PAGE1_UAPS_CONTROL_REG); + if (ret < 0) + return ret; + priv->uaps_enabled =3D ret & ACX00_PAGE1_UAPS_ENABLE; + + *(u16 *)data =3D priv->uaps_enabled ? ETHTOOL_PHY_EDPD_NO_TX : + ETHTOOL_PHY_EDPD_DISABLE; + + return 0; +} + +static int acx00_ephy_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tunable, + const void *data) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + bool enable; + u16 edpd; + int ret; + + if (tunable->id !=3D ETHTOOL_PHY_EDPD) + return -EOPNOTSUPP; + + edpd =3D *(const u16 *)data; + switch (edpd) { + case ETHTOOL_PHY_EDPD_DISABLE: + enable =3D false; + break; + case ETHTOOL_PHY_EDPD_NO_TX: + enable =3D true; + break; + default: + return -EINVAL; + } + + ret =3D phy_modify_paged(phydev, ACX00_PAGE_1, + ACX00_PAGE1_UAPS_CONTROL_REG, + ACX00_PAGE1_UAPS_ENABLE, + enable ? ACX00_PAGE1_UAPS_ENABLE : 0); + if (!ret) + priv->uaps_enabled =3D enable; + + return ret; +} + +static int acx00_ephy_power_on_and_resume(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + ret =3D priv->control->power_on(priv->control, phydev->mdio.addr); + if (ret) + return ret; + + ret =3D genphy_resume(phydev); + if (ret) + return ret; + + /* The control block loses the link-PHY vendor state while powered off. */ + return acx00_ephy_config_init(phydev); +} + +static int acx00_ephy_resume(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + ret =3D acx00_ephy_validate_interface(phydev); + if (ret) + return ret; + + if (priv->wol_suspended) { + ret =3D acx00_ephy_config_interrupts(phydev, priv->wolopts, + false); + if (ret) + return ret; + + priv->wol_suspended =3D false; + return 0; + } + + return acx00_ephy_power_on_and_resume(phydev); +} + +static int acx00_ephy_suspend(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int resume_ret; + int ret; + + mutex_lock(&phydev->lock); + if (priv->stats_valid) + acx00_ephy_update_stats(phydev); + mutex_unlock(&phydev->lock); + + if (phydev->wol_enabled) { + ret =3D acx00_ephy_config_interrupts(phydev, priv->wolopts, + true); + if (!ret) + priv->wol_suspended =3D true; + + return ret; + } + + ret =3D genphy_suspend(phydev); + if (ret) + return ret; + + ret =3D priv->control->power_off(priv->control); + + mutex_lock(&phydev->lock); + priv->stats_valid =3D false; + mutex_unlock(&phydev->lock); + if (ret) { + resume_ret =3D acx00_ephy_power_on_and_resume(phydev); + if (resume_ret) + phydev_warn(phydev, + "failed to recover from suspend error: %pe\n", + ERR_PTR(resume_ret)); + } + + return ret; +} + +static void acx00_ephy_remove(struct phy_device *phydev) +{ + struct device *dev =3D &phydev->mdio.dev; + int ret; + + ret =3D acx00_ephy_set_wake_irq(phydev, false); + if (ret) + phydev_warn(phydev, "failed to disarm wake IRQ: %pe\n", + ERR_PTR(ret)); + + device_set_wakeup_enable(dev, false); + device_set_wakeup_capable(dev, false); +} + +static int acx00_ephy_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) +{ + struct device_node *node =3D phydev->mdio.dev.of_node; + + if (!genphy_match_phy_device(phydev, phydrv) || !node) + return 0; + + /* RK630 reports the same PHY ID, so require an X-Powers control link. */ + return of_property_present(node, "x-powers,ac200-control") || + of_property_present(node, "x-powers,ac300-control"); +} + +static struct phy_driver acx00_ephy_driver[] =3D { + { + PHY_ID_MATCH_MODEL(ACX00_EPHY_ID), + .name =3D "X-Powers AC200/AC300 EPHY", + .flags =3D PHY_ALWAYS_CALL_SUSPEND, + .match_phy_device =3D acx00_ephy_match_phy_device, + .probe =3D acx00_ephy_probe, + .read_page =3D acx00_ephy_read_page, + .write_page =3D acx00_ephy_write_page, + .soft_reset =3D acx00_ephy_soft_reset, + .config_init =3D acx00_ephy_config_init, + .config_aneg =3D acx00_ephy_config_aneg, + .read_status =3D acx00_ephy_read_status, + .config_intr =3D acx00_ephy_config_intr, + .handle_interrupt =3D acx00_ephy_handle_interrupt, + .get_wol =3D acx00_ephy_get_wol, + .set_wol =3D acx00_ephy_set_wol, + .remove =3D acx00_ephy_remove, + .set_tx_lpi =3D acx00_ephy_set_tx_lpi, + .get_sset_count =3D acx00_ephy_get_sset_count, + .get_strings =3D acx00_ephy_get_strings, + .get_stats =3D acx00_ephy_get_stats, + .get_phy_stats =3D acx00_ephy_get_phy_stats, + .update_stats =3D acx00_ephy_update_stats, + .get_tunable =3D acx00_ephy_get_tunable, + .set_tunable =3D acx00_ephy_set_tunable, + .led_hw_is_supported =3D acx00_ephy_led_hw_is_supported, + .led_hw_control_set =3D acx00_ephy_led_hw_control_set, + .led_hw_control_get =3D acx00_ephy_led_hw_control_get, + .led_polarity_set =3D acx00_ephy_led_polarity_set, + .suspend =3D acx00_ephy_suspend, + .resume =3D acx00_ephy_resume, + }, +}; +module_phy_driver(acx00_ephy_driver); + +static const struct mdio_device_id __maybe_unused acx00_ephy_tbl[] =3D { + { PHY_ID_MATCH_MODEL(ACX00_EPHY_ID) }, + { } +}; +MODULE_DEVICE_TABLE(mdio, acx00_ephy_tbl); + +MODULE_AUTHOR("James Hilliard "); +MODULE_DESCRIPTION("X-Powers AC200/AC300 Ethernet PHY driver"); +MODULE_LICENSE("GPL"); --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f53.google.com (mail-ot1-f53.google.com [209.85.210.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0DB2439525E for ; Mon, 3 Aug 2026 05:15:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734152; cv=none; b=SA712rAMYkPzuQ3Eks6gqniKM7Hc/FPu9jpzgbqO64tP4RqKaA8Pj0yue9MVL1qphSW5pcGeR/cMTx2n/MuwlgFW03w4YrMGyPiI/L+23JXQ2pnsUMLH13IGbGFVuX51jvsu/WFOvM3Pp7Z3u0IlwX/GLhf3Nd3h5wQRJXUACW8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734152; c=relaxed/simple; bh=CsTsehT4z8CJxsGhaiEo1pllL05TyPVSaHwPj6kU07s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=G/cPpN4M9hNGlJbdFYK+J0BOKRhCVCbPQKApnlegXNTY7C45henjz+AXlQMBAbpJQGmDRnT+PIB1ip2Cr4xwNDXGhOwdUbfWn8tAPy2mNlYkTpzRoA0hZPbkXT9TbnjXXTEJPjB6GG7aOnUvRrotNv6Jy3PDy6ZUy8qVEFmVpiE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=kYLyWDy0; arc=none smtp.client-ip=209.85.210.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kYLyWDy0" Received: by mail-ot1-f53.google.com with SMTP id 46e09a7af769-7f18c0e03e3so1152373a34.2 for ; Sun, 02 Aug 2026 22:15:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734149; x=1786338949; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=9OpRGWNf+wnvCcP1DS85gL+udlM+7o9ZcunosuNBCWA=; b=kYLyWDy0P4VE11xbG48gBf1b+3N4mTWJNz4xhKm5Y+avebwamRQX+zKYH8/4jdcnkI c2JrRQoQxWkwm21PjVNNU6kZjZSzfhcLe5GtSYc7cm4Sksc4qawIJA3dZTmcSwEVJ0Ll wIMRCtn1Egpuokh6TLmKzIwi39AFiN2ByEA3pBPj3eyosN+PO+YUikmY9Mk6+WTULa4t Z9Uz3E1CLFTg9JsjigSQnytNgnxU+Onb38Xti4k3yxmwQNO+ubk6XBghKPCIKbT4bCcj uHvCNqf14u26K12IMCel3S+LsqQXE/wGboBaON8gUdeOXnW1aGW8pwb5bjEJBy3dIb2b 0w2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734149; x=1786338949; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=9OpRGWNf+wnvCcP1DS85gL+udlM+7o9ZcunosuNBCWA=; b=Me9h5oB7/J+CiYITc5UJIqOeBap3TgiP3bqdsykpsq9gPVow9ZwT/QAfpJON7+jCYF I65HlYyXEWkutBWUp/tFAbJGmLbOIj/Fw7j83wOiHCOBJanO//LDs7OAGyIjq067F5sQ spsPiqg7LK9amfLb+5AWPjRE7hN6kC8h8VtzM4qBRNDi98l+LdP17t9iotH5VDbz7oX/ Qp66YhAjHa2av52mCgCuXnivX+ConmeXyb6rud3+CbZpxLKpj2lEn3f/CNPP9dFaahDr OJpDgkKYSrt2q1JfRwQv8xXN/iV+iHlHEg93bE//xHvKZ3TMtpcc32h/aO/islITKHy6 dM0A== X-Forwarded-Encrypted: i=1; AHgh+Rr/giQ63O/pE9vxJFXBxSgUAQSYt7IMXF5eHPWBJtFQtoXpGumpHNwfOc4KRY5Qnt4VC9fAztD6ia7WzKE=@vger.kernel.org X-Gm-Message-State: AOJu0YzZ9Zls4ymp3mgAo/fk/SnHKwQMZ0NSNF5fQdc5HnirgBaYkTwJ dx8V2kYJpVo9n2P6OJRjas1CJX38X9V7COXMcyWdRLNz1agql4Gv8r5h X-Gm-Gg: AR+sD10s/R3zbfNlec/4nPR+LZw5dpSTT9U1zf3K//oLSuyuf06kcRakcJC+fIIk7+x /kcDLu0B1EBHskL/mPgyWMwOcoVT1sqfmqDtxh9nGPCRITxCggmbQZkUL/9pPfEDB6TaKz2tvYw YO7pgjIiHfaQKAa/TCPCFYwkQQPKP7uTOeyLlA5AfGN7pziVSGznBqFyp+V/J7zRTLkOLbxdGol CMqgHAErltNqaWfbmNXqfrLigNBU+bVZhdUizve9/NJMPrhnypoQgxq28nVhmAU8gyXv/Yztu9j y6dLmFX8EOOrd/vU4ZAwntAc4yIV4DrXih8goiIkCzLrq6j7AXJpJts8PuZ+IsJgeJC8fMypNCu S7JThnIBhr0qOaJs+QbmSsiSeeax4AFM6jV6H7sdf8ItRNotfyZqo5alBlm6b2gK1ZMecoRj4Dc G92eSiIOJsFxuoOSBySvhf3nz7Wq2yepvA+G/KBxeSyaMoC7owmvXBw3IQNT21s2PSYKPLoCWtT VOlYLjq3rIQqALUWPWZolkjFUvtDIVoz0y+VXexcuzxkg8mMutkhO7QWlG63wJDvqzxU9naLzYE ZxGy+uboWC4iOKIkbNE86oyE22A1MEr3UUYV+z7pHHXYee5P1elf0wghtL6rhYmD+bW2c20x0FO NWTxM0ofNnEco8c9O X-Received: by 2002:a05:6830:3592:b0:7e9:e488:3bce with SMTP id 46e09a7af769-7f196bab78dmr14968611a34.6.1785734148846; Sun, 02 Aug 2026 22:15:48 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:48 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:27 -0600 Subject: [PATCH 17/21] arm64: dts: allwinner: h616: add ACx00 EPHY resources Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-17-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 Expose logical SID cells for the AC200/AC300 EPHY calibration, the combined companion-variant and AC300-calibration-range configuration, and the AC200 bandgap fields. Also describe the PA10/PA11 I2C3 pin group used by the AC200 control interface. Signed-off-by: James Hilliard --- arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/bo= ot/dts/allwinner/sun50i-h616.dtsi index 6879f27c2b2b..2cedda6e87a9 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi @@ -252,6 +252,20 @@ ths_calibration: thermal-sensor-calibration@14 { cpu_speed_grade: cpu-speed-grade@0 { reg =3D <0x0 2>; }; + + ephy_calibration: ethernet-phy-calibration@2c,0 { + reg =3D <0x2c 1>; + bits =3D <0 4>; + }; + + ephy_config: ethernet-phy-configuration@2c { + reg =3D <0x2c 2>; + bits =3D <8 2>; + }; + + ac200_bandgap: bandgap@30 { + reg =3D <0x30 2>; + }; }; =20 timer0: timer@3009000 { @@ -324,6 +338,13 @@ i2c0_pins: i2c0-pins { function =3D "i2c0"; }; =20 + /omit-if-no-ref/ + i2c3_pa_pins: i2c3-pa-pins { + pins =3D "PA10", "PA11"; + function =3D "i2c3"; + bias-pull-up; + }; + i2c3_ph_pins: i2c3-ph-pins { pins =3D "PH4", "PH5"; function =3D "i2c3"; --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f54.google.com (mail-ot1-f54.google.com [209.85.210.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5ADA1397B1B for ; Mon, 3 Aug 2026 05:15:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734153; cv=none; b=MRXG/s4TeJxMesltoYz2GAhRq+gDcK2bzx1X4XYiLteY/GRUYYA9pzJnuub6NyvLaUntJolLLTK9KKDKgSMgHZr1f6h6aGpkXZOhxddCi2ognyW53I4EqzATqP/PTm+M8jNs6ID3R4wcJSKrAsRDPaaLXyoAehDA6R9AsbAHePQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734153; c=relaxed/simple; bh=ZUVZReuwX6u+VOoUVGjsuCMz/MOgQoewZH495TiPLJ0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mfpqCgBSnQQSidlEAnUYCnS/R5adEugf/IhfJI6ziayecfBDCo81fBtcWVqyyq4+t0pBqSU3F69wbUvbn6bnD64k1DVdaaqC96baV8kGw9yM2r1V6ZC/KpYWrpEhyIkA2PwW4Yftgqsfq0YbcWJQJSZAowwoXSVsrk/Yh04NkL4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Y2YZX1LQ; arc=none smtp.client-ip=209.85.210.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Y2YZX1LQ" Received: by mail-ot1-f54.google.com with SMTP id 46e09a7af769-7eb29ed2bbdso1002542a34.2 for ; Sun, 02 Aug 2026 22:15:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734150; x=1786338950; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=OJn8bgDlexj3pTLFD/TVKu44xwgcekcV50vMMBDdgSo=; b=Y2YZX1LQVBjsbzcaecmpbQH5pP2HHE4QV5cE/AUREBPl/XM05rojqrphqrxNigbLhb WeKfmbp96L9mk3atpyrL3XHTZURyxFW5/ycMVe0ZSe319RmS5ssdfY95QCtpaarCs6/f +IkDyMRoGQvxo6JAbuHDhX0VJYeSd5rofIc3reptOyghmLmHROXLQHb++id/Wvp0Td0T ddpSgW3biBRuvMNhLwWWPieoFAWgYji0Dc9BtbAZPEDsUFxnUIGcJVRROoG6Fh0e4+rZ wRBs6+xJjxOfDBI9BhiIDBPNhLKMqK4H4Lk6nxYuyiorg5TuFGjOZ4+PTZJg4PqugkzL YnSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734150; x=1786338950; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=OJn8bgDlexj3pTLFD/TVKu44xwgcekcV50vMMBDdgSo=; b=FQPu1om1OPgNy2zKe7kvL/ur6x5RqymqUFKb79yi4wYPSXzN8+E1OCgJfmpU5Ott98 xCUE5NlU4jANJdzxS4brwy2SFznguUGE7sigOrCio5Z92pk22F2kfKXNTG1Ij8p7nD9R XFlXe6hdj18ilUSTdq1rN0n7JY1Ri+eJE7QLlSOb+NB4OfF6q88UjbRoWsjGlCPdmrQB aB5J/QQDJLl1H71fsBBlPs1bLRqaEodi2dX0PnNpWpiiS/G88bf22/XV8d0lhJ9vebHW xa/cYuwhT/gIBXyS/ztQSSTqEcEPpMbQCxNgdUIpn2W7rMb7mZd6VIgNRb+1fFBj0mk0 8skQ== X-Forwarded-Encrypted: i=1; AHgh+RrqhXB7KWqrfyLTrvpxNqsRkinw9Sf9iZhpAAJTwyaFQj/ntE0XkHcMtORXa4n3c9vnAZlyx7Ff7YvWnWs=@vger.kernel.org X-Gm-Message-State: AOJu0Yw1Es2xB2OQ2UHR5W08RRtiwR9bdSii5zq9f7zuhtakuULs1/uB QacXcPZiZTt22dTfYX1CJNZApBg3lBQ7Yx7c/vJyHcq5H0ao08IUVRld X-Gm-Gg: AR+sD11fwjROiNS52wfarikGKiAPvXmlsPm00Zk6AOYxOcHHNQUPGrPBFGbdO+Zkh2x zLGuCuPY78R7dOZ6apzqwujJc5CmR7n7yl2sJQl/8VPzdjL6c+J2rFtiNRjCNNlSO3x7N0qo5Bi EwUZfIYJDZkYVlFpXTIvvX8WwyjloMXBPil6cqaVslsuwkyUUFhdtM0KSsdOdxZ64jNqEcXf5QW e6458kPw/l7tPv47BVAaNHwlgNamDbqvyrsRKONYUGey1qVH1dXEFnkNG0HkIIasFYl5ztiPi5O qNUe3kR1HITFSQWHfG5fCvB24WrY3bDz547TWlRRd+vE7A3UUn9aJi9XwzDHi7IDLKjIfF/BEeS zPtbt3pufFwRrwykIKtpC/6Qwq39ixHUrkyBS7CrE80JxfyButRY98ks6MNB/5VkcZCPfcsvPaY 2LAnylTEmphSKQpdO53D9V6V6MOHTWUqvf4FT7ccLWMPOb6t/0W4/1fILIe8h9z3TKi5TjCEB09 /HHtKWlNOAil36BPvskUNbo28b1Kc/C+F6HtXyTrOz4sygy2LuJQ2VwdWD5jDVdetM/ddB4ggtH Y2BG24sXxTQ7Y1xbAqD9+FcOTiQEDyVFqR1GSH9w4lR15cu8y7YrTatE2tvlB+BJPa3Geeo3F3d +T6TY+WLaOxxLL9uD X-Received: by 2002:a05:6830:82eb:b0:7eb:c933:eff7 with SMTP id 46e09a7af769-7f196f0d0e1mr13285248a34.9.1785734150243; Sun, 02 Aug 2026 22:15:50 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:49 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:28 -0600 Subject: [PATCH 18/21] arm64: dts: allwinner: orangepi-zero2w: enable Ethernet expansion Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-18-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The optional Orange Pi Zero 2W expansion board exposes H618 EMAC1 through a 100 Mbit Ethernet jack. Add a reusable H616-family description of the AC200/AC300 EPHY wiring alongside its first board user. The forced-ID link PHY selects the populated control path and AC300 tuning range from the logical SID configuration field. Keep the AC200 I2C controller and AC300 MDIO control node at status fail-needs-probe so only the selected path claims its pins. Enable EMAC1 and its PWM clock provider through the common include, provide the board's 3.3 V rail to either companion variant, and make EMAC1 the board Ethernet alias. Signed-off-by: James Hilliard --- .../boot/dts/allwinner/sun50i-h616-acx00-ephy.dtsi | 61 ++++++++++++++++++= ++++ .../dts/allwinner/sun50i-h618-orangepi-zero2w.dts | 13 +++++ 2 files changed, 74 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-acx00-ephy.dtsi b/ar= ch/arm64/boot/dts/allwinner/sun50i-h616-acx00-ephy.dtsi new file mode 100644 index 000000000000..26521429957a --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-acx00-ephy.dtsi @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Common X-Powers AC200/AC300 Ethernet PHY support for H616-family SoCs + * + * Copyright (C) 2026 James Hilliard + */ + +&emac1 { + phy-handle =3D <&acx00_ephy>; + status =3D "okay"; +}; + +&i2c3 { + pinctrl-names =3D "default"; + pinctrl-0 =3D <&i2c3_pa_pins>; + status =3D "fail-needs-probe"; + + ac200: mixed-signal@10 { + compatible =3D "x-powers,ac200"; + reg =3D <0x10>; + clocks =3D <&pwm 5>; + nvmem-cells =3D <&ac200_bandgap>; + nvmem-cell-names =3D "bandgap"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pwm5_pin>; + + ac200_ephy_ctl: ethernet-phy-control { + compatible =3D "x-powers,ac200-ephy-ctl"; + nvmem-cells =3D <&ephy_calibration>; + nvmem-cell-names =3D "calibration"; + phy-mode =3D "rmii"; + }; + }; +}; + +&mdio1 { + ac300_ephy_ctl: ethernet-phy-control@10 { + compatible =3D "x-powers,ac300-ephy-ctl"; + reg =3D <0x10>; + clocks =3D <&pwm 5>; + nvmem-cells =3D <&ephy_calibration>; + nvmem-cell-names =3D "calibration"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pwm5_pin>; + phy-mode =3D "rmii"; + status =3D "fail-needs-probe"; + }; + + acx00_ephy: ethernet-phy@0 { + compatible =3D "ethernet-phy-id0044.1400"; + reg =3D <0>; + nvmem-cells =3D <&ephy_config>; + nvmem-cell-names =3D "configuration"; + x-powers,ac200-control =3D <&ac200_ephy_ctl>; + x-powers,ac300-control =3D <&ac300_ephy_ctl>; + }; +}; + +&pwm { + status =3D "okay"; +}; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts = b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts index b340bbcb710d..e833ee267c83 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts @@ -6,6 +6,7 @@ /dts-v1/; =20 #include "sun50i-h616.dtsi" +#include "sun50i-h616-acx00-ephy.dtsi" #include "sun50i-h616-cpu-opp.dtsi" =20 #include @@ -17,6 +18,7 @@ / { compatible =3D "xunlong,orangepi-zero2w", "allwinner,sun50i-h618"; =20 aliases { + ethernet0 =3D &emac1; serial0 =3D &uart0; }; =20 @@ -54,6 +56,17 @@ reg_vcc3v3: vcc3v3 { }; }; =20 +&ac200 { + ac-ldoin-supply =3D <®_vcc3v3>; + ephy-vcc-supply =3D <®_vcc3v3>; + rtc-vcc-supply =3D <®_vcc3v3>; + tv-vcc-supply =3D <®_vcc3v3>; +}; + +&ac300_ephy_ctl { + vcc1-supply =3D <®_vcc3v3>; +}; + &codec { allwinner,audio-routing =3D "Line Out", "LINEOUT"; status =3D "okay"; --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-oi1-f169.google.com (mail-oi1-f169.google.com [209.85.167.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5F27139989B for ; Mon, 3 Aug 2026 05:15:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734159; cv=none; b=ZoxBL28B1E40pdMgAb6VrT2/4WFdH8iNTs9D8/JjNlP9QiW/MqVJ0OWapuYxvyHUwiew/28qMrWeT0v2CQl0ev1HkRieEdtrU2Jr1ujIxbMyTqV8I3k//8HP6qQPyjJ5BIY0sBMkKtH5O5sRlTGqJwDl6dBBcTjiL6SLT6cJmwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734159; c=relaxed/simple; bh=6ziM+f30xkSte3zlDzpBhj7lMZ8ieILh8cGDDWCvnhA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=J0HZmDsFBMFj+mBVbpKV04o7PDKcXmBqJCDZoIG0o47nq6YR64MzmplxAgqVJZ93nmiWEuBHym8lFaKKQKKWVqB8coKD17musmJcIstv6hmCAMKrnJ4y+crRS9VxZ9y+QaYA6WlmA5Po4wrueaFNDJkZ0cVmCnctLwqGYraSrRA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=XtT83fzp; arc=none smtp.client-ip=209.85.167.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XtT83fzp" Received: by mail-oi1-f169.google.com with SMTP id 5614622812f47-497d3e4460aso3200727b6e.1 for ; Sun, 02 Aug 2026 22:15:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734156; x=1786338956; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=e9FeknYPclzv16XYXDkTzfHxoN/DCYzLCAYv6oC+ejo=; b=XtT83fzpxAoSsD8J7SWejAivsSQz/+2Sqk64T6l9HSQWDwbn6SpcJ+yt3X0CmM4EJr 2AzzZ8l8pvJUQPeLhhzPJujzppH1t7LQQ1y7QjqlAMyN82HUuOGUDPNR/Ubr4NdfVDvP 0k4Q7SL/NUYmIoEYqbjQ+mentJ0EspPx0bIq5zi4tFWgED6mKGbfsyUxysCM48/ZU7dA zKgCumoCxvx9yBcN3tnqI3RIqcKop4NRY2gmXCI6kUVhuu/ref5eSFoYwxqEZOx0sEyO q1xvdRaosoidkgKjwYf2/O0ClDybeTLCqrWvGal1ZcTWV3tSmzUiz9rm1F6Lunk6YIyf oi1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734156; x=1786338956; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=e9FeknYPclzv16XYXDkTzfHxoN/DCYzLCAYv6oC+ejo=; b=NNSVN2fXS5tdBbi5/mNvdSuZGQFistf0GdVGwJV57SO0mjUxep5GwL3dEoKgGG4UZS iDoex4YoW6II1YWIA6J4d+U/lqeSktAYw3ghZgVsJq8ZKbMRW2/rBcg2why0ApPArBIF k2V4k/+80kpTf1ILqBNQr8oQmxiftQzkWQL0EtgFLdT9P87reQjbtBLwVFCro9lZ+CCA p+TRMnCggZyJIuk4Z4rc9fXpNak0LLotIm2tZKTNCZSLq7TsetS24fD5V/sT4mCo7uUy YwgAAfD4PNKvCSW/Q8tjpHh1WItPmHRNM4t8bvvV6uz48/4oz/3DpNiLQ18DM97vALMO DlDQ== X-Forwarded-Encrypted: i=1; AHgh+Ro1raxw8n3Q7GNu7WvQGtZsamgB+PaO5hlwtgjm+qnB4jPc6OKLZv2xpAdFe6gkspkQFUxDM1Q+4jtlGFw=@vger.kernel.org X-Gm-Message-State: AOJu0YzRfSGTBRkgvv4JT1UQT+GLJN4Dbcf8H04g7IjVi0H0lpKO5QGz r2wJlmM+AWpfteuQpXoaHUE2f94AhTrIbaEFD911EZd0HTcYTH8Uc5L2 X-Gm-Gg: AR+sD13z2agYTy01dY5HrHef7NcE8WMWYbWxL6eYhFR4O2zZDdddB59qFo7q85trMIs qheBgQLR2Oor/LoJEI3wNi+hy9wqyutvDKPcM+sbqWliutqZ1gGY9m1fBjIiMlg5m0rF4nCd+y1 S6M7roDiWBM2IsSRK2WHsBob15AJEZmE4q56We2ecXtmCyaou6tKGoBkaBQCNPzeAr+++nPG1lo nVhf5DFy3KAehiL0XRuCNE1MBSTLS6CiVSRBmI27t/kbeJ06O7geHUIbk+YLTpDhBxBlujDge2B b8NnMwfuEt/jPMEAkNtdZAttVTPFns0pmjMu80NHceb4BYVZY/zyiFthpAelpCRs4mkOQMfpTD7 SPzfIAicaSS2DSc9gHQ7/wWGG9XPNGxMNmvehdgDWmL4d1FwaTvUVDjI47Td+iyzfp36ZDC7fkg f6ThJKNLIAAelNeCyyA3fHzP/ZQotJf+VnCYzXlMA9//P82BpQlDpBK4iWM7T9yWZjvs0CCEfcg 7KiZF5OKYlnrcWqglTMQdXExSvzmTiCSy+kV0wZnUYJouIZ2UkfLVXbEbiUeqvyzG+gYudgY6FJ h6mFzd6F8xtzTrhu0SMZukyIVp8LC4y/smbRnZbXSvlHFwe9RmWitObxaQvkpakvNpra7ivezja MrgVpKp1n50BC2hpz X-Received: by 2002:a05:6808:1797:b0:495:f697:92d9 with SMTP id 5614622812f47-4ae3188b02dmr15246163b6e.7.1785734151556; Sun, 02 Aug 2026 22:15:51 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:51 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:29 -0600 Subject: [PATCH 19/21] arm64: dts: allwinner: h6: add AC200 EPHY resources Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-19-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 Add the H6 I2C3 controller and pinmux, the PWM-derived 24 MHz AC200 clock, SID calibration cells, RMII pinmux, and the AC200 MFD and EPHY control nodes. Describe the co-packaged AC200 INTB output on PB20. Keep both reusable AC200 nodes disabled so boards must explicitly enable the parent and its EPHY control function when the companion is present. Signed-off-by: James Hilliard --- arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 73 ++++++++++++++++++++++++= ++++ 1 file changed, 73 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot= /dts/allwinner/sun50i-h6.dtsi index 72ce1a75647b..55e6e185a4e5 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi @@ -17,6 +17,16 @@ / { #address-cells =3D <1>; #size-cells =3D <1>; =20 + ac200_pwm_clk: ac200-clock { + compatible =3D "pwm-clock"; + #clock-cells =3D <0>; + clock-frequency =3D <24000000>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pwm1_pin>; + pwms =3D <&pwm 1 42 0>; + status =3D "disabled"; + }; + cpus { #address-cells =3D <1>; #size-cells =3D <0>; @@ -314,6 +324,15 @@ ths_calibration: thermal-sensor-calibration@14 { cpu_speed_grade: cpu-speed-grade@1c { reg =3D <0x1c 0x4>; }; + + ephy_calibration: ethernet-phy-calibration@2c,0 { + reg =3D <0x2c 1>; + bits =3D <0 4>; + }; + + ac200_bandgap: bandgap@30 { + reg =3D <0x30 2>; + }; }; =20 timer@3009000 { @@ -368,6 +387,13 @@ ext_rgmii_pins: rgmii-pins { drive-strength =3D <40>; }; =20 + ext_rmii_pins: rmii-pins { + pins =3D "PA0", "PA1", "PA2", "PA3", "PA4", + "PA5", "PA6", "PA7", "PA8", "PA9"; + function =3D "emac"; + drive-strength =3D <40>; + }; + hdmi_pins: hdmi-pins { pins =3D "PH8", "PH9", "PH10"; function =3D "hdmi"; @@ -388,6 +414,12 @@ i2c2_pins: i2c2-pins { function =3D "i2c2"; }; =20 + i2c3_pins: i2c3-pins { + pins =3D "PB17", "PB18"; + function =3D "i2c3"; + bias-pull-up; + }; + mmc0_pins: mmc0-pins { pins =3D "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; @@ -414,6 +446,11 @@ mmc2_pins: mmc2-pins { bias-pull-up; }; =20 + pwm1_pin: pwm1-pin { + pins =3D "PB19"; + function =3D "pwm1"; + }; + /omit-if-no-ref/ spi0_pins: spi0-pins { pins =3D "PC0", "PC2", "PC3"; @@ -626,6 +663,42 @@ i2c2: i2c@5002800 { #size-cells =3D <0>; }; =20 + i2c3: i2c@5002c00 { + compatible =3D "allwinner,sun50i-h6-i2c", + "allwinner,sun6i-a31-i2c"; + reg =3D <0x05002c00 0x400>; + interrupts =3D ; + clocks =3D <&ccu CLK_BUS_I2C3>; + resets =3D <&ccu RST_BUS_I2C3>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&i2c3_pins>; + clock-frequency =3D <400000>; + status =3D "disabled"; + #address-cells =3D <1>; + #size-cells =3D <0>; + + ac200: mixed-signal@10 { + compatible =3D "x-powers,ac200"; + reg =3D <0x10>; + clocks =3D <&ac200_pwm_clk>; + interrupt-parent =3D <&pio>; + interrupts =3D <1 20 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells =3D <1>; + nvmem-cells =3D <&ac200_bandgap>; + nvmem-cell-names =3D "bandgap"; + status =3D "disabled"; + + ac200_ephy_ctl: ethernet-phy-control { + compatible =3D "x-powers,ac200-ephy-ctl"; + nvmem-cells =3D <&ephy_calibration>; + nvmem-cell-names =3D "calibration"; + phy-mode =3D "rmii"; + status =3D "disabled"; + }; + }; + }; + spi0: spi@5010000 { compatible =3D "allwinner,sun50i-h6-spi", "allwinner,sun8i-h3-spi"; --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f53.google.com (mail-ot1-f53.google.com [209.85.210.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 008AC3A759D for ; Mon, 3 Aug 2026 05:15:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734155; cv=none; b=nQ1ueRTaN7rLohYdm9KnB44vKReISHN0HFCUBA3/cam0Spc/B/xs4Han8GxmiUWyk6MHRx/N6rYFjRcqxuhgA1+tmGNhorcE1LQQikjzndyEbon9ak7U19fpTrdi+oYHMQeRYugBjZ0bRIfUh7qptbqfyY58yX8eOYKP+95xfW4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734155; c=relaxed/simple; bh=gC2dTirWRvmFzKHVs4SyB39x7wyh/gb+c26PdnYQrvQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LPgGilhvy8+jwZscdudW077tgw/raHpBKf5hbXdU8xZeUO5zpuUknNm1en6ZupBD8NxtRJ4UvVst/FqMSm1Yn2j5gPcdh7DdJoMmWvjtITJ6KSXDn1X66eiQN0c7RPYNeRQbd47F17TwRN4k7OQIAU8U66PpchpmFPkM+SCgQLY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CJhRDaH1; arc=none smtp.client-ip=209.85.210.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CJhRDaH1" Received: by mail-ot1-f53.google.com with SMTP id 46e09a7af769-7e6b554044fso2627384a34.0 for ; Sun, 02 Aug 2026 22:15:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734153; x=1786338953; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=1CvTLJea6zWTpGRaWOgZzRKuhjdqcAVM/Zr8VD5aTmI=; b=CJhRDaH17sZ+f6WEkcNxZPkH95uufIyaLG4shHeV+yq5C6bXlvM68L7BmJXYwLlBpe 6/0Y7ryzQmm4lvq4h5S0TEyWNtp/1GzE1c07glZ0xxUa00sh0VeM57HXQ+g+YJe7t90P bth6hkrfQ1N/dFyJaHFgziVlKQv7D4tDWIvSc4H47MjC+Okd0pggJ99LNkPPK6W62oqe ibBCUiBXObLLdzyHEwgWIxzXXY0fol+hlUmQ3Hc20Ih8139E4IUZqcxC1qrSfD1DnQy/ VpsZbeAQdIGTuzO/2CzK9O/yRFxSbZBVtBF+raf/LAUnwSNc0tx2wWosOLXk61HTbnwc rxGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734153; x=1786338953; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=1CvTLJea6zWTpGRaWOgZzRKuhjdqcAVM/Zr8VD5aTmI=; b=CbRbyg87U1aR+G4Be1yXl0fKR68uwqtjGqWxgeyyuHbm0tc/BQUB+WeXHf4UYli2hL aMy/jhnNHV6HrynkxVV0v14kNONRq3OWZpf/6r2ymTre+2YlJTzA+6VMnSWiuI3jjJJ2 782G2QqF1LsaUaWHQEENM9Wvil0+/AjncaDJ5XIyDT3btssUttmSNZAcSqHxNwphaKb/ u+kgmMUDaLpE3wc3+bbrQHxJa0dVHIdSRdNExJdlyhbhGG1hq1zoIERHcOtUXiGFcG0o Gdg8ipXZ9PDGjSZibgaV1D9yT5duJ48nnuc8+UCquWJYLxIdzS/Y6Kt2vbdfxR/ZbXuV 6tAw== X-Forwarded-Encrypted: i=1; AHgh+RqLP+TRegMnFZVAqpbr19WLZ0jQm9GpAx4aRdcdtJQqpV4ir+4YuuluZO/7qx9X8yX4PYjlc4woXpaGQj4=@vger.kernel.org X-Gm-Message-State: AOJu0YyDmgVchMZPK6VP+E9IrVbzkk2ebU89ayetKFnU2r2hakPWCYSn 9QGvwfK3UYvcoN2kbkkkWbYEAh5YvSDGmr5KyiEypxu4tCUahEQArpcB X-Gm-Gg: AR+sD12MSP6SnHIMqv1DF7d9aDv6PeQSmCg1QrXWQv7m/7QPLvJQxqegObas4VcsVWh HzfRVPBdRzJvQexIH2X8rbuwxv0mF5hVPfI1M8giqpkkjN5/w4buCCyVutHvgorTO4kbUUAhBhR N+bzGm2z1u70E3QMoJCrh/93L3+iFKHvUo0vbzrFyppOnot8T8BRHb4hRURAq14Wx4Uo4zE0XS5 Q+FZDuDoANJ2p5l5sp8O034YV+ah6PthRaxES+UceMu71onvtjb/nc70rjtAGsFj/fV1rkTDErG JbfOsEydwdP7u5R1wIDbfo0HGvgKx0gO5Vm8qIBaY4Cl2WkcdAdnWwl5P8o2qE/ab7arEpHUBR+ Yba1WMrBV1Popt+EBKAG07NW5g1ZsRjWWupK8XdR8VwrKHSJodS7pcCzKzirCQatF067MhxK1d9 VI+028WqfWQZ/AGOgyHGtHVy2YbD1O+ANHbwSTwzZMX1Fds8jll0ufWRpnI3Q/1QBrnrbzkNlni wMS+eQxAxpsFjY/CBXVhHnB8AUoIYsgOxBCBtqW7+CcItOx9AK0NjXwZzrRgGAdWp/g3IFq4ZvD eFZLbuOefKpQw7TxbjjJsJ7LE++yUqWoxvvqXckz2w38pC4juYw+Zauh3ZMBP36/E7LYSwS3QIa 6elyx/cPt/XZc7D/a X-Received: by 2002:a05:6830:398d:b0:7dc:e090:68a with SMTP id 46e09a7af769-7f1969181f7mr14873339a34.0.1785734152850; Sun, 02 Aug 2026 22:15:52 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:52 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:30 -0600 Subject: [PATCH 20/21] arm64: dts: allwinner: h6: tanix: enable AC200 EPHY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-20-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 Enable the AC200 control path and RMII Ethernet link on the Tanix TX6 family, and provide the board's 3.3 V rail to the AC200 function supplies. Route the PHY interrupt through the AC200 interrupt controller and mark it as a wakeup source for link interrupts and magic-packet wake. Signed-off-by: James Hilliard --- arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi | 45 ++++++++++++++++++= ++++ 1 file changed, 45 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi b/arch/arm6= 4/boot/dts/allwinner/sun50i-h6-tanix.dtsi index bb7de37c0d58..6cd75961e3cc 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi @@ -7,9 +7,11 @@ #include "sun50i-h6-cpu-opp.dtsi" =20 #include +#include =20 / { aliases { + ethernet0 =3D &emac; serial0 =3D &uart0; }; =20 @@ -84,6 +86,22 @@ wifi_pwrseq: wifi-pwrseq { }; }; =20 +&ac200 { + ac-ldoin-supply =3D <®_vcc3v3>; + ephy-vcc-supply =3D <®_vcc3v3>; + rtc-vcc-supply =3D <®_vcc3v3>; + tv-vcc-supply =3D <®_vcc3v3>; + status =3D "okay"; +}; + +&ac200_ephy_ctl { + status =3D "okay"; +}; + +&ac200_pwm_clk { + status =3D "okay"; +}; + &cpu0 { cpu-supply =3D <®_vdd_cpu_gpu>; }; @@ -104,6 +122,14 @@ &ehci3 { status =3D "okay"; }; =20 +&emac { + pinctrl-names =3D "default"; + pinctrl-0 =3D <&ext_rmii_pins>; + phy-mode =3D "rmii"; + phy-handle =3D <&ac200_ephy>; + status =3D "okay"; +}; + &gpu { mali-supply =3D <®_vdd_cpu_gpu>; status =3D "okay"; @@ -119,6 +145,21 @@ hdmi_out_con: endpoint { }; }; =20 +&i2c3 { + status =3D "okay"; +}; + +&mdio { + ac200_ephy: ethernet-phy@1 { + compatible =3D "ethernet-phy-id0044.1400"; + reg =3D <1>; + interrupts-extended =3D <&ac200 AC200_IRQ_EPHY>; + wakeup-source; + x-powers,ac200-control =3D <&ac200_ephy_ctl>; + x-powers,xmii-rx-clock-inverted; + }; +}; + &mmc0 { pinctrl-names =3D "default"; pinctrl-0 =3D <&mmc0_pins>; @@ -162,6 +203,10 @@ &pio { vcc-pg-supply =3D <®_vcc1v8>; }; =20 +&pwm { + status =3D "okay"; +}; + &r_ir { status =3D "okay"; }; --=20 2.53.0 From nobody Fri Oct 2 09:22:01 2026 Received: from mail-ot1-f52.google.com (mail-ot1-f52.google.com [209.85.210.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07D4E3A9DAE for ; Mon, 3 Aug 2026 05:15:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734158; cv=none; b=Bll7oF/Y/7+WOE15CC9cEkHZ8tWoOuGCPaR1C8CWFNV5Tm2SxKbPFzykhcixUtjzxWcozjFRYhXNKP8tGG8qwN8Um5aq4FHEZXGzmx+BoiiUNLoqbP/Jy+Z9OQh0b2gEt22dWioQM2ogSt0K0NmPetb3jlX0NfIzHsuawPjnj2c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785734158; c=relaxed/simple; bh=GJHoT3sGNBaHJutusjqByQrs0uUzgfDmspxJwWo+2Fw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hzexnf/JYGO7h9siuscLVUvJSEk6C/w9xItH+YKk6q2IqI44UTEdxLEjCCCX6lDOwAcHDPdRMsqPMC8HdofhLmhW/w0wo2vnbv16/oo0m58tO1hpBIi4mWXL8NB8aSIaOjkS08AlGr/zcctCsahSZR+dos00H3spDg+3LgZFcns= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ST7HRXPc; arc=none smtp.client-ip=209.85.210.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ST7HRXPc" Received: by mail-ot1-f52.google.com with SMTP id 46e09a7af769-7e6b5737bb2so2730435a34.1 for ; Sun, 02 Aug 2026 22:15:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785734156; x=1786338956; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=V3THAfFmoIZwxbw2uyAABLxKH+fs/K6w42J64CA1198=; b=ST7HRXPcMmjr8vPiDHuHugjkiSSNt3m0EpUVbjXGoiYvVT5I0gKXO6JAo7NLtNiUVC Rrc5Z4ktBlZQNsbKV/S4nZFVjXmJDerLjH7tOsxlMPfs39MRtpumznRqzC7ylUavnS3c 2sGZaE8ZAfGJKWGcGSC1L+gEvxSt9P8V/k8LPWcvZaqqYwZtpblw56G/3XEKjzSzb0Pl a+6bmeMrU9ib/z6d2YzGs0UJshembYC8vPrVMgjvATJp3ptyi3gEj0elgUIqXJ080fH0 ELO8x7RqToUhtY1wPBACNpUElgHTQ93HYtlU3586S4A8/HUuJY4xAfiPmOmF3N8jORq+ ISRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785734156; x=1786338956; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=V3THAfFmoIZwxbw2uyAABLxKH+fs/K6w42J64CA1198=; b=lBEqrfe1mPt4akm0ObeXKMOQR9lrE0NPSmqE2FOf+1z9/9gnrgf9jaFo9vY28G52bE MUaj+2FCnJEhL8F+Jj+rGiKYx2ioZXdtgvBd/wMhJLAIV7VfnaMeJHubhbE20bwLHyvD so4TPg9GX8nq80ju+VAaXuhc6rhxlbXbdC3AQxnlkvkTavy2Wm18fofbku4yLdWcnyYn hbW9VjJky+RrfILMlMEax9DehpvunQ2gFFyz5r/xqw/DxElPkVoOTjNITVX6BTVt7p7s TA/zEWJExq8XTcT5iaUU2AjWnaakLcNSfejFvEsE9naj+caY1g27jlaBQt2tvIVt9JHZ nRcQ== X-Forwarded-Encrypted: i=1; AHgh+Ro2ePsoVfIMlZcLaSzybwzBAm8kyuf8B4w/YxAGUp4rrN7vt5aklbtN1niR+wiQa1V2GDbaEqRKK67sxOc=@vger.kernel.org X-Gm-Message-State: AOJu0Yy4HQcl2a2MunsuJbFjfN2A3XqdRVzQNCrqsZZ+pSVBZJari/Wn PRf9AKCUB41Q5W0q3ff4m0dtMl9Bu6uifmBkxEk+ocEf8W+DM0OOTwck X-Gm-Gg: AR+sD11kle8MZoPDx/2Rjhs9N4M80PkWgVo3gquK7XC7nG2H4C/aDGYucHtii2XyhcV CSevfoAdeFWUN6zlE7glg9ckiCijWhKbRW+rIUaOQW+1vNq1UB8zhWuP45Jnsn2b6seKZyoRe7y 43LqOOKIOwQJpVAMOUsui3ecf25+GSym0IHgzoPjqdWMcT3fIfpqOwBgx2E9r89d64YybSbIvlP mEUW1Kgd2Ta26mY95Lg4DXSapABeeal5BPKWLPfhNLv6ltixRrjKN9EPMiuBwYXzzril8SUskKP 3wh9xcWrj+fP/RfZngkxz0mxMOOXHQKwxn7fChrtRQKDOqGpvmCo09coCVd2dbQ8tTOdDvA2YE1 vzY/1/iQQ+/w5y/XL4TWMqsjwtKzVDwdt0LtSTT3oJxtJAvfVMSmogQ+cUcbaEa9ULBNeQRS9sC Mu0ddZdMZIknGhGQ19uKRlqk33v2HpNBwo6IqUXKD36ic074E+6VPl7ChWiJISIGu4k2K5ebhET WqQW5nr08hRPCFw7yA1Mz1WvOJHvN0zLhIOgSfjyiJda0T3LXA67z71f5m76SjWcngnEHH5YsOW gk7SvqtC+jDcz8R/wkArWIdsacWuy3D4dnEOkVQKegAB3jquQyjKx1c5ksQDo1+VnGD5xSMoLtf 9yE3fld7zJIDGiaOYPFiR1uKoLvuF9JTF8JdL X-Received: by 2002:a05:6830:2a8b:b0:7e6:f7fb:9678 with SMTP id 46e09a7af769-7f196cb65a7mr14526881a34.1.1785734154482; Sun, 02 Aug 2026 22:15:54 -0700 (PDT) Received: from [127.0.1.1] (184-96-154-59.hlrn.qwest.net. [184.96.154.59]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7f18f07a5e3sm6787108a34.15.2026.08.02.22.15.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 22:15:54 -0700 (PDT) From: James Hilliard Date: Sun, 02 Aug 2026 23:14:31 -0600 Subject: [PATCH 21/21] arm64: defconfig: enable X-Powers ACx00 Ethernet support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-submit-acx00-of-dynamic-v1-v1-21-0a53cd9e21cc@gmail.com> References: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> In-Reply-To: <20260802-submit-acx00-of-dynamic-v1-v1-0-0a53cd9e21cc@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Andre Przywara , Richard Genoud , Maxime Ripard , Alexandre Torgue , Giuseppe Cavallaro , Jose Abreu , Maxime Chevallier , Maxime Coquelin , Andrew Lunn , Heiner Kallweit , Russell King , Saravana Kannan , Lee Jones , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, mfd@lists.linux.dev, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 Build the H616 PWM clock provider, AC200 MFD, both variant-specific EPHY control drivers and the shared link-PHY driver as modules. Enable the netdev LED trigger as a module so DT-described PHY LEDs can use hardware offload. Signed-off-by: James Hilliard --- arch/arm64/configs/defconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 654a102cb5bc..53f6b8edaf33 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -475,6 +475,9 @@ CONFIG_DP83869_PHY=3Dm CONFIG_DP83TD510_PHY=3Dy CONFIG_DP83TG720_PHY=3Dm CONFIG_VITESSE_PHY=3Dy +CONFIG_XPOWERS_AC200_PHY_CTL=3Dm +CONFIG_XPOWERS_AC300_PHY_CTL=3Dm +CONFIG_XPOWERS_ACX00_PHY=3Dm CONFIG_XILINX_GMII2RGMII=3Dm CONFIG_CAN_FLEXCAN=3Dm CONFIG_CAN_XILINXCAN=3Dm @@ -828,6 +831,7 @@ CONFIG_BCM7038_WDT=3Dm CONFIG_MFD_ADP5585=3Dm CONFIG_MFD_ALTERA_SYSMGR=3Dy CONFIG_MFD_BD9571MWV=3Dy +CONFIG_MFD_AC200=3Dm CONFIG_MFD_AXP20X_I2C=3Dy CONFIG_MFD_AXP20X_RSB=3Dy CONFIG_MFD_MACSMC=3Dm @@ -1325,6 +1329,7 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=3Dy CONFIG_LEDS_TRIGGER_CPU=3Dy CONFIG_LEDS_TRIGGER_DEFAULT_ON=3Dy CONFIG_LEDS_TRIGGER_PANIC=3Dy +CONFIG_LEDS_TRIGGER_NETDEV=3Dm CONFIG_EDAC=3Dy CONFIG_EDAC_GHES=3Dy CONFIG_EDAC_LAYERSCAPE=3Dm @@ -1726,6 +1731,7 @@ CONFIG_PWM_SAMSUNG=3Dy CONFIG_PWM_SL28CPLD=3Dm CONFIG_PWM_STM32=3Dm CONFIG_PWM_SUN4I=3Dm +CONFIG_PWM_SUN8I=3Dm CONFIG_PWM_TEGRA=3Dm CONFIG_PWM_TIECAP=3Dm CONFIG_PWM_TIEHRPWM=3Dm --=20 2.53.0