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