1 /**
2  * @file
3  *
4  * @brief Public APIs for Ethernet PHY drivers.
5  */
6 
7 /*
8  * Copyright (c) 2021 IP-Logix Inc.
9  * Copyright 2022 NXP
10  * Copyright (c) 2025 Aerlync Labs Inc.
11  *
12  * SPDX-License-Identifier: Apache-2.0
13  */
14 #ifndef ZEPHYR_INCLUDE_DRIVERS_PHY_H_
15 #define ZEPHYR_INCLUDE_DRIVERS_PHY_H_
16 
17 /**
18  * @brief Ethernet PHY Interface
19  * @defgroup ethernet_phy Ethernet PHY Interface
20  * @since 2.7
21  * @version 0.8.0
22  * @ingroup networking
23  * @{
24  */
25 #include <zephyr/types.h>
26 #include <zephyr/device.h>
27 #include <errno.h>
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 /** @brief Ethernet link speeds. */
34 enum phy_link_speed {
35 	/** 10Base-T Half-Duplex */
36 	LINK_HALF_10BASE_T = BIT(0),
37 	/** 10Base-T Full-Duplex */
38 	LINK_FULL_10BASE_T = BIT(1),
39 	/** 100Base-T Half-Duplex */
40 	LINK_HALF_100BASE_T = BIT(2),
41 	/** 100Base-T Full-Duplex */
42 	LINK_FULL_100BASE_T = BIT(3),
43 	/** 1000Base-T Half-Duplex */
44 	LINK_HALF_1000BASE_T = BIT(4),
45 	/** 1000Base-T Full-Duplex */
46 	LINK_FULL_1000BASE_T = BIT(5),
47 	/** 2.5GBase-T Full-Duplex */
48 	LINK_FULL_2500BASE_T = BIT(6),
49 	/** 5GBase-T Full-Duplex */
50 	LINK_FULL_5000BASE_T = BIT(7),
51 };
52 
53 /**
54  * @brief Check if phy link is full duplex.
55  *
56  * @param x Link capabilities
57  *
58  * @return True if link is full duplex, false if not.
59  */
60 #define PHY_LINK_IS_FULL_DUPLEX(x) (x & (BIT(1) | BIT(3) | BIT(5) | BIT(6) | BIT(7)))
61 
62 /**
63  * @brief Check if phy link speed is 1 Gbit/sec.
64  *
65  * @param x Link capabilities
66  *
67  * @return True if link is 1 Gbit/sec, false if not.
68  */
69 #define PHY_LINK_IS_SPEED_1000M(x) (x & (BIT(4) | BIT(5)))
70 
71 /**
72  * @brief Check if phy link speed is 100 Mbit/sec.
73  *
74  * @param x Link capabilities
75  *
76  * @return True if link is 1 Mbit/sec, false if not.
77  */
78 #define PHY_LINK_IS_SPEED_100M(x) (x & (BIT(2) | BIT(3)))
79 
80 /** @brief Link state */
81 struct phy_link_state {
82 	/** Link speed */
83 	enum phy_link_speed speed;
84 	/** When true the link is active and connected */
85 	bool is_up;
86 };
87 
88 /** @brief PLCA (Physical Layer Collision Avoidance) Reconciliation Sublayer configurations */
89 struct phy_plca_cfg {
90 	/** PLCA register map version */
91 	uint8_t version;
92 	/** PLCA configured mode (enable/disable) */
93 	bool enable;
94 	/** PLCA local node identifier */
95 	uint8_t node_id;
96 	/** PLCA node count */
97 	uint8_t node_count;
98 	/** Additional frames a node is allowed to send in single transmit opportunity (TO) */
99 	uint8_t burst_count;
100 	/** Wait time for the MAC to send a new frame before interrupting the burst */
101 	uint8_t burst_timer;
102 	/** PLCA to_timer in bit-times, which determines the PLCA transmit opportunity */
103 	uint8_t to_timer;
104 };
105 
106 /**
107  * @brief      Write PHY PLCA configuration
108  *
109  * This routine provides a generic interface to configure PHY PLCA settings.
110  *
111  * @param[in]  dev       PHY device structure
112  * @param[in]  plca_cfg  Pointer to plca configuration structure
113  *
114  * @retval 0 If successful.
115  * @retval -EIO If communication with PHY failed.
116  */
117 int genphy_get_plca_cfg(const struct device *dev, struct phy_plca_cfg *plca_cfg);
118 
119 /**
120  * @brief      Read PHY PLCA configuration
121  *
122  * This routine provides a generic interface to get PHY PLCA settings.
123  *
124  * @param[in]  dev       PHY device structure
125  * @param      plca_cfg  Pointer to plca configuration structure
126  *
127  * @retval 0 If successful.
128  * @retval -EIO If communication with PHY failed.
129  */
130 int genphy_set_plca_cfg(const struct device *dev, struct phy_plca_cfg *plca_cfg);
131 
132 /**
133  * @brief      Read PHY PLCA status
134  *
135  * This routine provides a generic interface to get PHY PLCA status.
136  *
137  * @param[in]  dev          PHY device structure
138  * @param      plca_status  Pointer to plca status
139  *
140  * @retval 0 If successful.
141  * @retval -EIO If communication with PHY failed.
142  */
143 int genphy_get_plca_sts(const struct device *dev, bool *plca_status);
144 
145 /**
146  * @typedef phy_callback_t
147  * @brief Define the callback function signature for
148  * `phy_link_callback_set()` function.
149  *
150  * @param dev       PHY device structure
151  * @param state     Pointer to link_state structure.
152  * @param user_data Pointer to data specified by user
153  */
154 typedef void (*phy_callback_t)(const struct device *dev, struct phy_link_state *state,
155 			       void *user_data);
156 
157 /**
158  * @cond INTERNAL_HIDDEN
159  *
160  * These are for internal use only, so skip these in
161  * public documentation.
162  */
163 __subsystem struct ethphy_driver_api {
164 	/** Get link state */
165 	int (*get_link)(const struct device *dev, struct phy_link_state *state);
166 
167 	/** Configure link */
168 	int (*cfg_link)(const struct device *dev, enum phy_link_speed adv_speeds);
169 
170 	/** Set callback to be invoked when link state changes. */
171 	int (*link_cb_set)(const struct device *dev, phy_callback_t cb, void *user_data);
172 
173 	/** Read PHY register */
174 	int (*read)(const struct device *dev, uint16_t reg_addr, uint32_t *data);
175 
176 	/** Write PHY register */
177 	int (*write)(const struct device *dev, uint16_t reg_addr, uint32_t data);
178 
179 	/** Read PHY C45 register */
180 	int (*read_c45)(const struct device *dev, uint8_t devad, uint16_t regad, uint16_t *data);
181 
182 	/** Write PHY C45 register */
183 	int (*write_c45)(const struct device *dev, uint8_t devad, uint16_t regad, uint16_t data);
184 
185 	/* Set PLCA settings */
186 	int (*set_plca_cfg)(const struct device *dev, struct phy_plca_cfg *plca_cfg);
187 
188 	/* Get PLCA settings */
189 	int (*get_plca_cfg)(const struct device *dev, struct phy_plca_cfg *plca_cfg);
190 
191 	/* Get PLCA status */
192 	int (*get_plca_sts)(const struct device *dev, bool *plca_sts);
193 };
194 /**
195  * @endcond
196  */
197 
198 /**
199  * @brief      Configure PHY link
200  *
201  * This route configures the advertised link speeds.
202  *
203  * @param[in]  dev     PHY device structure
204  * @param      speeds  OR'd link speeds to be advertised by the PHY
205  *
206  * @retval 0 If successful.
207  * @retval -EIO If communication with PHY failed.
208  * @retval -ENOTSUP If not supported.
209  */
phy_configure_link(const struct device * dev,enum phy_link_speed speeds)210 static inline int phy_configure_link(const struct device *dev, enum phy_link_speed speeds)
211 {
212 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
213 
214 	if (api->cfg_link == NULL) {
215 		return -ENOSYS;
216 	}
217 
218 	return api->cfg_link(dev, speeds);
219 }
220 
221 /**
222  * @brief      Get PHY link state
223  *
224  * Returns the current state of the PHY link. This can be used by
225  * to determine when a link is up and the negotiated link speed.
226  *
227  *
228  * @param[in]  dev    PHY device structure
229  * @param      state  Pointer to receive PHY state
230  *
231  * @retval 0 If successful.
232  * @retval -EIO If communication with PHY failed.
233  */
phy_get_link_state(const struct device * dev,struct phy_link_state * state)234 static inline int phy_get_link_state(const struct device *dev, struct phy_link_state *state)
235 {
236 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
237 
238 	if (api->get_link == NULL) {
239 		return -ENOSYS;
240 	}
241 
242 	return api->get_link(dev, state);
243 }
244 
245 /**
246  * @brief      Set link state change callback
247  *
248  * Sets a callback that is invoked when link state changes. This is the
249  * preferred method for ethernet drivers to be notified of the PHY link
250  * state change.
251  *
252  * @param[in]  dev        PHY device structure
253  * @param      callback   Callback handler
254  * @param      user_data  Pointer to data specified by user.
255  *
256  * @retval 0 If successful.
257  * @retval -ENOTSUP If not supported.
258  */
phy_link_callback_set(const struct device * dev,phy_callback_t callback,void * user_data)259 static inline int phy_link_callback_set(const struct device *dev, phy_callback_t callback,
260 					void *user_data)
261 {
262 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
263 
264 	if (api->link_cb_set == NULL) {
265 		return -ENOSYS;
266 	}
267 
268 	return api->link_cb_set(dev, callback, user_data);
269 }
270 
271 /**
272  * @brief      Read PHY registers
273  *
274  * This routine provides a generic interface to read from a PHY register.
275  *
276  * @param[in]  dev       PHY device structure
277  * @param[in]  reg_addr  Register address
278  * @param      value     Pointer to receive read value
279  *
280  * @retval 0 If successful.
281  * @retval -EIO If communication with PHY failed.
282  */
phy_read(const struct device * dev,uint16_t reg_addr,uint32_t * value)283 static inline int phy_read(const struct device *dev, uint16_t reg_addr, uint32_t *value)
284 {
285 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
286 
287 	if (api->read == NULL) {
288 		return -ENOSYS;
289 	}
290 
291 	return api->read(dev, reg_addr, value);
292 }
293 
294 /**
295  * @brief      Write PHY register
296  *
297  * This routine provides a generic interface to write to a PHY register.
298  *
299  * @param[in]  dev       PHY device structure
300  * @param[in]  reg_addr  Register address
301  * @param[in]  value     Value to write
302  *
303  * @retval 0 If successful.
304  * @retval -EIO If communication with PHY failed.
305  */
phy_write(const struct device * dev,uint16_t reg_addr,uint32_t value)306 static inline int phy_write(const struct device *dev, uint16_t reg_addr, uint32_t value)
307 {
308 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
309 
310 	if (api->write == NULL) {
311 		return -ENOSYS;
312 	}
313 
314 	return api->write(dev, reg_addr, value);
315 }
316 
317 /**
318  * @brief      Read PHY C45 register
319  *
320  * This routine provides a generic interface to read to a PHY C45 register.
321  *
322  * @param[in]  dev       PHY device structure
323  * @param[in]  devad       Device address
324  * @param[in]  regad       Register address
325  * @param      data        Pointer to receive read data
326  *
327  * @retval 0 If successful.
328  * @retval -EIO If communication with PHY failed.
329  */
phy_read_c45(const struct device * dev,uint8_t devad,uint16_t regad,uint16_t * data)330 static inline int phy_read_c45(const struct device *dev, uint8_t devad, uint16_t regad,
331 			       uint16_t *data)
332 {
333 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
334 
335 	if (api->read_c45 == NULL) {
336 		return -ENOSYS;
337 	}
338 
339 	return api->read_c45(dev, devad, regad, data);
340 }
341 
342 /**
343  * @brief      Write PHY C45 register
344  *
345  * This routine provides a generic interface to write to a PHY C45 register.
346  *
347  * @param[in]  dev       PHY device structure
348  * @param[in]  devad       Device address
349  * @param[in]  regad       Register address
350  * @param[in]  data        Data to write
351  *
352  * @retval 0 If successful.
353  * @retval -EIO If communication with PHY failed.
354  */
phy_write_c45(const struct device * dev,uint8_t devad,uint16_t regad,uint16_t data)355 static inline int phy_write_c45(const struct device *dev, uint8_t devad, uint16_t regad,
356 				uint16_t data)
357 {
358 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
359 
360 	if (api->write_c45 == NULL) {
361 		return -ENOSYS;
362 	}
363 
364 	return api->write_c45(dev, devad, regad, data);
365 }
366 
367 /**
368  * @brief      Write PHY PLCA configuration
369  *
370  * This routine provides a generic interface to configure PHY PLCA settings.
371  *
372  * @param[in]  dev       PHY device structure
373  * @param[in]  plca_cfg  Pointer to plca configuration structure
374  *
375  * @retval 0 If successful.
376  * @retval -EIO If communication with PHY failed.
377  */
phy_set_plca_cfg(const struct device * dev,struct phy_plca_cfg * plca_cfg)378 static inline int phy_set_plca_cfg(const struct device *dev, struct phy_plca_cfg *plca_cfg)
379 {
380 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
381 
382 	if (api->set_plca_cfg == NULL) {
383 		return -ENOSYS;
384 	}
385 
386 	return api->set_plca_cfg(dev, plca_cfg);
387 }
388 
389 /**
390  * @brief      Read PHY PLCA configuration
391  *
392  * This routine provides a generic interface to get PHY PLCA settings.
393  *
394  * @param[in]  dev       PHY device structure
395  * @param      plca_cfg  Pointer to plca configuration structure
396  *
397  * @retval 0 If successful.
398  * @retval -EIO If communication with PHY failed.
399  */
phy_get_plca_cfg(const struct device * dev,struct phy_plca_cfg * plca_cfg)400 static inline int phy_get_plca_cfg(const struct device *dev, struct phy_plca_cfg *plca_cfg)
401 {
402 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
403 
404 	if (api->get_plca_cfg == NULL) {
405 		return -ENOSYS;
406 	}
407 
408 	return api->get_plca_cfg(dev, plca_cfg);
409 }
410 
411 /**
412  * @brief      Read PHY PLCA status
413  *
414  * This routine provides a generic interface to get PHY PLCA status.
415  *
416  * @param[in]  dev          PHY device structure
417  * @param      plca_status  Pointer to plca status
418  *
419  * @retval 0 If successful.
420  * @retval -EIO If communication with PHY failed.
421  */
phy_get_plca_sts(const struct device * dev,bool * plca_status)422 static inline int phy_get_plca_sts(const struct device *dev, bool *plca_status)
423 {
424 	const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api;
425 
426 	if (api->get_plca_sts == NULL) {
427 		return -ENOSYS;
428 	}
429 
430 	return api->get_plca_sts(dev, plca_status);
431 }
432 
433 #ifdef __cplusplus
434 }
435 #endif
436 
437 /**
438  * @}
439  */
440 
441 #endif /* ZEPHYR_INCLUDE_DRIVERS_PHY_H_ */
442