Add include/pcs.h, a interface for Ethernet PCS (Physical Coding Sublayer) devices. A PCS driver provides a struct pcs_ops, and a MAC driver calls it through the pcs_set_config(), pcs_get_state() and pcs_disable() wrappers:
- set_config selects the interface mode, the auto-negotiation type (none, Clause 37 or Clause 73) and the expected speed - get_state reports link, auto-negotiation status and speed - disable stops auto-negotiation and powers the PCS down A PCS is a UCLASS_MISC device. The MAC driver is expected to find it by phandle. Signed-off-by: Akash Nair <[email protected]> --- include/pcs.h | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 include/pcs.h diff --git a/include/pcs.h b/include/pcs.h new file mode 100644 index 00000000000..710b8136d04 --- /dev/null +++ b/include/pcs.h @@ -0,0 +1,140 @@ +/* + * Generic interface of an Ethernet PCS (Physical Coding Sublayer) device + */ + +#ifndef __PCS_H +#define __PCS_H + +#include <dm/device.h> +#include <phy_interface.h> +#include <linux/errno.h> +#include <linux/types.h> + +/** + * enum pcs_an_mode - auto-negotiation used by a PCS + * @PCS_AN_FORCED: no auto-negotiation, the mode and speed are fixed + * @PCS_AN_C73: Clause 73 auto-negotiation (backplane, for example 10GBASE-KR) + * @PCS_AN_C37: Clause 37 auto-negotiation (1000BASE-X) + */ +enum pcs_an_mode { + PCS_AN_FORCED = 0, + PCS_AN_C73, + PCS_AN_C37, +}; + +/** + * struct pcs_config - requested configuration of a PCS + * @iface: interface mode to run. This selects the PCS mode. + * @an_mode: auto-negotiation to use with @iface. It must be one the PCS + * supports for that interface, otherwise the config is rejected. + * @speed_mbps: speed the caller expects for @iface, in Mbit/s. + * 0 means not specified, which is accepted only when @an_mode has + * auto-negotiation, and a mismatch is rejected. A mode without + * auto-negotiation needs the speed given. + */ +struct pcs_config { + phy_interface_t iface; + enum pcs_an_mode an_mode; + int speed_mbps; +}; + +/** + * struct pcs_state - state reported by a PCS + * @link: the link is up + * @an_complete: auto-negotiation has completed. Always false when the mode + * has no auto-negotiation. It does not mean the link is up, so check + * @link as well. + * @speed_mbps: speed of the configured mode, 0 if the PCS is not configured + * or is powered down. It is set as soon as the PCS is configured, not + * when the link comes up, so a non-zero value does not mean the link + * is up. + * + * If the PCS is powered down or not configured all fields stay 0. + * If pcs_get_state() returns an error, @link and @an_complete + * are not valid and should not be used. + */ +struct pcs_state { + bool link; + bool an_complete; + int speed_mbps; +}; + +/** + * struct pcs_ops - operations provided by a PCS driver + * + * @set_config: Configure the PCS for the requested interface mode and + * auto-negotiation type, and start auto-negotiation if the mode uses it. + * Returns 0 on success or a negative error. On error the PCS is left + * unconfigured. It can be called again later, including after @disable. + * @get_state: Read the link status, auto-negotiation status and speed. + * A negative return value means auto-negotiation failed. + * @disable: Stop auto-negotiation and power the PCS down. Calling it again + * has no effect. + */ +struct pcs_ops { + int (*set_config)(struct udevice *dev, const struct pcs_config *cfg); + int (*get_state)(struct udevice *dev, struct pcs_state *state); + int (*disable)(struct udevice *dev); +}; + +#define pcs_get_ops(dev) ((struct pcs_ops *)(dev)->driver->ops) + +/** + * pcs_set_config() - configure a PCS via its driver's set_config op + * @dev: PCS device + * @cfg: requested interface mode, auto-negotiation type and speed + * + * Return: 0 on success, -ENOSYS if the driver has no set_config op, + * or a negative error from the driver. + */ +static inline int pcs_set_config(struct udevice *dev, + const struct pcs_config *cfg) +{ + const struct pcs_ops *ops = pcs_get_ops(dev); + + if (!ops || !ops->set_config) + return -ENOSYS; + + return ops->set_config(dev, cfg); +} + +/** + * pcs_get_state() - read the link and auto-negotiation state of a PCS + * @dev: PCS device + * @state: filled in by the driver, zeroed first + * + * Return: 0 on success, -ENOSYS if the driver has no get_state op, or a + * negative error from the driver. @state is not valid on error. + */ +static inline int pcs_get_state(struct udevice *dev, struct pcs_state *state) +{ + const struct pcs_ops *ops = pcs_get_ops(dev); + + state->link = false; + state->an_complete = false; + state->speed_mbps = 0; + + if (!ops || !ops->get_state) + return -ENOSYS; + + return ops->get_state(dev, state); +} + +/** + * pcs_disable() - stop auto-negotiation and power a PCS down + * @dev: PCS device + * + * Return: 0 on success (also if already disabled), -ENOSYS if the driver has + * no disable op, or a negative error from the driver. + */ +static inline int pcs_disable(struct udevice *dev) +{ + const struct pcs_ops *ops = pcs_get_ops(dev); + + if (!ops || !ops->disable) + return -ENOSYS; + + return ops->disable(dev); +} + +#endif /* __PCS_H */ -- 2.43.0
