From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 041022609E3; Tue, 26 May 2026 21:52:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=o7i9fpmXLeRD0ZcuOTKgbnFtxY6Enegh3wlGp4ALhP9AJEJQyC3Xj+gtrRv2GjukxORSbmsiHPpC5fw6hK0gqTEXGOOOvT7eAMRf3agcfWNg4uwRsXZIIbcOplF3eTDmmXl6EfAQxFAFrAcpbZrwVnVSolR9yl8Ha0Qph32FlYU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=hBpZJqzIKkIMa0o5/UN2VhueexgYznTR0lfWQhW6fHE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hKzuI7/7J4pmHD7lbOqK/0RExmpv3OMS3fN8QiUOcnv+H6xpA1C4OvEdBwgfLoNZYOxZEqwAn0Onj6N5wZ8wn6XyBOkiy0hnrZA2fWN1QQVgGoZ43qBnvK5s7QhdpOVUbIfylTWE0AVlgutuZfIzq5wkwrzjdrcHfJKZPB2FSOQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=avnk7d6w; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="avnk7d6w" Received: by smtp.kernel.org (Postfix) with ESMTPS id B2C48C2BCB3; Tue, 26 May 2026 21:52:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832339; bh=hBpZJqzIKkIMa0o5/UN2VhueexgYznTR0lfWQhW6fHE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=avnk7d6wa6M32zelIYNiUxwi7u7v+79xnz4BXpZT5ERYXZC4Ev/ywAqXxR5xdrcYp 7S3oCuC6QNP39H6P0Pmqp3pKsCDAYWnh3IAPkTcPexgJ57vzarmfYiNOgfuTQ8bhSm 7OtkdDpwWWsr8UhyMrv9mWCHoOCcdDFG3g/OcsEATJy33gIqKvE9pxvSfM2Xc/0YRP ePSo5sMnljyngXK0WPNkkkRdH5jUNnjw+Y1RN2WQ1KGHKtS6GPWrDkquEPCVMLqnnr GWRUZjNXqSdSRej1JCz38kee8cIQXiqWIQQCa2QKBvWGUcTgkIa2pDUDJvWFXzGmhz RD6hbkdT4sD9A== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9CB4ACD5BD2; Tue, 26 May 2026 21:52:19 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:46 +0300 Subject: [PATCH net-next v2 01/10] dt-bindings: net: Add ADIN1140 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: <20260527-adin1140-driver-v2-1-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=2907; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=JlftDcHzI6Sedemvx0vq0rArN9pb+7G+DJh0bC/HRsA=; b=ldO/ufoMM8dwCDnfygQsluxwJlSHRKcej8SZQMzJkaSJFQetIuxEybBYdFbWggX2ZA6sIp08T 4hnzSsSI8ZnDm8mfL9PjfJ4qecIT+qgUcjsBQZdX7BPB+2Vatz/W5K7 X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus The ADIN1140 is a single port 10BASE-T1S Ethernet controller that includes both the MAC and a PHY in the same package. Signed-off-by: Ciprian Regus --- v2 changelog: - Reorder the compatible entries in the dt schema (ad3306, adin1140). - Removed "dt-bindings" from the commit title and message. - Updated the DT example to use IRQ_TYPE_LEVEL_LOW instead of IRQ_TYPE_EDGE_FALLING for the interrupt trigger condition. - "implements" -> "tries to implement" in the description. - Removed the MAINTAINERS entry, as it will be added in a later patch in the series. - Reordered as the first patch of the series --- .../devicetree/bindings/net/adi,adin1140.yaml | 69 ++++++++++++++++++= ++++ 1 file changed, 69 insertions(+) diff --git a/Documentation/devicetree/bindings/net/adi,adin1140.yaml b/Docu= mentation/devicetree/bindings/net/adi,adin1140.yaml new file mode 100644 index 000000000000..518ff6b36c46 --- /dev/null +++ b/Documentation/devicetree/bindings/net/adi,adin1140.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/adi,adin1140.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADI ADIN1140 10BASE-T1S MAC-PHY + +maintainers: + - Ciprian Regus + +description: | + The ADIN1140 (also called AD3306) is a low power single port + 10BASE-T1S MAC-PHY. It integrates an Ethernet PHY with a MAC + and all the associated analog circuitry. + The device tries to implement the Open Alliance TC6 10BASE-T1x MAC-PHY + Serial Interface specification and is compliant with the + IEEE 802.3cg-2019 Ethernet standard for 10 Mbps single pair + Ethernet (SPE). The device has a 4-wire SPI interface for + communication between the MAC and host processor. + +allOf: + - $ref: /schemas/net/ethernet-controller.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,ad3306 + - adi,adin1140 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 25000000 + + interrupts: + maxItems: 1 + description: Interrupt from the MAC-PHY for receive data available + and error conditions + +required: + - compatible + - reg + - interrupts + - spi-max-frequency + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet@0 { + compatible =3D "adi,adin1140"; + reg =3D <0>; + spi-max-frequency =3D <23000000>; + + interrupt-parent =3D <&gpio>; + interrupts =3D <6 IRQ_TYPE_LEVEL_LOW>; + + local-mac-address =3D [ 00 11 22 33 44 55 ]; + }; + }; --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 2D6ED3C3451; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=dxwApRefs1wgpK0YWa9l2H/8Un/8i8rpuonxUtFdNBdSS1dAhjq1lTacrjumP6dt4enKBl0olnBNI94taXZStje9G9xdpejlYBFTgvXf5AljV0EYKaplZxZmelLRMINJ3Flvy00hTyOL7eSvukh0Qx4P7cl6sf2YM3ft2a2hyHo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=xwlNj4vnY4PMilpPWPjQt3BWMmoV1vdfGS56+EF0V7A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NoRdQi/OY642f44lEAm08Bj5LrBZ7QtYXQwR30lI/KDaXiij2mgrs7GUlj87Z/iRF21ESynzhDiCs6Qm/k6AJC+nrh2kYeGKy/SA3EOJHhgmUErIkYvjfgo+Byr4/gK6ldBjI9z1H24UkZ8WMZ4GNyLF14wCqivhT+6kGwQd0Tw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LlJkpjRG; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LlJkpjRG" Received: by smtp.kernel.org (Postfix) with ESMTPS id BFFD3C2BCC6; Tue, 26 May 2026 21:52:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832339; bh=xwlNj4vnY4PMilpPWPjQt3BWMmoV1vdfGS56+EF0V7A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=LlJkpjRGyQG42KfCw0/3lYsCw5zUHXdGXgzrkXr/5v71BdhF2ouSrxg1bqY45H+JP n/+7npwtCajB7Up1KLOOTwBzjej/8KY+vOSrlrJXDmEhzlk10DgvT9BOazpNlcoCJQ Rqd9d/NRl1Doa19lij4Ls4v8rnXTFwMsAYb5/Vt4pNElSAjOQcp9ND04SVme/unfoc 8AbHfxtka/qa+7fXvl5V5bewPNYwuEzaRhoiSkrLb3BvhOKhkbh40ieSaFtJ4XbbBW v3Iu9ZqrXvURbzX01T+qwByd5E/wDLYbFqWAI/8K9g6laOvdAesqfxg9q0E8JJGBTA 1oDphWaeYiBXg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC417CD6E40; Tue, 26 May 2026 21:52:19 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:47 +0300 Subject: [PATCH net-next v2 02/10] net: ethernet: oa_tc6: Handle the OA TC6 SPI protected mode 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: <20260527-adin1140-driver-v2-2-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=8718; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=IW5iHGuR2REc3ASn2CJYH948sOEAxihITnt2zuS2lDc=; b=GZ9SjxpvVEYWTtGJIKfEZHoH1r/uuoNmOA8R7MvvjSlU7NJozXJKIAv6SDLq4gDDRmTTpyML1 QgTf2MaWGx6BcrZSzGRZ4Aiqv4Gh+SdZpl2eeWVMotOoBPjY2KMBYTx X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus Implement the OA TC6 standard defined protected mode for control (register access) transactions. In addition to the current register access formats the oa_tc6 driver handles, 1's complement values of the data field are included (by both the host and the MACPHY) in the SPI transfer frames. This feature acts as an integrity check. Control write transactions look like this: |<- 32 bits ->|<--- data_size --->|<- 32 bits ->| MOSI: | ctrl header | reg write data | ignored | MISO: | (discard) | echoed ctrl hdr | echoed data | data_size (LEN =3D number of registers to read in a sequence): Unprotected: 32 x (LEN + 1) bits Protected: 2 x 32 x (LEN + 1) bits Control read transaction: |<- 32 bits ->|<--- 32 bits --> |<- data_size ->| MOSI: | ctrl header | ignored ... | MISO: | (discard) | echoed ctrl hdr | reg read data | data_size (LEN =3D number of registers to read in a sequence): Unprotected: 32 x (LEN + 1) bits Protected: 2 x 32 x (LEN + 1) bits Register data format ("reg write data" and "reg read data"): Unprotected: | W1 (normal) | W2 (normal) | ... | Wx (normal) | Protected: | W1 (normal) | W1 (complement) | ... | Wx (normal) | Wx (complement)| The protected mode state can be read from the bit 5 of CONFIG0 (0x4) register, and this setting is usually only configured during the MACPHY's reset (depending on the device it can be done by setting the state of a pin). We can read the protected mode configuration before any other register access and since the SPI transfer is initially sized for an unprotected read, the MACPHY's complement words are never clocked out and no checking is required. The data transactions (Ethernet frames) remain unchanged. Signed-off-by: Ciprian Regus --- v2 changelog: - Updated OA_TC6_CTRL_SPI_BUF_SIZE to always alloc the control transaction buffer size required by the protected mode, instead of calling krealloc if the PROTE bit is set. - Formatting to fit the 80 character column limit. --- drivers/net/ethernet/oa_tc6.c | 93 +++++++++++++++++++++++++++++++++++----= ---- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 91a906a7918a..baba5aad84df 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -24,6 +24,7 @@ #define OA_TC6_REG_CONFIG0 0x0004 #define CONFIG0_SYNC BIT(15) #define CONFIG0_ZARFE_ENABLE BIT(12) +#define CONFIG0_PROTE BIT(5) =20 /* Status Register #0 */ #define OA_TC6_REG_STATUS0 0x0008 @@ -87,14 +88,17 @@ #define OA_TC6_PHY_C45_AUTO_NEG_MMS5 5 /* MMD 7 */ #define OA_TC6_PHY_C45_POWER_UNIT_MMS6 6 /* MMD 13 */ =20 +#define OA_TC6_CTRL_PROT_REPLY_SIZE 4 #define OA_TC6_CTRL_HEADER_SIZE 4 #define OA_TC6_CTRL_REG_VALUE_SIZE 4 #define OA_TC6_CTRL_IGNORED_SIZE 4 #define OA_TC6_CTRL_MAX_REGISTERS 128 -#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\ - (OA_TC6_CTRL_MAX_REGISTERS *\ - OA_TC6_CTRL_REG_VALUE_SIZE) +\ - OA_TC6_CTRL_IGNORED_SIZE) +#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\ + (OA_TC6_CTRL_MAX_REGISTERS *\ + (OA_TC6_CTRL_REG_VALUE_SIZE +\ + OA_TC6_CTRL_PROT_REPLY_SIZE)) +\ + OA_TC6_CTRL_IGNORED_SIZE) + #define OA_TC6_CHUNK_PAYLOAD_SIZE 64 #define OA_TC6_DATA_HEADER_SIZE 4 #define OA_TC6_CHUNK_SIZE (OA_TC6_DATA_HEADER_SIZE +\ @@ -129,6 +133,7 @@ struct oa_tc6 { u8 rx_chunks_available; bool rx_buf_overflow; bool int_flag; + bool prot_ctrl; }; =20 enum oa_tc6_header_type { @@ -212,25 +217,36 @@ static void oa_tc6_update_ctrl_write_data(struct oa_t= c6 *tc6, u32 value[], { __be32 *tx_buf =3D tc6->spi_ctrl_tx_buf + OA_TC6_CTRL_HEADER_SIZE; =20 - for (int i =3D 0; i < length; i++) + for (int i =3D 0; i < length; i++) { *tx_buf++ =3D cpu_to_be32(value[i]); + if (tc6->prot_ctrl) + *tx_buf++ =3D cpu_to_be32(~value[i]); + } } =20 -static u16 oa_tc6_calculate_ctrl_buf_size(u8 length) +static u16 oa_tc6_calculate_ctrl_buf_size(u8 length, bool ctrl_prot) { + u32 reply_size =3D OA_TC6_CTRL_REG_VALUE_SIZE; + + if (ctrl_prot) + reply_size +=3D OA_TC6_CTRL_PROT_REPLY_SIZE; + /* Control command consists 4 bytes header + 4 bytes register value for - * each register + 4 bytes ignored value. + * each register (+ 4 bytes for the register value complement in case + * protected mode is used) + 4 bytes ignored value. */ - return OA_TC6_CTRL_HEADER_SIZE + OA_TC6_CTRL_REG_VALUE_SIZE * length + + return OA_TC6_CTRL_HEADER_SIZE + reply_size * length + OA_TC6_CTRL_IGNORED_SIZE; } =20 static void oa_tc6_prepare_ctrl_spi_buf(struct oa_tc6 *tc6, u32 address, u32 value[], u8 length, - enum oa_tc6_register_op reg_op) + enum oa_tc6_register_op reg_op, + u16 buf_size) { __be32 *tx_buf =3D tc6->spi_ctrl_tx_buf; =20 + memset(tx_buf, 0, buf_size); *tx_buf =3D oa_tc6_prepare_ctrl_header(address, length, reg_op); =20 if (reg_op =3D=3D OA_TC6_CTRL_REG_WRITE) @@ -253,10 +269,12 @@ static int oa_tc6_check_ctrl_write_reply(struct oa_tc= 6 *tc6, u8 size) return 0; } =20 -static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 size) +static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 length) { - u32 *rx_buf =3D tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE; - u32 *tx_buf =3D tc6->spi_ctrl_tx_buf; + __be32 *rx_buf =3D tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE; + __be32 *tx_buf =3D tc6->spi_ctrl_tx_buf; + u32 complement; + u32 reply; =20 /* The echoed control read header must match with the one that was * transmitted. @@ -264,6 +282,20 @@ static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 = *tc6, u8 size) if (*tx_buf !=3D *rx_buf) return -EPROTO; =20 + if (tc6->prot_ctrl) { + /* Skip past the echoed header to the value/complement pairs */ + rx_buf +=3D 1; + for (int i =3D 0; i < length; i++) { + reply =3D be32_to_cpu(rx_buf[0]); + complement =3D be32_to_cpu(rx_buf[1]); + + if (complement !=3D ~reply) + return -EPROTO; + + rx_buf +=3D 2; + } + } + return 0; } =20 @@ -273,8 +305,13 @@ static void oa_tc6_copy_ctrl_read_data(struct oa_tc6 *= tc6, u32 value[], __be32 *rx_buf =3D tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE + OA_TC6_CTRL_HEADER_SIZE; =20 - for (int i =3D 0; i < length; i++) + for (int i =3D 0; i < length; i++) { value[i] =3D be32_to_cpu(*rx_buf++); + + /* skip complement word */ + if (tc6->prot_ctrl) + rx_buf++; + } } =20 static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 address, u32 value[= ], @@ -283,10 +320,10 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u3= 2 address, u32 value[], u16 size; int ret; =20 - /* Prepare control command and copy to SPI control buffer */ - oa_tc6_prepare_ctrl_spi_buf(tc6, address, value, length, reg_op); + size =3D oa_tc6_calculate_ctrl_buf_size(length, tc6->prot_ctrl); =20 - size =3D oa_tc6_calculate_ctrl_buf_size(length); + /* Prepare control command and copy to SPI control buffer */ + oa_tc6_prepare_ctrl_spi_buf(tc6, address, value, length, reg_op, size); =20 /* Perform SPI transfer */ ret =3D oa_tc6_spi_transfer(tc6, OA_TC6_CTRL_HEADER, size); @@ -301,7 +338,7 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 = address, u32 value[], return oa_tc6_check_ctrl_write_reply(tc6, size); =20 /* Check echoed/received control read command reply for errors */ - ret =3D oa_tc6_check_ctrl_read_reply(tc6, size); + ret =3D oa_tc6_check_ctrl_read_reply(tc6, length); if (ret) return ret; =20 @@ -1224,6 +1261,20 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, st= ruct sk_buff *skb) } EXPORT_SYMBOL_GPL(oa_tc6_start_xmit); =20 +static int oa_tc6_check_ctrl_protection(struct oa_tc6 *tc6) +{ + u32 regval; + int ret; + + ret =3D oa_tc6_read_register(tc6, OA_TC6_REG_CONFIG0, ®val); + if (ret) + return ret; + + tc6->prot_ctrl =3D FIELD_GET(CONFIG0_PROTE, regval); + + return 0; +} + /** * oa_tc6_init - allocates and initializes oa_tc6 structure. * @spi: device with which data will be exchanged. @@ -1276,6 +1327,14 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, s= truct net_device *netdev) if (!tc6->spi_data_rx_buf) return NULL; =20 + /* Check the PROTE bit status so that we can reset the device */ + ret =3D oa_tc6_check_ctrl_protection(tc6); + if (ret) { + dev_err(&tc6->spi->dev, + "Failed to check the protection mode: %d\n", ret); + return NULL; + } + ret =3D oa_tc6_sw_reset_macphy(tc6); if (ret) { dev_err(&tc6->spi->dev, --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 14BC13B4E9D; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=g8rUroiPwUTrZ+P0TXk9sklYmU/0mDXYnQh68VQj2+YPsJYd7grXjE1TlduwGUiRKbKE09cSX+zG8bY5IMrpGu60GrWV2AXbAty3UjUpL4GMDWn2eNuzSatu+7Jngvc9yv/wz7Mdy/ulan/TKLY+C2a24RHZpWn0dbUmSTpLIM0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=nUpVC0QG3MB56nqPHHF1WjBXBZiBKt28DL44cOSKh08=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DxoK9PS7Fc5+BUKwJV00bGDX2nVkjbQiWeBEUpigkRyzpDb4NIfe+YuUX7vjfY5GnlQBn2ZPsf8GkMt2yL3otHwWP0CUNOTeaj5n49RPWmx9F2YZ5mZwlkiBsEYy1nii97AisLA6wAE0bg0/8AuVVszFc0QQqDb8ueYs6vk1sWQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=geuR/Alf; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="geuR/Alf" Received: by smtp.kernel.org (Postfix) with ESMTPS id C760EC2BCF5; Tue, 26 May 2026 21:52:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832339; bh=nUpVC0QG3MB56nqPHHF1WjBXBZiBKt28DL44cOSKh08=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=geuR/AlfpcdR83wBXdQT9D/he2X/pkuwsL1eBjhyLFnSFdqz/1bU85xGBViMIsnSj AwE6jyOu1Tbi1v49KN8+as/mBT+rABYtin2Nmq4DWVw4zXoDHPgwC+CuM4kh8UQDIg 4IMAyQgtI8yNylYA8wxP3CJHXVkWY6vFpPBJmbSF7j5UajGqKqlET/eYvHmM9FN39j UpupFyH0wW1vX9HTNHrdFjLstWV02i+bnWodcn45r2hW2HQt/i9qpplHNWLU8nItyD fwp5shGJReb3+nTSJ7DIy20QGqZVDPpryXRifbCcVQT1wq/8JxtSW07DYqWztwB1UE IH5ey5LvHJKfg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id BAD84CD6E41; Tue, 26 May 2026 21:52:19 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:48 +0300 Subject: [PATCH net-next v2 03/10] net: ethernet: oa_tc6: add OA_TC6_BROKEN_PHY quirk flag 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: <20260527-adin1140-driver-v2-3-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=5464; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=MPRIc8vmHW/vXPKJZwVJUFyrwrfcbow4YLTfjncEe+U=; b=NjdT2brTF2fS6tAjlgi1zzBHEIQOL5rVJWErUbQWKGoej/DXgNvIM1tsgVPwKM5MvMBSKpqhQ njgbUjCcU0SCA22SqJS5BcFcpLVfa8Meof+Li0ShZXWe4HyquckY29k X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus Some MAC-PHY devices need custom MDIO bus access functions to work around hardware issues. Add the OA_TC6_BROKEN_PHY quirk flag so drivers can opt in to skip oa_tc6's internal PHY init and manage the PHY themselves. When the flag is set, oa_tc6 skips MDIO bus registration, PHY discovery and PHY connection, leaving these to the driver. Drivers that do not set the flag retain the existing behavior. To avoid extending the oa_tc6_init() signature for each new option, convert it to take a config struct. Update lan865x and the framework documentation accordingly. Signed-off-by: Ciprian Regus --- v2 changelog: - Added the quirk flag field in the oa_tc6_config struct and a first value entry (OA_TC6_BROKEN_PHY) instead of the mii_bus struct. --- Documentation/networking/oa-tc6-framework.rst | 3 +-- drivers/net/ethernet/microchip/lan865x/lan865x.c | 6 +++++- drivers/net/ethernet/oa_tc6.c | 25 +++++++++++++++++---= ---- include/linux/oa_tc6.h | 12 +++++++++++- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Documentation/networking/oa-tc6-framework.rst b/Documentation/= networking/oa-tc6-framework.rst index fe2aabde923a..eaa5b4b85b34 100644 --- a/Documentation/networking/oa-tc6-framework.rst +++ b/Documentation/networking/oa-tc6-framework.rst @@ -453,8 +453,7 @@ Device drivers API =20 The include/linux/oa_tc6.h defines the following functions: =20 -.. c:function:: struct oa_tc6 *oa_tc6_init(struct spi_device *spi, \ - struct net_device *netdev) +.. c:function:: struct oa_tc6 *oa_tc6_init(struct oa_tc6_config *config); =20 Initialize OA TC6 lib. =20 diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net= /ethernet/microchip/lan865x/lan865x.c index 0277d9737369..c509c8a3e321 100644 --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c @@ -332,6 +332,7 @@ static const struct net_device_ops lan865x_netdev_ops = =3D { =20 static int lan865x_probe(struct spi_device *spi) { + struct oa_tc6_config tc6_config =3D {}; struct net_device *netdev; struct lan865x_priv *priv; int ret; @@ -346,7 +347,10 @@ static int lan865x_probe(struct spi_device *spi) spi_set_drvdata(spi, priv); INIT_WORK(&priv->multicast_work, lan865x_multicast_work_handler); =20 - priv->tc6 =3D oa_tc6_init(spi, netdev); + tc6_config.spi =3D spi; + tc6_config.netdev =3D netdev; + + priv->tc6 =3D oa_tc6_init(&tc6_config); if (!priv->tc6) { ret =3D -ENODEV; goto free_netdev; diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index baba5aad84df..7ae3639beadd 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -134,6 +134,7 @@ struct oa_tc6 { bool rx_buf_overflow; bool int_flag; bool prot_ctrl; + enum oa_tc6_quirk_flag quirk_flags; }; =20 enum oa_tc6_header_type { @@ -580,6 +581,9 @@ static int oa_tc6_phy_init(struct oa_tc6 *tc6) { int ret; =20 + if (tc6->quirk_flags & OA_TC6_BROKEN_PHY) + return 0; + ret =3D oa_tc6_check_phy_reg_direct_access_capability(tc6); if (ret) { netdev_err(tc6->netdev, @@ -616,6 +620,9 @@ static int oa_tc6_phy_init(struct oa_tc6 *tc6) =20 static void oa_tc6_phy_exit(struct oa_tc6 *tc6) { + if (tc6->quirk_flags & OA_TC6_BROKEN_PHY) + return; + phy_disconnect(tc6->phydev); oa_tc6_mdiobus_unregister(tc6); } @@ -1277,24 +1284,28 @@ static int oa_tc6_check_ctrl_protection(struct oa_t= c6 *tc6) =20 /** * oa_tc6_init - allocates and initializes oa_tc6 structure. - * @spi: device with which data will be exchanged. - * @netdev: network device interface structure. + * @config: pointer to a caller-filled structure describing the MACPHY + * (SPI device, net_device, and config flags). * * Return: pointer reference to the oa_tc6 structure if the MAC-PHY * initialization is successful otherwise NULL. */ -struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netd= ev) +struct oa_tc6 *oa_tc6_init(struct oa_tc6_config *config) { struct oa_tc6 *tc6; int ret; =20 - tc6 =3D devm_kzalloc(&spi->dev, sizeof(*tc6), GFP_KERNEL); + if (!config) + return NULL; + + tc6 =3D devm_kzalloc(&config->spi->dev, sizeof(*tc6), GFP_KERNEL); if (!tc6) return NULL; =20 - tc6->spi =3D spi; - tc6->netdev =3D netdev; - SET_NETDEV_DEV(netdev, &spi->dev); + tc6->spi =3D config->spi; + tc6->netdev =3D config->netdev; + tc6->quirk_flags =3D config->quirk_flags; + SET_NETDEV_DEV(tc6->netdev, &tc6->spi->dev); mutex_init(&tc6->spi_ctrl_lock); spin_lock_init(&tc6->tx_skb_lock); =20 diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 15f58e3c56c7..6c38bf49e2a7 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -12,7 +12,17 @@ =20 struct oa_tc6; =20 -struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netd= ev); +enum oa_tc6_quirk_flag { + OA_TC6_BROKEN_PHY =3D BIT(0), +}; + +struct oa_tc6_config { + struct spi_device *spi; + struct net_device *netdev; + enum oa_tc6_quirk_flag quirk_flags; +}; + +struct oa_tc6 *oa_tc6_init(struct oa_tc6_config *config); void oa_tc6_exit(struct oa_tc6 *tc6); int oa_tc6_write_register(struct oa_tc6 *tc6, u32 address, u32 value); int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 address, u32 value[], --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 2D6253C344B; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=VimMRB5+Tbj76RGWQ/KXh0p/CYa6YYeCYxJKsElkDsUGJp6KkBx4tdgp4DL762t8VIpZwBUCjpdhbO/xP5GorezQvTLIAocy1ep+RdwLwE51esA61y8Gdv5YsB/IzHq4KUebEx4yFxPMWV0wnAIpfgZ997pl9KyPONTEEzlvZug= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=wy3Jx648a//MUt9p/ltDo3IVRrC1JhvoQ2FZ28LqGVM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Kk/2Ef1I6Jq6M1GlWsD89IVrkP5g67iBL+alMvvKdkJn+M9A0DPr0K8nLJCxnOwXXGC5zdDHq11blzDFHjOf1iOQFyvFJxo6mceNajrjZU214acsaAgVPFT6nYbnH6lCDKEc1wmBUbJ78+HNWGn0h8MJNOhYN8qy9fPzNijFU+E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g3Tk3KA6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="g3Tk3KA6" Received: by smtp.kernel.org (Postfix) with ESMTPS id D74BFC2BCFC; Tue, 26 May 2026 21:52:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832339; bh=wy3Jx648a//MUt9p/ltDo3IVRrC1JhvoQ2FZ28LqGVM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=g3Tk3KA60xS0nHabooTXsjhTwwc/rX5pMRFRmu7pm2khhPHgn9TyuhIgj7fFWy3Am fM976EIaFBxlBJBqvohd8c1qk3HUREvceRwelMmLcV0CpRgS78W+ISr8hBsxdsDKO+ nVJmVmWmb31EX91JTjIbKd1QWzLSCnUDkQ01YxZUCoBDsODorm0JpaIWfO0zh62aP6 xhFbvormTTXjkbGMDnOeE9KVxgeNvDTnXdO/ZOl1WnoQAwn+rNXMF8gQ3Lq9g31uvO g/OuUEyn1lBz15cdJkAfbs/Xkvb48SvwW1QTbMBSpbfwXdz3FF8bL0X+o4BcbPAF0m +le+kbp5mySQQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8F88CD6E43; Tue, 26 May 2026 21:52:19 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:49 +0300 Subject: [PATCH net-next v2 04/10] net: ethernet: oa_tc6: Export the C45 access functions 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: <20260527-adin1140-driver-v2-4-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=2238; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=G2YKLlP+q7gpNa7VGIqaY6JB/wn+q0v7tTUGj7fc4Ig=; b=rXoEtqv1uWHPXPcoFBESGbR3Q5tVL3l15HQBWIwlJn83PG/06JuEZTrkdpI7sO6ZufvqNxuAG +xsByidfo8ECAxj++HQOMh/6/3lXG4A1QZPEgZr5tAPniZA+QwpJ7nU X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus The C45 access functions can still be used by some Ethernet drivers which set the OA_TC6_BROKEN_PHY flag. Export them. Signed-off-by: Ciprian Regus Reviewed-by: Andrew Lunn --- v2 changelog: - New patch --- drivers/net/ethernet/oa_tc6.c | 10 ++++++---- include/linux/oa_tc6.h | 4 ++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 7ae3639beadd..4a1fd9fd75ab 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -499,8 +499,8 @@ static int oa_tc6_get_phy_c45_mms(int devnum) } } =20 -static int oa_tc6_mdiobus_read_c45(struct mii_bus *bus, int addr, int devn= um, - int regnum) +int oa_tc6_mdiobus_read_c45(struct mii_bus *bus, int addr, int devnum, + int regnum) { struct oa_tc6 *tc6 =3D bus->priv; u32 regval; @@ -516,9 +516,10 @@ static int oa_tc6_mdiobus_read_c45(struct mii_bus *bus= , int addr, int devnum, =20 return regval; } +EXPORT_SYMBOL_GPL(oa_tc6_mdiobus_read_c45); =20 -static int oa_tc6_mdiobus_write_c45(struct mii_bus *bus, int addr, int dev= num, - int regnum, u16 val) +int oa_tc6_mdiobus_write_c45(struct mii_bus *bus, int addr, int devnum, + int regnum, u16 val) { struct oa_tc6 *tc6 =3D bus->priv; int ret; @@ -529,6 +530,7 @@ static int oa_tc6_mdiobus_write_c45(struct mii_bus *bus= , int addr, int devnum, =20 return oa_tc6_write_register(tc6, (ret << 16) | regnum, val); } +EXPORT_SYMBOL_GPL(oa_tc6_mdiobus_write_c45); =20 static int oa_tc6_mdiobus_register(struct oa_tc6 *tc6) { diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 6c38bf49e2a7..95e041d7d77b 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -32,3 +32,7 @@ int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 address= , u32 value[], u8 length); netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb); int oa_tc6_zero_align_receive_frame_enable(struct oa_tc6 *tc6); +int oa_tc6_mdiobus_read_c45(struct mii_bus *bus, int addr, int devnum, + int regnum); +int oa_tc6_mdiobus_write_c45(struct mii_bus *bus, int addr, int devnum, + int regnum, u16 val); --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 3CD663C3795; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=uL6pEfGg0pI5IO/Yvv6L9mSnTUj8kEEBnaTEYmavY2aEnPCWHL/0Xczr22dgL4NiudRTqGFtEjJSvyQaoKcZuFGNQD3sFaQAy4XjkGbtAYNl212YvWoW8duuWlxgxUt+cl26Flet9FaW9h04aSo/m00hS2fcd6VRMK3DQJd1JQI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=1c9eoilvDt8KsBuPqAsdumfD0Ru05DaX3VNSMpKYIhg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=O3WLLxlt1ONZnP7X7EFuUssTtirdHOFb3VZ54ddeYAgLfoKFRvrTSiojh2+5/hFJo0veF6Dfc/BLuTweOsZXuc9LDwl3wBjorumTjWOhbLg4BbV2ZwYR9QxbZFaXnjsGlAyaJ4Q9XkDViS3pzibRKIJ/UO1VnpMGq/Phd79tm0M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dTpWH8+R; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dTpWH8+R" Received: by smtp.kernel.org (Postfix) with ESMTPS id E274EC2BCFF; Tue, 26 May 2026 21:52:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832340; bh=1c9eoilvDt8KsBuPqAsdumfD0Ru05DaX3VNSMpKYIhg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=dTpWH8+RVe+v1hyJNRb7nqOQ5JG22Oa5lfzDd3lKnm9viR9ny/99xrQvYmMu5qI7X Sj26rAMWJYqZBLBI91SW5jUsRJxbukbeDHr5rCpBktoXa01/NzGPUOdIgDHORpKGqI nhTr2gNtwndMXgo9UtXumdXi7qLGZysvNy+AWjTbzwobgZMdpmPDCCrEyABZ0RDO+r URId+K2dYk32bXTSXmqkiMwiD9YxewWwkao0eCwsoYwNJAzkWMAuTuz31a7MdntamF zxdbz9xfJPo9zl4pF/4bFJk2f1hN5Up2sWZNDJgP9KuPSwj02r6ATD3GJiA5uaMvvv Gw7Ea/sswPD8A== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7D57CD5BD5; Tue, 26 May 2026 21:52:19 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:50 +0300 Subject: [PATCH net-next v2 05/10] net: ethernet: oa_tc6: Export standard defined registers 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: <20260527-adin1140-driver-v2-5-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=8221; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=aV+GHXseVDM4Wf9bOjXPodLR5uFqPEOvaLMDmeSDI7Q=; b=gKWWUfnkaFEOFzYCAtZE5IFL012ol8G3ELyBUw1cUNXt2vT3uUCPd3aSJKQHdYJlvUjQVTmFw qTrYHkXey+XDM+lZbPKLV2au6sKeX6grm+457rUzn/+O957tvRvAhTS X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus Move defines for standard Open Alliance TC6 register addresses and subfields in the oa_tc6's header and add entries for the PHYID and CONFIG2. As such, other ethernet drivers that rely on oa_tc6 can use them directly. Signed-off-by: Ciprian Regus --- v2 changelog: - New patch --- drivers/net/ethernet/oa_tc6.c | 74 +++++++++++----------------------------= ---- include/linux/oa_tc6.h | 44 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 56 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 4a1fd9fd75ab..904bd790159d 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -11,45 +11,6 @@ #include #include =20 -/* OPEN Alliance TC6 registers */ -/* Standard Capabilities Register */ -#define OA_TC6_REG_STDCAP 0x0002 -#define STDCAP_DIRECT_PHY_REG_ACCESS BIT(8) - -/* Reset Control and Status Register */ -#define OA_TC6_REG_RESET 0x0003 -#define RESET_SWRESET BIT(0) /* Software Reset */ - -/* Configuration Register #0 */ -#define OA_TC6_REG_CONFIG0 0x0004 -#define CONFIG0_SYNC BIT(15) -#define CONFIG0_ZARFE_ENABLE BIT(12) -#define CONFIG0_PROTE BIT(5) - -/* Status Register #0 */ -#define OA_TC6_REG_STATUS0 0x0008 -#define STATUS0_RESETC BIT(6) /* Reset Complete */ -#define STATUS0_HEADER_ERROR BIT(5) -#define STATUS0_LOSS_OF_FRAME_ERROR BIT(4) -#define STATUS0_RX_BUFFER_OVERFLOW_ERROR BIT(3) -#define STATUS0_TX_PROTOCOL_ERROR BIT(0) - -/* Buffer Status Register */ -#define OA_TC6_REG_BUFFER_STATUS 0x000B -#define BUFFER_STATUS_TX_CREDITS_AVAILABLE GENMASK(15, 8) -#define BUFFER_STATUS_RX_CHUNKS_AVAILABLE GENMASK(7, 0) - -/* Interrupt Mask Register #0 */ -#define OA_TC6_REG_INT_MASK0 0x000C -#define INT_MASK0_HEADER_ERR_MASK BIT(5) -#define INT_MASK0_LOSS_OF_FRAME_ERR_MASK BIT(4) -#define INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK BIT(3) -#define INT_MASK0_TX_PROTOCOL_ERR_MASK BIT(0) - -/* PHY Clause 22 registers base address and mask */ -#define OA_TC6_PHY_STD_REG_ADDR_BASE 0xFF00 -#define OA_TC6_PHY_STD_REG_ADDR_MASK 0x1F - /* Control command header */ #define OA_TC6_CTRL_HEADER_DATA_NOT_CTRL BIT(31) #define OA_TC6_CTRL_HEADER_WRITE_NOT_READ BIT(29) @@ -445,7 +406,7 @@ static int oa_tc6_check_phy_reg_direct_access_capabilit= y(struct oa_tc6 *tc6) if (ret) return ret; =20 - if (!(regval & STDCAP_DIRECT_PHY_REG_ACCESS)) + if (!(regval & OA_TC6_STDCAP_DIRECT_PHY_REG_ACCESS)) return -ENODEV; =20 return 0; @@ -646,7 +607,7 @@ static int oa_tc6_read_status0(struct oa_tc6 *tc6) =20 static int oa_tc6_sw_reset_macphy(struct oa_tc6 *tc6) { - u32 regval =3D RESET_SWRESET; + u32 regval =3D OA_TC6_RESET_SWRESET; int ret; =20 ret =3D oa_tc6_write_register(tc6, OA_TC6_REG_RESET, regval); @@ -655,7 +616,7 @@ static int oa_tc6_sw_reset_macphy(struct oa_tc6 *tc6) =20 /* Poll for soft reset complete for every 1ms until 1s timeout */ ret =3D readx_poll_timeout(oa_tc6_read_status0, tc6, regval, - regval & STATUS0_RESETC, + regval & OA_TC6_STATUS0_RESETC, STATUS0_RESETC_POLL_DELAY, STATUS0_RESETC_POLL_TIMEOUT); if (ret) @@ -674,10 +635,10 @@ static int oa_tc6_unmask_macphy_error_interrupts(stru= ct oa_tc6 *tc6) if (ret) return ret; =20 - regval &=3D ~(INT_MASK0_TX_PROTOCOL_ERR_MASK | - INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK | - INT_MASK0_LOSS_OF_FRAME_ERR_MASK | - INT_MASK0_HEADER_ERR_MASK); + regval &=3D ~(OA_TC6_INT_MASK0_TX_PROTOCOL_ERR_MASK | + OA_TC6_INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK | + OA_TC6_INT_MASK0_LOSS_OF_FRAME_ERR_MASK | + OA_TC6_INT_MASK0_HEADER_ERR_MASK); =20 return oa_tc6_write_register(tc6, OA_TC6_REG_INT_MASK0, regval); } @@ -692,7 +653,7 @@ static int oa_tc6_enable_data_transfer(struct oa_tc6 *t= c6) return ret; =20 /* Enable configuration synchronization for data transfer */ - value |=3D CONFIG0_SYNC; + value |=3D OA_TC6_CONFIG0_SYNC; =20 return oa_tc6_write_register(tc6, OA_TC6_REG_CONFIG0, value); } @@ -735,25 +696,25 @@ static int oa_tc6_process_extended_status(struct oa_t= c6 *tc6) return ret; } =20 - if (FIELD_GET(STATUS0_RX_BUFFER_OVERFLOW_ERROR, value)) { + if (FIELD_GET(OA_TC6_STATUS0_RX_BUFFER_OVERFLOW_ERROR, value)) { tc6->rx_buf_overflow =3D true; oa_tc6_cleanup_ongoing_rx_skb(tc6); net_err_ratelimited("%s: Receive buffer overflow error\n", tc6->netdev->name); return -EAGAIN; } - if (FIELD_GET(STATUS0_TX_PROTOCOL_ERROR, value)) { + if (FIELD_GET(OA_TC6_STATUS0_TX_PROTOCOL_ERROR, value)) { netdev_err(tc6->netdev, "Transmit protocol error\n"); return -ENODEV; } /* TODO: Currently loss of frame and header errors are treated as * non-recoverable errors. They will be handled in the next version. */ - if (FIELD_GET(STATUS0_LOSS_OF_FRAME_ERROR, value)) { + if (FIELD_GET(OA_TC6_STATUS0_LOSS_OF_FRAME_ERROR, value)) { netdev_err(tc6->netdev, "Loss of frame error\n"); return -ENODEV; } - if (FIELD_GET(STATUS0_HEADER_ERROR, value)) { + if (FIELD_GET(OA_TC6_STATUS0_HEADER_ERROR, value)) { netdev_err(tc6->netdev, "Header error\n"); return -ENODEV; } @@ -1189,9 +1150,10 @@ static int oa_tc6_update_buffer_status_from_register= (struct oa_tc6 *tc6) if (ret) return ret; =20 - tc6->tx_credits =3D FIELD_GET(BUFFER_STATUS_TX_CREDITS_AVAILABLE, value); - tc6->rx_chunks_available =3D FIELD_GET(BUFFER_STATUS_RX_CHUNKS_AVAILABLE, - value); + tc6->tx_credits =3D FIELD_GET(OA_TC6_BUFFER_STATUS_TX_CREDITS_AVAILABLE, + value); + tc6->rx_chunks_available =3D + FIELD_GET(OA_TC6_BUFFER_STATUS_RX_CHUNKS_AVAILABLE, value); =20 return 0; } @@ -1231,7 +1193,7 @@ int oa_tc6_zero_align_receive_frame_enable(struct oa_= tc6 *tc6) return ret; =20 /* Set Zero-Align Receive Frame Enable */ - regval |=3D CONFIG0_ZARFE_ENABLE; + regval |=3D OA_TC6_CONFIG0_ZARFE_ENABLE; =20 return oa_tc6_write_register(tc6, OA_TC6_REG_CONFIG0, regval); } @@ -1279,7 +1241,7 @@ static int oa_tc6_check_ctrl_protection(struct oa_tc6= *tc6) if (ret) return ret; =20 - tc6->prot_ctrl =3D FIELD_GET(CONFIG0_PROTE, regval); + tc6->prot_ctrl =3D FIELD_GET(OA_TC6_CONFIG0_PROTE, regval); =20 return 0; } diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 95e041d7d77b..ad6f17218603 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -10,6 +10,50 @@ #include #include =20 +/* OPEN Alliance TC6 registers */ + +#define OA_TC6_REG_PHYID 0x0001 + +/* Standard Capabilities Register */ +#define OA_TC6_REG_STDCAP 0x0002 +#define OA_TC6_STDCAP_DIRECT_PHY_REG_ACCESS BIT(8) + +/* Reset Control and Status Register */ +#define OA_TC6_REG_RESET 0x0003 +#define OA_TC6_RESET_SWRESET BIT(0) /* Software Reset */ + +/* Configuration Register #0 */ +#define OA_TC6_REG_CONFIG0 0x0004 +#define OA_TC6_CONFIG0_SYNC BIT(15) +#define OA_TC6_CONFIG0_ZARFE_ENABLE BIT(12) +#define OA_TC6_CONFIG0_PROTE BIT(5) + +#define OA_TC6_REG_CONFIG2 0x0006 + +/* Status Register #0 */ +#define OA_TC6_REG_STATUS0 0x0008 +#define OA_TC6_STATUS0_RESETC BIT(6) /* Reset Complete */ +#define OA_TC6_STATUS0_HEADER_ERROR BIT(5) +#define OA_TC6_STATUS0_LOSS_OF_FRAME_ERROR BIT(4) +#define OA_TC6_STATUS0_RX_BUFFER_OVERFLOW_ERROR BIT(3) +#define OA_TC6_STATUS0_TX_PROTOCOL_ERROR BIT(0) + +/* Buffer Status Register */ +#define OA_TC6_REG_BUFFER_STATUS 0x000B +#define OA_TC6_BUFFER_STATUS_TX_CREDITS_AVAILABLE GENMASK(15, 8) +#define OA_TC6_BUFFER_STATUS_RX_CHUNKS_AVAILABLE GENMASK(7, 0) + +/* Interrupt Mask Register #0 */ +#define OA_TC6_REG_INT_MASK0 0x000C +#define OA_TC6_INT_MASK0_HEADER_ERR_MASK BIT(5) +#define OA_TC6_INT_MASK0_LOSS_OF_FRAME_ERR_MASK BIT(4) +#define OA_TC6_INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK BIT(3) +#define OA_TC6_INT_MASK0_TX_PROTOCOL_ERR_MASK BIT(0) + +/* PHY Clause 22 registers base address and mask */ +#define OA_TC6_PHY_STD_REG_ADDR_BASE 0xFF00 +#define OA_TC6_PHY_STD_REG_ADDR_MASK 0x1F + struct oa_tc6; =20 enum oa_tc6_quirk_flag { --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 3714F3C3455; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=sp1OPxesGCh2wyELCjVg0NvcRzlbZF4+bZ8v8D6XSnqJLSVEMWSIr6IcFiIAEveT7NzX+sutut7g2hoFFNyD1HqVO6ZdpgNg8U9uq8vZYWHnc2VaOnIIGWVpt/eMrFOZxZapWS6MkGjIunKmzno9CUCur9a8dESAtJTPGukt/as= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=VXJFwd7+XZM7tBzGTekSDUJDrHYV8J+lvqpkIxEouJE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RBSQs8jlAFT88HiDcegLaKv9jOeZjAiyIs527XCDf750pDaoVnKGF73tbFjfPyh/+yvoOb4mX/PRKroMnZ91+VH8SWtPDwqjDUrFBM8LmSlsKhQ/h1v/maFfp1HUPkfW4cqIwF2sIPTAl4VAI9F5ruM7c/esLh7LymXZ9o7bqd0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KewyH6kj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="KewyH6kj" Received: by smtp.kernel.org (Postfix) with ESMTPS id EDBF7C32786; Tue, 26 May 2026 21:52:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832340; bh=VXJFwd7+XZM7tBzGTekSDUJDrHYV8J+lvqpkIxEouJE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=KewyH6kjdZr6R6iIHvx5vqYMF8l3AXCTwNqZoLWb/LEte7ZpNZZ+hCD2R9A2Iiylo KJO6Z+h6gMA/rshXzO1LRbZDgauFiO4LbwXqeAEEgpZhLhCNMJwuGw6HUH0gk+OBTq CxopedjURp+feaX/GBB9GMbCW1QoqADGUhABeWgJ6xHSZgrd7u7b8h4QCWlh8bKg5r iefe4a8LDsXquepBadEfXSTx4mgg6ejugXirZEjiZ+u1PCwZAh1cZbKtbrjEnR5r3e RSB8cRz7gPDSo2UGewj050SJ1/31vYCSLeffFnFC7stEX0AFX+50E24rXG7eKTkKbj Fm8oa94z9FL8g== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E4DA1CD5BD2; Tue, 26 May 2026 21:52:19 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:51 +0300 Subject: [PATCH net-next v2 06/10] net: ethernet: oa_tc6: Add MMS register formatting macro 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: <20260527-adin1140-driver-v2-6-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=1763; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=5HSxO/CCFrO2eIoVbKXw+TUIV7w+rmcLQuB9FhaUalo=; b=gAhgj0HuuVyFkkyVsoXiYsNNmhf059JmCkplHxS9/qQNqowACEYivJblAY0FDgN/MPrcOhAZ9 Tbf0jXL4+GdCa1hPzqVzKEHCOZc5n1eI3gfDMULJqSTAeuYr3FhO9pw X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus The Open Alliance TC6 standard defines multiple memory maps for the MAC-PHY's register space. These are used to separate standard, vendor and PHY MMD specific registers. Add a macro to make it more clear which memory map each register is part of and allow easier definition. Signed-off-by: Ciprian Regus --- v2 changelog: - New patch --- drivers/net/ethernet/oa_tc6.c | 4 ++-- include/linux/oa_tc6.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 904bd790159d..876891ca9859 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -471,7 +471,7 @@ int oa_tc6_mdiobus_read_c45(struct mii_bus *bus, int ad= dr, int devnum, if (ret < 0) return ret; =20 - ret =3D oa_tc6_read_register(tc6, (ret << 16) | regnum, ®val); + ret =3D oa_tc6_read_register(tc6, OA_TC6_MMS_REG(ret, regnum), ®val); if (ret) return ret; =20 @@ -489,7 +489,7 @@ int oa_tc6_mdiobus_write_c45(struct mii_bus *bus, int a= ddr, int devnum, if (ret < 0) return ret; =20 - return oa_tc6_write_register(tc6, (ret << 16) | regnum, val); + return oa_tc6_write_register(tc6, OA_TC6_MMS_REG(ret, regnum), val); } EXPORT_SYMBOL_GPL(oa_tc6_mdiobus_write_c45); =20 diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index ad6f17218603..8b56a132c9e3 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -10,6 +10,9 @@ #include #include =20 +#define OA_TC6_MMS_REG(mms, reg) \ + ((((mms) & GENMASK(3, 0)) << 16) | ((reg) & GENMASK(15, 0))) + /* OPEN Alliance TC6 registers */ =20 #define OA_TC6_REG_PHYID 0x0001 --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 467B83C37B4; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=eweDJDZRPppX9ieWe0xt7qaU52/nWrfvCquwpU7XTrpWVfM2l8FvgeWW6IRW3/C4zi/eDMaVqFzinDoBWeRtWMGm8bGq4O2Ix+kGjgSdMOb59kpzwCr3Nql6cB83TGZdvhxjXHf7iLenCcQPyg7m2ndapy3U4eGIolieLNgVEn4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=+q+36NxgtETrUBoFeSMXCRVVSS2rQ61Hb75r4jxKEW8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YJndL0I+H+mSujfUvvCZOKJ9CMH3J/wdySOsJFJZ+8ipSH2m5CcA21lvS96DlHR7ReffbGmO08aXMUvgs/scxGZ+a58nkHL9y4nq3uSVT+EhesUtztFH6E8KBmw1pyOItckKhtFDAngGJO0YxvsYm9F0/StiA18+g8SXGXgU/V8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qW9ary2p; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qW9ary2p" Received: by smtp.kernel.org (Postfix) with ESMTPS id 1AC3CC2BCFB; Tue, 26 May 2026 21:52:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832340; bh=+q+36NxgtETrUBoFeSMXCRVVSS2rQ61Hb75r4jxKEW8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=qW9ary2ppRzddgsH/neVurBcDbZ1eXXaFnUIzhQ5o2yxx9tbGCr/CELiP3b6qYKuK jPK2PgX28fA8vFuzMJUZtkKZiBFu57V66lANrfJm2me+mVZ5E/VWF+BuzPwFaiB1OR n9jOc0uE+wIuODf/IY/XAgHdJVKXv7vBN933GUn3TfW3/ytcNBOj9NP7Im5lZk5lns WIXclLhyTmx2xyaVwzNB68fH9s9jBknfGegGfwM3xn0kAtzPYVAQP8dBVGuQSqidqU dTvBDcKANG3LdV5tZ2wZhDDH735nBF+T2fkClXw6uhXfqkpc/VKwhphHdrbrJkmLHb D262wHsxQnxtw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 12CF4CD5BD2; Tue, 26 May 2026 21:52:20 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:52 +0300 Subject: [PATCH net-next v2 07/10] net: phy: add generic helpers for direct C45 MMD access 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: <20260527-adin1140-driver-v2-7-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=2612; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=7mroT6JJ6YFYiL9jDdwaD4TEYFyc1gd5zGLfb5xFPLw=; b=WOSYYZ/LEUut3iSGgtDq/bazAuPqPWvCh5EO0TnO4VdZL/I4gLYNqSQAV0BeE8SjJcdAGJOX6 gzT62vGD9AODbssnyXUzsiEF2L50sYnDUesiJA054sz+mRNvdYwPGNA X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus Some PHYs support direct C45 register access but not C22 indirect MMD access (registers 0xD and 0xE). When discovered via C22, phylib routes MMD access through the indirect path, which won't work on these devices. Add genphy_read_mmd_c45() and genphy_write_mmd_c45() as read_mmd/ write_mmd callbacks that bypass the C22 indirect path and use the bus C45 accessors directly. Signed-off-by: Ciprian Regus Reviewed-by: Andrew Lunn --- v2 changelog: - New patch --- drivers/net/phy/phy_device.c | 25 +++++++++++++++++++++++++ include/linux/phy.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 3370eb822017..d33d096e700d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2764,6 +2764,31 @@ int genphy_read_abilities(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_read_abilities); =20 +/* Some PHYs support direct C45 register access but not C22 indirect + * MMD access (registers 13 and 14). When discovered via C22, phylib + * routes MMD access through the indirect path, which won't work on + * these devices. These helpers bypass indirect access and use the bus + * C45 accessors directly. + */ +int genphy_read_mmd_c45(struct phy_device *phydev, int devnum, u16 regnum) +{ + struct mii_bus *bus =3D phydev->mdio.bus; + int addr =3D phydev->mdio.addr; + + return __mdiobus_c45_read(bus, addr, devnum, regnum); +} +EXPORT_SYMBOL(genphy_read_mmd_c45); + +int genphy_write_mmd_c45(struct phy_device *phydev, int devnum, u16 regnum, + u16 val) +{ + struct mii_bus *bus =3D phydev->mdio.bus; + int addr =3D phydev->mdio.addr; + + return __mdiobus_c45_write(bus, addr, devnum, regnum, val); +} +EXPORT_SYMBOL(genphy_write_mmd_c45); + /* This is used for the phy device which doesn't support the MMD extended * register access, but it does have side effect when we are trying to acc= ess * the MMD register via indirect method. diff --git a/include/linux/phy.h b/include/linux/phy.h index 199a7aaa341b..432d44188dbc 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -2297,6 +2297,9 @@ static inline int genphy_no_config_intr(struct phy_de= vice *phydev) { return 0; } +int genphy_read_mmd_c45(struct phy_device *phydev, int devnum, u16 regnum); +int genphy_write_mmd_c45(struct phy_device *phydev, int devnum, u16 regnum, + u16 val); int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, u16 regnum); int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 518A63C3C10; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=VRPSy4nkInN3T8ZnuZ01A0kVxJLiWV1LfQwgGkMT8TJAH06oBpAmLSvU/yaGzO3i7LaYCLHmqWS5xXAcS3WG6PaLUhxo0HPyRCUWUkZ6NsQZEcsTIFZPerMA15Bn350IvvzTdmBRqtHHNrohn7kXPPM0CTuRhZPxYVR+ZS6sxFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=xY9q0pRRYwa9q25bCkjPTw/GQUB2n+PKZ0TiKQRf6Rg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dJQmTe8/5nKjsolpL2Fzmn/FLuAUg3jVT+QBj7rJBsAjM+8di5n2laWgTl+I/UNoBM+IImH6RDd9ilH2jFnvSXY4KXIoj7UmAJnUjcKU4PscZg9vth7nt5hzL7SBWaRYiUOfjePGBDE9tseMhBeV2FNhhKPGgLJIJ1ZjSGaDZD8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ao96Z2//; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ao96Z2//" Received: by smtp.kernel.org (Postfix) with ESMTPS id 2839BC2BCB3; Tue, 26 May 2026 21:52:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832340; bh=xY9q0pRRYwa9q25bCkjPTw/GQUB2n+PKZ0TiKQRf6Rg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ao96Z2//q3yWxRDKVrJomnm0R0+q+IX3Me4JxIsFsG8CvnhkMNwss40GV7KULmg9u npkv6H9qfp2osMHWz7okAVM0HUbcoi4TGKhc0hM1YnqgwwBGbdQ+KfHlpLJrlCxX4j W5gSi1ljNyfXuWcrzMRpoMq7OrBfn/7Kmf3WFGhehia+xSvivM0ISLNmOv6PaN5MBU DUWfxJ9N48WpKihfB2klmp3cCvDlAogNN36MfeAtZ5NBec8sGyl5xFwjaWDiRzp7Ah yuFdu8oHzD+q1cE+vMUrAhNax8aK0Jbu80m4SnIGmuY/wkb4qgmb0kM2RdEDUkQRjP V63GLW0j2bKbg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1F626CD6E41; Tue, 26 May 2026 21:52:20 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:53 +0300 Subject: [PATCH net-next v2 08/10] net: phy: microchip-t1s: use generic C45 MMD access helpers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260527-adin1140-driver-v2-8-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=2543; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=G25PvlzDzFteb9EPaVnGGuMAZ1Q1HnMvb5P4glW7CCc=; b=l+I90Erxm8QGOJR8yiMjbfm0bFCklvd8Msn8vzD/x5jkpkWg8DwoUlv6iwu83u0e2XZvlSd8F g+F+1xa1gHuD9hID6+VyielMSbIQMzF887m3L86p4sPkAdUP5EaEPhr X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus Replace the driver specific lan865x_phy_read_mmd() and lan865x_phy_write_mmd() with the shared genphy_read_mmd_c45() and genphy_write_mmd_c45() helpers. No functional change. Signed-off-by: Ciprian Regus Reviewed-by: Andrew Lunn --- v2 changelog: - New patch --- drivers/net/phy/microchip_t1s.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1= s.c index e601d56b2507..73c23d311d72 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -506,34 +506,6 @@ static int lan86xx_read_status(struct phy_device *phyd= ev) return 0; } =20 -/* OPEN Alliance 10BASE-T1x compliance MAC-PHYs will have both C22 and - * C45 registers space. If the PHY is discovered via C22 bus protocol it a= ssumes - * it uses C22 protocol and always uses C22 registers indirect access to a= ccess - * C45 registers. This is because, we don't have a clean separation between - * C22/C45 register space and C22/C45 MDIO bus protocols. Resulting, PHY C= 45 - * registers direct access can't be used which can save multiple SPI bus a= ccess. - * To support this feature, set .read_mmd/.write_mmd in the PHY driver to = call - * .read_c45/.write_c45 in the OPEN Alliance framework - * drivers/net/ethernet/oa_tc6.c - */ -static int lan865x_phy_read_mmd(struct phy_device *phydev, int devnum, - u16 regnum) -{ - struct mii_bus *bus =3D phydev->mdio.bus; - int addr =3D phydev->mdio.addr; - - return __mdiobus_c45_read(bus, addr, devnum, regnum); -} - -static int lan865x_phy_write_mmd(struct phy_device *phydev, int devnum, - u16 regnum, u16 val) -{ - struct mii_bus *bus =3D phydev->mdio.bus; - int addr =3D phydev->mdio.addr; - - return __mdiobus_c45_write(bus, addr, devnum, regnum, val); -} - static struct phy_driver microchip_t1s_driver[] =3D { { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1), @@ -584,8 +556,8 @@ static struct phy_driver microchip_t1s_driver[] =3D { .features =3D PHY_BASIC_T1S_P2MP_FEATURES, .config_init =3D lan865x_revb_config_init, .read_status =3D lan86xx_read_status, - .read_mmd =3D lan865x_phy_read_mmd, - .write_mmd =3D lan865x_phy_write_mmd, + .read_mmd =3D genphy_read_mmd_c45, + .write_mmd =3D genphy_write_mmd_c45, .get_plca_cfg =3D genphy_c45_plca_get_cfg, .set_plca_cfg =3D lan86xx_plca_set_cfg, .get_plca_status =3D genphy_c45_plca_get_status, --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 5BDC23C4565; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=A4JAmutYUGHc/8qcEavP+gWoipfuu96tdHTtJ28Ercs1ph/Ndv3AhJudjMcxplySs8PVrQvN3G9HXWvbnvgBx+ffHVZNdQVrqMuBAlKYXZEqR44A5f1ERgcJNjsUUf5tEEfjJzKuoVJpLusprijHfsURGNIKt9k+2ORLkEMSTNE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=A2Uj8QDZUKuoKmqg/79Vc/G1OinkPdUdxMsomCejTNE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Xa/P0WnuxCsfFW/0MfEQ4LjgxbsEuHIBM9+bRe53g0Yv5qhaLqd0WPc/f+lcx9k/qTcby84Qg0qfChx4WAnOK3HapJju2dtI7FA0QqlUqKExx9IFhAgMu4mvZVXfhNxfQR4/Gs+rpOrAL2K0Fa87u1vmYD5PYZf0j5uif2o/tfk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hCYDKd2G; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hCYDKd2G" Received: by smtp.kernel.org (Postfix) with ESMTPS id 35597C2BCC4; Tue, 26 May 2026 21:52:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832340; bh=A2Uj8QDZUKuoKmqg/79Vc/G1OinkPdUdxMsomCejTNE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=hCYDKd2GOuZHRA9yvZ4jszEYK95PJGGCUYOIM4CN0vQld5siyNPZPu3DE1mP9vNi1 LLW3q9crFYOpQVPLXpyW1WmnS6d/OP9OJkMmgf1igq6qpPuNdReQNLz3ntte54xUgc qcVCdZV+OxSV5o7iAzlEGWxUaRVxx9CSvzE40P1NwE/U9AxXab5wCFuCKtRDbQq52h g252LjH1sfFixJj76dwPF/k+UMNhTo2qxshCM+B/FL/Krz2BPeOB/FbU39BP/GIdXh gL56hhChgbQAijack9qVhOsT18WQV2sblChgQfK6G+M0ZBVVwfUNb0KxePOlvJ3p6L 0FLBVuQNI5qmQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D79BCD5BD5; Tue, 26 May 2026 21:52:20 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:54 +0300 Subject: [PATCH net-next v2 09/10] net: phy: Add support for the ADIN1140 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: <20260527-adin1140-driver-v2-9-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=4959; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=Q4PnHqnyimvMStlwH1jthtt1eNnizfbV+xozD0BJvuo=; b=kkvmtdw2dyz8SJo2UZhOwBtOVrFFdZU0wXmK34FiytmotOtwDPMEJohEBh8hnU/8Y6VgN8cAb v07PbES8FNJDrf39yI/nTZ1W0uVQfh9ypD4FAR+uGkcOSN/Fdc+NEGE X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus Add a driver for the ADIN1140's internal 10BASE-T1S PHY. The device doesn't implement autonegotiation, so the link is always reported as being up. The device implements both C22 and C45 MDIO access methods, but can only be discovered over C22, since the C45 MMD devices lack the MDIO_DEVID1 and MDIO_DEVID2 registers. The indirect C45 over C22 feature is not supported. Signed-off-by: Ciprian Regus Reviewed-by: Andrew Lunn --- v2 changelog: - No longer setting PHY_MAC_INTERRUPT in order to avoid state polling. - Replace the driver specific .read/write_mmd() functions with the ones exported from genphy. - Renamed the file to adin1140-phy.c in order to avoid module name conflicts with the adin1140 ethernet driver. --- MAINTAINERS | 7 ++++ drivers/net/phy/Kconfig | 6 ++++ drivers/net/phy/Makefile | 1 + drivers/net/phy/adin1140-phy.c | 72 ++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 86 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ca6c7425b45f..eda74f3154dc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1857,6 +1857,13 @@ S: Supported W: https://ez.analog.com/linux-software-drivers F: drivers/dma/dma-axi-dmac.c =20 +ANALOG DEVICES INC ETHERNET PHY DRIVERS +M: Ciprian Regus +L: netdev@vger.kernel.org +S: Maintained +W: https://ez.analog.com/linux-software-drivers +F: drivers/net/phy/adin1140-phy.c + ANALOG DEVICES INC IIO DRIVERS M: Lars-Peter Clausen M: Michael Hennerich diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 8b51bdc2e945..bd21a5dad366 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -124,6 +124,12 @@ config ADIN1100_PHY Currently supports the: - ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY =20 +config ADIN1140_PHY + tristate "Analog Devices ADIN1140 10BASE-T1S PHY" + help + Adds support for the Analog Devices, Inc. ADIN1140's internal + 10BASE-T1S PHY. + config AMCC_QT2025_PHY tristate "AMCC QT2025 PHY" depends on RUST_PHYLIB_ABSTRACTIONS diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 05e4878af27a..73152845b0b2 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_ADIN1140_PHY) +=3D adin1140-phy.o obj-$(CONFIG_AIR_EN8811H_PHY) +=3D air_en8811h.o obj-$(CONFIG_AMD_PHY) +=3D amd.o obj-$(CONFIG_AMCC_QT2025_PHY) +=3D qt2025.o diff --git a/drivers/net/phy/adin1140-phy.c b/drivers/net/phy/adin1140-phy.c new file mode 100644 index 000000000000..d35da4ad680d --- /dev/null +++ b/drivers/net/phy/adin1140-phy.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Analog Devices, Inc. ADIN1140 10BASE-T1S PHY + * + * Copyright 2026 Analog Devices Inc. + */ + +#include +#include +#include + +#define ADIN1140_PHY_ID 0x0283be00 + +#define ADIN1140_PCS_CTRL 0x08f3 +#define ADIN1140_PCS_CTRL_LOOPBACK BIT(14) + +static int adin1140_config_aneg(struct phy_device *phydev) +{ + /* phylib tries to clear BIT(12) in MDIO_CTRL1, since AN is disabled. + * However, on the ADIN1140, that field is non-standard, being used + * to control the reset status of the PHY (thus it needs to remain set). + */ + return 0; +} + +static int adin1140_loopback(struct phy_device *phydev, bool enable, int s= peed) +{ + if (enable && speed) + return -EOPNOTSUPP; + + return phy_modify_mmd(phydev, MDIO_MMD_PCS, ADIN1140_PCS_CTRL, + ADIN1140_PCS_CTRL_LOOPBACK, + enable ? ADIN1140_PCS_CTRL_LOOPBACK : 0); +} + +static int adin1140_read_status(struct phy_device *phydev) +{ + phydev->link =3D 1; + phydev->duplex =3D DUPLEX_HALF; + phydev->speed =3D SPEED_10; + phydev->autoneg =3D AUTONEG_DISABLE; + + return 0; +} + +static struct phy_driver adin1140_driver[] =3D { + { + PHY_ID_MATCH_EXACT(ADIN1140_PHY_ID), + .name =3D "ADIN1140_PHY", + .features =3D PHY_BASIC_T1S_P2MP_FEATURES, + .read_status =3D adin1140_read_status, + .config_aneg =3D adin1140_config_aneg, + .set_loopback =3D adin1140_loopback, + .read_mmd =3D genphy_read_mmd_c45, + .write_mmd =3D genphy_write_mmd_c45, + .get_plca_cfg =3D genphy_c45_plca_get_cfg, + .set_plca_cfg =3D genphy_c45_plca_set_cfg, + .get_plca_status =3D genphy_c45_plca_get_status, + }, +}; +module_phy_driver(adin1140_driver); + +static const struct mdio_device_id __maybe_unused adin1140_tbl[] =3D { + { PHY_ID_MATCH_EXACT(ADIN1140_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, adin1140_tbl); + +MODULE_DESCRIPTION("Analog Devices, Inc. ADIN1140 10BASE-T1S PHY"); +MODULE_AUTHOR("Ciprian Regus "); +MODULE_LICENSE("GPL"); --=20 2.43.0 From nobody Mon Jun 8 19:47:06 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 677A73C4B88; Tue, 26 May 2026 21:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; cv=none; b=Qq9F+ibPi4FnzCNVIsWCeCX7DNQ1y4SXOynWzSmBqqRWC7jffoERr2D3HRArYXazr39iWDJ6unVg1yuss+uLX78PDg58fEtwCA1o16V7S+cFG/rUH7fIPZVdlAcjM7VHJCOO0gKBRNY18FFtk5adEh7Kt1lzr9J1DLuprVm3PDY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779832340; c=relaxed/simple; bh=sdPG8AeUzxjVhIFMC3VhLuoCdZLuPynN7MopuoQ2b6Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dJ2L4/wMuVeeQmppunuIT9k6Q9PAB/GozKvkCcr+DlV7uz4A/+Kp9UhST5IlKUsuKKVoFsGEYW6ySvE5Aq3Zq1Y9lEdImd51W/3Tg5Fun83FVkITFP2TsN/r/xpEvRrtDFyvPnH4iJAT9zykIZ8FcgPBuo8Zm5PCMlm/tZNImbY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aJUdRVBE; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="aJUdRVBE" Received: by smtp.kernel.org (Postfix) with ESMTPS id 45FDEC4AF0D; Tue, 26 May 2026 21:52:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779832340; bh=sdPG8AeUzxjVhIFMC3VhLuoCdZLuPynN7MopuoQ2b6Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=aJUdRVBEVOPsYAn+ZIWpN3FsMLD34fSx/rc54PhlB6zt637LkmsT2fopHvhdr8Uu+ ZTctls1B8uuXWb4b9EZxTjLQjOZ4u6QOPebYfdt6pwt0GciGZNua6UMqD1CaPwYwQP SNP0lTn0MHQubcTKHK7XyiTb+zkrqymUif/A8nm/eJTe5h3sbUFQvzqSudD080RsRI 2BOWc/g19/VGUMcwO6cTKR6eeA54puYRIynzD6i2jOAENwbLjU7082nE1QHZRSU0a+ IvQD8jncig49A8ditjJG7GAeGiEBOLquEn0YFHdykV01EUmwDQGAyzJoa7utj9ynFg 9tajuJAdNw1SA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CF4CCD6E43; Tue, 26 May 2026 21:52:20 +0000 (UTC) From: Ciprian Regus via B4 Relay Date: Wed, 27 May 2026 00:51:55 +0300 Subject: [PATCH net-next v2 10/10] net: ethernet: adi: Add a driver for the ADIN1140 MACPHY 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: <20260527-adin1140-driver-v2-10-37e5c8d4e0a0@analog.com> References: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> In-Reply-To: <20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com> To: Parthiban Veerasooran , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan , Andrew Lunn , Heiner Kallweit , Russell King , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, devicetree@vger.kernel.org, Ciprian Regus X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1779832338; l=29144; i=ciprian.regus@analog.com; s=20260330; h=from:subject:message-id; bh=Eon0exvkWbcaGq8ytIR6Wrldgn6CO2XLL/IEhuzN5gs=; b=CN3yCFrI1doCBHx7wEcmIQqTPmmT3RlULfU8FGXGNvACzyJLZlRx/H+keP+kkzQlbdAQ+S6Vu fPDScG87U4rBBPUb5QA99NX1N+qocVvh+/8PpZ8QCb63MTJDOwVPK8p X-Developer-Key: i=ciprian.regus@analog.com; a=ed25519; pk=8WoNhI0kQcQUl8YqJO5ZevROYk9HP8lOIeIgIYgjfbc= X-Endpoint-Received: by B4 Relay for ciprian.regus@analog.com/20260330 with auth_id=703 X-Original-From: Ciprian Regus Reply-To: ciprian.regus@analog.com From: Ciprian Regus Add a driver for ADIN1140. The device is a 10BASE-T1S MAC-PHY (integrated in the same package) that connects to a CPU over an SPI bus, and implements the Open Alliance TC6 protocol for control and frame transfers. As such, this driver relies on oa_tc6 for the communication with the device. The device has an alternative name (AD3306), so the driver can be probed using one of the two compatible strings. For control transactions, ADIN1140 only implements the protected mode. The driver has a custom implementation for the mii_bus access methods as a workaround for hardware issues: 1. The OA TC6 standard defines the direct and indirect access modes for MDIO transactions. The ADIN1140 incorrectly advertises indirect mode only (supported capabilities register - 0x2, bit 9), while actually implementing just the direct mode. We cannot rely on the CAP register to choose an access method (which oa_tc6 does by default, even though it only implements the direct mode), so the driver has to use its own. 2. The ADIN1140 cannot access the C22 register space of the internal PHY, while the PHY is busy receiving frames. If that happens, the CONFIG0 and CONFIG2 registers of the MAC will get corrupted and the data transfer will stop. Those two registers configure settings for the transfer protocol between the MAC and host, so the value for some of their subfields shouldn't be changed while the netdev is up. Since we know the PHY is internal, the MAC driver can implement a custom mii_bus, which can intercept C22 accesses. Most of the registers mapped in the 0x0 - 0x3 range (the only ones the PHY offers) are read only, and their value can be read from somewhere else (e.g the PHYID 1 & 2 have the same value as 0x1 in the MAC memory map). For the fields that are R/W (loopback and AN/reset) in the control register, the PHY driver already implements the set_loopback() and config_aneg() functions. The C22 write function of the driver is a no-op and is used to protect against the ioctl MDIO access path. C45 accesses do not cause this issue, so we can properly implement them. Update the oa_tc6 header file to include definitions for the standard registers used by the adin1140 driver. Signed-off-by: Ciprian Regus --- v2 changelog: - Exported statistics that match the ethtool_stats entries as such and kept the other ones custom, using ethtool strings. - Used phy_do_ioctl_running() for ndo_eth_ioctl. - Adapted the mii_bus and PHY handling to the newly added OA_TC6_BROKEN_PHY flag for oa_tc6. - Used the oa_tc6_mdiobus_read_c45/oa_tc6_mdiobus_write_c45 functions for the C45 read/write mii_bus operations. - Removed OA TC6 register definitions (e.g CONFIG2) from the adin1140 driver and instead used the ones exported from oa_tc6.h - Used OA_TC6_MMS_REG to define MMS registers instead of ADIN1140_MMS_REG. - Returned default values for the MII_PHYSID1/MII_PHYSID2. - Set the mii_bus->phy_mask, since the the same PHY will be registered 32 times otherwise. - Updated the MAINTAINERS entry to include the dt-bindings. --- MAINTAINERS | 8 + drivers/net/ethernet/adi/Kconfig | 12 + drivers/net/ethernet/adi/Makefile | 1 + drivers/net/ethernet/adi/adin1140.c | 811 ++++++++++++++++++++++++++++++++= ++++ 4 files changed, 832 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index eda74f3154dc..3d6da16c4312 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1857,6 +1857,14 @@ S: Supported W: https://ez.analog.com/linux-software-drivers F: drivers/dma/dma-axi-dmac.c =20 +ANALOG DEVICES INC ETHERNET DRIVERS +M: Ciprian Regus +L: netdev@vger.kernel.org +S: Maintained +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/net/adi,adin1140.yaml +F: drivers/net/ethernet/adi/adin1140.c + ANALOG DEVICES INC ETHERNET PHY DRIVERS M: Ciprian Regus L: netdev@vger.kernel.org diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kc= onfig index 760a9a60bc15..bdb8ff7d15da 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig @@ -26,4 +26,16 @@ config ADIN1110 Say yes here to build support for Analog Devices ADIN1110 Low Power 10BASE-T1L Ethernet MAC-PHY. =20 +config ADIN1140 + tristate "Analog Devices ADIN1140 MAC-PHY" + depends on SPI + select ADIN1140_PHY + select OA_TC6 + help + Say yes here to build support for Analog Devices, Inc. ADIN1140 + 10BASE-T1S Ethernet MAC-PHY. + + To compile this driver as a module, choose M here. The module will be + called adin1140. + endif # NET_VENDOR_ADI diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/M= akefile index d0383d94303c..0390ca8ccc49 100644 --- a/drivers/net/ethernet/adi/Makefile +++ b/drivers/net/ethernet/adi/Makefile @@ -4,3 +4,4 @@ # =20 obj-$(CONFIG_ADIN1110) +=3D adin1110.o +obj-$(CONFIG_ADIN1140) +=3D adin1140.o diff --git a/drivers/net/ethernet/adi/adin1140.c b/drivers/net/ethernet/adi= /adin1140.c new file mode 100644 index 000000000000..671bfc08ce38 --- /dev/null +++ b/drivers/net/ethernet/adi/adin1140.c @@ -0,0 +1,811 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Analog Devices, Inc. ADIN1140 10BASE-T1S MAC-PHY + * + * Copyright 2026 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include + +#define ADIN1140_CONFIG2_FWD_UNK2HOST BIT(2) + +#define ADIN1140_MAC_P1_LOOP_ADDR_REG OA_TC6_MMS_REG(0x1, 0xC4) + +#define ADIN1140_MAC_ADDR_FILT_UPR_REG OA_TC6_MMS_REG(0x1, 0x50) +#define ADIN1140_MAC_ADDR_FILT_APPLY2PORT1 BIT(30) +#define ADIN1140_MAC_ADDR_FILT_TO_HOST BIT(16) + +#define ADIN1140_MAC_ADDR_FILT_LWR_REG OA_TC6_MMS_REG(0x1, 0x51) + +#define ADIN1140_MAC_ADDR_MASK_UPR_REG OA_TC6_MMS_REG(0x1, 0x70) +#define ADIN1140_MAC_ADDR_MASK_LWR_REG OA_TC6_MMS_REG(0x1, 0x71) + +#define ADIN1140_MAC_FILT_MC_SLOT 0U +#define ADIN1140_MAC_FILT_BC_SLOT 1U +#define ADIN1140_MAC_FILT_UC_SLOT 2U +#define ADIN1140_MAC_FILT_MAX_SLOT 16U + +#define ADIN1140_RX_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xA1) +#define ADIN1140_RX_BC_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xA2) +#define ADIN1140_RX_MC_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xA3) +#define ADIN1140_RX_UC_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xA4) +#define ADIN1140_RX_CRC_ERR_CNT OA_TC6_MMS_REG(0x1, 0xA5) +#define ADIN1140_RX_ALIGN_ERR_CNT OA_TC6_MMS_REG(0x1, 0xA6) +#define ADIN1140_RX_PREAMBLE_ERR_CNT OA_TC6_MMS_REG(0x1, 0xA7) +#define ADIN1140_RX_SHORT_ERR_CNT OA_TC6_MMS_REG(0x1, 0xA8) +#define ADIN1140_RX_LONG_ERR_CNT OA_TC6_MMS_REG(0x1, 0xA9) +#define ADIN1140_RX_PHY_ERR_CNT OA_TC6_MMS_REG(0x1, 0xAA) +#define ADIN1140_RX_DRP_FULL_CNT OA_TC6_MMS_REG(0x1, 0xAB) +#define ADIN1140_RX_DRP_FILTER_CNT OA_TC6_MMS_REG(0x1, 0xAD) +#define ADIN1140_RX_IFG_ERR_CNT OA_TC6_MMS_REG(0x1, 0xAE) +#define ADIN1140_TX_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xB1) +#define ADIN1140_TX_BC_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xB2) +#define ADIN1140_TX_MC_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xB3) +#define ADIN1140_TX_UC_FRAME_CNT OA_TC6_MMS_REG(0x1, 0xB4) +#define ADIN1140_TX_SINGLE_COL_CNT OA_TC6_MMS_REG(0x1, 0xB5) +#define ADIN1140_TX_MULTI_COL_CNT OA_TC6_MMS_REG(0x1, 0xB6) +#define ADIN1140_TX_DEFERRED_CNT OA_TC6_MMS_REG(0x1, 0xB7) +#define ADIN1140_TX_LATE_COL_CNT OA_TC6_MMS_REG(0x1, 0xB8) +#define ADIN1140_TX_EXCESS_COL_CNT OA_TC6_MMS_REG(0x1, 0xB9) +#define ADIN1140_TX_UNDERRUN_CNT OA_TC6_MMS_REG(0x1, 0xBA) + +/* ADIN1140_MAC_FILT_MAX_SLOT - 3 (multicast, broadcast and unicast + * reserved slots) + */ +#define ADIN1140_MAC_FILT_AVAIL 13U + +#define ADIN1140_PHY_CTRL_DEFAULT 0x1000 +#define ADIN1140_PHY_STATUS_DEFAULT 0x082D +#define ADIN1140_PHY_ID1 0x0283 +#define ADIN1140_PHY_ID2 0xBE00 + +#define ADIN1140_STATS_CHECK_DELAY (3 * HZ) + +enum adin1140_statistics_entry { + rx_frames, + rx_bc_frames, + rx_mc_frames, + rx_uc_frames, + rx_crc_errors, + rx_align_errors, + rx_preamble_errors, + rx_short_frame_errors, + rx_long_frame_errors, + rx_phy_errors, + rx_fifo_full_dropped, + rx_addr_filter_dropped, + rx_ifg_errors, + tx_frames, + tx_bc_frames, + tx_mc_frames, + tx_uc_frames, + tx_single_collision, + tx_multi_collision, + tx_deferred, + tx_late_collision, + tx_excess_collision, + tx_underrun, + ADIN1140_STATS_CNT, +}; + +struct adin1140_statistics_reg { + const char *name; + enum adin1140_statistics_entry idx; +}; + +struct adin1140_priv { + struct net_device *netdev; + struct oa_tc6 *tc6; + struct mii_bus *mdiobus; + struct phy_device *phydev; + struct work_struct rx_mode_work; + struct delayed_work stats_work; + + /* Protects stats[] from concurrent updates in adin1140_stats_work + * and reads in the get_stats functions + */ + spinlock_t stat_lock; + u64 stats[ADIN1140_STATS_CNT]; +}; + +static const u32 adin1140_stat_regs[] =3D { + [rx_frames] =3D ADIN1140_RX_FRAME_CNT, + [rx_bc_frames] =3D ADIN1140_RX_BC_FRAME_CNT, + [rx_mc_frames] =3D ADIN1140_RX_MC_FRAME_CNT, + [rx_uc_frames] =3D ADIN1140_RX_UC_FRAME_CNT, + [rx_crc_errors] =3D ADIN1140_RX_CRC_ERR_CNT, + [rx_align_errors] =3D ADIN1140_RX_ALIGN_ERR_CNT, + [rx_preamble_errors] =3D ADIN1140_RX_PREAMBLE_ERR_CNT, + [rx_short_frame_errors] =3D ADIN1140_RX_SHORT_ERR_CNT, + [rx_long_frame_errors] =3D ADIN1140_RX_LONG_ERR_CNT, + [rx_phy_errors] =3D ADIN1140_RX_PHY_ERR_CNT, + [rx_fifo_full_dropped] =3D ADIN1140_RX_DRP_FULL_CNT, + [rx_addr_filter_dropped] =3D ADIN1140_RX_DRP_FILTER_CNT, + [rx_ifg_errors] =3D ADIN1140_RX_IFG_ERR_CNT, + [tx_frames] =3D ADIN1140_TX_FRAME_CNT, + [tx_bc_frames] =3D ADIN1140_TX_BC_FRAME_CNT, + [tx_mc_frames] =3D ADIN1140_TX_MC_FRAME_CNT, + [tx_uc_frames] =3D ADIN1140_TX_UC_FRAME_CNT, + [tx_single_collision] =3D ADIN1140_TX_SINGLE_COL_CNT, + [tx_multi_collision] =3D ADIN1140_TX_MULTI_COL_CNT, + [tx_deferred] =3D ADIN1140_TX_DEFERRED_CNT, + [tx_late_collision] =3D ADIN1140_TX_LATE_COL_CNT, + [tx_excess_collision] =3D ADIN1140_TX_EXCESS_COL_CNT, + [tx_underrun] =3D ADIN1140_TX_UNDERRUN_CNT, +}; + +static const struct adin1140_statistics_reg adin1140_stats[] =3D { + {.name =3D "rx_unicast_frames", .idx =3D rx_uc_frames}, + {.name =3D "rx_preamble_errors", .idx =3D rx_preamble_errors}, + {.name =3D "rx_ifg_errors", .idx =3D rx_ifg_errors}, + {.name =3D "rx_addr_filter_dropped", .idx =3D rx_addr_filter_dropped}, + {.name =3D "tx_unicast_frames", .idx =3D tx_uc_frames}, +}; + +static int adin1140_mac_filter_set(struct adin1140_priv *priv, + const u8 *addr, const u8 *mask, + u8 slot) +{ + u32 mask_reg; + u32 val; + int ret; + + if (slot >=3D ADIN1140_MAC_FILT_MAX_SLOT) + return -ENOSPC; + + ret =3D oa_tc6_write_register(priv->tc6, + ADIN1140_MAC_ADDR_FILT_UPR_REG + 2 * slot, + get_unaligned_be16(&addr[0]) | + ADIN1140_MAC_ADDR_FILT_APPLY2PORT1 | + ADIN1140_MAC_ADDR_FILT_TO_HOST); + if (ret) + return ret; + + ret =3D oa_tc6_write_register(priv->tc6, + ADIN1140_MAC_ADDR_FILT_LWR_REG + 2 * slot, + get_unaligned_be32(&addr[2])); + if (ret) + return ret; + + val =3D get_unaligned_be16(&mask[0]); + mask_reg =3D ADIN1140_MAC_ADDR_MASK_UPR_REG + (2 * slot); + + ret =3D oa_tc6_write_register(priv->tc6, mask_reg, val); + if (ret) + return ret; + + val =3D get_unaligned_be32(&mask[2]); + mask_reg =3D ADIN1140_MAC_ADDR_MASK_LWR_REG + (2 * slot); + + return oa_tc6_write_register(priv->tc6, mask_reg, val); +} + +static int adin1140_mac_filter_clear(struct adin1140_priv *priv, u8 slot) +{ + u8 mask[ETH_ALEN]; + u8 addr[ETH_ALEN]; + + memset(mask, 0xFF, ETH_ALEN); + memset(addr, 0x0, ETH_ALEN); + + return adin1140_mac_filter_set(priv, addr, mask, slot); +} + +static int adin1140_filter_unicast(struct adin1140_priv *priv) +{ + u8 mask[ETH_ALEN]; + + memset(mask, 0xFF, ETH_ALEN); + + return adin1140_mac_filter_set(priv, priv->netdev->dev_addr, mask, + ADIN1140_MAC_FILT_UC_SLOT); +} + +static int adin1140_filter_all_multicast(struct adin1140_priv *priv, bool = en) +{ + u8 multicast_addr[ETH_ALEN] =3D {1, 0, 0, 0, 0, 0}; + + if (en) + return adin1140_mac_filter_set(priv, multicast_addr, + multicast_addr, + ADIN1140_MAC_FILT_MC_SLOT); + + return adin1140_mac_filter_clear(priv, ADIN1140_MAC_FILT_MC_SLOT); +} + +static int adin1140_filter_broadcast(struct adin1140_priv *priv, bool enab= led) +{ + u8 mask[ETH_ALEN]; + + if (enabled) { + memset(mask, 0xFF, ETH_ALEN); + return adin1140_mac_filter_set(priv, mask, mask, + ADIN1140_MAC_FILT_BC_SLOT); + } + + return adin1140_mac_filter_clear(priv, ADIN1140_MAC_FILT_BC_SLOT); +} + +static int adin1140_default_filter_config(struct adin1140_priv *priv) +{ + int ret; + + ret =3D adin1140_filter_broadcast(priv, true); + if (ret) + return ret; + + return adin1140_filter_unicast(priv); +} + +static int adin1140_promiscuous_mode(struct adin1140_priv *priv, bool enab= led) +{ + int ret; + u32 val; + + ret =3D oa_tc6_read_register(priv->tc6, OA_TC6_REG_CONFIG2, &val); + if (ret) + return ret; + + if (enabled) + val |=3D ADIN1140_CONFIG2_FWD_UNK2HOST; + else + val &=3D ~ADIN1140_CONFIG2_FWD_UNK2HOST; + + return oa_tc6_write_register(priv->tc6, OA_TC6_REG_CONFIG2, val); +} + +static void adin1140_rx_mode_work(struct work_struct *work) +{ + struct adin1140_priv *priv =3D container_of(work, struct adin1140_priv, + rx_mode_work); + struct netdev_hw_addr *ha; + bool all_multi, promisc; + u8 mask[ETH_ALEN]; + u8 start, end; + u32 mac_addrs; + u8 slot, i; + int ret; + + /* The ADIN1140 has 16 dest MAC address filter slots: + * 0 - reserved for all multicast filter. + * 1 - reserved for broadcast filter. + * 2 - reserved for the device's own unicast MAC. + * 3 -> 15 - available for other unicast/multicast filters. + */ + + mac_addrs =3D netdev_uc_count(priv->netdev) + + netdev_mc_count(priv->netdev); + + if (priv->netdev->flags & IFF_PROMISC) { + promisc =3D true; + all_multi =3D false; + } else if (priv->netdev->flags & IFF_ALLMULTI) { + promisc =3D false; + all_multi =3D true; + } else if (mac_addrs <=3D ADIN1140_MAC_FILT_AVAIL) { + promisc =3D false; + all_multi =3D false; + + slot =3D ADIN1140_MAC_FILT_UC_SLOT + 1; + memset(mask, 0xFF, ETH_ALEN); + + netdev_for_each_uc_addr(ha, priv->netdev) { + ret =3D adin1140_mac_filter_set(priv, ha->addr, mask, + slot); + if (ret) + return; + + slot++; + } + + netdev_for_each_mc_addr(ha, priv->netdev) { + ret =3D adin1140_mac_filter_set(priv, ha->addr, mask, + slot); + if (ret) + return; + + slot++; + } + } else { + /* The filter table is full. Enable promisc mode. */ + promisc =3D true; + all_multi =3D false; + + start =3D ADIN1140_MAC_FILT_UC_SLOT + 1; + end =3D ADIN1140_MAC_FILT_MAX_SLOT; + for (i =3D start; i < end; i++) { + ret =3D adin1140_mac_filter_clear(priv, i); + if (ret) + return; + } + } + + ret =3D adin1140_promiscuous_mode(priv, promisc); + if (ret) + return; + + adin1140_filter_all_multicast(priv, all_multi); +} + +static void adin1140_rx_mode(struct net_device *netdev) +{ + struct adin1140_priv *priv =3D netdev_priv(netdev); + + schedule_work(&priv->rx_mode_work); +} + +static void adin1140_stats_work(struct work_struct *work) +{ + struct delayed_work *dwork =3D to_delayed_work(work); + u64 stat_buff[ADIN1140_STATS_CNT] =3D {}; + struct adin1140_priv *priv; + u32 reg_val; + int ret; + u32 i; + + priv =3D container_of(dwork, struct adin1140_priv, stats_work); + + for (i =3D 0; i < ARRAY_SIZE(adin1140_stat_regs); i++) { + ret =3D oa_tc6_read_register(priv->tc6, adin1140_stat_regs[i], + ®_val); + if (ret) + break; + + stat_buff[i] =3D reg_val; + } + + spin_lock(&priv->stat_lock); + memcpy(&priv->stats, stat_buff, sizeof(priv->stats)); + spin_unlock(&priv->stat_lock); + + schedule_delayed_work(dwork, ADIN1140_STATS_CHECK_DELAY); +} + +static int adin1140_configure(struct adin1140_priv *priv) +{ + int ret; + + ret =3D oa_tc6_zero_align_receive_frame_enable(priv->tc6); + if (ret) + return ret; + + /* Disable MAC loopback */ + ret =3D oa_tc6_write_register(priv->tc6, ADIN1140_MAC_P1_LOOP_ADDR_REG, + 0x0); + if (ret) + return ret; + + return adin1140_default_filter_config(priv); +} + +static int adin1140_open(struct net_device *netdev) +{ + struct adin1140_priv *priv =3D netdev_priv(netdev); + + schedule_delayed_work(&priv->stats_work, ADIN1140_STATS_CHECK_DELAY); + + phy_start(netdev->phydev); + netif_start_queue(netdev); + + return 0; +} + +static int adin1140_close(struct net_device *netdev) +{ + struct adin1140_priv *priv =3D netdev_priv(netdev); + + cancel_delayed_work_sync(&priv->stats_work); + + netif_stop_queue(netdev); + phy_stop(netdev->phydev); + + return 0; +} + +static netdev_tx_t adin1140_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct adin1140_priv *priv =3D netdev_priv(netdev); + + /* Pad frames to minimum Ethernet frame size (60 bytes without FCS). + * The MAC will append the FCS, but we need to ensure the frame is + * at least ETH_ZLEN bytes. + */ + if (skb_put_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + + return oa_tc6_start_xmit(priv->tc6, skb); +} + +static int adin1140_set_mac_address(struct net_device *netdev, void *addr) +{ + struct adin1140_priv *priv =3D netdev_priv(netdev); + struct sockaddr *address =3D addr; + u8 mask[ETH_ALEN]; + int ret; + + ret =3D eth_prepare_mac_addr_change(netdev, addr); + if (ret < 0) + return ret; + + if (ether_addr_equal(address->sa_data, netdev->dev_addr)) + return 0; + + memset(mask, 0xFF, ETH_ALEN); + ret =3D adin1140_mac_filter_set(priv, address->sa_data, mask, + ADIN1140_MAC_FILT_UC_SLOT); + if (ret) + return ret; + + eth_commit_mac_addr_change(netdev, addr); + + return 0; +} + +static void adin1140_ndo_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *storage) +{ + struct adin1140_priv *priv =3D netdev_priv(dev); + + storage->rx_packets =3D priv->netdev->stats.rx_packets; + storage->tx_packets =3D priv->netdev->stats.tx_packets; + + storage->rx_bytes =3D priv->netdev->stats.rx_bytes; + storage->tx_bytes =3D priv->netdev->stats.tx_bytes; + + spin_lock(&priv->stat_lock); + + storage->rx_errors =3D priv->stats[rx_crc_errors] + + priv->stats[rx_align_errors] + + priv->stats[rx_preamble_errors] + + priv->stats[rx_short_frame_errors] + + priv->stats[rx_long_frame_errors] + + priv->stats[rx_phy_errors] + + priv->stats[rx_ifg_errors]; + + storage->tx_errors =3D priv->stats[tx_excess_collision] + + priv->stats[tx_underrun]; + + storage->rx_dropped =3D priv->stats[rx_fifo_full_dropped] + + priv->stats[rx_addr_filter_dropped]; + + storage->multicast =3D priv->stats[rx_mc_frames]; + + storage->collisions =3D priv->stats[tx_single_collision] + + priv->stats[tx_multi_collision]; + + storage->rx_length_errors =3D priv->stats[rx_short_frame_errors] + + priv->stats[rx_long_frame_errors]; + storage->rx_over_errors =3D priv->stats[rx_fifo_full_dropped]; + storage->rx_crc_errors =3D priv->stats[rx_crc_errors]; + storage->rx_frame_errors =3D priv->stats[rx_align_errors]; + storage->rx_missed_errors =3D priv->stats[rx_fifo_full_dropped]; + + storage->tx_aborted_errors =3D priv->stats[tx_excess_collision]; + storage->tx_fifo_errors =3D priv->stats[tx_underrun]; + storage->tx_window_errors =3D priv->stats[tx_late_collision]; + + spin_unlock(&priv->stat_lock); +} + +static void adin1140_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + strscpy(info->driver, "ADIN1140", sizeof(info->driver)); + strscpy(info->bus_info, dev_name(netdev->dev.parent), + sizeof(info->bus_info)); +} + +static void adin1140_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct adin1140_priv *priv =3D netdev_priv(netdev); + u32 i; + + spin_lock(&priv->stat_lock); + for (i =3D 0; i < ARRAY_SIZE(adin1140_stats); i++) + data[i] =3D priv->stats[adin1140_stats[i].idx]; + spin_unlock(&priv->stat_lock); +} + +static void adin1140_get_ethtool_strings(struct net_device *netdev, u32 ss= et, + u8 *p) +{ + u32 i; + + switch (sset) { + case ETH_SS_STATS: + for (i =3D 0; i < ARRAY_SIZE(adin1140_stats); i++) + ethtool_puts(&p, adin1140_stats[i].name); + + break; + } +} + +static int adin1140_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(adin1140_stats); + default: + return -EOPNOTSUPP; + } +} + +static void adin1140_get_eth_mac_stats(struct net_device *netdev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct adin1140_priv *priv =3D netdev_priv(netdev); + + spin_lock(&priv->stat_lock); + + mac_stats->FramesReceivedOK =3D priv->stats[rx_frames]; + mac_stats->BroadcastFramesReceivedOK =3D priv->stats[rx_bc_frames]; + mac_stats->MulticastFramesReceivedOK =3D priv->stats[rx_mc_frames]; + mac_stats->FrameCheckSequenceErrors =3D priv->stats[rx_crc_errors]; + mac_stats->AlignmentErrors =3D priv->stats[rx_align_errors]; + mac_stats->FrameTooLongErrors =3D priv->stats[rx_long_frame_errors]; + mac_stats->FramesLostDueToIntMACRcvError =3D + priv->stats[rx_fifo_full_dropped]; + mac_stats->FramesTransmittedOK =3D priv->stats[tx_frames]; + mac_stats->BroadcastFramesXmittedOK =3D priv->stats[tx_bc_frames]; + mac_stats->MulticastFramesXmittedOK =3D priv->stats[tx_mc_frames]; + mac_stats->SingleCollisionFrames =3D priv->stats[tx_single_collision]; + mac_stats->MultipleCollisionFrames =3D priv->stats[tx_multi_collision]; + mac_stats->FramesWithDeferredXmissions =3D priv->stats[tx_deferred]; + mac_stats->LateCollisions =3D priv->stats[tx_late_collision]; + mac_stats->FramesAbortedDueToXSColls =3D priv->stats[tx_excess_collision]; + mac_stats->FramesLostDueToIntMACXmitError =3D priv->stats[tx_underrun]; + + spin_unlock(&priv->stat_lock); +} + +static int adin1140_mdiobus_read(struct mii_bus *bus, int addr, int regnum) +{ + /* The ADIN1140's standard PHY C22 register map (OA TC6 0xFF00 - + * 0xFF1F), of which only 0xFF00 - 0xFF03 are implemented) cannot be + * accessed while frames are being received by the PHY. In case this + * happens the CONFIG0 and CONFIG2 register values will get corrupted, + * getting a random value. Both reads and writes cause the same + * behavior. This is a workaround that avoids MDIO accesses all + * together. Since this is a 10BASE-T1S PHY, only the loopback and + * reset (AN) bits in the control register (0x0) can be written. + * These functionalities have custom implementations in the PHY + * driver. C45 accesses do not cause this issue. + */ + + switch (regnum) { + case MII_BMCR: + return ADIN1140_PHY_CTRL_DEFAULT; + case MII_BMSR: + return ADIN1140_PHY_STATUS_DEFAULT; + case MII_PHYSID1: + return ADIN1140_PHY_ID1; + case MII_PHYSID2: + return ADIN1140_PHY_ID2; + default: + return 0xFFFF; + } +} + +static int adin1140_mdiobus_write(struct mii_bus *bus, int addr, int regnu= m, + u16 val) +{ + return -EIO; +} + +static int adin1140_mdio_register(struct adin1140_priv *priv, + struct spi_device *spidev) +{ + int ret; + + priv->mdiobus =3D mdiobus_alloc(); + if (!priv->mdiobus) { + netdev_err(priv->netdev, "MDIO bus alloc failed\n"); + return -ENOMEM; + } + + priv->mdiobus->name =3D "adin1140-mdiobus"; + priv->mdiobus->priv =3D priv->tc6; + priv->mdiobus->parent =3D &spidev->dev; + priv->mdiobus->phy_mask =3D ~BIT(0); + priv->mdiobus->read =3D adin1140_mdiobus_read; + priv->mdiobus->write =3D adin1140_mdiobus_write; + priv->mdiobus->read_c45 =3D oa_tc6_mdiobus_read_c45; + priv->mdiobus->write_c45 =3D oa_tc6_mdiobus_write_c45; + + snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "adin1140-%s.%u", + dev_name(&spidev->dev), spi_get_chipselect(spidev, 0)); + + ret =3D mdiobus_register(priv->mdiobus); + if (ret) { + netdev_err(priv->netdev, "Could not register MDIO bus\n"); + mdiobus_free(priv->mdiobus); + return ret; + } + + return 0; +} + +static void adin1140_handle_link_change(struct net_device *netdev) +{ + phy_print_status(netdev->phydev); +} + +static int adin1140_phy_init(struct adin1140_priv *priv, + struct spi_device *spidev) +{ + int ret; + + ret =3D adin1140_mdio_register(priv, spidev); + if (ret) + return ret; + + priv->phydev =3D phy_find_first(priv->mdiobus); + if (!priv->phydev) { + netdev_err(priv->netdev, "No PHY found\n"); + ret =3D -ENODEV; + goto free_mdio; + } + + priv->phydev->is_internal =3D true; + ret =3D phy_connect_direct(priv->netdev, priv->phydev, + &adin1140_handle_link_change, + PHY_INTERFACE_MODE_INTERNAL); + if (ret) { + netdev_err(priv->netdev, "Can't attach PHY to %s\n", + priv->mdiobus->id); + goto unregister_mdio; + } + + phy_attached_info(priv->phydev); + + return 0; + +unregister_mdio: + mdiobus_unregister(priv->mdiobus); +free_mdio: + mdiobus_free(priv->mdiobus); + + return ret; +} + +static void adin1140_phy_remove(struct adin1140_priv *priv) +{ + phy_disconnect(priv->phydev); + mdiobus_unregister(priv->mdiobus); + mdiobus_free(priv->mdiobus); +} + +static const struct ethtool_ops adin1140_ethtool_ops =3D { + .get_drvinfo =3D adin1140_get_drvinfo, + .get_link =3D ethtool_op_get_link, + .get_ethtool_stats =3D adin1140_get_ethtool_stats, + .get_sset_count =3D adin1140_get_sset_count, + .get_strings =3D adin1140_get_ethtool_strings, + .get_link_ksettings =3D phy_ethtool_get_link_ksettings, + .set_link_ksettings =3D phy_ethtool_set_link_ksettings, + .get_eth_mac_stats =3D adin1140_get_eth_mac_stats, +}; + +static const struct net_device_ops adin1140_netdev_ops =3D { + .ndo_open =3D adin1140_open, + .ndo_stop =3D adin1140_close, + .ndo_start_xmit =3D adin1140_start_xmit, + .ndo_set_mac_address =3D adin1140_set_mac_address, + .ndo_validate_addr =3D eth_validate_addr, + .ndo_set_rx_mode =3D adin1140_rx_mode, + .ndo_eth_ioctl =3D phy_do_ioctl_running, + .ndo_get_stats64 =3D adin1140_ndo_get_stats64, +}; + +static int adin1140_probe(struct spi_device *spi) +{ + struct oa_tc6_config tc6_config =3D {}; + struct net_device *netdev; + struct adin1140_priv *priv; + int ret; + + netdev =3D alloc_etherdev(sizeof(struct adin1140_priv)); + if (!netdev) + return -ENOMEM; + + priv =3D netdev_priv(netdev); + priv->netdev =3D netdev; + spi_set_drvdata(spi, priv); + spin_lock_init(&priv->stat_lock); + + tc6_config.spi =3D spi; + tc6_config.netdev =3D netdev; + tc6_config.quirk_flags =3D OA_TC6_BROKEN_PHY; + + priv->tc6 =3D oa_tc6_init(&tc6_config); + if (!priv->tc6) { + ret =3D -ENODEV; + goto netdev_free; + } + + ret =3D adin1140_phy_init(priv, spi); + if (ret) + goto oa_tc6_exit; + + if (device_get_ethdev_address(&spi->dev, netdev)) + eth_hw_addr_random(netdev); + + ret =3D adin1140_configure(priv); + if (ret) + goto phy_exit; + + INIT_WORK(&priv->rx_mode_work, adin1140_rx_mode_work); + INIT_DELAYED_WORK(&priv->stats_work, adin1140_stats_work); + + netdev->if_port =3D IF_PORT_10BASET; + netdev->irq =3D spi->irq; + netdev->netdev_ops =3D &adin1140_netdev_ops; + netdev->ethtool_ops =3D &adin1140_ethtool_ops; + netdev->netns_immutable =3D true; + netdev->priv_flags |=3D IFF_LIVE_ADDR_CHANGE | + IFF_UNICAST_FLT; + + ret =3D register_netdev(netdev); + if (ret) { + dev_err(&spi->dev, "Failed to register netdev (%d)", ret); + goto phy_exit; + } + + return 0; + +phy_exit: + adin1140_phy_remove(priv); +oa_tc6_exit: + oa_tc6_exit(priv->tc6); +netdev_free: + free_netdev(priv->netdev); + + return ret; +} + +static void adin1140_remove(struct spi_device *spi) +{ + struct adin1140_priv *priv =3D spi_get_drvdata(spi); + + cancel_work_sync(&priv->rx_mode_work); + unregister_netdev(priv->netdev); + adin1140_phy_remove(priv); + oa_tc6_exit(priv->tc6); + free_netdev(priv->netdev); +} + +static const struct spi_device_id adin1140_spi_id[] =3D { + { .name =3D "ad3306" }, + { .name =3D "adin1140" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, adin1140_spi_id); + +static const struct of_device_id adin1140_match_table[] =3D { + { .compatible =3D "adi,ad3306" }, + { .compatible =3D "adi,adin1140" }, + { } +}; +MODULE_DEVICE_TABLE(of, adin1140_match_table); + +static struct spi_driver adin1140_driver =3D { + .driver =3D { + .name =3D "adin1140", + .of_match_table =3D adin1140_match_table, + }, + .probe =3D adin1140_probe, + .remove =3D adin1140_remove, + .id_table =3D adin1140_spi_id, +}; +module_spi_driver(adin1140_driver); + +MODULE_DESCRIPTION("Analog Devices, Inc. ADIN1140 10BASE-T1S MAC-PHY"); +MODULE_AUTHOR("Ciprian Regus "); +MODULE_LICENSE("GPL"); --=20 2.43.0