From nobody Mon Jun 8 20:53:44 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 675BA2EC0A7; Tue, 26 May 2026 14:59:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807562; cv=none; b=p/fjkifJNSm7CeUDaZrVPJMCw9izCsH6as9hfh9xnCDtH0FAC55/NHJ/yt6HjUShcLuf6hCvtoIoXs6gTZF7Hdk50v2C6547ufInlICCwq5SgAU1O0DAuznUYy4z6FnyrRR5dDXgu5qoU8i3OoWrmwJ6ebMsT1kPOkcj8HAUF1Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807562; c=relaxed/simple; bh=jnjkd94RUMpF3IkbOII2OEsJPkhLiCqeJjlmx+sxlEE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=p//wZYQQVHXmGDjwNAyWxp87zLnMQX115QXVh8FciGreQeYxIqysXtkAkG2cD7HMxj4kgGCIsdWAQHkNT4aRGRkJMM3/YSCDsCyq8th5ILuYtb8TP2Gy07XGadtDwrvYxmGsKSUDR/zAumr6nxSojdu8DY545iPDvWaPTJTG40I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=emz5cx1R; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="emz5cx1R" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1779807558; bh=jnjkd94RUMpF3IkbOII2OEsJPkhLiCqeJjlmx+sxlEE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=emz5cx1RN9j/jc2l+4sjwVfbLBkCaw+ZdMXLwdeDggQTU8DX+ONoMB2JLgrZ8fnVC gGBvsnyz34H7P+XCkd8YVEDOvAcBpVuHFEPa92jahxRxfxyiMCm76JtS6iUrwKFVTp TW3dSqBSFOxikwXiXGBiyRn08TImHzxstiuAmn2pzo38zXI1WRzUY2qmeVShaKodNR qdzLwdn9B5Ykdx3+RXPxfcMByVg38MaV5TBZKplPjixIpfJBsMiVon3iqdKRG9Bv1z jB9re98J+b27nt1XVF3D0hKlUA2HWjP5Uv8/rPSlJz7lZXZlfVaaQbxhcxq5xXExnP hZ0zhEIw/Bnmg== Received: from yukiji.home (unknown [100.64.0.131]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laeyraud) by bali.collaboradmins.com (Postfix) with ESMTPSA id 2531B17E0DD3; Tue, 26 May 2026 16:59:17 +0200 (CEST) From: Louis-Alexis Eyraud Date: Tue, 26 May 2026 16:58:06 +0200 Subject: [PATCH net-next v5 1/6] dt-bindings: net: Add support for Airoha AN8801R GbE PHY 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: <20260526-add-airoha-an8801-support-v5-1-01aea8dee69b@collabora.com> References: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> In-Reply-To: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , AngeloGioacchino Del Regno , Andrew Lunn , Heiner Kallweit , Russell King Cc: kevin-kw.huang@airoha.com, macpaul.lin@mediatek.com, matthias.bgg@gmail.com, kernel@collabora.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Louis-Alexis Eyraud X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779807555; l=3989; i=louisalexis.eyraud@collabora.com; s=20250113; h=from:subject:message-id; bh=cHsrbSP2OxYlHlAYxTNFdvkiUfl9C3Vj73alAJHVnUo=; b=5Urn83jCctCngaKRIubjEOz/UJJu7RW9RwCFWd8iSYVV40rgGb/Tlh1q2IgxUDpY9VwOReoCj aC7TMIi23OPAPG5Owgda1tXuWu/qxiOAOaua5kpwbCnAIGBWdHY4VKg X-Developer-Key: i=louisalexis.eyraud@collabora.com; a=ed25519; pk=CHFBDB2Kqh4EHc6JIqFn69GhxJJAzc0Zr4e8QxtumuM= From: AngeloGioacchino Del Regno Add a new binding to support the Airoha AN8801R Series Gigabit Ethernet PHY. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring (Arm) Signed-off-by: Louis-Alexis Eyraud --- .../devicetree/bindings/net/airoha,an8801.yaml | 120 +++++++++++++++++= ++++ 1 file changed, 120 insertions(+) diff --git a/Documentation/devicetree/bindings/net/airoha,an8801.yaml b/Doc= umentation/devicetree/bindings/net/airoha,an8801.yaml new file mode 100644 index 000000000000..d6e5a60a6b20 --- /dev/null +++ b/Documentation/devicetree/bindings/net/airoha,an8801.yaml @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/airoha,an8801.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha AN8801R Series PHY + +maintainers: + - AngeloGioacchino Del Regno + +description: + The Airoha AN8801R is a low power single-port Ethernet PHY Transceiver + with Single-port serdes interface for 1000Base-X/RGMII; this chip is + compliant with 10Base-T, 100Base-TX and 1000Base-T IEEE 802.3(u,ab) + and supports Energy Efficient Ethernet (802.3az), Full Duplex Control + Flow (802.3x), auto-negotiation, crossover detect and autocorrection, + Wake-on-LAN with Magic Packet, and Jumbo Frame up to 9 Kilobytes. + This PHY also supports up to three user-configurable LEDs, which are + usually used for LAN Activity, 100M, 1000M indication. + +allOf: + - $ref: ethernet-phy.yaml# + +properties: + compatible: + enum: + - ethernet-phy-idc0ff.0421 + + reg: + maxItems: 1 + + leds: + type: object + description: + Describes the LEDs associated to the PHY + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-2]$": + type: object + description: PHY LEDs + $ref: /schemas/leds/common.yaml# + + properties: + reg: + enum: [0, 1, 2] + + function-enumerator: + enum: [0, 1, 2] + description: | + Specifies a function for offloading LED functionality to the= PHY: + 0 - No offloading + 1 - Link Availability + 2 - Network Activity + + required: + - reg + + unevaluatedProperties: false + + additionalProperties: false + + wakeup-source: + $ref: /schemas/types.yaml#/definitions/flag + description: + Enable Wake-on-LAN support + +required: + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy@0 { + compatible =3D "ethernet-phy-idc0ff.0421"; + reg =3D <0>; + + leds { + #address-cells =3D <1>; + #size-cells =3D <0>; + + led@0 { + reg =3D <0>; + color =3D ; + function =3D LED_FUNCTION_LAN; + default-state =3D "keep"; + }; + + led@1 { + reg =3D <1>; + color =3D ; + function =3D LED_FUNCTION_LAN; + function-enumerator =3D <1>; + default-state =3D "keep"; + }; + + led@2 { + reg =3D <2>; + color =3D ; + function =3D LED_FUNCTION_LAN; + function-enumerator =3D <2>; + default-state =3D "keep"; + }; + }; + }; + }; --=20 2.54.0 From nobody Mon Jun 8 20:53:44 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D89D927603F; Tue, 26 May 2026 14:59:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807563; cv=none; b=JopGBQy9l74kfH+ymWBOF664fQOrS0QlGc5LlFr0EKF3A1EH1z0iChE4nZ3Qou8Vj35iHllac33HN3uPv3zgZ0Y2JU4AV4PKqvd13l1C7QqKWUFrJnkwKfXr2eI3UXD7mS2bb1NqHsOme5ljBdf/87ELsT7eYc5EXEknfpMt++Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807563; c=relaxed/simple; bh=KFfk0PhMePzxO9UxVYUfEp185S/glCJ9TCT8OX9EIZk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=r+TzwyZe88UKEfCiDth4Arl/Nl6CzwuH6wywVCr/t980zrMoeIHQkop42CQz9cbdXFIacXLdRKq0pZv4aAmZx9cFpqe3aY8lXIOFQFt4tOXlwZ+8RtTefgO1itom44FFNzQhvA6XvDd3GGZ1HeLfRhQadGhYzz90OgN1d0jorA8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=gIJjsRC2; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="gIJjsRC2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1779807560; bh=KFfk0PhMePzxO9UxVYUfEp185S/glCJ9TCT8OX9EIZk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=gIJjsRC2SQb/ozLLO1TRCNJiFf5pfZhROrK6JCTfAK4vOfGUDkdUSq6kWH+6hisjn 7lbCPYueKhfPeV0aa09Df9ZgWxxLABcyp0V3IHq3wxxtVj86J+PBIpzSTBUOPI/fri UgdDEu61I4N2s+uudP60JLMNzpOm9wJY0I5SyLA1RMNzfFvz3kF0Qn26TTkCmiZYJl RkHPikrw+Dqz/CZcvh52P9bHOXuYPMppKWBhDPMtidaWgb2aeFdL4J3VdPANfWH6Jl vA9D3lMiVPNkz0wAHusgPC65yJIAmHQOOqmvbPOojwFTIaBbZ6GgZ1svPtkk38wogH dGgttyFjtk+0w== Received: from yukiji.home (unknown [100.64.0.131]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laeyraud) by bali.collaboradmins.com (Postfix) with ESMTPSA id CAFAB17E12C6; Tue, 26 May 2026 16:59:18 +0200 (CEST) From: Louis-Alexis Eyraud Date: Tue, 26 May 2026 16:58:07 +0200 Subject: [PATCH net-next v5 2/6] net: phy: Add Airoha phy library for shared code 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: <20260526-add-airoha-an8801-support-v5-2-01aea8dee69b@collabora.com> References: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> In-Reply-To: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , AngeloGioacchino Del Regno , Andrew Lunn , Heiner Kallweit , Russell King Cc: kevin-kw.huang@airoha.com, macpaul.lin@mediatek.com, matthias.bgg@gmail.com, kernel@collabora.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Louis-Alexis Eyraud X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779807555; l=4623; i=louisalexis.eyraud@collabora.com; s=20250113; h=from:subject:message-id; bh=KFfk0PhMePzxO9UxVYUfEp185S/glCJ9TCT8OX9EIZk=; b=TxiLMAUdU+ehakmm52ZXTW/G8exTekECuqEeRI2TEp+lKn4rIPJDqNPjgFUEI+en4xI0HzG1h K/2HD4JYqw/AcOh4gR9ITyZXijL+P3MMk0AGAUj1kCcRGF+VzZXhd5N X-Developer-Key: i=louisalexis.eyraud@collabora.com; a=ed25519; pk=CHFBDB2Kqh4EHc6JIqFn69GhxJJAzc0Zr4e8QxtumuM= In preparation of Airoha AN8801R PHY support, split out the interface functions that will be common between the already present air_en8811h driver and the new one, and put them into a new library named air_phy_lib. Reviewed-by: Andrew Lunn Signed-off-by: Louis-Alexis Eyraud --- drivers/net/phy/Kconfig | 6 ++++++ drivers/net/phy/Makefile | 1 + drivers/net/phy/air_en8811h.c | 13 ++----------- drivers/net/phy/air_phy_lib.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/phy/air_phy_lib.h | 16 ++++++++++++++++ 5 files changed, 57 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 8b51bdc2e945..d969a792beb5 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -92,10 +92,16 @@ config AS21XXX_PHY =20 config AIR_EN8811H_PHY tristate "Airoha EN8811H 2.5 Gigabit PHY" + select AIR_NET_PHYLIB select PHY_COMMON_PROPS help Currently supports the Airoha EN8811H PHY. =20 +config AIR_NET_PHYLIB + tristate + help + Airoha Ethernet PHY common library + config AMD_PHY tristate "AMD and Altima PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 05e4878af27a..7cf1fa9e12cb 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -30,6 +30,7 @@ obj-y +=3D $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_ADIN_PHY) +=3D adin.o obj-$(CONFIG_ADIN1100_PHY) +=3D adin1100.o obj-$(CONFIG_AIR_EN8811H_PHY) +=3D air_en8811h.o +obj-$(CONFIG_AIR_NET_PHYLIB) +=3D air_phy_lib.o obj-$(CONFIG_AMD_PHY) +=3D amd.o obj-$(CONFIG_AMCC_QT2025_PHY) +=3D qt2025.o obj-$(CONFIG_AQUANTIA_PHY) +=3D aquantia/ diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index 29ae73e65caa..be7c3426182a 100644 --- a/drivers/net/phy/air_en8811h.c +++ b/drivers/net/phy/air_en8811h.c @@ -21,6 +21,8 @@ #include #include =20 +#include "air_phy_lib.h" + #define EN8811H_PHY_ID 0x03a2a411 #define AN8811HB_PHY_ID 0xc0ff04a0 =20 @@ -40,7 +42,6 @@ #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc =20 -#define AIR_EXT_PAGE_ACCESS 0x1f #define AIR_PHY_PAGE_STANDARD 0x0000 #define AIR_PHY_PAGE_EXTENDED_4 0x0004 =20 @@ -244,16 +245,6 @@ static const unsigned long en8811h_led_trig =3D BIT(TR= IGGER_NETDEV_FULL_DUPLEX) | BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX); =20 -static int air_phy_read_page(struct phy_device *phydev) -{ - return __phy_read(phydev, AIR_EXT_PAGE_ACCESS); -} - -static int air_phy_write_page(struct phy_device *phydev, int page) -{ - return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page); -} - static int __air_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, u32 pbus_data) { diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c new file mode 100644 index 000000000000..8ef5af4becf0 --- /dev/null +++ b/drivers/net/phy/air_phy_lib.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Airoha Ethernet PHY common library + * + * Copyright (C) 2026 Airoha Technology Corp. + * Copyright (C) 2026 Collabora Ltd. + * Louis-Alexis Eyraud + */ + +#include +#include +#include + +#include "air_phy_lib.h" + +#define AIR_EXT_PAGE_ACCESS 0x1f + +int air_phy_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, AIR_EXT_PAGE_ACCESS); +} +EXPORT_SYMBOL_GPL(air_phy_read_page); + +int air_phy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page); +} +EXPORT_SYMBOL_GPL(air_phy_write_page); + +MODULE_DESCRIPTION("Airoha PHY Library"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Louis-Alexis Eyraud"); diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h new file mode 100644 index 000000000000..79367e8e5907 --- /dev/null +++ b/drivers/net/phy/air_phy_lib.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2026 Airoha Technology Corp. + * Copyright (C) 2026 Collabora Ltd. + * Louis-Alexis Eyraud + */ + +#ifndef __AIR_PHY_LIB_H +#define __AIR_PHY_LIB_H + +#include + +int air_phy_read_page(struct phy_device *phydev); +int air_phy_write_page(struct phy_device *phydev, int page); + +#endif /* __AIR_PHY_LIB_H */ --=20 2.54.0 From nobody Mon Jun 8 20:53:44 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9813E41C31E; Tue, 26 May 2026 14:59:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807565; cv=none; b=AnKbCzWWdWB46q2tpvfL1YWQBBaYXwc9EvbERqAJUYBrmdoH3puQFYKHmrm9Etr4Mj3DHxYbhEkUue1Tb7Q/Zqu+zUOCXomDA0/o0T41W+ad3RoErK4ydDZ5mhHUtNqX3Qt79r9clKrBEBfuJ332w6w0aVPj38vHvkPJy2Ai3uE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807565; c=relaxed/simple; bh=RUycHHP1Y0L/ZH0+76X6ndWUTpwKu3V/QnwT1hPq1FY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Mfx/k4m6w1qyrSmSg5WvXQLo6HTn4vkYLKPgcOvlU1KRSk/LFE9/sGHx8ur8QVHfxjleTdkZRWs+GoRpLeHfnBKbPktCYJ8ICqOlAcPV2MuEH5cVtzSDn68gAnVI6n79Kvbw2SGt+bwcA6a4oEAS1fzWFYvBNYfYQJFmzlmo4E0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=p99QfzWf; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="p99QfzWf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1779807561; bh=RUycHHP1Y0L/ZH0+76X6ndWUTpwKu3V/QnwT1hPq1FY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=p99QfzWfKVUT5c9U/Y8/W9aOKdWTVFjaP81ZBU/vBVRgyCYh/Ik0ZECJZRhUKThdw m+7DvZ0MX6dF62vuF18HZ++AyYYHZgqsAFBu69XE8ZOesm3ANcOb0htsQ9tjZtNote KRZNzmDG9Xi3zBMdoIayHtqPMgR9He3gcumczZQ0mRor4YSSgrhiGLyZatLNFV3Duz O0+79ajcH8UawA/iwXcMxPOh8xreZ4SyE6rpC6ekWylOSKd0jtYli5Dy3kOjBfW1aa 8LqaaOxTsedx1Z7wPeghs/J+CCkkd0KxV9BTkAZJtLJuIHCkvX+udJDkITLHuDBsRF SuKqeZKzXTKOQ== Received: from yukiji.home (unknown [100.64.0.131]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laeyraud) by bali.collaboradmins.com (Postfix) with ESMTPSA id 7CDAB17E1418; Tue, 26 May 2026 16:59:20 +0200 (CEST) From: Louis-Alexis Eyraud Date: Tue, 26 May 2026 16:58:08 +0200 Subject: [PATCH net-next v5 3/6] net: phy: air_phy_lib: Factorize BuckPBus register accessors 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: <20260526-add-airoha-an8801-support-v5-3-01aea8dee69b@collabora.com> References: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> In-Reply-To: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , AngeloGioacchino Del Regno , Andrew Lunn , Heiner Kallweit , Russell King Cc: kevin-kw.huang@airoha.com, macpaul.lin@mediatek.com, matthias.bgg@gmail.com, kernel@collabora.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Louis-Alexis Eyraud X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779807555; l=12880; i=louisalexis.eyraud@collabora.com; s=20250113; h=from:subject:message-id; bh=RUycHHP1Y0L/ZH0+76X6ndWUTpwKu3V/QnwT1hPq1FY=; b=a3JqzTtWfKTcEU9qeUxntSLaK08bEuRN5oI3ENmIhiajdu6mbYmioPUxahpqLxZionRc69Rr1 UnCwBSc0fmYDxEYhtxXZEZ5c82ZTJ16vIBOiDTFtlRu7GILeIvgFwIl X-Developer-Key: i=louisalexis.eyraud@collabora.com; a=ed25519; pk=CHFBDB2Kqh4EHc6JIqFn69GhxJJAzc0Zr4e8QxtumuM= In preparation of Airoha AN8801R PHY support, move the BuckPBus register accessors and definitions, present in air_en8811h driver, into the Airoha PHY shared code (air_phy_lib), so they will be usable by the new driver without duplicating them. Reviewed-by: Andrew Lunn Signed-off-by: Louis-Alexis Eyraud --- drivers/net/phy/air_en8811h.c | 193 --------------------------------------= ---- drivers/net/phy/air_phy_lib.c | 181 +++++++++++++++++++++++++++++++++++++++ drivers/net/phy/air_phy_lib.h | 23 +++++ 3 files changed, 204 insertions(+), 193 deletions(-) diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index be7c3426182a..2498bd3f7993 100644 --- a/drivers/net/phy/air_en8811h.c +++ b/drivers/net/phy/air_en8811h.c @@ -42,22 +42,6 @@ #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc =20 -#define AIR_PHY_PAGE_STANDARD 0x0000 -#define AIR_PHY_PAGE_EXTENDED_4 0x0004 - -/* MII Registers Page 4*/ -#define AIR_BPBUS_MODE 0x10 -#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 -#define AIR_BPBUS_MODE_ADDR_INCR BIT(15) -#define AIR_BPBUS_WR_ADDR_HIGH 0x11 -#define AIR_BPBUS_WR_ADDR_LOW 0x12 -#define AIR_BPBUS_WR_DATA_HIGH 0x13 -#define AIR_BPBUS_WR_DATA_LOW 0x14 -#define AIR_BPBUS_RD_ADDR_HIGH 0x15 -#define AIR_BPBUS_RD_ADDR_LOW 0x16 -#define AIR_BPBUS_RD_DATA_HIGH 0x17 -#define AIR_BPBUS_RD_DATA_LOW 0x18 - /* Registers on MDIO_MMD_VEND1 */ #define EN8811H_PHY_FW_STATUS 0x8009 #define EN8811H_PHY_READY 0x02 @@ -245,183 +229,6 @@ static const unsigned long en8811h_led_trig =3D BIT(T= RIGGER_NETDEV_FULL_DUPLEX) | BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX); =20 -static int __air_buckpbus_reg_write(struct phy_device *phydev, - u32 pbus_address, u32 pbus_data) -{ - int ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data)); - if (ret < 0) - return ret; - - return 0; -} - -static int air_buckpbus_reg_write(struct phy_device *phydev, - u32 pbus_address, u32 pbus_data) -{ - int saved_page; - int ret =3D 0; - - saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - - if (saved_page >=3D 0) { - ret =3D __air_buckpbus_reg_write(phydev, pbus_address, - pbus_data); - if (ret < 0) - phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - } - - return phy_restore_page(phydev, saved_page, ret); -} - -static int __air_buckpbus_reg_read(struct phy_device *phydev, - u32 pbus_address, u32 *pbus_data) -{ - int pbus_data_low, pbus_data_high; - int ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - return ret; - - pbus_data_high =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); - if (pbus_data_high < 0) - return pbus_data_high; - - pbus_data_low =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); - if (pbus_data_low < 0) - return pbus_data_low; - - *pbus_data =3D pbus_data_low | (pbus_data_high << 16); - return 0; -} - -static int air_buckpbus_reg_read(struct phy_device *phydev, - u32 pbus_address, u32 *pbus_data) -{ - int saved_page; - int ret =3D 0; - - saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - - if (saved_page >=3D 0) { - ret =3D __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); - if (ret < 0) - phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - } - - return phy_restore_page(phydev, saved_page, ret); -} - -static int __air_buckpbus_reg_modify(struct phy_device *phydev, - u32 pbus_address, u32 mask, u32 set) -{ - int pbus_data_low, pbus_data_high; - u32 pbus_data_old, pbus_data_new; - int ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - return ret; - - pbus_data_high =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); - if (pbus_data_high < 0) - return pbus_data_high; - - pbus_data_low =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); - if (pbus_data_low < 0) - return pbus_data_low; - - pbus_data_old =3D pbus_data_low | (pbus_data_high << 16); - pbus_data_new =3D (pbus_data_old & ~mask) | set; - if (pbus_data_new =3D=3D pbus_data_old) - return 0; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data_new)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data_new)); - if (ret < 0) - return ret; - - return 0; -} - -static int air_buckpbus_reg_modify(struct phy_device *phydev, - u32 pbus_address, u32 mask, u32 set) -{ - int saved_page; - int ret =3D 0; - - saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - - if (saved_page >=3D 0) { - ret =3D __air_buckpbus_reg_modify(phydev, pbus_address, mask, - set); - if (ret < 0) - phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - } - - return phy_restore_page(phydev, saved_page, ret); -} - static int __air_write_buf(struct phy_device *phydev, u32 address, const struct firmware *fw) { diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c index 8ef5af4becf0..aba4f95fe9e6 100644 --- a/drivers/net/phy/air_phy_lib.c +++ b/drivers/net/phy/air_phy_lib.c @@ -10,11 +10,192 @@ #include #include #include +#include =20 #include "air_phy_lib.h" =20 #define AIR_EXT_PAGE_ACCESS 0x1f =20 +static int __air_buckpbus_reg_read(struct phy_device *phydev, + u32 pbus_address, u32 *pbus_data) +{ + int pbus_data_low, pbus_data_high; + int ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + pbus_data_high =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return pbus_data_high; + + pbus_data_low =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return pbus_data_low; + + *pbus_data =3D pbus_data_low | (pbus_data_high << 16); + return 0; +} + +static int __air_buckpbus_reg_write(struct phy_device *phydev, + u32 pbus_address, u32 pbus_data) +{ + int ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data)); + if (ret < 0) + return ret; + + return 0; +} + +static int __air_buckpbus_reg_modify(struct phy_device *phydev, + u32 pbus_address, u32 mask, u32 set) +{ + int pbus_data_low, pbus_data_high; + u32 pbus_data_old, pbus_data_new; + int ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + pbus_data_high =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return pbus_data_high; + + pbus_data_low =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return pbus_data_low; + + pbus_data_old =3D pbus_data_low | (pbus_data_high << 16); + pbus_data_new =3D (pbus_data_old & ~mask) | set; + if (pbus_data_new =3D=3D pbus_data_old) + return 0; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data_new)); + if (ret < 0) + return ret; + + ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data_new)); + if (ret < 0) + return ret; + + return 0; +} + +int air_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data) +{ + int saved_page; + int ret =3D 0; + + saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >=3D 0) { + ret =3D __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); + if (ret < 0) + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} +EXPORT_SYMBOL_GPL(air_buckpbus_reg_read); + +int air_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data) +{ + int saved_page; + int ret =3D 0; + + saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >=3D 0) { + ret =3D __air_buckpbus_reg_write(phydev, pbus_address, + pbus_data); + if (ret < 0) + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} +EXPORT_SYMBOL_GPL(air_buckpbus_reg_write); + +int air_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, + u32 mask, u32 set) +{ + int saved_page; + int ret =3D 0; + + saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >=3D 0) { + ret =3D __air_buckpbus_reg_modify(phydev, pbus_address, mask, + set); + if (ret < 0) + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} +EXPORT_SYMBOL_GPL(air_buckpbus_reg_modify); + int air_phy_read_page(struct phy_device *phydev) { return __phy_read(phydev, AIR_EXT_PAGE_ACCESS); diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h index 79367e8e5907..b637f3e0f2d5 100644 --- a/drivers/net/phy/air_phy_lib.h +++ b/drivers/net/phy/air_phy_lib.h @@ -10,6 +10,29 @@ =20 #include =20 +#define AIR_PHY_PAGE_STANDARD 0x0000 +#define AIR_PHY_PAGE_EXTENDED_1 0x0001 +#define AIR_PHY_PAGE_EXTENDED_4 0x0004 + +/* MII Registers Page 4*/ +#define AIR_BPBUS_MODE 0x10 +#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 +#define AIR_BPBUS_MODE_ADDR_INCR BIT(15) +#define AIR_BPBUS_WR_ADDR_HIGH 0x11 +#define AIR_BPBUS_WR_ADDR_LOW 0x12 +#define AIR_BPBUS_WR_DATA_HIGH 0x13 +#define AIR_BPBUS_WR_DATA_LOW 0x14 +#define AIR_BPBUS_RD_ADDR_HIGH 0x15 +#define AIR_BPBUS_RD_ADDR_LOW 0x16 +#define AIR_BPBUS_RD_DATA_HIGH 0x17 +#define AIR_BPBUS_RD_DATA_LOW 0x18 + +int air_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, + u32 mask, u32 set); +int air_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data); +int air_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data); int air_phy_read_page(struct phy_device *phydev); int air_phy_write_page(struct phy_device *phydev, int page); =20 --=20 2.54.0 From nobody Mon Jun 8 20:53:44 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6572C41C311; Tue, 26 May 2026 14:59:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807567; cv=none; b=Y3/pFv4YYuSoE8vY+oknSU/GINuPkgmWRpVpuMwr7gRHqTUH20AXlCt0hIbgZ5aeyexXPmdHWiVBH+Lm2uzLBTbTp1HXMWSb+izM+qlXV4VVfrcIi8NzibtfZfspzvKQW2mBm1zckFjk026e6zQy5TEQMVL/God4GhIn9mzNIMI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807567; c=relaxed/simple; bh=ET2I3+lfoBkM0vWRX1UaWCbkopH2M3jyubM2in/C+LY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EaeILNQb9WqIXif5tlGxZj6bsj3EUA8jtkOIwvOFH0TuN1Pf5qwzvV+72fhPobOX4tEY3mz1s5BM5gEskG4/NPdEeh3Cc5RiwHdykb5CRU/xK1ga8dcT5NLdZHhyUN/FGAdBBMEZTqT2TaqzhvHTv64Xb+c90yYOfF2p6jwxI18= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=RLrXaFgN; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="RLrXaFgN" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1779807563; bh=ET2I3+lfoBkM0vWRX1UaWCbkopH2M3jyubM2in/C+LY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=RLrXaFgN6UtFAr+PXzK6oC0izEutaan4xcNFP3LnE+xVQFtYqpj2XKbOGkV3BurJQ VdX1DxvNZ5DuQXtGdiqqEwQrhKfyWoZeOaI/w8VSkrA+8wSwxn0cjt/YVYWk9gTGG4 TmLBcSM33+JOy8eVmvfetfxWEBhEapXyEaoYe68oQiMZRaaBQghia5bBOhZXwZDvun vDATnoJD0WthipS/i3wI5K9YfNwzlCja2CgxUa+I4Rly6+kWOtwEmr8OOFjGuN2cX4 fNIowDt6x435hfTrGzn+uxLAZ0dd6NhXZUL/D1jT/Ocl9b5F6NUhOaVl7K0no5AJiF Wrlj75U4SGung== Received: from yukiji.home (unknown [100.64.0.131]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laeyraud) by bali.collaboradmins.com (Postfix) with ESMTPSA id 2F7D417E141E; Tue, 26 May 2026 16:59:22 +0200 (CEST) From: Louis-Alexis Eyraud Date: Tue, 26 May 2026 16:58:09 +0200 Subject: [PATCH net-next v5 4/6] net: phy: Rename Airoha common BuckPBus register accessors 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: <20260526-add-airoha-an8801-support-v5-4-01aea8dee69b@collabora.com> References: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> In-Reply-To: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , AngeloGioacchino Del Regno , Andrew Lunn , Heiner Kallweit , Russell King Cc: kevin-kw.huang@airoha.com, macpaul.lin@mediatek.com, matthias.bgg@gmail.com, kernel@collabora.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Louis-Alexis Eyraud X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779807555; l=13356; i=louisalexis.eyraud@collabora.com; s=20250113; h=from:subject:message-id; bh=ET2I3+lfoBkM0vWRX1UaWCbkopH2M3jyubM2in/C+LY=; b=CswV/uNLtvQvcaKrB/kN948jsYGLfZBpjSQxkx4z4UIZ78wbSLwry7IwRwMW3CjWdhOU9srPH /cQ7IEIDWhxC8mDPUGpq4/oED45oh6x4KV//Duc8s0QY5sL+Lf9Viyj X-Developer-Key: i=louisalexis.eyraud@collabora.com; a=ed25519; pk=CHFBDB2Kqh4EHc6JIqFn69GhxJJAzc0Zr4e8QxtumuM= Rename the BuckPBus register accessors functions present in air_phy_lib and their calls in air_en8811h driver, so all exported functions start with the same prefix. Reviewed-by: Andrew Lunn Signed-off-by: Louis-Alexis Eyraud --- drivers/net/phy/air_en8811h.c | 110 +++++++++++++++++++++-----------------= ---- drivers/net/phy/air_phy_lib.c | 18 +++---- drivers/net/phy/air_phy_lib.h | 12 ++--- 3 files changed, 71 insertions(+), 69 deletions(-) diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index 2498bd3f7993..a42898ae4135 100644 --- a/drivers/net/phy/air_en8811h.c +++ b/drivers/net/phy/air_en8811h.c @@ -287,8 +287,8 @@ static int en8811h_wait_mcu_ready(struct phy_device *ph= ydev) { int ret, reg_value; =20 - ret =3D air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_FINISH); + ret =3D air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); if (ret) return ret; =20 @@ -313,28 +313,29 @@ static int an8811hb_check_crc(struct phy_device *phyd= ev, u32 set1, int ret; =20 /* Configure CRC */ - ret =3D air_buckpbus_reg_modify(phydev, set1, - AN8811HB_CRC_RD_EN, - AN8811HB_CRC_RD_EN); + ret =3D air_phy_buckpbus_reg_modify(phydev, set1, + AN8811HB_CRC_RD_EN, + AN8811HB_CRC_RD_EN); if (ret < 0) return ret; - air_buckpbus_reg_read(phydev, set1, &pbus_value); + air_phy_buckpbus_reg_read(phydev, set1, &pbus_value); =20 do { msleep(300); - air_buckpbus_reg_read(phydev, mon2, &pbus_value); + air_phy_buckpbus_reg_read(phydev, mon2, &pbus_value); =20 /* We do not know what errors this check is supposed * catch or what to do about a failure. So print the * result and continue like the vendor driver does. */ if (pbus_value & AN8811HB_CRC_ST) { - air_buckpbus_reg_read(phydev, mon3, &pbus_value); + air_phy_buckpbus_reg_read(phydev, mon3, &pbus_value); phydev_dbg(phydev, "CRC Check %s!\n", pbus_value & AN8811HB_CRC_CHECK_PASS ? "PASS" : "FAIL"); - return air_buckpbus_reg_modify(phydev, set1, - AN8811HB_CRC_RD_EN, 0); + return air_phy_buckpbus_reg_modify(phydev, set1, + AN8811HB_CRC_RD_EN, + 0); } } while (--retry); =20 @@ -346,8 +347,8 @@ static void en8811h_print_fw_version(struct phy_device = *phydev) { struct en8811h_priv *priv =3D phydev->priv; =20 - air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, - &priv->firmware_version); + air_phy_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, + &priv->firmware_version); phydev_info(phydev, "MD32 firmware version: %08x\n", priv->firmware_version); } @@ -372,8 +373,8 @@ static int an8811hb_load_firmware(struct phy_device *ph= ydev) { int ret; =20 - ret =3D air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); + ret =3D air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); if (ret < 0) return ret; =20 @@ -414,14 +415,14 @@ static int en8811h_load_firmware(struct phy_device *p= hydev) if (ret < 0) goto en8811h_load_firmware_rel1; =20 - ret =3D air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); + ret =3D air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); if (ret < 0) goto en8811h_load_firmware_out; =20 - ret =3D air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, - EN8811H_FW_CTRL_2_LOADING); + ret =3D air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, + EN8811H_FW_CTRL_2_LOADING); if (ret < 0) goto en8811h_load_firmware_out; =20 @@ -433,8 +434,8 @@ static int en8811h_load_firmware(struct phy_device *phy= dev) if (ret < 0) goto en8811h_load_firmware_out; =20 - ret =3D air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, 0); + ret =3D air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, 0); if (ret < 0) goto en8811h_load_firmware_out; =20 @@ -460,8 +461,8 @@ static int en8811h_restart_mcu(struct phy_device *phyde= v) { int ret; =20 - ret =3D air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); + ret =3D air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); if (ret < 0) return ret; =20 @@ -755,7 +756,7 @@ static unsigned long an8811hb_clk_recalc_rate(struct cl= k_hw *hw, u32 pbus_value; int ret; =20 - ret =3D air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); + ret =3D air_phy_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); if (ret < 0) return ret; =20 @@ -767,9 +768,9 @@ static int an8811hb_clk_enable(struct clk_hw *hw) struct en8811h_priv *priv =3D clk_hw_to_en8811h_priv(hw); struct phy_device *phydev =3D priv->phydev; =20 - return air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, - AN8811HB_CLK_DRV_CKO_MASK, - AN8811HB_CLK_DRV_CKO_MASK); + return air_phy_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, + AN8811HB_CLK_DRV_CKO_MASK, + AN8811HB_CLK_DRV_CKO_MASK); } =20 static void an8811hb_clk_disable(struct clk_hw *hw) @@ -777,8 +778,8 @@ static void an8811hb_clk_disable(struct clk_hw *hw) struct en8811h_priv *priv =3D clk_hw_to_en8811h_priv(hw); struct phy_device *phydev =3D priv->phydev; =20 - air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, - AN8811HB_CLK_DRV_CKO_MASK, 0); + air_phy_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, + AN8811HB_CLK_DRV_CKO_MASK, 0); } =20 static int an8811hb_clk_is_enabled(struct clk_hw *hw) @@ -788,7 +789,7 @@ static int an8811hb_clk_is_enabled(struct clk_hw *hw) u32 pbus_value; int ret; =20 - ret =3D air_buckpbus_reg_read(phydev, AN8811HB_CLK_DRV, &pbus_value); + ret =3D air_phy_buckpbus_reg_read(phydev, AN8811HB_CLK_DRV, &pbus_value); if (ret < 0) return ret; =20 @@ -854,7 +855,7 @@ static unsigned long en8811h_clk_recalc_rate(struct clk= _hw *hw, u32 pbus_value; int ret; =20 - ret =3D air_buckpbus_reg_read(phydev, EN8811H_HWTRAP1, &pbus_value); + ret =3D air_phy_buckpbus_reg_read(phydev, EN8811H_HWTRAP1, &pbus_value); if (ret < 0) return ret; =20 @@ -866,9 +867,9 @@ static int en8811h_clk_enable(struct clk_hw *hw) struct en8811h_priv *priv =3D clk_hw_to_en8811h_priv(hw); struct phy_device *phydev =3D priv->phydev; =20 - return air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM, - EN8811H_CLK_CGM_CKO, - EN8811H_CLK_CGM_CKO); + return air_phy_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM, + EN8811H_CLK_CGM_CKO, + EN8811H_CLK_CGM_CKO); } =20 static void en8811h_clk_disable(struct clk_hw *hw) @@ -876,8 +877,8 @@ static void en8811h_clk_disable(struct clk_hw *hw) struct en8811h_priv *priv =3D clk_hw_to_en8811h_priv(hw); struct phy_device *phydev =3D priv->phydev; =20 - air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM, - EN8811H_CLK_CGM_CKO, 0); + air_phy_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM, + EN8811H_CLK_CGM_CKO, 0); } =20 static int en8811h_clk_is_enabled(struct clk_hw *hw) @@ -887,7 +888,7 @@ static int en8811h_clk_is_enabled(struct clk_hw *hw) u32 pbus_value; int ret; =20 - ret =3D air_buckpbus_reg_read(phydev, EN8811H_CLK_CGM, &pbus_value); + ret =3D air_phy_buckpbus_reg_read(phydev, EN8811H_CLK_CGM, &pbus_value); if (ret < 0) return ret; =20 @@ -998,9 +999,9 @@ static int an8811hb_probe(struct phy_device *phydev) return ret; =20 /* Configure led gpio pins as output */ - ret =3D air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, - AN8811HB_GPIO_OUTPUT_345, - AN8811HB_GPIO_OUTPUT_345); + ret =3D air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, + AN8811HB_GPIO_OUTPUT_345, + AN8811HB_GPIO_OUTPUT_345); if (ret < 0) return ret; =20 @@ -1039,9 +1040,9 @@ static int en8811h_probe(struct phy_device *phydev) return ret; =20 /* Configure led gpio pins as output */ - ret =3D air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT, - EN8811H_GPIO_OUTPUT_345, - EN8811H_GPIO_OUTPUT_345); + ret =3D air_phy_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT, + EN8811H_GPIO_OUTPUT_345, + EN8811H_GPIO_OUTPUT_345); if (ret < 0) return ret; =20 @@ -1061,9 +1062,9 @@ static int an8811hb_config_serdes_polarity(struct phy= _device *phydev) return ret; if (pol =3D=3D PHY_POL_NORMAL) pbus_value |=3D AN8811HB_RX_POLARITY_NORMAL; - ret =3D air_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY, - AN8811HB_RX_POLARITY_NORMAL, - pbus_value); + ret =3D air_phy_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY, + AN8811HB_RX_POLARITY_NORMAL, + pbus_value); if (ret < 0) return ret; =20 @@ -1074,9 +1075,9 @@ static int an8811hb_config_serdes_polarity(struct phy= _device *phydev) pbus_value =3D 0; if (pol =3D=3D PHY_POL_NORMAL) pbus_value |=3D AN8811HB_TX_POLARITY_NORMAL; - return air_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY, - AN8811HB_TX_POLARITY_NORMAL, - pbus_value); + return air_phy_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY, + AN8811HB_TX_POLARITY_NORMAL, + pbus_value); } =20 static int en8811h_config_serdes_polarity(struct phy_device *phydev) @@ -1110,9 +1111,10 @@ static int en8811h_config_serdes_polarity(struct phy= _device *phydev) if (pol =3D=3D PHY_POL_NORMAL) pbus_value |=3D EN8811H_POLARITY_TX_NORMAL; =20 - return air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, - EN8811H_POLARITY_RX_REVERSE | - EN8811H_POLARITY_TX_NORMAL, pbus_value); + return air_phy_buckpbus_reg_modify(phydev, EN8811H_POLARITY, + EN8811H_POLARITY_RX_REVERSE | + EN8811H_POLARITY_TX_NORMAL, + pbus_value); } =20 static int an8811hb_config_init(struct phy_device *phydev) @@ -1264,8 +1266,8 @@ static int en8811h_read_status(struct phy_device *phy= dev) val & MDIO_AN_10GBT_STAT_LP2_5G); } else { /* Get link partner 2.5GBASE-T ability from vendor register */ - ret =3D air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, - &pbus_value); + ret =3D air_phy_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, + &pbus_value); if (ret < 0) return ret; linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c index aba4f95fe9e6..859fa41406d1 100644 --- a/drivers/net/phy/air_phy_lib.c +++ b/drivers/net/phy/air_phy_lib.c @@ -137,8 +137,8 @@ static int __air_buckpbus_reg_modify(struct phy_device = *phydev, return 0; } =20 -int air_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, - u32 *pbus_data) +int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data) { int saved_page; int ret =3D 0; @@ -154,10 +154,10 @@ int air_buckpbus_reg_read(struct phy_device *phydev, = u32 pbus_address, =20 return phy_restore_page(phydev, saved_page, ret); } -EXPORT_SYMBOL_GPL(air_buckpbus_reg_read); +EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_read); =20 -int air_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, - u32 pbus_data) +int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data) { int saved_page; int ret =3D 0; @@ -174,10 +174,10 @@ int air_buckpbus_reg_write(struct phy_device *phydev,= u32 pbus_address, =20 return phy_restore_page(phydev, saved_page, ret); } -EXPORT_SYMBOL_GPL(air_buckpbus_reg_write); +EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_write); =20 -int air_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, - u32 mask, u32 set) +int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_addres= s, + u32 mask, u32 set) { int saved_page; int ret =3D 0; @@ -194,7 +194,7 @@ int air_buckpbus_reg_modify(struct phy_device *phydev, = u32 pbus_address, =20 return phy_restore_page(phydev, saved_page, ret); } -EXPORT_SYMBOL_GPL(air_buckpbus_reg_modify); +EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_modify); =20 int air_phy_read_page(struct phy_device *phydev) { diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h index b637f3e0f2d5..a2f8b3725761 100644 --- a/drivers/net/phy/air_phy_lib.h +++ b/drivers/net/phy/air_phy_lib.h @@ -27,12 +27,12 @@ #define AIR_BPBUS_RD_DATA_HIGH 0x17 #define AIR_BPBUS_RD_DATA_LOW 0x18 =20 -int air_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, - u32 mask, u32 set); -int air_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, - u32 *pbus_data); -int air_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, - u32 pbus_data); +int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_addres= s, + u32 mask, u32 set); +int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data); +int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data); int air_phy_read_page(struct phy_device *phydev); int air_phy_write_page(struct phy_device *phydev, int page); =20 --=20 2.54.0 From nobody Mon Jun 8 20:53:44 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 06363421A19; Tue, 26 May 2026 14:59:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807569; cv=none; b=U7kPPbLTtZ3KFahpw+brd5W4TkEq6qSukV6JXZTzf9aNQqP45sXwLrjayviqK6rjaBMrLoNqFBsL3nJ5/hT1RYy9OYK06VgqD6MDf6U+YwcZV6TF3dYMZ+wcGzrGsrArs/cbSwcX6skIBTTt980TxoSZCNyVhwpX0zQmSQoQHHg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807569; c=relaxed/simple; bh=3MKJeaz77JKUAnngOsbW3qQoxFaieHB5TZ//aRzsqRk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NVdiLPniwJl3ZCwjjN/PO+Q28NmTYorKOmIMStdj7tGZkLKb35jJjEbSt2FrZBuz6WhaS6yuqZq7BvygbfDE7io/EYKadd8wcHSlJfG25p2MmCdWK2/d8N3H7trp90L/nreYLqk6kTSPA0O7CNl6nshVxP8QCwJpbklDKtDvH04= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=FsozXN/i; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="FsozXN/i" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1779807565; bh=3MKJeaz77JKUAnngOsbW3qQoxFaieHB5TZ//aRzsqRk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=FsozXN/iBmdBS8yWB1z2zulFQtjyfAHon/gxEyvEEfvGtTHM0Qr4e3E7akCfermHz bHdYtPMYKkzM+YyxWrJqq6v5A+oi2pu4dulhWaF2zklneHtozCF1yZfmIba3Rv0KPB 4CrUS/tSAxPquYcqgY4/kQms/E4laOT0NCLxBouphm6RKg9xe7r5wR28ehjQVpH8Un 2w/nFgBCOuC17P2uPdoffy9GEO9z5Cet0L1Xwdr2ZfvbE4LWBCrHD0xkTGOD5RW1cT uQOxLp9u++DN2dv8AYOjpQbYFRaGLL23Y8X5/Gu3ArteGMOp9LjqO8KKYfKOSpZF+H LG+Kg9dkWdeZA== Received: from yukiji.home (unknown [100.64.0.131]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laeyraud) by bali.collaboradmins.com (Postfix) with ESMTPSA id D583B17E1427; Tue, 26 May 2026 16:59:23 +0200 (CEST) From: Louis-Alexis Eyraud Date: Tue, 26 May 2026 16:58:10 +0200 Subject: [PATCH net-next v5 5/6] net: phy: Introduce Airoha AN8801R Gigabit Ethernet PHY 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: <20260526-add-airoha-an8801-support-v5-5-01aea8dee69b@collabora.com> References: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> In-Reply-To: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , AngeloGioacchino Del Regno , Andrew Lunn , Heiner Kallweit , Russell King Cc: kevin-kw.huang@airoha.com, macpaul.lin@mediatek.com, matthias.bgg@gmail.com, kernel@collabora.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Louis-Alexis Eyraud X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779807555; l=33073; i=louisalexis.eyraud@collabora.com; s=20250113; h=from:subject:message-id; bh=6O3OCcYAphZUjI32Y9R1YN+RG8eOYoak8c8E6zvT06g=; b=iifQoHKlJNjF+xB/YZuxZLV9sLddkswftYlkuLuwcZtiyURCDyzj5pYBXwIk9h8uTKy0kxz5W 2JQeoKs1OKjCa8knvvvpQvhj6lS7XADEg/mQ0ULl8mtGV/O5FIeTn5g X-Developer-Key: i=louisalexis.eyraud@collabora.com; a=ed25519; pk=CHFBDB2Kqh4EHc6JIqFn69GhxJJAzc0Zr4e8QxtumuM= From: AngeloGioacchino Del Regno Introduce a driver for the Airoha AN8801R Series Gigabit Ethernet PHY; this currently supports setting up PHY LEDs, 10/100M, 1000M speeds, and Wake on LAN and PHY interrupts. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Louis-Alexis Eyraud --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/air_an8801.c | 1120 ++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 1127 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d969a792beb5..099f25dceabb 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -90,6 +90,12 @@ config AS21XXX_PHY AS21210PB1 that all register with the PHY ID 0x7500 0x7500 before the firmware is loaded. =20 +config AIR_AN8801_PHY + tristate "Airoha AN8801 Gigabit PHY" + select AIR_NET_PHYLIB + help + Currently supports the Airoha AN8801R PHY. + config AIR_EN8811H_PHY tristate "Airoha EN8811H 2.5 Gigabit PHY" select AIR_NET_PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 7cf1fa9e12cb..de660ae94945 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -29,6 +29,7 @@ obj-y +=3D $(sfp-obj-y) $(sfp-obj-m) =20 obj-$(CONFIG_ADIN_PHY) +=3D adin.o obj-$(CONFIG_ADIN1100_PHY) +=3D adin1100.o +obj-$(CONFIG_AIR_AN8801_PHY) +=3D air_an8801.o obj-$(CONFIG_AIR_EN8811H_PHY) +=3D air_en8811h.o obj-$(CONFIG_AIR_NET_PHYLIB) +=3D air_phy_lib.o obj-$(CONFIG_AMD_PHY) +=3D amd.o diff --git a/drivers/net/phy/air_an8801.c b/drivers/net/phy/air_an8801.c new file mode 100644 index 000000000000..aa24bb182d64 --- /dev/null +++ b/drivers/net/phy/air_an8801.c @@ -0,0 +1,1120 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for the Airoha AN8801 Gigabit PHY. + * + * Copyright (C) 2025 Airoha Technology Corp. + * Copyright (C) 2025 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "air_phy_lib.h" + +#define AN8801R_PHY_ID 0xc0ff0421 + +/* MII Registers */ + +/* MII Registers - Airoha Page 1 */ +#define AN8801_EXT_REG_PHY 0x14 +#define AN8801_EXT_PHY_STATUS0 GENMASK(1, 0) +#define AN8801_EXT_PHY_DOWNSHIFT_CTL GENMASK(3, 2) /* 2 to 5 1G auto-neg= attempts (0..3) */ +#define AN8801_EXT_PHY_DOWNSHIFT_EN BIT(4) +#define AN8801_EXT_PHY_CTRL0 BIT(5) +#define AN8801_EXT_PHY_STATUS1 GENMASK(8, 6) +#define AN8801_EXT_PHY_CTRL1 GENMASK(14, 9) + +/* MII Registers - Airoha Page 4 */ +#define AN8801_PBUS_ACCESS BIT(28) +#define AN8801_PBUS_EPHY_ACCESS BIT(24) +#define AN8801_PBUS_CL22_ACCESS BIT(23) + +/* BPBUS Registers */ +#define AN8801_BPBUS_REG_LED_GPIO 0x54 +#define AN8801_BPBUS_REG_LED_ID_SEL 0x58 +#define LED_ID_GPIO_SEL(led, gpio) ((led) << ((gpio) * 3)) +#define LED_ID_GPIO_SEL_MASK(gpio) (0x7 << ((gpio) * 3)) +#define AN8801_BPBUS_REG_GPIO_MODE 0x70 +#define AN8801_BPBUS_REG_PHY_IRQ_GPIO 0x7c +#define AN8801_PHY_IRQ_GPIO_NUM_MASK GENMASK(19, 16) +#define AN8801_PHY_IRQ_GPIO_NUM 1 + +#define AN8801_BPBUS_REG_CKO 0x1a4 +#define AN8801_CKO_OUTPUT_MODE_AUTO 3 + +#define AN8801_BPBUS_REG_LINK_MODE 0x5054 +#define AN8801_BPBUS_LINK_MODE_1000 BIT(0) + +#define AN8801_BPBUS_REG_BYPASS_PTP 0x21c004 +#define AN8801_BYP_PTP_SGMII_TO_GPHY BIT(8) +#define AN8801_BYP_PTP_RGMII_TO_GPHY BIT(0) + +#define AN8801_BPBUS_REG_TXDLY_STEP 0x21c024 +#define RGMII_DELAY_STEP_MASK GENMASK(2, 0) +#define RGMII_DELAY_NO_STEP 0 +#define RGMII_DELAY_STEP_1 1 +#define RGMII_DELAY_STEP_2 2 +#define RGMII_DELAY_STEP_3 3 +#define RGMII_DELAY_STEP_4 4 +#define RGMII_DELAY_STEP_5 5 +#define RGMII_DELAY_STEP_6 6 +#define RGMII_DELAY_STEP_7 7 +#define RGMII_TXDELAY_FORCE_MODE BIT(24) + +/* Default RGMII TX delay setting, corresponding to a 1.883ns delay */ +#define AN8801_RGMII_TXDELAY_DEFAULT RGMII_DELAY_STEP_4 + +#define AN8801_BPBUS_REG_RXDLY_STEP 0x21c02c +#define RGMII_RXDELAY_ALIGN BIT(4) +#define RGMII_RXDELAY_FORCE_MODE BIT(24) + +/* Default RGMII RX delay setting, corresponding to a 1.992ns delay, + * when align bit is set or -0.008ns otherwise. + */ +#define AN8801_RGMII_RXDELAY_DEFAULT RGMII_DELAY_NO_STEP + +#define AN8801_BPBUS_REG_EFIFO_CTL(x) (0x270004 + (0x100 * (x))) /* 0..2 */ +#define AN8801_EFIFO_ALL_EN GENMASK(7, 0) +#define AN8801_EFIFO_RX_EN BIT(0) +#define AN8801_EFIFO_TX_EN BIT(1) +#define AN8801_EFIFO_RX_CLK_EN BIT(2) +#define AN8801_EFIFO_TX_CLK_EN BIT(3) +#define AN8801_EFIFO_RX_EEE_EN BIT(4) +#define AN8801_EFIFO_TX_EEE_EN BIT(5) +#define AN8801_EFIFO_RX_ODD_NIBBLE_EN BIT(6) +#define AN8801_EFIFO_TX_ODD_NIBBLE_EN BIT(7) + +#define AN8801_BPBUS_REG_WOL_MAC_16_47 0x285114 +#define AN8801_BPBUS_REG_WOL_MAC_0_15 0x285118 + +#define AN8801_BPBUS_REG_WAKEUP_CTL1 0x285400 +#define AN8801_WOL_WAKE_MAGIC_EN GENMASK(3, 1) +#define AN8801_WOL_WAKE_LNKCHG_EN BIT(4) + +#define AN8801_BPBUS_REG_WAKEUP_CTL2 0x285404 +#define AN8801_WAKE_OUT_TYPE_PULSE BIT(0) /* Set/Unset: Pulse/Static */ +#define AN8801_WAKE_OUT_POLARITY_NEG BIT(1) /* Set/Unset: Negative/Posit= ive */ +#define AN8801_WAKE_OUT_WIDTH GENMASK(3, 2) +#define AN8801_WAKE_OUT_84MS 0 +#define AN8801_WAKE_OUT_168MS 1 +#define AN8801_WAKE_OUT_336MS 2 +#define AN8801_WAKE_OUT_672MS 3 +#define AN8801_WAKE_OUT_EN BIT(4) +#define AN8801_PME_WAKEUP_CLR BIT(8) + +#define AN8801_BPBUS_REG_WAKE_IRQ_EN 0x285700 +#define AN8801_BPBUS_REG_WAKE_IRQ_STS 0x285704 +#define AN8801_IRQ_WAKE_LNKCHG BIT(0) /* Wake on link change */ +#define AN8801_IRQ_WAKE_UNIPKT BIT(1) /* Wake on unicast packet */ +#define AN8801_IRQ_WAKE_MULPKT BIT(2) /* Wake on multicast packet */ +#define AN8801_IRQ_WAKE_BCPKT BIT(3) /* Wake on broadcast packet */ +#define AN8801_IRQ_WAKE_MAGICPKT BIT(4) /* Wake on magic packet */ +#define AN8801_IRQ_WAKE_ALL GENMASK(4, 0) + +/* MDIO_MMD_VEND1 Registers */ +#define AN8801_PHY_TX_PAIR_DLY_SEL_GBE 0x13 +#define AN8801_PHY_PAIR_DLY_SEL_A_GBE GENMASK(14, 12) +#define AN8801_PHY_PAIR_DLY_SEL_B_GBE GENMASK(10, 8) +#define AN8801_PHY_PAIR_DLY_SEL_C_GBE GENMASK(6, 4) +#define AN8801_PHY_PAIR_DLY_SEL_D_GBE GENMASK(2, 0) +#define AN8801_PHY_RXADC_CTRL 0xd8 +#define AN8801_PHY_RXADC_SAMP_PHSEL_A BIT(12) +#define AN8801_PHY_RXADC_SAMP_PHSEL_B BIT(8) +#define AN8801_PHY_RXADC_SAMP_PHSEL_C BIT(4) +#define AN8801_PHY_RXADC_SAMP_PHSEL_D BIT(0) +#define AN8801_PHY_RXADC_REV_0 0xd9 +#define AN8801_PHY_RXADC_REV_MASK_A GENMASK(15, 8) +#define AN8801_PHY_RXADC_REV_MASK_B GENMASK(7, 0) +#define AN8801_PHY_RXADC_REV_1 0xda +#define AN8801_PHY_RXADC_REV_MASK_C GENMASK(15, 8) +#define AN8801_PHY_RXADC_REV_MASK_D GENMASK(7, 0) + +/* MDIO_MMD_VEND2 Registers */ +#define LED_BCR 0x21 +#define LED_BCR_MODE_MASK GENMASK(1, 0) +#define LED_BCR_TIME_TEST BIT(2) +#define LED_BCR_CLK_EN BIT(3) +#define LED_BCR_EVT_ALL BIT(4) +#define LED_BCR_EXT_CTRL BIT(15) +#define LED_BCR_MODE_DISABLE 0 +#define LED_BCR_MODE_2LED 1 +#define LED_BCR_MODE_3LED_1 2 +#define LED_BCR_MODE_3LED_2 3 + +#define LED_ON_DUR 0x22 +#define LED_ON_DUR_MASK GENMASK(15, 0) + +#define LED_BLINK_DUR 0x23 +#define LED_BLINK_DUR_MASK GENMASK(15, 0) + +#define LED_ON_CTRL(i) (0x24 + ((i) * 2)) +#define LED_ON_EVT_MASK GENMASK(6, 0) +#define LED_ON_EVT_LINK_1000M BIT(0) +#define LED_ON_EVT_LINK_100M BIT(1) +#define LED_ON_EVT_LINK_10M BIT(2) +#define LED_ON_EVT_LINK_DN BIT(3) +#define LED_ON_EVT_FDX BIT(4) +#define LED_ON_EVT_HDX BIT(5) +#define LED_ON_EVT_FORCE BIT(6) +#define LED_ON_POL BIT(14) +#define LED_ON_EN BIT(15) + +#define LED_BLINK_CTRL(i) (0x25 + ((i) * 2)) +#define LED_BLINK_EVT_MASK GENMASK(9, 0) +#define LED_BLINK_EVT_1000M_TX BIT(0) +#define LED_BLINK_EVT_1000M_RX BIT(1) +#define LED_BLINK_EVT_100M_TX BIT(2) +#define LED_BLINK_EVT_100M_RX BIT(3) +#define LED_BLINK_EVT_10M_TX BIT(4) +#define LED_BLINK_EVT_10M_RX BIT(5) +#define LED_BLINK_EVT_COLLISION BIT(6) +#define LED_BLINK_EVT_RX_CRC_ERR BIT(7) +#define LED_BLINK_EVT_RX_IDLE_ERR BIT(8) +#define LED_BLINK_EVT_FORCE BIT(9) + +#define AN8801R_NUM_LEDS 3 +#define AN8801_PERIOD_SHIFT 15 +#define AN8801_PERIOD_UNIT 32768 /* (1 << AN8801_PERIOD_SHIFT) */ +#define AN8801_MAX_PERIOD_MS 2147 + +#define AN8801_REG_PHY_INTERNAL0 0x600 +#define AN8801_REG_PHY_INTERNAL1 0x601 +#define AN8801_PHY_INTFUNC_MASK GENMASK(15, 0) /* PHY internal functions= */ + +enum an8801r_led_fn { + AN8801R_LED_FN_NONE, + AN8801R_LED_FN_LINK, + AN8801R_LED_FN_ACTIVITY, + AN8801R_LED_FN_MAX, +}; + +struct an8801r_priv { + bool wake_magic_enabled; + bool wake_lnkchg_enabled; +}; + +static const unsigned long an8801r_led_trig =3D BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_RX_ERR) | + BIT(TRIGGER_NETDEV_TX); + +static int an8801_buckpbus_reg_rmw(struct phy_device *phydev, + u32 addr, u32 mask, u32 set) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, set); +} + +static int an8801_buckpbus_reg_set_bits(struct phy_device *phydev, + u32 addr, u32 mask) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, mask); +} + +static int an8801_buckpbus_reg_clear_bits(struct phy_device *phydev, + u32 addr, u32 mask) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, 0); +} + +static int an8801_buckpbus_reg_write(struct phy_device *phydev, u32 addr, + u32 data) +{ + return air_phy_buckpbus_reg_write(phydev, + addr | AN8801_PBUS_ACCESS, + data); +} + +static int an8801_buckpbus_reg_read(struct phy_device *phydev, u32 addr, + u32 *data) +{ + return air_phy_buckpbus_reg_read(phydev, + addr | AN8801_PBUS_ACCESS, + data); +} + +static u32 an8801r_led_blink_ms_to_hw(unsigned long req_ms) +{ + u32 req_ns, regval; + + if (req_ms > AN8801_MAX_PERIOD_MS) + req_ms =3D AN8801_MAX_PERIOD_MS; + + req_ns =3D req_ms * NSEC_PER_MSEC; + + /* Round to the nearest period unit... */ + regval =3D req_ns + (AN8801_PERIOD_UNIT / 2); + + /* ...and now divide by the full period */ + regval >>=3D AN8801_PERIOD_SHIFT; + + return regval; +} + +static int an8801r_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) +{ + u32 hw_delay_on, hw_delay_off; + u16 blink_dur; + bool blink; + int ret; + + if (index >=3D AN8801R_NUM_LEDS) + return -EINVAL; + + if (delay_on && delay_off) { + blink =3D true; + + if (*delay_on =3D=3D 0 || *delay_off =3D=3D 0) { + *delay_on =3D 64; + *delay_off =3D 64; + } + + hw_delay_on =3D an8801r_led_blink_ms_to_hw(*delay_on); + hw_delay_off =3D an8801r_led_blink_ms_to_hw(*delay_off); + } else { + blink =3D false; + } + + if (blink) { + blink_dur =3D (u16)min(hw_delay_on + hw_delay_off, + LED_BLINK_DUR_MASK); + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_DUR, + blink_dur); + if (ret) + goto error; + + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_DUR, + hw_delay_on); + if (ret) + goto error; + } + + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index), + LED_BLINK_EVT_MASK, + blink ? LED_BLINK_EVT_FORCE : 0); + if (ret) + return ret; + + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_EVT_MASK, + 0); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_EN, blink ? LED_ON_EN : 0); + +error: + phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_EN, 0); + return ret; +} + +static int an8801r_led_brightness_set(struct phy_device *phydev, u8 index, + enum led_brightness value) +{ + int ret; + + if (index >=3D AN8801R_NUM_LEDS) + return -EINVAL; + + /* Disable blink first if previously enabled */ + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index), + LED_BLINK_EVT_MASK, 0); + if (ret) + return ret; + + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_EVT_MASK, + (value =3D=3D LED_OFF) ? 0 : LED_ON_EVT_FORCE); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_EN, (value =3D=3D LED_OFF) ? 0 : LED_ON_EN); +} + +static int an8801r_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int on, blink; + + if (index >=3D AN8801R_NUM_LEDS) + return -EINVAL; + + on =3D phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index)); + if (on < 0) + return on; + + blink =3D phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index)); + if (blink < 0) + return blink; + + if (FIELD_GET(LED_ON_EVT_LINK_10M, on)) + __set_bit(TRIGGER_NETDEV_LINK_10, rules); + + if (FIELD_GET(LED_ON_EVT_LINK_100M, on)) + __set_bit(TRIGGER_NETDEV_LINK_100, rules); + + if (FIELD_GET(LED_ON_EVT_LINK_1000M, on)) + __set_bit(TRIGGER_NETDEV_LINK_1000, rules); + + if (FIELD_GET(LED_ON_EVT_LINK_10M, on) && + FIELD_GET(LED_ON_EVT_LINK_100M, on) && + FIELD_GET(LED_ON_EVT_LINK_1000M, on)) + __set_bit(TRIGGER_NETDEV_LINK, rules); + + if (FIELD_GET(LED_BLINK_EVT_10M_RX, blink) || + FIELD_GET(LED_BLINK_EVT_100M_RX, blink) || + FIELD_GET(LED_BLINK_EVT_1000M_RX, blink)) + __set_bit(TRIGGER_NETDEV_RX, rules); + + if (FIELD_GET(LED_BLINK_EVT_10M_TX, blink) || + FIELD_GET(LED_BLINK_EVT_100M_TX, blink) || + FIELD_GET(LED_BLINK_EVT_1000M_TX, blink)) + __set_bit(TRIGGER_NETDEV_TX, rules); + + if (FIELD_GET(LED_BLINK_EVT_RX_CRC_ERR, blink)) + __set_bit(TRIGGER_NETDEV_RX_ERR, rules); + + return 0; +} + +static int an8801r_led_trig_to_hw(unsigned long rules, u16 *on, u16 *blink) +{ + /* All combinations of the supported triggers are allowed */ + if (rules & ~an8801r_led_trig) + return -EOPNOTSUPP; + + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + *on |=3D LED_ON_EVT_LINK_10M; + + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + *on |=3D LED_ON_EVT_LINK_100M; + + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + *on |=3D LED_ON_EVT_LINK_1000M; + + if (test_bit(TRIGGER_NETDEV_LINK, &rules)) { + *on |=3D LED_ON_EVT_LINK_10M; + *on |=3D LED_ON_EVT_LINK_100M; + *on |=3D LED_ON_EVT_LINK_1000M; + } + + if (test_bit(TRIGGER_NETDEV_RX, &rules)) { + *blink |=3D LED_BLINK_EVT_10M_RX; + *blink |=3D LED_BLINK_EVT_100M_RX; + *blink |=3D LED_BLINK_EVT_1000M_RX; + } + + if (test_bit(TRIGGER_NETDEV_TX, &rules)) { + *blink |=3D LED_BLINK_EVT_10M_TX; + *blink |=3D LED_BLINK_EVT_100M_TX; + *blink |=3D LED_BLINK_EVT_1000M_TX; + } + + if (test_bit(TRIGGER_NETDEV_RX_ERR, &rules)) + *blink |=3D LED_BLINK_EVT_RX_CRC_ERR; + + return 0; +} + +static int an8801r_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 on =3D 0, blink =3D 0; + + if (index >=3D AN8801R_NUM_LEDS) + return -EINVAL; + + return an8801r_led_trig_to_hw(rules, &on, &blink); +} + +static int an8801r_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 on =3D 0, blink =3D 0; + int ret; + + if (index >=3D AN8801R_NUM_LEDS) + return -EINVAL; + + ret =3D an8801r_led_trig_to_hw(rules, &on, &blink); + if (ret) + return ret; + + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_EVT_MASK, on); + if (ret) + return ret; + + ret =3D phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index), + LED_BLINK_EVT_MASK, blink); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_EN, (on | blink) ? LED_ON_EN : 0); +} + +static int an8801r_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + bool active_high =3D true; + unsigned long mode; + + if (index >=3D AN8801R_NUM_LEDS) + return -EINVAL; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_HIGH: + break; + case PHY_LED_ACTIVE_LOW: + active_high =3D false; + break; + default: + return -EINVAL; + } + } + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), + LED_ON_POL, active_high ? LED_ON_POL : 0); +} + +static int an8801r_led_init(struct phy_device *phydev, u8 *led_cfg) +{ + int led_id, ret; + + /* Set LED BCR Enable */ + ret =3D phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, LED_BCR, + LED_BCR_EXT_CTRL | LED_BCR_CLK_EN); + if (ret) + return ret; + + for (led_id =3D 0; led_id < AN8801R_NUM_LEDS; led_id++) { + unsigned long led_trigger =3D 0; + u32 led_gpio =3D led_id + 1; + + switch (led_cfg[led_id]) { + case AN8801R_LED_FN_LINK: + led_trigger =3D BIT(TRIGGER_NETDEV_LINK); + break; + case AN8801R_LED_FN_ACTIVITY: + led_trigger =3D BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX); + break; + default: + led_trigger =3D 0; + break; + } + + ret =3D an8801_buckpbus_reg_set_bits(phydev, + AN8801_BPBUS_REG_LED_GPIO, + BIT(led_gpio)); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_rmw(phydev, + AN8801_BPBUS_REG_LED_ID_SEL, + LED_ID_GPIO_SEL_MASK(led_gpio), + LED_ID_GPIO_SEL(led_id, + led_gpio)); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_clear_bits(phydev, + AN8801_BPBUS_REG_GPIO_MODE, + BIT(led_gpio)); + if (ret) + return ret; + + if (!led_trigger) + continue; + + ret =3D an8801r_led_hw_control_set(phydev, led_id, led_trigger); + if (ret) + return ret; + } + + return ret; +} + +static int an8801r_reset_wake(struct phy_device *phydev) +{ + struct an8801r_priv *priv =3D phydev->priv; + u32 reg_val =3D 0; + int ret; + + /* Enable wakeup clear and disable wake up output */ + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2, + AN8801_PME_WAKEUP_CLR | + AN8801_WAKE_OUT_POLARITY_NEG); + if (ret) + return ret; + + /* Clear WAKEUP_CTL1 register before enabling the wakeup events + * again + */ + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1, + 0); + if (ret) + return ret; + + if (priv->wake_magic_enabled) + reg_val |=3D AN8801_WOL_WAKE_MAGIC_EN; + + if (priv->wake_lnkchg_enabled) + reg_val |=3D AN8801_WOL_WAKE_LNKCHG_EN; + + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1, + reg_val); + if (ret) + return ret; + + /* Disable wake up clear and re-enable wake up output */ + return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2, + AN8801_WAKE_OUT_POLARITY_NEG | + AN8801_WAKE_OUT_EN); +} + +static int an8801r_ack_interrupt(struct phy_device *phydev) +{ + int ret; + + /* Reset wake status */ + ret =3D an8801r_reset_wake(phydev); + if (ret) + return ret; + + /* Clear the interrupts by writing the reg */ + return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS, + AN8801_IRQ_WAKE_ALL); +} + +static int an8801r_config_intr(struct phy_device *phydev) +{ + int ret; + + if (phydev->interrupts =3D=3D PHY_INTERRUPT_ENABLED) { + u32 val =3D FIELD_PREP(AN8801_PHY_IRQ_GPIO_NUM_MASK, + AN8801_PHY_IRQ_GPIO_NUM); + + ret =3D an8801_buckpbus_reg_write(phydev, + AN8801_BPBUS_REG_PHY_IRQ_GPIO, + val); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_set_bits(phydev, + AN8801_BPBUS_REG_WAKE_IRQ_EN, + AN8801_IRQ_WAKE_LNKCHG); + if (ret) + return ret; + + } else { + ret =3D an8801_buckpbus_reg_write(phydev, + AN8801_BPBUS_REG_PHY_IRQ_GPIO, + 0); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_clear_bits(phydev, + AN8801_BPBUS_REG_WAKE_IRQ_EN, + AN8801_IRQ_WAKE_LNKCHG); + if (ret) + return ret; + } + + return an8801r_ack_interrupt(phydev); +} + +static irqreturn_t an8801r_handle_interrupt(struct phy_device *phydev) +{ + u32 irq_status =3D 0; + bool irq_handled =3D false; + int ret; + + ret =3D an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS, + &irq_status); + if (ret) + return IRQ_NONE; + + ret =3D an8801r_ack_interrupt(phydev); + if (ret) + return IRQ_NONE; + + if (irq_status & AN8801_IRQ_WAKE_MAGICPKT) { + pm_wakeup_event(&phydev->mdio.dev, 0); + irq_handled =3D true; + } + + if (irq_status & AN8801_IRQ_WAKE_LNKCHG) { + phy_trigger_machine(phydev); + irq_handled =3D true; + } + + return irq_handled ? IRQ_HANDLED : IRQ_NONE; +} + +static void an8801r_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + u32 reg_val; + int ret; + + /* If the PHY is not capable of waking the system, then WoL can not + * be supported. + */ + if (!device_can_wakeup(&phydev->mdio.dev)) { + wol->supported =3D 0; + return; + } + + wol->supported =3D WAKE_MAGIC; + wol->wolopts =3D 0; + + ret =3D an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1, + ®_val); + if (ret) + return; + + if (reg_val & AN8801_WOL_WAKE_MAGIC_EN) + wol->wolopts |=3D WAKE_MAGIC; + else + wol->wolopts &=3D ~WAKE_MAGIC; +} + +static int an8801r_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct an8801r_priv *priv =3D phydev->priv; + struct net_device *attach_dev; + const u8 *macaddr; + u32 reg_val; + int ret; + + if (!device_can_wakeup(&phydev->mdio.dev)) + return -EOPNOTSUPP; + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGIC) { + attach_dev =3D phydev->attached_dev; + if (!attach_dev) + return -ENODEV; + + macaddr =3D (const u8 *)attach_dev->dev_addr; + if (!is_valid_ether_addr(macaddr)) + return -EINVAL; + + /* MAC bits 16..47 */ + reg_val =3D (macaddr[2] << 24) | (macaddr[3] << 16); + reg_val |=3D (macaddr[4] << 8) | (macaddr[5]); + + ret =3D an8801_buckpbus_reg_write(phydev, + AN8801_BPBUS_REG_WOL_MAC_16_47, + reg_val); + if (ret) + return ret; + + /* MAC bits 0..15 */ + reg_val =3D (macaddr[0] << 8) | (macaddr[1]); + + ret =3D an8801_buckpbus_reg_write(phydev, + AN8801_BPBUS_REG_WOL_MAC_0_15, + reg_val); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_set_bits(phydev, + AN8801_BPBUS_REG_WAKEUP_CTL1, + AN8801_WOL_WAKE_MAGIC_EN); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_set_bits(phydev, + AN8801_BPBUS_REG_WAKE_IRQ_EN, + AN8801_IRQ_WAKE_MAGICPKT); + if (ret) + return ret; + + } else { + ret =3D an8801_buckpbus_reg_clear_bits(phydev, + AN8801_BPBUS_REG_WAKEUP_CTL1, + AN8801_WOL_WAKE_MAGIC_EN); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_clear_bits(phydev, + AN8801_BPBUS_REG_WAKE_IRQ_EN, + AN8801_IRQ_WAKE_MAGICPKT); + if (ret) + return ret; + } + + priv->wake_magic_enabled =3D !!(wol->wolopts & WAKE_MAGIC); + + return device_set_wakeup_enable(&phydev->mdio.dev, + priv->wake_magic_enabled); +} + +static int an8801r_of_init_leds(struct phy_device *phydev, u8 *led_cfg) +{ + struct device *dev =3D &phydev->mdio.dev; + struct device_node *np =3D dev->of_node; + struct device_node *leds; + u32 function_enum_idx; + int ret =3D 0; + + if (!np) + return 0; + + /* If devicetree is present, leds configuration is required */ + leds =3D of_get_child_by_name(np, "leds"); + if (!leds) + return 0; + + for_each_available_child_of_node_scoped(leds, led) { + u32 led_idx; + + ret =3D of_property_read_u32(led, "reg", &led_idx); + if (ret) + goto out; + + if (led_idx >=3D AN8801R_NUM_LEDS) { + ret =3D -EINVAL; + goto out; + } + + ret =3D of_property_read_u32(led, "function-enumerator", + &function_enum_idx); + if (ret) { + function_enum_idx =3D AN8801R_LED_FN_NONE; + ret =3D 0; + } + + if (function_enum_idx >=3D AN8801R_LED_FN_MAX) { + ret =3D -EINVAL; + goto out; + } + + led_cfg[led_idx] =3D function_enum_idx; + } +out: + of_node_put(leds); + return ret; +} + +static int an8801r_rgmii_rxdelay(struct phy_device *phydev, bool enable, + u16 delay_steps) +{ + u32 reg_val; + + if (delay_steps > RGMII_DELAY_STEP_MASK) + return -EINVAL; + + if (enable) { + /* Set force mode bit to enable RX delay insertion */ + reg_val =3D delay_steps | RGMII_RXDELAY_FORCE_MODE; + + /* Set align bit to add extra offset for RX delay */ + reg_val |=3D RGMII_RXDELAY_ALIGN; + } else { + reg_val =3D 0; + } + + return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_RXDLY_STEP, + reg_val); +} + +static int an8801r_rgmii_txdelay(struct phy_device *phydev, bool enable, + u16 delay_steps) +{ + u32 reg_val; + + if (delay_steps > RGMII_DELAY_STEP_MASK) + return -EINVAL; + + if (enable) { + /* Set force mode bit to enable TX delay insertion */ + reg_val =3D delay_steps | RGMII_TXDELAY_FORCE_MODE; + } else { + reg_val =3D 0; + } + + return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_TXDLY_STEP, + reg_val); +} + +static int an8801r_rgmii_delay_config(struct phy_device *phydev) +{ + bool enable_delay; + u16 delay_step; + int ret; + + if (phydev->interface =3D=3D PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface =3D=3D PHY_INTERFACE_MODE_RGMII_TXID) { + enable_delay =3D true; + delay_step =3D AN8801_RGMII_TXDELAY_DEFAULT; + } else { + enable_delay =3D false; + delay_step =3D RGMII_DELAY_NO_STEP; + } + + ret =3D an8801r_rgmii_txdelay(phydev, enable_delay, delay_step); + if (ret) + return ret; + + if (phydev->interface =3D=3D PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface =3D=3D PHY_INTERFACE_MODE_RGMII_RXID) { + enable_delay =3D true; + delay_step =3D AN8801_RGMII_RXDELAY_DEFAULT; + } else { + enable_delay =3D false; + delay_step =3D RGMII_DELAY_NO_STEP; + } + + return an8801r_rgmii_rxdelay(phydev, enable_delay, delay_step); +} + +static int an8801r_config_init(struct phy_device *phydev) +{ + u8 led_default_function[AN8801R_NUM_LEDS] =3D { 0 }; + int ret; + + ret =3D an8801r_of_init_leds(phydev, led_default_function); + if (ret) + return ret; + + /* Disable Low Power Mode (LPM) */ + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL0, + FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x1e)); + if (ret) + return ret; + + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL1, + FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x2)); + if (ret) + return ret; + + /* Set the PHY to perform auto-downshift after 3 auto-negotiation + * attempts + */ + ret =3D phy_write_paged(phydev, AIR_PHY_PAGE_EXTENDED_1, + AN8801_EXT_REG_PHY, + FIELD_PREP(AN8801_EXT_PHY_CTRL1, 0x1d) | + FIELD_PREP(AN8801_EXT_PHY_DOWNSHIFT_CTL, 1) | + AN8801_EXT_PHY_DOWNSHIFT_EN); + if (ret < 0) + return ret; + + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_BYPASS_PTP, + AN8801_BYP_PTP_RGMII_TO_GPHY); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(0), + AN8801_EFIFO_RX_EN | + AN8801_EFIFO_TX_EN | + AN8801_EFIFO_RX_CLK_EN | + AN8801_EFIFO_TX_CLK_EN | + AN8801_EFIFO_RX_EEE_EN | + AN8801_EFIFO_TX_EEE_EN); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(1), + AN8801_EFIFO_ALL_EN); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(2), + AN8801_EFIFO_ALL_EN); + if (ret) + return ret; + + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND1, + AN8801_PHY_TX_PAIR_DLY_SEL_GBE, + FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_A_GBE, 4) | + FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_C_GBE, 4)); + if (ret) + return ret; + + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_CTRL, + AN8801_PHY_RXADC_SAMP_PHSEL_A | + AN8801_PHY_RXADC_SAMP_PHSEL_C); + if (ret) + return ret; + + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_0, + FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_A, 1)); + if (ret) + return ret; + + ret =3D phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_1, + FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_C, 1)); + if (ret) + return ret; + + ret =3D an8801r_rgmii_delay_config(phydev); + if (ret) + return ret; + + ret =3D an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_CKO, + AN8801_CKO_OUTPUT_MODE_AUTO); + if (ret) + return ret; + + ret =3D an8801r_led_init(phydev, led_default_function); + if (ret) { + phydev_err(phydev, "Cannot initialize LEDs: %d\n", ret); + return ret; + } + + return 0; +} + +static int an8801r_probe(struct phy_device *phydev) +{ + struct device *dev =3D &phydev->mdio.dev; + struct an8801r_priv *priv; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->wake_lnkchg_enabled =3D true; + + phydev->priv =3D priv; + + /* Mark this PHY as wakeup capable and register the interrupt as a + * wakeup IRQ if the PHY is marked as a wakeup source in devicetree, + * and the interrupt is valid. + */ + if (of_property_read_bool(dev->of_node, "wakeup-source") && + phy_interrupt_is_valid(phydev)) { + device_set_wakeup_capable(dev, true); + devm_pm_set_wake_irq(dev, phydev->irq); + } + + return 0; +} + +static int an8801r_suspend(struct phy_device *phydev) +{ + struct an8801r_priv *priv =3D phydev->priv; + int ret; + + /* If the PHY may wake up by a Wake-on-LAN (WOL) event, disable the link + * interrupt to only keep the WOL magic interrupt enabled + */ + if (device_may_wakeup(&phydev->mdio.dev)) { + priv->wake_lnkchg_enabled =3D false; + + if (phydev->interrupts =3D=3D PHY_INTERRUPT_ENABLED) { + ret =3D an8801_buckpbus_reg_clear_bits(phydev, + AN8801_BPBUS_REG_WAKE_IRQ_EN, + AN8801_IRQ_WAKE_LNKCHG); + if (ret) + return ret; + } + + /* Reset WOL status */ + ret =3D an8801r_reset_wake(phydev); + if (ret) + return ret; + } + + if (!phydev->wol_enabled) + return genphy_suspend(phydev); + + return 0; +} + +static int an8801r_resume(struct phy_device *phydev) +{ + struct an8801r_priv *priv =3D phydev->priv; + int ret; + + ret =3D genphy_resume(phydev); + if (ret) + return ret; + + /* Restore the interrupt enable so phylib can receive link + * state interrupts. + */ + if (device_may_wakeup(&phydev->mdio.dev)) { + priv->wake_lnkchg_enabled =3D true; + + ret =3D an8801_buckpbus_reg_set_bits(phydev, + AN8801_BPBUS_REG_WAKEUP_CTL1, + AN8801_WOL_WAKE_LNKCHG_EN); + if (ret) + return ret; + + if (phydev->interrupts =3D=3D PHY_INTERRUPT_ENABLED) { + ret =3D an8801_buckpbus_reg_set_bits(phydev, + AN8801_BPBUS_REG_WAKE_IRQ_EN, + AN8801_IRQ_WAKE_LNKCHG); + } + } + + return ret; +} + +static struct phy_driver airoha_driver[] =3D { +{ + PHY_ID_MATCH_MODEL(AN8801R_PHY_ID), + .name =3D "Airoha AN8801R", + .probe =3D an8801r_probe, + .config_init =3D an8801r_config_init, + .suspend =3D an8801r_suspend, + .resume =3D an8801r_resume, + .config_aneg =3D genphy_config_aneg, + .config_intr =3D an8801r_config_intr, + .handle_interrupt =3D an8801r_handle_interrupt, + .set_wol =3D an8801r_set_wol, + .get_wol =3D an8801r_get_wol, + .read_page =3D air_phy_read_page, + .write_page =3D air_phy_write_page, + .flags =3D PHY_ALWAYS_CALL_SUSPEND, + .led_brightness_set =3D an8801r_led_brightness_set, + .led_blink_set =3D an8801r_led_blink_set, + .led_hw_is_supported =3D an8801r_led_hw_is_supported, + .led_hw_control_set =3D an8801r_led_hw_control_set, + .led_hw_control_get =3D an8801r_led_hw_control_get, + .led_polarity_set =3D an8801r_led_polarity_set, +} }; +module_phy_driver(airoha_driver); + +static struct mdio_device_id __maybe_unused an8801_tbl[] =3D { + { PHY_ID_MATCH_MODEL(AN8801R_PHY_ID) }, + { } +}; +MODULE_DEVICE_TABLE(mdio, an8801_tbl); + +MODULE_DESCRIPTION("Airoha AN8801 PHY driver"); +MODULE_AUTHOR("AngeloGioacchino Del Regno "); +MODULE_LICENSE("GPL"); --=20 2.54.0 From nobody Mon Jun 8 20:53:44 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A415E402BB0; Tue, 26 May 2026 14:59:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807570; cv=none; b=T2hTA0JnJqUpLP58Upd0Im7+iyZua7iOXtqUOgoxTIZIrwxF2MpGoz293SmtBkyJzG305omhlB+5xjgh+kJ7e/dKFZ/b5YBdb9XZaPodz7gH/HYmzLE7gUv6oKP90XHituwvq4PmEFbQIDiYOk2j4+cTiafWB2t0gTWf/8yadm0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779807570; c=relaxed/simple; bh=qDIKeceRZQi8Kht1iTmljrU4lnSxyn0oEHL2dPnESio=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=g/MP4Kv6tiP+fQxkWiMmjgBP+tgk08t+dW6KwvFBW+x7xlYPm6e8EzypJ3SpWIh8uGCNphYooCXaTpEOP+CgN0irlcsBhXXPACLcErFCNzTNEcGWe9n5d4XmNcrn07h0gq8ZY/XMTM1OhgY4BGAUjxwq/02EryFQguQ/HS/Ftos= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=IBgymD9j; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="IBgymD9j" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1779807567; bh=qDIKeceRZQi8Kht1iTmljrU4lnSxyn0oEHL2dPnESio=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=IBgymD9jo/vveamU7KQIQ/SPp78mS7Js7yWQRSQUAKFwMKjek1sPLKWJ5LbPDp0Ya 6mQ5QkKCWBxQzj1G3v4wOd0AMy+qjeUPnHGBVyj/8q3+ch77h8jtYmhbxZzhEP8Yhi OeDD01C1+JkhvtGrrY1Qdsr9HLmE7f4rF7sQ5FbsARd6VlAe9Tx6zp/rnAZMDvGsvy 8hriMyGzR1KiOhKkoF+I71euLBo3Q0hEZJGVeLWdypiUrLNaM+IfaNOnLPX39Hlhdr RQQ2vZIOUe0onX6EB2DI9ucKcpJjvRNL2fdrNajgRcZDHuJjWV/q7W5fGhNVX+8Bjy P41cLMzcV1cAA== Received: from yukiji.home (unknown [100.64.0.131]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laeyraud) by bali.collaboradmins.com (Postfix) with ESMTPSA id 87E6417E0CF3; Tue, 26 May 2026 16:59:25 +0200 (CEST) From: Louis-Alexis Eyraud Date: Tue, 26 May 2026 16:58:11 +0200 Subject: [PATCH net-next v5 6/6] net: phy: air_an8801: ensure maximum available speed link use 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: <20260526-add-airoha-an8801-support-v5-6-01aea8dee69b@collabora.com> References: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> In-Reply-To: <20260526-add-airoha-an8801-support-v5-0-01aea8dee69b@collabora.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , AngeloGioacchino Del Regno , Andrew Lunn , Heiner Kallweit , Russell King Cc: kevin-kw.huang@airoha.com, macpaul.lin@mediatek.com, matthias.bgg@gmail.com, kernel@collabora.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Louis-Alexis Eyraud X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779807555; l=2209; i=louisalexis.eyraud@collabora.com; s=20250113; h=from:subject:message-id; bh=qDIKeceRZQi8Kht1iTmljrU4lnSxyn0oEHL2dPnESio=; b=6olIzN9aEMnfSw8gvWsFpzgsQ2QyrEQpwURR/hnSZZuk3wyNrHv4JqSvAxvw44N9mUNGAoBQy 3sADk+71SEUBD7gsGYrXKlLSRNBW+437hj52O6IomH+0DItxEgJ792M X-Developer-Key: i=louisalexis.eyraud@collabora.com; a=ed25519; pk=CHFBDB2Kqh4EHc6JIqFn69GhxJJAzc0Zr4e8QxtumuM= To ensure that the Airoha AN8801R PHY uses the maximum available link speed, an additional register write is needed to configure the function mode for either 1G or 100M/10M operation after link detection. So, in air_an8801 driver, implement a custom read_status callback, that after genphy_read_status determines the link speed, sets the bit 0 of the link mode register (REG_LINK_MODE) if the detected speed is 1Gbps, or unsets it otherwise. Signed-off-by: Louis-Alexis Eyraud --- drivers/net/phy/air_an8801.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/net/phy/air_an8801.c b/drivers/net/phy/air_an8801.c index aa24bb182d64..f97c78e43023 100644 --- a/drivers/net/phy/air_an8801.c +++ b/drivers/net/phy/air_an8801.c @@ -996,6 +996,41 @@ static int an8801r_config_init(struct phy_device *phyd= ev) return 0; } =20 +static int an8801r_read_status(struct phy_device *phydev) +{ + int prev_speed, ret; + u32 val; + + prev_speed =3D phydev->speed; + + ret =3D genphy_read_status(phydev); + if (ret) + return ret; + + if (!phydev->link) { + phydev->speed =3D SPEED_UNKNOWN; + return 0; + } + + if (prev_speed !=3D phydev->speed) { + /* Ensure that PHY switches to 1G speed when available, + * by configuring the function mode for either 1G or 100M/10M + * operation. + * Therefore, set the link mode register, after read_status + * determines the link speed. + */ + val =3D phydev->speed =3D=3D SPEED_1000 ? + AN8801_BPBUS_LINK_MODE_1000 : 0; + + return an8801_buckpbus_reg_rmw(phydev, + AN8801_BPBUS_REG_LINK_MODE, + AN8801_BPBUS_LINK_MODE_1000, + val); + } + + return 0; +} + static int an8801r_probe(struct phy_device *phydev) { struct device *dev =3D &phydev->mdio.dev; @@ -1093,6 +1128,7 @@ static struct phy_driver airoha_driver[] =3D { .suspend =3D an8801r_suspend, .resume =3D an8801r_resume, .config_aneg =3D genphy_config_aneg, + .read_status =3D an8801r_read_status, .config_intr =3D an8801r_config_intr, .handle_interrupt =3D an8801r_handle_interrupt, .set_wol =3D an8801r_set_wol, --=20 2.54.0