From nobody Tue Sep 9 21:30:29 2025 Received: from cstnet.cn (smtp81.cstnet.cn [159.226.251.81]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F0CD341AB6; Fri, 5 Sep 2025 11:10:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070646; cv=none; b=LL9+hbMFka2fblgItaNGZHa25RMLb9TWLW90+r0pSH8GlO7+OZkzfRNt5xmXvjniODtR2ZMa4ZW+q+uc2RwxiJuhxlunihn0mmAQL6IyLBBhM/L7JayAC1fIYhktMJJZMnPu4qgiEz+hzDxJnwe6v6II61M+t2YX60utSa8e5V0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070646; c=relaxed/simple; bh=EQWXbhs2+NcTFLOJAcUu2US3mXQ51f5l0WdRHPHMMbA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mn1CNcXQmwF0i0WeTzpJZxArGqTZS91Ee1IPRYfOvWa3XvPQCDTMk2SaPgoEyIuqnep4MhjgNfi3vwSbkRfWFtf8678AX4JqzwqfBGEb9KdDyzzzyh0KQ3CfYlMmORWVBO8NUWC4zGdegQREx3NVcXtphcr9zZubty8CaaNrn4o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from [127.0.0.2] (unknown [114.241.87.235]) by APP-03 (Coremail) with SMTP id rQCowACnu4X1xLpoFdfLAA--.1807S3; Fri, 05 Sep 2025 19:09:43 +0800 (CST) From: Vivian Wang Date: Fri, 05 Sep 2025 19:09:30 +0800 Subject: [PATCH net-next v9 1/5] dt-bindings: net: Add support for SpacemiT K1 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: <20250905-net-k1-emac-v9-1-f1649b98a19c@iscas.ac.cn> References: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> In-Reply-To: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> To: Andrew Lunn , Jakub Kicinski , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vivian Wang , "David S. Miller" , Eric Dumazet , Paolo Abeni , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti Cc: Vivian Wang , Vadim Fedorenko , Junhui Liu , Simon Horman , Maxime Chevallier , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, Conor Dooley X-Mailer: b4 0.14.2 X-CM-TRANSID: rQCowACnu4X1xLpoFdfLAA--.1807S3 X-Coremail-Antispam: 1UD129KBjvJXoW7Cry3WF45trW5KrW5Zr4rGrg_yoW5Jr1xpF 4fCrn3GF48KF13Jw4fXFykuF1fGw4kAF1DJrZFvw13tas5KF90qr4akryfXa4UurW8Ja43 XF1DAryDKr1DAaUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUm014x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jr4l82xGYIkIc2 x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UM2 8EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v26rxl6s0DM2AI xVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20x vE14v26r1j6r18McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xv r2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7M4IIrI8v6xkF7I0E8cxan2IY04 v7MxkF7I0En4kS14v26r4a6rW5MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j 6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7 AF67AKxVW8ZVWrXwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1j6r1xMIIF0xvE 2Ix0cI8IcVCY1x0267AKxVWxJVW8Jr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0x vEx4A2jsIE14v26r1j6r4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVj vjDU0xZFpf9x0pRlJPiUUUUU= X-CM-SenderInfo: pzdqw2pxlnt03j6l2u1dvotugofq/ The Ethernet MACs on SpacemiT K1 appears to be a custom design. SpacemiT refers to them as "EMAC", so let's just call them "spacemit,k1-emac". Signed-off-by: Vivian Wang Reviewed-by: Conor Dooley --- .../devicetree/bindings/net/spacemit,k1-emac.yaml | 81 ++++++++++++++++++= ++++ 1 file changed, 81 insertions(+) diff --git a/Documentation/devicetree/bindings/net/spacemit,k1-emac.yaml b/= Documentation/devicetree/bindings/net/spacemit,k1-emac.yaml new file mode 100644 index 0000000000000000000000000000000000000000..500a3e1daa230ea3a1fad30d8ea= 56a7822fccb3d --- /dev/null +++ b/Documentation/devicetree/bindings/net/spacemit,k1-emac.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/spacemit,k1-emac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K1 Ethernet MAC + +allOf: + - $ref: ethernet-controller.yaml# + +maintainers: + - Vivian Wang + +properties: + compatible: + const: spacemit,k1-emac + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + + mdio-bus: + $ref: mdio.yaml# + unevaluatedProperties: false + + resets: + maxItems: 1 + + spacemit,apmu: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to syscon that controls this MAC + - description: offset of control registers + description: + A phandle to syscon with byte offset to control registers for this M= AC + +required: + - compatible + - reg + - clocks + - interrupts + - resets + - spacemit,apmu + +unevaluatedProperties: false + +examples: + - | + #include + + ethernet@cac80000 { + compatible =3D "spacemit,k1-emac"; + reg =3D <0xcac80000 0x00000420>; + clocks =3D <&syscon_apmu CLK_EMAC0_BUS>; + interrupts =3D <131>; + mac-address =3D [ 00 00 00 00 00 00 ]; + phy-handle =3D <&rgmii0>; + phy-mode =3D "rgmii-id"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&gmac0_cfg>; + resets =3D <&syscon_apmu RESET_EMAC0>; + rx-internal-delay-ps =3D <0>; + tx-internal-delay-ps =3D <0>; + spacemit,apmu =3D <&syscon_apmu 0x3e4>; + + mdio-bus { + #address-cells =3D <0x1>; + #size-cells =3D <0x0>; + + rgmii0: phy@1 { + reg =3D <0x1>; + }; + }; + }; --=20 2.50.1 From nobody Tue Sep 9 21:30:29 2025 Received: from cstnet.cn (smtp81.cstnet.cn [159.226.251.81]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E2ED343210; Fri, 5 Sep 2025 11:10:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070651; cv=none; b=keV9B3hxby6mPDpcgb/rKLF2p2nfVqpFkvYTrgNdGTDqK3LXUH9/vCgLG6OqaJY+AsxrkOJQnC08puGX2ABvemC4xOJs45uR32DaEAFlVLbwSvWQ9++vZ5nEeqUXAoxapFjGx/puDqrALn28gWByqxr4Az28GK17GZPMvC2va1o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070651; c=relaxed/simple; bh=4cfbsEGIbP3ilP5yR1i876CBnmBadRXVzcZMi0Vxjvg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LxFmsOBPY7ZoiYheUPiJY40Typ5kxWjmtMmhcCsNdoqZsygxCTSd3wwbkWHj+51d5y9cvO4Sn5u8/6kY4EShjminLEKthg3WRfGc/jT0bbdEPICbYfHM6D+auMvff/lOLWyCVsBzsXZw2poscwxwFXYzPWupdGltRzhA+O2fhBg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from [127.0.0.2] (unknown [114.241.87.235]) by APP-03 (Coremail) with SMTP id rQCowACnu4X1xLpoFdfLAA--.1807S4; Fri, 05 Sep 2025 19:09:43 +0800 (CST) From: Vivian Wang Date: Fri, 05 Sep 2025 19:09:31 +0800 Subject: [PATCH net-next v9 2/5] net: spacemit: Add K1 Ethernet MAC 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: <20250905-net-k1-emac-v9-2-f1649b98a19c@iscas.ac.cn> References: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> In-Reply-To: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> To: Andrew Lunn , Jakub Kicinski , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vivian Wang , "David S. Miller" , Eric Dumazet , Paolo Abeni , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti Cc: Vivian Wang , Vadim Fedorenko , Junhui Liu , Simon Horman , Maxime Chevallier , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, Troy Mitchell X-Mailer: b4 0.14.2 X-CM-TRANSID: rQCowACnu4X1xLpoFdfLAA--.1807S4 X-Coremail-Antispam: 1UD129KBjvAXoWDXryrJF13Gr4Utr47KF15urg_yoW3WFW8Wo WfXasxtr1rJ34Ivws2gr1xJF1UZFnrZryUCayfAFZ5Wa9rZ3Zxury3Gw43Aw1YvFWrtFW5 WFykX3ZxAr4SyF95n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUO27AC8VAFwI0_Wr0E3s1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l82xGYIkIc2x26280x7IE14v26r15M28IrcIa0x kI8VCY1x0267AKxVW5JVCq3wA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l84AC jcxK6xIIjxv20xvE14v26r4j6ryUM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26F4j6r4UJw A2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq3wAS 0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2 IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0 Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwACI402YVCY1x02628vn2kIc2 xKxwCY1x0262kKe7AKxVW8ZVWrXwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWU JVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67 kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY 6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UMIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42 IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIev Ja73UjIFyTuYvjTRNiSHDUUUU X-CM-SenderInfo: pzdqw2pxlnt03j6l2u1dvotugofq/ The Ethernet MACs found on SpacemiT K1 appears to be a custom design that only superficially resembles some other embedded MACs. SpacemiT refers to them as "EMAC", so let's just call the driver "k1_emac". Supports RGMII and RMII interfaces. Includes support for MAC hardware statistics counters. PTP support is not implemented. Signed-off-by: Vivian Wang Reviewed-by: Maxime Chevallier Reviewed-by: Vadim Fedorenko Reviewed-by: Troy Mitchell Tested-by: Junhui Liu Tested-by: Troy Mitchell --- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/spacemit/Kconfig | 29 + drivers/net/ethernet/spacemit/Makefile | 6 + drivers/net/ethernet/spacemit/k1_emac.c | 2183 +++++++++++++++++++++++++++= ++++ drivers/net/ethernet/spacemit/k1_emac.h | 426 ++++++ 6 files changed, 2646 insertions(+) diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index f86d4557d8d7756a5e27bc17578353b5c19ca108..aead145dd91d129b7bb410f2d4d= 754c744dddbf4 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -188,6 +188,7 @@ source "drivers/net/ethernet/sis/Kconfig" source "drivers/net/ethernet/sfc/Kconfig" source "drivers/net/ethernet/smsc/Kconfig" source "drivers/net/ethernet/socionext/Kconfig" +source "drivers/net/ethernet/spacemit/Kconfig" source "drivers/net/ethernet/stmicro/Kconfig" source "drivers/net/ethernet/sun/Kconfig" source "drivers/net/ethernet/sunplus/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 67182339469a0d8337cc4e92aa51e498c615156d..998dd628b202ced212748450753= fe180f0440c74 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_NET_VENDOR_SOLARFLARE) +=3D sfc/ obj-$(CONFIG_NET_VENDOR_SGI) +=3D sgi/ obj-$(CONFIG_NET_VENDOR_SMSC) +=3D smsc/ obj-$(CONFIG_NET_VENDOR_SOCIONEXT) +=3D socionext/ +obj-$(CONFIG_NET_VENDOR_SPACEMIT) +=3D spacemit/ obj-$(CONFIG_NET_VENDOR_STMICRO) +=3D stmicro/ obj-$(CONFIG_NET_VENDOR_SUN) +=3D sun/ obj-$(CONFIG_NET_VENDOR_SUNPLUS) +=3D sunplus/ diff --git a/drivers/net/ethernet/spacemit/Kconfig b/drivers/net/ethernet/s= pacemit/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..85ef61a9b4eff4249ad2d32a6e7= dbf283b0c180f --- /dev/null +++ b/drivers/net/ethernet/spacemit/Kconfig @@ -0,0 +1,29 @@ +config NET_VENDOR_SPACEMIT + bool "SpacemiT devices" + default y + depends on ARCH_SPACEMIT || COMPILE_TEST + help + If you have a network (Ethernet) device belonging to this class, + say Y. + + Note that the answer to this question does not directly affect + the kernel: saying N will just cause the configurator to skip all + the questions regarding SpacemiT devices. If you say Y, you will + be asked for your specific chipset/driver in the following questions. + +if NET_VENDOR_SPACEMIT + +config SPACEMIT_K1_EMAC + tristate "SpacemiT K1 Ethernet MAC driver" + depends on ARCH_SPACEMIT || COMPILE_TEST + depends on MFD_SYSCON + depends on OF + default m if ARCH_SPACEMIT + select PHYLIB + help + This driver supports the Ethernet MAC in the SpacemiT K1 SoC. + + To compile this driver as a module, choose M here: the module + will be called k1_emac. + +endif # NET_VENDOR_SPACEMIT diff --git a/drivers/net/ethernet/spacemit/Makefile b/drivers/net/ethernet/= spacemit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d29efd997a4ff5dcb50986e4399= 97df7e3650570 --- /dev/null +++ b/drivers/net/ethernet/spacemit/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the SpacemiT network device drivers. +# + +obj-$(CONFIG_SPACEMIT_K1_EMAC) +=3D k1_emac.o diff --git a/drivers/net/ethernet/spacemit/k1_emac.c b/drivers/net/ethernet= /spacemit/k1_emac.c new file mode 100644 index 0000000000000000000000000000000000000000..f626aa346dde93054c5fbf483d9= 76bd37d01a609 --- /dev/null +++ b/drivers/net/ethernet/spacemit/k1_emac.c @@ -0,0 +1,2183 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SpacemiT K1 Ethernet driver + * + * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd + * Copyright (C) 2025 Vivian Wang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "k1_emac.h" + +#define DRIVER_NAME "k1_emac" + +#define EMAC_DEFAULT_BUFSIZE 1536 +#define EMAC_RX_BUF_2K 2048 +#define EMAC_RX_BUF_4K 4096 + +/* Tuning parameters from SpacemiT */ +#define EMAC_TX_FRAMES 64 +#define EMAC_TX_COAL_TIMEOUT 40000 +#define EMAC_RX_FRAMES 64 +#define EMAC_RX_COAL_TIMEOUT (600 * 312) + +#define DEFAULT_FC_PAUSE_TIME 0xffff +#define DEFAULT_FC_FIFO_HIGH 1600 +#define DEFAULT_TX_ALMOST_FULL 0x1f8 +#define DEFAULT_TX_THRESHOLD 1518 +#define DEFAULT_RX_THRESHOLD 12 +#define DEFAULT_TX_RING_NUM 1024 +#define DEFAULT_RX_RING_NUM 1024 +#define DEFAULT_DMA_BURST MREGBIT_BURST_16WORD +#define HASH_TABLE_SIZE 64 + +enum rx_frame_status { + RX_FRAME_OK, + RX_FRAME_DISCARD, +}; + +struct desc_buf { + u64 dma_addr; + void *buff_addr; + u16 dma_len; + u8 map_as_page; +}; + +struct emac_tx_desc_buffer { + struct sk_buff *skb; + struct desc_buf buf[2]; +}; + +struct emac_rx_desc_buffer { + struct sk_buff *skb; + u64 dma_addr; + void *buff_addr; + u16 dma_len; + u8 map_as_page; +}; + +/** + * struct emac_desc_ring - Software-side information for one descriptor ri= ng + * Same structure used for both RX and TX + * @desc_addr: Virtual address to the descriptor ring memory + * @desc_dma_addr: DMA address of the descriptor ring + * @total_size: Size of ring in bytes + * @total_cnt: Number of descriptors + * @head: Next descriptor to associate a buffer with + * @tail: Next descriptor to check status bit + * @rx_desc_buf: Array of descriptors for RX + * @tx_desc_buf: Array of descriptors for TX, with max of two buffers each + */ +struct emac_desc_ring { + void *desc_addr; + dma_addr_t desc_dma_addr; + u32 total_size; + u32 total_cnt; + u32 head; + u32 tail; + union { + struct emac_rx_desc_buffer *rx_desc_buf; + struct emac_tx_desc_buffer *tx_desc_buf; + }; +}; + +struct emac_priv { + void __iomem *iobase; + u32 dma_buf_sz; + struct emac_desc_ring tx_ring; + struct emac_desc_ring rx_ring; + + struct net_device *ndev; + struct napi_struct napi; + struct platform_device *pdev; + struct clk *bus_clk; + struct clk *ref_clk; + struct regmap *regmap_apmu; + u32 regmap_apmu_offset; + int irq; + + phy_interface_t phy_interface; + + struct emac_hw_tx_stats tx_stats, tx_stats_off; + struct emac_hw_rx_stats rx_stats, rx_stats_off; + + u32 tx_count_frames; + u32 tx_coal_frames; + u32 tx_coal_timeout; + struct work_struct tx_timeout_task; + + struct timer_list txtimer; + struct timer_list stats_timer; + + u32 tx_delay; + u32 rx_delay; + + bool flow_control_autoneg; + u8 flow_control; + + /* Hold for any statistics operation */ + spinlock_t stats_lock; +}; + +static void emac_wr(struct emac_priv *priv, u32 reg, u32 val) +{ + writel(val, priv->iobase + reg); +} + +static int emac_rd(struct emac_priv *priv, u32 reg) +{ + return readl(priv->iobase + reg); +} + +static int emac_phy_interface_config(struct emac_priv *priv) +{ + u32 val =3D 0, mask =3D REF_CLK_SEL | RGMII_TX_CLK_SEL | PHY_INTF_RGMII; + + if (phy_interface_mode_is_rgmii(priv->phy_interface)) + val |=3D PHY_INTF_RGMII; + + regmap_update_bits(priv->regmap_apmu, + priv->regmap_apmu_offset + APMU_EMAC_CTRL_REG, + mask, val); + + return 0; +} + +/* + * Where the hardware expects a MAC address, it is laid out in this high, = med, + * low order in three consecutive registers and in this format. + */ + +static void emac_set_mac_addr_reg(struct emac_priv *priv, + const unsigned char *addr, + u32 reg) +{ + emac_wr(priv, reg + sizeof(u32) * 0, addr[1] << 8 | addr[0]); + emac_wr(priv, reg + sizeof(u32) * 1, addr[3] << 8 | addr[2]); + emac_wr(priv, reg + sizeof(u32) * 2, addr[5] << 8 | addr[4]); +} + +static void emac_set_mac_addr(struct emac_priv *priv, const unsigned char = *addr) +{ + /* We use only one address, so set the same for flow control as well */ + emac_set_mac_addr_reg(priv, addr, MAC_ADDRESS1_HIGH); + emac_set_mac_addr_reg(priv, addr, MAC_FC_SOURCE_ADDRESS_HIGH); +} + +static void emac_reset_hw(struct emac_priv *priv) +{ + /* Disable all interrupts */ + emac_wr(priv, MAC_INTERRUPT_ENABLE, 0x0); + emac_wr(priv, DMA_INTERRUPT_ENABLE, 0x0); + + /* Disable transmit and receive units */ + emac_wr(priv, MAC_RECEIVE_CONTROL, 0x0); + emac_wr(priv, MAC_TRANSMIT_CONTROL, 0x0); + + /* Disable DMA */ + emac_wr(priv, DMA_CONTROL, 0x0); +} + +static void emac_init_hw(struct emac_priv *priv) +{ + /* Destination address for 802.3x Ethernet flow control */ + u8 fc_dest_addr[ETH_ALEN] =3D { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x01 }; + + u32 rxirq =3D 0, dma =3D 0; + + regmap_set_bits(priv->regmap_apmu, + priv->regmap_apmu_offset + APMU_EMAC_CTRL_REG, + AXI_SINGLE_ID); + + /* Disable transmit and receive units */ + emac_wr(priv, MAC_RECEIVE_CONTROL, 0x0); + emac_wr(priv, MAC_TRANSMIT_CONTROL, 0x0); + + /* Enable MAC address 1 filtering */ + emac_wr(priv, MAC_ADDRESS_CONTROL, MREGBIT_MAC_ADDRESS1_ENABLE); + + /* Zero initialize the multicast hash table */ + emac_wr(priv, MAC_MULTICAST_HASH_TABLE1, 0x0); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE2, 0x0); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE3, 0x0); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE4, 0x0); + + /* Configure thresholds */ + emac_wr(priv, MAC_TRANSMIT_FIFO_ALMOST_FULL, DEFAULT_TX_ALMOST_FULL); + emac_wr(priv, MAC_TRANSMIT_PACKET_START_THRESHOLD, + DEFAULT_TX_THRESHOLD); + emac_wr(priv, MAC_RECEIVE_PACKET_START_THRESHOLD, DEFAULT_RX_THRESHOLD); + + /* Configure flow control (enabled in emac_adjust_link() later) */ + emac_set_mac_addr_reg(priv, fc_dest_addr, MAC_FC_SOURCE_ADDRESS_HIGH); + emac_wr(priv, MAC_FC_PAUSE_HIGH_THRESHOLD, DEFAULT_FC_FIFO_HIGH); + emac_wr(priv, MAC_FC_HIGH_PAUSE_TIME, DEFAULT_FC_PAUSE_TIME); + emac_wr(priv, MAC_FC_PAUSE_LOW_THRESHOLD, 0); + + /* RX IRQ mitigation */ + rxirq =3D EMAC_RX_FRAMES & MREGBIT_RECEIVE_IRQ_FRAME_COUNTER_MASK; + rxirq |=3D (EMAC_RX_COAL_TIMEOUT + << MREGBIT_RECEIVE_IRQ_TIMEOUT_COUNTER_SHIFT) & + MREGBIT_RECEIVE_IRQ_TIMEOUT_COUNTER_MASK; + + rxirq |=3D MREGBIT_RECEIVE_IRQ_MITIGATION_ENABLE; + emac_wr(priv, DMA_RECEIVE_IRQ_MITIGATION_CTRL, rxirq); + + /* Disable and set DMA config */ + emac_wr(priv, DMA_CONTROL, 0x0); + + emac_wr(priv, DMA_CONFIGURATION, MREGBIT_SOFTWARE_RESET); + usleep_range(9000, 10000); + emac_wr(priv, DMA_CONFIGURATION, 0x0); + usleep_range(9000, 10000); + + dma |=3D MREGBIT_STRICT_BURST; + dma |=3D MREGBIT_DMA_64BIT_MODE; + dma |=3D DEFAULT_DMA_BURST; + + emac_wr(priv, DMA_CONFIGURATION, dma); +} + +static void emac_dma_start_transmit(struct emac_priv *priv) +{ + /* The actual value written does not matter */ + emac_wr(priv, DMA_TRANSMIT_POLL_DEMAND, 1); +} + +static void emac_enable_interrupt(struct emac_priv *priv) +{ + u32 val; + + val =3D emac_rd(priv, DMA_INTERRUPT_ENABLE); + val |=3D MREGBIT_TRANSMIT_TRANSFER_DONE_INTR_ENABLE; + val |=3D MREGBIT_RECEIVE_TRANSFER_DONE_INTR_ENABLE; + emac_wr(priv, DMA_INTERRUPT_ENABLE, val); +} + +static void emac_disable_interrupt(struct emac_priv *priv) +{ + u32 val; + + val =3D emac_rd(priv, DMA_INTERRUPT_ENABLE); + val &=3D ~MREGBIT_TRANSMIT_TRANSFER_DONE_INTR_ENABLE; + val &=3D ~MREGBIT_RECEIVE_TRANSFER_DONE_INTR_ENABLE; + emac_wr(priv, DMA_INTERRUPT_ENABLE, val); +} + +static u32 emac_tx_avail(struct emac_priv *priv) +{ + struct emac_desc_ring *tx_ring =3D &priv->tx_ring; + u32 avail; + + if (tx_ring->tail > tx_ring->head) + avail =3D tx_ring->tail - tx_ring->head - 1; + else + avail =3D tx_ring->total_cnt - tx_ring->head + tx_ring->tail - 1; + + return avail; +} + +static void emac_tx_coal_timer_resched(struct emac_priv *priv) +{ + mod_timer(&priv->txtimer, + jiffies + usecs_to_jiffies(priv->tx_coal_timeout)); +} + +static void emac_tx_coal_timer(struct timer_list *t) +{ + struct emac_priv *priv =3D timer_container_of(priv, t, txtimer); + + napi_schedule(&priv->napi); +} + +static bool emac_tx_should_interrupt(struct emac_priv *priv, u32 pkt_num) +{ + priv->tx_count_frames +=3D pkt_num; + if (likely(priv->tx_coal_frames > priv->tx_count_frames)) { + emac_tx_coal_timer_resched(priv); + return false; + } + + priv->tx_count_frames =3D 0; + return true; +} + +static void emac_free_tx_buf(struct emac_priv *priv, int i) +{ + struct emac_tx_desc_buffer *tx_buf; + struct emac_desc_ring *tx_ring; + struct desc_buf *buf; + int j; + + tx_ring =3D &priv->tx_ring; + tx_buf =3D &tx_ring->tx_desc_buf[i]; + + for (j =3D 0; j < 2; j++) { + buf =3D &tx_buf->buf[j]; + if (!buf->dma_addr) + continue; + + if (buf->map_as_page) + dma_unmap_page(&priv->pdev->dev, buf->dma_addr, + buf->dma_len, DMA_TO_DEVICE); + else + dma_unmap_single(&priv->pdev->dev, + buf->dma_addr, buf->dma_len, + DMA_TO_DEVICE); + + buf->dma_addr =3D 0; + buf->map_as_page =3D false; + buf->buff_addr =3D NULL; + } + + if (tx_buf->skb) { + dev_kfree_skb_any(tx_buf->skb); + tx_buf->skb =3D NULL; + } +} + +static void emac_clean_tx_desc_ring(struct emac_priv *priv) +{ + struct emac_desc_ring *tx_ring =3D &priv->tx_ring; + u32 i; + + /* Free all the TX ring skbs */ + for (i =3D 0; i < tx_ring->total_cnt; i++) + emac_free_tx_buf(priv, i); + + tx_ring->head =3D 0; + tx_ring->tail =3D 0; +} + +static void emac_clean_rx_desc_ring(struct emac_priv *priv) +{ + struct emac_rx_desc_buffer *rx_buf; + struct emac_desc_ring *rx_ring; + u32 i; + + rx_ring =3D &priv->rx_ring; + + /* Free all the RX ring skbs */ + for (i =3D 0; i < rx_ring->total_cnt; i++) { + rx_buf =3D &rx_ring->rx_desc_buf[i]; + + if (!rx_buf->skb) + continue; + + dma_unmap_single(&priv->pdev->dev, rx_buf->dma_addr, + rx_buf->dma_len, DMA_FROM_DEVICE); + + dev_kfree_skb(rx_buf->skb); + rx_buf->skb =3D NULL; + } + + rx_ring->tail =3D 0; + rx_ring->head =3D 0; +} + +static int emac_alloc_tx_resources(struct emac_priv *priv) +{ + struct emac_desc_ring *tx_ring =3D &priv->tx_ring; + struct platform_device *pdev =3D priv->pdev; + u32 size; + + size =3D sizeof(struct emac_tx_desc_buffer) * tx_ring->total_cnt; + + tx_ring->tx_desc_buf =3D kzalloc(size, GFP_KERNEL); + if (!tx_ring->tx_desc_buf) + return -ENOMEM; + + tx_ring->total_size =3D tx_ring->total_cnt * sizeof(struct emac_desc); + tx_ring->total_size =3D ALIGN(tx_ring->total_size, PAGE_SIZE); + + tx_ring->desc_addr =3D dma_alloc_coherent(&pdev->dev, tx_ring->total_size, + &tx_ring->desc_dma_addr, + GFP_KERNEL); + if (!tx_ring->desc_addr) { + kfree(tx_ring->tx_desc_buf); + return -ENOMEM; + } + + tx_ring->head =3D 0; + tx_ring->tail =3D 0; + + return 0; +} + +static int emac_alloc_rx_resources(struct emac_priv *priv) +{ + struct emac_desc_ring *rx_ring =3D &priv->rx_ring; + struct platform_device *pdev =3D priv->pdev; + u32 buf_len; + + buf_len =3D sizeof(struct emac_rx_desc_buffer) * rx_ring->total_cnt; + + rx_ring->rx_desc_buf =3D kzalloc(buf_len, GFP_KERNEL); + if (!rx_ring->rx_desc_buf) + return -ENOMEM; + + rx_ring->total_size =3D rx_ring->total_cnt * sizeof(struct emac_desc); + + rx_ring->total_size =3D ALIGN(rx_ring->total_size, PAGE_SIZE); + + rx_ring->desc_addr =3D dma_alloc_coherent(&pdev->dev, rx_ring->total_size, + &rx_ring->desc_dma_addr, + GFP_KERNEL); + if (!rx_ring->desc_addr) { + kfree(rx_ring->rx_desc_buf); + return -ENOMEM; + } + + rx_ring->head =3D 0; + rx_ring->tail =3D 0; + + return 0; +} + +static void emac_free_tx_resources(struct emac_priv *priv) +{ + struct emac_desc_ring *tr =3D &priv->tx_ring; + struct device *dev =3D &priv->pdev->dev; + + emac_clean_tx_desc_ring(priv); + + kfree(tr->tx_desc_buf); + tr->tx_desc_buf =3D NULL; + + dma_free_coherent(dev, tr->total_size, tr->desc_addr, + tr->desc_dma_addr); + tr->desc_addr =3D NULL; +} + +static void emac_free_rx_resources(struct emac_priv *priv) +{ + struct emac_desc_ring *rr =3D &priv->rx_ring; + struct device *dev =3D &priv->pdev->dev; + + emac_clean_rx_desc_ring(priv); + + kfree(rr->rx_desc_buf); + rr->rx_desc_buf =3D NULL; + + dma_free_coherent(dev, rr->total_size, rr->desc_addr, + rr->desc_dma_addr); + rr->desc_addr =3D NULL; +} + +static int emac_tx_clean_desc(struct emac_priv *priv) +{ + struct net_device *ndev =3D priv->ndev; + struct emac_desc_ring *tx_ring; + struct emac_desc *tx_desc; + u32 i; + + netif_tx_lock(ndev); + + tx_ring =3D &priv->tx_ring; + + i =3D tx_ring->tail; + + while (i !=3D tx_ring->head) { + tx_desc =3D &((struct emac_desc *)tx_ring->desc_addr)[i]; + + /* Stop checking if desc still own by DMA */ + if (READ_ONCE(tx_desc->desc0) & TX_DESC_0_OWN) + break; + + emac_free_tx_buf(priv, i); + memset(tx_desc, 0, sizeof(struct emac_desc)); + + if (++i =3D=3D tx_ring->total_cnt) + i =3D 0; + } + + tx_ring->tail =3D i; + + if (unlikely(netif_queue_stopped(ndev) && + emac_tx_avail(priv) > tx_ring->total_cnt / 4)) + netif_wake_queue(ndev); + + netif_tx_unlock(ndev); + + return 0; +} + +static u32 rx_frame_len(struct emac_desc *desc) +{ + return (desc->desc0 & RX_DESC_0_FRAME_PACKET_LENGTH_MASK) >> + RX_DESC_0_FRAME_PACKET_LENGTH_SHIFT; +} + +static int emac_rx_frame_status(struct emac_priv *priv, struct emac_desc *= desc) +{ + const char *msg =3D NULL; + int ret =3D RX_FRAME_OK; + + /* Drop if not last descriptor, should not normally happen */ + if (!(desc->desc0 & RX_DESC_0_LAST_DESCRIPTOR)) { + msg =3D "Not last descriptor"; + ret =3D RX_FRAME_DISCARD; + } + + if (desc->desc0 & RX_DESC_0_FRAME_RUNT) { + msg =3D "Runt frame"; + ret =3D RX_FRAME_DISCARD; + } + + if (desc->desc0 & RX_DESC_0_FRAME_CRC_ERR) { + msg =3D "Frame CRC error"; + ret =3D RX_FRAME_DISCARD; + } + + if (desc->desc0 & RX_DESC_0_FRAME_MAX_LEN_ERR) { + msg =3D "Frame exceeds max length"; + ret =3D RX_FRAME_DISCARD; + } + + if (desc->desc0 & RX_DESC_0_FRAME_JABBER_ERR) { + msg =3D "Frame jabber error"; + ret =3D RX_FRAME_DISCARD; + } + + if (desc->desc0 & RX_DESC_0_FRAME_LENGTH_ERR) { + msg =3D "Frame length error"; + ret =3D RX_FRAME_DISCARD; + } + + if (rx_frame_len(desc) <=3D ETH_FCS_LEN || + rx_frame_len(desc) > priv->dma_buf_sz) { + msg =3D "Frame length unacceptable"; + ret =3D RX_FRAME_DISCARD; + } + + if (ret !=3D RX_FRAME_OK) + dev_dbg_ratelimited(&priv->ndev->dev, "RX dropped: %s", msg); + + return ret; +} + +/* RX and TX use the same layout for {RX,TX}_DESC_1_BUFFER_SIZE_{1,2} */ + +static u32 make_buf_size_1(u32 size) +{ + return (size << TX_DESC_1_BUFFER_SIZE_1_SHIFT) & + TX_DESC_1_BUFFER_SIZE_1_MASK; +} + +static u32 make_buf_size_2(u32 size) +{ + return (size << TX_DESC_1_BUFFER_SIZE_2_SHIFT) & + TX_DESC_1_BUFFER_SIZE_2_MASK; +} + +static void emac_alloc_rx_desc_buffers(struct emac_priv *priv) +{ + struct emac_desc_ring *rx_ring =3D &priv->rx_ring; + struct emac_desc rx_desc, *rx_desc_addr; + struct net_device *ndev =3D priv->ndev; + struct emac_rx_desc_buffer *rx_buf; + struct sk_buff *skb; + u32 i; + + i =3D rx_ring->head; + rx_buf =3D &rx_ring->rx_desc_buf[i]; + + while (!rx_buf->skb) { + skb =3D netdev_alloc_skb_ip_align(ndev, priv->dma_buf_sz); + if (!skb) + break; + + skb->dev =3D ndev; + + rx_buf->skb =3D skb; + rx_buf->dma_len =3D priv->dma_buf_sz; + rx_buf->dma_addr =3D dma_map_single(&priv->pdev->dev, skb->data, + priv->dma_buf_sz, + DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, rx_buf->dma_addr)) { + dev_err_ratelimited(&ndev->dev, "Mapping skb failed\n"); + goto err_free_skb; + } + + rx_desc_addr =3D &((struct emac_desc *)rx_ring->desc_addr)[i]; + + memset(&rx_desc, 0, sizeof(rx_desc)); + + rx_desc.buffer_addr_1 =3D rx_buf->dma_addr; + rx_desc.desc1 =3D make_buf_size_1(rx_buf->dma_len); + + if (++i =3D=3D rx_ring->total_cnt) { + rx_desc.desc1 |=3D RX_DESC_1_END_RING; + i =3D 0; + } + + *rx_desc_addr =3D rx_desc; + dma_wmb(); + WRITE_ONCE(rx_desc_addr->desc0, rx_desc.desc0 | RX_DESC_0_OWN); + + rx_buf =3D &rx_ring->rx_desc_buf[i]; + } + + rx_ring->head =3D i; + return; + +err_free_skb: + dev_kfree_skb_any(skb); + rx_buf->skb =3D NULL; +} + +/* Returns number of packets received */ +static int emac_rx_clean_desc(struct emac_priv *priv, int budget) +{ + struct net_device *ndev =3D priv->ndev; + struct emac_rx_desc_buffer *rx_buf; + struct emac_desc_ring *rx_ring; + struct sk_buff *skb =3D NULL; + struct emac_desc *rx_desc; + u32 got =3D 0, skb_len, i; + int status; + + rx_ring =3D &priv->rx_ring; + + i =3D rx_ring->tail; + + while (budget--) { + rx_desc =3D &((struct emac_desc *)rx_ring->desc_addr)[i]; + + /* Stop checking if rx_desc still owned by DMA */ + if (READ_ONCE(rx_desc->desc0) & RX_DESC_0_OWN) + break; + + dma_rmb(); + + rx_buf =3D &rx_ring->rx_desc_buf[i]; + + if (!rx_buf->skb) + break; + + got++; + + dma_unmap_single(&priv->pdev->dev, rx_buf->dma_addr, + rx_buf->dma_len, DMA_FROM_DEVICE); + + status =3D emac_rx_frame_status(priv, rx_desc); + if (unlikely(status =3D=3D RX_FRAME_DISCARD)) { + ndev->stats.rx_dropped++; + dev_kfree_skb_irq(rx_buf->skb); + rx_buf->skb =3D NULL; + } else { + skb =3D rx_buf->skb; + skb_len =3D rx_frame_len(rx_desc) - ETH_FCS_LEN; + skb_put(skb, skb_len); + skb->dev =3D ndev; + ndev->hard_header_len =3D ETH_HLEN; + + skb->protocol =3D eth_type_trans(skb, ndev); + + skb->ip_summed =3D CHECKSUM_NONE; + + napi_gro_receive(&priv->napi, skb); + + ndev->stats.rx_packets++; + ndev->stats.rx_bytes +=3D skb_len; + + memset(rx_desc, 0, sizeof(struct emac_desc)); + rx_buf->skb =3D NULL; + } + + if (++i =3D=3D rx_ring->total_cnt) + i =3D 0; + } + + rx_ring->tail =3D i; + + emac_alloc_rx_desc_buffers(priv); + + return got; +} + +static int emac_rx_poll(struct napi_struct *napi, int budget) +{ + struct emac_priv *priv =3D container_of(napi, struct emac_priv, napi); + int work_done; + + emac_tx_clean_desc(priv); + + work_done =3D emac_rx_clean_desc(priv, budget); + if (work_done < budget && napi_complete_done(napi, work_done)) + emac_enable_interrupt(priv); + + return work_done; +} + +/* + * For convenience, skb->data is fragment 0, frags[0] is fragment 1, etc. + * + * Each descriptor can hold up to two fragments, called buffer 1 and 2. Fo= r each + * fragment f, if f % 2 =3D=3D 0, it uses buffer 1, otherwise it uses buff= er 2. + */ + +static int emac_tx_map_frag(struct device *dev, struct emac_desc *tx_desc, + struct emac_tx_desc_buffer *tx_buf, + struct sk_buff *skb, u32 frag_idx) +{ + bool map_as_page, buf_idx; + const skb_frag_t *frag; + phys_addr_t addr; + u32 len; + int ret; + + buf_idx =3D frag_idx % 2; + + if (frag_idx =3D=3D 0) { + /* Non-fragmented part */ + len =3D skb_headlen(skb); + addr =3D dma_map_single(dev, skb->data, len, DMA_TO_DEVICE); + map_as_page =3D false; + } else { + /* Fragment */ + frag =3D &skb_shinfo(skb)->frags[frag_idx - 1]; + len =3D skb_frag_size(frag); + addr =3D skb_frag_dma_map(dev, frag, 0, len, DMA_TO_DEVICE); + map_as_page =3D true; + } + + ret =3D dma_mapping_error(dev, addr); + if (ret) + return ret; + + tx_buf->buf[buf_idx].dma_addr =3D addr; + tx_buf->buf[buf_idx].dma_len =3D len; + tx_buf->buf[buf_idx].map_as_page =3D map_as_page; + + if (buf_idx =3D=3D 0) { + tx_desc->buffer_addr_1 =3D addr; + tx_desc->desc1 |=3D make_buf_size_1(len); + } else { + tx_desc->buffer_addr_2 =3D addr; + tx_desc->desc1 |=3D make_buf_size_2(len); + } + + return 0; +} + +static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb) +{ + struct emac_desc_ring *tx_ring =3D &priv->tx_ring; + struct emac_desc tx_desc, *tx_desc_addr; + struct device *dev =3D &priv->pdev->dev; + struct emac_tx_desc_buffer *tx_buf; + u32 head, old_head, frag_num, f; + bool buf_idx; + + frag_num =3D skb_shinfo(skb)->nr_frags; + head =3D tx_ring->head; + old_head =3D head; + + for (f =3D 0; f < frag_num + 1; f++) { + buf_idx =3D f % 2; + + /* + * If using buffer 1, initialize a new desc. Otherwise, use + * buffer 2 of previous fragment's desc. + */ + if (!buf_idx) { + tx_buf =3D &tx_ring->tx_desc_buf[head]; + tx_desc_addr =3D + &((struct emac_desc *)tx_ring->desc_addr)[head]; + memset(&tx_desc, 0, sizeof(tx_desc)); + + /* + * Give ownership for all but first desc initially. For + * first desc, give at the end so DMA cannot start + * reading uninitialized descs. + */ + if (head !=3D old_head) + tx_desc.desc0 |=3D TX_DESC_0_OWN; + + if (++head =3D=3D tx_ring->total_cnt) { + /* Just used last desc in ring */ + tx_desc.desc1 |=3D TX_DESC_1_END_RING; + head =3D 0; + } + } + + if (emac_tx_map_frag(dev, &tx_desc, tx_buf, skb, f)) { + dev_err_ratelimited(&priv->ndev->dev, + "Map TX frag %d failed\n", f); + goto err_free_skb; + } + + if (f =3D=3D 0) + tx_desc.desc1 |=3D TX_DESC_1_FIRST_SEGMENT; + + if (f =3D=3D frag_num) { + tx_desc.desc1 |=3D TX_DESC_1_LAST_SEGMENT; + tx_buf->skb =3D skb; + if (emac_tx_should_interrupt(priv, frag_num + 1)) + tx_desc.desc1 |=3D + TX_DESC_1_INTERRUPT_ON_COMPLETION; + } + + *tx_desc_addr =3D tx_desc; + } + + /* All descriptors are ready, give ownership for first desc */ + tx_desc_addr =3D &((struct emac_desc *)tx_ring->desc_addr)[old_head]; + dma_wmb(); + WRITE_ONCE(tx_desc_addr->desc0, tx_desc_addr->desc0 | TX_DESC_0_OWN); + + emac_dma_start_transmit(priv); + + tx_ring->head =3D head; + + priv->ndev->stats.tx_packets++; + priv->ndev->stats.tx_bytes +=3D skb->len; + + return; + +err_free_skb: + dev_kfree_skb_any(skb); + priv->ndev->stats.tx_dropped++; +} + +static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device = *ndev) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + int nfrags =3D skb_shinfo(skb)->nr_frags; + struct device *dev =3D &priv->pdev->dev; + + if (unlikely(emac_tx_avail(priv) < nfrags + 1)) { + if (!netif_queue_stopped(ndev)) { + netif_stop_queue(ndev); + dev_err_ratelimited(dev, "TX ring full, stop TX queue\n"); + } + return NETDEV_TX_BUSY; + } + + emac_tx_mem_map(priv, skb); + + /* Make sure there is space in the ring for the next TX. */ + if (unlikely(emac_tx_avail(priv) <=3D MAX_SKB_FRAGS + 2)) + netif_stop_queue(ndev); + + return NETDEV_TX_OK; +} + +static int emac_set_mac_address(struct net_device *ndev, void *addr) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + int ret =3D eth_mac_addr(ndev, addr); + + if (ret) + return ret; + + /* If running, set now; if not running it will be set in emac_up. */ + if (netif_running(ndev)) + emac_set_mac_addr(priv, ndev->dev_addr); + + return 0; +} + +static void emac_mac_multicast_filter_clear(struct emac_priv *priv) +{ + emac_wr(priv, MAC_MULTICAST_HASH_TABLE1, 0x0); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE2, 0x0); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE3, 0x0); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE4, 0x0); +} + +/* Configure Multicast and Promiscuous modes */ +static void emac_set_rx_mode(struct net_device *ndev) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + u32 crc32, bit, reg, hash, val; + struct netdev_hw_addr *ha; + u32 mc_filter[4] =3D { 0 }; + + val =3D emac_rd(priv, MAC_ADDRESS_CONTROL); + + val &=3D ~MREGBIT_PROMISCUOUS_MODE; + + if (ndev->flags & IFF_PROMISC) { + /* Enable promisc mode */ + val |=3D MREGBIT_PROMISCUOUS_MODE; + } else if ((ndev->flags & IFF_ALLMULTI) || + (netdev_mc_count(ndev) > HASH_TABLE_SIZE)) { + /* Accept all multicast frames by setting every bit */ + emac_wr(priv, MAC_MULTICAST_HASH_TABLE1, 0xffff); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE2, 0xffff); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE3, 0xffff); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE4, 0xffff); + } else if (!netdev_mc_empty(ndev)) { + emac_mac_multicast_filter_clear(priv); + netdev_for_each_mc_addr(ha, ndev) { + /* Calculate the CRC of the MAC address */ + crc32 =3D ether_crc(ETH_ALEN, ha->addr); + + /* + * The hash table is an array of 4 16-bit registers. It + * is treated like an array of 64 bits (bits[hash]). Use + * the upper 6 bits of the above CRC as the hash value. + */ + hash =3D (crc32 >> 26) & 0x3F; + reg =3D hash / 16; + bit =3D hash % 16; + mc_filter[reg] |=3D BIT(bit); + } + emac_wr(priv, MAC_MULTICAST_HASH_TABLE1, mc_filter[0]); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE2, mc_filter[1]); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE3, mc_filter[2]); + emac_wr(priv, MAC_MULTICAST_HASH_TABLE4, mc_filter[3]); + } + + emac_wr(priv, MAC_ADDRESS_CONTROL, val); +} + +static int emac_change_mtu(struct net_device *ndev, int mtu) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + u32 frame_len; + + if (netif_running(ndev)) { + netdev_err(ndev, "must be stopped to change MTU\n"); + return -EBUSY; + } + + frame_len =3D mtu + ETH_HLEN + ETH_FCS_LEN; + + if (frame_len <=3D EMAC_DEFAULT_BUFSIZE) + priv->dma_buf_sz =3D EMAC_DEFAULT_BUFSIZE; + else if (frame_len <=3D EMAC_RX_BUF_2K) + priv->dma_buf_sz =3D EMAC_RX_BUF_2K; + else + priv->dma_buf_sz =3D EMAC_RX_BUF_4K; + + ndev->mtu =3D mtu; + + return 0; +} + +static void emac_tx_timeout(struct net_device *ndev, unsigned int txqueue) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + + schedule_work(&priv->tx_timeout_task); +} + +static int emac_mii_read(struct mii_bus *bus, int phy_addr, int regnum) +{ + struct emac_priv *priv =3D bus->priv; + u32 cmd =3D 0, val; + int ret; + + cmd |=3D phy_addr & 0x1F; + cmd |=3D (regnum & 0x1F) << 5; + cmd |=3D MREGBIT_START_MDIO_TRANS | MREGBIT_MDIO_READ_WRITE; + + emac_wr(priv, MAC_MDIO_DATA, 0x0); + emac_wr(priv, MAC_MDIO_CONTROL, cmd); + + ret =3D readl_poll_timeout(priv->iobase + MAC_MDIO_CONTROL, val, + !((val >> 15) & 0x1), 100, 10000); + + if (ret) + return ret; + + val =3D emac_rd(priv, MAC_MDIO_DATA); + return val; +} + +static int emac_mii_write(struct mii_bus *bus, int phy_addr, int regnum, + u16 value) +{ + struct emac_priv *priv =3D bus->priv; + u32 cmd =3D 0, val; + int ret; + + emac_wr(priv, MAC_MDIO_DATA, value); + + cmd |=3D phy_addr & 0x1F; + cmd |=3D (regnum & 0x1F) << 5; + cmd |=3D MREGBIT_START_MDIO_TRANS; + + emac_wr(priv, MAC_MDIO_CONTROL, cmd); + + ret =3D readl_poll_timeout(priv->iobase + MAC_MDIO_CONTROL, val, + !((val >> 15) & 0x1), 100, 10000); + + return ret; +} + +static int emac_mdio_init(struct emac_priv *priv) +{ + struct device *dev =3D &priv->pdev->dev; + struct device_node *mii_np; + struct mii_bus *mii; + int ret; + + mii =3D devm_mdiobus_alloc(dev); + if (!mii) + return -ENOMEM; + + mii->priv =3D priv; + mii->name =3D "k1_emac_mii"; + mii->read =3D emac_mii_read; + mii->write =3D emac_mii_write; + mii->parent =3D dev; + mii->phy_mask =3D 0xffffffff; + snprintf(mii->id, MII_BUS_ID_SIZE, "%s", priv->pdev->name); + + mii_np =3D of_get_available_child_by_name(dev->of_node, "mdio-bus"); + + ret =3D devm_of_mdiobus_register(dev, mii, mii_np); + if (ret) + dev_err_probe(dev, ret, "Failed to register mdio bus\n"); + + of_node_put(mii_np); + return ret; +} + +static void emac_set_tx_fc(struct emac_priv *priv, bool enable) +{ + u32 val; + + val =3D emac_rd(priv, MAC_FC_CONTROL); + + if (enable) { + val |=3D MREGBIT_FC_GENERATION_ENABLE; + val |=3D MREGBIT_AUTO_FC_GENERATION_ENABLE; + } else { + val &=3D ~MREGBIT_FC_GENERATION_ENABLE; + val &=3D ~MREGBIT_AUTO_FC_GENERATION_ENABLE; + } + + emac_wr(priv, MAC_FC_CONTROL, val); +} + +static void emac_set_rx_fc(struct emac_priv *priv, bool enable) +{ + u32 val =3D emac_rd(priv, MAC_FC_CONTROL); + + if (enable) + val |=3D MREGBIT_FC_DECODE_ENABLE; + else + val &=3D ~MREGBIT_FC_DECODE_ENABLE; + + emac_wr(priv, MAC_FC_CONTROL, val); +} + +static void emac_set_fc(struct emac_priv *priv, u8 fc) +{ + emac_set_tx_fc(priv, fc & FLOW_CTRL_TX); + emac_set_rx_fc(priv, fc & FLOW_CTRL_RX); + priv->flow_control =3D fc; +} + +static void emac_set_fc_autoneg(struct emac_priv *priv) +{ + struct phy_device *phydev =3D priv->ndev->phydev; + u32 local_adv, remote_adv; + u8 fc; + + local_adv =3D linkmode_adv_to_lcl_adv_t(phydev->advertising); + + remote_adv =3D 0; + + if (phydev->pause) + remote_adv |=3D LPA_PAUSE_CAP; + + if (phydev->asym_pause) + remote_adv |=3D LPA_PAUSE_ASYM; + + fc =3D mii_resolve_flowctrl_fdx(local_adv, remote_adv); + + priv->flow_control_autoneg =3D true; + + emac_set_fc(priv, fc); +} + +/* + * Even though this MAC supports gigabit operation, it only provides 32-bit + * statistics counters. The most overflow-prone counters are the "bytes" o= nes, + * which at gigabit overflow about twice a minute. + * + * Therefore, we maintain the high 32 bits of counters ourselves, incremen= ting + * every time statistics seem to go backwards. Also, update periodically to + * catch overflows when we are not otherwise checking the statistics often + * enough. + */ + +#define EMAC_STATS_TIMER_PERIOD 20 + +static int emac_read_stat_cnt(struct emac_priv *priv, u8 cnt, u32 *res, + u32 control_reg, u32 high_reg, u32 low_reg) +{ + u32 val; + int ret; + + /* The "read" bit is the same for TX and RX */ + + val =3D MREGBIT_START_TX_COUNTER_READ | cnt; + emac_wr(priv, control_reg, val); + val =3D emac_rd(priv, control_reg); + + ret =3D readl_poll_timeout_atomic(priv->iobase + control_reg, val, + !(val & MREGBIT_START_TX_COUNTER_READ), + 100, 10000); + + if (ret) { + netdev_err(priv->ndev, "Read stat timeout\n"); + return ret; + } + + *res =3D emac_rd(priv, high_reg) << 16; + *res |=3D (u16)emac_rd(priv, low_reg); + + return 0; +} + +static int emac_tx_read_stat_cnt(struct emac_priv *priv, u8 cnt, u32 *res) +{ + return emac_read_stat_cnt(priv, cnt, res, MAC_TX_STATCTR_CONTROL, + MAC_TX_STATCTR_DATA_HIGH, + MAC_TX_STATCTR_DATA_LOW); +} + +static int emac_rx_read_stat_cnt(struct emac_priv *priv, u8 cnt, u32 *res) +{ + return emac_read_stat_cnt(priv, cnt, res, MAC_RX_STATCTR_CONTROL, + MAC_RX_STATCTR_DATA_HIGH, + MAC_RX_STATCTR_DATA_LOW); +} + +static void emac_update_counter(u64 *counter, u32 new_low) +{ + u32 old_low =3D (u32)*counter; + u64 high =3D *counter >> 32; + + if (old_low > new_low) { + /* Overflowed, increment high 32 bits */ + high++; + } + + *counter =3D (high << 32) | new_low; +} + +static void emac_stats_update(struct emac_priv *priv) +{ + u64 *tx_stats_off =3D (u64 *)&priv->tx_stats_off; + u64 *rx_stats_off =3D (u64 *)&priv->rx_stats_off; + u64 *tx_stats =3D (u64 *)&priv->tx_stats; + u64 *rx_stats =3D (u64 *)&priv->rx_stats; + u32 i, res; + + assert_spin_locked(&priv->stats_lock); + + if (!netif_running(priv->ndev) || !netif_device_present(priv->ndev)) { + /* Not up, don't try to update */ + return; + } + + for (i =3D 0; i < sizeof(priv->tx_stats) / sizeof(*tx_stats); i++) { + /* + * If reading stats times out, everything is broken and there's + * nothing we can do. Reading statistics also can't return an + * error, so just return without updating and without + * rescheduling. + */ + if (emac_tx_read_stat_cnt(priv, i, &res)) + return; + + /* + * Re-initializing while bringing interface up resets counters + * to zero, so to provide continuity, we add the values saved + * last time we did emac_down() to the new hardware-provided + * value. + */ + emac_update_counter(&tx_stats[i], res + (u32)tx_stats_off[i]); + } + + /* Similar remarks as TX stats */ + for (i =3D 0; i < sizeof(priv->rx_stats) / sizeof(*rx_stats); i++) { + if (emac_rx_read_stat_cnt(priv, i, &res)) + return; + emac_update_counter(&rx_stats[i], res + (u32)rx_stats_off[i]); + } + + mod_timer(&priv->stats_timer, jiffies + EMAC_STATS_TIMER_PERIOD * HZ); +} + +static void emac_stats_timer(struct timer_list *t) +{ + struct emac_priv *priv =3D timer_container_of(priv, t, stats_timer); + + spin_lock(&priv->stats_lock); + + emac_stats_update(priv); + + spin_unlock(&priv->stats_lock); +} + +static const struct ethtool_rmon_hist_range emac_rmon_hist_ranges[] =3D { + { 64, 64 }, + { 65, 127 }, + { 128, 255 }, + { 256, 511 }, + { 512, 1023 }, + { 1024, 1518 }, + { 1519, 4096 }, + { /* sentinel */ }, +}; + +static void emac_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *storage) +{ + struct emac_priv *priv =3D netdev_priv(dev); + struct emac_hw_tx_stats *tx_stats; + struct emac_hw_rx_stats *rx_stats; + + tx_stats =3D &priv->tx_stats; + rx_stats =3D &priv->rx_stats; + + spin_lock(&priv->stats_lock); + + emac_stats_update(priv); + + storage->tx_packets =3D tx_stats->tx_ok_pkts; + storage->tx_bytes =3D tx_stats->tx_ok_bytes; + storage->tx_errors =3D tx_stats->tx_err_pkts; + + storage->rx_packets =3D rx_stats->rx_ok_pkts; + storage->rx_bytes =3D rx_stats->rx_ok_bytes; + storage->rx_errors =3D rx_stats->rx_err_total_pkts; + storage->rx_crc_errors =3D rx_stats->rx_crc_err_pkts; + storage->rx_frame_errors =3D rx_stats->rx_align_err_pkts; + storage->rx_length_errors =3D rx_stats->rx_len_err_pkts; + + storage->collisions =3D tx_stats->tx_singleclsn_pkts; + storage->collisions +=3D tx_stats->tx_multiclsn_pkts; + storage->collisions +=3D tx_stats->tx_excessclsn_pkts; + + storage->rx_missed_errors =3D rx_stats->rx_drp_fifo_full_pkts; + storage->rx_missed_errors +=3D rx_stats->rx_truncate_fifo_full_pkts; + + spin_unlock(&priv->stats_lock); +} + +static void emac_get_rmon_stats(struct net_device *dev, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct emac_priv *priv =3D netdev_priv(dev); + struct emac_hw_rx_stats *rx_stats; + + rx_stats =3D &priv->rx_stats; + + *ranges =3D emac_rmon_hist_ranges; + + spin_lock(&priv->stats_lock); + + emac_stats_update(priv); + + rmon_stats->undersize_pkts =3D rx_stats->rx_len_undersize_pkts; + rmon_stats->oversize_pkts =3D rx_stats->rx_len_oversize_pkts; + rmon_stats->fragments =3D rx_stats->rx_len_fragment_pkts; + rmon_stats->jabbers =3D rx_stats->rx_len_jabber_pkts; + + /* Only RX has histogram stats */ + + rmon_stats->hist[0] =3D rx_stats->rx_64_pkts; + rmon_stats->hist[1] =3D rx_stats->rx_65_127_pkts; + rmon_stats->hist[2] =3D rx_stats->rx_128_255_pkts; + rmon_stats->hist[3] =3D rx_stats->rx_256_511_pkts; + rmon_stats->hist[4] =3D rx_stats->rx_512_1023_pkts; + rmon_stats->hist[5] =3D rx_stats->rx_1024_1518_pkts; + rmon_stats->hist[6] =3D rx_stats->rx_1519_plus_pkts; + + spin_unlock(&priv->stats_lock); +} + +static void emac_get_eth_mac_stats(struct net_device *dev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct emac_priv *priv =3D netdev_priv(dev); + struct emac_hw_tx_stats *tx_stats; + struct emac_hw_rx_stats *rx_stats; + + tx_stats =3D &priv->tx_stats; + rx_stats =3D &priv->rx_stats; + + spin_lock(&priv->stats_lock); + + emac_stats_update(priv); + + mac_stats->MulticastFramesXmittedOK =3D tx_stats->tx_multicast_pkts; + mac_stats->BroadcastFramesXmittedOK =3D tx_stats->tx_broadcast_pkts; + + mac_stats->MulticastFramesReceivedOK =3D rx_stats->rx_multicast_pkts; + mac_stats->BroadcastFramesReceivedOK =3D rx_stats->rx_broadcast_pkts; + + mac_stats->SingleCollisionFrames =3D tx_stats->tx_singleclsn_pkts; + mac_stats->MultipleCollisionFrames =3D tx_stats->tx_multiclsn_pkts; + mac_stats->LateCollisions =3D tx_stats->tx_lateclsn_pkts; + mac_stats->FramesAbortedDueToXSColls =3D tx_stats->tx_excessclsn_pkts; + + spin_unlock(&priv->stats_lock); +} + +static void emac_get_pause_stats(struct net_device *dev, + struct ethtool_pause_stats *pause_stats) +{ + struct emac_priv *priv =3D netdev_priv(dev); + struct emac_hw_tx_stats *tx_stats; + struct emac_hw_rx_stats *rx_stats; + + tx_stats =3D &priv->tx_stats; + rx_stats =3D &priv->rx_stats; + + spin_lock(&priv->stats_lock); + + emac_stats_update(priv); + + pause_stats->tx_pause_frames =3D tx_stats->tx_pause_pkts; + pause_stats->rx_pause_frames =3D rx_stats->rx_pause_pkts; + + spin_unlock(&priv->stats_lock); +} + +/* Other statistics that are not derivable from standard statistics */ + +#define EMAC_ETHTOOL_STAT(type, name) \ + { offsetof(type, name) / sizeof(u64), #name } + +static const struct emac_ethtool_stats { + size_t offset; + char str[ETH_GSTRING_LEN]; +} emac_ethtool_rx_stats[] =3D { + EMAC_ETHTOOL_STAT(struct emac_hw_rx_stats, rx_drp_fifo_full_pkts), + EMAC_ETHTOOL_STAT(struct emac_hw_rx_stats, rx_truncate_fifo_full_pkts), +}; + +static int emac_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(emac_ethtool_rx_stats); + default: + return -EOPNOTSUPP; + } +} + +static void emac_get_strings(struct net_device *dev, u32 stringset, u8 *da= ta) +{ + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i =3D 0; i < ARRAY_SIZE(emac_ethtool_rx_stats); i++) { + memcpy(data, emac_ethtool_rx_stats[i].str, + ETH_GSTRING_LEN); + data +=3D ETH_GSTRING_LEN; + } + break; + } +} + +static void emac_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct emac_priv *priv =3D netdev_priv(dev); + u64 *rx_stats =3D (u64 *)&priv->rx_stats; + int i; + + spin_lock(&priv->stats_lock); + + emac_stats_update(priv); + + for (i =3D 0; i < ARRAY_SIZE(emac_ethtool_rx_stats); i++) + data[i] =3D rx_stats[emac_ethtool_rx_stats[i].offset]; + + spin_unlock(&priv->stats_lock); +} + +static int emac_ethtool_get_regs_len(struct net_device *dev) +{ + return (EMAC_DMA_REG_CNT + EMAC_MAC_REG_CNT) * sizeof(u32); +} + +static void emac_ethtool_get_regs(struct net_device *dev, + struct ethtool_regs *regs, void *space) +{ + struct emac_priv *priv =3D netdev_priv(dev); + u32 *reg_space =3D space; + int i; + + regs->version =3D 1; + + for (i =3D 0; i < EMAC_DMA_REG_CNT; i++) + reg_space[i] =3D emac_rd(priv, DMA_CONFIGURATION + i * 4); + + for (i =3D 0; i < EMAC_MAC_REG_CNT; i++) + reg_space[i + EMAC_DMA_REG_CNT] =3D + emac_rd(priv, MAC_GLOBAL_CONTROL + i * 4); +} + +static void emac_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct emac_priv *priv =3D netdev_priv(dev); + + pause->autoneg =3D priv->flow_control_autoneg; + pause->tx_pause =3D !!(priv->flow_control & FLOW_CTRL_TX); + pause->rx_pause =3D !!(priv->flow_control & FLOW_CTRL_RX); +} + +static int emac_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct emac_priv *priv =3D netdev_priv(dev); + u8 fc =3D 0; + + priv->flow_control_autoneg =3D pause->autoneg; + + if (pause->autoneg) { + emac_set_fc_autoneg(priv); + } else { + if (pause->tx_pause) + fc |=3D FLOW_CTRL_TX; + + if (pause->rx_pause) + fc |=3D FLOW_CTRL_RX; + + emac_set_fc(priv, fc); + } + + return 0; +} + +static void emac_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strscpy(info->driver, DRIVER_NAME, sizeof(info->driver)); + info->n_stats =3D ARRAY_SIZE(emac_ethtool_rx_stats); +} + +static void emac_tx_timeout_task(struct work_struct *work) +{ + struct net_device *ndev; + struct emac_priv *priv; + + priv =3D container_of(work, struct emac_priv, tx_timeout_task); + ndev =3D priv->ndev; + + rtnl_lock(); + + /* No need to reset if already down */ + if (!netif_running(ndev)) { + rtnl_unlock(); + return; + } + + netdev_err(ndev, "MAC reset due to TX timeout\n"); + + netif_trans_update(ndev); /* prevent tx timeout */ + dev_close(ndev); + dev_open(ndev, NULL); + + rtnl_unlock(); +} + +static void emac_sw_init(struct emac_priv *priv) +{ + priv->dma_buf_sz =3D EMAC_DEFAULT_BUFSIZE; + + priv->tx_ring.total_cnt =3D DEFAULT_TX_RING_NUM; + priv->rx_ring.total_cnt =3D DEFAULT_RX_RING_NUM; + + spin_lock_init(&priv->stats_lock); + + INIT_WORK(&priv->tx_timeout_task, emac_tx_timeout_task); + + priv->tx_coal_frames =3D EMAC_TX_FRAMES; + priv->tx_coal_timeout =3D EMAC_TX_COAL_TIMEOUT; + + timer_setup(&priv->txtimer, emac_tx_coal_timer, 0); + timer_setup(&priv->stats_timer, emac_stats_timer, 0); +} + +static irqreturn_t emac_interrupt_handler(int irq, void *dev_id) +{ + struct net_device *ndev =3D (struct net_device *)dev_id; + struct emac_priv *priv =3D netdev_priv(ndev); + bool should_schedule =3D false; + u32 clr =3D 0; + u32 status; + + status =3D emac_rd(priv, DMA_STATUS_IRQ); + + if (status & MREGBIT_TRANSMIT_TRANSFER_DONE_IRQ) { + clr |=3D MREGBIT_TRANSMIT_TRANSFER_DONE_IRQ; + should_schedule =3D true; + } + + if (status & MREGBIT_TRANSMIT_DES_UNAVAILABLE_IRQ) + clr |=3D MREGBIT_TRANSMIT_DES_UNAVAILABLE_IRQ; + + if (status & MREGBIT_TRANSMIT_DMA_STOPPED_IRQ) + clr |=3D MREGBIT_TRANSMIT_DMA_STOPPED_IRQ; + + if (status & MREGBIT_RECEIVE_TRANSFER_DONE_IRQ) { + clr |=3D MREGBIT_RECEIVE_TRANSFER_DONE_IRQ; + should_schedule =3D true; + } + + if (status & MREGBIT_RECEIVE_DES_UNAVAILABLE_IRQ) + clr |=3D MREGBIT_RECEIVE_DES_UNAVAILABLE_IRQ; + + if (status & MREGBIT_RECEIVE_DMA_STOPPED_IRQ) + clr |=3D MREGBIT_RECEIVE_DMA_STOPPED_IRQ; + + if (status & MREGBIT_RECEIVE_MISSED_FRAME_IRQ) + clr |=3D MREGBIT_RECEIVE_MISSED_FRAME_IRQ; + + if (should_schedule) { + if (napi_schedule_prep(&priv->napi)) { + emac_disable_interrupt(priv); + __napi_schedule_irqoff(&priv->napi); + } + } + + emac_wr(priv, DMA_STATUS_IRQ, clr); + + return IRQ_HANDLED; +} + +static void emac_configure_tx(struct emac_priv *priv) +{ + u32 val; + + /* Set base address */ + val =3D (u32)priv->tx_ring.desc_dma_addr; + emac_wr(priv, DMA_TRANSMIT_BASE_ADDRESS, val); + + /* Set TX inter-frame gap value, enable transmit */ + val =3D emac_rd(priv, MAC_TRANSMIT_CONTROL); + val &=3D ~MREGBIT_IFG_LEN; + val |=3D MREGBIT_TRANSMIT_ENABLE; + val |=3D MREGBIT_TRANSMIT_AUTO_RETRY; + emac_wr(priv, MAC_TRANSMIT_CONTROL, val); + + emac_wr(priv, DMA_TRANSMIT_AUTO_POLL_COUNTER, 0x0); + + /* Start TX DMA */ + val =3D emac_rd(priv, DMA_CONTROL); + val |=3D MREGBIT_START_STOP_TRANSMIT_DMA; + emac_wr(priv, DMA_CONTROL, val); +} + +static void emac_configure_rx(struct emac_priv *priv) +{ + u32 val; + + /* Set base address */ + val =3D (u32)priv->rx_ring.desc_dma_addr; + emac_wr(priv, DMA_RECEIVE_BASE_ADDRESS, val); + + /* Enable receive */ + val =3D emac_rd(priv, MAC_RECEIVE_CONTROL); + val |=3D MREGBIT_RECEIVE_ENABLE; + val |=3D MREGBIT_STORE_FORWARD; + emac_wr(priv, MAC_RECEIVE_CONTROL, val); + + /* Start RX DMA */ + val =3D emac_rd(priv, DMA_CONTROL); + val |=3D MREGBIT_START_STOP_RECEIVE_DMA; + emac_wr(priv, DMA_CONTROL, val); +} + +static void emac_adjust_link(struct net_device *dev) +{ + struct emac_priv *priv =3D netdev_priv(dev); + struct phy_device *phydev =3D dev->phydev; + u32 ctrl; + + if (phydev->link) { + ctrl =3D emac_rd(priv, MAC_GLOBAL_CONTROL); + + /* Update duplex and speed from PHY */ + + if (!phydev->duplex) + ctrl &=3D ~MREGBIT_FULL_DUPLEX_MODE; + else + ctrl |=3D MREGBIT_FULL_DUPLEX_MODE; + + ctrl &=3D ~MREGBIT_SPEED; + + switch (phydev->speed) { + case SPEED_1000: + ctrl |=3D MREGBIT_SPEED_1000M; + break; + case SPEED_100: + ctrl |=3D MREGBIT_SPEED_100M; + break; + case SPEED_10: + ctrl |=3D MREGBIT_SPEED_10M; + break; + default: + netdev_err(dev, "Unknown speed: %d\n", phydev->speed); + phydev->speed =3D SPEED_UNKNOWN; + break; + } + + emac_wr(priv, MAC_GLOBAL_CONTROL, ctrl); + + emac_set_fc_autoneg(priv); + } + + phy_print_status(phydev); +} + +static void emac_update_delay_line(struct emac_priv *priv) +{ + u32 mask =3D 0, val =3D 0; + + mask |=3D EMAC_RX_DLINE_EN; + mask |=3D EMAC_RX_DLINE_STEP_MASK | EMAC_RX_DLINE_CODE_MASK; + mask |=3D EMAC_TX_DLINE_EN; + mask |=3D EMAC_TX_DLINE_STEP_MASK | EMAC_TX_DLINE_CODE_MASK; + + if (phy_interface_mode_is_rgmii(priv->phy_interface)) { + val |=3D EMAC_RX_DLINE_EN; + val |=3D EMAC_DLINE_STEP_15P6 << EMAC_RX_DLINE_STEP_SHIFT; + val |=3D (priv->rx_delay << EMAC_RX_DLINE_CODE_SHIFT) & + EMAC_RX_DLINE_CODE_MASK; + + val |=3D EMAC_TX_DLINE_EN; + val |=3D EMAC_DLINE_STEP_15P6 << EMAC_TX_DLINE_STEP_SHIFT; + val |=3D (priv->tx_delay << EMAC_TX_DLINE_CODE_SHIFT) & + EMAC_TX_DLINE_CODE_MASK; + } + + regmap_update_bits(priv->regmap_apmu, + priv->regmap_apmu_offset + APMU_EMAC_DLINE_REG, + mask, val); +} + +static int emac_phy_connect(struct net_device *ndev) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + struct device *dev =3D &priv->pdev->dev; + struct phy_device *phydev; + struct device_node *np; + int ret; + + ret =3D of_get_phy_mode(dev->of_node, &priv->phy_interface); + if (ret) { + netdev_err(ndev, "No phy-mode found"); + return ret; + } + + switch (priv->phy_interface) { + case PHY_INTERFACE_MODE_RMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + break; + default: + netdev_err(ndev, "Unsupported PHY interface %s", + phy_modes(priv->phy_interface)); + return -EINVAL; + } + + np =3D of_parse_phandle(dev->of_node, "phy-handle", 0); + if (!np && of_phy_is_fixed_link(dev->of_node)) + np =3D of_node_get(dev->of_node); + + if (!np) { + netdev_err(ndev, "No PHY specified"); + return -ENODEV; + } + + ret =3D emac_phy_interface_config(priv); + if (ret) + goto err_node_put; + + phydev =3D of_phy_connect(ndev, np, &emac_adjust_link, 0, + priv->phy_interface); + if (!phydev) { + netdev_err(ndev, "Could not attach to PHY\n"); + ret =3D -ENODEV; + goto err_node_put; + } + + phy_support_asym_pause(phydev); + + phydev->mac_managed_pm =3D true; + + emac_update_delay_line(priv); + +err_node_put: + of_node_put(np); + return ret; +} + +static int emac_up(struct emac_priv *priv) +{ + struct platform_device *pdev =3D priv->pdev; + struct net_device *ndev =3D priv->ndev; + int ret; + + pm_runtime_get_sync(&pdev->dev); + + ret =3D emac_phy_connect(ndev); + if (ret) { + dev_err(&pdev->dev, "emac_phy_connect failed\n"); + goto err_pm_put; + } + + emac_init_hw(priv); + + emac_set_mac_addr(priv, ndev->dev_addr); + emac_configure_tx(priv); + emac_configure_rx(priv); + + emac_alloc_rx_desc_buffers(priv); + + phy_start(ndev->phydev); + + ret =3D request_irq(priv->irq, emac_interrupt_handler, IRQF_SHARED, + ndev->name, ndev); + if (ret) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto err_reset_disconnect_phy; + } + + /* Don't enable MAC interrupts */ + emac_wr(priv, MAC_INTERRUPT_ENABLE, 0x0); + + /* Enable DMA interrupts */ + emac_wr(priv, DMA_INTERRUPT_ENABLE, + MREGBIT_TRANSMIT_TRANSFER_DONE_INTR_ENABLE | + MREGBIT_TRANSMIT_DMA_STOPPED_INTR_ENABLE | + MREGBIT_RECEIVE_TRANSFER_DONE_INTR_ENABLE | + MREGBIT_RECEIVE_DMA_STOPPED_INTR_ENABLE | + MREGBIT_RECEIVE_MISSED_FRAME_INTR_ENABLE); + + napi_enable(&priv->napi); + + netif_start_queue(ndev); + + emac_stats_timer(&priv->stats_timer); + + return 0; + +err_reset_disconnect_phy: + emac_reset_hw(priv); + phy_disconnect(ndev->phydev); + +err_pm_put: + pm_runtime_put_sync(&pdev->dev); + return ret; +} + +static int emac_down(struct emac_priv *priv) +{ + struct platform_device *pdev =3D priv->pdev; + struct net_device *ndev =3D priv->ndev; + + netif_stop_queue(ndev); + + phy_disconnect(ndev->phydev); + + emac_wr(priv, MAC_INTERRUPT_ENABLE, 0x0); + emac_wr(priv, DMA_INTERRUPT_ENABLE, 0x0); + + free_irq(priv->irq, ndev); + + napi_disable(&priv->napi); + + timer_delete_sync(&priv->txtimer); + cancel_work_sync(&priv->tx_timeout_task); + + timer_delete_sync(&priv->stats_timer); + + emac_reset_hw(priv); + + /* Update and save current stats, see emac_stats_update() for usage */ + + spin_lock(&priv->stats_lock); + + emac_stats_update(priv); + + priv->tx_stats_off =3D priv->tx_stats; + priv->rx_stats_off =3D priv->rx_stats; + + spin_unlock(&priv->stats_lock); + + pm_runtime_put_sync(&pdev->dev); + return 0; +} + +/* Called when net interface is brought up. */ +static int emac_open(struct net_device *ndev) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + struct device *dev =3D &priv->pdev->dev; + int ret; + + ret =3D emac_alloc_tx_resources(priv); + if (ret) { + dev_err(dev, "Cannot allocate TX resources\n"); + return ret; + } + + ret =3D emac_alloc_rx_resources(priv); + if (ret) { + dev_err(dev, "Cannot allocate RX resources\n"); + goto err_free_tx; + } + + ret =3D emac_up(priv); + if (ret) { + dev_err(dev, "Error when bringing interface up\n"); + goto err_free_rx; + } + return 0; + +err_free_rx: + emac_free_rx_resources(priv); +err_free_tx: + emac_free_tx_resources(priv); + + return ret; +} + +/* Called when interface is brought down. */ +static int emac_stop(struct net_device *ndev) +{ + struct emac_priv *priv =3D netdev_priv(ndev); + + emac_down(priv); + emac_free_tx_resources(priv); + emac_free_rx_resources(priv); + + return 0; +} + +static const struct ethtool_ops emac_ethtool_ops =3D { + .get_link_ksettings =3D phy_ethtool_get_link_ksettings, + .set_link_ksettings =3D phy_ethtool_set_link_ksettings, + .nway_reset =3D phy_ethtool_nway_reset, + .get_drvinfo =3D emac_get_drvinfo, + .get_link =3D ethtool_op_get_link, + + .get_regs =3D emac_ethtool_get_regs, + .get_regs_len =3D emac_ethtool_get_regs_len, + + .get_rmon_stats =3D emac_get_rmon_stats, + .get_pause_stats =3D emac_get_pause_stats, + .get_eth_mac_stats =3D emac_get_eth_mac_stats, + + .get_sset_count =3D emac_get_sset_count, + .get_strings =3D emac_get_strings, + .get_ethtool_stats =3D emac_get_ethtool_stats, + + .get_pauseparam =3D emac_get_pauseparam, + .set_pauseparam =3D emac_set_pauseparam, +}; + +static const struct net_device_ops emac_netdev_ops =3D { + .ndo_open =3D emac_open, + .ndo_stop =3D emac_stop, + .ndo_start_xmit =3D emac_start_xmit, + .ndo_validate_addr =3D eth_validate_addr, + .ndo_set_mac_address =3D emac_set_mac_address, + .ndo_eth_ioctl =3D phy_do_ioctl_running, + .ndo_change_mtu =3D emac_change_mtu, + .ndo_tx_timeout =3D emac_tx_timeout, + .ndo_set_rx_mode =3D emac_set_rx_mode, + .ndo_get_stats64 =3D emac_get_stats64, +}; + +/* Currently we always use 15.6 ps/step for the delay line */ + +static u32 delay_ps_to_unit(u32 ps) +{ + return DIV_ROUND_CLOSEST(ps * 10, 156); +} + +static u32 delay_unit_to_ps(u32 unit) +{ + return DIV_ROUND_CLOSEST(unit * 156, 10); +} + +#define EMAC_MAX_DELAY_UNIT \ + (EMAC_TX_DLINE_CODE_MASK >> EMAC_TX_DLINE_CODE_SHIFT) + +/* Minus one just to be safe from rounding errors */ +#define EMAC_MAX_DELAY_PS (delay_unit_to_ps(EMAC_MAX_DELAY_UNIT - 1)) + +static int emac_config_dt(struct platform_device *pdev, struct emac_priv *= priv) +{ + struct device_node *np =3D pdev->dev.of_node; + struct device *dev =3D &pdev->dev; + u8 mac_addr[ETH_ALEN] =3D { 0 }; + int ret; + + priv->iobase =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->iobase)) + return dev_err_probe(dev, PTR_ERR(priv->iobase), + "ioremap failed\n"); + + priv->regmap_apmu =3D + syscon_regmap_lookup_by_phandle_args(np, "spacemit,apmu", 1, + &priv->regmap_apmu_offset); + + if (IS_ERR(priv->regmap_apmu)) + return dev_err_probe(dev, PTR_ERR(priv->regmap_apmu), + "failed to get syscon\n"); + + priv->irq =3D platform_get_irq(pdev, 0); + if (priv->irq < 0) + return priv->irq; + + ret =3D of_get_mac_address(np, mac_addr); + if (ret) { + if (ret =3D=3D -EPROBE_DEFER) + return dev_err_probe(dev, ret, + "Can't get MAC address\n"); + + dev_info(&pdev->dev, "Using random MAC address\n"); + eth_hw_addr_random(priv->ndev); + } else { + eth_hw_addr_set(priv->ndev, mac_addr); + } + + priv->tx_delay =3D 0; + priv->rx_delay =3D 0; + + of_property_read_u32(np, "tx-internal-delay-ps", &priv->tx_delay); + of_property_read_u32(np, "rx-internal-delay-ps", &priv->rx_delay); + + if (priv->tx_delay > EMAC_MAX_DELAY_PS) { + dev_err(&pdev->dev, + "tx-internal-delay-ps too large: max %d, got %d", + EMAC_MAX_DELAY_PS, priv->tx_delay); + return -EINVAL; + } + + if (priv->rx_delay > EMAC_MAX_DELAY_PS) { + dev_err(&pdev->dev, + "rx-internal-delay-ps too large: max %d, got %d", + EMAC_MAX_DELAY_PS, priv->rx_delay); + return -EINVAL; + } + + priv->tx_delay =3D delay_ps_to_unit(priv->tx_delay); + priv->rx_delay =3D delay_ps_to_unit(priv->rx_delay); + + return 0; +} + +static void emac_phy_deregister_fixed_link(void *data) +{ + struct device_node *of_node =3D data; + + of_phy_deregister_fixed_link(of_node); +} + +static int emac_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct reset_control *reset; + struct net_device *ndev; + struct emac_priv *priv; + int ret; + + ndev =3D devm_alloc_etherdev(dev, sizeof(struct emac_priv)); + if (!ndev) + return -ENOMEM; + + ndev->hw_features =3D NETIF_F_SG; + ndev->features |=3D ndev->hw_features; + + ndev->max_mtu =3D EMAC_RX_BUF_4K - (ETH_HLEN + ETH_FCS_LEN); + + priv =3D netdev_priv(ndev); + priv->ndev =3D ndev; + priv->pdev =3D pdev; + platform_set_drvdata(pdev, priv); + + ret =3D emac_config_dt(pdev, priv); + if (ret < 0) + return dev_err_probe(dev, ret, "Configuration failed\n"); + + ndev->watchdog_timeo =3D 5 * HZ; + ndev->base_addr =3D (unsigned long)priv->iobase; + ndev->irq =3D priv->irq; + + ndev->ethtool_ops =3D &emac_ethtool_ops; + ndev->netdev_ops =3D &emac_netdev_ops; + + devm_pm_runtime_enable(&pdev->dev); + + priv->bus_clk =3D devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(priv->bus_clk)) + return dev_err_probe(dev, PTR_ERR(priv->bus_clk), + "Failed to get clock\n"); + + reset =3D devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, + NULL); + if (IS_ERR(reset)) + return dev_err_probe(dev, PTR_ERR(reset), + "Failed to get reset\n"); + + if (of_phy_is_fixed_link(dev->of_node)) { + ret =3D of_phy_register_fixed_link(dev->of_node); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register fixed-link\n"); + + ret =3D devm_add_action_or_reset(dev, + emac_phy_deregister_fixed_link, + dev->of_node); + + if (ret) { + dev_err(dev, "devm_add_action_or_reset failed\n"); + return ret; + } + } + + emac_sw_init(priv); + + ret =3D emac_mdio_init(priv); + if (ret) + goto err_timer_delete; + + SET_NETDEV_DEV(ndev, &pdev->dev); + + ret =3D devm_register_netdev(dev, ndev); + if (ret) { + dev_err(dev, "devm_register_netdev failed\n"); + goto err_timer_delete; + } + + netif_napi_add(ndev, &priv->napi, emac_rx_poll); + netif_carrier_off(ndev); + + return 0; + +err_timer_delete: + timer_delete_sync(&priv->txtimer); + timer_delete_sync(&priv->stats_timer); + + return ret; +} + +static void emac_remove(struct platform_device *pdev) +{ + struct emac_priv *priv =3D platform_get_drvdata(pdev); + + timer_shutdown_sync(&priv->txtimer); + cancel_work_sync(&priv->tx_timeout_task); + + timer_shutdown_sync(&priv->stats_timer); + + emac_reset_hw(priv); +} + +static int emac_resume(struct device *dev) +{ + struct emac_priv *priv =3D dev_get_drvdata(dev); + struct net_device *ndev =3D priv->ndev; + int ret; + + ret =3D clk_prepare_enable(priv->bus_clk); + if (ret < 0) { + dev_err(dev, "Failed to enable bus clock: %d\n", ret); + return ret; + } + + if (!netif_running(ndev)) + return 0; + + ret =3D emac_open(ndev); + if (ret) { + clk_disable_unprepare(priv->bus_clk); + return ret; + } + + netif_device_attach(ndev); + + emac_stats_timer(&priv->stats_timer); + + return 0; +} + +static int emac_suspend(struct device *dev) +{ + struct emac_priv *priv =3D dev_get_drvdata(dev); + struct net_device *ndev =3D priv->ndev; + + if (!ndev || !netif_running(ndev)) { + clk_disable_unprepare(priv->bus_clk); + return 0; + } + + emac_stop(ndev); + + clk_disable_unprepare(priv->bus_clk); + netif_device_detach(ndev); + return 0; +} + +static const struct dev_pm_ops emac_pm_ops =3D { + SYSTEM_SLEEP_PM_OPS(emac_suspend, emac_resume) +}; + +static const struct of_device_id emac_of_match[] =3D { + { .compatible =3D "spacemit,k1-emac" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, emac_of_match); + +static struct platform_driver emac_driver =3D { + .probe =3D emac_probe, + .remove =3D emac_remove, + .driver =3D { + .name =3D DRIVER_NAME, + .of_match_table =3D of_match_ptr(emac_of_match), + .pm =3D &emac_pm_ops, + }, +}; +module_platform_driver(emac_driver); + +MODULE_DESCRIPTION("SpacemiT K1 Ethernet driver"); +MODULE_AUTHOR("Vivian Wang "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/spacemit/k1_emac.h b/drivers/net/ethernet= /spacemit/k1_emac.h new file mode 100644 index 0000000000000000000000000000000000000000..ef681f06a50a63cca34561353a7= b7ccf3f996853 --- /dev/null +++ b/drivers/net/ethernet/spacemit/k1_emac.h @@ -0,0 +1,426 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * SpacemiT K1 Ethernet hardware definitions + * + * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd + * Copyright (C) 2025 Vivian Wang + */ + +#ifndef _K1_EMAC_H_ +#define _K1_EMAC_H_ + +/* APMU syscon registers */ + +#define APMU_EMAC_CTRL_REG 0x0 + +#define PHY_INTF_RGMII BIT(2) + +/* + * Only valid for RMII mode + * 0: Ref clock from External PHY + * 1: Ref clock from SoC + */ +#define REF_CLK_SEL BIT(3) + +/* + * Function clock select + * 0: 208 MHz + * 1: 312 MHz + */ +#define FUNC_CLK_SEL BIT(4) + +/* Only valid for RMII, invert TX clk */ +#define RMII_TX_CLK_SEL BIT(6) + +/* Only valid for RMII, invert RX clk */ +#define RMII_RX_CLK_SEL BIT(7) + +/* + * Only valid for RGMII + * 0: TX clk from RX clk + * 1: TX clk from SoC + */ +#define RGMII_TX_CLK_SEL BIT(8) + +#define PHY_IRQ_EN BIT(12) +#define AXI_SINGLE_ID BIT(13) + +#define RMII_TX_PHASE_SHIFT 16 +#define RMII_TX_PHASE_MASK GENMASK(18, 16) +#define RMII_RX_PHASE_SHIFT 20 +#define RMII_RX_PHASE_MASK GENMASK(22, 20) + +#define RGMII_TX_PHASE_SHIFT 24 +#define RGMII_TX_PHASE_MASK GENMASK(26, 24) +#define RGMII_RX_PHASE_SHIFT 28 +#define RGMII_RX_PHASE_MASK GENMASK(30, 28) + +#define APMU_EMAC_DLINE_REG 0x4 + +#define EMAC_RX_DLINE_EN BIT(0) +#define EMAC_RX_DLINE_STEP_SHIFT 4 +#define EMAC_RX_DLINE_STEP_MASK GENMASK(5, 4) +#define EMAC_RX_DLINE_CODE_SHIFT 8 +#define EMAC_RX_DLINE_CODE_MASK GENMASK(15, 8) + +#define EMAC_TX_DLINE_EN BIT(16) +#define EMAC_TX_DLINE_STEP_SHIFT 20 +#define EMAC_TX_DLINE_STEP_MASK GENMASK(21, 20) +#define EMAC_TX_DLINE_CODE_SHIFT 24 +#define EMAC_TX_DLINE_CODE_MASK GENMASK(31, 24) + +#define EMAC_DLINE_STEP_15P6 0 /* 15.6 ps/step */ +#define EMAC_DLINE_STEP_24P4 1 /* 24.4 ps/step */ +#define EMAC_DLINE_STEP_29P7 2 /* 29.7 ps/step */ +#define EMAC_DLINE_STEP_35P1 3 /* 35.1 ps/step */ + +/* DMA register set */ +#define DMA_CONFIGURATION 0x0000 +#define DMA_CONTROL 0x0004 +#define DMA_STATUS_IRQ 0x0008 +#define DMA_INTERRUPT_ENABLE 0x000c + +#define DMA_TRANSMIT_AUTO_POLL_COUNTER 0x0010 +#define DMA_TRANSMIT_POLL_DEMAND 0x0014 +#define DMA_RECEIVE_POLL_DEMAND 0x0018 + +#define DMA_TRANSMIT_BASE_ADDRESS 0x001c +#define DMA_RECEIVE_BASE_ADDRESS 0x0020 +#define DMA_MISSED_FRAME_COUNTER 0x0024 +#define DMA_STOP_FLUSH_COUNTER 0x0028 + +#define DMA_RECEIVE_IRQ_MITIGATION_CTRL 0x002c + +#define DMA_CURRENT_TRANSMIT_DESCRIPTOR_POINTER 0x0030 +#define DMA_CURRENT_TRANSMIT_BUFFER_POINTER 0x0034 +#define DMA_CURRENT_RECEIVE_DESCRIPTOR_POINTER 0x0038 +#define DMA_CURRENT_RECEIVE_BUFFER_POINTER 0x003c + +/* MAC Register set */ +#define MAC_GLOBAL_CONTROL 0x0100 +#define MAC_TRANSMIT_CONTROL 0x0104 +#define MAC_RECEIVE_CONTROL 0x0108 +#define MAC_MAXIMUM_FRAME_SIZE 0x010c +#define MAC_TRANSMIT_JABBER_SIZE 0x0110 +#define MAC_RECEIVE_JABBER_SIZE 0x0114 +#define MAC_ADDRESS_CONTROL 0x0118 +#define MAC_MDIO_CLK_DIV 0x011c +#define MAC_ADDRESS1_HIGH 0x0120 +#define MAC_ADDRESS1_MED 0x0124 +#define MAC_ADDRESS1_LOW 0x0128 +#define MAC_ADDRESS2_HIGH 0x012c +#define MAC_ADDRESS2_MED 0x0130 +#define MAC_ADDRESS2_LOW 0x0134 +#define MAC_ADDRESS3_HIGH 0x0138 +#define MAC_ADDRESS3_MED 0x013c +#define MAC_ADDRESS3_LOW 0x0140 +#define MAC_ADDRESS4_HIGH 0x0144 +#define MAC_ADDRESS4_MED 0x0148 +#define MAC_ADDRESS4_LOW 0x014c +#define MAC_MULTICAST_HASH_TABLE1 0x0150 +#define MAC_MULTICAST_HASH_TABLE2 0x0154 +#define MAC_MULTICAST_HASH_TABLE3 0x0158 +#define MAC_MULTICAST_HASH_TABLE4 0x015c +#define MAC_FC_CONTROL 0x0160 +#define MAC_FC_PAUSE_FRAME_GENERATE 0x0164 +#define MAC_FC_SOURCE_ADDRESS_HIGH 0x0168 +#define MAC_FC_SOURCE_ADDRESS_MED 0x016c +#define MAC_FC_SOURCE_ADDRESS_LOW 0x0170 +#define MAC_FC_DESTINATION_ADDRESS_HIGH 0x0174 +#define MAC_FC_DESTINATION_ADDRESS_MED 0x0178 +#define MAC_FC_DESTINATION_ADDRESS_LOW 0x017c +#define MAC_FC_PAUSE_TIME_VALUE 0x0180 +#define MAC_FC_HIGH_PAUSE_TIME 0x0184 +#define MAC_FC_LOW_PAUSE_TIME 0x0188 +#define MAC_FC_PAUSE_HIGH_THRESHOLD 0x018c +#define MAC_FC_PAUSE_LOW_THRESHOLD 0x0190 +#define MAC_MDIO_CONTROL 0x01a0 +#define MAC_MDIO_DATA 0x01a4 +#define MAC_RX_STATCTR_CONTROL 0x01a8 +#define MAC_RX_STATCTR_DATA_HIGH 0x01ac +#define MAC_RX_STATCTR_DATA_LOW 0x01b0 +#define MAC_TX_STATCTR_CONTROL 0x01b4 +#define MAC_TX_STATCTR_DATA_HIGH 0x01b8 +#define MAC_TX_STATCTR_DATA_LOW 0x01bc +#define MAC_TRANSMIT_FIFO_ALMOST_FULL 0x01c0 +#define MAC_TRANSMIT_PACKET_START_THRESHOLD 0x01c4 +#define MAC_RECEIVE_PACKET_START_THRESHOLD 0x01c8 +#define MAC_STATUS_IRQ 0x01e0 +#define MAC_INTERRUPT_ENABLE 0x01e4 + +/* Used for register dump */ +#define EMAC_DMA_REG_CNT 16 +#define EMAC_MAC_REG_CNT 124 + +/* DMA_CONFIGURATION (0x0000) */ + +/* + * 0-DMA controller in normal operation mode, + * 1-DMA controller reset to default state, + * clearing all internal state information + */ +#define MREGBIT_SOFTWARE_RESET BIT(0) + +#define MREGBIT_BURST_1WORD BIT(1) +#define MREGBIT_BURST_2WORD BIT(2) +#define MREGBIT_BURST_4WORD BIT(3) +#define MREGBIT_BURST_8WORD BIT(4) +#define MREGBIT_BURST_16WORD BIT(5) +#define MREGBIT_BURST_32WORD BIT(6) +#define MREGBIT_BURST_64WORD BIT(7) +#define MREGBIT_BURST_LENGTH GENMASK(7, 1) +#define MREGBIT_DESCRIPTOR_SKIP_LENGTH GENMASK(12, 8) + +/* For Receive and Transmit DMA operate in Big-Endian mode for Descriptors= . */ +#define MREGBIT_DESCRIPTOR_BYTE_ORDERING BIT(13) + +#define MREGBIT_BIG_LITLE_ENDIAN BIT(14) +#define MREGBIT_TX_RX_ARBITRATION BIT(15) +#define MREGBIT_WAIT_FOR_DONE BIT(16) +#define MREGBIT_STRICT_BURST BIT(17) +#define MREGBIT_DMA_64BIT_MODE BIT(18) + +/* DMA_CONTROL (0x0004) */ +#define MREGBIT_START_STOP_TRANSMIT_DMA BIT(0) +#define MREGBIT_START_STOP_RECEIVE_DMA BIT(1) + +/* DMA_STATUS_IRQ (0x0008) */ +#define MREGBIT_TRANSMIT_TRANSFER_DONE_IRQ BIT(0) +#define MREGBIT_TRANSMIT_DES_UNAVAILABLE_IRQ BIT(1) +#define MREGBIT_TRANSMIT_DMA_STOPPED_IRQ BIT(2) +#define MREGBIT_RECEIVE_TRANSFER_DONE_IRQ BIT(4) +#define MREGBIT_RECEIVE_DES_UNAVAILABLE_IRQ BIT(5) +#define MREGBIT_RECEIVE_DMA_STOPPED_IRQ BIT(6) +#define MREGBIT_RECEIVE_MISSED_FRAME_IRQ BIT(7) +#define MREGBIT_MAC_IRQ BIT(8) +#define MREGBIT_TRANSMIT_DMA_STATE GENMASK(18, 16) +#define MREGBIT_RECEIVE_DMA_STATE GENMASK(23, 20) + +/* DMA_INTERRUPT_ENABLE (0x000c) */ +#define MREGBIT_TRANSMIT_TRANSFER_DONE_INTR_ENABLE BIT(0) +#define MREGBIT_TRANSMIT_DES_UNAVAILABLE_INTR_ENABLE BIT(1) +#define MREGBIT_TRANSMIT_DMA_STOPPED_INTR_ENABLE BIT(2) +#define MREGBIT_RECEIVE_TRANSFER_DONE_INTR_ENABLE BIT(4) +#define MREGBIT_RECEIVE_DES_UNAVAILABLE_INTR_ENABLE BIT(5) +#define MREGBIT_RECEIVE_DMA_STOPPED_INTR_ENABLE BIT(6) +#define MREGBIT_RECEIVE_MISSED_FRAME_INTR_ENABLE BIT(7) +#define MREGBIT_MAC_INTR_ENABLE BIT(8) + +/* DMA_RECEIVE_IRQ_MITIGATION_CTRL (0x002c) */ +#define MREGBIT_RECEIVE_IRQ_FRAME_COUNTER_MASK GENMASK(7, 0) +#define MREGBIT_RECEIVE_IRQ_TIMEOUT_COUNTER_SHIFT 8 +#define MREGBIT_RECEIVE_IRQ_TIMEOUT_COUNTER_MASK GENMASK(27, 8) +#define MREGBIT_RECEIVE_IRQ_FRAME_COUNTER_MODE BIT(30) +#define MREGBIT_RECEIVE_IRQ_MITIGATION_ENABLE BIT(31) + +/* MAC_GLOBAL_CONTROL (0x0100) */ +#define MREGBIT_SPEED GENMASK(1, 0) +#define MREGBIT_SPEED_10M 0x0 +#define MREGBIT_SPEED_100M BIT(0) +#define MREGBIT_SPEED_1000M BIT(1) +#define MREGBIT_FULL_DUPLEX_MODE BIT(2) +#define MREGBIT_RESET_RX_STAT_COUNTERS BIT(3) +#define MREGBIT_RESET_TX_STAT_COUNTERS BIT(4) +#define MREGBIT_UNICAST_WAKEUP_MODE BIT(8) +#define MREGBIT_MAGIC_PACKET_WAKEUP_MODE BIT(9) + +/* MAC_TRANSMIT_CONTROL (0x0104) */ +#define MREGBIT_TRANSMIT_ENABLE BIT(0) +#define MREGBIT_INVERT_FCS BIT(1) +#define MREGBIT_DISABLE_FCS_INSERT BIT(2) +#define MREGBIT_TRANSMIT_AUTO_RETRY BIT(3) +#define MREGBIT_IFG_LEN GENMASK(6, 4) +#define MREGBIT_PREAMBLE_LENGTH GENMASK(9, 7) + +/* MAC_RECEIVE_CONTROL (0x0108) */ +#define MREGBIT_RECEIVE_ENABLE BIT(0) +#define MREGBIT_DISABLE_FCS_CHECK BIT(1) +#define MREGBIT_STRIP_FCS BIT(2) +#define MREGBIT_STORE_FORWARD BIT(3) +#define MREGBIT_STATUS_FIRST BIT(4) +#define MREGBIT_PASS_BAD_FRAMES BIT(5) +#define MREGBIT_ACOOUNT_VLAN BIT(6) + +/* MAC_MAXIMUM_FRAME_SIZE (0x010c) */ +#define MREGBIT_MAX_FRAME_SIZE GENMASK(13, 0) + +/* MAC_TRANSMIT_JABBER_SIZE (0x0110) */ +#define MREGBIT_TRANSMIT_JABBER_SIZE GENMASK(15, 0) + +/* MAC_RECEIVE_JABBER_SIZE (0x0114) */ +#define MREGBIT_RECEIVE_JABBER_SIZE GENMASK(15, 0) + +/* MAC_ADDRESS_CONTROL (0x0118) */ +#define MREGBIT_MAC_ADDRESS1_ENABLE BIT(0) +#define MREGBIT_MAC_ADDRESS2_ENABLE BIT(1) +#define MREGBIT_MAC_ADDRESS3_ENABLE BIT(2) +#define MREGBIT_MAC_ADDRESS4_ENABLE BIT(3) +#define MREGBIT_INVERSE_MAC_ADDRESS1_ENABLE BIT(4) +#define MREGBIT_INVERSE_MAC_ADDRESS2_ENABLE BIT(5) +#define MREGBIT_INVERSE_MAC_ADDRESS3_ENABLE BIT(6) +#define MREGBIT_INVERSE_MAC_ADDRESS4_ENABLE BIT(7) +#define MREGBIT_PROMISCUOUS_MODE BIT(8) + +/* MAC_FC_CONTROL (0x0160) */ +#define MREGBIT_FC_DECODE_ENABLE BIT(0) +#define MREGBIT_FC_GENERATION_ENABLE BIT(1) +#define MREGBIT_AUTO_FC_GENERATION_ENABLE BIT(2) +#define MREGBIT_MULTICAST_MODE BIT(3) +#define MREGBIT_BLOCK_PAUSE_FRAMES BIT(4) + +/* MAC_FC_PAUSE_FRAME_GENERATE (0x0164) */ +#define MREGBIT_GENERATE_PAUSE_FRAME BIT(0) + +/* MAC_FC_PAUSE_TIME_VALUE (0x0180) */ +#define MREGBIT_MAC_FC_PAUSE_TIME GENMASK(15, 0) + +/* MAC_MDIO_CONTROL (0x01a0) */ +#define MREGBIT_PHY_ADDRESS GENMASK(4, 0) +#define MREGBIT_REGISTER_ADDRESS GENMASK(9, 5) +#define MREGBIT_MDIO_READ_WRITE BIT(10) +#define MREGBIT_START_MDIO_TRANS BIT(15) + +/* MAC_MDIO_DATA (0x01a4) */ +#define MREGBIT_MDIO_DATA GENMASK(15, 0) + +/* MAC_RX_STATCTR_CONTROL (0x01a8) */ +#define MREGBIT_RX_COUNTER_NUMBER GENMASK(4, 0) +#define MREGBIT_START_RX_COUNTER_READ BIT(15) + +/* MAC_RX_STATCTR_DATA_HIGH (0x01ac) */ +#define MREGBIT_RX_STATCTR_DATA_HIGH GENMASK(15, 0) +/* MAC_RX_STATCTR_DATA_LOW (0x01b0) */ +#define MREGBIT_RX_STATCTR_DATA_LOW GENMASK(15, 0) + +/* MAC_TX_STATCTR_CONTROL (0x01b4) */ +#define MREGBIT_TX_COUNTER_NUMBER GENMASK(4, 0) +#define MREGBIT_START_TX_COUNTER_READ BIT(15) + +/* MAC_TX_STATCTR_DATA_HIGH (0x01b8) */ +#define MREGBIT_TX_STATCTR_DATA_HIGH GENMASK(15, 0) +/* MAC_TX_STATCTR_DATA_LOW (0x01bc) */ +#define MREGBIT_TX_STATCTR_DATA_LOW GENMASK(15, 0) + +/* MAC_TRANSMIT_FIFO_ALMOST_FULL (0x01c0) */ +#define MREGBIT_TX_FIFO_AF GENMASK(13, 0) + +/* MAC_TRANSMIT_PACKET_START_THRESHOLD (0x01c4) */ +#define MREGBIT_TX_PACKET_START_THRESHOLD GENMASK(13, 0) + +/* MAC_RECEIVE_PACKET_START_THRESHOLD (0x01c8) */ +#define MREGBIT_RX_PACKET_START_THRESHOLD GENMASK(13, 0) + +/* MAC_STATUS_IRQ (0x01e0) */ +#define MREGBIT_MAC_UNDERRUN_IRQ BIT(0) +#define MREGBIT_MAC_JABBER_IRQ BIT(1) + +/* MAC_INTERRUPT_ENABLE (0x01e4) */ +#define MREGBIT_MAC_UNDERRUN_INTERRUPT_ENABLE BIT(0) +#define MREGBIT_JABBER_INTERRUPT_ENABLE BIT(1) + +/* RX DMA descriptor */ + +#define RX_DESC_0_FRAME_PACKET_LENGTH_SHIFT 0 +#define RX_DESC_0_FRAME_PACKET_LENGTH_MASK GENMASK(13, 0) +#define RX_DESC_0_FRAME_ALIGN_ERR BIT(14) +#define RX_DESC_0_FRAME_RUNT BIT(15) +#define RX_DESC_0_FRAME_ETHERNET_TYPE BIT(16) +#define RX_DESC_0_FRAME_VLAN BIT(17) +#define RX_DESC_0_FRAME_MULTICAST BIT(18) +#define RX_DESC_0_FRAME_BROADCAST BIT(19) +#define RX_DESC_0_FRAME_CRC_ERR BIT(20) +#define RX_DESC_0_FRAME_MAX_LEN_ERR BIT(21) +#define RX_DESC_0_FRAME_JABBER_ERR BIT(22) +#define RX_DESC_0_FRAME_LENGTH_ERR BIT(23) +#define RX_DESC_0_FRAME_MAC_ADDR1_MATCH BIT(24) +#define RX_DESC_0_FRAME_MAC_ADDR2_MATCH BIT(25) +#define RX_DESC_0_FRAME_MAC_ADDR3_MATCH BIT(26) +#define RX_DESC_0_FRAME_MAC_ADDR4_MATCH BIT(27) +#define RX_DESC_0_FRAME_PAUSE_CTRL BIT(28) +#define RX_DESC_0_LAST_DESCRIPTOR BIT(29) +#define RX_DESC_0_FIRST_DESCRIPTOR BIT(30) +#define RX_DESC_0_OWN BIT(31) + +#define RX_DESC_1_BUFFER_SIZE_1_SHIFT 0 +#define RX_DESC_1_BUFFER_SIZE_1_MASK GENMASK(11, 0) +#define RX_DESC_1_BUFFER_SIZE_2_SHIFT 12 +#define RX_DESC_1_BUFFER_SIZE_2_MASK GENMASK(23, 12) + /* [24] reserved */ +#define RX_DESC_1_SECOND_ADDRESS_CHAINED BIT(25) +#define RX_DESC_1_END_RING BIT(26) + /* [29:27] reserved */ +#define RX_DESC_1_RX_TIMESTAMP BIT(30) +#define RX_DESC_1_PTP_PKT BIT(31) + +/* TX DMA descriptor */ + + /* [29:0] unused */ +#define TX_DESC_0_TX_TIMESTAMP BIT(30) +#define TX_DESC_0_OWN BIT(31) + +#define TX_DESC_1_BUFFER_SIZE_1_SHIFT 0 +#define TX_DESC_1_BUFFER_SIZE_1_MASK GENMASK(11, 0) +#define TX_DESC_1_BUFFER_SIZE_2_SHIFT 12 +#define TX_DESC_1_BUFFER_SIZE_2_MASK GENMASK(23, 12) +#define TX_DESC_1_FORCE_EOP_ERROR BIT(24) +#define TX_DESC_1_SECOND_ADDRESS_CHAINED BIT(25) +#define TX_DESC_1_END_RING BIT(26) +#define TX_DESC_1_DISABLE_PADDING BIT(27) +#define TX_DESC_1_ADD_CRC_DISABLE BIT(28) +#define TX_DESC_1_FIRST_SEGMENT BIT(29) +#define TX_DESC_1_LAST_SEGMENT BIT(30) +#define TX_DESC_1_INTERRUPT_ON_COMPLETION BIT(31) + +struct emac_desc { + u32 desc0; + u32 desc1; + u32 buffer_addr_1; + u32 buffer_addr_2; +}; + +/* Keep stats in this order, index used for accessing hardware */ + +struct emac_hw_tx_stats { + u64 tx_ok_pkts; + u64 tx_total_pkts; + u64 tx_ok_bytes; + u64 tx_err_pkts; + u64 tx_singleclsn_pkts; + u64 tx_multiclsn_pkts; + u64 tx_lateclsn_pkts; + u64 tx_excessclsn_pkts; + u64 tx_unicast_pkts; + u64 tx_multicast_pkts; + u64 tx_broadcast_pkts; + u64 tx_pause_pkts; +}; + +struct emac_hw_rx_stats { + u64 rx_ok_pkts; + u64 rx_total_pkts; + u64 rx_crc_err_pkts; + u64 rx_align_err_pkts; + u64 rx_err_total_pkts; + u64 rx_ok_bytes; + u64 rx_total_bytes; + u64 rx_unicast_pkts; + u64 rx_multicast_pkts; + u64 rx_broadcast_pkts; + u64 rx_pause_pkts; + u64 rx_len_err_pkts; + u64 rx_len_undersize_pkts; + u64 rx_len_oversize_pkts; + u64 rx_len_fragment_pkts; + u64 rx_len_jabber_pkts; + u64 rx_64_pkts; + u64 rx_65_127_pkts; + u64 rx_128_255_pkts; + u64 rx_256_511_pkts; + u64 rx_512_1023_pkts; + u64 rx_1024_1518_pkts; + u64 rx_1519_plus_pkts; + u64 rx_drp_fifo_full_pkts; + u64 rx_truncate_fifo_full_pkts; +}; + +#endif /* _K1_EMAC_H_ */ --=20 2.50.1 From nobody Tue Sep 9 21:30:29 2025 Received: from cstnet.cn (smtp81.cstnet.cn [159.226.251.81]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7CDB34166E; Fri, 5 Sep 2025 11:10:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070646; cv=none; b=hxcgjtrK+r4GB3QnR0PJJIoKW3ejPKfIY3oMFTPsEfaSTkWTH0i5Hg5P9zCVfDqFlePwFPwgmhELpFSGURthkwtYJeFNr6w20ZVMAgLE9+6Ckw+4s67Hg7n88jO1CNUwXIXFhP3F3puAoeLCE9dgrs8b8YnymFTxUj6e0/RM6gg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070646; c=relaxed/simple; bh=JYwXZ2yQ2DNcBndTAT6ZFh53Jl3ZF9pzbFC7JU7r9Q0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TGe9jlNMzjxywiZrsJppxWyKaboivpZ+a8cJBxXsj5UUBTOei4Rk3IykNvFlfsoJ2NbR78sUKSuXvnS40dibrF1E7MxfvukPAaeP/odCSHVUI9SrXDbwFEB7JVtS/kZAsRCZ+bY3YnQSRK7kul7a6UAi7Gp7megnrittbM8OrWQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from [127.0.0.2] (unknown [114.241.87.235]) by APP-03 (Coremail) with SMTP id rQCowACnu4X1xLpoFdfLAA--.1807S5; Fri, 05 Sep 2025 19:09:44 +0800 (CST) From: Vivian Wang Date: Fri, 05 Sep 2025 19:09:32 +0800 Subject: [PATCH net-next v9 3/5] riscv: dts: spacemit: Add Ethernet support for K1 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: <20250905-net-k1-emac-v9-3-f1649b98a19c@iscas.ac.cn> References: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> In-Reply-To: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> To: Andrew Lunn , Jakub Kicinski , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vivian Wang , "David S. Miller" , Eric Dumazet , Paolo Abeni , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti Cc: Vivian Wang , Vadim Fedorenko , Junhui Liu , Simon Horman , Maxime Chevallier , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.2 X-CM-TRANSID: rQCowACnu4X1xLpoFdfLAA--.1807S5 X-Coremail-Antispam: 1UD129KBjvJXoWxWFy7AFy8Wry7XF48Kr18AFb_yoW5KF4Dpa yUAFs3Cr4xCw1rCwnavF9rWF4kGa1FkFyrGr9xGFWxGF4rtry7tFn0yry5Xw48Zws8ArW8 Gr48XrWxKFnrtw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUm214x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JrWl82xGYIkIc2 x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F4UJw A2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq3wAS 0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2 IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0 Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwACI402YVCY1x02628vn2kIc2 xKxwCY1x0262kKe7AKxVW8ZVWrXwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWU JVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67 kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY 6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIx AIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVF xhVjvjDU0xZFpf9x0pRl_MsUUUUU= X-CM-SenderInfo: pzdqw2pxlnt03j6l2u1dvotugofq/ Add nodes for each of the two Ethernet MACs on K1 with generic properties. Also add "gmac" pins to pinctrl config. Signed-off-by: Vivian Wang Reviewed-by: Yixun Lan --- arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi | 48 ++++++++++++++++++++++++= ++++ arch/riscv/boot/dts/spacemit/k1.dtsi | 22 +++++++++++++ 2 files changed, 70 insertions(+) diff --git a/arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi b/arch/riscv/boot= /dts/spacemit/k1-pinctrl.dtsi index 3810557374228100be7adab58cd785c72e6d4aed..aff19c86d5ff381881016eaa87f= c4809da65b50e 100644 --- a/arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi +++ b/arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi @@ -11,6 +11,54 @@ #define K1_GPIO(x) (x / 32) (x % 32) =20 &pinctrl { + gmac0_cfg: gmac0-cfg { + gmac0-pins { + pinmux =3D , /* gmac0_rxdv */ + , /* gmac0_rx_d0 */ + , /* gmac0_rx_d1 */ + , /* gmac0_rx_clk */ + , /* gmac0_rx_d2 */ + , /* gmac0_rx_d3 */ + , /* gmac0_tx_d0 */ + , /* gmac0_tx_d1 */ + , /* gmac0_tx */ + , /* gmac0_tx_d2 */ + , /* gmac0_tx_d3 */ + , /* gmac0_tx_en */ + , /* gmac0_mdc */ + , /* gmac0_mdio */ + , /* gmac0_int_n */ + ; /* gmac0_clk_ref */ + + bias-pull-up =3D <0>; + drive-strength =3D <21>; + }; + }; + + gmac1_cfg: gmac1-cfg { + gmac1-pins { + pinmux =3D , /* gmac1_rxdv */ + , /* gmac1_rx_d0 */ + , /* gmac1_rx_d1 */ + , /* gmac1_rx_clk */ + , /* gmac1_rx_d2 */ + , /* gmac1_rx_d3 */ + , /* gmac1_tx_d0 */ + , /* gmac1_tx_d1 */ + , /* gmac1_tx */ + , /* gmac1_tx_d2 */ + , /* gmac1_tx_d3 */ + , /* gmac1_tx_en */ + , /* gmac1_mdc */ + , /* gmac1_mdio */ + , /* gmac1_int_n */ + ; /* gmac1_clk_ref */ + + bias-pull-up =3D <0>; + drive-strength =3D <21>; + }; + }; + uart0_2_cfg: uart0-2-cfg { uart0-2-pins { pinmux =3D , diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spa= cemit/k1.dtsi index abde8bb07c95c5a745736a2dd6f0c0e0d7c696e4..7b2ac3637d6d9fa1929418cc68a= a25c57850ac7f 100644 --- a/arch/riscv/boot/dts/spacemit/k1.dtsi +++ b/arch/riscv/boot/dts/spacemit/k1.dtsi @@ -805,6 +805,28 @@ network-bus { #size-cells =3D <2>; dma-ranges =3D <0x0 0x00000000 0x0 0x00000000 0x0 0x80000000>, <0x0 0x80000000 0x1 0x00000000 0x0 0x80000000>; + + eth0: ethernet@cac80000 { + compatible =3D "spacemit,k1-emac"; + reg =3D <0x0 0xcac80000 0x0 0x420>; + clocks =3D <&syscon_apmu CLK_EMAC0_BUS>; + interrupts =3D <131>; + mac-address =3D [ 00 00 00 00 00 00 ]; + resets =3D <&syscon_apmu RESET_EMAC0>; + spacemit,apmu =3D <&syscon_apmu 0x3e4>; + status =3D "disabled"; + }; + + eth1: ethernet@cac81000 { + compatible =3D "spacemit,k1-emac"; + reg =3D <0x0 0xcac81000 0x0 0x420>; + clocks =3D <&syscon_apmu CLK_EMAC1_BUS>; + interrupts =3D <133>; + mac-address =3D [ 00 00 00 00 00 00 ]; + resets =3D <&syscon_apmu RESET_EMAC1>; + spacemit,apmu =3D <&syscon_apmu 0x3ec>; + status =3D "disabled"; + }; }; =20 pcie-bus { --=20 2.50.1 From nobody Tue Sep 9 21:30:29 2025 Received: from cstnet.cn (smtp81.cstnet.cn [159.226.251.81]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87B09342CB5; Fri, 5 Sep 2025 11:10:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070656; cv=none; b=N/z1usetpP8nM6IdF4H9D3J1r7HpB5Njg2f+la0vzFs+zFboaOu80wKVf0aLKJNN6lvdwIxLNKwsFgsmzYp0k5S0Dgz7xTaXUpM5fU7AL+ggZmi+IbTza9wdzKqmybfUbgFzT+h/rQYol96qJRxRwlTs4VingwM/zKJvHWrwPKQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070656; c=relaxed/simple; bh=Qkmj3/jPBhieoaSBMeXMM5nRP7Nczqi+TXkMq1kBi4g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Z5UIKVzBmlWEDlENMQli7Bp7+1/X7V8Fqnn511gyZvTRkAIlKKbRI5mXk/ko9xxT38VA/yw81MtEYfI6U7ph3fE4zjqXTqwyGrGKcO28u1BPvdBm/H0yvMe5ocgG+xzXuMfhlBmRxc9pzDt17abDL6kM/e8ItjWRZ83ebZjpS/I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from [127.0.0.2] (unknown [114.241.87.235]) by APP-03 (Coremail) with SMTP id rQCowACnu4X1xLpoFdfLAA--.1807S6; Fri, 05 Sep 2025 19:09:44 +0800 (CST) From: Vivian Wang Date: Fri, 05 Sep 2025 19:09:33 +0800 Subject: [PATCH net-next v9 4/5] riscv: dts: spacemit: Add Ethernet support for BPI-F3 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: <20250905-net-k1-emac-v9-4-f1649b98a19c@iscas.ac.cn> References: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> In-Reply-To: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> To: Andrew Lunn , Jakub Kicinski , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vivian Wang , "David S. Miller" , Eric Dumazet , Paolo Abeni , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti Cc: Vivian Wang , Vadim Fedorenko , Junhui Liu , Simon Horman , Maxime Chevallier , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, Hendrik Hamerlinck X-Mailer: b4 0.14.2 X-CM-TRANSID: rQCowACnu4X1xLpoFdfLAA--.1807S6 X-Coremail-Antispam: 1UD129KBjvJXoW7uF13JF4rXF1kZF15Gw18Grg_yoW8ArWxp3 yakFs3uFWDKr4Skw43ur9F9r1fGa95XrykG3ya9F1rGr4qvr90vw15Kwn7tr1DWrW5Xa45 Xr4xtFyj9r1qkw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUmS14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF0E3s1l82xGYI kIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2 z4x0Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F 4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq 3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7 IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4U M4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwACI402YVCY1x02628vn2 kIc2xKxwCY1x0262kKe7AKxVW8ZVWrXwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkE bVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67 AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI 42IY6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF 4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBI daVFxhVjvjDU0xZFpf9x0pRQJ5wUUUUU= X-CM-SenderInfo: pzdqw2pxlnt03j6l2u1dvotugofq/ Banana Pi BPI-F3 uses an RGMII PHY for each port and uses GPIO for PHY reset. Tested-by: Hendrik Hamerlinck Signed-off-by: Vivian Wang Reviewed-by: Yixun Lan --- arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 46 +++++++++++++++++++++= ++++ 1 file changed, 46 insertions(+) diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/b= oot/dts/spacemit/k1-bananapi-f3.dts index fe22c747c5012fe56d42ac8a7efdbbdb694f31b6..15fa4a5ebd043f3fbb115d37e5a= 980c9b773a228 100644 --- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts +++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts @@ -40,6 +40,52 @@ &emmc { status =3D "okay"; }; =20 +ð0 { + phy-handle =3D <&rgmii0>; + phy-mode =3D "rgmii-id"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&gmac0_cfg>; + rx-internal-delay-ps =3D <0>; + tx-internal-delay-ps =3D <0>; + status =3D "okay"; + + mdio-bus { + #address-cells =3D <0x1>; + #size-cells =3D <0x0>; + + reset-gpios =3D <&gpio K1_GPIO(110) GPIO_ACTIVE_LOW>; + reset-delay-us =3D <10000>; + reset-post-delay-us =3D <100000>; + + rgmii0: phy@1 { + reg =3D <0x1>; + }; + }; +}; + +ð1 { + phy-handle =3D <&rgmii1>; + phy-mode =3D "rgmii-id"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&gmac1_cfg>; + rx-internal-delay-ps =3D <0>; + tx-internal-delay-ps =3D <250>; + status =3D "okay"; + + mdio-bus { + #address-cells =3D <0x1>; + #size-cells =3D <0x0>; + + reset-gpios =3D <&gpio K1_GPIO(115) GPIO_ACTIVE_LOW>; + reset-delay-us =3D <10000>; + reset-post-delay-us =3D <100000>; + + rgmii1: phy@1 { + reg =3D <0x1>; + }; + }; +}; + &uart0 { pinctrl-names =3D "default"; pinctrl-0 =3D <&uart0_2_cfg>; --=20 2.50.1 From nobody Tue Sep 9 21:30:29 2025 Received: from cstnet.cn (smtp81.cstnet.cn [159.226.251.81]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7C5C29DB6E; Fri, 5 Sep 2025 11:10:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070645; cv=none; b=sdddhuanXKCWu9cVJEpQ4QuVF+UolYUMeWkU4ueFe9FXJLZLeKrgRRFd2ecU0kU04oGbFUAe22efsswX1a3/MZ6QxRzpaDClt18MT232r48bqjCeU0Wmc6fm2sBsAk26ztbljLX7zrjFTHvBNoaNlI8ecAciae0aOALNwcGTtbM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757070645; c=relaxed/simple; bh=5uErrrV3rp6pA/pHEkzJKprTkfL5j3WOFyZrL2Ec1jM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BaSGtiyZ2gR3n2Ez+17PhhYYDy5H70NxnAPxqYT5JDtSF/JtctM8q7+TIgph09ZDrPi0ji0vmJgARrbA0uKCurD8HrJzlvFV34qhcuN7DUf4uMQVFXdlOTz/eA438JhNepwn/rMA91ppImKwQzUX3bAl7RAXDq9QmgDYgLsGGOw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from [127.0.0.2] (unknown [114.241.87.235]) by APP-03 (Coremail) with SMTP id rQCowACnu4X1xLpoFdfLAA--.1807S7; Fri, 05 Sep 2025 19:09:44 +0800 (CST) From: Vivian Wang Date: Fri, 05 Sep 2025 19:09:34 +0800 Subject: [PATCH net-next v9 5/5] riscv: dts: spacemit: Add Ethernet support for Jupiter 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: <20250905-net-k1-emac-v9-5-f1649b98a19c@iscas.ac.cn> References: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> In-Reply-To: <20250905-net-k1-emac-v9-0-f1649b98a19c@iscas.ac.cn> To: Andrew Lunn , Jakub Kicinski , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vivian Wang , "David S. Miller" , Eric Dumazet , Paolo Abeni , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti Cc: Vivian Wang , Vadim Fedorenko , Junhui Liu , Simon Horman , Maxime Chevallier , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.2 X-CM-TRANSID: rQCowACnu4X1xLpoFdfLAA--.1807S7 X-Coremail-Antispam: 1UD129KBjvJXoW7Kw43Gw1ftrWfAF43Cr45Jrb_yoW8WFW8pa y3CFsaqFZ7Cr1fKw43Zr9F9F13Ga95GrWkC3y3uF1rJ3yIvFZ0vw1ftw1xtr1DGrW5X34Y vr1IyFyxurnFkw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUmS14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF0E3s1l82xGYI kIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2 z4x0Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F 4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq 3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7 IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4U M4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwACI402YVCY1x02628vn2 kIc2xKxwCY1x0262kKe7AKxVW8ZVWrXwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkE bVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67 AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI 42IY6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF 4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBI daVFxhVjvjDU0xZFpf9x0pRQJ5wUUUUU= X-CM-SenderInfo: pzdqw2pxlnt03j6l2u1dvotugofq/ Milk-V Jupiter uses an RGMII PHY for each port and uses GPIO for PHY reset. Signed-off-by: Vivian Wang Reviewed-by: Yixun Lan --- arch/riscv/boot/dts/spacemit/k1-milkv-jupiter.dts | 46 +++++++++++++++++++= ++++ 1 file changed, 46 insertions(+) diff --git a/arch/riscv/boot/dts/spacemit/k1-milkv-jupiter.dts b/arch/riscv= /boot/dts/spacemit/k1-milkv-jupiter.dts index 4483192141049caa201c093fb206b6134a064f42..c5933555c06b66f40e61fe2b9c1= 59ba0770c2fa1 100644 --- a/arch/riscv/boot/dts/spacemit/k1-milkv-jupiter.dts +++ b/arch/riscv/boot/dts/spacemit/k1-milkv-jupiter.dts @@ -20,6 +20,52 @@ chosen { }; }; =20 +ð0 { + phy-handle =3D <&rgmii0>; + phy-mode =3D "rgmii-id"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&gmac0_cfg>; + rx-internal-delay-ps =3D <0>; + tx-internal-delay-ps =3D <0>; + status =3D "okay"; + + mdio-bus { + #address-cells =3D <0x1>; + #size-cells =3D <0x0>; + + reset-gpios =3D <&gpio K1_GPIO(110) GPIO_ACTIVE_LOW>; + reset-delay-us =3D <10000>; + reset-post-delay-us =3D <100000>; + + rgmii0: phy@1 { + reg =3D <0x1>; + }; + }; +}; + +ð1 { + phy-handle =3D <&rgmii1>; + phy-mode =3D "rgmii-id"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&gmac1_cfg>; + rx-internal-delay-ps =3D <0>; + tx-internal-delay-ps =3D <250>; + status =3D "okay"; + + mdio-bus { + #address-cells =3D <0x1>; + #size-cells =3D <0x0>; + + reset-gpios =3D <&gpio K1_GPIO(115) GPIO_ACTIVE_LOW>; + reset-delay-us =3D <10000>; + reset-post-delay-us =3D <100000>; + + rgmii1: phy@1 { + reg =3D <0x1>; + }; + }; +}; + &uart0 { pinctrl-names =3D "default"; pinctrl-0 =3D <&uart0_2_cfg>; --=20 2.50.1