1 /*
2 * Copyright (c) 2016, 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 500000U
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 reg;
33 uint32_t idReg = 0;
34 uint32_t delay = PHY_TIMEOUT_COUNT;
35 uint32_t instance = ENET_GetInstance(base);
36 bool status = false;
37
38 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
39 /* Set SMI first. */
40 (void)CLOCK_EnableClock(s_enetClock[instance]);
41 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
42
43 #if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)
44 ENET_SetSMI(base, srcClock_Hz, false);
45 #elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
46 ENET_SetSMI(base);
47 #endif
48 /* Initialization after PHY stars to work. */
49 while ((idReg != PHY_CONTROL_ID1) && (delay != 0U))
50 {
51 (void)PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
52 delay--;
53 }
54
55 if (delay == 0U)
56 {
57 return kStatus_Fail;
58 }
59 delay = PHY_TIMEOUT_COUNT;
60
61 /* Reset PHY and wait until completion. */
62 (void)PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
63 do
64 {
65 (void)PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, ®);
66 } while ((delay-- != 0U) && ((reg & PHY_BCTL_RESET_MASK) != 0U));
67
68 if (delay == 0U)
69 {
70 return kStatus_Fail;
71 }
72
73 /* Set the ability. */
74 (void)PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, (PHY_ALL_CAPABLE_MASK | 0x1U));
75
76 /* Start Auto negotiation and wait until auto negotiation completion */
77 (void)PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
78 delay = PHY_TIMEOUT_COUNT;
79 do
80 {
81 (void)PHY_Read(base, phyAddr, PHY_SEPCIAL_CONTROL_REG, ®);
82 delay--;
83 } while ((delay != 0U) && ((reg & PHY_SPECIALCTL_AUTONEGDONE_MASK) == 0U));
84
85 if (delay == 0U)
86 {
87 return kStatus_PHY_AutoNegotiateFail;
88 }
89
90 /* Waiting a moment for phy stable. */
91 for (delay = 0U; delay < PHY_TIMEOUT_COUNT; delay++)
92 {
93 __ASM("nop");
94 (void)PHY_GetLinkStatus(base, phyAddr, &status);
95 if (status)
96 {
97 break;
98 }
99 }
100
101 return kStatus_Success;
102 }
103
PHY_Write(ENET_Type * base,uint32_t phyAddr,uint32_t phyReg,uint32_t data)104 status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
105 {
106 #if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)
107 uint32_t counter;
108
109 /* Clear the SMI interrupt event. */
110 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
111
112 /* Starts a SMI write command. */
113 ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data);
114
115 /* Wait for SMI complete. */
116 for (counter = PHY_TIMEOUT_COUNT; counter > 0U; counter--)
117 {
118 if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
119 {
120 break;
121 }
122 }
123
124 /* Check for timeout. */
125 if (counter == 0U)
126 {
127 return kStatus_PHY_SMIVisitTimeout;
128 }
129
130 /* Clear MII interrupt event. */
131 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
132
133 #elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
134 ENET_StartSMIWrite(base, phyAddr, phyReg, data);
135 while (ENET_IsSMIBusy(base))
136 {
137 }
138 #endif
139 return kStatus_Success;
140 }
141
PHY_Read(ENET_Type * base,uint32_t phyAddr,uint32_t phyReg,uint32_t * dataPtr)142 status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
143 {
144 #if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)
145 assert(dataPtr);
146
147 uint32_t counter;
148
149 /* Clear the MII interrupt event. */
150 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
151
152 /* Starts a SMI read command operation. */
153 ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame);
154
155 /* Wait for MII complete. */
156 for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
157 {
158 if ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) != 0U)
159 {
160 break;
161 }
162 }
163
164 /* Check for timeout. */
165 if (counter == 0U)
166 {
167 return kStatus_PHY_SMIVisitTimeout;
168 }
169
170 /* Get data from MII register. */
171 *dataPtr = ENET_ReadSMIData(base);
172
173 /* Clear MII interrupt event. */
174 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
175 #elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
176 ENET_StartSMIRead(base, phyAddr, phyReg);
177 while (ENET_IsSMIBusy(base))
178 {
179 }
180 *dataPtr = ENET_ReadSMIData(base);
181 #endif
182 return kStatus_Success;
183 }
184
PHY_GetLinkStatus(ENET_Type * base,uint32_t phyAddr,bool * status)185 status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status)
186 {
187 uint32_t reg;
188 status_t result = kStatus_Success;
189
190 /* Read the basic status register. */
191 result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, ®);
192 if (result == kStatus_Success)
193 {
194 if ((reg & PHY_BSTATUS_LINKSTATUS_MASK) != 0U)
195 {
196 /* link up. */
197 *status = true;
198 }
199 else
200 {
201 *status = false;
202 }
203 }
204 return result;
205 }
206
PHY_GetLinkSpeedDuplex(ENET_Type * base,uint32_t phyAddr,phy_speed_t * speed,phy_duplex_t * duplex)207 status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex)
208 {
209 assert(duplex);
210 assert(speed);
211
212 uint32_t reg;
213 status_t result = kStatus_Success;
214
215 /* Read the control two register. */
216 result = PHY_Read(base, phyAddr, PHY_SEPCIAL_CONTROL_REG, ®);
217 if (result == kStatus_Success)
218 {
219 if ((reg & PHY_SPECIALCTL_DUPLEX_MASK) != 0U)
220 {
221 /* Full duplex. */
222 *duplex = kPHY_FullDuplex;
223 }
224 else
225 {
226 /* Half duplex. */
227 *duplex = kPHY_HalfDuplex;
228 }
229
230 if ((reg & PHY_SPECIALCTL_100SPEED_MASK) != 0U)
231 {
232 /* 100M speed. */
233 *speed = kPHY_Speed100M;
234 }
235 else
236 { /* 10M speed. */
237 *speed = kPHY_Speed10M;
238 }
239 }
240 return result;
241 }
242