[PATCH net-next 3/3] net: phy: dp83867: Add support for amplitude graph

From: João Rodrigues
Date: Thu Jun 13 2024 - 10:52:23 EST


Output the raw information of each segment.
Each segment also comes with the distance information,
but this does not map to the current output.

Signed-off-by: João Rodrigues <jrodrigues@xxxxxxxxxx>
---
drivers/net/phy/dp83867.c | 86 ++++++++++++++++++++++++++++++++++++---
1 file changed, 80 insertions(+), 6 deletions(-)

diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index ff8c97a29195..e56a892d3da7 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -54,6 +54,8 @@
#define DP83867_RXFSOP2 0x013A
#define DP83867_RXFSOP3 0x013B
#define DP83867_IO_MUX_CFG 0x0170
+#define DP83867_TDR_GEN_CFG2 0x0181
+#define DP83867_TDR_GEN_CFG4 0x0185
#define DP83867_TDR_GEN_CFG5 0x0186
#define DP83867_TDR_GEN_CFG6 0x0187
#define DP83867_TDR_GEN_CFG7 0x0189
@@ -223,6 +225,8 @@ struct dp83867_private {
bool set_clk_output;
u32 clk_output_sel;
bool sgmii_ref_clk_en;
+ bool cable_test_tdr;
+ s8 pair;
};

/* Register values are converted to SNR(dB) as suggested by
@@ -1068,7 +1072,7 @@ static u32 dp83867_cycles2cm(u32 cycles)
return cycles * 8 * 20;
}

-static int dp83867_cable_test_start(struct phy_device *phydev)
+static int dp83867_cable_test_common(struct phy_device *phydev)
{
int ret;

@@ -1082,11 +1086,38 @@ static int dp83867_cable_test_start(struct phy_device *phydev)
if (ret < 0)
return ret;

- ret = phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_TDR_GEN_CFG5,
- DP83867_TDR_GEN_CFG5_FLAGS);
+ return phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_TDR_GEN_CFG5,
+ DP83867_TDR_GEN_CFG5_FLAGS);
+}
+
+static int dp83867_cable_test_start(struct phy_device *phydev)
+{
+ struct dp83867_private *priv = phydev->priv;
+ int ret;
+
+ ret = dp83867_cable_test_common(phydev);
+ if (ret < 0)
+ return ret;
+
+ priv->cable_test_tdr = false;
+
+ return phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG3,
+ DP83867_TDR_START);
+}
+
+static int dp83867_cable_test_tdr_start(struct phy_device *phydev,
+ const struct phy_tdr_config *cfg)
+{
+ struct dp83867_private *priv = phydev->priv;
+ int ret;
+
+ ret = dp83867_cable_test_common(phydev);
if (ret < 0)
return ret;

+ priv->cable_test_tdr = true;
+ priv->pair = cfg->pair;
+
return phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG3,
DP83867_TDR_START);
}
@@ -1105,9 +1136,14 @@ static int dp83867_cable_test_report_trans(struct phy_device *phydev, s8 pair,

for (i = number_peaks; i >= 0; --i) {
if (peak_value[i] > threshold) {
- fault_location =
- dp83867_cycles2cm(peak_location[i] -
+ if (peak_location[i] >= DP83867_TDR_OFFSET) {
+ fault_location = dp83867_cycles2cm(peak_location[i] -
DP83867_TDR_OFFSET) / 2;
+ } else {
+ phydev_dbg(phydev, "Returned TDR fault location is too low");
+ fault_location = dp83867_cycles2cm(peak_location[i]) / 2;
+ }
+
if (peak_sign[i] == 1) {
fault_rslt =
ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
@@ -1208,6 +1244,39 @@ static int dp83867_read_tdr_registers(struct phy_device *phydev, s8 pair,
return 0;
}

+static int dp83867_simplified_amplitude_graph(struct phy_device *phydev)
+{
+ struct dp83867_private *priv = phydev->priv;
+ int peak_sign[5];
+ int peak_loc[ARRAY_SIZE(peak_sign)];
+ int peak_val[ARRAY_SIZE(peak_sign)];
+ int i;
+ int mV;
+ int ret;
+ s8 pair;
+
+ for (pair = ETHTOOL_A_CABLE_PAIR_A; pair <= ETHTOOL_A_CABLE_PAIR_D;
+ pair++) {
+ if (priv->pair != PHY_PAIR_ALL && pair != priv->pair)
+ continue;
+
+ ret = dp83867_read_tdr_registers(phydev, pair, peak_loc,
+ peak_val, peak_sign,
+ ARRAY_SIZE(peak_sign));
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(peak_loc); i++) {
+ mV = peak_val[i];
+ if (peak_sign[i])
+ mV *= -1;
+
+ ethnl_cable_test_amplitude(phydev, pair, mV);
+ }
+ }
+ return 0;
+}
+
static int dp83867_cable_test_report_pair(struct phy_device *phydev, s8 pair)
{
int peak_sign[5];
@@ -1242,6 +1311,7 @@ static int dp83867_cable_test_report(struct phy_device *phydev)
static int dp83867_cable_test_get_status(struct phy_device *phydev,
bool *finished)
{
+ struct dp83867_private *priv = phydev->priv;
int ret;

*finished = false;
@@ -1258,7 +1328,10 @@ static int dp83867_cable_test_get_status(struct phy_device *phydev,
if (ret & DP83867_TDR_FAIL)
return -EBUSY;

- return dp83867_cable_test_report(phydev);
+ if (priv->cable_test_tdr)
+ return dp83867_simplified_amplitude_graph(phydev);
+ else
+ return dp83867_cable_test_report(phydev);
}

static int dp83867_get_sqi(struct phy_device *phydev)
@@ -1478,6 +1551,7 @@ static struct phy_driver dp83867_driver[] = {
.set_loopback = dp83867_loopback,

.cable_test_start = dp83867_cable_test_start,
+ .cable_test_tdr_start = dp83867_cable_test_tdr_start,
.cable_test_get_status = dp83867_cable_test_get_status,

.led_brightness_set = dp83867_led_brightness_set,
--
2.25.1