[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250904154402.300032-15-vladimir.oltean@nxp.com>
Date: Thu, 4 Sep 2025 18:44:02 +0300
From: Vladimir Oltean <vladimir.oltean@....com>
To: linux-phy@...ts.infradead.org
Cc: Ioana Ciornei <ioana.ciornei@....com>,
Vinod Koul <vkoul@...nel.org>,
Kishon Vijay Abraham I <kishon@...nel.org>,
linux-kernel@...r.kernel.org,
Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
devicetree@...r.kernel.org
Subject: [PATCH phy 14/14] phy: lynx-28g: probe on per-SoC and per-instance compatible strings
There are 3 SerDes blocks on LX2160A and 2 on LX2162A, and they differ
in some aspects, namely in the number of lanes per SerDes and in the
protocol converters instantiated per lane.
All of this justifies introducing compatible strings for each SerDes and
some driver structures for figuring out the differences. The
"fsl,lynx-28g" compatible string is kind of the "maximal configuration".
It corresponds to SerDes 1 of LX2160A. If we were to treat all SerDes
blocks like this one, we would access lanes which do not exist (0-3) and
we would fail to reject lane modes which don't work.
Cc: Rob Herring <robh@...nel.org>
Cc: Krzysztof Kozlowski <krzk+dt@...nel.org>
Cc: Conor Dooley <conor+dt@...nel.org>
Cc: devicetree@...r.kernel.org
Signed-off-by: Vladimir Oltean <vladimir.oltean@....com>
---
drivers/phy/freescale/phy-fsl-lynx-28g.c | 97 +++++++++++++++++++++++-
1 file changed, 93 insertions(+), 4 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 91a3b3928ab4..991587c453df 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -479,9 +479,18 @@ struct lynx_28g_lane {
enum lynx_lane_mode mode;
};
+struct lynx_info {
+ int (*get_pccr)(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr);
+ int (*get_pcvt_offset)(int lane, enum lynx_lane_mode mode);
+ bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
+ int first_lane;
+};
+
struct lynx_28g_priv {
void __iomem *base;
struct device *dev;
+ const struct lynx_info *info;
/* Serialize concurrent access to registers shared between lanes,
* like PCCn
*/
@@ -800,6 +809,79 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
}
}
+static bool lx2160a_serdes1_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return true;
+}
+
+static bool lx2160a_serdes2_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return true;
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ return lane == 6 || lane == 7;
+ default:
+ return false;
+ }
+}
+
+static bool lx2160a_serdes3_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ /*
+ * Non-networking SerDes, and this driver supports only
+ * networking protocols
+ */
+ return false;
+}
+
+static bool lx2162a_serdes1_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return true;
+}
+
+static bool lx2162a_serdes2_lane_supports_mode(int lane,
+ enum lynx_lane_mode mode)
+{
+ return lx2160a_serdes2_lane_supports_mode(lane, mode);
+}
+
+static const struct lynx_info lynx_info_lx2160a_serdes1 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2160a_serdes1_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2160a_serdes2 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2160a_serdes2_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2160a_serdes3 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2160a_serdes3_lane_supports_mode,
+};
+
+static const struct lynx_info lynx_info_lx2162a_serdes1 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2162a_serdes1_lane_supports_mode,
+ .first_lane = 4,
+};
+
+static const struct lynx_info lynx_info_lx2162a_serdes2 = {
+ .get_pccr = lynx_28g_get_pccr,
+ .get_pcvt_offset = lynx_28g_get_pcvt_offset,
+ .lane_supports_mode = lx2162a_serdes2_lane_supports_mode,
+};
+
static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode,
u32 *val)
{
@@ -1202,7 +1284,7 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
u32 rrstctl;
int i;
- for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
lane = &priv->lane[i];
mutex_lock(&lane->phy->mutex);
@@ -1258,7 +1340,8 @@ static struct phy *lynx_28g_xlate(struct device *dev,
struct lynx_28g_priv *priv = dev_get_drvdata(dev);
int idx = args->args[0];
- if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
+ if (WARN_ON(idx >= LYNX_28G_NUM_LANE ||
+ idx < priv->info->first_lane))
return ERR_PTR(-EINVAL);
return priv->lane[idx].phy;
@@ -1275,6 +1358,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->dev = &pdev->dev;
+ priv->info = of_device_get_match_data(dev);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
@@ -1282,7 +1366,7 @@ static int lynx_28g_probe(struct platform_device *pdev)
lynx_28g_pll_read_configuration(priv);
- for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
struct lynx_28g_lane *lane = &priv->lane[i];
struct phy *phy;
@@ -1322,7 +1406,12 @@ static void lynx_28g_remove(struct platform_device *pdev)
}
static const struct of_device_id lynx_28g_of_match_table[] = {
- { .compatible = "fsl,lynx-28g" },
+ { .compatible = "fsl,lx2160a-serdes1", .data = &lynx_info_lx2160a_serdes1 },
+ { .compatible = "fsl,lx2160a-serdes2", .data = &lynx_info_lx2160a_serdes2 },
+ { .compatible = "fsl,lx2160a-serdes3", .data = &lynx_info_lx2160a_serdes3 },
+ { .compatible = "fsl,lx2162a-serdes1", .data = &lynx_info_lx2162a_serdes1 },
+ { .compatible = "fsl,lx2162a-serdes2", .data = &lynx_info_lx2162a_serdes2 },
+ { .compatible = "fsl,lynx-28g", .data = &lynx_info_lx2160a_serdes1 }, /* fallback */
{ },
};
MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
--
2.34.1
Powered by blists - more mailing lists