diff mbox series

[RFC,net-next,3/8] phy: xgkr: add configuration interface for copper backplane Ethernet PHYs

Message ID 20230817150644.3605105-4-vladimir.oltean@nxp.com (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series Add C72/C73 copper backplane support for LX2160 | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline fail Detected static functions without inline keyword in header files: 1
netdev/build_32bit fail Errors and warnings before: 1435 this patch: 1844
netdev/cc_maintainers success CCed 3 of 3 maintainers
netdev/build_clang success Errors and warnings before: 1378 this patch: 1378
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 1456 this patch: 1865
netdev/checkpatch fail ERROR: inline keyword should sit between storage class and type WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
netdev/kdoc fail Errors and warnings before: 0 this patch: 3
netdev/source_inline success Was 0 now: 0

Commit Message

Vladimir Oltean Aug. 17, 2023, 3:06 p.m. UTC
In Layerscape and QorIQ SoCs, compliance with the backplane Ethernet
protocol is bolted on top of the SerDes lanes using an external IP core,
that is modeled as an Ethernet PHY. This means that dynamic tuning of
the electrical equalization parameters of the link needs to be
communicated with the consumer of the generic PHY.

Create a small layer of glue API between a networking PHY (dealing with
the AN/LT logic for backplanes) and a generic PHY by extending the
phy_configure() API with a new struct phy_configure_opts_xgkr.

There are 2 directions of interest. In the "local TX training", the
generic PHY consumer gets requests over the wire from the link partner
regarding changes we should make to our TX equalization. In the "remote
TX training" direction, the generic PHY is the producer of requests,
based on its RX status, and the generic PHY consumer polls for these
requests until we are happy. Each request is also sent (externally to
the generic PHY layer) to the link partner board, for it to adjust its
TX equalization.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 include/linux/phy/phy-xgkr.h | 165 +++++++++++++++++++++++++++++++++++
 include/linux/phy/phy.h      |   4 +
 2 files changed, 169 insertions(+)
 create mode 100644 include/linux/phy/phy-xgkr.h
diff mbox series

Patch

diff --git a/include/linux/phy/phy-xgkr.h b/include/linux/phy/phy-xgkr.h
new file mode 100644
index 000000000000..8accfb1002a0
--- /dev/null
+++ b/include/linux/phy/phy-xgkr.h
@@ -0,0 +1,165 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2023 NXP
+ */
+
+#ifndef __PHY_XGKR_H_
+#define __PHY_XGKR_H_
+
+struct phy;
+
+enum coef_status {
+	COEF_STAT_NOT_UPDATED = 0,
+	COEF_STAT_UPDATED = 1,
+	COEF_STAT_MIN = 2,
+	COEF_STAT_MAX = 3,
+};
+
+enum coef_update {
+	COEF_UPD_HOLD = 0,
+	COEF_UPD_INC = 1,
+	COEF_UPD_DEC = 2,
+};
+
+struct c72_coef_update {
+	enum coef_update com1;
+	enum coef_update coz;
+	enum coef_update cop1;
+	bool preset;
+	bool init;
+};
+
+struct c72_coef_status {
+	enum coef_status com1;
+	enum coef_status coz;
+	enum coef_status cop1;
+};
+
+enum xgkr_phy_configure_type {
+	XGKR_CONFIGURE_LOCAL_TX,
+	XGKR_CONFIGURE_REMOTE_TX,
+	XGKR_CONFIGURE_LT_DONE,
+};
+
+/* Adjust PHY TX equalization in response to a C72 coefficient
+ * update request from the link partner
+ */
+struct xgkr_phy_configure_local_tx {
+	/* input to PHY */
+	struct c72_coef_update update;
+	/* output from PHY */
+	struct c72_coef_status status;
+};
+
+/* Query the PHY RX quality in order to compute a C72 coefficient update
+ * request to the link partner to improve that. Optional callback to see
+ * how the link partner reacted to the update request (which is echoed back
+ * unmodified). The coefficient status is only valid if there was no error
+ * during its propagation.
+ */
+struct xgkr_phy_configure_remote_tx {
+	/* output from PHY */
+	bool rx_ready;
+	struct c72_coef_update update;
+	/* input to PHY */
+	void (*cb)(void *cb_priv, int err, struct c72_coef_update update,
+		   struct c72_coef_status status);
+	void *cb_priv;
+};
+
+/**
+ * struct phy_configure_opts_xgkr - 10GBase-KR configuration
+ *
+ * This structure is used to represent the configuration state of a
+ * 10GBase-KR Ethernet Copper Backplane PHY.
+ */
+struct phy_configure_opts_xgkr {
+	enum xgkr_phy_configure_type type;
+	union {
+		struct xgkr_phy_configure_local_tx local_tx;
+		struct xgkr_phy_configure_remote_tx remote_tx;
+	};
+};
+
+/* Some helpers */
+static inline enum coef_update coef_update_opposite(enum coef_update update)
+{
+	switch (update) {
+	case COEF_UPD_INC:
+		return COEF_UPD_DEC;
+	case COEF_UPD_DEC:
+		return COEF_UPD_INC;
+	default:
+		return COEF_UPD_HOLD;
+	}
+}
+
+static inline void coef_update_clamp(enum coef_update *update,
+				     enum coef_status status)
+{
+	if (*update == COEF_UPD_INC && status == COEF_STAT_MAX)
+		*update = COEF_UPD_HOLD;
+	if (*update == COEF_UPD_DEC && status == COEF_STAT_MIN)
+		*update = COEF_UPD_HOLD;
+}
+
+static inline bool coef_update_is_all_hold(const struct c72_coef_update *update)
+{
+	return update->coz == COEF_UPD_HOLD &&
+	       update->com1 == COEF_UPD_HOLD &&
+	       update->cop1 == COEF_UPD_HOLD;
+}
+
+#define C72_COEF_UPDATE_BUFSIZ 64
+#define C72_COEF_STATUS_BUFSIZ 64
+
+static inline const char *coef_update_to_string(enum coef_update coef)
+{
+	switch (coef) {
+	case COEF_UPD_HOLD:
+		return "HOLD";
+	case COEF_UPD_INC:
+		return "INC";
+	case COEF_UPD_DEC:
+		return "DEC";
+	default:
+		return "unknown";
+	}
+}
+
+static inline const char *coef_status_to_string(enum coef_status coef)
+{
+	switch (coef) {
+	case COEF_STAT_NOT_UPDATED:
+		return "NOT_UPDATED";
+	case COEF_STAT_UPDATED:
+		return "UPDATED";
+	case COEF_STAT_MIN:
+		return "MIN";
+	case COEF_STAT_MAX:
+		return "MAX";
+	default:
+		return "unknown";
+	}
+}
+
+static void inline c72_coef_update_print(const struct c72_coef_update *update,
+					 char buf[C72_COEF_UPDATE_BUFSIZ])
+{
+	sprintf(buf, "INIT %d, PRESET %d, C(-1) %s, C(0) %s, C(+1) %s",
+		update->init, update->preset,
+		coef_update_to_string(update->com1),
+		coef_update_to_string(update->coz),
+		coef_update_to_string(update->cop1));
+}
+
+static inline void c72_coef_status_print(const struct c72_coef_status *status,
+					 char buf[C72_COEF_STATUS_BUFSIZ])
+{
+	sprintf(buf, "C(-1) %s, C(0) %s, C(+1) %s",
+		coef_status_to_string(status->com1),
+		coef_status_to_string(status->coz),
+		coef_status_to_string(status->cop1));
+}
+
+#endif /* __PHY_XGKR_H_ */
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 7e10761303fc..8ef7de7d2a90 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -19,6 +19,7 @@ 
 #include <linux/phy/phy-dp.h>
 #include <linux/phy/phy-lvds.h>
 #include <linux/phy/phy-mipi-dphy.h>
+#include <linux/phy/phy-xgkr.h>
 
 struct phy;
 
@@ -61,11 +62,14 @@  enum phy_media {
  *		the DisplayPort protocol.
  * @lvds:	Configuration set applicable for phys supporting
  *		the LVDS phy mode.
+ * @xgkr:	Configuration set applicable for phys supporting
+ *		the 10GBase-KR phy mode.
  */
 union phy_configure_opts {
 	struct phy_configure_opts_mipi_dphy	mipi_dphy;
 	struct phy_configure_opts_dp		dp;
 	struct phy_configure_opts_lvds		lvds;
+	struct phy_configure_opts_xgkr		xgkr;
 };
 
 /**