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