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, ®Value);
88 if (result != kStatus_Success)
89 {
90 return result;
91 }
92 devId = regValue << 16U;
93
94 result = PHY_VSC8541_READ(handle, PHY_ID2_REG, ®Value);
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, ®Value);
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, ®Value);
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, ®Value);
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, ®Value);
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, ®Value);
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, ®Value);
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, ®Value);
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