1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_phy.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /*! @brief Defines the timeout macro. */
16 #define PHY_TIMEOUT_COUNT 100000U
17
18 /*******************************************************************************
19 * Prototypes
20 ******************************************************************************/
21
22 /*******************************************************************************
23 * Variables
24 ******************************************************************************/
25
26 /*******************************************************************************
27 * Code
28 ******************************************************************************/
29
PHY_Init(ENET_Type * base,uint32_t phyAddr,uint32_t srcClock_Hz)30 status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
31 {
32 uint32_t bssReg;
33 uint32_t counter = PHY_TIMEOUT_COUNT;
34 uint32_t idReg = 0;
35 status_t result = kStatus_Success;
36 uint32_t instance = ENET_GetInstance(base);
37 uint32_t timeDelay;
38 uint32_t ctlReg = 0;
39
40 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
41 /* Set SMI first. */
42 CLOCK_EnableClock(s_enetClock[instance]);
43 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
44 ENET_SetSMI(base, srcClock_Hz, false);
45
46 /* Initialization after PHY stars to work. */
47 while ((idReg != PHY_CONTROL_ID1) && (counter != 0U))
48 {
49 (void)PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
50 counter--;
51 }
52
53 if (counter == 0U)
54 {
55 return kStatus_Fail;
56 }
57
58 /* Reset PHY. */
59 counter = PHY_TIMEOUT_COUNT;
60 result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
61 if (result == kStatus_Success)
62 {
63 #if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE)
64 uint32_t data = 0;
65 result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
66 if (result != kStatus_Success)
67 {
68 return result;
69 }
70 result = PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REFCLK_SELECT_MASK));
71 if (result != kStatus_Success)
72 {
73 return result;
74 }
75 #endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */
76
77 /* Set the negotiation. */
78 result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
79 (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
80 PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U));
81 if (result == kStatus_Success)
82 {
83 result =
84 PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
85 if (result == kStatus_Success)
86 {
87 /* Check auto negotiation complete. */
88 while (counter-- != 0U)
89 {
90 result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg);
91 if (result == kStatus_Success)
92 {
93 (void)PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
94 if (((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) && ((ctlReg & PHY_LINK_READY_MASK) != 0U))
95 {
96 /* Wait a moment for Phy status stable. */
97 for (timeDelay = 0; timeDelay < PHY_TIMEOUT_COUNT; timeDelay++)
98 {
99 __ASM("nop");
100 }
101 break;
102 }
103 }
104
105 if (counter == 0U)
106 {
107 return kStatus_PHY_AutoNegotiateFail;
108 }
109 }
110 }
111 }
112 }
113
114 return result;
115 }
116
PHY_Write(ENET_Type * base,uint32_t phyAddr,uint32_t phyReg,uint32_t data)117 status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
118 {
119 uint32_t counter;
120
121 /* Clear the SMI interrupt event. */
122 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
123
124 /* Starts a SMI write command. */
125 ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data);
126
127 /* Wait for SMI complete. */
128 for (counter = PHY_TIMEOUT_COUNT; counter > 0U; counter--)
129 {
130 if ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) != 0U)
131 {
132 break;
133 }
134 }
135
136 /* Check for timeout. */
137 if (counter == 0U)
138 {
139 return kStatus_PHY_SMIVisitTimeout;
140 }
141
142 /* Clear MII interrupt event. */
143 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
144
145 return kStatus_Success;
146 }
147
PHY_Read(ENET_Type * base,uint32_t phyAddr,uint32_t phyReg,uint32_t * dataPtr)148 status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
149 {
150 assert(dataPtr);
151
152 uint32_t counter;
153
154 /* Clear the MII interrupt event. */
155 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
156
157 /* Starts a SMI read command operation. */
158 ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame);
159
160 /* Wait for MII complete. */
161 for (counter = PHY_TIMEOUT_COUNT; counter > 0U; counter--)
162 {
163 if ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) != 0U)
164 {
165 break;
166 }
167 }
168
169 /* Check for timeout. */
170 if (counter == 0U)
171 {
172 return kStatus_PHY_SMIVisitTimeout;
173 }
174
175 /* Get data from MII register. */
176 *dataPtr = ENET_ReadSMIData(base);
177
178 /* Clear MII interrupt event. */
179 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
180
181 return kStatus_Success;
182 }
183
PHY_EnableLoopback(ENET_Type * base,uint32_t phyAddr,phy_loop_t mode,phy_speed_t speed,bool enable)184 status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, phy_speed_t speed, bool enable)
185 {
186 status_t result;
187 uint32_t data = 0;
188
189 /* Set the loop mode. */
190 if (enable)
191 {
192 if (mode == kPHY_LocalLoop)
193 {
194 if (speed == kPHY_Speed100M)
195 {
196 data = PHY_BCTL_SPEED_100M_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
197 }
198 else
199 {
200 data = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
201 }
202 return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, data);
203 }
204 else
205 {
206 /* First read the current status in control register. */
207 result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
208 if (result == kStatus_Success)
209 {
210 return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REMOTELOOP_MASK));
211 }
212 }
213 }
214 else
215 {
216 /* Disable the loop mode. */
217 if (mode == kPHY_LocalLoop)
218 {
219 /* First read the current status in control register. */
220 result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data);
221 if (result == kStatus_Success)
222 {
223 data &= ~PHY_BCTL_LOOP_MASK;
224 return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data | PHY_BCTL_RESTART_AUTONEG_MASK));
225 }
226 }
227 else
228 {
229 /* First read the current status in control one register. */
230 result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
231 if (result == kStatus_Success)
232 {
233 return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data & ~PHY_CTL2_REMOTELOOP_MASK));
234 }
235 }
236 }
237 return result;
238 }
239
PHY_GetLinkStatus(ENET_Type * base,uint32_t phyAddr,bool * status)240 status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status)
241 {
242 assert(status);
243
244 status_t result = kStatus_Success;
245 uint32_t data;
246
247 /* Read the basic status register. */
248 result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &data);
249 if (result == kStatus_Success)
250 {
251 if ((PHY_BSTATUS_LINKSTATUS_MASK & data) == 0U)
252 {
253 /* link down. */
254 *status = false;
255 }
256 else
257 {
258 /* link up. */
259 *status = true;
260 }
261 }
262 return result;
263 }
264
PHY_GetLinkSpeedDuplex(ENET_Type * base,uint32_t phyAddr,phy_speed_t * speed,phy_duplex_t * duplex)265 status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex)
266 {
267 assert(duplex);
268
269 status_t result = kStatus_Success;
270 uint32_t data, ctlReg;
271
272 /* Read the control two register. */
273 result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
274 if (result == kStatus_Success)
275 {
276 data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
277 if ((PHY_CTL1_10FULLDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
278 {
279 /* Full duplex. */
280 *duplex = kPHY_FullDuplex;
281 }
282 else
283 {
284 /* Half duplex. */
285 *duplex = kPHY_HalfDuplex;
286 }
287
288 data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
289 if ((PHY_CTL1_100HALFDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
290 {
291 /* 100M speed. */
292 *speed = kPHY_Speed100M;
293 }
294 else
295 { /* 10M speed. */
296 *speed = kPHY_Speed10M;
297 }
298 }
299
300 return result;
301 }
302