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, &reg);
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, &reg);
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, &reg);
363     if (_FLD2VAL( PHYBMSR_EXT_CAPABILITY, reg) == 1UL)
364     {
365         /* 1. check gigabit is supported or not */
366         phy->fnPhyRead( phyAddress, PHYREG_10_MSSR, &reg);
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, &reg);
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