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