1 /*
2  * Copyright 2021 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "fsl_phyvsc8541.h"
8 
9 /*******************************************************************************
10  * Definitions
11  ******************************************************************************/
12 
13 /*! @brief Defines the PHY VSC8541 vendor defined registers. */
14 #define PHY_AUXILIARY_CTRL_STATUS_REG 0x1CU /*!< The PHY auxiliary control and status register. */
15 #define PHY_PAGE_SELECT_REG           0x1FU /*!< The PHY page select register. */
16 
17 /*! @brief Defines the PHY VSC8541 device ID information. */
18 #define PHY_OUI                 0x1C1U /*!< The PHY organizationally unique identifier. */
19 #define PHY_MODEL_NUM           0x37U  /*!< The PHY organizationally unique identifier. */
20 #define PHY_DEVICE_REVISION_NUM 0x2U   /*!< The PHY organizationally unique identifier. */
21 #define PHY_DEVICE_ID           ((PHY_OUI << 10U) | (PHY_MODEL_NUM << 4U) | (PHY_DEVICE_REVISION_NUM))
22 
23 /*! @brief Defines the mask flag in specific status register. */
24 #define PHY_AUXILIARY_CTRL_STATUS_LINKSPEED_MASK  0x18U /*!< The PHY link speed mask. */
25 #define PHY_AUXILIARY_CTRL_STATUS_LINKDUPLEX_MASK 0x20U /*!< The PHY link duplex mask. */
26 #define PHY_AUXILIARY_CTRL_STATUS_LINKSPEED_SHIFT 3U    /*!< The link speed shift */
27 
28 /*! @brief Defines the PHY VSC8541 extra page and the registers in specified page. */
29 #define PHY_RGMII_TXRX_DELAY_REG 0x14U /*!< The RGMII TXC/RXC delay register. */
30 #define PHY_RGMII_TX_DELAY_SHIFT 0U    /*!< The RGMII TXC delay mask. */
31 #define PHY_RGMII_RX_DELAY_SHIFT 4U    /*!< The RGMII RXC delay mask. */
32 
33 /*! @brief Defines the timeout macro. */
34 #define PHY_READID_TIMEOUT_COUNT 1000U
35 
36 /*! @brief Defines the PHY resource interface. */
37 #define PHY_VSC8541_WRITE(handle, regAddr, data) \
38     ((phy_vsc8541_resource_t *)(handle)->resource)->write((handle)->phyAddr, regAddr, data)
39 #define PHY_VSC8541_READ(handle, regAddr, pData) \
40     ((phy_vsc8541_resource_t *)(handle)->resource)->read((handle)->phyAddr, regAddr, pData)
41 
42 /*******************************************************************************
43  * Prototypes
44  ******************************************************************************/
45 
46 #if 0
47 static status_t PHY_VSC8541_MMD_SetDevice(phy_handle_t *handle,
48                                           uint8_t device,
49                                           uint16_t addr,
50                                           phy_mmd_access_mode_t mode);
51 static inline status_t PHY_VSC8541_MMD_ReadData(phy_handle_t *handle, uint16_t *pData);
52 static inline status_t PHY_VSC8541_MMD_WriteData(phy_handle_t *handle, uint16_t data);
53 static status_t PHY_VSC8541_MMD_Read(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t *pData);
54 static status_t PHY_VSC8541_MMD_Write(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t data);
55 #endif
56 
57 /*******************************************************************************
58  * Variables
59  ******************************************************************************/
60 
61 const phy_operations_t phyvsc8541_ops = {.phyInit            = PHY_VSC8541_Init,
62                                          .phyWrite           = PHY_VSC8541_Write,
63                                          .phyRead            = PHY_VSC8541_Read,
64                                          .getAutoNegoStatus  = PHY_VSC8541_GetAutoNegotiationStatus,
65                                          .getLinkStatus      = PHY_VSC8541_GetLinkStatus,
66                                          .getLinkSpeedDuplex = PHY_VSC8541_GetLinkSpeedDuplex,
67                                          .setLinkSpeedDuplex = PHY_VSC8541_SetLinkSpeedDuplex,
68                                          .enableLoopback     = PHY_VSC8541_EnableLoopback};
69 
70 /*******************************************************************************
71  * Code
72  ******************************************************************************/
73 
PHY_VSC8541_Init(phy_handle_t * handle,const phy_config_t * config)74 status_t PHY_VSC8541_Init(phy_handle_t *handle, const phy_config_t *config)
75 {
76     uint32_t counter = PHY_READID_TIMEOUT_COUNT;
77     status_t result;
78     uint16_t regValue = 0U;
79     uint32_t devId    = 0U;
80 
81     handle->phyAddr  = config->phyAddr;
82     handle->resource = config->resource;
83 
84     /* Check PHY ID. */
85     do
86     {
87         result = PHY_VSC8541_READ(handle, PHY_ID1_REG, &regValue);
88         if (result != kStatus_Success)
89         {
90             return result;
91         }
92         devId = regValue << 16U;
93 
94         result = PHY_VSC8541_READ(handle, PHY_ID2_REG, &regValue);
95         if (result != kStatus_Success)
96         {
97             return result;
98         }
99         devId += regValue;
100 
101         counter--;
102     } while ((devId != PHY_DEVICE_ID) && (counter != 0U));
103 
104     if (counter == 0U)
105     {
106         return kStatus_Fail;
107     }
108 
109     /* Reset PHY. */
110     result = PHY_VSC8541_WRITE(handle, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
111     if (result != kStatus_Success)
112     {
113         return result;
114     }
115 
116     if (config->autoNeg)
117     {
118         /* Set the auto-negotiation. */
119         result = PHY_VSC8541_WRITE(handle, PHY_AUTONEG_ADVERTISE_REG,
120                                    PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
121                                        PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK |
122                                        PHY_IEEE802_3_SELECTOR_MASK);
123         if (result == kStatus_Success)
124         {
125             result = PHY_VSC8541_WRITE(handle, PHY_1000BASET_CONTROL_REG, PHY_1000BASET_FULLDUPLEX_MASK);
126             if (result == kStatus_Success)
127             {
128                 result = PHY_VSC8541_READ(handle, PHY_BASICCONTROL_REG, &regValue);
129                 if (result == kStatus_Success)
130                 {
131                     result = PHY_VSC8541_WRITE(handle, PHY_BASICCONTROL_REG,
132                                                (regValue | PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
133                 }
134             }
135         }
136     }
137     else
138     {
139         /* Disable isolate mode */
140         result = PHY_VSC8541_READ(handle, PHY_BASICCONTROL_REG, &regValue);
141         if (result != kStatus_Success)
142         {
143             return result;
144         }
145         regValue &= PHY_BCTL_ISOLATE_MASK;
146         result = PHY_VSC8541_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
147         if (result != kStatus_Success)
148         {
149             return result;
150         }
151 
152         /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
153         result = PHY_VSC8541_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
154     }
155     return result;
156 }
157 
PHY_VSC8541_Write(phy_handle_t * handle,uint8_t phyReg,uint16_t data)158 status_t PHY_VSC8541_Write(phy_handle_t *handle, uint8_t phyReg, uint16_t data)
159 {
160     return PHY_VSC8541_WRITE(handle, phyReg, data);
161 }
162 
PHY_VSC8541_Read(phy_handle_t * handle,uint8_t phyReg,uint16_t * pData)163 status_t PHY_VSC8541_Read(phy_handle_t *handle, uint8_t phyReg, uint16_t *pData)
164 {
165     return PHY_VSC8541_READ(handle, phyReg, pData);
166 }
167 
PHY_VSC8541_GetAutoNegotiationStatus(phy_handle_t * handle,bool * status)168 status_t PHY_VSC8541_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status)
169 {
170     assert(status);
171 
172     status_t result;
173     uint16_t regValue;
174 
175     *status = false;
176 
177     /* Check auto negotiation complete. */
178     result = PHY_VSC8541_READ(handle, PHY_BASICSTATUS_REG, &regValue);
179     if (result == kStatus_Success)
180     {
181         if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U)
182         {
183             *status = true;
184         }
185     }
186     return result;
187 }
188 
PHY_VSC8541_GetLinkStatus(phy_handle_t * handle,bool * status)189 status_t PHY_VSC8541_GetLinkStatus(phy_handle_t *handle, bool *status)
190 {
191     assert(status);
192 
193     status_t result;
194     uint16_t regValue;
195 
196     /* Read the basic status register. */
197     result = PHY_VSC8541_READ(handle, PHY_BASICSTATUS_REG, &regValue);
198     if (result == kStatus_Success)
199     {
200         if ((regValue & PHY_BSTATUS_LINKSTATUS_MASK) != 0U)
201         {
202             /* Link up. */
203             *status = true;
204         }
205         else
206         {
207             /* Link down. */
208             *status = false;
209         }
210     }
211     return result;
212 }
213 
PHY_VSC8541_GetLinkSpeedDuplex(phy_handle_t * handle,phy_speed_t * speed,phy_duplex_t * duplex)214 status_t PHY_VSC8541_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex)
215 {
216     assert(!((speed == NULL) && (duplex == NULL)));
217 
218     status_t result;
219     uint16_t regValue;
220 
221     /* Read the status register. */
222     result = PHY_VSC8541_READ(handle, PHY_AUXILIARY_CTRL_STATUS_REG, &regValue);
223     if (result == kStatus_Success)
224     {
225         if (speed != NULL)
226         {
227             switch ((regValue & PHY_AUXILIARY_CTRL_STATUS_LINKSPEED_MASK) >> PHY_AUXILIARY_CTRL_STATUS_LINKSPEED_SHIFT)
228             {
229                 case (uint16_t)kPHY_Speed10M:
230                     *speed = kPHY_Speed10M;
231                     break;
232                 case (uint16_t)kPHY_Speed100M:
233                     *speed = kPHY_Speed100M;
234                     break;
235                 case (uint16_t)kPHY_Speed1000M:
236                     *speed = kPHY_Speed1000M;
237                     break;
238                 default:
239                     *speed = kPHY_Speed10M;
240                     break;
241             }
242         }
243 
244         if (duplex != NULL)
245         {
246             if ((regValue & PHY_AUXILIARY_CTRL_STATUS_LINKDUPLEX_MASK) != 0U)
247             {
248                 *duplex = kPHY_FullDuplex;
249             }
250             else
251             {
252                 *duplex = kPHY_HalfDuplex;
253             }
254         }
255     }
256     return result;
257 }
258 
PHY_VSC8541_SetLinkSpeedDuplex(phy_handle_t * handle,phy_speed_t speed,phy_duplex_t duplex)259 status_t PHY_VSC8541_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex)
260 {
261     status_t result;
262     uint16_t regValue;
263 
264     result = PHY_VSC8541_READ(handle, PHY_BASICCONTROL_REG, &regValue);
265     if (result == kStatus_Success)
266     {
267         /* Disable the auto-negotiation and set according to user-defined configuration. */
268         regValue &= ~PHY_BCTL_AUTONEG_MASK;
269         if (speed == kPHY_Speed1000M)
270         {
271             regValue &= PHY_BCTL_SPEED0_MASK;
272             regValue |= PHY_BCTL_SPEED1_MASK;
273         }
274         else if (speed == kPHY_Speed100M)
275         {
276             regValue |= PHY_BCTL_SPEED0_MASK;
277             regValue &= ~PHY_BCTL_SPEED1_MASK;
278         }
279         else
280         {
281             regValue &= ~PHY_BCTL_SPEED0_MASK;
282             regValue &= ~PHY_BCTL_SPEED1_MASK;
283         }
284         if (duplex == kPHY_FullDuplex)
285         {
286             regValue |= PHY_BCTL_DUPLEX_MASK;
287         }
288         else
289         {
290             regValue &= ~PHY_BCTL_DUPLEX_MASK;
291         }
292         result = PHY_VSC8541_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
293     }
294     return result;
295 }
296 
PHY_VSC8541_EnableLoopback(phy_handle_t * handle,phy_loop_t mode,phy_speed_t speed,bool enable)297 status_t PHY_VSC8541_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable)
298 {
299     /* This PHY only supports local loopback. */
300     assert(mode == kPHY_LocalLoop);
301 
302     status_t result;
303     uint16_t regValue;
304 
305     /* Set the loop mode. */
306     if (enable)
307     {
308         if (speed == kPHY_Speed1000M)
309         {
310             regValue = PHY_BCTL_SPEED1_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
311         }
312         else if (speed == kPHY_Speed100M)
313         {
314             regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
315         }
316         else
317         {
318             regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
319         }
320         result = PHY_VSC8541_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
321     }
322     else
323     {
324         /* First read the current status in control register. */
325         result = PHY_VSC8541_READ(handle, PHY_BASICCONTROL_REG, &regValue);
326         if (result == kStatus_Success)
327         {
328             regValue &= ~PHY_BCTL_LOOP_MASK;
329             result = PHY_VSC8541_WRITE(handle, PHY_BASICCONTROL_REG, (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
330         }
331     }
332     return result;
333 }
334 
335 #if 0
336 static status_t PHY_VSC8541_MMD_SetDevice(phy_handle_t *handle,
337                                           uint8_t device,
338                                           uint16_t addr,
339                                           phy_mmd_access_mode_t mode)
340 {
341     status_t result = kStatus_Success;
342 
343     /* Set Function mode of address access(b00) and device address. */
344     result = PHY_VSC8541_WRITE(handle, PHY_MMD_ACCESS_CONTROL_REG, device);
345     if (result != kStatus_Success)
346     {
347         return result;
348     }
349 
350     /* Set register address. */
351     result = PHY_VSC8541_WRITE(handle, PHY_MMD_ACCESS_DATA_REG, addr);
352     if (result != kStatus_Success)
353     {
354         return result;
355     }
356 
357     /* Set Function mode of data access(b01~11) and device address. */
358     result = PHY_VSC8541_WRITE(handle, PHY_MMD_ACCESS_CONTROL_REG, (uint16_t)mode | (uint16_t)device);
359     return result;
360 }
361 
362 static inline status_t PHY_VSC8541_MMD_ReadData(phy_handle_t *handle, uint16_t *pData)
363 {
364     return PHY_VSC8541_READ(handle, PHY_MMD_ACCESS_DATA_REG, pData);
365 }
366 
367 static inline status_t PHY_VSC8541_MMD_WriteData(phy_handle_t *handle, uint16_t data)
368 {
369     return PHY_VSC8541_WRITE(handle, PHY_MMD_ACCESS_DATA_REG, data);
370 }
371 
372 static status_t PHY_VSC8541_MMD_Read(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t *pData)
373 {
374     status_t result = kStatus_Success;
375     result          = PHY_VSC8541_MMD_SetDevice(handle, device, addr, kPHY_MMDAccessNoPostIncrement);
376     if (result == kStatus_Success)
377     {
378         result = PHY_VSC8541_MMD_ReadData(handle, pData);
379     }
380     return result;
381 }
382 
383 static status_t PHY_VSC8541_MMD_Write(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t data)
384 {
385     status_t result = kStatus_Success;
386 
387     result = PHY_VSC8541_MMD_SetDevice(handle, device, addr, kPHY_MMDAccessNoPostIncrement);
388     if (result == kStatus_Success)
389     {
390         result = PHY_VSC8541_MMD_WriteData(handle, data);
391     }
392     return result;
393 }
394 #endif
395