1 /*
2  * Copyright 2020-2023 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #ifndef _FSL_PHY_H_
7 #define _FSL_PHY_H_
8 
9 #include "fsl_common.h"
10 
11 /*! @brief This abstract layer is to unify the PHY interface in SDK, let application
12  *  use one set of PHY interfaces. The data structures are applicable to different
13  *  PHYs.
14  */
15 
16 /*******************************************************************************
17  * Definitions
18  ******************************************************************************/
19 
20 /*! @note The following PHY registers are the IEEE802.3 standard definition, same register and bit field may
21           have different names in various PHYs, but the feature they represent should be same or very similar. */
22 
23 /*! @brief Defines the IEEE802.3 standard PHY registers. */
24 #define PHY_BASICCONTROL_REG        (0x00U) /*!< The PHY basic control register. */
25 #define PHY_BASICSTATUS_REG         (0x01U) /*!< The PHY basic status register. */
26 #define PHY_ID1_REG                 (0x02U) /*!< The PHY ID one register. */
27 #define PHY_ID2_REG                 (0x03U) /*!< The PHY ID two register. */
28 #define PHY_AUTONEG_ADVERTISE_REG   (0x04U) /*!< The PHY auto-negotiate advertise register. */
29 #define PHY_AUTONEG_LINKPARTNER_REG (0x05U) /*!< The PHY auto negotiation link partner ability register. */
30 #define PHY_AUTONEG_EXPANSION_REG   (0x06U) /*!< The PHY auto negotiation expansion register. */
31 #define PHY_1000BASET_CONTROL_REG   (0x09U) /*!< The PHY 1000BASE-T control register. */
32 #define PHY_MMD_ACCESS_CONTROL_REG  (0x0DU) /*!< The PHY MMD access control register. */
33 #define PHY_MMD_ACCESS_DATA_REG     (0x0EU) /*!< The PHY MMD access data register. */
34 
35 /*! @brief Defines the mask flag in basic control register(Address 0x00). */
36 #define PHY_BCTL_SPEED1_MASK          ((uint16_t)0x0040U) /*!< The PHY speed bit mask(MSB).*/
37 #define PHY_BCTL_ISOLATE_MASK         ((uint16_t)0x0400U) /*!< The PHY isolate mask.*/
38 #define PHY_BCTL_DUPLEX_MASK          ((uint16_t)0x0100U) /*!< The PHY duplex bit mask. */
39 #define PHY_BCTL_RESTART_AUTONEG_MASK ((uint16_t)0x0200U) /*!< The PHY restart auto negotiation mask. */
40 #define PHY_BCTL_AUTONEG_MASK         ((uint16_t)0x1000U) /*!< The PHY auto negotiation bit mask. */
41 #define PHY_BCTL_SPEED0_MASK          ((uint16_t)0x2000U) /*!< The PHY speed bit mask(LSB). */
42 #define PHY_BCTL_LOOP_MASK            ((uint16_t)0x4000U) /*!< The PHY loop bit mask. */
43 #define PHY_BCTL_RESET_MASK           ((uint16_t)0x8000U) /*!< The PHY reset bit mask. */
44 
45 /*! @brief Defines the mask flag in basic status register(Address 0x01). */
46 #define PHY_BSTATUS_LINKSTATUS_MASK  ((uint16_t)0x0004U) /*!< The PHY link status mask. */
47 #define PHY_BSTATUS_AUTONEGABLE_MASK ((uint16_t)0x0008U) /*!< The PHY auto-negotiation ability mask. */
48 #define PHY_BSTATUS_SPEEDUPLX_MASK   ((uint16_t)0x001CU) /*!< The PHY speed and duplex mask. */
49 #define PHY_BSTATUS_AUTONEGCOMP_MASK ((uint16_t)0x0020U) /*!< The PHY auto-negotiation complete mask. */
50 
51 /*! @brief Defines the mask flag in PHY auto-negotiation advertise register(Address 0x04). */
52 #define PHY_100BaseT4_ABILITY_MASK    ((uint16_t)0x200U) /*!< The PHY have the T4 ability. */
53 #define PHY_100BASETX_FULLDUPLEX_MASK ((uint16_t)0x100U) /*!< The PHY has the 100M full duplex ability.*/
54 #define PHY_100BASETX_HALFDUPLEX_MASK ((uint16_t)0x080U) /*!< The PHY has the 100M full duplex ability.*/
55 #define PHY_10BASETX_FULLDUPLEX_MASK  ((uint16_t)0x040U) /*!< The PHY has the 10M full duplex ability.*/
56 #define PHY_10BASETX_HALFDUPLEX_MASK  ((uint16_t)0x020U) /*!< The PHY has the 10M full duplex ability.*/
57 #define PHY_IEEE802_3_SELECTOR_MASK   ((uint16_t)0x001U) /*!< The message type being sent by Auto-Nego.*/
58 
59 /*! @brief Defines the mask flag in the 1000BASE-T control register(Address 0x09). */
60 #define PHY_1000BASET_FULLDUPLEX_MASK ((uint16_t)0x200U) /*!< The PHY has the 1000M full duplex ability.*/
61 #define PHY_1000BASET_HALFDUPLEX_MASK ((uint16_t)0x100U) /*!< The PHY has the 1000M half duplex ability.*/
62 
63 /*! @brief Defines the IEEE802.3 standard MDIO Manageable Device addresses. */
64 #define PHY_MMD_PMAPMD       (1U)
65 #define PHY_MMD_WIS          (2U)
66 #define PHY_MMD_PCS          (3U)
67 #define PHY_MMD_PHY_XS       (4U)
68 #define PHY_MMD_DTE_XS       (5U)
69 #define PHY_MMD_TC           (6U)
70 #define PHY_MMD_AN           (7U)
71 #define PHY_MMD_PMA1         (8U)
72 #define PHY_MMD_PMA2         (9U)
73 #define PHY_MMD_PMA3         (10U)
74 #define PHY_MMD_PMA4         (11U)
75 #define PHY_MMD_OFDM_PMAPMD  (12U)
76 #define PHY_MMD_POWER_UNIT   (13U)
77 #define PHY_MMD_C22EXT       (29U)
78 #define PHY_MMD_VEND1        (30U)
79 #define PHY_MMD_VEND2        (31U)
80 
81 typedef struct _phy_handle phy_handle_t;
82 typedef struct _phy_config phy_config_t;
83 
84 /*! @brief IEEE 802.3 Clause 22 MDIO write data. */
85 typedef status_t (*mdioWrite)(uint8_t phyAddr, uint8_t regAddr, uint16_t data);
86 
87 /*! @brief IEEE 802.3 Clause 22 MDIO read data. */
88 typedef status_t (*mdioRead)(uint8_t phyAddr, uint8_t regAddr, uint16_t *pData);
89 
90 /*! @brief IEEE 802.3 Clause 45 MDIO write data. */
91 typedef status_t (*mdioWriteExt)(uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t data);
92 
93 /*! @brief IEEE 802.3 Clause 45 MDIO read data. */
94 typedef status_t (*mdioReadExt)(uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t *pData);
95 
96 /*! @brief Defines the PHY link speed. */
97 typedef enum _phy_speed
98 {
99     kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */
100     kPHY_Speed100M,     /*!< ENET PHY 100M speed. */
101     kPHY_Speed1000M,    /*!< ENET PHY 1000M speed. */
102     kPHY_Speed2500M,    /*!< ENET PHY 2.5G speed. */
103     kPHY_Speed5G,       /*!< ENET PHY 5G speed. */
104     kPHY_Speed10G       /*!< ENET PHY 10G speed. */
105 } phy_speed_t;
106 
107 /*! @brief Defines the PHY link duplex. */
108 typedef enum _phy_duplex
109 {
110     kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */
111     kPHY_FullDuplex       /*!< ENET PHY full duplex. */
112 } phy_duplex_t;
113 
114 /*! @brief Defines the PHY loopback mode. */
115 typedef enum _phy_loop
116 {
117     kPHY_LocalLoop = 0U, /*!< ENET PHY local/digital loopback. */
118     kPHY_RemoteLoop,     /*!< ENET PHY remote loopback. */
119     kPHY_ExternalLoop,   /*!< ENET PHY external loopback. */
120 } phy_loop_t;
121 
122 /*! @brief Defines the PHY MMD data access mode. */
123 typedef enum _phy_mmd_access_mode
124 {
125     kPHY_MMDAccessNoPostIncrement = (1U << 14), /*!< ENET PHY MMD access data with no address post increment. */
126     kPHY_MMDAccessRdWrPostIncrement =
127         (2U << 14),                             /*!< ENET PHY MMD access data with Read/Write address post increment. */
128     kPHY_MMDAccessWrPostIncrement = (3U << 14), /*!< ENET PHY MMD access data with Write address post increment. */
129 } phy_mmd_access_mode_t;
130 
131 /*! @brief Defines the PHY interrupt type. */
132 typedef enum _phy_interrupt_type
133 {
134     kPHY_IntrDisable = 0U, /*!< ENET PHY interrupt disable. */
135     kPHY_IntrActiveLow,    /*!< ENET PHY interrupt active low. */
136     kPHY_IntrActiveHigh,   /*!< ENET PHY interrupt active high. */
137 } phy_interrupt_type_t;
138 
139 /*! @brief PHY device operations. */
140 typedef struct _phy_operations
141 {
142     status_t (*phyInit)(phy_handle_t *handle, const phy_config_t *config);
143     status_t (*phyWrite)(phy_handle_t *handle, uint8_t phyReg, uint16_t data);
144     status_t (*phyRead)(phy_handle_t *handle, uint8_t phyReg, uint16_t *pData);
145     status_t (*phyWriteC45)(phy_handle_t *handle, uint8_t devAddr, uint16_t regAddr, uint16_t data);
146     status_t (*phyReadC45)(phy_handle_t *handle, uint8_t devAddr, uint16_t regAddr, uint16_t *pdata);
147     status_t (*getAutoNegoStatus)(phy_handle_t *handle, bool *status);
148     status_t (*getLinkStatus)(phy_handle_t *handle, bool *status);
149     status_t (*getLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
150     status_t (*setLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
151     status_t (*enableLoopback)(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
152     status_t (*enableLinkInterrupt)(phy_handle_t *handle, phy_interrupt_type_t type);
153     status_t (*clearInterrupt)(phy_handle_t *handle);
154 } phy_operations_t;
155 
156 /*! @brief Defines PHY configuration. */
157 struct _phy_config
158 {
159     uint8_t phyAddr;               /*!< PHY address. */
160     void *resource;                /*!< PHY specific resource supporting operation of PHY hardware. */
161     const phy_operations_t *ops;   /*!< PHY operational method. */
162     phy_speed_t speed;             /*!< PHY speed configuration. */
163     phy_duplex_t duplex;           /*!< PHY duplex configuration. */
164     bool autoNeg;                  /*!< PHY auto-negotiation, true: enable, false: disable. */
165     bool enableEEE;                /*!< PHY Energy Efficient Ethernet, true: enable, false: disable. */
166     phy_interrupt_type_t intrType; /*!< PHY interrupt configuration. */
167 };
168 
169 /*! @brief PHY device handle. */
170 struct _phy_handle
171 {
172     uint8_t phyAddr;             /*!< PHY address. */
173     void *resource;              /*!< PHY specific resource supporting operation of PHY hardware. */
174     const phy_operations_t *ops; /*!< PHY operational method. */
175 };
176 
177 /*******************************************************************************
178  * API
179  ******************************************************************************/
180 
181 #if defined(__cplusplus)
182 extern "C" {
183 #endif
184 
185 /*!
186  * @name PHY Driver
187  * @{
188  */
189 
190 /*!
191  * @brief Initializes PHY.
192  * This function initializes PHY.
193  *
194  * @param handle  PHY device handle.
195  * @param config  PHY configuration.
196  * @retval kStatus_Success  PHY initialization succeeds
197  * @retval kStatus_Fail  PHY initialization fails
198  * @retval kStatus_Timeout  PHY MDIO visit time out
199  */
PHY_Init(phy_handle_t * handle,const phy_config_t * config)200 static inline status_t PHY_Init(phy_handle_t *handle, const phy_config_t *config)
201 {
202     handle->ops = config->ops;
203     return handle->ops->phyInit(handle, config);
204 }
205 /*!
206  * @brief PHY Write function.
207  * This function writes data over the MDIO to the specified PHY register.
208  *
209  * @param handle  PHY device handle.
210  * @param phyReg  The PHY register.
211  * @param data    The data written to the PHY register.
212  * @retval kStatus_Success  PHY write success
213  * @retval kStatus_Timeout  PHY MDIO visit time out
214  */
PHY_Write(phy_handle_t * handle,uint8_t phyReg,uint16_t data)215 static inline status_t PHY_Write(phy_handle_t *handle, uint8_t phyReg, uint16_t data)
216 {
217     return handle->ops->phyWrite(handle, phyReg, data);
218 }
219 
220 /*!
221  * @brief PHY Read function.
222  * This interface reads data over the MDIO from the specified PHY register.
223  *
224  * @param handle  PHY device handle.
225  * @param phyReg  The PHY register address.
226  * @param pData  The address to store the data read from the PHY register.
227  * @retval kStatus_Success  PHY read success
228  * @retval kStatus_Timeout  PHY MDIO visit time out
229  */
PHY_Read(phy_handle_t * handle,uint8_t phyReg,uint16_t * pData)230 static inline status_t PHY_Read(phy_handle_t *handle, uint8_t phyReg, uint16_t *pData)
231 {
232     return handle->ops->phyRead(handle, phyReg, pData);
233 }
234 
235 /*!
236  * @brief PHY Write C45 function.
237  * This function writes data over the MDIO to the specified PHY register.
238  *
239  * @param handle  PHY device handle.
240  * @param devAddr  The device address.
241  * @param phyReg  The PHY register.
242  * @param data    The data written to the PHY register.
243  * @retval kStatus_Success  PHY write success
244  * @retval kStatus_Timeout  PHY MDIO visit time out
245  */
PHY_WriteC45(phy_handle_t * handle,uint8_t devAddr,uint8_t phyReg,uint16_t data)246 static inline status_t PHY_WriteC45(phy_handle_t *handle, uint8_t devAddr, uint8_t phyReg, uint16_t data)
247 {
248     return handle->ops->phyWriteC45(handle, devAddr, phyReg, data);
249 }
250 
251 /*!
252  * @brief PHY Read C45 function.
253  * This interface reads data over the MDIO from the specified PHY register.
254  *
255  * @param handle  PHY device handle.
256  * @param devAddr  The device address.
257  * @param phyReg  The PHY register address.
258  * @param pData  The address to store the data read from the PHY register.
259  * @retval kStatus_Success  PHY read success
260  * @retval kStatus_Timeout  PHY MDIO visit time out
261  */
PHY_ReadC45(phy_handle_t * handle,uint8_t devAddr,uint8_t phyReg,uint16_t * pData)262 static inline status_t PHY_ReadC45(phy_handle_t *handle, uint8_t devAddr, uint8_t phyReg, uint16_t *pData)
263 {
264     return handle->ops->phyReadC45(handle, devAddr, phyReg, pData);
265 }
266 
267 /*!
268  * @brief Gets the PHY auto-negotiation status.
269  *
270  * @param handle  PHY device handle.
271  * @param status  The auto-negotiation status of the PHY.
272  *        - true the auto-negotiation is over.
273  *        - false the auto-negotiation is on-going or not started.
274  * @retval kStatus_Success   PHY gets status success
275  * @retval kStatus_Timeout  PHY MDIO visit time out
276  */
PHY_GetAutoNegotiationStatus(phy_handle_t * handle,bool * status)277 static inline status_t PHY_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status)
278 {
279     return handle->ops->getAutoNegoStatus(handle, status);
280 }
281 
282 /*!
283  * @brief Gets the PHY link status.
284  *
285  * @param handle  PHY device handle.
286  * @param status  The link up or down status of the PHY.
287  *        - true the link is up.
288  *        - false the link is down.
289  * @retval kStatus_Success   PHY get link status success
290  * @retval kStatus_Timeout  PHY MDIO visit time out
291  */
PHY_GetLinkStatus(phy_handle_t * handle,bool * status)292 static inline status_t PHY_GetLinkStatus(phy_handle_t *handle, bool *status)
293 {
294     return handle->ops->getLinkStatus(handle, status);
295 }
296 
297 /*!
298  * @brief Gets the PHY link speed and duplex.
299  *
300  * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
301  * and duplex address paramter and set the other as NULL if only wants to get one of them.
302  *
303  * @param handle  PHY device handle.
304  * @param speed   The address of PHY link speed.
305  * @param duplex  The link duplex of PHY.
306  * @retval kStatus_Success   PHY get link speed and duplex success
307  * @retval kStatus_Timeout  PHY MDIO visit time out
308  */
PHY_GetLinkSpeedDuplex(phy_handle_t * handle,phy_speed_t * speed,phy_duplex_t * duplex)309 static inline status_t PHY_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex)
310 {
311     return handle->ops->getLinkSpeedDuplex(handle, speed, duplex);
312 }
313 
314 /*!
315  * @brief Sets the PHY link speed and duplex.
316  *
317  * @param handle  PHY device handle.
318  * @param speed   Specified PHY link speed.
319  * @param duplex  Specified PHY link duplex.
320  * @retval kStatus_Success   PHY gets status success
321  * @retval kStatus_Timeout  PHY MDIO visit time out
322  */
PHY_SetLinkSpeedDuplex(phy_handle_t * handle,phy_speed_t speed,phy_duplex_t duplex)323 static inline status_t PHY_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex)
324 {
325     return handle->ops->setLinkSpeedDuplex(handle, speed, duplex);
326 }
327 
328 /*!
329  * @brief Enables/Disables PHY loopback mode.
330  *
331  * @param handle  PHY device handle.
332  * @param mode    The loopback mode to be enabled, please see "phy_loop_t".
333  * All loopback modes should not be set together, when one loopback mode is set
334  * another should be disabled.
335  * @param speed   PHY speed for loopback mode.
336  * @param enable  True to enable, false to disable.
337  * @retval kStatus_Success   PHY get link speed and duplex success
338  * @retval kStatus_Timeout  PHY MDIO visit time out
339  */
PHY_EnableLoopback(phy_handle_t * handle,phy_loop_t mode,phy_speed_t speed,bool enable)340 static inline status_t PHY_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable)
341 {
342     return handle->ops->enableLoopback(handle, mode, speed, enable);
343 }
344 
345 /*!
346  * @brief Enables/Disables PHY link management interrupt.
347  *
348  * This function controls link status change interrupt. Application should get
349  * status through PHY_GetLinkStatus() and PHY_GetAutoNegotiationStatus() when
350  * interrupt triggers.
351  *
352  * @note Not all PHYs support link up, link down and auto auto-negotiation complete
353  * interrupt separately. Some PHY may combine link up/down or no link up or no
354  * auto-negotiation complete interrupt. The interrupt trigger situation depends
355  * on specific PHY.
356  *
357  * @param handle  PHY device handle.
358  * @param type    PHY interrupt type.
359  * @retval kStatus_Success  PHY enables/disables interrupt success
360  * @retval kStatus_Timeout  PHY MDIO visit time out
361  */
PHY_EnableLinkInterrupt(phy_handle_t * handle,phy_interrupt_type_t type)362 static inline status_t PHY_EnableLinkInterrupt(phy_handle_t *handle, phy_interrupt_type_t type)
363 {
364     return handle->ops->enableLinkInterrupt(handle, type);
365 }
366 
367 /*!
368  * @brief Clears PHY interrupt status.
369  * @note Usually this API clears all interrupts of PHY because related register
370  * flags are read clear.
371  *
372  * @param handle  PHY device handle.
373  * @retval kStatus_Success  PHY read and clear interrupt success
374  * @retval kStatus_Timeout  PHY MDIO visit time out
375  */
PHY_ClearInterrupt(phy_handle_t * handle)376 static inline status_t PHY_ClearInterrupt(phy_handle_t *handle)
377 {
378     return handle->ops->clearInterrupt(handle);
379 }
380 
381 /* @} */
382 
383 #if defined(__cplusplus)
384 }
385 #endif
386 
387 /*! @}*/
388 #endif
389