Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2026-03-25 10:19:37 +08:00
28 changed files with 2435 additions and 1386 deletions
@@ -0,0 +1,162 @@
From df8e1e4a2eb5f8ecdef36c502601e8afbc6ad891 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 24 Dec 2025 17:29:33 +0100
Subject: [PATCH] net: airoha: Reset PPE default cput port in
airoha_ppe_hw_init()
Before this patch the default PPE cpu port used for a specific GDM
device was set running ndo_init() callback during device initialization.
The selected PPE cpu port configured for the specific GDM device depends
on the QDMA block assigned to the GDM device. The selected QDMA block
depends on LAN/WAN configuration as specified in commmit XXXX.
However, the user selected PPE cpu port can be different with respect to
the one hardcoded in the NPU firmware binary. The hardcoded PPE cput port
value is loaded initializing the PPE engine running npu ops ppe_init()
callback in airoha_ppe_offload_setup routine.
Reset the default value for PPE cpu ports in airoha_ppe_hw_init routine
in order to apply the user requested configuration according to the device
DTS setup.
Please note this patch is fixing an issue not visible to the user (so we
do not need to backport it) since airoha_eth driver currently supports just
the internal phy available via the MT7530 DSA switch and there are no WAN
interfaces officially supporte since PCS/external phy is not merged mainline
yet (it will be posted with following patches).
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 28 +++++------------------
drivers/net/ethernet/airoha/airoha_eth.h | 2 ++
drivers/net/ethernet/airoha/airoha_ppe.c | 23 ++++++++++++++++++-
drivers/net/ethernet/airoha/airoha_regs.h | 7 +++---
4 files changed, 33 insertions(+), 27 deletions(-)
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1755,8 +1755,7 @@ static int airoha_dev_init(struct net_de
{
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_eth *eth = port->eth;
- u32 fe_cpu_port;
- u8 ppe_id;
+ int i;
/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
port->qdma = &eth->qdma[!airoha_is_lan_gdm_port(port)];
@@ -1774,28 +1773,13 @@ static int airoha_dev_init(struct net_de
if (err)
return err;
}
- fallthrough;
- case AIROHA_GDM2_IDX:
- if (airoha_ppe_is_enabled(eth, 1)) {
- /* For PPE2 always use secondary cpu port. */
- fe_cpu_port = FE_PSE_PORT_CDM2;
- ppe_id = 1;
- break;
- }
- fallthrough;
- default: {
- u8 qdma_id = port->qdma - &eth->qdma[0];
-
- /* For PPE1 select cpu port according to the running QDMA. */
- fe_cpu_port = qdma_id ? FE_PSE_PORT_CDM2 : FE_PSE_PORT_CDM1;
- ppe_id = 0;
break;
- }
+ default:
+ break;
}
- airoha_fe_rmw(eth, REG_PPE_DFT_CPORT0(ppe_id),
- DFT_CPORT_MASK(port->id),
- __field_prep(DFT_CPORT_MASK(port->id), fe_cpu_port));
+ for (i = 0; i < eth->soc->num_ppe; i++)
+ airoha_ppe_set_cpu_port(port, i);
return 0;
}
@@ -1898,7 +1882,7 @@ static u32 airoha_get_dsa_tag(struct sk_
#endif
}
-static int airoha_get_fe_port(struct airoha_gdm_port *port)
+int airoha_get_fe_port(struct airoha_gdm_port *port)
{
struct airoha_qdma *qdma = port->qdma;
struct airoha_eth *eth = qdma->eth;
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -646,9 +646,11 @@ static inline bool airoha_is_7583(struct
return eth->soc->version == 0x7583;
}
+int airoha_get_fe_port(struct airoha_gdm_port *port);
bool airoha_is_valid_gdm_port(struct airoha_eth *eth,
struct airoha_gdm_port *port);
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
u16 hash, bool rx_wlan);
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -85,6 +85,20 @@ static u32 airoha_ppe_get_timestamp(stru
return FIELD_GET(AIROHA_FOE_IB1_BIND_TIMESTAMP, timestamp);
}
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id)
+{
+ struct airoha_qdma *qdma = port->qdma;
+ u8 fport = airoha_get_fe_port(port);
+ struct airoha_eth *eth = qdma->eth;
+ u8 qdma_id = qdma - &eth->qdma[0];
+ u32 fe_cpu_port;
+
+ fe_cpu_port = qdma_id ? FE_PSE_PORT_CDM2 : FE_PSE_PORT_CDM1;
+ airoha_fe_rmw(eth, REG_PPE_DFT_CPORT(ppe_id, fport),
+ DFT_CPORT_MASK(fport),
+ __field_prep(DFT_CPORT_MASK(fport), fe_cpu_port));
+}
+
static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
{
u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries;
@@ -147,7 +161,9 @@ static void airoha_ppe_hw_init(struct ai
airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED);
- for (p = 0; p < ARRAY_SIZE(eth->ports); p++)
+ for (p = 0; p < ARRAY_SIZE(eth->ports); p++) {
+ struct airoha_gdm_port *port = eth->ports[p];
+
airoha_fe_rmw(eth, REG_PPE_MTU(i, p),
FP0_EGRESS_MTU_MASK |
FP1_EGRESS_MTU_MASK,
@@ -155,6 +171,11 @@ static void airoha_ppe_hw_init(struct ai
AIROHA_MAX_MTU) |
FIELD_PREP(FP1_EGRESS_MTU_MASK,
AIROHA_MAX_MTU));
+ if (!port)
+ continue;
+
+ airoha_ppe_set_cpu_port(port, i);
+ }
}
}
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -312,10 +312,9 @@
#define REG_PPE_HASH_SEED(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x244)
#define PPE_HASH_SEED 0x12345678
-#define REG_PPE_DFT_CPORT0(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x248)
-#define DFT_CPORT_MASK(_n) GENMASK(3 + ((_n) << 2), ((_n) << 2))
-
-#define REG_PPE_DFT_CPORT1(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x24c)
+#define REG_PPE_DFT_CPORT_BASE(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x248)
+#define REG_PPE_DFT_CPORT(_m, _n) (REG_PPE_DFT_CPORT_BASE(_m) + (((_n) / 8) << 2))
+#define DFT_CPORT_MASK(_n) GENMASK(3 + (((_n) % 8) << 2), (((_n) % 8) << 2))
#define REG_PPE_TB_HASH_CFG(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x250)
#define PPE_DRAM_HASH1_MODE_MASK GENMASK(31, 28)
@@ -0,0 +1,165 @@
From b1c803d5c8167026791abfaed96fd3e6a1fcd750 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sat, 21 Mar 2026 15:41:44 +0100
Subject: [PATCH] net: airoha: Rework the code flow in airoha_remove() and in
airoha_probe() error path
As suggested by Simon in [0], rework the code flow in airoha_remove()
and in the airoha_probe() error path in order to rely on a more common
approach un-registering configured net-devices first and destroying the
hw resources at the end of the code.
Introduce airoha_qdma_cleanup routine to release QDMA resources.
[0] https://lore.kernel.org/netdev/20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org/
Suggested-by: Simon Horman <horms@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260321-airoha-remove-rework-v2-1-16c7bade5fe5@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 76 ++++++++++++++----------
1 file changed, 44 insertions(+), 32 deletions(-)
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1368,6 +1368,33 @@ static int airoha_qdma_init(struct platf
return airoha_qdma_hw_init(qdma);
}
+static void airoha_qdma_cleanup(struct airoha_qdma *qdma)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
+ continue;
+
+ netif_napi_del(&qdma->q_rx[i].napi);
+ airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]);
+ if (qdma->q_rx[i].page_pool) {
+ page_pool_destroy(qdma->q_rx[i].page_pool);
+ qdma->q_rx[i].page_pool = NULL;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
+ netif_napi_del(&qdma->q_tx_irq[i].napi);
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
+ if (!qdma->q_tx[i].ndesc)
+ continue;
+
+ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
+ }
+}
+
static int airoha_hw_init(struct platform_device *pdev,
struct airoha_eth *eth)
{
@@ -1395,41 +1422,30 @@ static int airoha_hw_init(struct platfor
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
err = airoha_qdma_init(pdev, eth, &eth->qdma[i]);
if (err)
- return err;
+ goto error;
}
err = airoha_ppe_init(eth);
if (err)
- return err;
+ goto error;
set_bit(DEV_STATE_INITIALIZED, &eth->state);
return 0;
+error:
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_qdma_cleanup(&eth->qdma[i]);
+
+ return err;
}
-static void airoha_hw_cleanup(struct airoha_qdma *qdma)
+static void airoha_hw_cleanup(struct airoha_eth *eth)
{
int i;
- for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
- if (!qdma->q_rx[i].ndesc)
- continue;
-
- netif_napi_del(&qdma->q_rx[i].napi);
- airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]);
- if (qdma->q_rx[i].page_pool)
- page_pool_destroy(qdma->q_rx[i].page_pool);
- }
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
- netif_napi_del(&qdma->q_tx_irq[i].napi);
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
- if (!qdma->q_tx[i].ndesc)
- continue;
-
- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
- }
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_qdma_cleanup(&eth->qdma[i]);
+ airoha_ppe_deinit(eth);
}
static void airoha_qdma_start_napi(struct airoha_qdma *qdma)
@@ -3012,7 +3028,7 @@ static int airoha_probe(struct platform_
err = airoha_hw_init(pdev, eth);
if (err)
- goto error_hw_cleanup;
+ goto error_netdev_free;
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_start_napi(&eth->qdma[i]);
@@ -3040,10 +3056,6 @@ static int airoha_probe(struct platform_
error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(&eth->qdma[i]);
- airoha_ppe_deinit(eth);
-error_hw_cleanup:
- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
- airoha_hw_cleanup(&eth->qdma[i]);
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -3055,6 +3067,8 @@ error_hw_cleanup:
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
+ airoha_hw_cleanup(eth);
+error_netdev_free:
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
@@ -3066,10 +3080,8 @@ static void airoha_remove(struct platfor
struct airoha_eth *eth = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(&eth->qdma[i]);
- airoha_hw_cleanup(&eth->qdma[i]);
- }
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -3080,9 +3092,9 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
- free_netdev(eth->napi_dev);
+ airoha_hw_cleanup(eth);
- airoha_ppe_deinit(eth);
+ free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
}
@@ -13,7 +13,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1382,6 +1382,10 @@ static int airoha_hw_init(struct platfor
@@ -1409,6 +1409,10 @@ static int airoha_hw_init(struct platfor
if (err)
return err;
@@ -28,7 +28,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
airoha_fe_crsn_qsel_init(eth);
@@ -1625,7 +1627,8 @@ static int airoha_dev_open(struct net_de
@@ -1641,7 +1643,8 @@ static int airoha_dev_open(struct net_de
if (err)
return err;
@@ -15,7 +15,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -3113,7 +3113,6 @@ static void airoha_remove(struct platfor
@@ -3109,7 +3109,6 @@ static void airoha_remove(struct platfor
}
static const char * const en7581_xsi_rsts_names[] = {
@@ -23,7 +23,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
"hsi0-mac",
"hsi1-mac",
"hsi-mac",
@@ -3145,7 +3144,6 @@ static int airoha_en7581_get_src_port_id
@@ -3141,7 +3140,6 @@ static int airoha_en7581_get_src_port_id
}
static const char * const an7583_xsi_rsts_names[] = {
@@ -35,7 +35,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
{
struct airoha_eth *eth = port->qdma->eth;
@@ -1622,6 +1628,17 @@ static int airoha_dev_open(struct net_de
@@ -1638,6 +1644,17 @@ static int airoha_dev_open(struct net_de
struct airoha_qdma *qdma = port->qdma;
u32 pse_port = FE_PSE_PORT_PPE1;
@@ -53,7 +53,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
if (err)
@@ -1686,6 +1703,11 @@ static int airoha_dev_stop(struct net_de
@@ -1702,6 +1719,11 @@ static int airoha_dev_stop(struct net_de
}
}
@@ -199,7 +199,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
return airoha_metadata_dst_alloc(port);
}
@@ -3079,6 +3214,10 @@ error_hw_cleanup:
@@ -3075,6 +3210,10 @@ error_napi_stop:
if (port->dev->reg_state == NETREG_REGISTERED)
unregister_netdev(port->dev);
@@ -209,8 +209,8 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+ }
airoha_metadata_dst_free(port);
}
free_netdev(eth->napi_dev);
@@ -3105,6 +3244,10 @@ static void airoha_remove(struct platfor
airoha_hw_cleanup(eth);
@@ -3101,6 +3240,10 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
@@ -219,7 +219,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+ airoha_pcs_destroy(port->pcs);
+ }
}
free_netdev(eth->napi_dev);
airoha_hw_cleanup(eth);
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -236,7 +236,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS);
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -359,6 +359,18 @@
@@ -358,6 +358,18 @@
#define IP_FRAGMENT_PORT_MASK GENMASK(8, 5)
#define IP_FRAGMENT_NBQ_MASK GENMASK(4, 0)
@@ -28,7 +28,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
{
@@ -1631,6 +1633,7 @@ static int airoha_dev_open(struct net_de
@@ -1647,6 +1649,7 @@ static int airoha_dev_open(struct net_de
struct airoha_qdma *qdma = port->qdma;
u32 pse_port = FE_PSE_PORT_PPE1;
@@ -36,7 +36,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
if (airhoa_is_phy_external(port)) {
err = phylink_of_phy_connect(port->phylink, dev->dev.of_node, 0);
if (err) {
@@ -1641,6 +1644,7 @@ static int airoha_dev_open(struct net_de
@@ -1657,6 +1660,7 @@ static int airoha_dev_open(struct net_de
phylink_start(port->phylink);
}
@@ -44,7 +44,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
@@ -1706,10 +1710,12 @@ static int airoha_dev_stop(struct net_de
@@ -1722,10 +1726,12 @@ static int airoha_dev_stop(struct net_de
}
}
@@ -103,7 +103,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
return airoha_metadata_dst_alloc(port);
}
@@ -3217,10 +3229,12 @@ error_hw_cleanup:
@@ -3213,10 +3225,12 @@ error_napi_stop:
if (port->dev->reg_state == NETREG_REGISTERED)
unregister_netdev(port->dev);
@@ -115,8 +115,8 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+#endif
airoha_metadata_dst_free(port);
}
free_netdev(eth->napi_dev);
@@ -3247,10 +3261,12 @@ static void airoha_remove(struct platfor
airoha_hw_cleanup(eth);
@@ -3243,10 +3257,12 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
@@ -127,7 +127,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
}
+#endif
}
free_netdev(eth->napi_dev);
airoha_hw_cleanup(eth);
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
+2
View File
@@ -1839,6 +1839,7 @@ define Device/huawei_ap5030dn
DEVICE_PACKAGES := ath10k-firmware-qca988x-ct kmod-ath10k-ct
LOADER_TYPE := bin
LOADER_FLASH_OFFS := 0x111DC0
LZMA_TEXT_START := 0x82800000
KERNEL_SIZE := 15360k
IMAGE_SIZE := 30720k
COMPILE := loader-$(1).bin
@@ -1854,6 +1855,7 @@ define Device/huawei_ap6010dn
DEVICE_MODEL := AP6010DN
LOADER_TYPE := bin
LOADER_FLASH_OFFS := 0x111DC0
LZMA_TEXT_START := 0x82800000
KERNEL_SIZE := 15360k
IMAGE_SIZE := 30720k
COMPILE := loader-$(1).bin
@@ -1,24 +0,0 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) */
#ifndef _DTS_CLK_LAN9691_H
#define _DTS_CLK_LAN9691_H
#define GCK_ID_QSPI0 0
#define GCK_ID_QSPI2 1
#define GCK_ID_SDMMC0 2
#define GCK_ID_SDMMC1 3
#define GCK_ID_MCAN0 4
#define GCK_ID_MCAN1 5
#define GCK_ID_FLEXCOM0 6
#define GCK_ID_FLEXCOM1 7
#define GCK_ID_FLEXCOM2 8
#define GCK_ID_FLEXCOM3 9
#define GCK_ID_TIMER 10
#define GCK_ID_USB_REFCLK 11
/* Gate clocks */
#define GCK_GATE_USB_DRD 12
#define GCK_GATE_MCRAMC 13
#define GCK_GATE_HMATRIX 14
#endif
-545
View File
@@ -1,545 +0,0 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
/*
* Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
*/
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mfd/at91-usart.h>
#include <dt-bindings/mfd/atmel-flexcom.h>
#include "clk-lan9691.h"
/ {
#address-cells = <1>;
#size-cells = <1>;
model = "Microchip LAN969x";
compatible = "microchip,lan9691";
interrupt-parent = <&gic>;
clocks {
fx100_clk: fx100-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <320000000>;
};
cpu_clk: cpu-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
};
ddr_clk: ddr-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <600000000>;
};
fabric_clk: fabric-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <250000000>;
};
};
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a53";
device_type = "cpu";
reg = <0x0 0x0>;
next-level-cache = <&l2_0>;
};
l2_0: l2-cache {
compatible = "cache";
cache-level = <2>;
cache-unified;
};
};
psci {
compatible = "arm,psci-1.0";
method = "smc";
};
pmu {
compatible = "arm,cortex-a53-pmu";
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
};
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Secure Phys IRQ */
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* Non-secure Phys IRQ */
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* Virt IRQ */
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hyp IRQ */
};
axi: axi {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
usb: usb@300000 {
compatible = "microchip,lan9691-dwc3", "snps,dwc3";
reg = <0x300000 0x80000>;
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks GCK_GATE_USB_DRD>,
<&clks GCK_ID_USB_REFCLK>;
clock-names = "bus_early", "ref";
assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
assigned-clock-rates = <60000000>;
maximum-speed = "high-speed";
dr_mode = "host";
status = "disabled";
};
otp: otp@e0021000 {
compatible = "microchip,lan9691-otpc";
reg = <0xe0021000 0x1000>;
};
flx0: flexcom@e0040000 {
compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
reg = <0xe0040000 0x100>;
ranges = <0x0 0xe0040000 0x800>;
clocks = <&clks GCK_ID_FLEXCOM0>;
#address-cells = <1>;
#size-cells = <1>;
status = "disabled";
usart0: serial@200 {
compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
reg = <0x200 0x200>;
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
<&dma AT91_XDMAC_DT_PERID(2)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "usart";
atmel,fifo-size = <32>;
atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
status = "disabled";
};
spi0: spi@400 {
compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
reg = <0x400 0x200>;
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
<&dma AT91_XDMAC_DT_PERID(2)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "spi_clk";
#address-cells = <1>;
#size-cells = <0>;
atmel,fifo-size = <32>;
status = "disabled";
};
i2c0: i2c@600 {
compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
reg = <0x600 0x200>;
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
<&dma AT91_XDMAC_DT_PERID(2)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
};
flx1: flexcom@e0044000 {
compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
reg = <0xe0044000 0x100>;
ranges = <0x0 0xe0044000 0x800>;
clocks = <&clks GCK_ID_FLEXCOM1>;
#address-cells = <1>;
#size-cells = <1>;
status = "disabled";
usart1: serial@200 {
compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
reg = <0x200 0x200>;
interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
<&dma AT91_XDMAC_DT_PERID(2)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "usart";
atmel,fifo-size = <32>;
atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
status = "disabled";
};
spi1: spi@400 {
compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
reg = <0x400 0x200>;
interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
<&dma AT91_XDMAC_DT_PERID(2)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "spi_clk";
#address-cells = <1>;
#size-cells = <0>;
atmel,fifo-size = <32>;
status = "disabled";
};
i2c1: i2c@600 {
compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
reg = <0x600 0x200>;
interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
<&dma AT91_XDMAC_DT_PERID(2)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
};
trng: rng@e0048000 {
compatible = "microchip,lan9691-trng", "atmel,at91sam9g45-trng";
reg = <0xe0048000 0x100>;
clocks = <&fabric_clk>;
status = "disabled";
};
aes: crypto@e004c000 {
compatible = "microchip,lan9691-aes", "atmel,at91sam9g46-aes";
reg = <0xe004c000 0x100>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(12)>,
<&dma AT91_XDMAC_DT_PERID(13)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "aes_clk";
status = "disabled";
};
flx2: flexcom@e0060000 {
compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
reg = <0xe0060000 0x100>;
ranges = <0x0 0xe0060000 0x800>;
clocks = <&clks GCK_ID_FLEXCOM2>;
#address-cells = <1>;
#size-cells = <1>;
status = "disabled";
usart2: serial@200 {
compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
reg = <0x200 0x200>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
<&dma AT91_XDMAC_DT_PERID(6)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "usart";
atmel,fifo-size = <32>;
atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
status = "disabled";
};
spi2: spi@400 {
compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
reg = <0x400 0x200>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
<&dma AT91_XDMAC_DT_PERID(6)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "spi_clk";
#address-cells = <1>;
#size-cells = <0>;
atmel,fifo-size = <32>;
status = "disabled";
};
i2c2: i2c@600 {
compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
reg = <0x600 0x200>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
<&dma AT91_XDMAC_DT_PERID(6)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
};
flx3: flexcom@e0064000 {
compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
reg = <0xe0064000 0x100>;
ranges = <0x0 0xe0064000 0x800>;
clocks = <&clks GCK_ID_FLEXCOM3>;
#address-cells = <1>;
#size-cells = <1>;
status = "disabled";
usart3: serial@200 {
compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
reg = <0x200 0x200>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
<&dma AT91_XDMAC_DT_PERID(8)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "usart";
atmel,fifo-size = <32>;
atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
status = "disabled";
};
spi3: spi@400 {
compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
reg = <0x400 0x200>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
<&dma AT91_XDMAC_DT_PERID(8)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
clock-names = "spi_clk";
#address-cells = <1>;
#size-cells = <0>;
atmel,fifo-size = <32>;
status = "disabled";
};
i2c3: i2c@600 {
compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
reg = <0x600 0x200>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
<&dma AT91_XDMAC_DT_PERID(8)>;
dma-names = "tx", "rx";
clocks = <&fabric_clk>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
};
dma: dma-controller@e0068000 {
compatible = "microchip,lan9691-dma", "microchip,sama7g5-dma";
reg = <0xe0068000 0x1000>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
dma-channels = <16>;
#dma-cells = <1>;
clocks = <&fabric_clk>;
clock-names = "dma_clk";
};
sha: crypto@e006c000 {
compatible = "microchip,lan9691-sha", "atmel,at91sam9g46-sha";
reg = <0xe006c000 0xec>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma AT91_XDMAC_DT_PERID(14)>;
dma-names = "tx";
clocks = <&fabric_clk>;
clock-names = "sha_clk";
status = "disabled";
};
timer: timer@e008c000 {
compatible = "snps,dw-apb-timer";
reg = <0xe008c000 0x400>;
clocks = <&fabric_clk>;
clock-names = "timer";
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
watchdog: watchdog@e0090000 {
compatible = "snps,dw-wdt";
reg = <0xe0090000 0x1000>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&fabric_clk>;
};
cpu_ctrl: syscon@e00c0000 {
compatible = "microchip,lan966x-cpu-syscon", "syscon";
reg = <0xe00c0000 0x350>;
};
switch: switch@e00c0000 {
compatible = "microchip,lan9691-switch";
reg = <0xe00c0000 0x0010000>,
<0xe2010000 0x1410000>;
reg-names = "cpu", "devices";
interrupt-names = "xtr", "fdma", "ptp";
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
resets = <&reset 0>;
reset-names = "switch";
status = "disabled";
};
clks: clock-controller@e00c00b4 {
compatible = "microchip,lan9691-gck";
reg = <0xe00c00b4 0x30>, <0xe00c0308 0x4>;
#clock-cells = <1>;
clocks = <&cpu_clk>, <&ddr_clk>, <&fx100_clk>;
clock-names = "cpu", "ddr", "sys";
};
qspi0: spi@e0804000 {
compatible = "microchip,lan9691-qspi";
reg = <0xe0804000 0x00000100>,
<0x20000000 0x08000000>;
reg-names = "qspi_base", "qspi_mmap";
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&fabric_clk>, <&clks GCK_ID_QSPI0>;
clock-names = "pclk", "gclk";
assigned-clocks = <&clks GCK_ID_QSPI0>;
assigned-clock-rates = <100000000>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
sdmmc0: mmc@e0830000 {
compatible = "microchip,lan9691-sdhci";
reg = <0xe0830000 0x00000300>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks GCK_ID_SDMMC0>, <&clks GCK_ID_SDMMC0>;
clock-names = "hclock", "multclk";
assigned-clocks = <&clks GCK_ID_SDMMC0>;
assigned-clock-rates = <100000000>;
status = "disabled";
};
sdmmc1: mmc@e0838000 {
compatible = "microchip,lan9691-sdhci";
reg = <0xe0838000 0x00000300>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks GCK_ID_SDMMC1>, <&clks GCK_ID_SDMMC1>;
clock-names = "hclock", "multclk";
assigned-clocks = <&clks GCK_ID_SDMMC1>;
assigned-clock-rates = <45000000>;
status = "disabled";
};
qspi2: spi@e0834000 {
compatible = "microchip,lan9691-qspi";
reg = <0xe0834000 0x00000100>,
<0x30000000 0x04000000>;
reg-names = "qspi_base", "qspi_mmap";
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&fabric_clk>, <&clks GCK_ID_QSPI2>;
clock-names = "pclk", "gclk";
assigned-clocks = <&clks GCK_ID_QSPI2>;
assigned-clock-rates = <100000000>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
reset: reset-controller@e201000c {
compatible = "microchip,lan9691-switch-reset",
"microchip,lan966x-switch-reset";
reg = <0xe201000c 0x4>;
reg-names = "gcb";
#reset-cells = <1>;
cpu-syscon = <&cpu_ctrl>;
};
gpio: pinctrl@e20100d4 {
compatible = "microchip,lan9691-pinctrl";
reg = <0xe20100d4 0xd4>,
<0xe2010370 0xa8>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&gpio 0 0 66>;
interrupt-controller;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
#interrupt-cells = <2>;
};
mdio0: mdio@e20101a8 {
compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
reg = <0xe20101a8 0x24>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&fx100_clk>;
status = "disabled";
};
mdio1: mdio@e20101cc {
compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
reg = <0xe20101cc 0x24>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&fx100_clk>;
status = "disabled";
};
sgpio: gpio@e2010230 {
compatible = "microchip,lan9691-sgpio", "microchip,sparx5-sgpio";
reg = <0xe2010230 0x118>;
clocks = <&fx100_clk>;
resets = <&reset 0>;
reset-names = "switch";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
sgpio_in: gpio@0 {
compatible = "microchip,lan9691-sgpio-bank",
"microchip,sparx5-sgpio-bank";
reg = <0>;
gpio-controller;
#gpio-cells = <3>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <3>;
};
sgpio_out: gpio@1 {
compatible = "microchip,lan9691-sgpio-bank",
"microchip,sparx5-sgpio-bank";
reg = <1>;
gpio-controller;
#gpio-cells = <3>;
};
};
tmon: hwmon@e2020100 {
compatible = "microchip,lan9691-temp", "microchip,sparx5-temp";
reg = <0xe2020100 0xc>;
clocks = <&fx100_clk>;
#thermal-sensor-cells = <0>;
};
serdes: serdes@e3410000 {
compatible = "microchip,lan9691-serdes";
reg = <0xe3410000 0x150000>;
#phy-cells = <1>;
clocks = <&fabric_clk>;
};
gic: interrupt-controller@e8c11000 {
compatible = "arm,gic-400";
reg = <0xe8c11000 0x1000>, /* Distributor GICD_ */
<0xe8c12000 0x2000>, /* CPU interface GICC_ */
<0xe8c14000 0x2000>, /* Virt interface control */
<0xe8c16000 0x2000>; /* Virt CPU interface */
#interrupt-cells = <3>;
interrupt-controller;
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
};
};
};
@@ -1,795 +0,0 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
/*
* Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
*/
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
#include "lan9691.dtsi"
/ {
model = "Microchip EV23X71A";
compatible = "microchip,ev23x71a", "microchip,lan9696", "microchip,lan9691";
aliases {
serial0 = &usart0;
};
chosen {
stdout-path = "serial0:115200n8";
};
gpio-restart {
compatible = "gpio-restart";
gpios = <&gpio 60 GPIO_ACTIVE_LOW>;
open-source;
priority = <200>;
};
i2c-mux {
compatible = "i2c-mux-gpio";
#address-cells = <1>;
#size-cells = <0>;
i2c-parent = <&i2c3>;
idle-state = <0x8>;
mux-gpios = <&sgpio_out 0 1 GPIO_ACTIVE_HIGH>,
<&sgpio_out 0 2 GPIO_ACTIVE_HIGH>,
<&sgpio_out 0 3 GPIO_ACTIVE_HIGH>;
settle-time-us = <100>;
i2c_sfp0: i2c@0 {
reg = <0x0>;
};
i2c_sfp1: i2c@1 {
reg = <0x1>;
};
i2c_sfp2: i2c@2 {
reg = <0x2>;
};
i2c_sfp3: i2c@3 {
reg = <0x3>;
};
i2c_poe: i2c@7 {
reg = <0x7>;
};
};
leds {
compatible = "gpio-leds";
led-status {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_STATUS;
gpios = <&gpio 61 GPIO_ACTIVE_LOW>;
};
led-sfp1-green {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
function-enumerator = <0>;
gpios = <&sgpio_out 6 0 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led-sfp1-yellow {
color = <LED_COLOR_ID_YELLOW>;
function = LED_FUNCTION_LAN;
function-enumerator = <0>;
gpios = <&sgpio_out 6 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led-sfp2-green {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
function-enumerator = <1>;
gpios = <&sgpio_out 7 0 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led-sfp2-yellow {
color = <LED_COLOR_ID_YELLOW>;
function = LED_FUNCTION_LAN;
function-enumerator = <1>;
gpios = <&sgpio_out 7 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led-sfp3-green {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
function-enumerator = <2>;
gpios = <&sgpio_out 8 0 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led-sfp3-yellow {
color = <LED_COLOR_ID_YELLOW>;
function = LED_FUNCTION_LAN;
function-enumerator = <2>;
gpios = <&sgpio_out 8 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led-sfp4-green {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
function-enumerator = <3>;
gpios = <&sgpio_out 9 0 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led-sfp4-yellow {
color = <LED_COLOR_ID_YELLOW>;
function = LED_FUNCTION_LAN;
function-enumerator = <3>;
gpios = <&sgpio_out 9 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
};
mux-controller {
compatible = "gpio-mux";
#mux-control-cells = <0>;
mux-gpios = <&sgpio_out 1 2 GPIO_ACTIVE_LOW>,
<&sgpio_out 1 3 GPIO_ACTIVE_LOW>;
};
sfp0: sfp0 {
compatible = "sff,sfp";
i2c-bus = <&i2c_sfp0>;
tx-disable-gpios = <&sgpio_out 6 2 GPIO_ACTIVE_HIGH>;
los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
};
sfp1: sfp1 {
compatible = "sff,sfp";
i2c-bus = <&i2c_sfp1>;
tx-disable-gpios = <&sgpio_out 7 2 GPIO_ACTIVE_HIGH>;
los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
};
sfp2: sfp2 {
compatible = "sff,sfp";
i2c-bus = <&i2c_sfp2>;
tx-disable-gpios = <&sgpio_out 8 2 GPIO_ACTIVE_HIGH>;
los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
};
sfp3: sfp3 {
compatible = "sff,sfp";
i2c-bus = <&i2c_sfp3>;
tx-disable-gpios = <&sgpio_out 9 2 GPIO_ACTIVE_HIGH>;
los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
};
};
&gpio {
emmc_sd_pins: emmc-sd-pins {
/* eMMC_SD - CMD, CLK, D0, D1, D2, D3, D4, D5, D6, D7, RSTN */
pins = "GPIO_14", "GPIO_15", "GPIO_16", "GPIO_17",
"GPIO_18", "GPIO_19", "GPIO_20", "GPIO_21",
"GPIO_22", "GPIO_23", "GPIO_24";
function = "emmc_sd";
};
fan_pins: fan-pins {
pins = "GPIO_25", "GPIO_26";
function = "fan";
};
fc0_pins: fc0-pins {
pins = "GPIO_3", "GPIO_4";
function = "fc";
};
fc2_pins: fc2-pins {
pins = "GPIO_64", "GPIO_65", "GPIO_66";
function = "fc";
};
fc3_pins: fc3-pins {
pins = "GPIO_55", "GPIO_56";
function = "fc";
};
mdio_irq_pins: mdio-irq-pins {
pins = "GPIO_11";
function = "miim_irq";
};
mdio_pins: mdio-pins {
pins = "GPIO_9", "GPIO_10";
function = "miim";
};
ptp_ext_pins: ptp-ext-pins {
pins = "GPIO_59";
function = "ptpsync_5";
};
ptp_out_pins: ptp-out-pins {
pins = "GPIO_58";
function = "ptpsync_4";
};
sgpio_pins: sgpio-pins {
/* SCK, D0, D1, LD */
pins = "GPIO_5", "GPIO_6", "GPIO_7", "GPIO_8";
function = "sgpio_a";
};
usb_over_pins: usb-over-pins {
pins = "GPIO_13";
function = "usb_over_detect";
};
usb_power_pins: usb-power-pins {
pins = "GPIO_1";
function = "usb_power";
};
usb_rst_pins: usb-rst-pins {
pins = "GPIO_12";
function = "usb2phy_rst";
};
usb_ulpi_pins: usb-ulpi-pins {
pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
"GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",
"GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
function = "usb_ulpi";
};
};
&flx0 {
atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
status = "okay";
};
&flx2 {
atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_SPI>;
status = "okay";
};
&flx3 {
atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
status = "okay";
};
&i2c3 {
pinctrl-0 = <&fc3_pins>;
pinctrl-names = "default";
i2c-analog-filter;
i2c-digital-filter;
i2c-digital-filter-width-ns = <35>;
i2c-sda-hold-time-ns = <1500>;
status = "okay";
};
&mdio0 {
pinctrl-0 = <&mdio_pins>, <&mdio_irq_pins>;
pinctrl-names = "default";
reset-gpios = <&gpio 62 GPIO_ACTIVE_LOW>;
status = "okay";
phy3: phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy4: phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <4>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy5: phy@5 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <5>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy6: phy@6 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <6>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy7: phy@7 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <7>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy8: phy@8 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <8>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy9: phy@9 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <9>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy10: phy@10 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <10>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy11: phy@11 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <11>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy12: phy@12 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <12>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy13: phy@13 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <13>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy14: phy@14 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <14>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy15: phy@15 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <15>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy16: phy@16 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <16>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy17: phy@17 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <17>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy18: phy@18 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <18>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy19: phy@19 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <19>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy20: phy@20 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <20>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy21: phy@21 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <21>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy22: phy@22 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <22>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy23: phy@23 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <23>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy24: phy@24 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <24>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy25: phy@25 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <25>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy26: phy@26 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <26>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
phy27: phy@27 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <27>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio>;
};
};
&otp {
nvmem-layout {
compatible = "microchip,otp-layout";
base_mac_address: base-mac-address {
#nvmem-cell-cells = <1>;
};
};
};
&qspi0 {
status = "okay";
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <100000000>;
#address-cells = <1>;
#size-cells = <1>;
spi-tx-bus-width = <1>;
spi-rx-bus-width = <4>;
m25p,fast-read;
};
};
&sdmmc0 {
pinctrl-0 = <&emmc_sd_pins>;
pinctrl-names = "default";
max-frequency = <100000000>;
bus-width = <8>;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
non-removable;
disable-wp;
status = "okay";
};
&serdes {
status = "okay";
};
&sgpio {
pinctrl-0 = <&sgpio_pins>;
pinctrl-names = "default";
microchip,sgpio-port-ranges = <0 1>, <6 9>;
status = "okay";
gpio@0 {
ngpios = <128>;
};
gpio@1 {
ngpios = <128>;
};
};
&spi2 {
pinctrl-0 = <&fc2_pins>;
pinctrl-names = "default";
cs-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
status = "okay";
};
&switch {
pinctrl-0 = <&ptp_out_pins>, <&ptp_ext_pins>;
pinctrl-names = "default";
nvmem-cells = <&base_mac_address 0>;
nvmem-cell-names = "mac-address";
status = "okay";
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
port0: port@0 {
reg = <0>;
phy-handle = <&phy4>;
phy-mode = "qsgmii";
phys = <&serdes 0>;
microchip,bandwidth = <1000>;
};
port1: port@1 {
reg = <1>;
phy-handle = <&phy5>;
phy-mode = "qsgmii";
phys = <&serdes 0>;
microchip,bandwidth = <1000>;
};
port2: port@2 {
reg = <2>;
phy-handle = <&phy6>;
phy-mode = "qsgmii";
phys = <&serdes 0>;
microchip,bandwidth = <1000>;
};
port3: port@3 {
reg = <3>;
phy-handle = <&phy7>;
phy-mode = "qsgmii";
phys = <&serdes 0>;
microchip,bandwidth = <1000>;
};
port4: port@4 {
reg = <4>;
phy-handle = <&phy8>;
phy-mode = "qsgmii";
phys = <&serdes 1>;
microchip,bandwidth = <1000>;
};
port5: port@5 {
reg = <5>;
phy-handle = <&phy9>;
phy-mode = "qsgmii";
phys = <&serdes 1>;
microchip,bandwidth = <1000>;
};
port6: port@6 {
reg = <6>;
phy-handle = <&phy10>;
phy-mode = "qsgmii";
phys = <&serdes 1>;
microchip,bandwidth = <1000>;
};
port7: port@7 {
reg = <7>;
phy-handle = <&phy11>;
phy-mode = "qsgmii";
phys = <&serdes 1>;
microchip,bandwidth = <1000>;
};
port8: port@8 {
reg = <8>;
phy-handle = <&phy12>;
phy-mode = "qsgmii";
phys = <&serdes 2>;
microchip,bandwidth = <1000>;
};
port9: port@9 {
reg = <9>;
phy-handle = <&phy13>;
phy-mode = "qsgmii";
phys = <&serdes 2>;
microchip,bandwidth = <1000>;
};
port10: port@10 {
reg = <10>;
phy-handle = <&phy14>;
phy-mode = "qsgmii";
phys = <&serdes 2>;
microchip,bandwidth = <1000>;
};
port11: port@11 {
reg = <11>;
phy-handle = <&phy15>;
phy-mode = "qsgmii";
phys = <&serdes 2>;
microchip,bandwidth = <1000>;
};
port12: port@12 {
reg = <12>;
phy-handle = <&phy16>;
phy-mode = "qsgmii";
phys = <&serdes 3>;
microchip,bandwidth = <1000>;
};
port13: port@13 {
reg = <13>;
phy-handle = <&phy17>;
phy-mode = "qsgmii";
phys = <&serdes 3>;
microchip,bandwidth = <1000>;
};
port14: port@14 {
reg = <14>;
phy-handle = <&phy18>;
phy-mode = "qsgmii";
phys = <&serdes 3>;
microchip,bandwidth = <1000>;
};
port15: port@15 {
reg = <15>;
phy-handle = <&phy19>;
phy-mode = "qsgmii";
phys = <&serdes 3>;
microchip,bandwidth = <1000>;
};
port16: port@16 {
reg = <16>;
phy-handle = <&phy20>;
phy-mode = "qsgmii";
phys = <&serdes 4>;
microchip,bandwidth = <1000>;
};
port17: port@17 {
reg = <17>;
phy-handle = <&phy21>;
phy-mode = "qsgmii";
phys = <&serdes 4>;
microchip,bandwidth = <1000>;
};
port18: port@18 {
reg = <18>;
phy-handle = <&phy22>;
phy-mode = "qsgmii";
phys = <&serdes 4>;
microchip,bandwidth = <1000>;
};
port19: port@19 {
reg = <19>;
phy-handle = <&phy23>;
phy-mode = "qsgmii";
phys = <&serdes 4>;
microchip,bandwidth = <1000>;
};
port20: port@20 {
reg = <20>;
phy-handle = <&phy24>;
phy-mode = "qsgmii";
phys = <&serdes 5>;
microchip,bandwidth = <1000>;
};
port21: port@21 {
reg = <21>;
phy-handle = <&phy25>;
phy-mode = "qsgmii";
phys = <&serdes 5>;
microchip,bandwidth = <1000>;
};
port22: port@22 {
reg = <22>;
phy-handle = <&phy26>;
phy-mode = "qsgmii";
phys = <&serdes 5>;
microchip,bandwidth = <1000>;
};
port23: port@23 {
reg = <23>;
phy-handle = <&phy27>;
phy-mode = "qsgmii";
phys = <&serdes 5>;
microchip,bandwidth = <1000>;
};
port24: port@24 {
reg = <24>;
phys = <&serdes 6>;
phy-mode = "10gbase-r";
sfp = <&sfp0>;
managed = "in-band-status";
microchip,bandwidth = <10000>;
microchip,sd-sgpio = <24>;
};
port25: port@25 {
reg = <25>;
phys = <&serdes 7>;
phy-mode = "10gbase-r";
sfp = <&sfp1>;
managed = "in-band-status";
microchip,bandwidth = <10000>;
microchip,sd-sgpio = <28>;
};
port26: port@26 {
reg = <26>;
phys = <&serdes 8>;
phy-mode = "10gbase-r";
sfp = <&sfp2>;
managed = "in-band-status";
microchip,bandwidth = <10000>;
microchip,sd-sgpio = <32>;
};
port27: port@27 {
reg = <27>;
phys = <&serdes 9>;
phy-mode = "10gbase-r";
sfp = <&sfp3>;
managed = "in-band-status";
microchip,bandwidth = <10000>;
microchip,sd-sgpio = <36>;
};
port29: port@29 {
reg = <29>;
phy-handle = <&phy3>;
phy-mode = "rgmii-id";
microchip,bandwidth = <1000>;
};
};
};
&tmon {
pinctrl-0 = <&fan_pins>;
pinctrl-names = "default";
};
&usart0 {
pinctrl-0 = <&fc0_pins>;
pinctrl-names = "default";
status = "okay";
};
&usb {
pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
pinctrl-names = "default";
status = "okay";
};
@@ -195,6 +195,8 @@
los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
/* RS1 is internally tied to RS0 */
rate-select0-gpios = <&sgpio_out 6 3 GPIO_ACTIVE_HIGH>;
};
sfp1: sfp1 {
@@ -204,6 +206,8 @@
los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
/* RS1 is internally tied to RS0 */
rate-select0-gpios = <&sgpio_out 7 3 GPIO_ACTIVE_HIGH>;
};
sfp2: sfp2 {
@@ -213,6 +217,8 @@
los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
/* RS1 is internally tied to RS0 */
rate-select0-gpios = <&sgpio_out 8 3 GPIO_ACTIVE_HIGH>;
};
sfp3: sfp3 {
@@ -222,6 +228,8 @@
los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
/* RS1 is internally tied to RS0 */
rate-select0-gpios = <&sgpio_out 9 3 GPIO_ACTIVE_HIGH>;
};
};
@@ -1,3 +1,5 @@
DTS_DIR := $(DTS_DIR)/microchip
define Build/lan969x-fip
cat $(STAGING_DIR_IMAGE)/$1-fip.bin >> $@
endef
@@ -25,6 +27,7 @@ define Device/microchip_ev23x71a
DEVICE_VENDOR := Microchip
DEVICE_MODEL := EV23X71A
SOC := lan9696
DEVICE_DTS_DIR := $(DTS_DIR)
DEVICE_PACKAGES := kmod-i2c-mux-gpio
IMAGES += emmc-atf-gpt.gz emmc-gpt.img.gz
IMAGE/emmc-atf-gpt.gz := lan969x-gpt-emmc |\
@@ -0,0 +1,44 @@
From 229eeb0ad913c1bb2dd6027e5983d1e4c409abd0 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Mon, 2 Mar 2026 12:20:11 +0100
Subject: [PATCH] arm64: dts: microchip: add LAN969x clock header file
LAN969x uses hardware clock indexes, so document theses in a header to make
them humanly readable.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Reviewed-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Link: https://lore.kernel.org/r/20260302112153.464422-4-robert.marko@sartura.hr
Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
---
arch/arm64/boot/dts/microchip/clk-lan9691.h | 24 +++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 arch/arm64/boot/dts/microchip/clk-lan9691.h
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/clk-lan9691.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) */
+
+#ifndef _DTS_CLK_LAN9691_H
+#define _DTS_CLK_LAN9691_H
+
+#define GCK_ID_QSPI0 0
+#define GCK_ID_QSPI2 1
+#define GCK_ID_SDMMC0 2
+#define GCK_ID_SDMMC1 3
+#define GCK_ID_MCAN0 4
+#define GCK_ID_MCAN1 5
+#define GCK_ID_FLEXCOM0 6
+#define GCK_ID_FLEXCOM1 7
+#define GCK_ID_FLEXCOM2 8
+#define GCK_ID_FLEXCOM3 9
+#define GCK_ID_TIMER 10
+#define GCK_ID_USB_REFCLK 11
+
+/* Gate clocks */
+#define GCK_GATE_USB_DRD 12
+#define GCK_GATE_MCRAMC 13
+#define GCK_GATE_HMATRIX 14
+
+#endif
@@ -0,0 +1,508 @@
From 1effec9834710ec417861634c32208edcd2fcb2a Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Mon, 2 Mar 2026 12:20:12 +0100
Subject: [PATCH] arm64: dts: microchip: add LAN969x support
Add support for Microchip LAN969x switch SoC series by adding the SoC DTSI.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Reviewed-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Acked-by: Daniel Machon <daniel.machon@microchip.com>
Link: https://lore.kernel.org/r/20260302112153.464422-5-robert.marko@sartura.hr
Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
---
arch/arm64/boot/dts/microchip/lan9691.dtsi | 488 +++++++++++++++++++++
1 file changed, 488 insertions(+)
create mode 100644 arch/arm64/boot/dts/microchip/lan9691.dtsi
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
@@ -0,0 +1,488 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <dt-bindings/dma/at91.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mfd/at91-usart.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+
+#include "clk-lan9691.h"
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ model = "Microchip LAN969x";
+ compatible = "microchip,lan9691";
+ interrupt-parent = <&gic>;
+
+ clocks {
+ fx100_clk: fx100-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <320000000>;
+ };
+
+ cpu_clk: cpu-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000000>;
+ };
+
+ ddr_clk: ddr-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <600000000>;
+ };
+
+ fabric_clk: fabric-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <250000000>;
+ };
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <0x0 0x0>;
+ next-level-cache = <&l2_0>;
+ };
+
+ l2_0: l2-cache {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Secure Phys IRQ */
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, /* Non-secure Phys IRQ */
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, /* Virt IRQ */
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hyp IRQ */
+ };
+
+ axi: axi {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ usb: usb@300000 {
+ compatible = "microchip,lan9691-dwc3", "snps,dwc3";
+ reg = <0x300000 0x80000>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks GCK_GATE_USB_DRD>,
+ <&clks GCK_ID_USB_REFCLK>;
+ clock-names = "bus_early", "ref";
+ assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
+ assigned-clock-rates = <60000000>;
+ maximum-speed = "high-speed";
+ dr_mode = "host";
+ status = "disabled";
+ };
+
+ flx0: flexcom@e0040000 {
+ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+ reg = <0xe0040000 0x100>;
+ ranges = <0x0 0xe0040000 0x800>;
+ clocks = <&clks GCK_ID_FLEXCOM0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ usart0: serial@200 {
+ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+ reg = <0x200 0x200>;
+ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+ <&dma AT91_XDMAC_DT_PERID(2)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "usart";
+ atmel,fifo-size = <32>;
+ atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+ status = "disabled";
+ };
+
+ spi0: spi@400 {
+ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+ reg = <0x400 0x200>;
+ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+ <&dma AT91_XDMAC_DT_PERID(2)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "spi_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ atmel,fifo-size = <32>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@600 {
+ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+ reg = <0x600 0x200>;
+ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+ <&dma AT91_XDMAC_DT_PERID(2)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ flx1: flexcom@e0044000 {
+ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+ reg = <0xe0044000 0x100>;
+ ranges = <0x0 0xe0044000 0x800>;
+ clocks = <&clks GCK_ID_FLEXCOM1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ usart1: serial@200 {
+ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+ reg = <0x200 0x200>;
+ interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+ <&dma AT91_XDMAC_DT_PERID(2)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "usart";
+ atmel,fifo-size = <32>;
+ atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+ status = "disabled";
+ };
+
+ spi1: spi@400 {
+ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+ reg = <0x400 0x200>;
+ interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+ <&dma AT91_XDMAC_DT_PERID(2)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "spi_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ atmel,fifo-size = <32>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@600 {
+ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+ reg = <0x600 0x200>;
+ interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
+ <&dma AT91_XDMAC_DT_PERID(2)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ trng: rng@e0048000 {
+ compatible = "microchip,lan9691-trng", "atmel,at91sam9g45-trng";
+ reg = <0xe0048000 0x100>;
+ clocks = <&fabric_clk>;
+ status = "disabled";
+ };
+
+ aes: crypto@e004c000 {
+ compatible = "microchip,lan9691-aes", "atmel,at91sam9g46-aes";
+ reg = <0xe004c000 0x100>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(12)>,
+ <&dma AT91_XDMAC_DT_PERID(13)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "aes_clk";
+ status = "disabled";
+ };
+
+ flx2: flexcom@e0060000 {
+ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+ reg = <0xe0060000 0x100>;
+ ranges = <0x0 0xe0060000 0x800>;
+ clocks = <&clks GCK_ID_FLEXCOM2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ usart2: serial@200 {
+ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+ reg = <0x200 0x200>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+ <&dma AT91_XDMAC_DT_PERID(6)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "usart";
+ atmel,fifo-size = <32>;
+ atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+ status = "disabled";
+ };
+
+ spi2: spi@400 {
+ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+ reg = <0x400 0x200>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+ <&dma AT91_XDMAC_DT_PERID(6)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "spi_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ atmel,fifo-size = <32>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@600 {
+ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+ reg = <0x600 0x200>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
+ <&dma AT91_XDMAC_DT_PERID(6)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ flx3: flexcom@e0064000 {
+ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+ reg = <0xe0064000 0x100>;
+ ranges = <0x0 0xe0064000 0x800>;
+ clocks = <&clks GCK_ID_FLEXCOM3>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ usart3: serial@200 {
+ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
+ reg = <0x200 0x200>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+ <&dma AT91_XDMAC_DT_PERID(8)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "usart";
+ atmel,fifo-size = <32>;
+ atmel,usart-mode = <AT91_USART_MODE_SERIAL>;
+ status = "disabled";
+ };
+
+ spi3: spi@400 {
+ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
+ reg = <0x400 0x200>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+ <&dma AT91_XDMAC_DT_PERID(8)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ clock-names = "spi_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ atmel,fifo-size = <32>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@600 {
+ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
+ reg = <0x600 0x200>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
+ <&dma AT91_XDMAC_DT_PERID(8)>;
+ dma-names = "tx", "rx";
+ clocks = <&fabric_clk>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ dma: dma-controller@e0068000 {
+ compatible = "microchip,lan9691-dma", "microchip,sama7g5-dma";
+ reg = <0xe0068000 0x1000>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ dma-channels = <16>;
+ #dma-cells = <1>;
+ clocks = <&fabric_clk>;
+ clock-names = "dma_clk";
+ };
+
+ sha: crypto@e006c000 {
+ compatible = "microchip,lan9691-sha", "atmel,at91sam9g46-sha";
+ reg = <0xe006c000 0xec>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma AT91_XDMAC_DT_PERID(14)>;
+ dma-names = "tx";
+ clocks = <&fabric_clk>;
+ clock-names = "sha_clk";
+ status = "disabled";
+ };
+
+ timer: timer@e008c000 {
+ compatible = "snps,dw-apb-timer";
+ reg = <0xe008c000 0x400>;
+ clocks = <&fabric_clk>;
+ clock-names = "timer";
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ watchdog: watchdog@e0090000 {
+ compatible = "snps,dw-wdt";
+ reg = <0xe0090000 0x1000>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&fabric_clk>;
+ };
+
+ cpu_ctrl: syscon@e00c0000 {
+ compatible = "microchip,lan966x-cpu-syscon", "syscon";
+ reg = <0xe00c0000 0x350>;
+ };
+
+ switch: switch@e00c0000 {
+ compatible = "microchip,lan9691-switch";
+ reg = <0xe00c0000 0x0010000>,
+ <0xe2010000 0x1410000>;
+ reg-names = "cpu", "devices";
+ interrupt-names = "xtr", "fdma", "ptp";
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&reset 0>;
+ reset-names = "switch";
+ status = "disabled";
+ };
+
+ clks: clock-controller@e00c00b4 {
+ compatible = "microchip,lan9691-gck";
+ reg = <0xe00c00b4 0x30>, <0xe00c0308 0x4>;
+ #clock-cells = <1>;
+ clocks = <&cpu_clk>, <&ddr_clk>, <&fx100_clk>;
+ clock-names = "cpu", "ddr", "sys";
+ };
+
+ reset: reset-controller@e201000c {
+ compatible = "microchip,lan9691-switch-reset",
+ "microchip,lan966x-switch-reset";
+ reg = <0xe201000c 0x4>;
+ reg-names = "gcb";
+ #reset-cells = <1>;
+ cpu-syscon = <&cpu_ctrl>;
+ };
+
+ gpio: pinctrl@e20100d4 {
+ compatible = "microchip,lan9691-pinctrl";
+ reg = <0xe20100d4 0xd4>,
+ <0xe2010370 0xa8>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&gpio 0 0 66>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ #interrupt-cells = <2>;
+ };
+
+ mdio0: mdio@e20101a8 {
+ compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
+ reg = <0xe20101a8 0x24>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&fx100_clk>;
+ status = "disabled";
+ };
+
+ mdio1: mdio@e20101cc {
+ compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
+ reg = <0xe20101cc 0x24>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&fx100_clk>;
+ status = "disabled";
+ };
+
+ sgpio: gpio@e2010230 {
+ compatible = "microchip,lan9691-sgpio", "microchip,sparx5-sgpio";
+ reg = <0xe2010230 0x118>;
+ clocks = <&fx100_clk>;
+ resets = <&reset 0>;
+ reset-names = "switch";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ sgpio_in: gpio@0 {
+ compatible = "microchip,lan9691-sgpio-bank",
+ "microchip,sparx5-sgpio-bank";
+ reg = <0>;
+ gpio-controller;
+ #gpio-cells = <3>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ sgpio_out: gpio@1 {
+ compatible = "microchip,lan9691-sgpio-bank",
+ "microchip,sparx5-sgpio-bank";
+ reg = <1>;
+ gpio-controller;
+ #gpio-cells = <3>;
+ };
+ };
+
+ tmon: hwmon@e2020100 {
+ compatible = "microchip,lan9691-temp", "microchip,sparx5-temp";
+ reg = <0xe2020100 0xc>;
+ clocks = <&fx100_clk>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ serdes: serdes@e3410000 {
+ compatible = "microchip,lan9691-serdes";
+ reg = <0xe3410000 0x150000>;
+ #phy-cells = <1>;
+ clocks = <&fabric_clk>;
+ };
+
+ gic: interrupt-controller@e8c11000 {
+ compatible = "arm,gic-400";
+ reg = <0xe8c11000 0x1000>, /* Distributor GICD_ */
+ <0xe8c12000 0x2000>, /* CPU interface GICC_ */
+ <0xe8c14000 0x2000>, /* Virt interface control */
+ <0xe8c16000 0x2000>; /* Virt CPU interface */
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+};
@@ -0,0 +1,786 @@
From 711cca0f1cfef57018654b969da4041c2bab68d3 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Mon, 2 Mar 2026 12:20:14 +0100
Subject: [PATCH] arm64: dts: microchip: add EV23X71A board
Microchip EV23X71A is an LAN9696 based evaluation board.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Reviewed-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Acked-by: Daniel Machon <daniel.machon@microchip.com>
Tested-by: Daniel Machon <daniel.machon@microchip.com>
Link: https://lore.kernel.org/r/20260302112153.464422-7-robert.marko@sartura.hr
Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
---
arch/arm64/boot/dts/microchip/Makefile | 1 +
.../boot/dts/microchip/lan9696-ev23x71a.dts | 756 ++++++++++++++++++
2 files changed, 757 insertions(+)
create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
--- a/arch/arm64/boot/dts/microchip/Makefile
+++ b/arch/arm64/boot/dts/microchip/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_LAN969X) += lan9696-ev23x71a.dtb
dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include "lan9691.dtsi"
+
+/ {
+ model = "Microchip EV23X71A";
+ compatible = "microchip,ev23x71a", "microchip,lan9696", "microchip,lan9691";
+
+ aliases {
+ serial0 = &usart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpio 60 GPIO_ACTIVE_LOW>;
+ open-source;
+ priority = <200>;
+ };
+
+ i2c-mux {
+ compatible = "i2c-mux-gpio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-parent = <&i2c3>;
+ idle-state = <0x8>;
+ mux-gpios = <&sgpio_out 0 1 GPIO_ACTIVE_HIGH>,
+ <&sgpio_out 0 2 GPIO_ACTIVE_HIGH>,
+ <&sgpio_out 0 3 GPIO_ACTIVE_HIGH>;
+ settle-time-us = <100>;
+
+ i2c_sfp0: i2c@0 {
+ reg = <0x0>;
+ };
+
+ i2c_sfp1: i2c@1 {
+ reg = <0x1>;
+ };
+
+ i2c_sfp2: i2c@2 {
+ reg = <0x2>;
+ };
+
+ i2c_sfp3: i2c@3 {
+ reg = <0x3>;
+ };
+
+ i2c_poe: i2c@7 {
+ reg = <0x7>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led-status {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_STATUS;
+ gpios = <&gpio 61 GPIO_ACTIVE_LOW>;
+ };
+
+ led-sfp1-green {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <0>;
+ gpios = <&sgpio_out 6 0 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led-sfp1-yellow {
+ color = <LED_COLOR_ID_YELLOW>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <0>;
+ gpios = <&sgpio_out 6 1 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led-sfp2-green {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <1>;
+ gpios = <&sgpio_out 7 0 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led-sfp2-yellow {
+ color = <LED_COLOR_ID_YELLOW>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <1>;
+ gpios = <&sgpio_out 7 1 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led-sfp3-green {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <2>;
+ gpios = <&sgpio_out 8 0 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led-sfp3-yellow {
+ color = <LED_COLOR_ID_YELLOW>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <2>;
+ gpios = <&sgpio_out 8 1 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led-sfp4-green {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <3>;
+ gpios = <&sgpio_out 9 0 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led-sfp4-yellow {
+ color = <LED_COLOR_ID_YELLOW>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <3>;
+ gpios = <&sgpio_out 9 1 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+ };
+
+ mux-controller {
+ compatible = "gpio-mux";
+ #mux-control-cells = <0>;
+ mux-gpios = <&sgpio_out 1 2 GPIO_ACTIVE_LOW>,
+ <&sgpio_out 1 3 GPIO_ACTIVE_LOW>;
+ };
+
+ sfp0: sfp0 {
+ compatible = "sff,sfp";
+ i2c-bus = <&i2c_sfp0>;
+ tx-disable-gpios = <&sgpio_out 6 2 GPIO_ACTIVE_HIGH>;
+ los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
+ tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
+ };
+
+ sfp1: sfp1 {
+ compatible = "sff,sfp";
+ i2c-bus = <&i2c_sfp1>;
+ tx-disable-gpios = <&sgpio_out 7 2 GPIO_ACTIVE_HIGH>;
+ los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
+ tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
+ };
+
+ sfp2: sfp2 {
+ compatible = "sff,sfp";
+ i2c-bus = <&i2c_sfp2>;
+ tx-disable-gpios = <&sgpio_out 8 2 GPIO_ACTIVE_HIGH>;
+ los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
+ tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
+ };
+
+ sfp3: sfp3 {
+ compatible = "sff,sfp";
+ i2c-bus = <&i2c_sfp3>;
+ tx-disable-gpios = <&sgpio_out 9 2 GPIO_ACTIVE_HIGH>;
+ los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
+ tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&gpio {
+ emmc_sd_pins: emmc-sd-pins {
+ /* eMMC_SD - CMD, CLK, D0, D1, D2, D3, D4, D5, D6, D7, RSTN */
+ pins = "GPIO_14", "GPIO_15", "GPIO_16", "GPIO_17",
+ "GPIO_18", "GPIO_19", "GPIO_20", "GPIO_21",
+ "GPIO_22", "GPIO_23", "GPIO_24";
+ function = "emmc_sd";
+ };
+
+ fan_pins: fan-pins {
+ pins = "GPIO_25", "GPIO_26";
+ function = "fan";
+ };
+
+ fc0_pins: fc0-pins {
+ pins = "GPIO_3", "GPIO_4";
+ function = "fc";
+ };
+
+ fc2_pins: fc2-pins {
+ pins = "GPIO_64", "GPIO_65", "GPIO_66";
+ function = "fc";
+ };
+
+ fc3_pins: fc3-pins {
+ pins = "GPIO_55", "GPIO_56";
+ function = "fc";
+ };
+
+ mdio_irq_pins: mdio-irq-pins {
+ pins = "GPIO_11";
+ function = "miim_irq";
+ };
+
+ mdio_pins: mdio-pins {
+ pins = "GPIO_9", "GPIO_10";
+ function = "miim";
+ };
+
+ ptp_ext_pins: ptp-ext-pins {
+ pins = "GPIO_59";
+ function = "ptpsync_5";
+ };
+
+ ptp_out_pins: ptp-out-pins {
+ pins = "GPIO_58";
+ function = "ptpsync_4";
+ };
+
+ sgpio_pins: sgpio-pins {
+ /* SCK, D0, D1, LD */
+ pins = "GPIO_5", "GPIO_6", "GPIO_7", "GPIO_8";
+ function = "sgpio_a";
+ };
+
+ usb_over_pins: usb-over-pins {
+ pins = "GPIO_13";
+ function = "usb_over_detect";
+ };
+
+ usb_power_pins: usb-power-pins {
+ pins = "GPIO_1";
+ function = "usb_power";
+ };
+
+ usb_rst_pins: usb-rst-pins {
+ pins = "GPIO_12";
+ function = "usb2phy_rst";
+ };
+
+ usb_ulpi_pins: usb-ulpi-pins {
+ pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
+ "GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",
+ "GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
+ function = "usb_ulpi";
+ };
+};
+
+&flx0 {
+ atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+ status = "okay";
+};
+
+&flx2 {
+ atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_SPI>;
+ status = "okay";
+};
+
+&flx3 {
+ atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+ status = "okay";
+};
+
+&i2c3 {
+ pinctrl-0 = <&fc3_pins>;
+ pinctrl-names = "default";
+ i2c-analog-filter;
+ i2c-digital-filter;
+ i2c-digital-filter-width-ns = <35>;
+ i2c-sda-hold-time-ns = <1500>;
+ status = "okay";
+};
+
+&mdio0 {
+ pinctrl-0 = <&mdio_pins>, <&mdio_irq_pins>;
+ pinctrl-names = "default";
+ reset-gpios = <&gpio 62 GPIO_ACTIVE_LOW>;
+ status = "okay";
+
+ phy3: phy@3 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <3>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy4: phy@4 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <4>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy5: phy@5 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <5>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy6: phy@6 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <6>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy7: phy@7 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <7>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy8: phy@8 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <8>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy9: phy@9 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <9>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy10: phy@10 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <10>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy11: phy@11 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <11>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy12: phy@12 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <12>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy13: phy@13 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <13>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy14: phy@14 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <14>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy15: phy@15 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <15>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy16: phy@16 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <16>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy17: phy@17 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <17>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy18: phy@18 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <18>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy19: phy@19 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <19>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy20: phy@20 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <20>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy21: phy@21 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <21>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy22: phy@22 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <22>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy23: phy@23 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <23>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy24: phy@24 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <24>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy25: phy@25 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <25>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy26: phy@26 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <26>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+
+ phy27: phy@27 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <27>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ };
+};
+
+&serdes {
+ status = "okay";
+};
+
+&sgpio {
+ pinctrl-0 = <&sgpio_pins>;
+ pinctrl-names = "default";
+ microchip,sgpio-port-ranges = <0 1>, <6 9>;
+ status = "okay";
+
+ gpio@0 {
+ ngpios = <128>;
+ };
+ gpio@1 {
+ ngpios = <128>;
+ };
+};
+
+&spi2 {
+ pinctrl-0 = <&fc2_pins>;
+ pinctrl-names = "default";
+ cs-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&switch {
+ pinctrl-0 = <&ptp_out_pins>, <&ptp_ext_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ ethernet-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port0: port@0 {
+ reg = <0>;
+ phy-handle = <&phy4>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 0>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port1: port@1 {
+ reg = <1>;
+ phy-handle = <&phy5>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 0>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port2: port@2 {
+ reg = <2>;
+ phy-handle = <&phy6>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 0>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port3: port@3 {
+ reg = <3>;
+ phy-handle = <&phy7>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 0>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port4: port@4 {
+ reg = <4>;
+ phy-handle = <&phy8>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 1>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port5: port@5 {
+ reg = <5>;
+ phy-handle = <&phy9>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 1>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port6: port@6 {
+ reg = <6>;
+ phy-handle = <&phy10>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 1>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port7: port@7 {
+ reg = <7>;
+ phy-handle = <&phy11>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 1>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port8: port@8 {
+ reg = <8>;
+ phy-handle = <&phy12>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 2>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port9: port@9 {
+ reg = <9>;
+ phy-handle = <&phy13>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 2>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port10: port@10 {
+ reg = <10>;
+ phy-handle = <&phy14>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 2>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port11: port@11 {
+ reg = <11>;
+ phy-handle = <&phy15>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 2>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port12: port@12 {
+ reg = <12>;
+ phy-handle = <&phy16>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 3>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port13: port@13 {
+ reg = <13>;
+ phy-handle = <&phy17>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 3>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port14: port@14 {
+ reg = <14>;
+ phy-handle = <&phy18>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 3>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port15: port@15 {
+ reg = <15>;
+ phy-handle = <&phy19>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 3>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port16: port@16 {
+ reg = <16>;
+ phy-handle = <&phy20>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 4>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port17: port@17 {
+ reg = <17>;
+ phy-handle = <&phy21>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 4>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port18: port@18 {
+ reg = <18>;
+ phy-handle = <&phy22>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 4>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port19: port@19 {
+ reg = <19>;
+ phy-handle = <&phy23>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 4>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port20: port@20 {
+ reg = <20>;
+ phy-handle = <&phy24>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 5>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port21: port@21 {
+ reg = <21>;
+ phy-handle = <&phy25>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 5>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port22: port@22 {
+ reg = <22>;
+ phy-handle = <&phy26>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 5>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port23: port@23 {
+ reg = <23>;
+ phy-handle = <&phy27>;
+ phy-mode = "qsgmii";
+ phys = <&serdes 5>;
+ microchip,bandwidth = <1000>;
+ };
+
+ port24: port@24 {
+ reg = <24>;
+ phys = <&serdes 6>;
+ phy-mode = "10gbase-r";
+ sfp = <&sfp0>;
+ managed = "in-band-status";
+ microchip,bandwidth = <10000>;
+ microchip,sd-sgpio = <24>;
+ };
+
+ port25: port@25 {
+ reg = <25>;
+ phys = <&serdes 7>;
+ phy-mode = "10gbase-r";
+ sfp = <&sfp1>;
+ managed = "in-band-status";
+ microchip,bandwidth = <10000>;
+ microchip,sd-sgpio = <28>;
+ };
+
+ port26: port@26 {
+ reg = <26>;
+ phys = <&serdes 8>;
+ phy-mode = "10gbase-r";
+ sfp = <&sfp2>;
+ managed = "in-band-status";
+ microchip,bandwidth = <10000>;
+ microchip,sd-sgpio = <32>;
+ };
+
+ port27: port@27 {
+ reg = <27>;
+ phys = <&serdes 9>;
+ phy-mode = "10gbase-r";
+ sfp = <&sfp3>;
+ managed = "in-band-status";
+ microchip,bandwidth = <10000>;
+ microchip,sd-sgpio = <36>;
+ };
+
+ port29: port@29 {
+ reg = <29>;
+ phy-handle = <&phy3>;
+ phy-mode = "rgmii-id";
+ microchip,bandwidth = <1000>;
+ };
+ };
+};
+
+&tmon {
+ pinctrl-0 = <&fan_pins>;
+ pinctrl-names = "default";
+};
+
+&usart0 {
+ pinctrl-0 = <&fc0_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&usb {
+ pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+};
@@ -0,0 +1,51 @@
From a03ebe904b22e0c3f80498fe0dbfc66090552f67 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 25 Sep 2025 22:26:13 +0200
Subject: [PATCH 122/124] arm64: dts: microchip: lan969x: add QSPI nodes
Add the required DT nodes for both QSPI controllers.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
arch/arm64/boot/dts/microchip/lan9691.dtsi | 30 ++++++++++++++++++++++
1 file changed, 30 insertions(+)
--- a/arch/arm64/boot/dts/microchip/lan9691.dtsi
+++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
@@ -391,6 +391,36 @@
clock-names = "cpu", "ddr", "sys";
};
+ qspi0: spi@e0804000 {
+ compatible = "microchip,lan9691-qspi";
+ reg = <0xe0804000 0x00000100>,
+ <0x20000000 0x08000000>;
+ reg-names = "qspi_base", "qspi_mmap";
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&fabric_clk>, <&clks GCK_ID_QSPI0>;
+ clock-names = "pclk", "gclk";
+ assigned-clocks = <&clks GCK_ID_QSPI0>;
+ assigned-clock-rates = <100000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ qspi2: spi@e0834000 {
+ compatible = "microchip,lan9691-qspi";
+ reg = <0xe0834000 0x00000100>,
+ <0x30000000 0x04000000>;
+ reg-names = "qspi_base", "qspi_mmap";
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&fabric_clk>, <&clks GCK_ID_QSPI2>;
+ clock-names = "pclk", "gclk";
+ assigned-clocks = <&clks GCK_ID_QSPI2>;
+ assigned-clock-rates = <100000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
reset: reset-controller@e201000c {
compatible = "microchip,lan9691-switch-reset",
"microchip,lan966x-switch-reset";
@@ -0,0 +1,43 @@
From 6751906070b6708ede20d896be7d62e19be6ef63 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 25 Sep 2025 22:26:58 +0200
Subject: [PATCH 123/124] arm64: dts: microchip: lan969x: add SDMMC nodes
Add nodes for both SDMMC controllers.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
arch/arm64/boot/dts/microchip/lan9691.dtsi | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
--- a/arch/arm64/boot/dts/microchip/lan9691.dtsi
+++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
@@ -406,6 +406,28 @@
status = "disabled";
};
+ sdmmc0: mmc@e0830000 {
+ compatible = "microchip,lan9691-sdhci";
+ reg = <0xe0830000 0x00000300>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks GCK_ID_SDMMC0>, <&clks GCK_ID_SDMMC0>;
+ clock-names = "hclock", "multclk";
+ assigned-clocks = <&clks GCK_ID_SDMMC0>;
+ assigned-clock-rates = <100000000>;
+ status = "disabled";
+ };
+
+ sdmmc1: mmc@e0838000 {
+ compatible = "microchip,lan9691-sdhci";
+ reg = <0xe0838000 0x00000300>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks GCK_ID_SDMMC1>, <&clks GCK_ID_SDMMC1>;
+ clock-names = "hclock", "multclk";
+ assigned-clocks = <&clks GCK_ID_SDMMC1>;
+ assigned-clock-rates = <45000000>;
+ status = "disabled";
+ };
+
qspi2: spi@e0834000 {
compatible = "microchip,lan9691-qspi";
reg = <0xe0834000 0x00000100>,
@@ -0,0 +1,26 @@
From 477b5c9af4bb7c68bd4ec4807c94dac5a90dcd2f Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 24 Oct 2025 18:46:46 +0200
Subject: [PATCH 124/124] arm64: dts: microchip: lan969x: add OTP node
Add the required OTP on LAN969x.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
arch/arm64/boot/dts/microchip/lan9691.dtsi | 5 +++++
1 file changed, 5 insertions(+)
--- a/arch/arm64/boot/dts/microchip/lan9691.dtsi
+++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
@@ -100,6 +100,11 @@
status = "disabled";
};
+ otp: otp@e0021000 {
+ compatible = "microchip,lan9691-otpc";
+ reg = <0xe0021000 0x1000>;
+ };
+
flx0: flexcom@e0040000 {
compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
reg = <0xe0040000 0x100>;
@@ -0,0 +1,48 @@
From 78c8a6b2d6e98dbd384e93c68779582df04fc32a Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 25 Sep 2025 22:27:58 +0200
Subject: [PATCH] arm64: dts: microchip: ev23x71a: enable QSPI and eMMC
Add the required nodes for QSPI and eMMC support.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
.../boot/dts/microchip/lan9696-ev23x71a.dts | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
--- a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
+++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
@@ -463,6 +463,33 @@
};
};
+&qspi0 {
+ status = "okay";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <100000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spi-tx-bus-width = <1>;
+ spi-rx-bus-width = <4>;
+ m25p,fast-read;
+ };
+};
+
+&sdmmc0 {
+ pinctrl-0 = <&emmc_sd_pins>;
+ pinctrl-names = "default";
+ max-frequency = <100000000>;
+ bus-width = <8>;
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ non-removable;
+ disable-wp;
+ status = "okay";
+};
+
&serdes {
status = "okay";
};
@@ -0,0 +1,37 @@
From 44ed546c4231fbf9d0c92738c2c48c49f8249f48 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 24 Mar 2026 12:02:05 +0100
Subject: [PATCH 126/130] net: lan969x: correct RGMII port mapping index
Currently, the lan969x_port_dev_mapping does not check for RGMII ports
and just returns the physical port index.
However, this does not work for RGMII ports as they have dedicated DEVRGMII
register space with an dedicated instance per RGMII port.
So, check if requested port index is an RGMII port and return the correct
DEVRGMII index.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c | 9 +++++++++
1 file changed, 9 insertions(+)
--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
+++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
@@ -142,6 +142,15 @@ static u32 lan969x_get_dev_mode_bit(stru
static u32 lan969x_port_dev_mapping(struct sparx5 *sparx5, int port)
{
+ if (lan969x_port_is_rgmii(port)) {
+ switch (port) {
+ case 28:
+ return 0;
+ case 29:
+ return 1;
+ }
+ }
+
if (lan969x_port_is_5g(port)) {
switch (port) {
case 9:
@@ -0,0 +1,264 @@
From 372e0295a1dbf0ea4333183ac82b8620bef9c0dc Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 24 Mar 2026 12:19:03 +0100
Subject: [PATCH 127/130] net: sparx5: add MTU change framework
Port the MTU change framework from Microchip BSP kernel.
This only wires the generic SparX-5 and LAN969x code.
SparX-5 and LAN969x specific code to actually change the MTU will follow.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
.../net/ethernet/microchip/sparx5/Makefile | 2 +-
.../ethernet/microchip/sparx5/sparx5_fdma.c | 20 +++
.../ethernet/microchip/sparx5/sparx5_main.h | 8 ++
.../microchip/sparx5/sparx5_main_regs.h | 11 ++
.../ethernet/microchip/sparx5/sparx5_mtu.c | 130 ++++++++++++++++++
5 files changed, 170 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/microchip/sparx5/sparx5_mtu.c
--- a/drivers/net/ethernet/microchip/sparx5/Makefile
+++ b/drivers/net/ethernet/microchip/sparx5/Makefile
@@ -11,7 +11,7 @@ sparx5-switch-y := sparx5_main.o sparx5
sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o \
sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o \
- sparx5_psfp.o sparx5_mirror.o sparx5_regs.o
+ sparx5_psfp.o sparx5_mirror.o sparx5_regs.o sparx5_mtu.o
sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o
sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
@@ -462,6 +462,15 @@ int sparx5_fdma_start(struct sparx5 *spa
sparx5_fdma_rx_activate(sparx5, rx);
sparx5_fdma_tx_activate(sparx5, tx);
+ for (int i = 0; i < sparx5->data->consts->n_ports; i++) {
+ struct sparx5_port *port = sparx5->ports[i];
+
+ if (!port)
+ continue;
+ if (netif_queue_stopped(port->ndev))
+ netif_wake_queue(port->ndev);
+ }
+
return 0;
}
@@ -471,6 +480,7 @@ int sparx5_fdma_stop(struct sparx5 *spar
struct sparx5_tx *tx = &sparx5->tx;
u32 val;
+ napi_synchronize(&sparx5->rx.napi);
napi_disable(&rx->napi);
/* Stop the fdma and channel interrupts */
@@ -482,5 +492,15 @@ int sparx5_fdma_stop(struct sparx5 *spar
FDMA_PORT_CTRL_XTR_BUF_IS_EMPTY_GET(val) == 0,
500, 10000, 0, sparx5);
+ for (int i = 0; i < sparx5->data->consts->n_ports; i++) {
+ struct sparx5_port *port = sparx5->ports[i];
+
+ if (!port)
+ continue;
+ netif_stop_queue(port->ndev);
+ }
+
+ netif_napi_del(&sparx5->rx.napi);
+
return 0;
}
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
@@ -102,6 +102,7 @@ enum sparx5_feature {
#define PGID_TABLE_SIZE 3290
#define IFH_LEN 9 /* 36 bytes */
+#define IFH_LEN_BYTES (IFH_LEN * sizeof(u32))
#define NULL_VID 0
#define SPX5_MACT_PULL_DELAY (2 * HZ)
#define SPX5_STATS_CHECK_DELAY (1 * HZ)
@@ -188,6 +189,7 @@ struct sparx5_tx {
struct sparx5_tx_buf *dbs;
u64 packets;
u64 dropped;
+ u16 max_mtu;
};
struct sparx5_port_config {
@@ -348,6 +350,8 @@ struct sparx5_ops {
int (*fdma_poll)(struct napi_struct *napi, int weight);
int (*fdma_xmit)(struct sparx5 *sparx5, u32 *ifh, struct sk_buff *skb,
struct net_device *dev);
+ int (*fdma_resize)(struct sparx5 *sparx5);
+ u32 (*get_mtu)(struct sparx5 *sparx5);
};
struct sparx5_main_io_resource {
@@ -712,6 +716,10 @@ void sparx5_mirror_del(struct sparx5_mal
void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
struct flow_stats *fstats);
+/* sparx5_mtu.c */
+int sparx5_mtu_change(struct net_device *dev, int new_mtu);
+u32 sparx5_mtu_max(struct sparx5 *sparx5);
+
/* Clock period in picoseconds */
static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
{
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
@@ -8204,6 +8204,17 @@ extern const struct sparx5_regs *regs;
FIELD_GET(DEVRGMII_MAC_ENA_CFG_TX_ENA, x)
/* LAN969X ONLY */
+/* DEV1G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
+#define DEVRGMII_MAC_MAXLEN_CFG(t) \
+ __REG(TARGET_DEVRGMII, t, 2, 36, 0, 1, 36, 8, 0, 1, 4)
+
+#define DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN GENMASK(15, 0)
+#define DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
+ FIELD_PREP(DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN, x)
+#define DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
+ FIELD_GET(DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN, x)
+
+/* LAN969X ONLY */
/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG */
#define DEVRGMII_MAC_TAGS_CFG(t) \
__REG(TARGET_DEVRGMII, t, 2, 36, 0, 1, 36, 12, 0, 1, 4)
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mtu.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include "sparx5_main.h"
+
+#define SPX5_HW_MTU(mtu) ((mtu) + ETH_ALEN + IFH_LEN * 4 + ETH_FCS_LEN)
+
+/* Get the MTU for this port */
+static u32 sparx5_mtu_get(struct sparx5_port *port)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+ const struct sparx5_ops *ops = sparx5->data->ops;
+ u32 val;
+
+ /* We always set 2G5 or RGMII MTU, so there is no point in trying to
+ * read high-speed MAC MTU here
+ */
+ if (ops->is_port_rgmii(port->portno)) {
+ u32 idx = ops->get_port_dev_index(sparx5, port->portno);
+ val = spx5_rd(sparx5, DEVRGMII_MAC_MAXLEN_CFG(idx));
+ return DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_GET(val);
+ } else {
+ val = spx5_rd(sparx5, DEV2G5_MAC_MAXLEN_CFG(port->portno));
+ return DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_GET(val);
+ }
+}
+
+/* Set the MTU for this port. */
+static void sparx5_mtu_set(struct sparx5_port *port, u32 new_mtu)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+ const struct sparx5_ops *ops;
+ u32 idx, hw_mtu;
+
+ ops = sparx5->data->ops;
+ idx = ops->get_port_dev_index(sparx5, port->portno);
+ hw_mtu = SPX5_HW_MTU(new_mtu);
+
+ pr_debug("Setting MTU to: %u for portno (idx: %u): %u\n", new_mtu,
+ port->portno, idx);
+
+ /* All port modules have a 2g5 shadow device (and DEV2G5 is indexed
+ * by port number). Except the RGMII ports
+ */
+ if (!ops->is_port_rgmii(port->portno))
+ spx5_rmw(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
+ DEV2G5_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
+ DEV2G5_MAC_MAXLEN_CFG(port->portno));
+
+ if (ops->is_port_rgmii(port->portno))
+ spx5_rmw(DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
+ DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
+ DEVRGMII_MAC_MAXLEN_CFG(idx));
+ else if (ops->is_port_2g5(port->portno))
+ return; /* Already configured. */
+ else if (ops->is_port_5g(port->portno))
+ spx5_rmw(DEV5G_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
+ DEV5G_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
+ DEV5G_MAC_MAXLEN_CFG(idx));
+ else if (ops->is_port_10g(port->portno))
+ spx5_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
+ DEV10G_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
+ DEV10G_MAC_MAXLEN_CFG(idx));
+ else
+ spx5_rmw(DEV25G_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
+ DEV25G_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
+ DEV25G_MAC_MAXLEN_CFG(idx));
+}
+
+u32 sparx5_mtu_max(struct sparx5 *sparx5)
+{
+ u32 mtu_max = 0;
+
+ for (int i = 0; i < sparx5->data->consts->n_ports; i++) {
+ struct sparx5_port *port = sparx5->ports[i];
+ u32 mtu;
+
+ if (!port)
+ continue;
+
+ mtu = sparx5_mtu_get(port) + IFH_LEN_BYTES +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
+ VLAN_HLEN * 2 + XDP_PACKET_HEADROOM;
+
+ if (mtu > mtu_max)
+ mtu_max = mtu;
+ }
+
+ return mtu_max;
+}
+
+static int sparx5_mtu_fdma_set(struct sparx5 *sparx5)
+{
+ const struct sparx5_ops *ops = sparx5->data->ops;
+ u32 mtu_max = sparx5_mtu_max(sparx5);
+
+ /* We might not be using FDMA */
+ if (sparx5->fdma_irq <= 0)
+ return 0;
+
+ /* No need to restart FDMA if the MTU reflects the buffer size */
+ if (mtu_max == sparx5->tx.max_mtu)
+ return 0;
+
+ return ops->fdma_resize(sparx5);
+}
+
+int sparx5_mtu_change(struct net_device *dev, int new_mtu)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int err, orig_mtu = dev->mtu;
+
+ /* Write MTU to hardware */
+ sparx5_mtu_set(port, new_mtu);
+
+ err = sparx5_mtu_fdma_set(sparx5);
+ if (err) {
+ sparx5_mtu_set(port, orig_mtu);
+ return err;
+ }
+
+ /* Let the stack know */
+ WRITE_ONCE(dev->mtu, new_mtu);
+
+ return 0;
+}
@@ -0,0 +1,107 @@
From 466d22c9d3bdb2feda284c582d4f183879fc57ad Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 24 Mar 2026 12:26:51 +0100
Subject: [PATCH 128/130] net: sparx5: add MTU change
Add the required SparX-5 specific code to change the MTU.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
.../ethernet/microchip/sparx5/sparx5_fdma.c | 52 +++++++++++++++++++
.../ethernet/microchip/sparx5/sparx5_main.c | 2 +
.../ethernet/microchip/sparx5/sparx5_main.h | 1 +
3 files changed, 55 insertions(+)
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
@@ -278,6 +278,8 @@ static void sparx5_fdma_rx_init(struct s
struct fdma *fdma = &rx->fdma;
int idx;
+ sparx5->rx.page_order =
+ round_up(sparx5->tx.max_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
fdma->channel_id = channel;
fdma->n_dcbs = FDMA_DCB_MAX;
fdma->n_dbs = FDMA_RX_DCB_MAX_DBS;
@@ -403,6 +405,8 @@ int sparx5_fdma_init(struct sparx5 *spar
{
int err;
+ sparx5->tx.max_mtu = sparx5->data->ops->get_mtu(sparx5);
+
/* Reset FDMA state */
spx5_wr(FDMA_CTRL_NRESET_SET(0), sparx5, FDMA_CTRL);
spx5_wr(FDMA_CTRL_NRESET_SET(1), sparx5, FDMA_CTRL);
@@ -504,3 +508,51 @@ int sparx5_fdma_stop(struct sparx5 *spar
return 0;
}
+
+int sparx5_fdma_resize(struct sparx5 *sparx5)
+{
+ u32 old_mtu = sparx5->tx.max_mtu;
+ struct fdma tx_fdma_old = {0};
+ struct fdma rx_fdma_old = {0};
+ int err;
+
+ memcpy(&tx_fdma_old, &sparx5->tx.fdma, sizeof(struct fdma));
+ memcpy(&rx_fdma_old, &sparx5->rx.fdma, sizeof(struct fdma));
+
+ sparx5_fdma_stop(sparx5);
+
+ err = sparx5_fdma_init(sparx5);
+ if (err)
+ goto restore;
+
+ fdma_free_phys(&rx_fdma_old);
+ fdma_free_phys(&tx_fdma_old);
+
+ goto start;
+
+restore:
+
+ /* At this point, the FDMA engine is stopped and the stack is not
+ * calling us for xmit. Restore the old MTU and rx,tx buffers and
+ * restart the engine.
+ */
+
+ sparx5->tx.max_mtu = old_mtu;
+ memcpy(&sparx5->tx.fdma, &tx_fdma_old, sizeof(struct fdma));
+ memcpy(&sparx5->rx.fdma, &rx_fdma_old, sizeof(struct fdma));
+
+ /* Old buffers have to be re-initialized. */
+
+ fdma_dcbs_init(&sparx5->rx.fdma,
+ FDMA_DCB_INFO_DATAL(sparx5->rx.fdma.db_size),
+ FDMA_DCB_STATUS_INTR);
+
+ fdma_dcbs_init(&sparx5->tx.fdma,
+ FDMA_DCB_INFO_DATAL(sparx5->tx.fdma.db_size),
+ FDMA_DCB_STATUS_DONE);
+
+start:
+ sparx5_fdma_start(sparx5);
+
+ return err;
+}
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
@@ -1108,6 +1108,8 @@ static const struct sparx5_ops sparx5_op
.fdma_deinit = &sparx5_fdma_deinit,
.fdma_poll = &sparx5_fdma_napi_callback,
.fdma_xmit = &sparx5_fdma_xmit,
+ .fdma_resize = &sparx5_fdma_resize,
+ .get_mtu = &sparx5_mtu_max,
};
static const struct sparx5_match_data sparx5_desc = {
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
@@ -472,6 +472,7 @@ int sparx5_fdma_xmit(struct sparx5 *spar
irqreturn_t sparx5_fdma_handler(int irq, void *args);
void sparx5_fdma_reload(struct sparx5 *sparx5, struct fdma *fdma);
void sparx5_fdma_injection_mode(struct sparx5 *sparx5);
+int sparx5_fdma_resize(struct sparx5 *sparx5);
/* sparx5_mactable.c */
void sparx5_mact_pull_work(struct work_struct *work);
@@ -0,0 +1,126 @@
From b73c8d9fe87d3e35dc09faca85d5a5f9ee8e3f6c Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 24 Mar 2026 12:30:45 +0100
Subject: [PATCH 129/130] net: lan969x: add MTU change
Add the LAN969x specific code for MTU change.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
.../microchip/sparx5/lan969x/lan969x.c | 2 +
.../microchip/sparx5/lan969x/lan969x.h | 1 +
.../microchip/sparx5/lan969x/lan969x_fdma.c | 60 ++++++++++++++++++-
3 files changed, 61 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
+++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
@@ -354,6 +354,8 @@ static const struct sparx5_ops lan969x_o
.fdma_deinit = &lan969x_fdma_deinit,
.fdma_poll = &lan969x_fdma_napi_poll,
.fdma_xmit = &lan969x_fdma_xmit,
+ .fdma_resize = lan969x_fdma_resize,
+ .get_mtu = &sparx5_mtu_max,
};
const struct sparx5_match_data lan969x_desc = {
--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.h
+++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.h
@@ -78,5 +78,6 @@ int lan969x_fdma_deinit(struct sparx5 *s
int lan969x_fdma_napi_poll(struct napi_struct *napi, int weight);
int lan969x_fdma_xmit(struct sparx5 *sparx5, u32 *ifh, struct sk_buff *skb,
struct net_device *dev);
+int lan969x_fdma_resize(struct sparx5 *sparx5);
#endif
--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_fdma.c
+++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_fdma.c
@@ -154,7 +154,7 @@ static int lan969x_fdma_rx_alloc(struct
int err;
struct page_pool_params pp_params = {
- .order = 0,
+ .order = rx->page_order,
.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
.pool_size = fdma->n_dcbs * fdma->n_dbs,
.nid = NUMA_NO_NODE,
@@ -209,12 +209,14 @@ static void lan969x_fdma_rx_init(struct
{
struct fdma *fdma = &sparx5->rx.fdma;
+ sparx5->rx.page_order =
+ round_up(sparx5->tx.max_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
fdma->channel_id = FDMA_XTR_CHANNEL;
fdma->n_dcbs = FDMA_DCB_MAX;
fdma->n_dbs = 1;
fdma->priv = sparx5;
fdma->size = fdma_get_size(fdma);
- fdma->db_size = PAGE_SIZE;
+ fdma->db_size = PAGE_SIZE << sparx5->rx.page_order;
fdma->ops.dataptr_cb = &lan969x_fdma_rx_dataptr_cb;
fdma->ops.nextptr_cb = &fdma_nextptr_cb;
@@ -359,6 +361,8 @@ int lan969x_fdma_init(struct sparx5 *spa
struct sparx5_rx *rx = &sparx5->rx;
int err;
+ sparx5->tx.max_mtu = sparx5->data->ops->get_mtu(sparx5);
+
lan969x_fdma_rx_init(sparx5);
lan969x_fdma_tx_init(sparx5);
sparx5_fdma_injection_mode(sparx5);
@@ -404,3 +408,55 @@ int lan969x_fdma_deinit(struct sparx5 *s
return 0;
}
+
+int lan969x_fdma_resize(struct sparx5 *sparx5)
+{
+ struct page_pool *page_pool_old = sparx5->rx.page_pool;
+ u32 old_mtu = sparx5->tx.max_mtu;
+ struct fdma tx_fdma_old = {0};
+ struct fdma rx_fdma_old = {0};
+ int err;
+
+ memcpy(&tx_fdma_old, &sparx5->tx.fdma, sizeof(struct fdma));
+ memcpy(&rx_fdma_old, &sparx5->rx.fdma, sizeof(struct fdma));
+
+ sparx5_fdma_stop(sparx5);
+ lan969x_fdma_free_pages(&sparx5->rx);
+
+ err = lan969x_fdma_init(sparx5);
+ if (err)
+ goto restore;
+
+ fdma_free_coherent(sparx5->dev, &rx_fdma_old);
+ fdma_free_coherent(sparx5->dev, &tx_fdma_old);
+ page_pool_destroy(page_pool_old);
+
+ goto start;
+
+restore:
+
+ /* At this point, the FDMA engine is stopped and the stack is not
+ * calling us for xmit. Restore the old MTU and rx,tx buffers and
+ * restart the engine.
+ */
+
+ sparx5->tx.max_mtu = old_mtu;
+ sparx5->rx.page_pool = page_pool_old;
+ memcpy(&sparx5->tx.fdma, &tx_fdma_old, sizeof(struct fdma));
+ memcpy(&sparx5->rx.fdma, &rx_fdma_old, sizeof(struct fdma));
+
+ /* Old buffers have to be re-initialized. */
+
+ fdma_dcbs_init(&sparx5->rx.fdma,
+ FDMA_DCB_INFO_DATAL(sparx5->rx.fdma.db_size),
+ FDMA_DCB_STATUS_INTR);
+
+ fdma_dcbs_init(&sparx5->tx.fdma,
+ FDMA_DCB_INFO_DATAL(sparx5->tx.fdma.db_size),
+ FDMA_DCB_STATUS_DONE);
+
+start:
+ sparx5_fdma_start(sparx5);
+
+ return err;
+}
@@ -0,0 +1,33 @@
From aa92b8a004be460d68aa671c3f8e98373496b199 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 24 Mar 2026 12:32:39 +0100
Subject: [PATCH 130/130] net: sparx5: wire in MTU change
Now that both generic and chip specific MTU code is in place, add the
required netdev OP to trigger the MTU change.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
@@ -259,6 +259,7 @@ static const struct net_device_ops sparx
.ndo_setup_tc = sparx5_port_setup_tc,
.ndo_hwtstamp_get = sparx5_port_hwtstamp_get,
.ndo_hwtstamp_set = sparx5_port_hwtstamp_set,
+ .ndo_change_mtu = sparx5_mtu_change,
};
bool sparx5_netdevice_check(const struct net_device *dev)
@@ -279,6 +280,9 @@ struct net_device *sparx5_create_netdev(
ndev->hw_features |= NETIF_F_HW_TC;
ndev->features |= NETIF_F_HW_TC;
+ /* The MAC supports frame lengths of up to 14,000 bytes */
+ ndev->max_mtu = 14000;
+
SET_NETDEV_DEV(ndev, sparx5->dev);
spx5_port = netdev_priv(ndev);
spx5_port->ndev = ndev;
@@ -13,7 +13,7 @@
led-failsafe = &led_status_yellow;
led-running = &led_status_blue;
led-upgrade = &led_status_blue;
label-mac-device = &gmac0;
label-mac-device = &gmac1;
};
leds {
@@ -13,7 +13,7 @@
led-failsafe = &led_status_amber;
led-running = &led_status_white;
led-upgrade = &led_status_white;
label-mac-device = &gmac0;
label-mac-device = &gmac1;
};
leds {
@@ -61,7 +61,7 @@
&switch0 {
ethernet-ports {
SWITCH_PORT(16, 9, qsgmii)
SWITCH_PORT(17, 10, qsgmii)
SWITCH_PORT_SDS(16, 9, 2, qsgmii)
SWITCH_PORT_SDS(17, 10, 2, qsgmii)
};
};