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