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