From: Can Guo <can.guo@oss.qualcomm.com>
To: bvanassche@acm.org, beanhuo@micron.com, peter.wang@mediatek.com,
martin.petersen@oracle.com, mani@kernel.org
Cc: linux-scsi@vger.kernel.org, Can Guo <can.guo@oss.qualcomm.com>,
Alim Akhtar <alim.akhtar@samsung.com>,
Avri Altman <avri.altman@wdc.com>,
"James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>,
Ram Kumar Dwivedi <quic_rdwivedi@quicinc.com>,
Nitin Rawat <quic_nitirawa@quicinc.com>,
linux-kernel@vger.kernel.org (open list)
Subject: [PATCH 2/2] scsi: ufs: core: Add support for static TX Equalization settings
Date: Fri, 1 May 2026 06:44:18 -0700 [thread overview]
Message-ID: <20260501134418.863432-3-can.guo@oss.qualcomm.com> (raw)
In-Reply-To: <20260501134418.863432-1-can.guo@oss.qualcomm.com>
HW design team usually provide static TX Equalization settings based on
PCB board characteristics. The static TX Equalization settings may not be
optimal for all PCBs, but it is better than having nothing when adaptive
TX EQTR is not used. Since the static TX Equalization settings are PCB
board specific, pass the static TX Equalization settings from device tree.
Signed-off-by: Can Guo <can.guo@oss.qualcomm.com>
---
drivers/ufs/core/ufs-txeq.c | 4 +-
drivers/ufs/host/ufshcd-pltfrm.c | 82 ++++++++++++++++++++++++++++++++
include/ufs/ufshcd.h | 5 ++
3 files changed, 90 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/core/ufs-txeq.c b/drivers/ufs/core/ufs-txeq.c
index 4b264adfdf49..634ec039e129 100644
--- a/drivers/ufs/core/ufs-txeq.c
+++ b/drivers/ufs/core/ufs-txeq.c
@@ -1297,7 +1297,7 @@ int ufshcd_config_tx_eq_settings(struct ufs_hba *hba,
}
params = &hba->tx_eq_params[gear - 1];
- if (!params->is_valid || force_tx_eqtr) {
+ if (!params->is_valid || params->is_static || force_tx_eqtr) {
int ret;
ret = ufshcd_tx_eqtr(hba, params, pwr_mode);
@@ -1310,6 +1310,7 @@ int ufshcd_config_tx_eq_settings(struct ufs_hba *hba,
/* Mark TX Equalization settings as valid */
params->is_valid = true;
params->is_trained = true;
+ params->is_static = false;
params->is_applied = false;
}
@@ -1495,6 +1496,7 @@ static void ufshcd_extract_tx_eq_settings_attrs(struct ufs_hba *hba, u8 gear)
}
params->is_valid = true;
+ params->is_static = false;
}
void ufshcd_retrieve_tx_eq_settings(struct ufs_hba *hba)
diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c
index c2dafb583cf5..de6302e8c067 100644
--- a/drivers/ufs/host/ufshcd-pltfrm.c
+++ b/drivers/ufs/host/ufshcd-pltfrm.c
@@ -210,6 +210,86 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
}
}
+static void ufshcd_parse_static_tx_eq_settings(struct ufs_hba *hba)
+{
+ size_t sz = hba->lanes_per_direction * 2 * TX_EQ_SETTINGS_TUPLE_SZ;
+ u32 settings[UFS_MAX_LANES * 2 * TX_EQ_SETTINGS_TUPLE_SZ];
+ u32 *host_settings, *device_settings;
+ u32 lpd = hba->lanes_per_direction;
+ struct ufshcd_tx_eq_params *params;
+ struct device *dev = hba->dev;
+ int i, err, count, gear, lane;
+ char prop_name[MAX_PROP_SIZE];
+
+ if (!lpd || lpd > UFS_MAX_LANES) {
+ dev_err(dev, "Invalid lanes-per-direction value (%u) provided\n", lpd);
+ return;
+ }
+
+ for (gear = UFS_HS_G1; gear <= UFS_HS_GEAR_MAX; gear++) {
+ snprintf(prop_name, MAX_PROP_SIZE, "txeq-settings-g%d", gear);
+ count = of_property_count_u32_elems(dev->of_node, prop_name);
+ if (count <= 0)
+ continue;
+
+ if (count != sz) {
+ dev_err(dev, "Property %s has invalid count (%d), expecting %zu \n",
+ prop_name, count, sz);
+ continue;
+ }
+
+ err = of_property_read_u32_array(dev->of_node, prop_name,
+ settings, sz);
+ if (err) {
+ dev_err(dev, "Failed to read %s property, %d\n",
+ prop_name, err);
+ continue;
+ }
+
+ for (i = 0; i < count; i += TX_EQ_SETTINGS_TUPLE_SZ) {
+ if (settings[i] >= TX_HS_NUM_PRESHOOT) {
+ dev_err(dev, "An invalid TX EQ PreShoot (%d) provided in %s property\n",
+ settings[i], prop_name);
+ break;
+ }
+
+ if (settings[i + 1] >= TX_HS_NUM_DEEMPHASIS) {
+ dev_err(dev, "An invalid TX EQ DeEmphasis (%d) provided in %s property\n",
+ settings[i + 1], prop_name);
+ break;
+ }
+
+ if (settings[i + 2] > 1) {
+ dev_err(dev, "An invalid PrecodeEn (%d) provided in %s property\n",
+ settings[i + 2], prop_name);
+ break;
+ }
+ }
+
+ if (i != count)
+ continue;
+
+ params = &hba->tx_eq_params[gear - 1];
+ host_settings = settings;
+ device_settings = settings + lpd * TX_EQ_SETTINGS_TUPLE_SZ;
+
+ for (lane = 0; lane < lpd; lane++) {
+ params->host[lane].preshoot = host_settings[0];
+ params->host[lane].deemphasis = host_settings[1];
+ params->host[lane].precode_en = host_settings[2];
+ host_settings += TX_EQ_SETTINGS_TUPLE_SZ;
+
+ params->device[lane].preshoot = device_settings[0];
+ params->device[lane].deemphasis = device_settings[1];
+ params->device[lane].precode_en = device_settings[2];
+ device_settings += TX_EQ_SETTINGS_TUPLE_SZ;
+ }
+
+ params->is_valid = true;
+ params->is_static = true;
+ }
+}
+
/**
* ufshcd_parse_clock_min_max_freq - Parse MIN and MAX clocks freq
* @hba: per adapter instance
@@ -528,6 +608,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
ufshcd_init_lanes_per_dir(hba);
+ ufshcd_parse_static_tx_eq_settings(hba);
+
err = ufshcd_parse_operating_points(hba);
if (err) {
dev_err(dev, "%s: OPP parse failed %d\n", __func__, err);
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index f48d6416e299..2d385d42fcff 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -359,6 +359,7 @@ struct ufshcd_tx_eqtr_record {
* @is_valid: True if parameter contains valid TX Equalization settings
* @is_applied: True if settings have been applied to UniPro of both sides
* @is_trained: True if parameters obtained from TX EQTR procedure
+ * @is_static: True if settings are static
*/
struct ufshcd_tx_eq_params {
struct ufshcd_tx_eq_settings host[UFS_MAX_LANES];
@@ -367,8 +368,12 @@ struct ufshcd_tx_eq_params {
bool is_valid;
bool is_applied;
bool is_trained;
+ bool is_static;
};
+/* TX EQ Settings Tuple has 3 elements - PreShoot, DeEmphasis and PrecodeEn. */
+#define TX_EQ_SETTINGS_TUPLE_SZ 3
+
/**
* struct ufs_hba_variant_ops - variant specific callbacks
* @name: variant name
--
2.34.1
prev parent reply other threads:[~2026-05-01 13:44 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260501134418.863432-1-can.guo@oss.qualcomm.com>
2026-05-01 13:44 ` [PATCH 1/2] dt-bindings: ufs: Document static TX Equalization settings properties Can Guo
2026-05-01 17:02 ` Conor Dooley
2026-05-02 9:30 ` Can Guo
2026-05-01 13:44 ` Can Guo [this message]
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=20260501134418.863432-3-can.guo@oss.qualcomm.com \
--to=can.guo@oss.qualcomm.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=alim.akhtar@samsung.com \
--cc=avri.altman@wdc.com \
--cc=beanhuo@micron.com \
--cc=bvanassche@acm.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=mani@kernel.org \
--cc=martin.petersen@oracle.com \
--cc=peter.wang@mediatek.com \
--cc=quic_nitirawa@quicinc.com \
--cc=quic_rdwivedi@quicinc.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