1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * o Redistributions of source code must retain the above copyright notice, this list
9 * of conditions and the following disclaimer.
10 *
11 * o Redistributions in binary form must reproduce the above copyright notice, this
12 * list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * o Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "fsl_phy.h"
32
33 /*******************************************************************************
34 * Definitions
35 ******************************************************************************/
36
37 /*! @brief Defines the timeout macro. */
38 #define PHY_TIMEOUT_COUNT 0xFFFFFU
39
40 /*******************************************************************************
41 * Prototypes
42 ******************************************************************************/
43
44 /*!
45 * @brief Get the ENET instance from peripheral base address.
46 *
47 * @param base ENET peripheral base address.
48 * @return ENET instance.
49 */
50 extern uint32_t ENET_GetInstance(ENET_Type *base);
51
52 /*******************************************************************************
53 * Variables
54 ******************************************************************************/
55
56 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
57 /*! @brief Pointers to enet clocks for each instance. */
58 extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
59 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
60
61 /*******************************************************************************
62 * Code
63 ******************************************************************************/
64
PHY_Init(ENET_Type * base,uint32_t phyAddr,uint32_t srcClock_Hz)65 status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
66 {
67 uint32_t bssReg;
68 uint32_t counter = PHY_TIMEOUT_COUNT;
69 uint32_t idReg = 0;
70 status_t result = kStatus_Success;
71 uint32_t instance = ENET_GetInstance(base);
72
73 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
74 /* Set SMI first. */
75 CLOCK_EnableClock(s_enetClock[instance]);
76 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
77 ENET_SetSMI(base, srcClock_Hz, false);
78
79 /* Initialization after PHY stars to work. */
80 while ((idReg != PHY_CONTROL_ID1) && (counter != 0))
81 {
82 PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
83 counter --;
84 }
85
86 if (!counter)
87 {
88 return kStatus_Fail;
89 }
90
91 /* Reset PHY. */
92 counter = PHY_TIMEOUT_COUNT;
93 result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
94 if (result == kStatus_Success)
95 {
96 /* Set the negotiation. */
97 result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
98 (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
99 PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U));
100 if (result == kStatus_Success)
101 {
102 result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG,
103 (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
104 if (result == kStatus_Success)
105 {
106 /* Check auto negotiation complete. */
107 while (counter --)
108 {
109 result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg);
110 if ( result == kStatus_Success)
111 {
112 if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0)
113 {
114 break;
115 }
116 }
117
118 if (!counter)
119 {
120 return kStatus_PHY_AutoNegotiateFail;
121 }
122 }
123 }
124 }
125 }
126
127 return result;
128 }
129
PHY_Write(ENET_Type * base,uint32_t phyAddr,uint32_t phyReg,uint32_t data)130 status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
131 {
132 uint32_t counter;
133
134 /* Clear the SMI interrupt event. */
135 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
136
137 /* Starts a SMI write command. */
138 ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data);
139
140 /* Wait for SMI complete. */
141 for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
142 {
143 if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
144 {
145 break;
146 }
147 }
148
149 /* Check for timeout. */
150 if (!counter)
151 {
152 return kStatus_PHY_SMIVisitTimeout;
153 }
154
155 /* Clear MII interrupt event. */
156 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
157
158 return kStatus_Success;
159 }
160
PHY_Read(ENET_Type * base,uint32_t phyAddr,uint32_t phyReg,uint32_t * dataPtr)161 status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
162 {
163 assert(dataPtr);
164
165 uint32_t counter;
166
167 /* Clear the MII interrupt event. */
168 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
169
170 /* Starts a SMI read command operation. */
171 ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame);
172
173 /* Wait for MII complete. */
174 for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
175 {
176 if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
177 {
178 break;
179 }
180 }
181
182 /* Check for timeout. */
183 if (!counter)
184 {
185 return kStatus_PHY_SMIVisitTimeout;
186 }
187
188 /* Get data from MII register. */
189 *dataPtr = ENET_ReadSMIData(base);
190
191 /* Clear MII interrupt event. */
192 ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
193
194 return kStatus_Success;
195 }
196
PHY_EnableLoopback(ENET_Type * base,uint32_t phyAddr,phy_loop_t mode,bool enable)197 status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, bool enable)
198 {
199 status_t result;
200 uint32_t data = 0;
201
202 /* Set the loop mode. */
203 if (enable)
204 {
205 if (mode == kPHY_LocalLoop)
206 {
207 /* First read the current status in control register. */
208 result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data);
209 if (result == kStatus_Success)
210 {
211 return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data | PHY_BCTL_LOOP_MASK));
212 }
213 }
214 else
215 {
216 /* First read the current status in control register. */
217 result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
218 if (result == kStatus_Success)
219 {
220 return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REMOTELOOP_MASK));
221 }
222 }
223 }
224 else
225 {
226 /* Disable the loop mode. */
227 if (mode == kPHY_LocalLoop)
228 {
229 /* First read the current status in the basic control register. */
230 result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data);
231 if (result == kStatus_Success)
232 {
233 return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data & ~PHY_BCTL_LOOP_MASK));
234 }
235 }
236 else
237 {
238 /* First read the current status in control one register. */
239 result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
240 if (result == kStatus_Success)
241 {
242 return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data & ~PHY_CTL2_REMOTELOOP_MASK));
243 }
244 }
245 }
246 return result;
247 }
248
PHY_GetLinkStatus(ENET_Type * base,uint32_t phyAddr,bool * status)249 status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status)
250 {
251 assert(status);
252
253 status_t result = kStatus_Success;
254 uint32_t data;
255
256 /* Read the basic status register. */
257 result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &data);
258 if (result == kStatus_Success)
259 {
260 if (!(PHY_BSTATUS_LINKSTATUS_MASK & data))
261 {
262 /* link down. */
263 *status = false;
264 }
265 else
266 {
267 /* link up. */
268 *status = true;
269 }
270 }
271 return result;
272 }
273
PHY_GetLinkSpeedDuplex(ENET_Type * base,uint32_t phyAddr,phy_speed_t * speed,phy_duplex_t * duplex)274 status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex)
275 {
276 assert(duplex);
277
278 status_t result = kStatus_Success;
279 uint32_t data, ctlReg;
280
281 /* Read the control two register. */
282 result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
283 if (result == kStatus_Success)
284 {
285 data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
286 if ((PHY_CTL1_10FULLDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
287 {
288 /* Full duplex. */
289 *duplex = kPHY_FullDuplex;
290 }
291 else
292 {
293 /* Half duplex. */
294 *duplex = kPHY_HalfDuplex;
295 }
296
297 data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
298 if ((PHY_CTL1_100HALFDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
299 {
300 /* 100M speed. */
301 *speed = kPHY_Speed100M;
302 }
303 else
304 { /* 10M speed. */
305 *speed = kPHY_Speed10M;
306 }
307 }
308
309 return result;
310 }
311