Skip to content

Commit e194640

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 6773051 commit e194640

File tree

5 files changed

+450
-2
lines changed

5 files changed

+450
-2
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: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
/*
2+
* Copyright 2025 Planet Innovation
3+
* All rights reserved.
4+
*
5+
* Based on NXP RTL8211F driver structure and TI DP83867 specifications.
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*/
8+
9+
#include "fsl_phydp83867.h"
10+
11+
/*******************************************************************************
12+
* Definitions
13+
******************************************************************************/
14+
15+
/*! @brief Defines the PHY DP83867 vendor defined registers. */
16+
#define PHY_PHYSTS_REG 0x11U /*!< The PHY Status register. */
17+
18+
/*! @brief Defines the PHY DP83867 ID number. */
19+
#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 (upper 16 bits). */
20+
#define PHY_CONTROL_ID2 0xA231U /*!< The PHY ID2 (lower 16 bits). */
21+
#define PHY_FULL_ID 0x2000A231U /*!< Full PHY ID. */
22+
23+
/*! @brief Defines the mask flag in PHYSTS register. */
24+
#define PHY_PHYSTS_LINKSTATUS_MASK 0x0400U /*!< The PHY link status mask. */
25+
#define PHY_PHYSTS_LINKSPEED_MASK 0xC000U /*!< The PHY link speed mask. */
26+
#define PHY_PHYSTS_LINKDUPLEX_MASK 0x2000U /*!< The PHY link duplex mask. */
27+
#define PHY_PHYSTS_LINKSPEED_SHIFT 14U /*!< The link speed shift */
28+
29+
/*! @brief Link speed values from PHYSTS register. */
30+
#define PHY_PHYSTS_LINKSPEED_10M 0U /*!< 10M link speed. */
31+
#define PHY_PHYSTS_LINKSPEED_100M 1U /*!< 100M link speed. */
32+
#define PHY_PHYSTS_LINKSPEED_1000M 2U /*!< 1000M link speed. */
33+
34+
/*! @brief Defines the timeout macro. */
35+
#define PHY_READID_TIMEOUT_COUNT 1000U
36+
37+
/*******************************************************************************
38+
* Prototypes
39+
******************************************************************************/
40+
41+
/*******************************************************************************
42+
* Variables
43+
******************************************************************************/
44+
45+
const phy_operations_t phydp83867_ops = {.phyInit = PHY_DP83867_Init,
46+
.phyWrite = PHY_DP83867_Write,
47+
.phyRead = PHY_DP83867_Read,
48+
.getAutoNegoStatus = PHY_DP83867_GetAutoNegotiationStatus,
49+
.getLinkStatus = PHY_DP83867_GetLinkStatus,
50+
.getLinkSpeedDuplex = PHY_DP83867_GetLinkSpeedDuplex,
51+
.setLinkSpeedDuplex = PHY_DP83867_SetLinkSpeedDuplex,
52+
.enableLoopback = PHY_DP83867_EnableLoopback};
53+
54+
/*******************************************************************************
55+
* Code
56+
******************************************************************************/
57+
58+
status_t PHY_DP83867_Init(phy_handle_t *handle, const phy_config_t *config) {
59+
uint32_t counter = PHY_READID_TIMEOUT_COUNT;
60+
status_t result;
61+
uint32_t regValue = 0U;
62+
63+
64+
/* Init MDIO interface. */
65+
MDIO_Init(handle->mdioHandle);
66+
67+
/* Assign phy address. */
68+
handle->phyAddr = config->phyAddr;
69+
70+
71+
/* Check PHY ID. */
72+
do
73+
{
74+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
75+
if (result != kStatus_Success) {
76+
return result;
77+
}
78+
counter--;
79+
} while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
80+
81+
if (counter == 0U) {
82+
return kStatus_Fail;
83+
}
84+
85+
86+
/* Reset PHY. */
87+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
88+
if (result != kStatus_Success) {
89+
return result;
90+
}
91+
92+
93+
/* Wait for reset to complete */
94+
counter = PHY_READID_TIMEOUT_COUNT;
95+
do {
96+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
97+
if (result != kStatus_Success) {
98+
return result;
99+
}
100+
counter--;
101+
} while ((regValue & PHY_BCTL_RESET_MASK) && (counter != 0U));
102+
103+
if (counter == 0U) {
104+
return kStatus_Fail;
105+
}
106+
107+
108+
if (config->autoNeg) {
109+
/* Set the auto-negotiation. */
110+
result =
111+
MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
112+
PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | PHY_10BASETX_FULLDUPLEX_MASK |
113+
PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK);
114+
if (result == kStatus_Success) {
115+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_1000BASET_CONTROL_REG,
116+
PHY_1000BASET_FULLDUPLEX_MASK);
117+
if (result == kStatus_Success) {
118+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
119+
if (result == kStatus_Success) {
120+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
121+
(regValue | PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
122+
}
123+
}
124+
}
125+
} else {
126+
/* Disable isolate mode */
127+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
128+
if (result != kStatus_Success) {
129+
return result;
130+
}
131+
regValue &= ~PHY_BCTL_ISOLATE_MASK;
132+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
133+
if (result != kStatus_Success) {
134+
return result;
135+
}
136+
137+
/* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
138+
result = PHY_DP83867_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
139+
}
140+
141+
142+
return result;
143+
}
144+
145+
status_t PHY_DP83867_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
146+
return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
147+
}
148+
149+
status_t PHY_DP83867_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
150+
return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
151+
}
152+
153+
status_t PHY_DP83867_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
154+
assert(status);
155+
156+
status_t result;
157+
uint32_t regValue;
158+
159+
*status = false;
160+
161+
/* Check auto negotiation complete. */
162+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
163+
if (result == kStatus_Success) {
164+
if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
165+
*status = true;
166+
}
167+
}
168+
return result;
169+
}
170+
171+
status_t PHY_DP83867_GetLinkStatus(phy_handle_t *handle, bool *status) {
172+
assert(status);
173+
174+
status_t result;
175+
uint32_t regValue;
176+
177+
/* Read the PHY Status register. */
178+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
179+
if (result == kStatus_Success) {
180+
if ((PHY_PHYSTS_LINKSTATUS_MASK & regValue) != 0U) {
181+
/* Link up. */
182+
*status = true;
183+
} else {
184+
/* Link down. */
185+
*status = false;
186+
}
187+
}
188+
return result;
189+
}
190+
191+
status_t PHY_DP83867_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
192+
assert(!((speed == NULL) && (duplex == NULL)));
193+
194+
status_t result;
195+
uint32_t regValue;
196+
197+
/* Read the status register. */
198+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, &regValue);
199+
if (result == kStatus_Success) {
200+
if (speed != NULL) {
201+
switch ((regValue & PHY_PHYSTS_LINKSPEED_MASK) >> PHY_PHYSTS_LINKSPEED_SHIFT)
202+
{
203+
case PHY_PHYSTS_LINKSPEED_10M:
204+
*speed = kPHY_Speed10M;
205+
break;
206+
case PHY_PHYSTS_LINKSPEED_100M:
207+
*speed = kPHY_Speed100M;
208+
break;
209+
case PHY_PHYSTS_LINKSPEED_1000M:
210+
*speed = kPHY_Speed1000M;
211+
break;
212+
default:
213+
*speed = kPHY_Speed10M;
214+
break;
215+
}
216+
}
217+
218+
if (duplex != NULL) {
219+
if ((regValue & PHY_PHYSTS_LINKDUPLEX_MASK) != 0U) {
220+
*duplex = kPHY_FullDuplex;
221+
} else {
222+
*duplex = kPHY_HalfDuplex;
223+
}
224+
}
225+
}
226+
return result;
227+
}
228+
229+
status_t PHY_DP83867_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
230+
status_t result;
231+
uint32_t regValue;
232+
233+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
234+
if (result == kStatus_Success) {
235+
/* Disable the auto-negotiation and set according to user-defined configuration. */
236+
regValue &= ~PHY_BCTL_AUTONEG_MASK;
237+
if (speed == kPHY_Speed1000M) {
238+
regValue &= ~PHY_BCTL_SPEED0_MASK;
239+
regValue |= PHY_BCTL_SPEED1_MASK;
240+
} else if (speed == kPHY_Speed100M) {
241+
regValue |= PHY_BCTL_SPEED0_MASK;
242+
regValue &= ~PHY_BCTL_SPEED1_MASK;
243+
} else {
244+
regValue &= ~PHY_BCTL_SPEED0_MASK;
245+
regValue &= ~PHY_BCTL_SPEED1_MASK;
246+
}
247+
if (duplex == kPHY_FullDuplex) {
248+
regValue |= PHY_BCTL_DUPLEX_MASK;
249+
} else {
250+
regValue &= ~PHY_BCTL_DUPLEX_MASK;
251+
}
252+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
253+
}
254+
return result;
255+
}
256+
257+
status_t PHY_DP83867_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
258+
/* This PHY only supports local loopback. */
259+
assert(mode == kPHY_LocalLoop);
260+
261+
status_t result;
262+
uint32_t regValue;
263+
264+
/* Set the loop mode. */
265+
if (enable) {
266+
if (speed == kPHY_Speed1000M) {
267+
regValue = PHY_BCTL_SPEED1_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
268+
} else if (speed == kPHY_Speed100M) {
269+
regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
270+
} else {
271+
regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
272+
}
273+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
274+
} else {
275+
/* First read the current status in control register. */
276+
result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
277+
if (result == kStatus_Success) {
278+
regValue &= ~PHY_BCTL_LOOP_MASK;
279+
result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
280+
(regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
281+
}
282+
}
283+
return result;
284+
}

0 commit comments

Comments
 (0)