1 /***************************************************************************//**
2 * \file cy_ephy.c
3 * \version 1.10
4 *
5 * Provides an API implementation of the Ethernet PHY driver
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2020, Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24
25 #include "cy_device.h"
26
27 #if defined (CY_IP_MXETH)
28
29 #include "cy_ephy.h"
30
31 #if defined(__cplusplus)
32 extern "C" {
33 #endif
34
35 #define DEFAULT_PHY_ADDRESS 0x0
36 #define CY_EPHY_INVALID_VALUE 0xFFFFUL
37
38
39 /*******************************************************************************
40 * Function Name: Cy_EPHY_Init
41 ****************************************************************************//**
42 *
43 * This function initializes the private structure and assign a PHY-read,
44 * PHY-write function handle to its private data structure.
45 *
46 * \param phy pointer to PHY private data structure.
47 * \param fnRead pointer to read function implemented in application
48 * \param fnWrite pointer to write function implemented in application
49 *
50 * \return Initialization status
51 * \return CY_EPHY_SUCCESS for successfully initializes the internal data structures.
52 *
53 *******************************************************************************/
Cy_EPHY_Init(cy_stc_ephy_t * phy,phy_read_handle fnRead,phy_write_handle fnWrite)54 cy_en_ephy_status_t Cy_EPHY_Init( cy_stc_ephy_t *phy, phy_read_handle fnRead, phy_write_handle fnWrite )
55 {
56 CY_ASSERT_L2(phy != NULL);
57 CY_ASSERT_L2(fnRead != NULL);
58 CY_ASSERT_L2(fnWrite != NULL);
59
60 phy->fnPhyRead = fnRead;
61 phy->fnPhyWrite = fnWrite;
62 phy->phyId = CY_EPHY_INVALID_VALUE;
63 phy->state = CY_EPHY_DOWN;
64 phy->bmcr = 0UL;
65 phy->anar = 0UL;
66
67 return CY_EPHY_SUCCESS;
68 }
69
70
71 /*******************************************************************************
72 * Function Name: Cy_EPHY_Discover
73 ****************************************************************************//**
74 *
75 * Discovers connected PHY at address zero. Reads ID1 and ID2 register to form
76 * PHY ID.
77 *
78 * \param phy pointer to PHY private data structure
79 *
80 * \return CY_EPHY_ERROR PHY chip contains invalid PHY ID
81 * \return CY_EPHY_SUCCESS PHY chip contains a valid PHY ID
82 *
83 *******************************************************************************/
Cy_EPHY_Discover(cy_stc_ephy_t * phy)84 cy_en_ephy_status_t Cy_EPHY_Discover( cy_stc_ephy_t *phy )
85 {
86 uint32_t phyAddress = DEFAULT_PHY_ADDRESS;
87 uint32_t ulLowerID = 0;
88 uint32_t ulUpperID = 0;
89 uint32_t ulPhyID = 0;
90
91 CY_ASSERT_L2(phy->fnPhyRead != NULL);
92 CY_ASSERT_L2(phy->fnPhyWrite != NULL);
93
94 phy->fnPhyRead( phyAddress, PHYREG_03_PHYSID2, &ulLowerID );
95 if ( CY_EPHY_INVALID_VALUE == ulLowerID )
96 {
97 return CY_EPHY_ERROR;
98 }
99 /* A valid PHY id can not be all zeros or all ones. */
100 if( ulLowerID != ( uint16_t )0UL )
101 {
102 phy->fnPhyRead( phyAddress, PHYREG_02_PHYSID1, &ulUpperID );
103 if ( CY_EPHY_INVALID_VALUE == ulUpperID )
104 {
105 return CY_EPHY_ERROR;
106 }
107 ulPhyID = ( _VAL2FLD( PHYID_ID1, ulUpperID ) | _VAL2FLD( PHYID_ID2, ulLowerID ) );
108 }
109 phy->phyId = ulPhyID;
110 return CY_EPHY_SUCCESS;
111 }
112
113
114 /*******************************************************************************
115 * Function Name: Cy_EPHY_Reset
116 ****************************************************************************//**
117 * Soft reset PHY by enabling 15th bit of BMCR register
118 *
119 * \param phy pointer to PHY private data structure
120 *
121 * \return CY_EPHY_SUCCESS for successful soft reset
122 *
123 *******************************************************************************/
Cy_EPHY_Reset(cy_stc_ephy_t * phy)124 cy_en_ephy_status_t Cy_EPHY_Reset(cy_stc_ephy_t *phy)
125 {
126 uint32_t ulConfig;
127 uint32_t phyAddress = DEFAULT_PHY_ADDRESS;
128 uint32_t delay, max_delay=10;
129
130 CY_ASSERT_L2(phy->fnPhyRead != NULL);
131 CY_ASSERT_L2(phy->fnPhyWrite != NULL);
132
133 /* Read Control register. */
134 phy->fnPhyRead( phyAddress, PHYREG_00_BMCR, &ulConfig );
135 phy->fnPhyWrite( phyAddress, PHYREG_00_BMCR, ( ulConfig | PHYBMCR_RESET_Msk ) );
136 /* The reset should last less than a second. */
137 for( delay=0; delay < max_delay; delay++ )
138 {
139 phy->fnPhyRead( phyAddress, PHYREG_00_BMCR, &ulConfig );
140 if(_FLD2VAL(PHYBMCR_RESET, ulConfig) == 0UL)
141 {
142 break;
143 }
144 Cy_SysLib_Delay(100);
145 }
146
147 /* Clear the reset bits. */
148 phy->fnPhyRead( phyAddress, PHYREG_00_BMCR, &ulConfig );
149 phy->fnPhyWrite( phyAddress, PHYREG_00_BMCR, ( ulConfig & ( ~PHYBMCR_RESET_Msk ) ) );
150 Cy_SysLib_Delay(50);
151 return CY_EPHY_SUCCESS;
152 }
153
154
155 /*******************************************************************************
156 * Function Name: Cy_EPHY_Configure
157 ****************************************************************************//**
158 *
159 * Configures PHY with user provided speed and duplex mode
160 *
161 * \param phy pointer to PHY private data structure
162 * \param config pointer to PHY configuration structure
163 *
164 * \return CY_EPHY_SUCCESS
165 * Successfully configure PHY registers
166 * \return CY_EPHY_AN_NOT_SUPPORTED
167 * PHY does not support Auto-Negotiation.
168 *
169 * \note For Auto-Negotiation configure the speed and duplex mode to
170 * CY_EPHY_SPEED_AUTO and CY_EPHY_DUPLEX_AUTO respectively. In this configuration
171 * PHY will advertise with highest capabilities. Also if vendor specific registers
172 * are supported then user may needs to configure the vendor specific registers to
173 * highest capabilities. For more details please refer to the PHY datasheet.
174 *
175 *******************************************************************************/
Cy_EPHY_Configure(cy_stc_ephy_t * phy,cy_stc_ephy_config_t * config)176 cy_en_ephy_status_t Cy_EPHY_Configure( cy_stc_ephy_t *phy, cy_stc_ephy_config_t *config )
177 {
178 uint32_t ulConfig, reg, bmsr;
179 uint32_t phyAddress = DEFAULT_PHY_ADDRESS;
180 cy_en_ephy_status_t ret = CY_EPHY_SUCCESS;
181
182 CY_ASSERT_L2(phy->fnPhyRead != NULL);
183 CY_ASSERT_L2(phy->fnPhyWrite != NULL);
184
185 /* Read Control register. */
186 phy->fnPhyRead( phyAddress, PHYREG_00_BMCR, &ulConfig );
187
188 if ((config->speed == ((uint32_t)CY_EPHY_SPEED_AUTO)) || (config->duplex == ((uint32_t)CY_EPHY_DUPLEX_AUTO)))
189 {
190 /* check AN is supported */
191 phy->fnPhyRead( phyAddress, PHYREG_01_BMSR, ®);
192 if (_FLD2VAL(PHYBMSR_AN_ABILITY,reg) == 1UL)
193 {
194 /* 1. BMCR enable AN */
195 ulConfig |= PHYBMCR_AN_ENABLE_Msk;
196 /* 2. BMCR restart AN */
197 ulConfig |= PHYBMCR_AN_RESTART_Msk;
198 }
199 else
200 {
201 ret = CY_EPHY_AN_NOT_SUPPORTED;
202 }
203 }
204 else
205 {
206 /* Read Control register. */
207 phy->fnPhyRead( phyAddress, PHYREG_01_BMSR, &bmsr );
208 /* check BMSR 8th bit. All PHYs supporting 1000 Mb/s operation
209 * shall have this bit set to a logic one */
210
211 ulConfig &= ~( PHYBMCR_SPEED_1000_Msk | PHYBMCR_SPEED_100_Msk | PHYBMCR_FULL_DUPLEX_Msk | PHYBMCR_AN_ENABLE_Msk);
212
213 if( config->speed == ((uint32_t)CY_EPHY_SPEED_100))
214 {
215 ulConfig |= PHYBMCR_SPEED_100_Msk;
216 }
217 else if ((config->speed == ((uint32_t)CY_EPHY_SPEED_1000)) && ((bmsr & PHYBMSR_EXT_STATUS_Msk) != 0x0UL))
218 {
219 ulConfig |= PHYBMCR_AN_ENABLE_Msk;
220 ulConfig |= PHYBMCR_SPEED_1000_Msk;
221 }
222 else if( config->speed == ((uint32_t)CY_EPHY_SPEED_10))
223 {
224 ulConfig &= ~PHYBMCR_SPEED_100_Msk;
225 }
226 else
227 {
228 /* Invalid speed or bad parameter */
229 ret = CY_EPHY_ERROR;
230 }
231
232 if( config->duplex == ((uint32_t)CY_EPHY_DUPLEX_FULL))
233 {
234 ulConfig |= PHYBMCR_FULL_DUPLEX_Msk;
235 }
236 else if( config->duplex == ((uint32_t)CY_EPHY_DUPLEX_HALF))
237 {
238 ulConfig &= ~PHYBMCR_FULL_DUPLEX_Msk;
239 }
240 else
241 {
242 /* invalid duplex mode */
243 ret = CY_EPHY_INVALID_DUPLEX;
244 }
245 }
246
247 if (ret == CY_EPHY_SUCCESS)
248 {
249 /* Keep these values for later use. */
250 phy->bmcr = ulConfig & ~PHYBMCR_ISOLATE_Msk;
251
252 /* configure bmcr */
253 phy->fnPhyWrite( phyAddress, PHYREG_00_BMCR, phy->bmcr);
254 }
255
256 return ret;
257 }
258
259
260 /*******************************************************************************
261 * Function Name: Cy_EPHY_GetLinkStatus
262 ****************************************************************************//**
263 *
264 * Get current link status of PHY.
265 *
266 * \param phy pointer to PHY private data structure
267 *
268 * \return
269 * link status of PHY (0=down, 1=up)
270 *
271 *******************************************************************************/
Cy_EPHY_GetLinkStatus(cy_stc_ephy_t * phy)272 uint32_t Cy_EPHY_GetLinkStatus(cy_stc_ephy_t *phy)
273 {
274 uint32_t phyAddress=DEFAULT_PHY_ADDRESS;
275 uint32_t status;
276
277 CY_ASSERT_L2(phy->fnPhyRead != NULL);
278 CY_ASSERT_L2(phy->fnPhyWrite != NULL);
279
280 /* read bmcr */
281 phy->fnPhyRead( phyAddress, PHYREG_00_BMCR, &status);
282
283 /* check for auto-neg-restart. Autoneg is being started, therefore disregard
284 * BMSR value and report link as down.
285 */
286 if (0UL != (status & PHYBMCR_AN_RESTART_Msk))
287 {
288 return 0UL;
289 }
290
291 /* Read link and Auto-Negotiation status */
292 status = 0;
293 phy->fnPhyRead( phyAddress, PHYREG_01_BMSR, &status);
294
295 if (CY_EPHY_INVALID_VALUE == status)
296 {
297 return 0UL;
298 }
299 else
300 {
301 return _FLD2VAL( PHYBMSR_LINK_STATUS, status);
302 }
303 }
304
305
306 /*******************************************************************************
307 * Function Name: Cy_EPHY_GetAutoNegotiationStatus
308 ****************************************************************************//**
309 *
310 * Get current Auto-Negotiation status (completed or In-progress).
311 *
312 * \param phy pointer to PHY private data structure
313 *
314 * \return
315 * Auto-Negotiation status of PHY.
316 * 0 = Auto-Negotiation process is not completed.
317 * 1 = Auto-Negotiation process is completed.
318 *
319 *******************************************************************************/
Cy_EPHY_GetAutoNegotiationStatus(cy_stc_ephy_t * phy)320 uint32_t Cy_EPHY_GetAutoNegotiationStatus(cy_stc_ephy_t *phy)
321 {
322 uint32_t reg;
323 uint32_t phyAddress=DEFAULT_PHY_ADDRESS;
324
325 CY_ASSERT_L2(phy->fnPhyRead != NULL);
326 CY_ASSERT_L2(phy->fnPhyWrite != NULL);
327
328 phy->fnPhyRead(phyAddress, PHYREG_01_BMSR, ®);
329
330 return _FLD2VAL(PHYBMSR_AN_COMPLETE, reg);
331 }
332
333
334 /*******************************************************************************
335 * Function Name: Cy_EPHY_getLinkPartnerCapabilities
336 ****************************************************************************//**
337 *
338 * Gets Link partner capabilities (speed and duplex)
339 *
340 * \param phy Pointer to PHY private data structure
341 * \param lpConfig [Output] Speed and duplex information
342 *
343 * \return CY_EPHY_SUCCESS : Success in processing the link capability.
344 * \return CY_EPHY_ERROR : Error in processing the link capability. Ignore the lpConfig output parameter.
345 * \note This function should be called after Auto-Negotiation is completed ( \ref Cy_EPHY_GetAutoNegotiationStatus )
346 *
347 *******************************************************************************/
Cy_EPHY_getLinkPartnerCapabilities(cy_stc_ephy_t * phy,cy_stc_ephy_config_t * lpConfig)348 cy_en_ephy_status_t Cy_EPHY_getLinkPartnerCapabilities(cy_stc_ephy_t *phy, cy_stc_ephy_config_t *lpConfig)
349 {
350 uint32_t reg;
351 cy_en_ephy_status_t ret = CY_EPHY_SUCCESS;
352 uint32_t phyAddress = DEFAULT_PHY_ADDRESS;
353
354 CY_ASSERT_L2(phy->fnPhyRead != NULL);
355 CY_ASSERT_L2(phy->fnPhyWrite != NULL);
356
357 /* default assignment */
358 lpConfig->speed = (uint32_t)CY_EPHY_SPEED_10;
359 lpConfig->duplex = (uint32_t)CY_EPHY_DUPLEX_HALF;
360
361 /* Check Extended Register is supported */
362 phy->fnPhyRead( phyAddress, PHYREG_01_BMSR, ®);
363 if (_FLD2VAL( PHYBMSR_EXT_CAPABILITY, reg) == 1UL)
364 {
365 /* 1. check gigabit is supported or not */
366 phy->fnPhyRead( phyAddress, PHYREG_10_MSSR, ®);
367 if (_FLD2VAL( MSSR_1000BASE_T_FULLDUPLEX, reg) == 1UL)
368 {
369 lpConfig->speed = (uint32_t)CY_EPHY_SPEED_1000;
370 lpConfig->duplex = (uint32_t)CY_EPHY_DUPLEX_FULL;
371 }
372 else if (_FLD2VAL( MSSR_1000BASE_T_HALFDUPLEX, reg) == 1UL)
373 {
374 lpConfig->speed = (uint32_t)CY_EPHY_SPEED_1000;
375 lpConfig->duplex = (uint32_t)CY_EPHY_DUPLEX_HALF;
376 }
377 else
378 {
379 /* 2. if not then check 10 and 100 Mbps */
380 phy->fnPhyRead( phyAddress, PHYREG_05_ANLPAR, ®);
381 if (_FLD2VAL( ANLPAR_TXFD, reg) == 1UL)
382 {
383 lpConfig->speed = (uint32_t)CY_EPHY_SPEED_100;
384 lpConfig->duplex = (uint32_t)CY_EPHY_DUPLEX_FULL;
385 }
386 else if ((_FLD2VAL( ANLPAR_T4, reg) == 1UL) || (_FLD2VAL( ANLPAR_TX, reg) == 1UL))
387 {
388 lpConfig->speed = (uint32_t)CY_EPHY_SPEED_100;
389 lpConfig->duplex = (uint32_t)CY_EPHY_DUPLEX_HALF;
390 }
391 else if (_FLD2VAL( ANLPAR_10FD, reg) == 1UL)
392 {
393 lpConfig->speed = (uint32_t)CY_EPHY_SPEED_10;
394 lpConfig->duplex = (uint32_t)CY_EPHY_DUPLEX_FULL;
395 }
396 else if (_FLD2VAL( ANLPAR_10, reg) == 1UL)
397 {
398 lpConfig->speed = (uint32_t)CY_EPHY_SPEED_10;
399 lpConfig->duplex = (uint32_t)CY_EPHY_DUPLEX_HALF;
400 }
401 else
402 {
403 ret = CY_EPHY_ERROR;
404 }
405 }
406 }
407 else
408 {
409 ret = CY_EPHY_ERROR;
410 }
411
412 return ret;
413 }
414
415
416 #if defined(__cplusplus)
417 }
418 #endif
419
420 #endif /* CY_IP_MXETH */
421
422 /* [] END OF FILE */
423