1 /*
2  * Copyright 2020-2021 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_enet_mdio.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /*******************************************************************************
15  * Prototypes
16  ******************************************************************************/
17 
18 static void ENET_MDIO_Init(mdio_handle_t *handle);
19 static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data);
20 static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr);
21 #if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO
22 static status_t ENET_MDIO_WriteExt(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data);
23 static status_t ENET_MDIO_ReadExt(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr);
24 #endif
25 static status_t ENET_MDIO_WaitTransferOver(ENET_Type *base);
26 
27 /*******************************************************************************
28  * Variables
29  ******************************************************************************/
30 
31 const mdio_operations_t enet_ops = {.mdioInit  = ENET_MDIO_Init,
32                                     .mdioWrite = ENET_MDIO_Write,
33                                     .mdioRead  = ENET_MDIO_Read,
34 #if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO
35                                     .mdioWriteExt = ENET_MDIO_WriteExt,
36                                     .mdioReadExt  = ENET_MDIO_ReadExt};
37 #else
38                                     .mdioWriteExt = NULL,
39                                     .mdioReadExt  = NULL};
40 #endif
41 
42 /*******************************************************************************
43  * Code
44  ******************************************************************************/
45 
ENET_MDIO_Init(mdio_handle_t * handle)46 static void ENET_MDIO_Init(mdio_handle_t *handle)
47 {
48     mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
49     ENET_Type *base           = (ENET_Type *)resource->base;
50 
51 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
52     uint32_t instance         = ENET_GetInstance(base);
53 
54     /* Set SMI first. */
55     (void)CLOCK_EnableClock(s_enetClock[instance]);
56 #if defined(FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE) && FSL_FEATURE_ENET_HAS_EXTRA_CLOCK_GATE
57     (void)CLOCK_EnableClock(s_enetExtraClock[instance]);
58 #endif
59 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
60     ENET_SetSMI(base, resource->csrClock_Hz, false);
61 }
62 
ENET_MDIO_Write(mdio_handle_t * handle,uint32_t phyAddr,uint32_t devAddr,uint32_t data)63 static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data)
64 {
65     mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
66     ENET_Type *base           = (ENET_Type *)resource->base;
67     status_t result           = kStatus_Success;
68 
69     /* Clear the SMI interrupt event. */
70     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
71 
72     /* Starts a SMI write command. */
73     ENET_StartSMIWrite(base, phyAddr, devAddr, kENET_MiiWriteValidFrame, data);
74 
75     result = ENET_MDIO_WaitTransferOver(base);
76     if (result != kStatus_Success)
77     {
78         return result;
79     }
80 
81     /* Clear SMI interrupt event. */
82     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
83 
84     return result;
85 }
86 
ENET_MDIO_Read(mdio_handle_t * handle,uint32_t phyAddr,uint32_t devAddr,uint32_t * dataPtr)87 static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr)
88 {
89     assert(dataPtr != NULL);
90 
91     mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
92     ENET_Type *base           = (ENET_Type *)resource->base;
93     status_t result           = kStatus_Success;
94 
95     /* Clear the SMI interrupt event. */
96     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
97 
98     /* Starts a SMI read command operation. */
99     ENET_StartSMIRead(base, phyAddr, devAddr, kENET_MiiReadValidFrame);
100 
101     result = ENET_MDIO_WaitTransferOver(base);
102     if (result != kStatus_Success)
103     {
104         return result;
105     }
106 
107     /* Get data from SMI register. */
108     *dataPtr = ENET_ReadSMIData(base);
109 
110     /* Clear SMI interrupt event. */
111     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
112 
113     return result;
114 }
115 
116 #if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO
ENET_MDIO_WriteExt(mdio_handle_t * handle,uint32_t phyAddr,uint32_t devAddr,uint32_t data)117 static status_t ENET_MDIO_WriteExt(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data)
118 {
119     mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
120     ENET_Type *base           = (ENET_Type *)resource->base;
121     status_t result           = kStatus_Success;
122 
123     /* Write the register address */
124     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
125     ENET_StartExtC45SMIWriteReg(base, phyAddr, devAddr);
126     result = ENET_MDIO_WaitTransferOver(base);
127     if (result != kStatus_Success)
128     {
129         return result;
130     }
131     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
132 
133     /* Write data to the specified register address */
134     ENET_StartExtC45SMIWriteData(base, phyAddr, devAddr, data);
135     result = ENET_MDIO_WaitTransferOver(base);
136     if (result != kStatus_Success)
137     {
138         return result;
139     }
140     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
141 
142     return result;
143 }
144 
ENET_MDIO_ReadExt(mdio_handle_t * handle,uint32_t phyAddr,uint32_t devAddr,uint32_t * dataPtr)145 static status_t ENET_MDIO_ReadExt(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr)
146 {
147     assert(dataPtr != NULL);
148 
149     mdio_resource_t *resource = (mdio_resource_t *)&handle->resource;
150     ENET_Type *base           = (ENET_Type *)resource->base;
151     status_t result           = kStatus_Success;
152 
153     /* Write the register address */
154     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
155     ENET_StartExtC45SMIWriteReg(base, phyAddr, devAddr);
156     result = ENET_MDIO_WaitTransferOver(base);
157     if (result != kStatus_Success)
158     {
159         return result;
160     }
161 
162     /* Read data from the specified register address */
163     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
164     ENET_StartExtC45SMIReadData(base, phyAddr, devAddr);
165     result = ENET_MDIO_WaitTransferOver(base);
166     if (result != kStatus_Success)
167     {
168         return result;
169     }
170     ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
171     *dataPtr = ENET_ReadSMIData(base);
172     return result;
173 }
174 #endif
175 
ENET_MDIO_WaitTransferOver(ENET_Type * base)176 static status_t ENET_MDIO_WaitTransferOver(ENET_Type *base)
177 {
178     status_t result = kStatus_Success;
179 #ifdef MDIO_TIMEOUT_COUNT
180     uint32_t counter;
181 #endif
182 
183     /* Wait for SMI complete. */
184 #ifdef MDIO_TIMEOUT_COUNT
185     for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--)
186     {
187         if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK))
188         {
189             break;
190         }
191     }
192     /* Check for timeout. */
193     if (0U == counter)
194     {
195         result = kStatus_PHY_SMIVisitTimeout;
196     }
197 #else
198     while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK))
199     {
200     }
201 #endif
202     return result;
203 }
204