drivers: Add Ethernet PHY API
This commit adds support for Ethernet PHY drivers via a PHY API. It also includes a driver for a generic MII compliant PHY which supports most PHYs on the market. Separating PHY driver from the SoC specific Ethernet driver simplifies the Ethernet driver code and enables code re-use. Drivers for specific PHYs with more advanced features, such as RGMII delay in PHY can be developed independent of the Ethernet MAC driver. Signed-off-by: Arvin Farahmand <arvinf@ip-logix.com>
This commit is contained in:
parent
2bec7587e9
commit
f845cddcf7
9 changed files with 749 additions and 0 deletions
231
include/net/phy.h
Normal file
231
include/net/phy.h
Normal file
|
@ -0,0 +1,231 @@
|
|||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Public APIs for Ethernet PHY drivers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 IP-Logix Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_PHY_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_PHY_H_
|
||||
|
||||
/**
|
||||
* @brief Ethernet PHY Interface
|
||||
* @defgroup ethernet_phy Ethernet PHY Interface
|
||||
* @ingroup networking
|
||||
* @{
|
||||
*/
|
||||
#include <zephyr/types.h>
|
||||
#include <device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Ethernet link speeds. */
|
||||
enum phy_link_speed {
|
||||
/** 10Base-T Half-Duplex */
|
||||
LINK_HALF_10BASE_T = BIT(0),
|
||||
/** 10Base-T Full-Duplex */
|
||||
LINK_FULL_10BASE_T = BIT(1),
|
||||
/** 100Base-T Half-Duplex */
|
||||
LINK_HALF_100BASE_T = BIT(2),
|
||||
/** 100Base-T Full-Duplex */
|
||||
LINK_FULL_100BASE_T = BIT(3),
|
||||
};
|
||||
|
||||
#define PHY_LINK_IS_FULL_DUPLEX(x) (x & (BIT(1) | BIT(3)))
|
||||
#define PHY_LINK_IS_SPEED_100M(x) (x & (BIT(2) | BIT(3)))
|
||||
|
||||
/** @brief Link state */
|
||||
struct phy_link_state {
|
||||
/** Link speed */
|
||||
enum phy_link_speed speed;
|
||||
/** When true the link is active and connected */
|
||||
bool is_up;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef phy_callback_t
|
||||
* @brief Define the callback function signature for
|
||||
* `phy_link_callback_set()` function.
|
||||
*
|
||||
* @param dev PHY device structure
|
||||
* @param state Pointer to link_state structure.
|
||||
* @param user_data Pointer to data specified by user
|
||||
*/
|
||||
typedef void (*phy_callback_t)(const struct device *dev,
|
||||
struct phy_link_state *state,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @cond INTERNAL_HIDDEN
|
||||
*
|
||||
* These are for internal use only, so skip these in
|
||||
* public documentation.
|
||||
*/
|
||||
__subsystem struct ethphy_driver_api {
|
||||
/** Get link state */
|
||||
int (*get_link)(const struct device *dev,
|
||||
struct phy_link_state *state);
|
||||
|
||||
/** Configure link */
|
||||
int (*cfg_link)(const struct device *dev,
|
||||
enum phy_link_speed adv_speeds);
|
||||
|
||||
/** Set callback to be invoked when link state changes. */
|
||||
int (*link_cb_set)(const struct device *dev, phy_callback_t cb,
|
||||
void *user_data);
|
||||
|
||||
/** Read PHY register */
|
||||
int (*read)(const struct device *dev, uint16_t reg_addr,
|
||||
uint32_t *data);
|
||||
|
||||
/** Write PHY register */
|
||||
int (*write)(const struct device *dev, uint16_t reg_addr,
|
||||
uint32_t data);
|
||||
};
|
||||
/**
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Configure PHY link
|
||||
*
|
||||
* This route configures the advertised link speeds.
|
||||
*
|
||||
* @param[in] dev PHY device structure
|
||||
* @param speeds OR'd link speeds to be advertised by the PHY
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EIO If communication with PHY failed.
|
||||
* @retval -ENOTSUP If not supported.
|
||||
*/
|
||||
__syscall int phy_configure_link(const struct device *dev,
|
||||
enum phy_link_speed speeds);
|
||||
|
||||
static inline int z_impl_phy_configure_link(const struct device *dev,
|
||||
enum phy_link_speed speeds)
|
||||
{
|
||||
const struct ethphy_driver_api *api =
|
||||
(const struct ethphy_driver_api *)dev->api;
|
||||
|
||||
return api->cfg_link(dev, speeds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get PHY link state
|
||||
*
|
||||
* Returns the current state of the PHY link. This can be used by
|
||||
* to determine when a link is up and the negotiated link speed.
|
||||
*
|
||||
*
|
||||
* @param[in] dev PHY device structure
|
||||
* @param state Pointer to receive PHY state
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EIO If communication with PHY failed.
|
||||
*/
|
||||
__syscall int phy_get_link_state(const struct device *dev,
|
||||
struct phy_link_state *state);
|
||||
|
||||
static inline int z_impl_phy_get_link_state(const struct device *dev,
|
||||
struct phy_link_state *state)
|
||||
{
|
||||
const struct ethphy_driver_api *api =
|
||||
(const struct ethphy_driver_api *)dev->api;
|
||||
|
||||
return api->get_link(dev, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set link state change callback
|
||||
*
|
||||
* Sets a callback that is invoked when link state changes. This is the
|
||||
* preferred method for ethernet drivers to be notified of the PHY link
|
||||
* state change.
|
||||
*
|
||||
* @param[in] dev PHY device structure
|
||||
* @param callback Callback handler
|
||||
* @param user_data Pointer to data specified by user.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -ENOTSUP If not supported.
|
||||
*/
|
||||
__syscall int phy_link_callback_set(const struct device *dev,
|
||||
phy_callback_t callback,
|
||||
void *user_data);
|
||||
|
||||
static inline int z_impl_phy_link_callback_set(const struct device *dev,
|
||||
phy_callback_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
const struct ethphy_driver_api *api =
|
||||
(const struct ethphy_driver_api *)dev->api;
|
||||
|
||||
return api->link_cb_set(dev, callback, user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read PHY registers
|
||||
*
|
||||
* This routine provides a generic interface to read from a PHY register.
|
||||
*
|
||||
* @param[in] dev PHY device structure
|
||||
* @param[in] reg_addr Register address
|
||||
* @param value Pointer to receive read value
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EIO If communication with PHY failed.
|
||||
*/
|
||||
__syscall int phy_read(const struct device *dev, uint16_t reg_addr,
|
||||
uint32_t *value);
|
||||
|
||||
static inline int z_impl_phy_read(const struct device *dev, uint16_t reg_addr,
|
||||
uint32_t *value)
|
||||
{
|
||||
const struct ethphy_driver_api *api =
|
||||
(const struct ethphy_driver_api *)dev->api;
|
||||
|
||||
return api->read(dev, reg_addr, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write PHY register
|
||||
*
|
||||
* This routine provides a generic interface to write to a PHY register.
|
||||
*
|
||||
* @param[in] dev PHY device structure
|
||||
* @param[in] reg_addr Register address
|
||||
* @param[in] value Value to write
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EIO If communication with PHY failed.
|
||||
*/
|
||||
__syscall int phy_write(const struct device *dev, uint16_t reg_addr,
|
||||
uint32_t value);
|
||||
|
||||
static inline int z_impl_phy_write(const struct device *dev, uint16_t reg_addr,
|
||||
uint32_t value)
|
||||
{
|
||||
const struct ethphy_driver_api *api =
|
||||
(const struct ethphy_driver_api *)dev->api;
|
||||
|
||||
return api->write(dev, reg_addr, value);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <syscalls/phy.h>
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_PHY_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue