Devicetree
 help / color / mirror / Atom feed
From: Larisa Grigore <larisa.grigore@oss.nxp.com>
To: Larisa Grigore <larisa.grigore@oss.nxp.com>,
	NXP S32 Linux Team <s32@nxp.com>,
	Alim Akhtar <alim.akhtar@samsung.com>,
	Avri Altman <avri.altman@sandisk.com>,
	Bart Van Assche <bvanassche@acm.org>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>, Frank Li <Frank.Li@nxp.com>,
	Sascha Hauer <s.hauer@pengutronix.de>,
	Pengutronix Kernel Team <kernel@pengutronix.de>,
	Fabio Estevam <festevam@gmail.com>,
	"James E . J . Bottomley" <James.Bottomley@HansenPartnership.com>,
	"Martin K . Petersen" <martin.petersen@oracle.com>,
	Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>,
	Ajay Neeli <ajay.neeli@amd.com>,
	Manivannan Sadhasivam <mani@kernel.org>,
	Pedro Sousa <pedrom.sousa@synopsys.com>,
	clizzi@redhat.com, aruizrui@redhat.com, eballetb@redhat.com,
	echanude@redhat.com
Cc: linux-scsi@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, imx@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org
Subject: [PATCH 03/10] ufs: host: Add common Hibern8 TX FSM polling helper
Date: Wed, 26 Aug 2026 15:40:41 +0200	[thread overview]
Message-ID: <20260826134048.854748-4-larisa.grigore@oss.nxp.com> (raw)
In-Reply-To: <20260826134048.854748-1-larisa.grigore@oss.nxp.com>

Factor out the common logic used to poll TX_FSM_STATE until the TX lanes
enter Hibern8 into ufshcd_check_hibern8().

The HiSilicon and Qualcomm drivers currently implement similar checks
using the UniPro TX_FSM_STATE attribute after link/PHY bring-up. Move
this logic to a common helper in ufshcd-pltfrm so it can be shared
across host controller drivers.

Switch the HiSilicon and Qualcomm drivers to use the new helper and drop
their local implementations.

This also prepares for reusing the same UniPro-specific Hibern8 check in
a subsequent commit.

Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
 drivers/ufs/host/ufs-hisi.c      | 48 +------------------
 drivers/ufs/host/ufs-qcom.c      | 42 +----------------
 drivers/ufs/host/ufshcd-pltfrm.c | 79 ++++++++++++++++++++++++++++++++
 drivers/ufs/host/ufshcd-pltfrm.h |  2 +
 4 files changed, 84 insertions(+), 87 deletions(-)

diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c
index bd223bda1ce2..76d77bc30322 100644
--- a/drivers/ufs/host/ufs-hisi.c
+++ b/drivers/ufs/host/ufs-hisi.c
@@ -22,50 +22,6 @@
 #include <ufs/ufshci.h>
 #include <ufs/ufs_quirks.h>
 
-static int ufs_hisi_check_hibern8(struct ufs_hba *hba)
-{
-	int err = 0;
-	u32 tx_fsm_val_0 = 0;
-	u32 tx_fsm_val_1 = 0;
-	unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS);
-
-	do {
-		err = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(TX_FSM_STATE, 0),
-				      &tx_fsm_val_0);
-		err |= ufshcd_dme_get(hba,
-		    UIC_ARG_MIB_SEL(TX_FSM_STATE, 1), &tx_fsm_val_1);
-		if (err || (tx_fsm_val_0 == TX_STATE_HIBERN8 &&
-			tx_fsm_val_1 == TX_STATE_HIBERN8))
-			break;
-
-		/* sleep for max. 200us */
-		usleep_range(100, 200);
-	} while (time_before(jiffies, timeout));
-
-	/*
-	 * we might have scheduled out for long during polling so
-	 * check the state again.
-	 */
-	if (time_after(jiffies, timeout)) {
-		err = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(TX_FSM_STATE, 0),
-				     &tx_fsm_val_0);
-		err |= ufshcd_dme_get(hba,
-		 UIC_ARG_MIB_SEL(TX_FSM_STATE, 1), &tx_fsm_val_1);
-	}
-
-	if (err) {
-		dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
-			__func__, err);
-	} else if (tx_fsm_val_0 != TX_STATE_HIBERN8 ||
-			 tx_fsm_val_1 != TX_STATE_HIBERN8) {
-		err = -1;
-		dev_err(hba->dev, "%s: invalid TX_FSM_STATE, lane0 = %d, lane1 = %d\n",
-			__func__, tx_fsm_val_0, tx_fsm_val_1);
-	}
-
-	return err;
-}
-
 static void ufs_hisi_clk_init(struct ufs_hba *hba)
 {
 	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
@@ -224,9 +180,9 @@ static int ufs_hisi_link_startup_pre_change(struct ufs_hba *hba)
 
 	/* Unipro VS_mphy_disable */
 	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0C1, 0x0), 0x0);
-	err = ufs_hisi_check_hibern8(hba);
+	err = ufshcd_check_hibern8(hba, 2, HBRN8_POLL_TOUT_MS);
 	if (err)
-		dev_err(hba->dev, "ufs_hisi_check_hibern8 error\n");
+		dev_err(hba->dev, "hibern8 TX FSM check failed\n");
 
 	if (!(host->caps & UFS_HISI_CAP_PHY10nm))
 		ufshcd_writel(hba, UFS_HCLKDIV_NORMAL_VALUE, UFS_REG_HCLKDIV);
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index b2081ed6197a..c94488661bcf 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -382,46 +382,6 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
 	return 0;
 }
 
-static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
-{
-	int err;
-	u32 tx_fsm_val;
-	unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS);
-
-	do {
-		err = ufshcd_dme_get(hba,
-				UIC_ARG_MIB_SEL(TX_FSM_STATE,
-					UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
-				&tx_fsm_val);
-		if (err || tx_fsm_val == TX_STATE_HIBERN8)
-			break;
-
-		/* sleep for max. 200us */
-		usleep_range(100, 200);
-	} while (time_before(jiffies, timeout));
-
-	/*
-	 * we might have scheduled out for long during polling so
-	 * check the state again.
-	 */
-	if (time_after(jiffies, timeout))
-		err = ufshcd_dme_get(hba,
-				UIC_ARG_MIB_SEL(TX_FSM_STATE,
-					UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
-				&tx_fsm_val);
-
-	if (err) {
-		dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
-				__func__, err);
-	} else if (tx_fsm_val != TX_STATE_HIBERN8) {
-		err = tx_fsm_val;
-		dev_err(hba->dev, "%s: invalid TX_FSM_STATE = %d\n",
-				__func__, err);
-	}
-
-	return err;
-}
-
 static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host)
 {
 	ufshcd_rmwl(host->hba, QUNIPRO_SEL, QUNIPRO_SEL, REG_UFS_CFG1);
@@ -607,7 +567,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
 		break;
 	case POST_CHANGE:
 		/* check if UFS PHY moved from DISABLED to HIBERN8 */
-		err = ufs_qcom_check_hibern8(hba);
+		err = ufshcd_check_hibern8(hba, 1, HBRN8_POLL_TOUT_MS);
 		ufs_qcom_enable_hw_clk_gating(hba);
 		ufs_qcom_ice_enable(host);
 		ufs_qcom_config_ice_allocator(host);
diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c
index c2dafb583cf5..034ee988924a 100644
--- a/drivers/ufs/host/ufshcd-pltfrm.c
+++ b/drivers/ufs/host/ufshcd-pltfrm.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
@@ -563,6 +564,84 @@ void ufshcd_pltfrm_remove(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_remove);
 
+/**
+ * ufshcd_check_hibern8 - Check if all TX lanes entered Hibern8 state
+ * @hba: host controller instance
+ * @num_lanes: number of TX lanes to check
+ * @timeout_ms: timeout in milliseconds for all lanes
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int ufshcd_check_hibern8(struct ufs_hba *hba, unsigned int num_lanes,
+			 unsigned int timeout_ms)
+{
+	unsigned long timeout;
+	u32 tx_fsm_val = 0;
+	unsigned int i;
+	bool success;
+	int err;
+
+	if (!num_lanes)
+		return -EINVAL;
+
+	timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+	do {
+		success = true;
+
+		for (i = 0; i < num_lanes; i++) {
+			err = ufshcd_dme_get(hba,
+					UIC_ARG_MIB_SEL(TX_FSM_STATE,
+						UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
+					&tx_fsm_val);
+			if (err) {
+				dev_err(hba->dev,
+						"%s: unable to get TX_FSM_STATE for lane %u, err %d\n",
+						__func__, i, err);
+				return err;
+			}
+
+			if (tx_fsm_val != TX_STATE_HIBERN8) {
+				success = false;
+				break;
+			}
+		}
+
+		if (success)
+			return 0;
+
+		/* sleep for max. 200us */
+		usleep_range(100, 200);
+	} while (time_before(jiffies, timeout));
+
+	/*
+	 * We might have been scheduled out for long during polling, so do
+	 * one final check before reporting timeout.
+	 */
+	for (i = 0; i < num_lanes; i++) {
+		err = ufshcd_dme_get(hba,
+				UIC_ARG_MIB_SEL(TX_FSM_STATE,
+					UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
+				&tx_fsm_val);
+		if (err) {
+			dev_err(hba->dev,
+					"%s: unable to get TX_FSM_STATE for lane %u, err %d\n",
+					__func__, i, err);
+			return err;
+		}
+
+		if (tx_fsm_val != TX_STATE_HIBERN8) {
+			dev_err(hba->dev,
+					"%s: timeout waiting for lane %u to enter HIBERN8, TX_FSM_STATE=%u\n",
+					__func__, i, tx_fsm_val);
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ufshcd_check_hibern8);
+
 MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
 MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
 MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h
index 0a18a8aed94d..ec2a8013e975 100644
--- a/drivers/ufs/host/ufshcd-pltfrm.h
+++ b/drivers/ufs/host/ufshcd-pltfrm.h
@@ -35,5 +35,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
 void ufshcd_pltfrm_remove(struct platform_device *pdev);
 int ufshcd_populate_vreg(struct device *dev, const char *name,
 			 struct ufs_vreg **out_vreg, bool skip_current);
+int ufshcd_check_hibern8(struct ufs_hba *hba, unsigned int num_lanes,
+			 unsigned int timeout_ms);
 
 #endif /* UFSHCD_PLTFRM_H_ */
-- 
2.43.0


  parent reply	other threads:[~2026-08-26 13:41 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26 13:40 [PATCH 00/10] Add S32N79RDB UFS support Larisa Grigore
2026-08-26 13:40 ` [PATCH 01/10] ufs: unipro: Move Tx/Rx FSM state definitions to unipro.h Larisa Grigore
2026-08-26 15:05   ` Frank Li
2026-08-27 13:59     ` Larisa Ileana Grigore
2026-08-26 13:40 ` [PATCH 02/10] ufs: unipro: Add TX/RX FSM state attributes Larisa Grigore
2026-08-26 15:09   ` Frank Li
2026-08-26 13:40 ` Larisa Grigore [this message]
2026-08-26 15:17   ` [PATCH 03/10] ufs: host: Add common Hibern8 TX FSM polling helper Frank Li
2026-08-26 15:33   ` Bart Van Assche
2026-08-27 14:03     ` Larisa Ileana Grigore
2026-08-27  9:14   ` Bough Chen
2026-08-27 14:10     ` Larisa Ileana Grigore
2026-08-27 15:00   ` Stanley Jhu
2026-08-26 13:40 ` [PATCH 04/10] scsi: ufs: Move Versal2 M-PHY CREG access helpers into ufshcd-dwc Larisa Grigore
2026-08-26 15:20   ` Frank Li
2026-08-27 14:11     ` Larisa Ileana Grigore
2026-08-26 15:36   ` Bart Van Assche
2026-08-27 14:13     ` Larisa Ileana Grigore
2026-08-27 10:47   ` Bough Chen
2026-08-26 13:40 ` [PATCH 05/10] scsi: ufs: dwc: Export common clock divider and link status helpers Larisa Grigore
2026-08-26 15:22   ` Frank Li
2026-08-26 13:40 ` [PATCH 06/10] dt-bindings: ufs: Add compatibles for S32N79 Host Controller platform driver Larisa Grigore
2026-08-26 14:35   ` Frank Li
2026-08-26 15:57     ` Conor Dooley
2026-08-27 14:37       ` Larisa Ileana Grigore
2026-08-27 14:36     ` Larisa Ileana Grigore
2026-08-27 14:45       ` Frank Li
2026-08-27 15:09         ` Larisa Ileana Grigore
2026-08-26 13:40 ` [PATCH 07/10] scsi: ufs: Add NXP S32N79 UFS host controller driver Larisa Grigore
2026-08-26 14:01   ` sashiko-bot
2026-08-26 15:49   ` Frank Li
2026-08-27 14:44     ` Larisa Ileana Grigore
2026-08-26 13:40 ` [PATCH 08/10] arm64: dts: freescale: s32n79: Add UFS host controller Larisa Grigore
2026-08-26 13:40 ` [PATCH 09/10] arm64: dts: freescale: s32n79-rdb: Enable UFS Larisa Grigore
2026-08-26 13:40 ` [PATCH 10/10] MAINTAINERS: Add NXP S32N7 UFS host controller entry Larisa Grigore

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=20260826134048.854748-4-larisa.grigore@oss.nxp.com \
    --to=larisa.grigore@oss.nxp.com \
    --cc=Frank.Li@nxp.com \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=ajay.neeli@amd.com \
    --cc=alim.akhtar@samsung.com \
    --cc=aruizrui@redhat.com \
    --cc=avri.altman@sandisk.com \
    --cc=bvanassche@acm.org \
    --cc=clizzi@redhat.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=eballetb@redhat.com \
    --cc=echanude@redhat.com \
    --cc=festevam@gmail.com \
    --cc=imx@lists.linux.dev \
    --cc=kernel@pengutronix.de \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=mani@kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=pedrom.sousa@synopsys.com \
    --cc=robh@kernel.org \
    --cc=s.hauer@pengutronix.de \
    --cc=s32@nxp.com \
    --cc=sai.krishna.potthuri@amd.com \
    /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