Skip to content

Commit 45d958f

Browse files
drivers: mdio: Add Xilinx Axi Ethernet Lite driver
This commit adds support for the Xilinx AXI Ethernet Lite device, also known as the emaclite. The emaclite is a light-weight 10/100 MII Ethernet device. It can optionally be configured to include an MDIO. The MMIO interface is controlled via MMIO registers and requires the software to busy-wait until completion. Signed-off-by: Eric Ackermann <[email protected]>
1 parent e0fcfa1 commit 45d958f

File tree

5 files changed

+227
-0
lines changed

5 files changed

+227
-0
lines changed

drivers/mdio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_RENESAS_RA mdio_renesas_ra.c)
2020
zephyr_library_sources_ifdef(CONFIG_MDIO_LAN865X mdio_lan865x.c)
2121
zephyr_library_sources_ifdef(CONFIG_MDIO_SENSRY_SY1XX mdio_sy1xx.c)
2222
zephyr_library_sources_ifdef(CONFIG_MDIO_XILINX_AXI_ENET mdio_xilinx_axienet.c)
23+
zephyr_library_sources_ifdef(CONFIG_MDIO_XILINX_AXI_ETHERNET_LITE mdio_xilinx_axi_ethernet_lite.c)
2324
zephyr_library_sources_ifdef(CONFIG_MDIO_INTEL_IGC mdio_intel_igc.c)

drivers/mdio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ source "drivers/mdio/Kconfig.renesas_ra"
4141
source "drivers/mdio/Kconfig.lan865x"
4242
source "drivers/mdio/Kconfig.sy1xx"
4343
source "drivers/mdio/Kconfig.xilinx_axienet"
44+
source "drivers/mdio/Kconfig.xilinx_axi_ethernet_lite"
4445
source "drivers/mdio/Kconfig.intel_igc"
4546

4647
config MDIO_INIT_PRIORITY
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright 2025 CISPA Helmholtz Center for Information Security
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config MDIO_XILINX_AXI_ETHERNET_LITE
5+
bool "Xilinx AXI Ethernet Lite MDIO driver"
6+
default y
7+
depends on DT_HAS_XLNX_XPS_ETHERNETLITE_3_00_A_MDIO_ENABLED
8+
depends on NETWORKING
9+
help
10+
Enable Xilinx AXI Ethernet Lite MDIO bus driver.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Xilinx AXI Ethernet Lite MDIO
3+
*
4+
* Copyright(c) 202%, CISPA Helmholtz Center for Information Security
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
#include <zephyr/logging/log.h>
8+
LOG_MODULE_REGISTER(eth_xilinx_axi_ethernet_lite_mdio, CONFIG_ETHERNET_LOG_LEVEL);
9+
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/drivers/mdio.h>
12+
13+
#include <stdint.h>
14+
15+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MAX_PHY_DEVICES 32
16+
17+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_OFFSET 0x07e4
18+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_WRITE_DATA_REG_OFFSET 0x07e8
19+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_READ_DATA_REG_OFFSET 0x07ec
20+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_OFFSET 0x07f0
21+
22+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_ENABLE_MASK BIT(3)
23+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_BUSY_MASK BIT(0)
24+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_DISABLE_MASK 0
25+
26+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_OP_READ BIT(10)
27+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_OP_WRITE 0
28+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_SHIFT_REGADDR 0
29+
#define MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_SHIFT_PHYADDR 5
30+
31+
struct mdio_xilinx_axi_ethernet_lite_data {
32+
bool bus_enabled;
33+
};
34+
35+
struct mdio_xilinx_axi_ethernet_lite_config {
36+
void *reg;
37+
};
38+
39+
static int xilinx_axi_ethernet_lite_mdio_probe(const struct device *dev)
40+
{
41+
return 0; /* Nothing to do*/
42+
}
43+
44+
static inline uint32_t
45+
mdio_xilinx_axi_ethernet_lite_read_reg(const struct mdio_xilinx_axi_ethernet_lite_config *config,
46+
mem_addr_t reg)
47+
{
48+
return sys_read32((mem_addr_t)config->reg + reg);
49+
}
50+
51+
static inline void
52+
mdio_xilinx_axi_ethernet_lite_write_reg(const struct mdio_xilinx_axi_ethernet_lite_config *config,
53+
mem_addr_t reg, uint32_t value)
54+
{
55+
sys_write32(value, (mem_addr_t)config->reg + reg);
56+
}
57+
58+
static inline int
59+
mdio_xilinx_axi_ethernet_lite_check_busy(const struct mdio_xilinx_axi_ethernet_lite_config *config)
60+
{
61+
uint32_t mdio_control_reg_val = mdio_xilinx_axi_ethernet_lite_read_reg(
62+
config, MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_OFFSET);
63+
64+
return mdio_control_reg_val & MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_BUSY_MASK
65+
? -EBUSY
66+
: 0;
67+
}
68+
69+
static inline void
70+
mdio_xilinx_axi_ethernet_lite_set_addr(const struct mdio_xilinx_axi_ethernet_lite_config *config,
71+
uint8_t prtad, uint8_t regad, bool is_read)
72+
{
73+
uint32_t mdio_addr_val = is_read ? MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_OP_READ
74+
: MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_OP_WRITE;
75+
76+
/* range check done below in read/write functions */
77+
mdio_addr_val |= (uint32_t)regad
78+
<< MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_SHIFT_REGADDR;
79+
mdio_addr_val |= (uint32_t)prtad
80+
<< MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_SHIFT_PHYADDR;
81+
82+
mdio_xilinx_axi_ethernet_lite_write_reg(
83+
config, MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_ADDRESS_REG_OFFSET, mdio_addr_val);
84+
}
85+
86+
static inline void xilinx_axi_ethernet_lite_mdio_bus_enable(const struct device *dev)
87+
{
88+
const struct mdio_xilinx_axi_ethernet_lite_config *config = dev->config;
89+
struct mdio_xilinx_axi_ethernet_lite_data *data = dev->data;
90+
91+
mdio_xilinx_axi_ethernet_lite_write_reg(
92+
config, MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_OFFSET,
93+
MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_ENABLE_MASK);
94+
95+
data->bus_enabled = true;
96+
}
97+
98+
static inline void xilinx_axi_ethernet_lite_mdio_complete_transaction(
99+
const struct mdio_xilinx_axi_ethernet_lite_config *config)
100+
{
101+
/* start transaction - everything set up */
102+
mdio_xilinx_axi_ethernet_lite_write_reg(
103+
config, MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_OFFSET,
104+
MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_ENABLE_MASK |
105+
MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_BUSY_MASK);
106+
107+
while (mdio_xilinx_axi_ethernet_lite_check_busy(config)) {
108+
/* no need to block the CPU */
109+
k_msleep(1);
110+
}
111+
/* busy went low - transaction complete */
112+
}
113+
114+
static int xilinx_axi_ethernet_lite_mdio_read(const struct device *dev, uint8_t prtad,
115+
uint8_t regad, uint16_t *value)
116+
{
117+
const struct mdio_xilinx_axi_ethernet_lite_config *config = dev->config;
118+
struct mdio_xilinx_axi_ethernet_lite_data *data = dev->data;
119+
120+
if (prtad >= MDIO_XILINX_AXI_ETHERNET_LITE_MAX_PHY_DEVICES) {
121+
LOG_ERR("Requested read port address %" PRIu8 " not supported - max %d", prtad,
122+
MDIO_XILINX_AXI_ETHERNET_LITE_MAX_PHY_DEVICES);
123+
return -ENOSYS;
124+
}
125+
if (!data->bus_enabled) {
126+
LOG_ERR("MDIO bus not enabled!");
127+
return -ENOSYS;
128+
}
129+
if (mdio_xilinx_axi_ethernet_lite_check_busy(config)) {
130+
LOG_ERR("MDIO bus busy!");
131+
return -ENOSYS;
132+
}
133+
134+
mdio_xilinx_axi_ethernet_lite_set_addr(config, prtad, regad, true);
135+
136+
xilinx_axi_ethernet_lite_mdio_complete_transaction(config);
137+
138+
*value = (uint16_t)mdio_xilinx_axi_ethernet_lite_read_reg(
139+
config, MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_READ_DATA_REG_OFFSET);
140+
141+
return 0;
142+
}
143+
144+
static int xilinx_axi_ethernet_lite_mdio_write(const struct device *dev, uint8_t prtad,
145+
uint8_t regad, uint16_t value)
146+
{
147+
const struct mdio_xilinx_axi_ethernet_lite_config *config = dev->config;
148+
struct mdio_xilinx_axi_ethernet_lite_data *data = dev->data;
149+
150+
if (prtad >= MDIO_XILINX_AXI_ETHERNET_LITE_MAX_PHY_DEVICES) {
151+
LOG_ERR("Requested write port address %" PRIu8 " not supported - max %d", prtad,
152+
MDIO_XILINX_AXI_ETHERNET_LITE_MAX_PHY_DEVICES);
153+
return -ENOSYS;
154+
}
155+
if (!data->bus_enabled) {
156+
LOG_ERR("MDIO bus not enabled!");
157+
return -ENOSYS;
158+
}
159+
if (mdio_xilinx_axi_ethernet_lite_check_busy(config)) {
160+
LOG_ERR("MDIO bus busy!");
161+
return -ENOSYS;
162+
}
163+
mdio_xilinx_axi_ethernet_lite_set_addr(config, prtad, regad, false);
164+
mdio_xilinx_axi_ethernet_lite_write_reg(
165+
config, MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_WRITE_DATA_REG_OFFSET, value);
166+
167+
xilinx_axi_ethernet_lite_mdio_complete_transaction(config);
168+
169+
return 0;
170+
}
171+
172+
static inline void xilinx_axi_ethernet_lite_mdio_bus_disable(const struct device *dev)
173+
{
174+
const struct mdio_xilinx_axi_ethernet_lite_config *config = dev->config;
175+
struct mdio_xilinx_axi_ethernet_lite_data *data = dev->data;
176+
177+
mdio_xilinx_axi_ethernet_lite_write_reg(
178+
config, MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_OFFSET,
179+
MDIO_XILINX_AXI_ETHERNET_LITE_MDIO_CONTROL_REG_MDIO_DISABLE_MASK);
180+
181+
data->bus_enabled = false;
182+
}
183+
184+
static const struct mdio_driver_api mdio_xilinx_axi_ethernet_lite_api = {
185+
/* clause 45 not supported */
186+
.bus_enable = xilinx_axi_ethernet_lite_mdio_bus_enable,
187+
.bus_disable = xilinx_axi_ethernet_lite_mdio_bus_disable,
188+
.read = xilinx_axi_ethernet_lite_mdio_read,
189+
.write = xilinx_axi_ethernet_lite_mdio_write};
190+
191+
#define XILINX_AXI_ETHERNET_LITE_MDIO_INIT(inst) \
192+
\
193+
static const struct mdio_xilinx_axi_ethernet_lite_config \
194+
mdio_xilinx_axi_ethernet_lite_config##inst = { \
195+
.reg = (void *)(uintptr_t)DT_REG_ADDR(DT_INST_PARENT(inst)), \
196+
}; \
197+
static struct mdio_xilinx_axi_ethernet_lite_data \
198+
mdio_xilinx_axi_ethernet_lite_data##inst = {0}; \
199+
DEVICE_DT_INST_DEFINE(inst, xilinx_axi_ethernet_lite_mdio_probe, NULL, \
200+
&mdio_xilinx_axi_ethernet_lite_data##inst, \
201+
&mdio_xilinx_axi_ethernet_lite_config##inst, POST_KERNEL, \
202+
CONFIG_MDIO_INIT_PRIORITY, &mdio_xilinx_axi_ethernet_lite_api);
203+
204+
#define DT_DRV_COMPAT xlnx_xps_ethernetlite_3_00_a_mdio
205+
DT_INST_FOREACH_STATUS_OKAY(XILINX_AXI_ETHERNET_LITE_MDIO_INIT)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 CISPA Helmholtz Center for Information Security
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Common fields for MDIO controllers
5+
6+
include: mdio-controller.yaml
7+
8+
compatible: xlnx,xps-ethernetlite-3.00.a-mdio
9+
10+
description: MDIO interface of Xilinx AXI Ethernet Lite.

0 commit comments

Comments
 (0)