Linux-PHY Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Vladimir Oltean <vladimir.oltean@nxp.com>
To: linux-phy@lists.infradead.org
Cc: Ioana Ciornei <ioana.ciornei@nxp.com>,
	Vinod Koul <vkoul@kernel.org>,
	Kishon Vijay Abraham I <kishon@kernel.org>,
	linux-kernel@vger.kernel.org
Subject: [PATCH phy 11/14] phy: lynx-28g: truly power the lanes up or down
Date: Thu,  4 Sep 2025 18:43:59 +0300	[thread overview]
Message-ID: <20250904154402.300032-12-vladimir.oltean@nxp.com> (raw)
In-Reply-To: <20250904154402.300032-1-vladimir.oltean@nxp.com>

The current procedure for power_off() and power_on() is the same as the
one used for major lane reconfiguration, aka halting. But one can
observe that a halted lane does not cause, for example, the CDR loop of
the link partner to lose lock on its RX stream.

Implement the procedure mentioned in the block guide for powering down
a lane, and then back on.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/phy/freescale/phy-fsl-lynx-28g.c | 78 ++++++++++++++++++------
 1 file changed, 60 insertions(+), 18 deletions(-)

diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 08553ffe273f..5055ddba0363 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -73,9 +73,11 @@
 
 /* Lane a Tx Reset Control Register */
 #define LNaTRSTCTL(lane)			(0x800 + (lane) * 0x100 + 0x20)
-#define LNaTRSTCTL_HLT_REQ			BIT(27)
-#define LNaTRSTCTL_RST_DONE			BIT(30)
 #define LNaTRSTCTL_RST_REQ			BIT(31)
+#define LNaTRSTCTL_RST_DONE			BIT(30)
+#define LNaTRSTCTL_HLT_REQ			BIT(27)
+#define LNaTRSTCTL_STP_REQ			BIT(26)
+#define LNaTRSTCTL_DIS				BIT(24)
 
 /* Lane a Tx General Control Register */
 #define LNaTGCR0(lane)				(0x800 + (lane) * 0x100 + 0x24)
@@ -102,9 +104,11 @@
 
 /* Lane a Rx Reset Control Register */
 #define LNaRRSTCTL(lane)			(0x800 + (lane) * 0x100 + 0x40)
-#define LNaRRSTCTL_HLT_REQ			BIT(27)
-#define LNaRRSTCTL_RST_DONE			BIT(30)
 #define LNaRRSTCTL_RST_REQ			BIT(31)
+#define LNaRRSTCTL_RST_DONE			BIT(30)
+#define LNaRRSTCTL_HLT_REQ			BIT(27)
+#define LNaRRSTCTL_STP_REQ			BIT(26)
+#define LNaRRSTCTL_DIS				BIT(24)
 #define LNaRRSTCTL_CDR_LOCK			BIT(12)
 
 /* Lane a Rx General Control Register */
@@ -660,14 +664,12 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
 	}
 }
 
-static int lynx_28g_power_off(struct phy *phy)
+/* Halting puts the lane in a mode in which it can be reconfigured */
+static void lynx_28g_lane_halt(struct phy *phy)
 {
 	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
 	u32 trstctl, rrstctl;
 
-	if (!lane->powered_up)
-		return 0;
-
 	/* Issue a halt request */
 	lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ,
 			  LNaTRSTCTL_HLT_REQ);
@@ -680,20 +682,13 @@ static int lynx_28g_power_off(struct phy *phy)
 		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
 	} while ((trstctl & LNaTRSTCTL_HLT_REQ) ||
 		 (rrstctl & LNaRRSTCTL_HLT_REQ));
-
-	lane->powered_up = false;
-
-	return 0;
 }
 
-static int lynx_28g_power_on(struct phy *phy)
+static void lynx_28g_lane_reset(struct phy *phy)
 {
 	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
 	u32 trstctl, rrstctl;
 
-	if (lane->powered_up)
-		return 0;
-
 	/* Issue a reset request on the lane */
 	lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ,
 			  LNaTRSTCTL_RST_REQ);
@@ -706,6 +701,52 @@ static int lynx_28g_power_on(struct phy *phy)
 		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
 	} while (!(trstctl & LNaTRSTCTL_RST_DONE) ||
 		 !(rrstctl & LNaRRSTCTL_RST_DONE));
+}
+
+static int lynx_28g_power_off(struct phy *phy)
+{
+	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+	u32 trstctl, rrstctl;
+
+	if (!lane->powered_up)
+		return 0;
+
+	/* Issue a stop request */
+	lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_STP_REQ,
+			  LNaTRSTCTL_STP_REQ);
+	lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_STP_REQ,
+			  LNaRRSTCTL_STP_REQ);
+
+	/* Wait until the stop process is complete */
+	do {
+		trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
+		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
+	} while ((trstctl & LNaTRSTCTL_STP_REQ) ||
+		 (rrstctl & LNaRRSTCTL_STP_REQ));
+
+	/* Power down the RX and TX portions of the lane */
+	lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_DIS,
+			  LNaRRSTCTL_DIS);
+	lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_DIS,
+			  LNaTRSTCTL_DIS);
+
+	lane->powered_up = false;
+
+	return 0;
+}
+
+static int lynx_28g_power_on(struct phy *phy)
+{
+	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+
+	if (lane->powered_up)
+		return 0;
+
+	/* Power up the RX and TX portions of the lane */
+	lynx_28g_lane_rmw(lane, LNaRRSTCTL, 0, LNaRRSTCTL_DIS);
+	lynx_28g_lane_rmw(lane, LNaTRSTCTL, 0, LNaTRSTCTL_DIS);
+
+	lynx_28g_lane_reset(phy);
 
 	lane->powered_up = true;
 
@@ -1035,7 +1076,7 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 	 * the reconfiguration is being done.
 	 */
 	if (powered_up)
-		lynx_28g_power_off(phy);
+		lynx_28g_lane_halt(phy);
 
 	err = lynx_28g_lane_disable_pcvt(lane, lane->mode);
 	if (err)
@@ -1048,8 +1089,9 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 	lane->mode = lane_mode;
 
 out:
+	/* Reset the lane if necessary */
 	if (powered_up)
-		lynx_28g_power_on(phy);
+		lynx_28g_lane_reset(phy);
 
 	return err;
 }
-- 
2.34.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

  parent reply	other threads:[~2025-09-04 19:53 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-04 15:43 [PATCH phy 00/14] Lynx 28G improvements part 1 Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 01/14] phy: lynx-28g: remove LYNX_28G_ prefix from register names Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 02/14] phy: lynx-28g: don't concatenate lynx_28g_lane_rmw() argument "reg" with "val" and "mask" Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 03/14] phy: lynx-28g: use FIELD_GET() and FIELD_PREP() Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 04/14] phy: lynx-28g: convert iowrite32() calls with magic values to macros Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 05/14] phy: lynx-28g: restructure protocol configuration register accesses Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 06/14] phy: lynx-28g: make lynx_28g_set_lane_mode() more systematic Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 07/14] phy: lynx-28g: refactor lane->interface to lane->mode Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 08/14] phy: lynx-28g: distinguish between 10GBASE-R and USXGMII Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 09/14] phy: lynx-28g: configure more equalization params for 1GbE and 10GbE Vladimir Oltean
2025-09-04 15:43 ` [PATCH phy 10/14] phy: lynx-28g: add support for 25GBASER Vladimir Oltean
2025-09-04 15:43 ` Vladimir Oltean [this message]
2025-09-04 15:44 ` [PATCH phy 12/14] phy: lynx-28g: implement phy_exit() operation Vladimir Oltean
2025-09-04 15:44 ` [PATCH phy 13/14] dt-bindings: phy: lynx-28g: add compatible strings per SerDes and instantiation Vladimir Oltean
2025-09-04 19:22   ` Conor Dooley
2025-09-05 10:49     ` Vladimir Oltean
2025-09-05 11:10       ` Josua Mayer
2025-09-05 11:37         ` Vladimir Oltean
2025-09-05 14:23           ` Josua Mayer
2025-09-05 14:44             ` Josua Mayer
2025-09-05 15:29               ` Vladimir Oltean
2025-09-05 15:50                 ` Josua Mayer
2025-09-09 11:37                   ` Vladimir Oltean
2025-09-05 18:58       ` Conor Dooley
2025-09-05  8:29   ` Krzysztof Kozlowski
2025-09-05 11:02     ` Vladimir Oltean
2025-09-05 15:41     ` Vladimir Oltean
2025-09-05 19:02       ` Conor Dooley
2025-09-08  9:37         ` Vladimir Oltean
2025-09-08 14:02           ` Josua Mayer
2025-09-08 15:37             ` Vladimir Oltean
2025-09-08 16:04               ` Josua Mayer
2025-09-09 11:35                 ` Vladimir Oltean
2025-09-09 18:35                   ` Conor Dooley
2025-09-09 18:58                     ` Vladimir Oltean
2025-09-16 17:07                   ` Vladimir Oltean
2025-09-17 10:47                   ` Josua Mayer
2025-09-08 18:39             ` Conor Dooley
2025-09-04 15:44 ` [PATCH phy 14/14] phy: lynx-28g: probe on per-SoC and per-instance compatible strings Vladimir Oltean
2025-09-05 10:41   ` Ioana Ciornei

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250904154402.300032-12-vladimir.oltean@nxp.com \
    --to=vladimir.oltean@nxp.com \
    --cc=ioana.ciornei@nxp.com \
    --cc=kishon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-phy@lists.infradead.org \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox