1 /*
2  * Copyright (c) 2013-2016 ARM Limited. All rights reserved.
3  * Copyright (c) 2016, Freescale Semiconductor, Inc. Not a Contribution.
4  * Copyright 2016-2022 NXP. Not a Contribution.
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * Licensed under the Apache License, Version 2.0 (the License); you may
9  * not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
16  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #include "fsl_enet_phy_cmsis.h"
22 #include "fsl_enet.h"
23 
24 #define ARM_ETH_PHY_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2, 1)
25 
26 #ifndef PHY_AUTONEGO_DELAY_COUNT
27 #define PHY_AUTONEGO_DELAY_COUNT (800000U)
28 #endif
29 
30 typedef struct _cmsis_enet_phy_state
31 {
32     cmsis_enet_phy_resource_t *resource; /*!< Basic enet resource. */
33     uint32_t cmsis_enet_phy_mode;        /*!< ENET MII interface work mode. */
34 } cmsis_enet_phy_state_t;
35 
36 static const ARM_DRIVER_VERSION s_phyDriverVersion = {ARM_ETH_PHY_API_VERSION, ARM_ETH_PHY_DRV_VERSION};
37 
PHYx_GetVersion(void)38 static ARM_DRIVER_VERSION PHYx_GetVersion(void)
39 {
40     return s_phyDriverVersion;
41 }
42 
PHY_SetForcedSpeedDuplexMode(cmsis_enet_phy_state_t * ethPhy,uint32_t mode)43 static int32_t PHY_SetForcedSpeedDuplexMode(cmsis_enet_phy_state_t *ethPhy, uint32_t mode)
44 {
45     int32_t result;
46     uint16_t bsctlReg;
47 
48     /* Reset PHY. */
49     result = PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
50     if (result == kStatus_Success)
51     {
52         /* Set with the forced speed and duplex. */
53         result = PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &bsctlReg);
54         if (result == kStatus_Success)
55         {
56             /* Build the control value. */
57             bsctlReg &= ~(PHY_BCTL_DUPLEX_MASK | PHY_BCTL_SPEED0_MASK | PHY_BCTL_AUTONEG_MASK);
58             if (mode == (uint32_t)ARM_ETH_PHY_DUPLEX_FULL)
59             {
60                 bsctlReg |= PHY_BCTL_DUPLEX_MASK;
61             }
62             if (mode == (uint32_t)ARM_ETH_PHY_SPEED_100M)
63             {
64                 bsctlReg |= PHY_BCTL_SPEED0_MASK;
65             }
66             result = PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, bsctlReg);
67         }
68     }
69 
70     return result;
71 }
72 
PHY_SetPowerDown(cmsis_enet_phy_resource_t * enet,bool down)73 static void PHY_SetPowerDown(cmsis_enet_phy_resource_t *enet, bool down)
74 {
75     uint16_t data;
76 
77     if (down)
78     {
79         (void)PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &data);
80         data |= (uint16_t)(1UL << 11);
81         (void)PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, data);
82     }
83     else
84     {
85         (void)PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &data);
86         data &= ~(uint16_t)(1UL << 11);
87         (void)PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, data);
88         (void)PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &data);
89     }
90 }
91 
92 #if RTE_ENET
93 
94 extern cmsis_enet_phy_resource_t ENETPHY0_Resource;
95 
96 static cmsis_enet_phy_state_t ENETPHY0_State = {&ENETPHY0_Resource, ARM_ETH_PHY_AUTO_NEGOTIATE};
97 
PHY0_Initialize(ARM_ETH_PHY_Read_t fn_read,ARM_ETH_PHY_Write_t fn_write)98 static int32_t PHY0_Initialize(ARM_ETH_PHY_Read_t fn_read, ARM_ETH_PHY_Write_t fn_write)
99 {
100     return ARM_DRIVER_OK;
101 }
102 
PHY0_UnInitialize(void)103 static int32_t PHY0_UnInitialize(void)
104 {
105     return ARM_DRIVER_OK;
106 }
107 
PHY0_PowerControl(ARM_POWER_STATE state)108 static int32_t PHY0_PowerControl(ARM_POWER_STATE state)
109 {
110     int32_t status;
111     phy_config_t phyConfig = {0};
112     bool autonego          = false;
113     uint32_t count;
114 
115     switch (state)
116     {
117         case ARM_POWER_FULL:
118         {
119             phyConfig.phyAddr  = ENETPHY0_State.resource->phyAddr;
120             phyConfig.ops      = ENETPHY0_State.resource->ops;
121             phyConfig.resource = ENETPHY0_State.resource->opsResource;
122             phyConfig.autoNeg  = true;
123             status             = PHY_Init(&phyHandle, &phyConfig);
124             if (status == kStatus_Success)
125             {
126                 count = PHY_AUTONEGO_DELAY_COUNT;
127                 do
128                 {
129                     (void)PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
130                     if (autonego)
131                     {
132                         break;
133                     }
134                 } while (--count != 0U);
135             }
136             if (autonego)
137             {
138                 status = ARM_DRIVER_OK;
139             }
140             else
141             {
142                 status = ARM_DRIVER_ERROR;
143             }
144         }
145         break;
146         case ARM_POWER_OFF:
147         {
148             PHY_SetPowerDown(ENETPHY0_State.resource, true);
149             status = ARM_DRIVER_OK;
150         }
151         break;
152         default:
153             status = ARM_DRIVER_ERROR_UNSUPPORTED;
154             break;
155     }
156     return status;
157 }
158 
PHY0_SetInterface(uint32_t interface)159 static int32_t PHY0_SetInterface(uint32_t interface)
160 {
161     int32_t status = ARM_DRIVER_OK;
162     /* The interface for PHY is fixed or controlled by JUMPER setting.
163      * The interface setting for MAC is defined by "RTE_ENET_RMII/RTE_ENET_MII"
164      */
165     if (interface == (uint32_t)ARM_ETH_INTERFACE_SMII)
166     {
167         status = ARM_DRIVER_ERROR_UNSUPPORTED;
168     }
169     return status;
170 }
171 
PHY0_SetMode(uint32_t mode)172 static int32_t PHY0_SetMode(uint32_t mode)
173 {
174     int32_t status         = ARM_DRIVER_OK;
175     phy_config_t phyConfig = {0};
176     bool autonego          = false;
177     uint32_t count;
178 
179     /*!< Check input mode. */
180     if ((mode == (uint32_t)ARM_ETH_PHY_SPEED_1G) || (mode == ARM_ETH_PHY_ISOLATE))
181     {
182         return ARM_DRIVER_ERROR_UNSUPPORTED;
183     }
184 
185     if (mode == ARM_ETH_PHY_LOOPBACK)
186     {
187         status = PHY_EnableLoopback(&phyHandle, kPHY_RemoteLoop, kPHY_Speed100M, true);
188     }
189     else if (mode == ARM_ETH_PHY_AUTO_NEGOTIATE)
190     {
191         phyConfig.phyAddr  = ENETPHY0_State.resource->phyAddr;
192         phyConfig.ops      = ENETPHY0_State.resource->ops;
193         phyConfig.resource = &ENETPHY0_State.resource->opsResource;
194         phyConfig.autoNeg  = true;
195         status             = PHY_Init(&phyHandle, &phyConfig);
196         if (status == kStatus_Success)
197         {
198             count = PHY_AUTONEGO_DELAY_COUNT;
199             do
200             {
201                 (void)PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
202                 if (autonego)
203                 {
204                     break;
205                 }
206             } while (--count != 0U);
207             if (!autonego)
208             {
209                 status = kStatus_Fail;
210             }
211         }
212     }
213     else
214     {
215         status = PHY_SetForcedSpeedDuplexMode(&ENETPHY0_State, mode);
216     }
217     ENETPHY0_State.cmsis_enet_phy_mode = mode;
218 
219     /* Convert to CMSIS status */
220     if (status == kStatus_Success)
221     {
222         status = ARM_DRIVER_OK;
223     }
224     else
225     {
226         status = ARM_DRIVER_ERROR;
227     }
228 
229     return status;
230 }
231 
PHY0_GetLinkState(void)232 static ARM_ETH_LINK_STATE PHY0_GetLinkState(void)
233 {
234     ARM_ETH_LINK_STATE state;
235     bool linkUp = false;
236     int32_t status;
237 
238     status = PHY_GetLinkStatus(&phyHandle, &linkUp);
239     if ((status == kStatus_Success) && linkUp)
240     {
241         state = ARM_ETH_LINK_UP;
242     }
243     else
244     {
245         state = ARM_ETH_LINK_DOWN;
246     }
247     return state;
248 }
249 
PHY0_GetLinkInfo(void)250 static ARM_ETH_LINK_INFO PHY0_GetLinkInfo(void)
251 {
252     ARM_ETH_LINK_INFO linkInfo = {0};
253     phy_speed_t speed;
254     phy_duplex_t duplex;
255     int32_t status;
256 
257     status = PHY_GetLinkSpeedDuplex(&phyHandle, &speed, &duplex);
258     if (status == kStatus_Success)
259     {
260         if (speed == kPHY_Speed10M)
261         {
262             linkInfo.speed = ARM_ETH_SPEED_10M;
263         }
264         else if (speed == kPHY_Speed100M)
265         {
266             linkInfo.speed = ARM_ETH_SPEED_100M;
267         }
268         else
269         {
270             linkInfo.speed = ARM_ETH_SPEED_1G;
271         }
272 
273         if (duplex == kPHY_FullDuplex)
274         {
275             linkInfo.duplex = ARM_ETH_DUPLEX_FULL;
276         }
277         else
278         {
279             linkInfo.duplex = ARM_ETH_DUPLEX_HALF;
280         }
281     }
282     return linkInfo;
283 }
284 
285 ARM_DRIVER_ETH_PHY Driver_ETH_PHY0 = {PHYx_GetVersion,   PHY0_Initialize, PHY0_UnInitialize, PHY0_PowerControl,
286                                       PHY0_SetInterface, PHY0_SetMode,    PHY0_GetLinkState, PHY0_GetLinkInfo};
287 #endif
288