From nobody Fri Oct 2 05:31:05 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 5AD713BCD2E for ; Wed, 5 Aug 2026 02:28:30 +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=1785896911; cv=none; b=LtpB1EssKqJdwGsla871fO9Ixj8BZHTjayj7l3Uj9QAbWw68jhXKwlyK+xPvVBrcPxNjhVv+5HchqYyefMtuSDSv0hqHZF+dIOEem+lLOBBUTpE9nqhZ7bZRRFu3bAiuVX3CBHQbR88koG5jjuGKVD07/mZ/zvOcrVz/DggMBNU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896911; c=relaxed/simple; bh=R6g0JPwxdv7PypX7v84NybJBf7f2xtEhtnKMo6TTQpE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hGBXTgwp02eEtCHu0E/6mpthhUM6IXeUmJHLR/dFw9xaJ45e2yAIcexKFYuLXrKr46eMXcP/eS0QJ40Y2J2coWBF0kGQr+vx/Tu3PutHC1GF2P1EdV2fZZ1OtG8kpfF1AwIGmDQLDnEaMfV93QUclRke7T0yZ/lyCFS/iHMVNC8= 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=kqGjSr+o; 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="kqGjSr+o" Received: by mail-ot1-f52.google.com with SMTP id 46e09a7af769-7eb545db3afso406348a34.0 for ; Tue, 04 Aug 2026 19:28:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896909; x=1786501709; 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=azC4yJVvIjculgK3P7AokYSHVCXvbgOhfjCyepYSyOo=; b=kqGjSr+oa9DN+NL0fyYNKVaFUIJrRBsEzIyoQRoXuSXn0+eazbdjEHfBT5SvKPwpKr rSjqHe7BNmlBoPxlWCfHyhLbbOsHAzwV34f2raJvc9fQS1gZ1plRKRzMw4GI18URKzA3 N5XSt0iZk7sKQXZKqQj5C7lKgQPNQVPcyGX/xA/pei/tkVBrNc95ZuzgTGuJMzRNIyu9 J3WEEkSzAAtfrH0MehIFL0KSyAP2RHLsFw6zjLXYo+Ybmd+/QT3Ou1s76I5Yj/LaTxln y8XWL8NgfsPTQHzmy1vCoKGfL3rJ1fLSELf1Gimx2iKKYmVPOdMchtFLx8BAw/3iZpzE pxDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896909; x=1786501709; 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=azC4yJVvIjculgK3P7AokYSHVCXvbgOhfjCyepYSyOo=; b=KPjqqQDPruZW6CQma743FHzBLf/x01dIH/v0v5IStEt/OzFYG4K62AKbU/+6nKHMIC qGL6r+yrak1Jg/5e2qBHMhD2tzKCmriy93QsK9p5GPdkZ9mIfiyvq+vHVDoCuDxwuZRZ xZVVsp1eicPAR+WgSDEVWnxePLxfOKNg3hHLVXzVO3Hnm35kpZTvKYseF633kng3mKfK oYEoFYniJ2H9C6CmDmnTJ1kOdYOqUUNWnOL2t5yA4EwdhNb3v9L1m2uA24eS3pVnBInD 7ip5HH5fkc3tCRXJExZWJqMYFat/Bc0p9ANDYTMMEUDJ1D66T+hrj0iFZz8KwxdnnZ2Z gU/A== X-Forwarded-Encrypted: i=1; AHgh+Ro6V9/TDbHuRisivkNYANcJlXi284MtJubbv5w1vYqH0fCXrIk7sL6Qywxyoc0wE95ZnoYm+EpPd2rEk2w=@vger.kernel.org X-Gm-Message-State: AOJu0Yyp+Xt2GjRyUO2a1P4v20M0nvpgAIOS6CF5mpE+SQTRIKkgIJme b2BUzoykE0/zIsK2JYaLCB/ONj0zQ2cxxatbJ/xAS+s27Sfhh+fJdf6A X-Gm-Gg: AR+sD11BPjoMobyfhH5rIKCCsXQzunN8/PaX4AA5aH7I8nR4oryMClPUCRSVQD/tXkx aaWEWsC/XUGVXwaP8NsWaC5GzTTTGrJUMf3Jw5g4EIVUM+9INM22/8yBW1LAP5RuzQgPXmGBl1x oYCWEQs7e8O0LRiTGw0Ho4wAaBPbmos7xK9nYchM99wABPUSSjCH6zCqw7IA8SxH6jjG3AFpjxP FCl+CIt75Zi2trlo2jEWTTVUiPhTSdd6Yw4KEMvs+mbSbLtssfgagqQjJuE607jqpiOejpjl4BA /ujcwxfBr5yKBsTJlq1FBneTdRuL+ccOfZzEalCSN11SCDk1oMbgJD5dekQd+DeY4MkzoD4c5xn BAWjG5FOUMdKlUNI8KpnEjrd7RWZoRgZ1wG93v9l5mLRnWmfCVZjhjTV563NO3uS6v4Ro0NDKc9 oVv5399Nk4J+9wwfh+U18TbLy1eDLW6lyv14yyi+E8hxt3iPJ8PrTC7E/wg8pLbcWtdoqMODjN6 akcT7PjQ4K/e8V2TIQcBxjKfHGxXvXhPp9hnnB5hVngroTNW+k796lBVQ+LFDMbybFoHhcPPnQU LugTZeU66jZIwTFlv3sFG8AbPA6YlipDD3CaRIqRlMxiYIQZmsRevdFASi0/42D5orbvEZ2FX0C nUEB2ebU9yOSp+siz X-Received: by 2002:a05:6830:2116:b0:7d7:ed69:81b2 with SMTP id 46e09a7af769-7f1e5d0f2e8mr2637298a34.5.1785896909187; Tue, 04 Aug 2026 19:28:29 -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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:28 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:26:59 -0600 Subject: [PATCH net-next v2 1/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-1-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC200 contains a Fast Ethernet PHY whose power, calibration and interface-selection registers are accessed through the parent AC200 I2C regmap. Describe this control function and its optional SoC SID calibration cell. The vendor sequence adds three to the calibration value modulo 16 before writing BPS_EFFUSE. If the cell is omitted, the driver reads the AC200's internal copy of the calibration eFuse. This node represents the package control logic, not the Clause 22 PHY. The latter remains a separate ethernet-phy node on the MDIO bus, which supplies its address and the MAC-selected interface mode at runtime. Signed-off-by: James Hilliard --- .../bindings/net/x-powers,ac200-ephy-ctl.yaml | 39 ++++++++++++++++++= ++++ 1 file changed, 39 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..5bb60542030f --- /dev/null +++ b/Documentation/devicetree/bindings/net/x-powers,ac200-ephy-ctl.yaml @@ -0,0 +1,39 @@ +# 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 + +required: + - compatible + +dependentRequired: + nvmem-cells: [ nvmem-cell-names ] + +additionalProperties: false +... --=20 2.53.0 From nobody Fri Oct 2 05:31:05 2026 Received: from mail-oi1-f172.google.com (mail-oi1-f172.google.com [209.85.167.172]) (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 411E13C13F8 for ; Wed, 5 Aug 2026 02:28:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896912; cv=none; b=OuYhediK9WU103W9IXBaCz7ZejXX8YHNcnxvYC6ymy32S8s+VpBxISrkq72p7+KmTXP9eflLWnstZnN8kQfjGTqLTsxX4zNDmzP0SUtPB6VbYHTQwtNI0ntp1uEjwQck8IxP43Ms6p10OZj9SctPQ2Ls0L+g968evk69HNNGFBc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896912; c=relaxed/simple; bh=88UypGhQr4MP1727IeMqM86/bOK2bO2zPytpS8FWMYY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BRJydhEv34aD76mzDZhN4povXBWQ8Ve7CoYbcukKGgOUOhhc0upX5cxs+WNkc5yLNBIKBC9n622Kkz9z8tabyz03IQyywmX5FRwQwaHfy2yd7IidNUIdMMaq0dXVVUa+Up+P+LLiFWbLE/OsbpVjSV208iAEN0AKdRXNp3COJig= 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=HQYFeqyC; arc=none smtp.client-ip=209.85.167.172 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="HQYFeqyC" Received: by mail-oi1-f172.google.com with SMTP id 5614622812f47-495b98b4f6aso204065b6e.2 for ; Tue, 04 Aug 2026 19:28:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896910; x=1786501710; 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=YY4CB5Vy00/NtteUzUzKZor/e0ptbflg+HuPiVWnSpQ=; b=HQYFeqyC6g73v1blqhBI+lUkgIfdYbzUbkPFcY3kVNNkbEpdels376cKUzBqQ+3/Vc B8Pf6uG+dk3QAIkK/z3cbcXC2eooHpmn2KKaVC8N05VtpHKbC71f9vgZihnnDYOEwUw9 d4wmeEeXKE4dtnmaWE2QSV6Al07fUqsl3CDHhjG5CqB/UPvIOdxPDLZ3XodjjyoUCcan OZD4Fk8m1Fnb5+lEGU6oSi3vOCAwuNFnKXnhK86dJWfddXtJB0+GPmQ7hsQw45YANib6 kEV8iApfxGyQ/oATK+8/f95yhH/X7E3tLgzKQ5JJ3Z2nZ6MKQg+uq9HC0WaNsiVWbMLa sG4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896910; x=1786501710; 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=YY4CB5Vy00/NtteUzUzKZor/e0ptbflg+HuPiVWnSpQ=; b=YnsP78w4zpjK1A8J6utBcfqQDX9oCX7JoOa1QSMcYjZYSfHKXk5GPOQVlHGfATuFbN PtiHm3fVfrUT/ceDqLy01RaaIL6rn1IzpmtChxipPmOysRy5PhElE4q0bvNlMx7Vh4hs LSb1IegqzNpPfJFYEjo65KFICdYV9viZc7ZnM0kJ3/S95tpz7D3C7fg5TnPYNutEUmDI tcowbfNMA8pPLMJ6rStFof00PWebZg9O7YehYEeSVrjtpyuJKsD1EFTcXY/4iZT9tVVk JUUnXE0xBG1S3nx0Wa1i5f/9IkBckTzDwUZ4EPXnTwDkLfCZSy44WihR/8CnrUGe9CLh zxeA== X-Forwarded-Encrypted: i=1; AHgh+Rp02fMQ60vzxUFBsiQADlSB++otOIKeT0zd5yirAbZarh5NCD8gePQ/2NfRx1hIm2zYGeDKhOL70kZjovw=@vger.kernel.org X-Gm-Message-State: AOJu0YwKb+Crg9+d0kyopK1M0XAgqPdv/fVYON+7hBfcPIp1OwGZwlrd hSRNrcHzpANgp42Gnhe00NohVCQDnQklQOqmRMDXeMixEt3cnXU6vRNE X-Gm-Gg: AR+sD13KnzvDwZ9atFIAbv4c7lj9LLmriMaFcwYh2TZQwHgdTOFio199j+NgKrEzzNV N3KEBwEExAzW3yVKjX4s4Z7ylE/0m6Tkz7/7WhmmBQAWZS4eHN/rM79AM4KO1jNiFg+FSd0RFPS T9hZasRwYCyoa+fRvzz5NALySdB+kepldXKePBQkj3HeoeIG2r1RuCtPIwYa6LzixAW6Q7UoKV0 gns5lNUUaV/lrxCc3zCnbv2nVKQSOmvhu60SjVNJeOOByXxi6BJSyKkS/WV8qUtOqU48AtKRDr6 /s+YUT9YR+V+oOTWG/0k1quNpfLAiQPGINE8bIcdNB8KTk2lUNJLeiWDaZhIPSvQPEAATx/RzUb d5JPZlshfF7103Lz51Jst/dJ9LsfmkmZNfqnG5L6ELF+nOD6IpDX210tA0eYMICHBNxQPbwt6v6 YUeDUwHEtXmozrw3eRNzHjEuRrUWcOo6yWPnnOmCnAl0JeGGiL5wr5A9aYV6pbtGhXhAHqszHHk A4dvyXSQSegDbo0u2VgT7UqaJ2m5U5yL6npcpb3b7RB1UGiHly8/pMZrwdEZbUNC1Q3xL4fP2go d9uXAig8eXjCML9OTHIFZBGhvoZM0lTW++8hYNUM+WlF5xvSTQ0SkJEAOwm9NUAFto9LjGPYTpB KD5PzL/IGekXDXO1w X-Received: by 2002:a4a:ee12:0:b0:6a0:a791:6885 with SMTP id 006d021491bc7-6ae96ed36f7mr2063730eaf.23.1785896910119; Tue, 04 Aug 2026 19:28: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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:29 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:27:00 -0600 Subject: [PATCH net-next v2 2/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-2-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, 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, the four package supplies and its optional Ethernet PHY control child. The input clock must run at 24 or 27 MHz when the Ethernet PHY is used, matching the rates encoded by the documented EPHY clock selector. Interrupt-controller and TV-encoder calibration properties can be added with the child functions which consume them; the initial binding covers only the common core and Ethernet control child implemented here. Signed-off-by: James Hilliard --- .../devicetree/bindings/mfd/x-powers,ac200.yaml | 77 ++++++++++++++++++= ++++ 1 file changed, 77 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..4ea56e99c370 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/x-powers,ac200.yaml @@ -0,0 +1,77 @@ +# 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. + + 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 + + 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 + +additionalProperties: false + +examples: + - | + 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>; + ethernet-phy-control { + compatible =3D "x-powers,ac200-ephy-ctl"; + nvmem-cells =3D <&ephy_calibration>; + nvmem-cell-names =3D "calibration"; + }; + }; + }; +... --=20 2.53.0 From nobody Fri Oct 2 05:31:05 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 13F6F3BE14D for ; Wed, 5 Aug 2026 02:28:32 +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=1785896915; cv=none; b=UVK4NhxcLqIKZhcSS7IkyZFGSiVFAuvl75MPgNg0ESTOLBUgOToKeBrBkwx9u5VTBOgP4kDt5SNHE5VCjtI/lELeDHjQnlSsj72BGknqJ5od4qzj722wke9X2m2rs7F+tqJgYtVEjC/OJIKaGfQhQ9uTAi90z30Z9WvkJXhVv7Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896915; c=relaxed/simple; bh=+Kl7/o2g51rZtXOjQPCwpj9s8N21QOoMJZkvyli0wKU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oUsXhJ6bXzD8DwlN2ijTSqUV1RaHiCohqnP9SG1rPOrrn5ZbrzhTyXk+vRAqQ8WCPIpWgzPPr/nlHm2K6xMHHXH/AtF+fsTsQ4lx3B6OHgvFWUa5E4YXdndd3ko05XB0utrwsQeZ5Vh+AGS5vL/xe0LX6c41TyLimGY7jfuRxOA= 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=rVQVvuBP; 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="rVQVvuBP" Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-7eb545db3afso406368a34.0 for ; Tue, 04 Aug 2026 19:28:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896912; x=1786501712; 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=DteK7ahJcWyyf0jNlGCUan3gdCG+7fB8ZCtaU7OCkNA=; b=rVQVvuBPSsZM9otAH5YW2fUxM7boEpwGk/3/at8bkCC7S0zPIayw/w0OZLzoiCobiY Qsey8RWj193DNFmmjZCT2EsGmZTodnIY88mQHOGJy9HmpjmVmUEcc2rf4ter6S1dUUf6 vqV/7FG8wMu1PqSuZSWMZQj91wBhJz+yni2OGtJHYgDTogeO4vOuRyFiQ59v2kw8Ibpe RAOBp2oLpVrE6sMSggzOogYRy/Az0iMz9S6rto3kjIgGcyRVzoP4/+3NCEZcrOfdW+WQ Q4MrnVgqiMtPiVk5gHiwS90hcSOdJ0lHMuWygH+q1Pb8uu4p27iTLpgaXkr3jC9gkwwY 63Mg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896912; x=1786501712; 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=DteK7ahJcWyyf0jNlGCUan3gdCG+7fB8ZCtaU7OCkNA=; b=RiJNeNrMOSATHFzYgyeoGje4QBxj+JhcA1ecwmlSh64822D1E3do97uSxMU9DSvvdX ltkGTrhq3Md1n3hrqzHwY+aAN3Vnz/7vJX7LVK7ehDbvhRCfLdgy012B9jeixtKNqfIo tiUtmL5DcW8Ad4WXsG/DUQqPsZd1/YWHULNPgVWsLdHZ6J08PG50xG3bzwZ/RI8tecbT W8eUasnl8FPSRThYwuyzV5P9q+ZVb3Yj6QNEG7UftiGEUyoOeltBOve83khD/TJQqH6Q ozgWacDC/U9EsqCeP0xrNhUEIDFYBdZjyLj7RU3eY5ISex4X1NlQ555a60NtrU/xh7CV Qt1g== X-Forwarded-Encrypted: i=1; AHgh+RqTRr3fRQISbDDGdX+i90GZplIYaJeGDoGIAvkpkQH8IjfdozbYmlq+dO191atPqDaRFdTKav27iGYfIlA=@vger.kernel.org X-Gm-Message-State: AOJu0YyLgNNS7NdsQvH8XFO6HbvkMFrH60U+u5CjUEcHzZdAj1c+96oo dR4j330PwUSHKMvuCh0Dpmz63vGilVw+yrsYIjTsnQanxiAawDwqYvSy X-Gm-Gg: AR+sD11F36TEdnznBtUmrdoVN+80WmaDRlV7VLG3wtYyyJTrpT23xJLjmU2pFN6hSw5 NPwlKx1/322rYLAiwnOGoKECg5KPEOIOkk0K971e5Wp8KRL993SXyRdJZZ1kWQnpwPZBd3Ju66g GZtSe3W4ZwvwdD0a7N91A6V0NFGybM2MBUOjhnWs1zbAKyAdV9m9mVqIUywdhzmZ9i9vBoLJtXG +j4ox9aYVdwhYY9uPBLhZVYisdzP8n+QjxYC/JSLINNuEk50ddop6p2NwBCEICq4OEpnURLSCL8 Fc9VLP9T02NZ0rev6W7HxsZ2uArMIOjuRJEM3xxFUm9DrD5NFRQGDEWbZk/2TXFa8xsbO9eh5fQ t7T2TVitNwejY2+MaYKfT86qpKycB3XLjsOknl5gH0KLOLSKsCHlnB1bBe1sJwtqIv6A0zQaBGt AcLBKaRlHYIM1XCPqqnL/9Gl5P0KAi4kwzpZQMIZuFIKFlzT5eAeaoRAtbwKmKM4RQuFTSP1oxX Wz7kqP22YlUcF/zlU+ZZgWS7RWjmDpmma90CnQLtYLufXIi9ZCd0dC/BBjj2NWFod9Sxe5SHIQn x/hVvI9Hq/5dibUtfET+Oou2SU0bzaRgdaIFDZ3J2qAgvL81P5E3jV5IxN+GPh0apTWdS1L9zcI tkpxwWOqvUbd6gnVh X-Received: by 2002:a05:6830:290a:b0:7f1:ddf1:c731 with SMTP id 46e09a7af769-7f1e5f6ca2dmr2589356a34.13.1785896911128; Tue, 04 Aug 2026 19:28:31 -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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:30 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:27:01 -0600 Subject: [PATCH net-next v2 3/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-3-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, 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 the package supplies and input clock, prevent the clock rate from changing, and apply the vendor settling delays around common reset. Initialize the paged regmap, report the chip and package revision, and instantiate the Ethernet PHY control child when firmware describes it. Cache only the common page selector. Individual function resets can invalidate other registers without regmap's knowledge, so all functional registers remain volatile. The AC200 and its children cannot initiate DMA. Mark the parent as DMA-incapable before adding the child. Register the common-reset action before the MFD child so managed teardown removes the child before resetting its parent, and also reset the chip during system shutdown. Signed-off-by: James Hilliard --- drivers/mfd/Kconfig | 12 +++ drivers/mfd/Makefile | 1 + drivers/mfd/ac200.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 220 insertions(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 763ce6a34782..3360c9b86be8 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -205,6 +205,18 @@ 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 + 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..dd31205fe698 --- /dev/null +++ b/drivers/mfd/ac200.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MFD core driver for the X-Powers AC200 + * + * Copyright (C) 2019 Jernej Skrabec + * Copyright (C) 2026 James Hilliard + * + * Based on the AC100 driver: + * Copyright (C) 2016 Chen-Yu Tsai + */ + +#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) + +/* 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 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_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; + 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); + + /* + * 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; + + /* Match the settling interval used by the vendor initialization. */ + usleep_range(1000, 2000); + + /* 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; + + ret =3D devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, ac200_cells, + ARRAY_SIZE(ac200_cells), NULL, 0, NULL); + if (ret) + return dev_err_probe(dev, ret, "failed to add MFD devices\n"); + + return 0; +} + +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 05:31:05 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 9F64B3C3F67 for ; Wed, 5 Aug 2026 02:28:33 +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=1785896916; cv=none; b=N1SMXW+KJa+tGs/DBhe6WN3y6ZcgN7SkTCibt4KtxHnWP7kXUyrXhQBSWbBjMFCin0fIF0ImUuaimtjagFb/zJCiewsYqcWMGLikUltz20PGYY8DFNPS6AkJiqDnjFQMbq6j2iqjCGjMkf8wguK9ecEM0+5dm171PtGEJZVWf6A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896916; c=relaxed/simple; bh=EtsvSPxIGmlk0h5JqXOaBe4OHq/KZ7Qoebh3PMfLeHY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=j/q9u1QrbXgVAsfNrkitJUktAZ8xWV2mXR4hsYR6+dKXWvzqHuqJ1agjqYw2Me5o1n2T4p1sxbyetPt4CN6hrM3qsETM0bbYSrHIqRtH8oJFS0hlOjIlLSZRnXQ75twmOfM+pI0ZUGF6MyDGwF1vR8FKp89q38x9JajuYporRD4= 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=h9EbTRC6; 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="h9EbTRC6" Received: by mail-ot1-f54.google.com with SMTP id 46e09a7af769-7eb29ed2bbdso212734a34.2 for ; Tue, 04 Aug 2026 19:28:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896912; x=1786501712; 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=D64PmTVEKzBZLdk+xtOtavancebLmpSxAZFhbcTQDwg=; b=h9EbTRC6dI7ckeJ66ZrgXCSCeO9HBbd58YCESeF0q7e5yzZy1IMktkbskRKTVyBRIH 5huMzZDGswKly39/o3F00UAaxIEWMbjEhgcIehBYPUidA45VtTfC0MsL7xtzffZ+Zsgd HMba2YcGUD/OKDumC8QMzK0Q1UmJbmEJtB1hbaLTBbcKXrZrsr8DhL/TzK1Xpo2GR4Vu lbP0ALCXwmGuv4A3Wb+KFevhlKLveILLZGThEgE1TyaVptR1hy2Tafq7udFIAUBLs7Fa RnVRLz+N0jvXKGs9TNSbJid61bitSYqXzsyemJpTVo6DMvspCMi/2u2wy5lIMQj3sJTq P0AQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896912; x=1786501712; 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=D64PmTVEKzBZLdk+xtOtavancebLmpSxAZFhbcTQDwg=; b=SbelAcPDFTxnqALsdHDFI2vELXFY42d9IKTuDGhiV0Aui3FSwot85bbytz3dd5AnbC vCM80midN4V4LOSaXh93qNIUWOa2Av1LXCMbcWP0TVJnSkt4aa+QhyOY4dTDDV9TZZxJ VirV80uzDLW/7rxCli47CoFANEHzRgUtZasyqf/09qg4mF2yoU10n1qVl0N9tcyMxqL1 5oUVKrNDITyoxXBsmhRFi03LYRbkqIgrS38ORJzWZ3u3o9rQL8IjxTADcxSk2BLgn8a2 ZXG/gF2xsd00BmK7i7sEGpcZLv8e/AoitPwE062zBVhPtgn4hVDjQUBr+g+Jq83BxbpJ zHWA== X-Forwarded-Encrypted: i=1; AHgh+RrX3wlTKgD0JXE4oozEYW8XZLrFQKF/BDhMcwJoAcuv0wFJ2czxjrldIblqzdHZqaG67X16J5ySWFT/yhg=@vger.kernel.org X-Gm-Message-State: AOJu0YzKb472gxqCFzdZjW7aaMlmqy+a5VUWTFKaFtsvt5YZ/GVphd48 SdZmsLrH5Ksh1TMe7m2si4RNtJAjLx3L4dNGpz57//fRivKja9J979X1 X-Gm-Gg: AR+sD12JfAIvbjXnI1wKRA0Q1bj1H8gwubuRinTEc/uMAOKmXzEwavOVBpZdjqEj9U3 ZG6maGZuF9x6r3kjI4C376fr4TUFIE7w83YGkZMqhGRwKbuVG8WR0Vd7twoTt+98wZZAzfJpVxN 3ueqXDqI0p2sl9H8Y8i753j7kwB3UVBCflHOkauu8F67LgWQnylE7/NyhhTItQFU4twnXTI+a2g /R+jisIu1jmyLJf+Ppl7EkuaW8KHeZtEtqMZIBuOMjZobcT19We/UoUWxfhd7RMYMxWdrQn0lTp oTUC4bmj4hazLoAe1/BOb5Y5gyTehao4igqFgvmcMm2/Wd8BPVSC31DDktAXNY/nOMLOVH0bXUW 1A4GC9XoEj+RkvqCBMjRJRPeLRprWUVR4bqG5bS7yDv0sZHFSzRfYn0l/ypGkmegxSAvGwpMRqR LsPTsmnzw0YU2V3mb/oPrK7fny5iNs4Y/ZAH0tNepyPNFqgW31lFmGgFTSY9eMp4C7h2+FKpCso snii/18AdJUXX3c5TFBmVkOMDvQ+W8T6xGc7EWGvW/W2a+UEtHE2rmRFpJM2ycGuef+VYxblNpy E5lMNe3sJZSNLlujqcP2luKi+ojs1FP4Zzf3mIADbf0SdnFjxPH5KCLAYLDNHdDeE/nvYE/Ntn4 29yQbH36iepnGNTVn X-Received: by 2002:a05:6830:828e:b0:7dc:c4ae:a689 with SMTP id 46e09a7af769-7f1e5c13d47mr2668638a34.2.1785896912411; Tue, 04 Aug 2026 19:28: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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:31 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:27:02 -0600 Subject: [PATCH net-next v2 4/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-4-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC200 Fast Ethernet PHY needs package registers in the parent I2C regmap to be configured before its Clause 22 endpoint becomes usable. Add a control driver which obtains the calibration value, applies the vendor offset, selects the documented 24 or 27 MHz input clock, programs the link PHY address and performs the required reset, clock and shutdown sequence. Use the optional SoC SID cell when supplied and otherwise read the AC200's internal calibration eFuse. Early PHY creation occurs before a MAC has attached, so use reset-default MII initially. A separate operation later applies phydev->interface; when the block is already powered it changes only RMII_SEL before the normal PHY soft reset. Expose serialized, idempotent power and interface operations to the common PHY driver. Enable only the MII I/O pads in this basic driver; dedicated LED outputs remain disabled until a later LED patch describes and manages them. Signed-off-by: James Hilliard --- drivers/net/phy/Kconfig | 9 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/xpowers-ac200-ctl.c | 294 ++++++++++++++++++++++++++++++++= ++++ drivers/net/phy/xpowers-acx00.h | 15 ++ 4 files changed, 319 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a29d3fed8a05..6119f4de880d 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -475,6 +475,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 e23df5e836e9..f81854fc9f12 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -100,4 +100,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..c69e6a8c71a4 --- /dev/null +++ b/drivers/net/phy/xpowers-ac200-ctl.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * X-Powers AC200 Ethernet PHY control driver + * + * Copyright (c) 2022 Arm Ltd. (Andre Przywara ) + * 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) + +/* 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_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; + unsigned int phy_addr; + phy_interface_t interface; + bool powered; +}; + +static u16 ac200_ephy_ctl_config(const struct ac200_ephy_ctl *priv) +{ + return priv->ephy_ctl | + (priv->interface =3D=3D PHY_INTERFACE_MODE_RMII ? + AC200_EPHY_RMII_SEL : 0) | + FIELD_PREP(AC200_EPHY_PHY_ADDR_MASK, priv->phy_addr); +} + +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, + ac200_ephy_ctl_config(priv) | 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_set_interface(struct acx00_ephy_control *control, + phy_interface_t interface) +{ + struct ac200_ephy_ctl *priv =3D + container_of(control, struct ac200_ephy_ctl, control); + u16 value; + int ret =3D 0; + + switch (interface) { + case PHY_INTERFACE_MODE_MII: + value =3D 0; + break; + case PHY_INTERFACE_MODE_RMII: + value =3D AC200_EPHY_RMII_SEL; + break; + default: + return -EINVAL; + } + + mutex_lock(&priv->lock); + if (priv->interface =3D=3D interface) + goto out_unlock; + + if (priv->powered) + ret =3D regmap_update_bits(priv->regmap, AC200_EPHY_CTL_REG, + AC200_EPHY_RMII_SEL, value); + if (!ret) + priv->interface =3D interface; + +out_unlock: + 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; + } + priv->phy_addr =3D phy_addr; + + ephy_ctl =3D ac200_ephy_ctl_config(priv); + + /* 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); + 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->powered =3D true; + goto out_unlock; + +err_disable: + /* Attempt every step of the shutdown sequence after a partial start. */ + 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; + unsigned long clk_rate; + unsigned int calibration; + u8 nvmem_calibration; + u8 bps_effuse_code; + struct clk *clk; + 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"); + } + + /* 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); + priv->ephy_ctl =3D + FIELD_PREP(AC200_EPHY_BPS_EFFUSE_MASK, bps_effuse_code); + /* EPHY_MODE and BIST_CLK_EN stay clear for normal operation. */ + + 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: + priv->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_interface =3D ac200_ephy_ctl_set_interface; + /* MII is the reset default used until the MAC supplies its interface. */ + priv->interface =3D PHY_INTERFACE_MODE_MII; + 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..482ba6faba6e --- /dev/null +++ b/drivers/net/phy/xpowers-acx00.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DRIVERS_NET_PHY_XPOWERS_ACX00_H +#define __DRIVERS_NET_PHY_XPOWERS_ACX00_H + +#include + +struct acx00_ephy_control { + int (*power_on)(struct acx00_ephy_control *control, + unsigned int phy_addr); + int (*power_off)(struct acx00_ephy_control *control); + int (*set_interface)(struct acx00_ephy_control *control, + phy_interface_t interface); +}; + +#endif --=20 2.53.0 From nobody Fri Oct 2 05:31:05 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 A63073C2762 for ; Wed, 5 Aug 2026 02:28:34 +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=1785896917; cv=none; b=Weuic7heAJpQHu8iSkeQxAjceknzze4XGFueNkI1NE5yzA0M8V7uGj5G/vHgCmJZ2tssUsA7qc28639OEzI1zIjRn4gA4hgibwe5rSIKDPEsN8Pg2PHsVLMr3OwoSVU5WrSXt2mk8++HDV8xONgJdL/mOLnayK4t/kFSKE/ETOM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896917; c=relaxed/simple; bh=q+8gVOKLd88te1BW659igZ2T20EfQQD8SX4NxV6IpGw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Yalu6Rzdq+AcaejqvkzluwCsoa/4swNl5rw8UEVVznvkY0djVe2OB5DimropVI/7/x/AEiJ4UG5MPDGwu5v3oEw+rR+1lvp50FVluqkqHR8vOHI1TPIGGGFsysuRFUoNEpFCyXTlpUjeMRwyRSt6T+Amv6w14JvxJVtULR38FDI= 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=sicZo6g/; 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="sicZo6g/" Received: by mail-ot1-f42.google.com with SMTP id 46e09a7af769-7eb61bbeb25so383335a34.1 for ; Tue, 04 Aug 2026 19:28:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896913; x=1786501713; 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=AGkeXkcQmVAMhKi4BRouTjNasW9FdK69cwCP5dyljV8=; b=sicZo6g/Xf8d0f7Qvq+03BET0vqr/ZJ+Hb61loW89qAHKJp+hTH0MX/PCAyHT8H877 2I5inoAr6fE3LL9mBqATKLHMBd2hkTvIR+ln9PlMdNoie2TKnO4ybE2PdcHWAP73DO5S uig1Xejd2lBOfFXFx51v/jyEAAkuTsAontgJLBY3D0UpkkYgltOeNOFBLaoe/YIioOJq OJ93A2E6CrTIqQ7HVsQDdL9ZW/Yn4sDyYRNqVrs3sgNJaHdwv/ybzyU949GLzZroRHIW mKpULSnINHm3mTaJ2sS61SB6DHdv3H+P1y1/i7rrkvRhHJdPDJZzA+A1f+JuwXv4OU5J PhZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896913; x=1786501713; 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=AGkeXkcQmVAMhKi4BRouTjNasW9FdK69cwCP5dyljV8=; b=Q5zH1AjNXdQOvCan4NSpzKogc8Ld8/qmrsyBDStyCILmE21ST7ZpxVwhIYSM1/fZ5t HkmAfUrEaLCO7053MgKfZ30C9k6kLrc8/quMSSSF/YRJksToBo2tJ1HPIciNAi1xbrkx co1lMY3aM1dKuFjyGsLXx1CvypoHRyweo/r2RoxXPmjQTakTUBEF4gfdaLUBruPIMoMh r8L+GZolDLE6Y5nBG07H4RaMTgTLPGNWNEjOWH5X4oJLjXyNfn7RkqXBMGojf1gRL5pp nNRt4ofwTaF5J5baJ2MepBmo2igynAgL2M3HQj+y1A3jHH6SbqMK25dKNVfd1cZBetlN q8/w== X-Forwarded-Encrypted: i=1; AHgh+RovQIDkUe3n3AzP3VJj3zPo87XD5WUdEGFCaLE4Tz+btV2CJaDyniqauFOBzhA8pjvMcIMwunwliIxK434=@vger.kernel.org X-Gm-Message-State: AOJu0Yz6nAWXdzIRe4JqdcNy2AOkfPYxF1EXGDEe9Eyu3qAgXgiUbwHt vRXcSHrxHazgZPnCVMwBpAq1U+PpNTxkd5p+0OBLs+KdcRpGS8CrVkov X-Gm-Gg: AR+sD12X+VP+4KAHNYieNFKDkDkvy3/yeD/oB6PZ1Iv9IaqeCqLAhtSlHNtFRE1dqki dmsMSmHsJQuhnaev6F0oNugflI/nR+/ODGcDmsTWBcHlzVUVPdaVH6L0zppDVVY6avcxj974wtw 1ANZU6cg8ViNekeSVSjOqj6v13il071kiGMjLeh0NNGo9Sx+JIrocxkg2bWSotY/lrde8boOVlA Axx/IByjYBI9/swOEET/B6Jv/PUiCusJlAOYuEJKFqaj3C62nxso4FanAXGOJMXoHsLblpaJb7T LUILvNznGkLioouw6SvJP9NxQbENcDpVPQYqw2iALqHmnmw6S/V2MRCC3yR4S+zZpK8rUyz5qIP Btrtt18OqC760+W9k0C8nM7gOlvqUXs1KXaw8wcdFfi3cE9secuFc8AUWRAvksHd6t5ucSoelRy uFEVle+XzAZSgd2fggPcjdZ9A9thVFVA0nQni/AiveAoiqZ4fsUoMpyuwlKcaMjxoXRN7MuIoZU 5iuDHgRzwKy0YO1oLskUEV5tbcTR6GD6IbPPZzYGyBbt+RU8TPcg5vrfeYDAKlzbdDXjZv/z3T8 fG2gb9sJfHcC+P3FIEkFTW/qOy/JlLLwICgADg+qVuDqDkFwkYJeDzmUkToFk8tGK7WT2J6OvPF LSmXz7V7sdn6ygLiK X-Received: by 2002:a05:6830:7010:b0:7e9:d634:77b8 with SMTP id 46e09a7af769-7f1e5c13e8cmr2629082a34.2.1785896913436; Tue, 04 Aug 2026 19:28:33 -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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:33 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:27:03 -0600 Subject: [PATCH net-next v2 5/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-5-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC300 exposes its Fast Ethernet PHY control registers through a separate non-PHY Clause 22 address. The manual defines that address as the link PHY address plus 16, giving control addresses 16 through 23 and link addresses 0 through 7. Describe the control endpoint, its required VCC1 supply, its 24, 25 or 27 MHz input clock and its SoC SID calibration cell. The actual PHY remains a separate ethernet-phy node and supplies the MAC-selected interface mode at runtime. Signed-off-by: James Hilliard --- .../bindings/net/x-powers,ac300-ephy-ctl.yaml | 70 ++++++++++++++++++= ++++ 1 file changed, 70 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..8a616ff3e89f --- /dev/null +++ b/Documentation/devicetree/bindings/net/x-powers,ac300-ephy-ctl.yaml @@ -0,0 +1,70 @@ +# 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 + +required: + - compatible + - reg + - clocks + - vcc1-supply + - nvmem-cells + - nvmem-cell-names + +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"; + }; + }; +... --=20 2.53.0 From nobody Fri Oct 2 05:31:05 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 F40633C3F4B for ; Wed, 5 Aug 2026 02:28:35 +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=1785896919; cv=none; b=Kf3SP3ZiwOst8hm7v44HQHBeh0OusW5SuUu7CCpLk8Jjj5MYLEB3vLbr4jCHNxeafacM8oRZoqzWr7vb4WnQ4U9PqRqAJfWI2ftVF8zg8Gl3Xq1ouuWMYEfyeldoivGuD2MYhy618xlDN+FN4BTDZBcpAStXWL3rreDXzLHSYpk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896919; c=relaxed/simple; bh=Rs5Yvai1KoUa6Gkj0I714GUovC4e+WNAYLOEwIvALJM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JlI+lCStsy8Osas/Mq67ko8ivsBJaqx/3CNj4ihCiCfkNTzFEDncGnDBwLkOP1b6VbjejzGekYwq4rwisd0ywoThYhYKzWovPn6+hV3cUMucLQ/ru1zcH2cJjBosm0sOGPzxAgHEMF9itqQ/SB+pNytzeNnGatYKI48g2ATStfc= 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=BNcw5ia5; 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="BNcw5ia5" Received: by mail-ot1-f46.google.com with SMTP id 46e09a7af769-7ec1e9d3359so408068a34.0 for ; Tue, 04 Aug 2026 19:28:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896914; x=1786501714; 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=RzurtN0DXtJ4YV8O94n+1KjkgXHYGsR0+0vBXEULE1M=; b=BNcw5ia5/cUpAbu9happjcpe8t6Y34JhkCX0D8QcRwbosHdjHdMuC6e27XR3tc8qih UuVfQXeWAhLBIUmtZrPiW/k1MynPtRSlF2qdkIFKVk66OJ3UYlP/C+U/eQaLjRYNgnT0 UarBZyJeHf/XVuXPmIeKBq86hHzI9V/P0SDGII2yL9ndKxrYQMSbJTegnCmuSH9tLka6 tvthGIp9a+UXnoP/XiPrz45TE+EvKi2zYRgGm1Wr+hGLNfkZ1/4wnb2S0B+saNfhk42U T55YpaMrRDJPsWaMGtCwQJOW0VEXOaBfrBl5GJFGFWwTuaEc4yFYgt8cMMtHZplpq3Dh Wjgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896914; x=1786501714; 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=RzurtN0DXtJ4YV8O94n+1KjkgXHYGsR0+0vBXEULE1M=; b=RcY6hnJJxWekA5XLWpgmRRjXJcSsSYRdaMgwueA4Eg003qCBmo+j+MkObFstHkPfrJ UgKLj6KM1yvGgSXvaBOr0hlk17oqwQF/G6sMV8QBquQYfyY15Y0LJm/liutC45me0eVi xEDOZ6P2adBYSA/K0XKSXwVpYrH1poo4+5ZhgHwoO8F0r/bzU57xdsH54Fi/IQXVMJ2Y 0LfxgsrEAnSFu2gxdNxQZnEwtoIevh6yaVp7yYmcnRuQF0e8Y1Y+HYDUxD56GtHYVhd7 I3FGaIFaXpr90hH9IJSndlPC6uvbSNJ12hN+VXOf9d/K7mEyZKsDJNhyAG5b0LMBshLR 9s4A== X-Forwarded-Encrypted: i=1; AHgh+Rp9JdcgPUtwojxpk00Vrfkn+SOIl7Pf9OeJ7CzSb7dSw1kBEvmZxdklf+oGvHd9Ujvm9lVloM5S9M9SAsY=@vger.kernel.org X-Gm-Message-State: AOJu0YwQylmEPaMnzhNLd9Ae478F5CPkLt5LOobi4BXMPhW9GNic39Oc EoQjgt5Yl+FQc2zC7hzv1xm3cB2EUlm2U4ZGMEyeeCKgeDtK74XzzKa+ X-Gm-Gg: AR+sD13HEWAz16dvCdTRZveAY/+lrj+wiPdaVMUHHMoCZCx6WNNiNFiGE/yW4UmrleS XYnFHYbi90ilxBNZ0rVLnqrnE7H7kWM2MQWJU8OZdoo0XUlub/Urfi0nzcJbv8Fcr3lXhh11IOF JDcWG4w3HZW2QtzvQr/YgIoH3rDdkVou583maOkICRaubocdPp48UIHEVQ1QDBC3CJcuklrJ4KM GfA/dkY1myaLExhA3wZ+VZGxteEIhK/1Z3XElGefVh/lBHdHQwmkcihdk30Lh7sswcvagtdzt2q CT5GyFPiCY0yzot3sA2TF75UbGXTGVu0HRD+sS0395hpys6hEPowPHB0JVQPiw4WPEIxu/WXKUV PZJ8+0o3gk3MYzJrV+/rrxfVkyJJew4Jd8cCyJWHxOlOfKekc7S6M+6Lc6I5yy9VVRh2t7eBX/9 kTow2x6koSDIExHvW2V4thX84JdyiTsJdwXoaK+wOlfiPKOAa9EiPatRtFh2QIhIUCl1yD8flu/ j0wz8ivU2eeIp2XtWzDwdsBpHSrYasfJJEk5dKrcdpWSTQgnZyBRIbQn+ymzaIRTDb/RfungqtY vc7GxjEnrt3rs6DNZHN45Sr3bz6XESb7KD+xED6++n20kkIfeLtgUignujOQpxfyuG+c/2JkLVX ajS1YwVEVi1ZWkaIE X-Received: by 2002:a05:6830:67f9:b0:7e6:8955:c52d with SMTP id 46e09a7af769-7f1e5d2f816mr2651673a34.5.1785896914418; Tue, 04 Aug 2026 19:28: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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:34 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:27:04 -0600 Subject: [PATCH net-next v2 6/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-6-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC300 Fast Ethernet PHY needs a separate non-PHY Clause 22 endpoint to complete package setup before the link endpoint becomes usable. Enable VCC1 and the input clock, select its 24, 25 or 27 MHz rate, apply the SoC SID calibration value and vendor offset, configure the documented I/O drive strength, and perform the reset-before-clock power-up sequence. Validate the control and link address relationship against the package straps, clear a latched MDIO error, and configure the internal digital LDO only for the package variant which uses it. Early PHY creation uses reset-default MII. A separate operation later applies phydev->interface and, if already powered, changes only RMII_SEL before the normal PHY soft reset. Expose serialized, idempotent power and interface operations to the common PHY driver. Enable only the MDIO, MII and input-clock pads in this basic driver; dedicated LED outputs remain disabled for a later patch. Signed-off-by: James Hilliard --- drivers/net/phy/Kconfig | 9 + drivers/net/phy/Makefile | 1 + drivers/net/phy/xpowers-ac300-ctl.c | 423 ++++++++++++++++++++++++++++++++= ++++ drivers/net/phy/xpowers-acx00.h | 2 + 4 files changed, 435 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 6119f4de880d..7535db7f3471 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -484,6 +484,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 f81854fc9f12..0c4e40c9a28a 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -101,4 +101,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..d3ca4df8a9a3 --- /dev/null +++ b/drivers/net/phy/xpowers-ac300-ctl.c @@ -0,0 +1,423 @@ +// 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_MII_DRV_MASK GENMASK(11, 10) +#define AC300_IO_DRV_LEVEL_2 2 +#define AC300_CLKIN_PAD_ENABLE BIT(4) +#define AC300_EPHY_MII_IO_ENABLE BIT(0) + +#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_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_VALUE \ + (FIELD_PREP(AC300_MDIO_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; + phy_interface_t interface; + 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 u16 ac300_ephy_ctl_config(const struct ac300_ephy_ctl *priv) +{ + return priv->ephy_config | + (priv->interface =3D=3D PHY_INTERFACE_MODE_RMII ? + AC300_EPHY_RMII_SEL : 0); +} + +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, + ac300_ephy_ctl_config(priv) | 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_set_interface(struct acx00_ephy_control *control, + phy_interface_t interface) +{ + struct ac300_ephy_ctl *priv =3D + container_of(control, struct ac300_ephy_ctl, control); + u16 value; + int ret =3D 0; + + switch (interface) { + case PHY_INTERFACE_MODE_MII: + value =3D 0; + break; + case PHY_INTERFACE_MODE_RMII: + value =3D AC300_EPHY_RMII_SEL; + break; + default: + return -EINVAL; + } + + mutex_lock(&priv->lock); + if (priv->interface =3D=3D interface) + goto out_unlock; + + if (priv->powered) + ret =3D mdiodev_modify(priv->mdiodev, AC300_EPHY_CONFIG_REG, + AC300_EPHY_RMII_SEL, value); + if (!ret) + priv->interface =3D interface; + +out_unlock: + 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; + u16 reset_value; + int sys_control; + 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_VALUE); + if (ret) + goto err_power_off; + + fsleep(10000); + + ret =3D mdiodev_write(priv->mdiodev, AC300_EPHY_CONFIG_REG, + ac300_ephy_ctl_config(priv) | AC300_EPHY_SHUTDOWN); + if (ret) + goto err_power_off; + + fsleep(10000); + + ret =3D mdiodev_write(priv->mdiodev, AC300_EPHY_CONFIG_REG, + ac300_ephy_ctl_config(priv)); + 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; + unsigned long clk_rate; + unsigned int phy_addr; + u8 calibration; + u8 bgs_effuse_code; + u8 package_status; + int mask_version; + int sys_control; + 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); + + priv->clk =3D devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), + "failed to get input clock\n"); + + ret =3D devm_clk_rate_exclusive_get(dev, priv->clk); + if (ret) + return dev_err_probe(dev, ret, "failed to lock clock rate\n"); + + clk_rate =3D clk_get_rate(priv->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"); + + /* 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); + priv->ephy_config =3D + FIELD_PREP(AC300_EPHY_BGS_EFFUSE_MASK, bgs_effuse_code); + /* EPHY_MODE and BIST_CLK_EN stay clear for normal operation. */ + + priv->control.power_on =3D ac300_ephy_ctl_power_on; + priv->control.power_off =3D ac300_ephy_ctl_power_off; + priv->control.set_interface =3D ac300_ephy_ctl_set_interface; + /* MII is the reset default used until the MAC supplies its interface. */ + priv->interface =3D PHY_INTERFACE_MODE_MII; + mdiodev_set_drvdata(mdiodev, &priv->control); + + /* Validate the package while the control endpoint is known to respond. */ + phy_addr =3D ac300_ephy_ctl_link_addr(priv); + ret =3D ac300_ephy_ctl_power_on(&priv->control, phy_addr); + if (ret) + return ret; + + 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); + + ret =3D ac300_ephy_ctl_power_off(&priv->control); + if (ret) + return dev_err_probe(dev, ret, + "failed to quiesce control block\n"); + + 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 482ba6faba6e..0af8895e4cae 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 + struct acx00_ephy_control { int (*power_on)(struct acx00_ephy_control *control, unsigned int phy_addr); --=20 2.53.0 From nobody Fri Oct 2 05:31:05 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 E21113C585B for ; Wed, 5 Aug 2026 02:28:36 +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=1785896920; cv=none; b=aUKvW8Scau6mJ/LESuLZnnjVm6jXxzUwh018DRa94gShztrsYhAOtV+twyQoGoBuuP/wyOfXpc55tFhD/R6in48oDeCdYyroR6QXbRDRyzdOoyq8B8jAnf1clWO6FVmdb8AuZyzUcdaU33051sD3CuuDWRGG6lYJ4cyKBNFwwc8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896920; c=relaxed/simple; bh=x9Lw0syNJki2K15bJqB51uvJ4FZQCZJczX77O6639L4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=c2IFZR23kEA8tNwj+IItWcUDC+eFlk9G0G1SwIAxzreTWxvGQUvg570UNB/87UJkMWPiHVZUXKN3b1wOjgKuQsKkQkyCLV4ipNZiHd7KOCNSbQ4wOKQ5FcoNziQq/GEZo+ao+pBLmVv9NokEwInsGxztgr5mrTDZv10EmXrk49Y= 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=Eek7uyu6; 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="Eek7uyu6" Received: by mail-ot1-f46.google.com with SMTP id 46e09a7af769-7e9ecb1e13cso611739a34.3 for ; Tue, 04 Aug 2026 19:28:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896915; x=1786501715; 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=MjVtijpmJ/oNZWvDUTBmnWApL7aWLNJ+r5jlKeKXMpI=; b=Eek7uyu6hr/hilnOqZTQ6zEY+2BdCD4XLP4X2HrLhK1Y0dR6xt/gzWNzuuXDC13G0h DITxayog+UCRDpfBerqX81SdbmurJQei+qZPeU2k/PDkYaAOEiJU26YnBxjRQDduR0zx 3iBfZtPXBjVK9UmVkI1Hw4AR+pclKc17bJf55MhZiKrDdFu8EH5tguYhs51h3wlVAjOC /THzF8BmIonJ9Zt29v398OtILyQR/9lPLVkKAjv9/BasSgPhgtehOnxs2TOyDUCtMF9t 7/wy/tOq+KhsGe5IGa6Z2qDAT2/ct/hXsigQmRUk5Be6xHeY7UZYUo7a29etc9XhPsEX 6xYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896915; x=1786501715; 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=MjVtijpmJ/oNZWvDUTBmnWApL7aWLNJ+r5jlKeKXMpI=; b=bIEs/gW+aHkOcMTdP+HRsj4UtL2mekC4yoymqcsphYMWqn2Je1FqdU1XtQ84XqnGJy YNflnhOSbcfevwXVJKcn9BsMhZvRpAVfdGtYvBMLEaReTd02NNuISZ4QBR5BPxv4VuvH bOtttWQZsSQR0tG2/q0Le6/UjG7Lp/trrN+xfCKuTP8NJBQft/wwRL2r8mcefWwx1Cct deDPAT0ksAiWJQlW+3cDImbeFudy6/TYYgcR8HMidQiDOjQwBNtRUREBBX9h3sImrF/L 5dZf3tUlaFRHKpbS6QXrpCBphPTDXobQls3qDLgPJ23enC/e8p1fqj2Zn9yfBPv0LejG 6cUg== X-Forwarded-Encrypted: i=1; AHgh+RoYTxJK4uf6e2fT1Posv5yAs5pZ/7JJVWVlq8C5d1x7mwD2/s6lk0rJUpLOJqez+AH7s7w1MAwfqfzdwGA=@vger.kernel.org X-Gm-Message-State: AOJu0YwrZJ9i9ATY4J5FvXBUHR2QQxME72Q7/jPMvpxaaJGDHocKvRf9 Dbe8zoHEw+PdtLhO/vr4C+RlY+kDTtcstjdlsSATTc/Idim+iJoNYm8E X-Gm-Gg: AR+sD13S4tsl2/GnrYCVSySJjzdMgoWLCwEsBj13dDoTZuvuK5TKqAjDtWwKdZUZYRJ 5n/ghO50Tk/T1ez5yJA8C12EDNccO+KK0dEz2SnzBk8eU0D5UVMueP1gt/Vlr3Q/g3CiTFsNYP0 8vDe7vpUulH73waIxLm2i4F3P/OEWE1mKy2NnssrcJY2UKYlbZZUOXKNbaoVLGJX53G/oULsS1z KJihpndsLcuWmDQfil/9aqrQTHZhIL21QP6yTCGSZnW1nZWpfiXz66EVu0BhBZ5EsHtz350sV7w YShG5LG6FYbCWK6ftz/XhGvCf4rUoMxJr/HvYGHbj1Y29ebotsExrP1CqWz2WE6yGj05bbJA0Op UpLfchPdl7ylg9O+K9SeZ3lYJx0EGbChYyCNWDjmLZOTOzwrkODe7kg8lKyhgS30749Kovi7SyU uO/JXiTzePlfa46dA3PyxzjZn6VJR/d5kzwWU0YOgGLcNwqIaOtkieqOqalxKS2UEhvR/lQjZcI EIktQUqtbdTsb+sI8+mhRVLok2/UAWiGFx0iqlagrDXzFATljXqP7d9m+PiXS0WlyomF2h1g6Ug 98QbPPbph5zOlXkFBZ+CptzY87vZMYKRetn7pxNSCa0hbVNj+4KO6HwoqUF5dfBUKJbVtBSfpez r2lshFSxuc+xwYeK/OjmKlDLiSwI= X-Received: by 2002:a05:6830:3741:b0:7e9:ea28:4c1f with SMTP id 46e09a7af769-7f1e5d893e2mr2408593a34.8.1785896915399; Tue, 04 Aug 2026 19:28:35 -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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:35 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:27:05 -0600 Subject: [PATCH net-next v2 7/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-7-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC200 and AC300 MDIO link interfaces report the same Clause 22 identifier and use a compatible link-side paged register layout, but need different package control interfaces before that identifier can be read. Describe the forced-ID PHY and require exactly one reference to an enabled AC200 or AC300 control device. 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 and is therefore limited to 0 through 7. Allow a system to provide its optional two-bit SID configuration field. Bit 0 identifies the AC200 or AC300 package and must agree with the described control device. Bit 1 selects the AC300 low-calibration tuning sequence. Omitting the field skips package validation and selects the normal calibration sequence. Also describe the optional xMII receive-clock inversion needed by some integrations. Requiring an X-Powers control reference distinguishes these integrations from the Rockchip RK630 PHY, which reports the same identifier. Signed-off-by: James Hilliard --- .../bindings/net/x-powers,acx00-ephy.yaml | 117 +++++++++++++++++= ++++ 1 file changed, 117 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..c280bcf8aa25 --- /dev/null +++ b/Documentation/devicetree/bindings/net/x-powers,acx00-ephy.yaml @@ -0,0 +1,117 @@ +# 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 expose Fast Ethernet MDIO link interfaces which repo= rt + the same PHY ID and use a compatible link-side paged register layout. Ea= ch + package uses a different control interface to make its MDIO endpoint + accessible. A fixed board references its enabled AC200 or AC300 control + device. The PHY node's reg value is programmed through the AC200 interfa= ce; + 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: + Optional two-bit SoC SID configuration field. Bit 0 selects the pack= age + variant, with zero for AC200 and one for AC300, and must agree with = the + described control device. Bit 1 selects the AC300 vendor low-calibra= tion + tuning sequence. Omitting the field selects the normal tuning sequen= ce + without validating the package variant. + + nvmem-cell-names: + 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. + +required: + - compatible + +oneOf: + - properties: + x-powers,ac300-control: false + required: + - x-powers,ac200-control + - properties: + x-powers,ac200-control: false + required: + - x-powers,ac300-control + +dependentRequired: + nvmem-cells: [ nvmem-cell-names ] + +allOf: + - $ref: ethernet-phy.yaml# + - if: + required: + - x-powers,ac300-control + then: + properties: + reg: + maximum: 7 + +unevaluatedProperties: false + +examples: + - | + 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_configuration>; + nvmem-cell-names =3D "configuration"; + x-powers,ac300-control =3D <&ac300_ephy_ctl>; + }; + }; + + - | + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy@1 { + compatible =3D "ethernet-phy-id0044.1400"; + reg =3D <1>; + x-powers,ac200-control =3D <&ac200_ephy_ctl>; + }; + }; +... --=20 2.53.0 From nobody Fri Oct 2 05:31:05 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 5C23A3C8717 for ; Wed, 5 Aug 2026 02:28:38 +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=1785896921; cv=none; b=bUtXcwHXCacFhtUFNLWCw1E8AXwDCE/+FyoOQDXbIDfgJWE+Y8M+KBEP2dMBZCYUOcb/ZYzwgYLu72BiTCCTg07VmHHckfKAmo8U+gog3CVvEQwDs69QkzyXxZ+ZT18n59oG2p3iYw0SopOWauTtwLL0UIsOYat6bjBySm1zf+4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785896921; c=relaxed/simple; bh=tHO5yBuqCrRzthf4FCgHKrDW7oQG+8YTZFwaAVI9jHQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=m+Y2hgC4kk5DDyE+6+05rnLXE8ukLG3j2bCHuibNPz8G/ErVURKtbFpjN+l/z/EwtYZLaB+Aj8cCZd5QnZBmlOfKzESOR7DjcRKNmbiqA1Za54aAM+ZjE+LoLBwfqPRmfw9zAsoXUPygn7AhCM/toFf8mRixV8swM04W3Eeg7XI= 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=Abhzvfs3; 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="Abhzvfs3" Received: by mail-ot1-f44.google.com with SMTP id 46e09a7af769-7e9eaf04bfaso226426a34.1 for ; Tue, 04 Aug 2026 19:28:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785896917; x=1786501717; 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=a7n627btFdgAMk+nFRlo8bZ30B6WMW9WO37DeKOzDqM=; b=Abhzvfs3EqxNzsa3w15az0k8K2bjsQ59VSTzchKtlk+I2Xcg7TjxjEj3g3Ir421RXX /2re7Kv5ZDK+MG+FAI7uY9yyrp06hxqlut0HbWMWg4iFUSNq6+JheQrCVwC5OOK8low9 kxLlno22reOql1CHvsQgNQCW74r+kiDbYVWnGDI7jp3bFc0DtWieUSkxFx150SsSP0MF NNo9DyzCzqhv+MmZ1fTwSOjJ486BZdJ2NHNMNXSXk39szCKdkGJYK43M1mnx1GO0kUjc fadBpI9BZAC5/I6Bg+UXaBMivowqq8Sw7M0SONIRmXtLkYkz7KAw5oNzSdHHGMIYiGvK ieRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785896917; x=1786501717; 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=a7n627btFdgAMk+nFRlo8bZ30B6WMW9WO37DeKOzDqM=; b=n03KabT4KyKnHpfmJX3RhmPzodCvrheWKYPtZ/Dh+rN7ZBpTHcZvIpkSRZ+LCW0n5w WSnVgkhDLqeGDtaNvzjgnwugm1z+xYhoremichASSSsAe425zzuoQybeJ3dQ+W43gHpJ KMxg6FZieqb+c4fj8x2y7vaAjEEvKJpG9ljorj/cpB/9JYThHxyig9vatieynHzcQyeE vpPwGkYK+mKhXZ6YIwgyrLCvpyjs5G3yZicM4itYK3Hp88S9s68+2uO6rd0ZoEbqao+7 KExZ5Wa8QRZgVecqk8OhlkU1jXuUO6f1YgbvwtgKouQURFWy/dKJvE1nkEjo0RcrAVJY 9usA== X-Forwarded-Encrypted: i=1; AHgh+RoCmEqqmbQTuysgMoji8Bwmovn1clXZZpTVEno14eq0WK8FzgHqj665W8oVBDt412kqZW4tQXFx9EEKBac=@vger.kernel.org X-Gm-Message-State: AOJu0YxQ4uq4a+6bJXUhd1yDv2fzhD3cdku9YOElvshel/sHtNRyu+sd cVrdbT1Y7aGM8JS4zvIDfEBWXT9UlZVN6VMmiXKTxuohfaLL3o7qt3JM X-Gm-Gg: AR+sD12O/1BMDncxRuX2JhV4uvYMCyT3tP+ygAlZxieQ/ChJL+UJ9ACr6baFNcRQ7Uy argCLM857EgC0Pe+vhFcRavif+pI6mtcrFmUp+dFd32cCTJ6fOQI2GioJymq83DBUAbBxivo0Xp u6htxZvsgl7nvDORKKUkQWuxaqbKVLWZi1uQL7fooXPRtZQI3ayyisDwR8GLdgYF0j87X3f5EqE Sy/FDKceWBw3Uuw5Re5a+yK5tVKjsaulNunaLhZGb8l+UTr1lzPbfiZ/k8WRaVEkkHC2l+1xMXc MBTGh4LtH5ShS3SsllBpzklSCKeC2blpwYEUyeW7fTMugxzx0USIOM24LBg8vfBnsn5PLpsKucD YatXMXSzKnVqyvSkhqzPEAqeSOIISqdtQUtVAc/H0sQcKqnZKWIUGlpYl8MJIoiqLPNY4AlKnNK TIL5TQui2SwwHoV7sZQQ5JBSmPOXgb/1oBqVT6rUyhurJ0UG44QKk9BTu+Z/e0ZknkQwCCn5a9A gAOBtapI3rw2/9ojZAvr9rSPeyOoW43eBT6nPasICrOmyszPESL3Krh09T/faceft0RQdcZaM4W 3SbwFdNaGnhTX5+YvpZlL2UOBF+K14V9vLopSILIl0MKNQTKZqBP2yu7hKArr/SOOlYfeoQNRN5 mLekwWNsH/WSrMXe9 X-Received: by 2002:a05:6830:3489:b0:7e9:bf64:b70b with SMTP id 46e09a7af769-7f1e5c2af15mr2626135a34.1.1785896916416; Tue, 04 Aug 2026 19:28: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-7f1df565d37sm2078153a34.16.2026.08.04.19.28.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 19:28:36 -0700 (PDT) From: James Hilliard Date: Tue, 04 Aug 2026 20:27:06 -0600 Subject: [PATCH net-next v2 8/8] 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: <20260804-submit-acx00-of-dynamic-v1-v2-8-3eef49ff1d8c@gmail.com> References: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> In-Reply-To: <20260804-submit-acx00-of-dynamic-v1-v2-0-3eef49ff1d8c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Andrew Lunn , Heiner Kallweit , Russell King , Heiko Stuebner Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, mfd@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, James Hilliard X-Mailer: b4 0.15.2 The AC200 and AC300 MDIO link endpoints report the same Clause 22 identifier and use a compatible link-side paged register layout. Their identification registers are inaccessible until a package-specific control path powers and configures the block. Add a common PHY driver which matches the firmware-provided identifier only when the node also references one X-Powers control device. Validate that reference and the AC300 address relationship, defer until the provider is bound, and create a managed device link to protect its lifetime and order teardown and power management. When the optional two-bit SID configuration field is present, verify that its package-selector bit agrees with the fixed control reference. Use its second bit to select the AC300 low-calibration tuning sequence. Omitting the field skips package validation and selects the normal sequence. Power the control block in reset-default MII mode during PHY probe. Once the MAC supplies phydev->interface, pass MII or RMII to the provider before the normal PHY soft reset. Program the AC200 link address through its provider and let the AC300 provider validate its strapped address. Apply the common vendor analog initialization, with the package-specific normal value and the optional AC300 low-calibration sequence. Support the board-selected xMII receive-clock inversion and leave MDI/MDI-X in its vendor automatic mode. Disable standard and Intelligent EEE initially, then restore phylib's standard EEE policy after later resets. Power the package control block down with the PHY and restore the vendor configuration on resume. If power-off fails, attempt to restore the PHY before returning the original suspend error. Signed-off-by: James Hilliard --- drivers/net/phy/Kconfig | 9 + drivers/net/phy/Makefile | 1 + drivers/net/phy/xpowers-acx00.c | 544 ++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 554 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 7535db7f3471..c505ade5955c 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -493,6 +493,15 @@ 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 their common MDIO PHY + registers and uses one statically selected package-control provider for + power, calibration and interface setup. + config XILINX_GMII2RGMII tristate "Xilinx GMII2RGMII converter driver" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 0c4e40c9a28a..db71f1c2b756 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -102,4 +102,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..f9e6be751252 --- /dev/null +++ b/drivers/net/phy/xpowers-acx00.c @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * X-Powers AC200/AC300 Ethernet PHY driver + * + * Copyright (C) 2019 Jernej Skrabec + * Copyright (C) 2026 James Hilliard + */ + +#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_PAGE0_GLOBAL_CONFIG_REG 0x13 +#define ACX00_PAGE0_XMII_RX_CLOCK_INVERT BIT(12) +#define ACX00_PAGE0_MDI_MODE_MASK GENMASK(1, 0) +#define ACX00_PAGE0_MDI_MODE_AUTO 2 + +#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 AC200_PAGE6_AFE_EQ_RX_DETECT_VALUE 0x708f +#define AC300_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_DEFAULT_VALUE \ + ACX00_PAGE6_TX_LEVEL_VALUE(0x15, 0x30) +#define ACX00_PAGE6_TX_LEVEL_LOW_CAL_VALUE \ + ACX00_PAGE6_TX_LEVEL_VALUE(0x35, 0x33) + +#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) + +/* + * 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 phy_device *phydev; + struct acx00_ephy_control *control; + bool is_ac300; + bool use_low_calibration_tuning; + bool xmii_rx_clock_inverted; +}; + +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_control_power_on(struct acx00_ephy_priv *priv) +{ + return priv->control->power_on(priv->control, + priv->phydev->mdio.addr); +} + +static int acx00_ephy_control_power_off(struct acx00_ephy_priv *priv) +{ + return priv->control->power_off(priv->control); +} + +static int acx00_ephy_set_interface(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + + if (phydev->interface =3D=3D PHY_INTERFACE_MODE_NA) + return 0; + if (phydev->interface !=3D PHY_INTERFACE_MODE_MII && + phydev->interface !=3D PHY_INTERFACE_MODE_RMII) + return -EINVAL; + + return priv->control->set_interface(priv->control, + phydev->interface); +} + +static void acx00_ephy_control_release(void *data) +{ + struct acx00_ephy_priv *priv =3D data; + int ret; + + ret =3D acx00_ephy_control_power_off(priv); + if (ret) + phydev_warn(priv->phydev, + "failed to power off control block: %pe\n", + ERR_PTR(ret)); +} + +static struct device * +acx00_ephy_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_ephy_get_control(struct phy_device *phydev, + struct acx00_ephy_priv *priv) +{ + struct device *dev =3D &phydev->mdio.dev; + struct acx00_ephy_control *control; + struct device_node *control_node; + struct device *supplier; + struct device_link *link; + const char *compatible; + const char *property; + bool has_ac200; + bool has_ac300; + u32 control_addr; + u32 configuration =3D 0; + int ret; + + has_ac200 =3D of_property_present(dev->of_node, + "x-powers,ac200-control"); + has_ac300 =3D of_property_present(dev->of_node, + "x-powers,ac300-control"); + if (has_ac200 =3D=3D has_ac300) + return dev_err_probe(dev, -EINVAL, + "exactly one ACx00 control is required\n"); + + priv->is_ac300 =3D has_ac300; + property =3D has_ac300 ? "x-powers,ac300-control" : + "x-powers,ac200-control"; + compatible =3D has_ac300 ? "x-powers,ac300-ephy-ctl" : + "x-powers,ac200-ephy-ctl"; + control_node =3D of_parse_phandle(dev->of_node, property, 0); + if (!control_node) + return dev_err_probe(dev, -EINVAL, "missing %s\n", property); + if (!of_device_is_compatible(control_node, compatible)) { + ret =3D dev_err_probe(dev, -EINVAL, + "%s does not reference a %s device\n", + property, compatible); + goto out_put_node; + } + if (!of_device_is_available(control_node)) { + ret =3D dev_err_probe(dev, -EINVAL, + "%s references a disabled device\n", + property); + goto out_put_node; + } + + if (has_ac300) { + ret =3D of_property_read_u32(control_node, "reg", &control_addr); + if (ret || control_addr !=3D phydev->mdio.addr + + AC300_EPHY_CONTROL_ADDR_OFFSET) { + ret =3D dev_err_probe(dev, -EINVAL, + "AC300 control address does not match reg\n"); + goto out_put_node; + } + } + + if (device_property_present(dev, "nvmem-cells")) { + ret =3D nvmem_cell_read_variable_le_u32(dev, + "configuration", + &configuration); + if (ret) { + dev_err_probe(dev, ret, + "failed to read PHY configuration\n"); + goto out_put_node; + } + + if (!!(configuration & ACX00_EPHY_CONFIG_VARIANT_AC300) !=3D + priv->is_ac300) { + ret =3D dev_err_probe(dev, -EINVAL, + "configuration does not match control device\n"); + goto out_put_node; + } + } + + priv->use_low_calibration_tuning =3D + priv->is_ac300 && + !!(configuration & ACX00_EPHY_CONFIG_CALIBRATION_LOW); + ret =3D 0; + + supplier =3D acx00_ephy_find_supplier(control_node, priv->is_ac300); + if (!supplier) { + ret =3D dev_err_probe(dev, -EPROBE_DEFER, + "%s device is not registered\n", property); + goto out_put_node; + } + + link =3D device_link_add(dev, supplier, DL_FLAG_AUTOREMOVE_CONSUMER); + if (!link) { + ret =3D dev_err_probe(dev, -EINVAL, + "failed to link %s device\n", property); + goto out_put_supplier; + } + + /* The managed link keeps the provider and its operations bound. */ + device_lock(supplier); + if (!device_is_bound(supplier)) { + ret =3D -EPROBE_DEFER; + } else { + control =3D dev_get_drvdata(supplier); + if (!control || !control->power_on || !control->power_off || + !control->set_interface) + ret =3D -EINVAL; + else + priv->control =3D control; + } + device_unlock(supplier); + if (ret =3D=3D -EPROBE_DEFER) + ret =3D dev_err_probe(dev, ret, "%s driver is not ready\n", + property); + else if (ret) + ret =3D dev_err_probe(dev, ret, + "%s driver has invalid control operations\n", + property); + +out_put_supplier: + put_device(supplier); +out_put_node: + of_node_put(control_node); + return ret; +} + +static int acx00_ephy_disable_eee(struct phy_device *phydev) +{ + int ret; + + ret =3D phy_modify_paged(phydev, ACX00_PAGE_1, + ACX00_PAGE1_INTELLIGENT_EEE_CONTROL_REG, + ACX00_PAGE1_INTELLIGENT_EEE_ENABLE, 0); + if (ret) + return ret; + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, + MDIO_EEE_100TX); +} + +static int acx00_ephy_probe(struct phy_device *phydev) +{ + struct device *dev =3D &phydev->mdio.dev; + struct acx00_ephy_priv *priv; + int ret; + + if (!dev->of_node) + return -ENODEV; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->phydev =3D phydev; + ret =3D acx00_ephy_get_control(phydev, priv); + if (ret) + return ret; + + priv->xmii_rx_clock_inverted =3D + device_property_read_bool(dev, + "x-powers,xmii-rx-clock-inverted"); + phydev->priv =3D priv; + ret =3D devm_add_action_or_reset(dev, acx00_ephy_control_release, priv); + if (ret) + return ret; + + ret =3D acx00_ephy_control_power_on(priv); + if (ret) + return dev_err_probe(dev, ret, + "failed to power on control block\n"); + + /* Set the hardware default before phylib reads its EEE advertisement. */ + ret =3D acx00_ephy_disable_eee(phydev); + if (ret) + return dev_err_probe(dev, ret, + "failed to disable EEE\n"); + + return 0; +} + +static int acx00_ephy_soft_reset(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + ret =3D acx00_ephy_set_interface(phydev); + if (ret) + return ret; + + ret =3D acx00_ephy_control_power_on(priv); + if (ret) + return ret; + + /* ACx00 can acknowledge reset in power-down without restarting. */ + ret =3D genphy_resume(phydev); + if (ret) + return ret; + + return genphy_soft_reset(phydev); +} + +static int acx00_ephy_config_init(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + u16 afe_eq_rx_detect =3D priv->is_ac300 ? + AC300_PAGE6_AFE_EQ_RX_DETECT_VALUE : + AC200_PAGE6_AFE_EQ_RX_DETECT_VALUE; + u16 tx_level_value =3D ACX00_PAGE6_TX_LEVEL_DEFAULT_VALUE; + u16 global_config; + int oldpage; + int ret; + + global_config =3D FIELD_PREP(ACX00_PAGE0_MDI_MODE_MASK, + ACX00_PAGE0_MDI_MODE_AUTO); + if (priv->xmii_rx_clock_inverted) + global_config |=3D ACX00_PAGE0_XMII_RX_CLOCK_INVERT; + + ret =3D phy_modify_paged(phydev, ACX00_PAGE_0, + ACX00_PAGE0_GLOBAL_CONFIG_REG, + ACX00_PAGE0_XMII_RX_CLOCK_INVERT | + ACX00_PAGE0_MDI_MODE_MASK, global_config); + if (ret) + return ret; + + if (priv->is_ac300 && priv->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 oldpage; + + 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, 0); + if (ret) + goto out_restore_page; + ret =3D __phy_modify(phydev, ACX00_PAGE1_INTELLIGENT_EEE_CONTROL_REG, + 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 (priv->is_ac300 && priv->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 (priv->is_ac300 && priv->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); + +out_restore_page: + ret =3D phy_restore_page(phydev, oldpage, ret); + if (ret) + return ret; + + /* Restore the standard EEE policy retained by phylib across resets. */ + return genphy_c45_an_config_eee_aneg(phydev); +} + +static int acx00_ephy_power_on_and_resume(struct phy_device *phydev) +{ + struct acx00_ephy_priv *priv =3D phydev->priv; + int ret; + + ret =3D acx00_ephy_set_interface(phydev); + if (ret) + return ret; + + ret =3D acx00_ephy_control_power_on(priv); + if (ret) + return ret; + + ret =3D genphy_resume(phydev); + if (ret) { + acx00_ephy_control_power_off(priv); + return ret; + } + + /* Powering off the control block loses the vendor-page state. */ + return acx00_ephy_config_init(phydev); +} + +static int acx00_ephy_resume(struct phy_device *phydev) +{ + 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; + + ret =3D genphy_suspend(phydev); + if (ret) + return ret; + + ret =3D acx00_ephy_control_power_off(priv); + 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 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", + .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, + .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