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, &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, &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, &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, &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