Skip to content

Commit f230fca

Browse files
committed
mimxrt/eth: Add DP83867 PHY driver support.
Adds new PHY driver for TI DP83867 Gigabit Ethernet PHY. Signed-off-by: Andrew Leech <[email protected]>
1 parent 2762fe6 commit f230fca

File tree

5 files changed

+471
-1
lines changed

5 files changed

+471
-1
lines changed

ports/mimxrt/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ SRC_ETH_C += \
113113
$(MCUX_SDK_DIR)/drivers/enet/fsl_enet.c \
114114
hal/phy/device/phydp83825/fsl_phydp83825.c \
115115
hal/phy/device/phydp83848/fsl_phydp83848.c \
116+
hal/phy/device/phydp83867/fsl_phydp83867.c \
116117
hal/phy/device/phyksz8081/fsl_phyksz8081.c \
117118
hal/phy/device/phylan8720/fsl_phylan8720.c \
118119
hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.c \

ports/mimxrt/eth.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "hal/phy/device/phyksz8081/fsl_phyksz8081.h"
4545
#include "hal/phy/device/phydp83825/fsl_phydp83825.h"
4646
#include "hal/phy/device/phydp83848/fsl_phydp83848.h"
47+
#include "hal/phy/device/phydp83867/fsl_phydp83867.h"
4748
#include "hal/phy/device/phylan8720/fsl_phylan8720.h"
4849
#include "hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h"
4950

@@ -422,7 +423,7 @@ void eth_init_1(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int ph
422423
uint32_t source_clock = eth_clock_init(eth_id, phy_clock);
423424

424425
const machine_pin_obj_t *reset_pin = NULL;
425-
#if defined(pin_ENET_1_INT)
426+
#if defined(pin_ENET_1_RESET)
426427
reset_pin = pin_ENET_1_RESET;
427428
#endif
428429
const machine_pin_obj_t *int_pin = NULL;
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2025 Andrew Leech
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "fsl_phydp83867.h"
28+
29+
/*******************************************************************************
30+
* Definitions
31+
******************************************************************************/
32+
33+
/*! @brief Defines the PHY DP83867 vendor defined registers. */
34+
#define PHY_PHYSTS_REG 0x11U /*!< The PHY Status register. */
35+
36+
/*! @brief Defines the PHY DP83867 ID number. */
37+
#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 (upper 16 bits). */
38+
#define PHY_CONTROL_ID2 0xA231U /*!< The PHY ID2 (lower 16 bits). */
39+
#define PHY_FULL_ID 0x2000A231U /*!< Full PHY ID. */
40+
41+
/*! @brief Defines the mask flag in PHYSTS register. */
42+
#define PHY_PHYSTS_LINKSTATUS_MASK 0x0400U /*!< The PHY link status mask. */
43+
#define PHY_PHYSTS_LINKSPEED_MASK 0xC000U /*!< The PHY link speed mask. */
44+
#define PHY_PHYSTS_LINKDUPLEX_MASK 0x2000U /*!< The PHY link duplex mask. */
45+
#define PHY_PHYSTS_LINKSPEED_SHIFT 14U /*!< The link speed shift */
46+
47+
/*! @brief Link speed values from PHYSTS register. */
48+
#define PHY_PHYSTS_LINKSPEED_10M 0U /*!< 10M link speed. */
49+
#define PHY_PHYSTS_LINKSPEED_100M 1U /*!< 100M link speed. */
50+
#define PHY_PHYSTS_LINKSPEED_1000M 2U /*!< 1000M link speed. */
51+
52+
/*! @brief Defines the timeout macro. */
53+
#define PHY_READID_TIMEOUT_COUNT 1000U
54+
55+
/*******************************************************************************
56+
* Prototypes
57+
******************************************************************************/
58+
59+
/*******************************************************************************
60+
* Variables
61+
******************************************************************************/
62+
63+
const phy_operations_t phydp83867_ops = {.phyInit = PHY_DP83867_Init,
64+
.phyWrite = PHY_DP83867_Write,
65+
.phyRead = PHY_DP83867_Read,
66+
.getAutoNegoStatus = PHY_DP83867_GetAutoNegotiationStatus,
67+
.getLinkStatus = PHY_DP83867_GetLinkStatus,
68+
.getLinkSpeedDuplex = PHY_DP83867_GetLinkSpeedDuplex,
69+
.setLinkSpeedDuplex = PHY_DP83867_SetLinkSpeedDuplex,
70+
.enableLoopback = PHY_DP83867_EnableLoopback};
71+
72+
/*******************************************************************************
73+
* Code
74+
******************************************************************************/
75+
76+
status_t PHY_DP83867_Init(phy_handle_t *handle, const phy_config_t *config) {
77+
uint32_t counter = PHY_READID_TIMEOUT_COUNT;
78+
status_t result;
79+
uint32_t regValue = 0U;
80+
81+
82+
/* Init MDIO interface. */
83+
MDIO_Init(handle->mdioHandle);
84+
85+
/* Assign phy address. */
86+
handle->phyAddr = config->phyAddr;
87+
88+
89+
/* Check PHY ID. */
90+
do
91+
{
92+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
93+
if (result != kStatus_Success) {
94+
return result;
95+
}
96+
counter--;
97+
} while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
98+
99+
if (counter == 0U) {
100+
return kStatus_Fail;
101+
}
102+
103+
104+
/* Reset PHY. */
105+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
106+
if (result != kStatus_Success) {
107+
return result;
108+
}
109+
110+
111+
/* Wait for reset to complete */
112+
counter = PHY_READID_TIMEOUT_COUNT;
113+
do {
114+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
115+
if (result != kStatus_Success) {
116+
return result;
117+
}
118+
counter--;
119+
} while ((regValue & PHY_BCTL_RESET_MASK) && (counter != 0U));
120+
121+
if (counter == 0U) {
122+
return kStatus_Fail;
123+
}
124+
125+
126+
if (config->autoNeg) {
127+
/* Set the auto-negotiation. */
128+
result =
129+
MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
130+
PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | PHY_10BASETX_FULLDUPLEX_MASK |
131+
PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK);
132+
if (result == kStatus_Success) {
133+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_1000BASET_CONTROL_REG,
134+
PHY_1000BASET_FULLDUPLEX_MASK);
135+
if (result == kStatus_Success) {
136+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
137+
if (result == kStatus_Success) {
138+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
139+
(regValue | PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
140+
}
141+
}
142+
}
143+
} else {
144+
/* Disable isolate mode */
145+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
146+
if (result != kStatus_Success) {
147+
return result;
148+
}
149+
regValue &= ~PHY_BCTL_ISOLATE_MASK;
150+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
151+
if (result != kStatus_Success) {
152+
return result;
153+
}
154+
155+
/* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
156+
result = PHY_DP83867_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
157+
}
158+
159+
160+
return result;
161+
}
162+
163+
status_t PHY_DP83867_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
164+
return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
165+
}
166+
167+
status_t PHY_DP83867_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
168+
return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
169+
}
170+
171+
status_t PHY_DP83867_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
172+
assert(status);
173+
174+
status_t result;
175+
uint32_t regValue;
176+
177+
*status = false;
178+
179+
/* Check auto negotiation complete. */
180+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
181+
if (result == kStatus_Success) {
182+
if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
183+
*status = true;
184+
}
185+
}
186+
return result;
187+
}
188+
189+
status_t PHY_DP83867_GetLinkStatus(phy_handle_t *handle, bool *status) {
190+
assert(status);
191+
192+
status_t result;
193+
uint32_t regValue;
194+
195+
/* Read the PHY Status register. */
196+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
197+
if (result == kStatus_Success) {
198+
if ((PHY_PHYSTS_LINKSTATUS_MASK & regValue) != 0U) {
199+
/* Link up. */
200+
*status = true;
201+
} else {
202+
/* Link down. */
203+
*status = false;
204+
}
205+
}
206+
return result;
207+
}
208+
209+
status_t PHY_DP83867_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
210+
assert(!((speed == NULL) && (duplex == NULL)));
211+
212+
status_t result;
213+
uint32_t regValue;
214+
215+
/* Read the status register. */
216+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
217+
if (result == kStatus_Success) {
218+
if (speed != NULL) {
219+
switch ((regValue & PHY_PHYSTS_LINKSPEED_MASK) >> PHY_PHYSTS_LINKSPEED_SHIFT)
220+
{
221+
case PHY_PHYSTS_LINKSPEED_10M:
222+
*speed = kPHY_Speed10M;
223+
break;
224+
case PHY_PHYSTS_LINKSPEED_100M:
225+
*speed = kPHY_Speed100M;
226+
break;
227+
case PHY_PHYSTS_LINKSPEED_1000M:
228+
*speed = kPHY_Speed1000M;
229+
break;
230+
default:
231+
*speed = kPHY_Speed10M;
232+
break;
233+
}
234+
}
235+
236+
if (duplex != NULL) {
237+
if ((regValue & PHY_PHYSTS_LINKDUPLEX_MASK) != 0U) {
238+
*duplex = kPHY_FullDuplex;
239+
} else {
240+
*duplex = kPHY_HalfDuplex;
241+
}
242+
}
243+
}
244+
return result;
245+
}
246+
247+
status_t PHY_DP83867_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
248+
status_t result;
249+
uint32_t regValue;
250+
251+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
252+
if (result == kStatus_Success) {
253+
/* Disable the auto-negotiation and set according to user-defined configuration. */
254+
regValue &= ~PHY_BCTL_AUTONEG_MASK;
255+
if (speed == kPHY_Speed1000M) {
256+
regValue &= ~PHY_BCTL_SPEED0_MASK;
257+
regValue |= PHY_BCTL_SPEED1_MASK;
258+
} else if (speed == kPHY_Speed100M) {
259+
regValue |= PHY_BCTL_SPEED0_MASK;
260+
regValue &= ~PHY_BCTL_SPEED1_MASK;
261+
} else {
262+
regValue &= ~PHY_BCTL_SPEED0_MASK;
263+
regValue &= ~PHY_BCTL_SPEED1_MASK;
264+
}
265+
if (duplex == kPHY_FullDuplex) {
266+
regValue |= PHY_BCTL_DUPLEX_MASK;
267+
} else {
268+
regValue &= ~PHY_BCTL_DUPLEX_MASK;
269+
}
270+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
271+
}
272+
return result;
273+
}
274+
275+
status_t PHY_DP83867_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
276+
/* This PHY only supports local loopback. */
277+
assert(mode == kPHY_LocalLoop);
278+
279+
status_t result;
280+
uint32_t regValue;
281+
282+
/* Set the loop mode. */
283+
if (enable) {
284+
if (speed == kPHY_Speed1000M) {
285+
regValue = PHY_BCTL_SPEED1_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
286+
} else if (speed == kPHY_Speed100M) {
287+
regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
288+
} else {
289+
regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
290+
}
291+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
292+
} else {
293+
/* First read the current status in control register. */
294+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
295+
if (result == kStatus_Success) {
296+
regValue &= ~PHY_BCTL_LOOP_MASK;
297+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
298+
(regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
299+
}
300+
}
301+
return result;
302+
}

0 commit comments

Comments
 (0)