Skip to content

Commit cae6044

Browse files
committed
drivers: mdio: Add Intel i226 MDIO driver support
Intel i226 MAC supports MDIO C22 and MDIO C45. Standard PHY registers are accessible through MDIO C22, whereas PMAPMD and PCS are accssible through MDIO C45. Signed-off-by: Vijayakannan Ayyathurai <vijayakannan.ayyathurai@intel.com>
1 parent b48e787 commit cae6044

File tree

5 files changed

+207
-0
lines changed

5 files changed

+207
-0
lines changed

drivers/mdio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ 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_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.intel_igc"
4445

4546
config MDIO_INIT_PRIORITY
4647
int "Init priority"

drivers/mdio/Kconfig.intel_igc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
menuconfig MDIO_INTEL_IGC
5+
bool "Intel IGC MDIO driver"
6+
default y
7+
depends on DT_HAS_INTEL_IGC_MDIO_ENABLED
8+
help
9+
Enable Intel IGC MDIO driver.
10+
11+
if MDIO_INTEL_IGC
12+
13+
config MDIO_INTEL_BUSY_CHECK_TIMEOUT
14+
int "MDIO_INTEL_IGC busy wait timeout"
15+
default 10000
16+
help
17+
This timeout in microseconds, specifies the duration to wait for the
18+
completion of an MDIO read or write cycle.
19+
20+
endif # MDIO_INTEL_IGC

drivers/mdio/mdio_intel_igc.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* Copyright (c) 2025 Intel Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT intel_igc_mdio
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/net/mdio.h>
11+
#include <zephyr/drivers/mdio.h>
12+
#include <zephyr/drivers/pcie/pcie.h>
13+
14+
#include <zephyr/logging/log.h>
15+
LOG_MODULE_REGISTER(intel_igc_mdio, CONFIG_MDIO_LOG_LEVEL);
16+
17+
#define INTEL_IGC_MDIC_OFFSET 0x00020
18+
#define INTEL_IGC_MDIC_DATA_MASK GENMASK(15, 0)
19+
#define INTEL_IGC_MDIC_REG_MASK GENMASK(20, 16)
20+
#define INTEL_IGC_MDIC_PHY_MASK GENMASK(25, 21)
21+
#define INTEL_IGC_MDIC_OP_MASK GENMASK(27, 26)
22+
#define INTEL_IGC_MDIC_READY BIT(28)
23+
#define INTEL_IGC_MMDCTRL 0xD
24+
#define INTEL_IGC_MMDCTRL_ACTYPE_MASK GENMASK(15, 14)
25+
#define INTEL_IGC_MMDCTRL_DEVAD_MASK GENMASK(4, 0)
26+
#define INTEL_IGC_MMDDATA 0xE
27+
#define INTEL_IGC_DEFAULT_DEVNUM 0
28+
29+
struct intel_igc_mdio_cfg {
30+
const struct device *const platform;
31+
};
32+
33+
struct intel_igc_mdio_data {
34+
struct k_mutex mutex;
35+
};
36+
37+
static int intel_igc_mdio(const struct device *dev, uint32_t command)
38+
{
39+
const struct intel_igc_mdio_cfg *cfg = dev->config;
40+
struct intel_igc_mdio_data *data = dev->data;
41+
mm_reg_t mdic;
42+
int ret;
43+
44+
mdic = DEVICE_MMIO_GET(cfg->platform) + INTEL_IGC_MDIC_OFFSET;
45+
46+
k_mutex_lock(&data->mutex, K_FOREVER);
47+
sys_write32(command, mdic);
48+
/* Wait for the read or write transaction to complete */
49+
if (!WAIT_FOR((sys_read32(mdic) & INTEL_IGC_MDIC_READY),
50+
CONFIG_MDIO_INTEL_BUSY_CHECK_TIMEOUT, k_usleep(1))) {
51+
LOG_ERR("MDIC operation timed out");
52+
k_mutex_unlock(&data->mutex);
53+
return -ETIMEDOUT;
54+
}
55+
ret = sys_read32(mdic);
56+
k_mutex_unlock(&data->mutex);
57+
58+
return ret;
59+
}
60+
61+
static int intel_igc_mdio_read(const struct device *dev, uint8_t prtad, uint8_t regad,
62+
uint16_t *user_data)
63+
{
64+
int ret = 0;
65+
uint32_t command = FIELD_PREP(INTEL_IGC_MDIC_PHY_MASK, prtad) |
66+
FIELD_PREP(INTEL_IGC_MDIC_REG_MASK, regad) |
67+
FIELD_PREP(INTEL_IGC_MDIC_OP_MASK, MDIO_OP_C22_READ);
68+
69+
ret = intel_igc_mdio(dev, command);
70+
if (ret < 0) {
71+
return ret;
72+
}
73+
74+
*user_data = FIELD_GET(INTEL_IGC_MDIC_DATA_MASK, ret);
75+
76+
return 0;
77+
}
78+
79+
static int intel_igc_mdio_write(const struct device *dev, uint8_t prtad, uint8_t regad,
80+
uint16_t user_data)
81+
{
82+
int ret;
83+
84+
uint32_t command = FIELD_PREP(INTEL_IGC_MDIC_PHY_MASK, prtad) |
85+
FIELD_PREP(INTEL_IGC_MDIC_REG_MASK, regad) |
86+
FIELD_PREP(INTEL_IGC_MDIC_OP_MASK, MDIO_OP_C22_WRITE) |
87+
FIELD_PREP(INTEL_IGC_MDIC_DATA_MASK, user_data);
88+
89+
ret = intel_igc_mdio(dev, command);
90+
91+
return ret < 0 ? ret : 0;
92+
}
93+
94+
static int intel_igc_mdio_pre_handle_c45(const struct device *dev, uint8_t prtad, uint8_t devnum,
95+
uint16_t regad)
96+
{
97+
int ret;
98+
99+
/* Set device number using MMDCTRL */
100+
ret = intel_igc_mdio_write(dev, prtad, INTEL_IGC_MMDCTRL,
101+
(uint16_t)(FIELD_PREP(INTEL_IGC_MMDCTRL_DEVAD_MASK, devnum)));
102+
if (ret < 0) {
103+
return ret;
104+
}
105+
106+
/* Set register address using MMDDATA */
107+
ret = intel_igc_mdio_write(dev, prtad, INTEL_IGC_MMDDATA, regad);
108+
if (ret < 0) {
109+
return ret;
110+
}
111+
112+
/* Set device number and access type as data using MMDCTRL */
113+
return intel_igc_mdio_write(dev, prtad, INTEL_IGC_MMDCTRL,
114+
(uint16_t)(FIELD_PREP(INTEL_IGC_MMDCTRL_ACTYPE_MASK, 1) |
115+
FIELD_PREP(INTEL_IGC_MMDCTRL_DEVAD_MASK, devnum)));
116+
}
117+
118+
static int intel_igc_mdio_post_handle_c45(const struct device *dev, uint8_t prtad)
119+
{
120+
/* Restore default device number using MMDCTRL */
121+
return intel_igc_mdio_write(dev, prtad, INTEL_IGC_MMDCTRL, INTEL_IGC_DEFAULT_DEVNUM);
122+
}
123+
124+
static int intel_igc_mdio_read_c45(const struct device *dev, uint8_t prtad, uint8_t devnum,
125+
uint16_t regad, uint16_t *user_data)
126+
{
127+
int ret = intel_igc_mdio_pre_handle_c45(dev, prtad, devnum, regad);
128+
129+
if (ret < 0) {
130+
return ret;
131+
}
132+
133+
/* Read user data using MMDDATA */
134+
ret = intel_igc_mdio_read(dev, prtad, INTEL_IGC_MMDDATA, user_data);
135+
if (ret < 0) {
136+
return ret;
137+
}
138+
139+
return intel_igc_mdio_post_handle_c45(dev, prtad);
140+
}
141+
142+
static int intel_igc_mdio_write_c45(const struct device *dev, uint8_t prtad, uint8_t devnum,
143+
uint16_t regad, uint16_t user_data)
144+
{
145+
int ret = intel_igc_mdio_pre_handle_c45(dev, prtad, devnum, regad);
146+
147+
if (ret < 0) {
148+
return ret;
149+
}
150+
151+
/* Write the user_data using MMDDATA */
152+
ret = intel_igc_mdio_write(dev, prtad, INTEL_IGC_MMDDATA, user_data);
153+
if (ret < 0) {
154+
return ret;
155+
}
156+
157+
return intel_igc_mdio_post_handle_c45(dev, prtad);
158+
}
159+
160+
static DEVICE_API(mdio, mdio_api) = {
161+
.read = intel_igc_mdio_read,
162+
.write = intel_igc_mdio_write,
163+
.read_c45 = intel_igc_mdio_read_c45,
164+
.write_c45 = intel_igc_mdio_write_c45,
165+
};
166+
167+
#define INTEL_IGC_MDIO_INIT(n) \
168+
static struct intel_igc_mdio_data mdio_data_##n = { \
169+
.mutex = Z_MUTEX_INITIALIZER(mdio_data_##n.mutex), \
170+
}; \
171+
static struct intel_igc_mdio_cfg mdio_cfg_##n = { \
172+
.platform = DEVICE_DT_GET(DT_INST_PARENT(n)), \
173+
}; \
174+
DEVICE_DT_INST_DEFINE(n, NULL, NULL, &mdio_data_##n, &mdio_cfg_##n, POST_KERNEL, \
175+
CONFIG_MDIO_INIT_PRIORITY, &mdio_api);
176+
177+
DT_INST_FOREACH_STATUS_OKAY(INTEL_IGC_MDIO_INIT)

dts/bindings/mdio/intel,igc-mdio.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Intel IGC MDIO device.
5+
6+
compatible: "intel,igc-mdio"
7+
8+
include: [mdio-controller.yaml, base.yaml]

0 commit comments

Comments
 (0)