2023-11-29 08:29:49

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 00/10] Enable HS-G5 support on SM8550

This series enables HS-G5 support on SM8550.

This series is rebased on below changes from Mani -
https://patchwork.kernel.org/project/linux-scsi/patch/[email protected]/
https://patchwork.kernel.org/project/linux-scsi/patch/[email protected]/

This series is tested on below HW combinations -
SM8550 MTP + UFS4.0
SM8550 QRD + UFS3.1
SM8450 MTP + UFS3.1 (for regression test)
SM8350 MTP + UFS3.1 (for regression test)

Note that during reboot test on above platforms, I occasinally hit PA (PHY)
error during the 2nd init, this is not related with this series. A fix for
this is mentioned in below patchwork -

https://patchwork.kernel.org/project/linux-scsi/patch/[email protected]/

Also note that on platforms, which have two sets of UFS PHY settings are
provided (say G4 and no-G4, G5 and no-G5). The two sets of PHY settings are
basically programming different values to different registers, mixing the
two sets and/or overwriting one set with another set is definitely not
blessed by UFS PHY designers. For SM8550, this series will make sure we
honor the rule. However, for old targets Mani and I will fix them in
another series in future.

v5 -> v6:
1. Rebased on scsi-queue-6.8
2. Addressed comments from Dmitry and Mani in patches to phy-qcom-qmp-ufs.c

v4 -> v5:
Removed two useless debug prints in patch #9

v3 -> v4:
Used .tbls_hs_overlay array instead of adding more tables with different names like .tbls_hs_g5

v2 -> v3:
1. Addressed comments from Andrew, Mani and Bart in patch #1
2. Added patch #2 as per request from Andrew and Mani
3. Added patch #4 to fix a common issue on old targets, it is not necessary
for this series, but put in this series only because it would be easier
to maintain and no need to rebase
4. Addressed comments from Dmitry and Mani in patches to phy-qcom-qmp-ufs.c

v1 -> v2:
1. Removed 2 changes which were exposing power info in sysfs
2. Removed 1 change which was moving data structs to phy-qcom-qmp-ufs.h
3. Added one new change (the 1st one) to clean up usage of ufs_dev_params based on comments from Mani
4. Adjusted the logic of UFS device version detection according to comments from Mani:
4.1 For HW version < 0x5, go through dual init
4.2 For HW version >= 0x5
a. If UFS device version is populated, one init is required
b. If UFS device version is not populated, go through dual init


Bao D. Nguyen (1):
scsi: ufs: ufs-qcom: Add support for UFS device version detection

Can Guo (9):
scsi: ufs: host: Rename structure ufs_dev_params to ufs_host_params
scsi: ufs: ufs-qcom: No need to set hs_rate after
ufshcd_init_host_param()
scsi: ufs: ufs-qcom: Setup host power mode during init
scsi: ufs: ufs-qcom: Allow the first init start with the maximum
supported gear
scsi: ufs: ufs-qcom: Limit HS-G5 Rate-A to hosts with HW version 5
scsi: ufs: ufs-qcom: Set initial PHY gear to max HS gear for HW ver 4
and newer
phy: qualcomm: phy-qcom-qmp-ufs: Rectify SM8550 UFS HS-G4 PHY Settings
phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for
SM8550
scsi: ufs: ufs-qcom: Check return value of phy_set_mode_ext()

drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 2 +
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h | 2 +
.../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 12 ++
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 192 ++++++++++++++++++---
drivers/ufs/host/ufs-exynos.c | 7 +-
drivers/ufs/host/ufs-hisi.c | 11 +-
drivers/ufs/host/ufs-mediatek.c | 12 +-
drivers/ufs/host/ufs-qcom.c | 90 +++++++---
drivers/ufs/host/ufs-qcom.h | 5 +-
drivers/ufs/host/ufshcd-pltfrm.c | 69 ++++----
drivers/ufs/host/ufshcd-pltfrm.h | 10 +-
11 files changed, 306 insertions(+), 106 deletions(-)

--
2.7.4


2023-11-29 08:30:04

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 10/10] scsi: ufs: ufs-qcom: Add support for UFS device version detection

From: "Bao D. Nguyen" <[email protected]>

A spare register in UFS host controller is used to indicate the UFS device
version. The spare register is populated by bootloader for now, but in
future it will be populated by HW automatically during link startup with
its best efforts in any boot stages prior to Linux.

During host driver init, read the spare register, if it is not populated
with a UFS device version, go ahead with the dual init mechanism. If a UFS
device version is in there, use the UFS device version together with host
controller's HW version to decide the proper PHY gear which should be used
to configure the UFS PHY without going through the second init.

Signed-off-by: Bao D. Nguyen <[email protected]>
Signed-off-by: Can Guo <[email protected]>
---
drivers/ufs/host/ufs-qcom.c | 23 ++++++++++++++++++-----
drivers/ufs/host/ufs-qcom.h | 2 ++
2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 9c0ebbc..e94dea2 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -1068,15 +1068,28 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
{
struct ufs_host_params *host_params = &host->host_params;
+ u32 val, dev_major = 0;

host->phy_gear = host_params->hs_tx_gear;

- /*
- * Power up the PHY using the minimum supported gear (UFS_HS_G2).
- * Switching to max gear will be performed during reinit if supported.
- */
- if (host->hw_ver.major < 0x4)
+ if (host->hw_ver.major < 0x4) {
+ /*
+ * Power up the PHY using the minimum supported gear (UFS_HS_G2).
+ * Switching to max gear will be performed during reinit if supported.
+ */
host->phy_gear = UFS_HS_G2;
+ } else {
+ val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
+ dev_major = FIELD_GET(GENMASK(7, 4), val);
+
+ /* UFS device version populated, no need to do init twice */
+ if (dev_major != 0)
+ host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
+
+ /* For UFS 3.1 and older, apply HS-G4 PHY gear to save power */
+ if (dev_major < 0x4 && dev_major > 0)
+ host->phy_gear = UFS_HS_G4;
+ }
}

static void ufs_qcom_set_host_params(struct ufs_hba *hba)
diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
index 11419eb..d12fc5a 100644
--- a/drivers/ufs/host/ufs-qcom.h
+++ b/drivers/ufs/host/ufs-qcom.h
@@ -54,6 +54,8 @@ enum {
UFS_AH8_CFG = 0xFC,

REG_UFS_CFG3 = 0x271C,
+
+ REG_UFS_DEBUG_SPARE_CFG = 0x284C,
};

/* QCOM UFS host controller vendor specific debug registers */
--
2.7.4

2023-11-29 08:30:21

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 07/10] phy: qualcomm: phy-qcom-qmp-ufs: Rectify SM8550 UFS HS-G4 PHY Settings

The registers, which are being touched in current SM8550 UFS PHY settings,
and the values being programmed are mainly the ones working for HS-G4 mode,
meanwhile, there are also a few ones somehow taken from HS-G5 PHY settings.
However, even consider HS-G4 mode only, some of them are incorrect and some
are missing. Rectify the HS-G4 PHY settings by strictly aligning with the
SM8550 UFS PHY Hardware Programming Guide suggested HS-G4 PHY settings.

Fixes: 1679bfef906f ("phy: qcom-qmp-ufs: Add SM8550 support")
Reviewed-by: Dmitry Baryshkov <[email protected]>
Reviewed-by: Abel Vesa <[email protected]>
Reviewed-by: Manivannan Sadhasivam <[email protected]>
Signed-off-by: Can Guo <[email protected]>
---
.../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 3 +++
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 28 +++++++++++++++-------
2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
index 15bcb4b..674f158 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
@@ -10,9 +10,12 @@
#define QSERDES_UFS_V6_TX_RES_CODE_LANE_RX 0x2c
#define QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX 0x30
#define QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX 0x34
+#define QSERDES_UFS_V6_TX_LANE_MODE_1 0x7c
+#define QSERDES_UFS_V6_TX_FR_DCC_CTRL 0x108

#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08
#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
+#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4
#define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178
#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208
#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 514fa14..2173418 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -763,22 +763,26 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x4c),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x99),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
};

static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = {
- QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c),
};

static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
- QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2, 0x0c),
- QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),

QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2),
@@ -801,6 +805,8 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
};

struct qmp_ufs_offsets {
@@ -1296,6 +1302,10 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
.pcs = sm8550_ufsphy_pcs,
.pcs_num = ARRAY_SIZE(sm8550_ufsphy_pcs),
},
+ .tbls_hs_b = {
+ .serdes = sm8550_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
+ },
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
--
2.7.4

2023-11-29 08:30:57

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 06/10] scsi: ufs: ufs-qcom: Set initial PHY gear to max HS gear for HW ver 4 and newer

Since HW ver 4, max HS gear can be get from UFS host controller's register,
use the max HS gear as the initial PHY gear instead of UFS_HS_G2, so that
we don't need to update the hard code for newer targets in future.

Signed-off-by: Can Guo <[email protected]>
---
drivers/ufs/host/ufs-qcom.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index aca6199..30f4ca6 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -1060,6 +1060,20 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
}

+static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
+{
+ struct ufs_host_params *host_params = &host->host_params;
+
+ host->phy_gear = host_params->hs_tx_gear;
+
+ /*
+ * Power up the PHY using the minimum supported gear (UFS_HS_G2).
+ * Switching to max gear will be performed during reinit if supported.
+ */
+ if (host->hw_ver.major < 0x4)
+ host->phy_gear = UFS_HS_G2;
+}
+
static void ufs_qcom_set_host_params(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1296,6 +1310,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
ufs_qcom_set_host_params(hba);
+ ufs_qcom_set_phy_gear(host);

err = ufs_qcom_ice_init(host);
if (err)
@@ -1313,12 +1328,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
dev_warn(dev, "%s: failed to configure the testbus %d\n",
__func__, err);

- /*
- * Power up the PHY using the minimum supported gear (UFS_HS_G2).
- * Switching to max gear will be performed during reinit if supported.
- */
- host->phy_gear = UFS_HS_G2;
-
return 0;

out_variant_clear:
--
2.7.4

2023-11-29 08:30:59

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 03/10] scsi: ufs: ufs-qcom: Setup host power mode during init

Setup host power mode and its limitations during UFS host driver init to
avoid repetitive work during every power mode change.

Acked-by: Andrew Halaney <[email protected]>
Reviewed-by: Nitin Rawat <[email protected]>
Reviewed-by: Manivannan Sadhasivam <[email protected]>
Co-developed-by: Bao D. Nguyen <[email protected]>
Signed-off-by: Bao D. Nguyen <[email protected]>
Signed-off-by: Can Guo <[email protected]>
---
drivers/ufs/host/ufs-qcom.c | 21 ++++++++++++++-------
drivers/ufs/host/ufs-qcom.h | 1 +
2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index c21ff2c..9a90019 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -898,7 +898,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_req_params)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct ufs_host_params host_params;
+ struct ufs_host_params *host_params = &host->host_params;
int ret = 0;

if (!dev_req_params) {
@@ -908,12 +908,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,

switch (status) {
case PRE_CHANGE:
- ufshcd_init_host_params(&host_params);
-
- /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */
- host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba);
-
- ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
+ ret = ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params);
if (ret) {
dev_err(hba->dev, "%s: failed to determine capabilities\n",
__func__);
@@ -1048,6 +1043,17 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
}

+static void ufs_qcom_set_host_params(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ struct ufs_host_params *host_params = &host->host_params;
+
+ ufshcd_init_host_params(host_params);
+
+ /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */
+ host_params->hs_tx_gear = host_params->hs_rx_gear = ufs_qcom_get_hs_gear(hba);
+}
+
static void ufs_qcom_set_caps(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1272,6 +1278,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)

ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
+ ufs_qcom_set_host_params(hba);

err = ufs_qcom_ice_init(host);
if (err)
diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
index 82cd143..11419eb 100644
--- a/drivers/ufs/host/ufs-qcom.h
+++ b/drivers/ufs/host/ufs-qcom.h
@@ -238,6 +238,7 @@ struct ufs_qcom_host {

struct gpio_desc *device_reset;

+ struct ufs_host_params host_params;
u32 phy_gear;

bool esi_enabled;
--
2.7.4

2023-11-29 08:31:00

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 08/10] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550

On SM8550, two sets of UFS PHY settings are provided, one set is to support
HS-G5, another set is to support HS-G4 and lower gears. The two sets of PHY
settings are programming different values to different registers, mixing
the two sets and/or overwriting one set with another set is definitely not
blessed by UFS PHY designers.

To add HS-G5 support for SM8550, split the two sets of PHY settings into
their dedicated overlay tables, only the common parts of the two sets of
PHY settings are left in the .tbls.

Consider we are going to add even higher gear support in future, to avoid
adding more tables with different names, rename the .tbls_hs_g4 and make it
an array, a size of 2 is enough as of now.

In this case, .tbls alone is not a complete set of PHY settings, so either
tbls_hs_overlay[0] or tbls_hs_overlay[1] must be applied on top of the
.tbls to become a complete set of PHY settings.

Signed-off-by: Can Guo <[email protected]>
---
drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 2 +
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h | 2 +
.../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 9 ++
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 170 ++++++++++++++++++---
4 files changed, 163 insertions(+), 20 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
index c23d5e4..e563af5 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
@@ -18,6 +18,7 @@
#define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
#define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
#define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc
+#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c
#define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158
#define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c
#define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184
@@ -27,5 +28,6 @@
#define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8
#define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4
#define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc
+#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220

#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
index f420f8f..ef392ce 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
@@ -56,6 +56,8 @@
#define QSERDES_V6_COM_SYS_CLK_CTRL 0xe4
#define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8
#define QSERDES_V6_COM_PLL_IVCO 0xf4
+#define QSERDES_V6_COM_CMN_IETRIM 0xfc
+#define QSERDES_V6_COM_CMN_IPTRIM 0x100
#define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110
#define QSERDES_V6_COM_RESETSM_CNTRL 0x118
#define QSERDES_V6_COM_LOCK_CMP_EN 0x120
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
index 674f158..48f31c8 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
@@ -15,8 +15,15 @@

#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08
#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
+#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24
+#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54
#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4
+#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc
+#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0
+#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4
#define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178
+#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc
+#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4
#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208
#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c
#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214
@@ -28,6 +35,8 @@
#define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264
#define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270
#define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280
+#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284
#define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c
+#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8

#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 2173418..7e5f1154 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -41,6 +41,8 @@

#define PHY_INIT_COMPLETE_TIMEOUT 10000

+#define NUM_OVERLAY 2
+
struct qmp_phy_init_tbl {
unsigned int offset;
unsigned int val;
@@ -754,15 +756,22 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
@@ -771,19 +780,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
};

-static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
- QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
+static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
};

static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = {
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = {
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c),
};

static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
- QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),

QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2),
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2),
@@ -799,16 +813,45 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
};

+static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30),
+};
+
static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
- QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
};

+static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e),
+};
+
struct qmp_ufs_offsets {
u16 serdes;
u16 pcs;
@@ -828,6 +871,8 @@ struct qmp_phy_cfg_tbls {
int rx_num;
const struct qmp_phy_init_tbl *pcs;
int pcs_num;
+ /* Maximum supported Gear of this tbls */
+ u32 max_gear;
};

/* struct qmp_phy_cfg - per-PHY initialization config */
@@ -835,13 +880,15 @@ struct qmp_phy_cfg {
int lanes;

const struct qmp_ufs_offsets *offsets;
+ /* Maximum supported Gear of this config */
+ u32 max_supported_gear;

/* Main init sequence for PHY blocks - serdes, tx, rx, pcs */
const struct qmp_phy_cfg_tbls tbls;
/* Additional sequence for HS Series B */
const struct qmp_phy_cfg_tbls tbls_hs_b;
- /* Additional sequence for HS G4 */
- const struct qmp_phy_cfg_tbls tbls_hs_g4;
+ /* Additional sequence for different HS Gears */
+ const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY];

/* clock ids to be requested */
const char * const *clk_list;
@@ -944,6 +991,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
.lanes = 1,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G3,

.tbls = {
.serdes = msm8996_ufsphy_serdes,
@@ -969,6 +1017,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G4,

.tbls = {
.serdes = sm8350_ufsphy_serdes,
@@ -984,13 +1033,14 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
.serdes = sm8350_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
},
- .tbls_hs_g4 = {
+ .tbls_hs_overlay[0] = {
.tx = sm8350_ufsphy_g4_tx,
.tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
.rx = sm8350_ufsphy_g4_rx,
.rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
.pcs = sm8350_ufsphy_g4_pcs,
.pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ .max_gear = UFS_HS_G4,
},
.clk_list = sm8450_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
@@ -1003,6 +1053,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G4,

.tbls = {
.serdes = sm8150_ufsphy_serdes,
@@ -1018,13 +1069,14 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
.serdes = sm8150_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
},
- .tbls_hs_g4 = {
+ .tbls_hs_overlay[0] = {
.tx = sm8250_ufsphy_hs_g4_tx,
.tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
.rx = sc7280_ufsphy_hs_g4_rx,
.rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx),
.pcs = sm8150_ufsphy_hs_g4_pcs,
.pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
+ .max_gear = UFS_HS_G4,
},
.clk_list = sm8450_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
@@ -1037,6 +1089,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G4,

.tbls = {
.serdes = sm8350_ufsphy_serdes,
@@ -1052,13 +1105,14 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
.serdes = sm8350_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
},
- .tbls_hs_g4 = {
+ .tbls_hs_overlay[0] = {
.tx = sm8350_ufsphy_g4_tx,
.tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
.rx = sm8350_ufsphy_g4_rx,
.rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
.pcs = sm8350_ufsphy_g4_pcs,
.pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ .max_gear = UFS_HS_G4,
},
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
@@ -1071,6 +1125,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G3,

.tbls = {
.serdes = sdm845_ufsphy_serdes,
@@ -1099,6 +1154,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
.lanes = 1,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G3,

.tbls = {
.serdes = sm6115_ufsphy_serdes,
@@ -1127,6 +1183,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = {
.lanes = 1,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G3,

.tbls = {
.serdes = sdm845_ufsphy_serdes,
@@ -1155,6 +1212,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G4,

.tbls = {
.serdes = sm8150_ufsphy_serdes,
@@ -1170,13 +1228,14 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
.serdes = sm8150_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
},
- .tbls_hs_g4 = {
+ .tbls_hs_overlay[0] = {
.tx = sm8150_ufsphy_hs_g4_tx,
.tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx),
.rx = sm8150_ufsphy_hs_g4_rx,
.rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx),
.pcs = sm8150_ufsphy_hs_g4_pcs,
.pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
+ .max_gear = UFS_HS_G4,
},
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
@@ -1189,6 +1248,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G4,

.tbls = {
.serdes = sm8150_ufsphy_serdes,
@@ -1204,13 +1264,14 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
.serdes = sm8150_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
},
- .tbls_hs_g4 = {
+ .tbls_hs_overlay[0] = {
.tx = sm8250_ufsphy_hs_g4_tx,
.tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
.rx = sm8250_ufsphy_hs_g4_rx,
.rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx),
.pcs = sm8150_ufsphy_hs_g4_pcs,
.pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
+ .max_gear = UFS_HS_G4,
},
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
@@ -1223,6 +1284,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G4,

.tbls = {
.serdes = sm8350_ufsphy_serdes,
@@ -1238,13 +1300,14 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
.serdes = sm8350_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
},
- .tbls_hs_g4 = {
+ .tbls_hs_overlay[0] = {
.tx = sm8350_ufsphy_g4_tx,
.tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
.rx = sm8350_ufsphy_g4_rx,
.rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
.pcs = sm8350_ufsphy_g4_pcs,
.pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ .max_gear = UFS_HS_G4,
},
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
@@ -1257,6 +1320,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets,
+ .max_supported_gear = UFS_HS_G4,

.tbls = {
.serdes = sm8350_ufsphy_serdes,
@@ -1272,13 +1336,14 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
.serdes = sm8350_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
},
- .tbls_hs_g4 = {
+ .tbls_hs_overlay[0] = {
.tx = sm8350_ufsphy_g4_tx,
.tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
.rx = sm8350_ufsphy_g4_rx,
.rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
.pcs = sm8350_ufsphy_g4_pcs,
.pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ .max_gear = UFS_HS_G4,
},
.clk_list = sm8450_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
@@ -1291,6 +1356,7 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
.lanes = 2,

.offsets = &qmp_ufs_offsets_v6,
+ .max_supported_gear = UFS_HS_G5,

.tbls = {
.serdes = sm8550_ufsphy_serdes,
@@ -1306,6 +1372,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
.serdes = sm8550_ufsphy_hs_b_serdes,
.serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
},
+ .tbls_hs_overlay[0] = {
+ .serdes = sm8550_ufsphy_g4_serdes,
+ .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes),
+ .tx = sm8550_ufsphy_g4_tx,
+ .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx),
+ .rx = sm8550_ufsphy_g4_rx,
+ .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx),
+ .pcs = sm8550_ufsphy_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs),
+ .max_gear = UFS_HS_G4,
+ },
+ .tbls_hs_overlay[1] = {
+ .serdes = sm8550_ufsphy_g5_serdes,
+ .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes),
+ .rx = sm8550_ufsphy_g5_rx,
+ .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx),
+ .pcs = sm8550_ufsphy_g5_pcs,
+ .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs),
+ .max_gear = UFS_HS_G5,
+ },
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
@@ -1368,17 +1454,55 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls
qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num);
}

+static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
+{
+ u32 max_gear, floor_max_gear = cfg->max_supported_gear;
+ int i = NUM_OVERLAY - 1;
+ int ret = -EINVAL;
+
+ for (; i >= 0; i --) {
+ max_gear = cfg->tbls_hs_overlay[i].max_gear;
+
+ if (max_gear == 0)
+ continue;
+
+ /* Direct matching, bail */
+ if (qmp->submode == max_gear)
+ return i;
+
+ /* If no direct matching, the lowest gear is the best matching */
+ if (max_gear < floor_max_gear) {
+ ret = i;
+ floor_max_gear = max_gear;
+ }
+ }
+
+ return ret;
+}
+
static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
{
+ int i;
+ bool apply_overlay = false;
+
+ i = qmp_ufs_get_gear_overlay(qmp, cfg);
+ if (i >= 0)
+ apply_overlay = true;
+
qmp_ufs_serdes_init(qmp, &cfg->tbls);
+ if (apply_overlay)
+ qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[i]);
+
if (qmp->mode == PHY_MODE_UFS_HS_B)
qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b);
+
qmp_ufs_lanes_init(qmp, &cfg->tbls);
- if (qmp->submode == UFS_HS_G4)
- qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_g4);
+ if (apply_overlay)
+ qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[i]);
+
qmp_ufs_pcs_init(qmp, &cfg->tbls);
- if (qmp->submode == UFS_HS_G4)
- qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_g4);
+ if (apply_overlay)
+ qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_overlay[i]);
}

static int qmp_ufs_com_init(struct qmp_ufs *qmp)
@@ -1550,6 +1674,12 @@ static int qmp_ufs_disable(struct phy *phy)
static int qmp_ufs_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct qmp_ufs *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+
+ if (submode > cfg->max_supported_gear || submode == 0) {
+ dev_err(qmp->dev, "Invalid PHY submode %d\n", submode);
+ return -EINVAL;
+ }

qmp->mode = mode;
qmp->submode = submode;
--
2.7.4

2023-11-29 08:31:08

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 05/10] scsi: ufs: ufs-qcom: Limit HS-G5 Rate-A to hosts with HW version 5

Qcom UFS hosts, with HW ver 5, can only support up to HS-G5 Rate-A due to
HW limitations. If the HS-G5 PHY gear is used, update host_params->hs_rate
to Rate-A, so that the subsequent power mode changes shall stick to Rate-A.

Reviewed-by: Nitin Rawat <[email protected]>
Reviewed-by: Manivannan Sadhasivam <[email protected]>
Signed-off-by: Can Guo <[email protected]>
---
drivers/ufs/host/ufs-qcom.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 81056b9..aca6199 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -442,9 +442,25 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba)
static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ struct ufs_host_params *host_params = &host->host_params;
struct phy *phy = host->generic_phy;
+ enum phy_mode mode;
int ret;

+ /*
+ * HW ver 5 can only support up to HS-G5 Rate-A due to HW limitations.
+ * If the HS-G5 PHY gear is used, update host_params->hs_rate to Rate-A,
+ * so that the subsequent power mode change shall stick to Rate-A.
+ */
+ if (host->hw_ver.major == 0x5) {
+ if (host->phy_gear == UFS_HS_G5)
+ host_params->hs_rate = PA_HS_MODE_A;
+ else
+ host_params->hs_rate = PA_HS_MODE_B;
+ }
+
+ mode = host_params->hs_rate == PA_HS_MODE_B ? PHY_MODE_UFS_HS_B : PHY_MODE_UFS_HS_A;
+
/* Reset UFS Host Controller and PHY */
ret = ufs_qcom_host_reset(hba);
if (ret)
@@ -459,7 +475,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
return ret;
}

- phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->phy_gear);
+ phy_set_mode_ext(phy, mode, host->phy_gear);

/* power on phy - start serdes and phy's power and clocks */
ret = phy_power_on(phy);
--
2.7.4

2023-11-29 08:31:23

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 01/10] scsi: ufs: host: Rename structure ufs_dev_params to ufs_host_params

Structure ufs_dev_params is actually used in UFS host vendor drivers to
declare host specific power mode parameters, like ufs_<vendor>_params or
host_cap, which makes the code not very straightforward to read. Rename the
structure ufs_dev_params to ufs_host_params and unify the declarations in
all vendor drivers to host_params.

In addition, rename the two functions ufshcd_init_pwr_dev_param() and
ufshcd_get_pwr_dev_param() which work based on the ufs_host_params to
ufshcd_init_host_params() and ufshcd_negotiate_pwr_params() respectively to
avoid confusions.

This change does not change any functionalities or logic.

Acked-by: Andrew Halaney <[email protected]>
Reviewed-by: Nitin Rawat <[email protected]>
Reviewed-by: Manivannan Sadhasivam <[email protected]>
Signed-off-by: Can Guo <[email protected]>
---
drivers/ufs/host/ufs-exynos.c | 7 ++--
drivers/ufs/host/ufs-hisi.c | 11 +++----
drivers/ufs/host/ufs-mediatek.c | 12 +++----
drivers/ufs/host/ufs-qcom.c | 12 +++----
drivers/ufs/host/ufshcd-pltfrm.c | 69 ++++++++++++++++++++--------------------
drivers/ufs/host/ufshcd-pltfrm.h | 10 +++---
6 files changed, 57 insertions(+), 64 deletions(-)

diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c
index 71bd6db..734d40f 100644
--- a/drivers/ufs/host/ufs-exynos.c
+++ b/drivers/ufs/host/ufs-exynos.c
@@ -765,7 +765,7 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
{
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
struct phy *generic_phy = ufs->phy;
- struct ufs_dev_params ufs_exynos_cap;
+ struct ufs_host_params host_params;
int ret;

if (!dev_req_params) {
@@ -774,10 +774,9 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
goto out;
}

- ufshcd_init_pwr_dev_param(&ufs_exynos_cap);
+ ufshcd_init_host_params(&host_params);

- ret = ufshcd_get_pwr_dev_param(&ufs_exynos_cap,
- dev_max_params, dev_req_params);
+ ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
if (ret) {
pr_err("%s: failed to determine capabilities\n", __func__);
goto out;
diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c
index 0229ac0..5ee73ff 100644
--- a/drivers/ufs/host/ufs-hisi.c
+++ b/drivers/ufs/host/ufs-hisi.c
@@ -293,9 +293,9 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba,
return err;
}

-static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param)
+static void ufs_hisi_set_dev_cap(struct ufs_host_params *host_params)
{
- ufshcd_init_pwr_dev_param(hisi_param);
+ ufshcd_init_host_params(host_params);
}

static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba)
@@ -365,7 +365,7 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
- struct ufs_dev_params ufs_hisi_cap;
+ struct ufs_host_params host_params;
int ret = 0;

if (!dev_req_params) {
@@ -377,9 +377,8 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba,

switch (status) {
case PRE_CHANGE:
- ufs_hisi_set_dev_cap(&ufs_hisi_cap);
- ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap,
- dev_max_params, dev_req_params);
+ ufs_hisi_set_dev_cap(&host_params);
+ ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
if (ret) {
dev_err(hba->dev,
"%s: failed to determine capabilities\n", __func__);
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index fc61790..776bca4 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -996,16 +996,14 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_req_params)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
- struct ufs_dev_params host_cap;
+ struct ufs_host_params host_params;
int ret;

- ufshcd_init_pwr_dev_param(&host_cap);
- host_cap.hs_rx_gear = UFS_HS_G5;
- host_cap.hs_tx_gear = UFS_HS_G5;
+ ufshcd_init_host_params(&host_params);
+ host_params.hs_rx_gear = UFS_HS_G5;
+ host_params.hs_tx_gear = UFS_HS_G5;

- ret = ufshcd_get_pwr_dev_param(&host_cap,
- dev_max_params,
- dev_req_params);
+ ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
if (ret) {
pr_info("%s: failed to determine capabilities\n",
__func__);
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 96cb8b5..197c5a5 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -898,7 +898,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_req_params)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct ufs_dev_params ufs_qcom_cap;
+ struct ufs_host_params host_params;
int ret = 0;

if (!dev_req_params) {
@@ -908,15 +908,13 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,

switch (status) {
case PRE_CHANGE:
- ufshcd_init_pwr_dev_param(&ufs_qcom_cap);
- ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE;
+ ufshcd_init_host_params(&host_params);
+ host_params.hs_rate = UFS_QCOM_LIMIT_HS_RATE;

/* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */
- ufs_qcom_cap.hs_tx_gear = ufs_qcom_cap.hs_rx_gear = ufs_qcom_get_hs_gear(hba);
+ host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba);

- ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap,
- dev_max_params,
- dev_req_params);
+ ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
if (ret) {
dev_err(hba->dev, "%s: failed to determine capabilities\n",
__func__);
diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c
index da2558e..1633edc 100644
--- a/drivers/ufs/host/ufshcd-pltfrm.c
+++ b/drivers/ufs/host/ufshcd-pltfrm.c
@@ -285,61 +285,60 @@ static int ufshcd_parse_operating_points(struct ufs_hba *hba)
}

/**
- * ufshcd_get_pwr_dev_param - get finally agreed attributes for
- * power mode change
- * @pltfrm_param: pointer to platform parameters
+ * ufshcd_negotiate_pwr_params - find power mode settings that are supported by
+ both the controller and the device
+ * @host_params: pointer to host parameters
* @dev_max: pointer to device attributes
* @agreed_pwr: returned agreed attributes
*
* Return: 0 on success, non-zero value on failure.
*/
-int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param,
- const struct ufs_pa_layer_attr *dev_max,
- struct ufs_pa_layer_attr *agreed_pwr)
+int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params,
+ const struct ufs_pa_layer_attr *dev_max,
+ struct ufs_pa_layer_attr *agreed_pwr)
{
- int min_pltfrm_gear;
+ int min_host_gear;
int min_dev_gear;
bool is_dev_sup_hs = false;
- bool is_pltfrm_max_hs = false;
+ bool is_host_max_hs = false;

if (dev_max->pwr_rx == FAST_MODE)
is_dev_sup_hs = true;

- if (pltfrm_param->desired_working_mode == UFS_HS_MODE) {
- is_pltfrm_max_hs = true;
- min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear,
- pltfrm_param->hs_tx_gear);
+ if (host_params->desired_working_mode == UFS_HS_MODE) {
+ is_host_max_hs = true;
+ min_host_gear = min_t(u32, host_params->hs_rx_gear,
+ host_params->hs_tx_gear);
} else {
- min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear,
- pltfrm_param->pwm_tx_gear);
+ min_host_gear = min_t(u32, host_params->pwm_rx_gear,
+ host_params->pwm_tx_gear);
}

/*
- * device doesn't support HS but
- * pltfrm_param->desired_working_mode is HS,
- * thus device and pltfrm_param don't agree
+ * device doesn't support HS but host_params->desired_working_mode is HS,
+ * thus device and host_params don't agree
*/
- if (!is_dev_sup_hs && is_pltfrm_max_hs) {
+ if (!is_dev_sup_hs && is_host_max_hs) {
pr_info("%s: device doesn't support HS\n",
__func__);
return -ENOTSUPP;
- } else if (is_dev_sup_hs && is_pltfrm_max_hs) {
+ } else if (is_dev_sup_hs && is_host_max_hs) {
/*
* since device supports HS, it supports FAST_MODE.
- * since pltfrm_param->desired_working_mode is also HS
+ * since host_params->desired_working_mode is also HS
* then final decision (FAST/FASTAUTO) is done according
* to pltfrm_params as it is the restricting factor
*/
- agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs;
+ agreed_pwr->pwr_rx = host_params->rx_pwr_hs;
agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
} else {
/*
- * here pltfrm_param->desired_working_mode is PWM.
+ * here host_params->desired_working_mode is PWM.
* it doesn't matter whether device supports HS or PWM,
- * in both cases pltfrm_param->desired_working_mode will
+ * in both cases host_params->desired_working_mode will
* determine the mode
*/
- agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm;
+ agreed_pwr->pwr_rx = host_params->rx_pwr_pwm;
agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
}

@@ -349,9 +348,9 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param,
* the same decision will be made for rx
*/
agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx,
- pltfrm_param->tx_lanes);
+ host_params->tx_lanes);
agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx,
- pltfrm_param->rx_lanes);
+ host_params->rx_lanes);

/* device maximum gear is the minimum between device rx and tx gears */
min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx);
@@ -364,26 +363,26 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param,
* what is the gear, as it is the one that also decided previously what
* pwr the device will be configured to.
*/
- if ((is_dev_sup_hs && is_pltfrm_max_hs) ||
- (!is_dev_sup_hs && !is_pltfrm_max_hs)) {
+ if ((is_dev_sup_hs && is_host_max_hs) ||
+ (!is_dev_sup_hs && !is_host_max_hs)) {
agreed_pwr->gear_rx =
- min_t(u32, min_dev_gear, min_pltfrm_gear);
+ min_t(u32, min_dev_gear, min_host_gear);
} else if (!is_dev_sup_hs) {
agreed_pwr->gear_rx = min_dev_gear;
} else {
- agreed_pwr->gear_rx = min_pltfrm_gear;
+ agreed_pwr->gear_rx = min_host_gear;
}
agreed_pwr->gear_tx = agreed_pwr->gear_rx;

- agreed_pwr->hs_rate = pltfrm_param->hs_rate;
+ agreed_pwr->hs_rate = host_params->hs_rate;

return 0;
}
-EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param);
+EXPORT_SYMBOL_GPL(ufshcd_negotiate_pwr_params);

-void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param)
+void ufshcd_init_host_params(struct ufs_host_params *host_params)
{
- *dev_param = (struct ufs_dev_params){
+ *host_params = (struct ufs_host_params){
.tx_lanes = UFS_LANE_2,
.rx_lanes = UFS_LANE_2,
.hs_rx_gear = UFS_HS_G3,
@@ -398,7 +397,7 @@ void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param)
.desired_working_mode = UFS_HS_MODE,
};
}
-EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param);
+EXPORT_SYMBOL_GPL(ufshcd_init_host_params);

/**
* ufshcd_pltfrm_init - probe routine of the driver
diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h
index a86a3ad..df387be 100644
--- a/drivers/ufs/host/ufshcd-pltfrm.h
+++ b/drivers/ufs/host/ufshcd-pltfrm.h
@@ -10,7 +10,7 @@
#define UFS_PWM_MODE 1
#define UFS_HS_MODE 2

-struct ufs_dev_params {
+struct ufs_host_params {
u32 pwm_rx_gear; /* pwm rx gear to work in */
u32 pwm_tx_gear; /* pwm tx gear to work in */
u32 hs_rx_gear; /* hs rx gear to work in */
@@ -25,10 +25,10 @@ struct ufs_dev_params {
u32 desired_working_mode;
};

-int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *dev_param,
- const struct ufs_pa_layer_attr *dev_max,
- struct ufs_pa_layer_attr *agreed_pwr);
-void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param);
+int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params,
+ const struct ufs_pa_layer_attr *dev_max,
+ struct ufs_pa_layer_attr *agreed_pwr);
+void ufshcd_init_host_params(struct ufs_host_params *host_params);
int ufshcd_pltfrm_init(struct platform_device *pdev,
const struct ufs_hba_variant_ops *vops);
int ufshcd_populate_vreg(struct device *dev, const char *name,
--
2.7.4

2023-11-29 08:32:30

by Can Guo

[permalink] [raw]
Subject: [PATCH v6 04/10] scsi: ufs: ufs-qcom: Allow the first init start with the maximum supported gear

During host driver init, the phy_gear is set to the minimum supported gear
(HS_G2). Then, during the first power mode change, the negotiated gear, say
HS-G4, is updated to the phy_gear variable so that in the second init the
updated phy_gear can be used to program the PHY.

But the current code only allows update the phy_gear to a higher value. If
one wants to start the first init with the maximum support gear, say HS-G4,
the phy_gear is not updated to HS-G3 if the device only supports HS-G3.

The original check added there is intend to make sure the phy_gear won't be
updated when gear is scaled down (during clock scaling). Update the check
so that one can start the first init with the maximum support gear without
breaking the original fix by checking the ufshcd_state, that is, allow
update to phy_gear only if power mode change is invoked from
ufshcd_probe_hba().

This change is a preparation patch for the next patches in the same series.

Signed-off-by: Can Guo <[email protected]>
---
drivers/ufs/host/ufs-qcom.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 9a90019..81056b9 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -916,11 +916,12 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
}

/*
- * Update phy_gear only when the gears are scaled to a higher value. This is
- * because, the PHY gear settings are backwards compatible and we only need to
- * change the PHY gear settings while scaling to higher gears.
+ * During UFS driver probe, always update the PHY gear to match the negotiated
+ * gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled,
+ * the second init can program the optimal PHY settings. This allows one to start
+ * the first init with either the minimum or the maximum support gear.
*/
- if (dev_req_params->gear_tx > host->phy_gear)
+ if (hba->ufshcd_state == UFSHCD_STATE_RESET)
host->phy_gear = dev_req_params->gear_tx;

/* enable the device ref clock before changing to HS mode */
--
2.7.4

2023-11-29 18:12:09

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH v6 01/10] scsi: ufs: host: Rename structure ufs_dev_params to ufs_host_params

On 11/29/23 00:28, Can Guo wrote:
> Structure ufs_dev_params is actually used in UFS host vendor drivers to
> declare host specific power mode parameters, like ufs_<vendor>_params or
> host_cap, which makes the code not very straightforward to read. Rename the
> structure ufs_dev_params to ufs_host_params and unify the declarations in
> all vendor drivers to host_params.
>
> In addition, rename the two functions ufshcd_init_pwr_dev_param() and
> ufshcd_get_pwr_dev_param() which work based on the ufs_host_params to
> ufshcd_init_host_params() and ufshcd_negotiate_pwr_params() respectively to
> avoid confusions.
>
> This change does not change any functionalities or logic.

Reviewed-by: Bart Van Assche <[email protected]>

2023-11-29 19:04:53

by Eric Chanudet

[permalink] [raw]
Subject: Re: [PATCH v6 10/10] scsi: ufs: ufs-qcom: Add support for UFS device version detection

On Wed, Nov 29, 2023 at 12:28:35AM -0800, Can Guo wrote:
> From: "Bao D. Nguyen" <[email protected]>
>
> A spare register in UFS host controller is used to indicate the UFS device
> version. The spare register is populated by bootloader for now, but in
> future it will be populated by HW automatically during link startup with
> its best efforts in any boot stages prior to Linux.
>
> During host driver init, read the spare register, if it is not populated
> with a UFS device version, go ahead with the dual init mechanism. If a UFS
> device version is in there, use the UFS device version together with host
> controller's HW version to decide the proper PHY gear which should be used
> to configure the UFS PHY without going through the second init.
>
> Signed-off-by: Bao D. Nguyen <[email protected]>
> Signed-off-by: Can Guo <[email protected]>
> ---
> drivers/ufs/host/ufs-qcom.c | 23 ++++++++++++++++++-----
> drivers/ufs/host/ufs-qcom.h | 2 ++
> 2 files changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
> index 9c0ebbc..e94dea2 100644
> --- a/drivers/ufs/host/ufs-qcom.c
> +++ b/drivers/ufs/host/ufs-qcom.c
> @@ -1068,15 +1068,28 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
> static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
> {
> struct ufs_host_params *host_params = &host->host_params;
> + u32 val, dev_major = 0;
>
> host->phy_gear = host_params->hs_tx_gear;
>
> - /*
> - * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> - * Switching to max gear will be performed during reinit if supported.
> - */
> - if (host->hw_ver.major < 0x4)
> + if (host->hw_ver.major < 0x4) {
> + /*
> + * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> + * Switching to max gear will be performed during reinit if supported.
> + */
> host->phy_gear = UFS_HS_G2;
> + } else {
> + val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
> + dev_major = FIELD_GET(GENMASK(7, 4), val);
> +
> + /* UFS device version populated, no need to do init twice */

This change documents the content of the register as "UFS device
version", both inline in the code and in the commit description. Earlier
in this series[1], Mani mentioned it was the gear info:
> > [...]populating a spare register in the bootloader with the max gear
> > info that the bootloader has already found[...]

Is it the gear number as in HS-G4? Or the version as in UFS controller
revision 3.1?

[1] https://lore.kernel.org/all/20231018124741.GA47321@thinkpad/

> + if (dev_major != 0)
> + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
> +
> + /* For UFS 3.1 and older, apply HS-G4 PHY gear to save power */
> + if (dev_major < 0x4 && dev_major > 0)
> + host->phy_gear = UFS_HS_G4;
> + }
> }
>
> static void ufs_qcom_set_host_params(struct ufs_hba *hba)
> diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
> index 11419eb..d12fc5a 100644
> --- a/drivers/ufs/host/ufs-qcom.h
> +++ b/drivers/ufs/host/ufs-qcom.h
> @@ -54,6 +54,8 @@ enum {
> UFS_AH8_CFG = 0xFC,
>
> REG_UFS_CFG3 = 0x271C,
> +
> + REG_UFS_DEBUG_SPARE_CFG = 0x284C,
> };
>
> /* QCOM UFS host controller vendor specific debug registers */
> --
> 2.7.4
>
>

--
Eric Chanudet

2023-11-30 05:53:25

by Nitin Rawat

[permalink] [raw]
Subject: Re: [PATCH v6 06/10] scsi: ufs: ufs-qcom: Set initial PHY gear to max HS gear for HW ver 4 and newer



On 11/29/2023 1:58 PM, Can Guo wrote:
> Since HW ver 4, max HS gear can be get from UFS host controller's register,
> use the max HS gear as the initial PHY gear instead of UFS_HS_G2, so that
> we don't need to update the hard code for newer targets in future.
>
> Signed-off-by: Can Guo <[email protected]>
> ---
> drivers/ufs/host/ufs-qcom.c | 21 +++++++++++++++------
> 1 file changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
> index aca6199..30f4ca6 100644
> --- a/drivers/ufs/host/ufs-qcom.c
> +++ b/drivers/ufs/host/ufs-qcom.c
> @@ -1060,6 +1060,20 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
> hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
> }
>
> +static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
> +{
> + struct ufs_host_params *host_params = &host->host_params;
> +
> + host->phy_gear = host_params->hs_tx_gear;
> +
> + /*
> + * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> + * Switching to max gear will be performed during reinit if supported.
> + */
> + if (host->hw_ver.major < 0x4)
> + host->phy_gear = UFS_HS_G2;
> +}
> +
> static void ufs_qcom_set_host_params(struct ufs_hba *hba)
> {
> struct ufs_qcom_host *host = ufshcd_get_variant(hba);
> @@ -1296,6 +1310,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
> ufs_qcom_set_caps(hba);
> ufs_qcom_advertise_quirks(hba);
> ufs_qcom_set_host_params(hba);
> + ufs_qcom_set_phy_gear(host);
>
> err = ufs_qcom_ice_init(host);
> if (err)
> @@ -1313,12 +1328,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
> dev_warn(dev, "%s: failed to configure the testbus %d\n",
> __func__, err);
>
> - /*
> - * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> - * Switching to max gear will be performed during reinit if supported.
> - */
> - host->phy_gear = UFS_HS_G2;
> -
> return 0;
>
> out_variant_clear:

Reviewed-by: Nitin Rawat <[email protected]>

2023-11-30 06:42:44

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v6 04/10] scsi: ufs: ufs-qcom: Allow the first init start with the maximum supported gear

On Wed, Nov 29, 2023 at 12:28:29AM -0800, Can Guo wrote:
> During host driver init, the phy_gear is set to the minimum supported gear
> (HS_G2). Then, during the first power mode change, the negotiated gear, say
> HS-G4, is updated to the phy_gear variable so that in the second init the
> updated phy_gear can be used to program the PHY.
>
> But the current code only allows update the phy_gear to a higher value. If
> one wants to start the first init with the maximum support gear, say HS-G4,
> the phy_gear is not updated to HS-G3 if the device only supports HS-G3.
>
> The original check added there is intend to make sure the phy_gear won't be
> updated when gear is scaled down (during clock scaling). Update the check
> so that one can start the first init with the maximum support gear without
> breaking the original fix by checking the ufshcd_state, that is, allow
> update to phy_gear only if power mode change is invoked from
> ufshcd_probe_hba().
>
> This change is a preparation patch for the next patches in the same series.

If you happen to respin the series, please remove this line. When the patches
get merged, there will be no concept of patches/series as all will be git
commits.

You can have this information in the comment section (below --- line) though.

>
> Signed-off-by: Can Guo <[email protected]>

Reviewed-by: Manivannan Sadhasivam <[email protected]>

- Mani

> ---
> drivers/ufs/host/ufs-qcom.c | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
> index 9a90019..81056b9 100644
> --- a/drivers/ufs/host/ufs-qcom.c
> +++ b/drivers/ufs/host/ufs-qcom.c
> @@ -916,11 +916,12 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
> }
>
> /*
> - * Update phy_gear only when the gears are scaled to a higher value. This is
> - * because, the PHY gear settings are backwards compatible and we only need to
> - * change the PHY gear settings while scaling to higher gears.
> + * During UFS driver probe, always update the PHY gear to match the negotiated
> + * gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled,
> + * the second init can program the optimal PHY settings. This allows one to start
> + * the first init with either the minimum or the maximum support gear.
> */
> - if (dev_req_params->gear_tx > host->phy_gear)
> + if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> host->phy_gear = dev_req_params->gear_tx;
>
> /* enable the device ref clock before changing to HS mode */
> --
> 2.7.4
>
>

--
மணிவண்ணன் சதாசிவம்

2023-11-30 06:48:32

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v6 06/10] scsi: ufs: ufs-qcom: Set initial PHY gear to max HS gear for HW ver 4 and newer

On Wed, Nov 29, 2023 at 12:28:31AM -0800, Can Guo wrote:
> Since HW ver 4, max HS gear can be get from UFS host controller's register,
> use the max HS gear as the initial PHY gear instead of UFS_HS_G2, so that
> we don't need to update the hard code for newer targets in future.
>
> Signed-off-by: Can Guo <[email protected]>

One comment below. With that addressed,

Reviewed-by: Manivannan Sadhasivam <[email protected]>

> ---
> drivers/ufs/host/ufs-qcom.c | 21 +++++++++++++++------
> 1 file changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
> index aca6199..30f4ca6 100644
> --- a/drivers/ufs/host/ufs-qcom.c
> +++ b/drivers/ufs/host/ufs-qcom.c
> @@ -1060,6 +1060,20 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
> hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
> }
>
> +static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
> +{
> + struct ufs_host_params *host_params = &host->host_params;
> +
> + host->phy_gear = host_params->hs_tx_gear;
> +
> + /*
> + * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> + * Switching to max gear will be performed during reinit if supported.

As I mentioned in v5, you need to reword this comment to make it clear we are
setting G2 only for platforms < v4. Something like below:

"For controllers whose major version is < 4, power up the PHY using minimum
supported gear (UFS_HS_G2). Switching to max gear will be performed during
reinit if supported. For newer controllers (>= 4), PHY will be powered up using
max supported gear."

- Mani

> + */
> + if (host->hw_ver.major < 0x4)
> + host->phy_gear = UFS_HS_G2;
> +}
> +
> static void ufs_qcom_set_host_params(struct ufs_hba *hba)
> {
> struct ufs_qcom_host *host = ufshcd_get_variant(hba);
> @@ -1296,6 +1310,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
> ufs_qcom_set_caps(hba);
> ufs_qcom_advertise_quirks(hba);
> ufs_qcom_set_host_params(hba);
> + ufs_qcom_set_phy_gear(host);
>
> err = ufs_qcom_ice_init(host);
> if (err)
> @@ -1313,12 +1328,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
> dev_warn(dev, "%s: failed to configure the testbus %d\n",
> __func__, err);
>
> - /*
> - * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> - * Switching to max gear will be performed during reinit if supported.
> - */
> - host->phy_gear = UFS_HS_G2;
> -
> return 0;
>
> out_variant_clear:
> --
> 2.7.4
>
>

--
மணிவண்ணன் சதாசிவம்

2023-11-30 07:13:14

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v6 08/10] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550

On Wed, Nov 29, 2023 at 12:28:33AM -0800, Can Guo wrote:
> On SM8550, two sets of UFS PHY settings are provided, one set is to support
> HS-G5, another set is to support HS-G4 and lower gears. The two sets of PHY
> settings are programming different values to different registers, mixing
> the two sets and/or overwriting one set with another set is definitely not
> blessed by UFS PHY designers.
>
> To add HS-G5 support for SM8550, split the two sets of PHY settings into
> their dedicated overlay tables, only the common parts of the two sets of
> PHY settings are left in the .tbls.
>
> Consider we are going to add even higher gear support in future, to avoid
> adding more tables with different names, rename the .tbls_hs_g4 and make it
> an array, a size of 2 is enough as of now.
>
> In this case, .tbls alone is not a complete set of PHY settings, so either
> tbls_hs_overlay[0] or tbls_hs_overlay[1] must be applied on top of the
> .tbls to become a complete set of PHY settings.
>
> Signed-off-by: Can Guo <[email protected]>
> ---
> drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 2 +
> drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h | 2 +
> .../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 9 ++
> drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 170 ++++++++++++++++++---
> 4 files changed, 163 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
> index c23d5e4..e563af5 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
> @@ -18,6 +18,7 @@
> #define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
> #define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
> #define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc
> +#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c
> #define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158
> #define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c
> #define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184
> @@ -27,5 +28,6 @@
> #define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8
> #define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4
> #define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc
> +#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220
>
> #endif
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
> index f420f8f..ef392ce 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
> @@ -56,6 +56,8 @@
> #define QSERDES_V6_COM_SYS_CLK_CTRL 0xe4
> #define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8
> #define QSERDES_V6_COM_PLL_IVCO 0xf4
> +#define QSERDES_V6_COM_CMN_IETRIM 0xfc
> +#define QSERDES_V6_COM_CMN_IPTRIM 0x100
> #define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110
> #define QSERDES_V6_COM_RESETSM_CNTRL 0x118
> #define QSERDES_V6_COM_LOCK_CMP_EN 0x120
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
> index 674f158..48f31c8 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
> @@ -15,8 +15,15 @@
>
> #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08
> #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
> +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24
> +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54
> #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4
> +#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc
> +#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0
> +#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4
> #define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178
> +#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc
> +#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4
> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208
> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c
> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214
> @@ -28,6 +35,8 @@
> #define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264
> #define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270
> #define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280
> +#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284
> #define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c
> +#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8
>
> #endif
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
> index 2173418..7e5f1154 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
> @@ -41,6 +41,8 @@
>
> #define PHY_INIT_COMPLETE_TIMEOUT 10000
>
> +#define NUM_OVERLAY 2
> +
> struct qmp_phy_init_tbl {
> unsigned int offset;
> unsigned int val;
> @@ -754,15 +756,22 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
> +};
> +
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
> +};
> +
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = {
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a),
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
> @@ -771,19 +780,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
> };
>
> -static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = {
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b),
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c),
> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
> };
>
> static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = {
> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
> +};
> +
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = {
> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c),
> };
>
> static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
> - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
>
> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2),
> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2),
> @@ -799,16 +813,45 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
> };
>
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = {
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
> +};
> +
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = {
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff),
> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30),
> +};
> +
> static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = {
> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69),
> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
> - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
> +};
> +
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = {
> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
> };
>
> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_pcs[] = {
> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f),
> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e),
> +};
> +
> struct qmp_ufs_offsets {
> u16 serdes;
> u16 pcs;
> @@ -828,6 +871,8 @@ struct qmp_phy_cfg_tbls {
> int rx_num;
> const struct qmp_phy_init_tbl *pcs;
> int pcs_num;
> + /* Maximum supported Gear of this tbls */
> + u32 max_gear;
> };
>
> /* struct qmp_phy_cfg - per-PHY initialization config */
> @@ -835,13 +880,15 @@ struct qmp_phy_cfg {
> int lanes;
>
> const struct qmp_ufs_offsets *offsets;
> + /* Maximum supported Gear of this config */
> + u32 max_supported_gear;
>
> /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */
> const struct qmp_phy_cfg_tbls tbls;
> /* Additional sequence for HS Series B */
> const struct qmp_phy_cfg_tbls tbls_hs_b;
> - /* Additional sequence for HS G4 */
> - const struct qmp_phy_cfg_tbls tbls_hs_g4;
> + /* Additional sequence for different HS Gears */
> + const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY];
>
> /* clock ids to be requested */
> const char * const *clk_list;
> @@ -944,6 +991,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
> .lanes = 1,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G3,
>
> .tbls = {
> .serdes = msm8996_ufsphy_serdes,
> @@ -969,6 +1017,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G4,
>
> .tbls = {
> .serdes = sm8350_ufsphy_serdes,
> @@ -984,13 +1033,14 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
> .serdes = sm8350_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> },
> - .tbls_hs_g4 = {
> + .tbls_hs_overlay[0] = {
> .tx = sm8350_ufsphy_g4_tx,
> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> .rx = sm8350_ufsphy_g4_rx,
> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> .pcs = sm8350_ufsphy_g4_pcs,
> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> + .max_gear = UFS_HS_G4,
> },
> .clk_list = sm8450_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
> @@ -1003,6 +1053,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G4,
>
> .tbls = {
> .serdes = sm8150_ufsphy_serdes,
> @@ -1018,13 +1069,14 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
> .serdes = sm8150_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
> },
> - .tbls_hs_g4 = {
> + .tbls_hs_overlay[0] = {
> .tx = sm8250_ufsphy_hs_g4_tx,
> .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
> .rx = sc7280_ufsphy_hs_g4_rx,
> .rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx),
> .pcs = sm8150_ufsphy_hs_g4_pcs,
> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
> + .max_gear = UFS_HS_G4,
> },
> .clk_list = sm8450_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
> @@ -1037,6 +1089,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G4,
>
> .tbls = {
> .serdes = sm8350_ufsphy_serdes,
> @@ -1052,13 +1105,14 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
> .serdes = sm8350_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> },
> - .tbls_hs_g4 = {
> + .tbls_hs_overlay[0] = {
> .tx = sm8350_ufsphy_g4_tx,
> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> .rx = sm8350_ufsphy_g4_rx,
> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> .pcs = sm8350_ufsphy_g4_pcs,
> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> + .max_gear = UFS_HS_G4,
> },
> .clk_list = sdm845_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> @@ -1071,6 +1125,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G3,
>
> .tbls = {
> .serdes = sdm845_ufsphy_serdes,
> @@ -1099,6 +1154,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
> .lanes = 1,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G3,
>
> .tbls = {
> .serdes = sm6115_ufsphy_serdes,
> @@ -1127,6 +1183,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = {
> .lanes = 1,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G3,
>
> .tbls = {
> .serdes = sdm845_ufsphy_serdes,
> @@ -1155,6 +1212,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G4,
>
> .tbls = {
> .serdes = sm8150_ufsphy_serdes,
> @@ -1170,13 +1228,14 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
> .serdes = sm8150_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
> },
> - .tbls_hs_g4 = {
> + .tbls_hs_overlay[0] = {
> .tx = sm8150_ufsphy_hs_g4_tx,
> .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx),
> .rx = sm8150_ufsphy_hs_g4_rx,
> .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx),
> .pcs = sm8150_ufsphy_hs_g4_pcs,
> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
> + .max_gear = UFS_HS_G4,
> },
> .clk_list = sdm845_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> @@ -1189,6 +1248,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G4,
>
> .tbls = {
> .serdes = sm8150_ufsphy_serdes,
> @@ -1204,13 +1264,14 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
> .serdes = sm8150_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
> },
> - .tbls_hs_g4 = {
> + .tbls_hs_overlay[0] = {
> .tx = sm8250_ufsphy_hs_g4_tx,
> .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
> .rx = sm8250_ufsphy_hs_g4_rx,
> .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx),
> .pcs = sm8150_ufsphy_hs_g4_pcs,
> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
> + .max_gear = UFS_HS_G4,
> },
> .clk_list = sdm845_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> @@ -1223,6 +1284,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G4,
>
> .tbls = {
> .serdes = sm8350_ufsphy_serdes,
> @@ -1238,13 +1300,14 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
> .serdes = sm8350_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> },
> - .tbls_hs_g4 = {
> + .tbls_hs_overlay[0] = {
> .tx = sm8350_ufsphy_g4_tx,
> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> .rx = sm8350_ufsphy_g4_rx,
> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> .pcs = sm8350_ufsphy_g4_pcs,
> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> + .max_gear = UFS_HS_G4,
> },
> .clk_list = sdm845_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> @@ -1257,6 +1320,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets,
> + .max_supported_gear = UFS_HS_G4,
>
> .tbls = {
> .serdes = sm8350_ufsphy_serdes,
> @@ -1272,13 +1336,14 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
> .serdes = sm8350_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> },
> - .tbls_hs_g4 = {
> + .tbls_hs_overlay[0] = {
> .tx = sm8350_ufsphy_g4_tx,
> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> .rx = sm8350_ufsphy_g4_rx,
> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> .pcs = sm8350_ufsphy_g4_pcs,
> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> + .max_gear = UFS_HS_G4,
> },
> .clk_list = sm8450_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
> @@ -1291,6 +1356,7 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
> .lanes = 2,
>
> .offsets = &qmp_ufs_offsets_v6,
> + .max_supported_gear = UFS_HS_G5,
>
> .tbls = {
> .serdes = sm8550_ufsphy_serdes,
> @@ -1306,6 +1372,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
> .serdes = sm8550_ufsphy_hs_b_serdes,
> .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
> },
> + .tbls_hs_overlay[0] = {
> + .serdes = sm8550_ufsphy_g4_serdes,
> + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes),
> + .tx = sm8550_ufsphy_g4_tx,
> + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx),
> + .rx = sm8550_ufsphy_g4_rx,
> + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx),
> + .pcs = sm8550_ufsphy_g4_pcs,
> + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs),
> + .max_gear = UFS_HS_G4,
> + },
> + .tbls_hs_overlay[1] = {
> + .serdes = sm8550_ufsphy_g5_serdes,
> + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes),
> + .rx = sm8550_ufsphy_g5_rx,
> + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx),
> + .pcs = sm8550_ufsphy_g5_pcs,
> + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs),
> + .max_gear = UFS_HS_G5,
> + },
> .clk_list = sdm845_ufs_phy_clk_l,
> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> .vreg_list = qmp_phy_vreg_l,
> @@ -1368,17 +1454,55 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls
> qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num);
> }
>
> +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
> +{
> + u32 max_gear, floor_max_gear = cfg->max_supported_gear;
> + int i = NUM_OVERLAY - 1;

Just use i directly in the for loop. Also, please rename "i" with "idx" to make
it clear.

> + int ret = -EINVAL;
> +
> + for (; i >= 0; i --) {

i--

> + max_gear = cfg->tbls_hs_overlay[i].max_gear;
> +
> + if (max_gear == 0)
> + continue;

You are setting max_gear even for targets with a single overlay. How can this
become 0?

> +
> + /* Direct matching, bail */
> + if (qmp->submode == max_gear)
> + return i;
> +
> + /* If no direct matching, the lowest gear is the best matching */
> + if (max_gear < floor_max_gear) {
> + ret = i;
> + floor_max_gear = max_gear;
> + }
> + }
> +
> + return ret;
> +}
> +
> static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
> {
> + int i;
> + bool apply_overlay = false;
> +
> + i = qmp_ufs_get_gear_overlay(qmp, cfg);
> + if (i >= 0)
> + apply_overlay = true;

How about?

```
int idx;

idx = qmp_ufs_get_gear_overlay(qmp, cfg);

qmp_ufs_serdes_init(qmp, &cfg->tbls);
qmp_ufs_lanes_init(qmp, &cfg->tbls);
...

if (idx >= 0) {
qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[idx]);
qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[idx]);
...
}
```

Since the ordering doesn't matter for init sequence, you can program the overlay
tables under a single condition.

- Mani

--
மணிவண்ணன் சதாசிவம்

2023-11-30 07:25:50

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v6 10/10] scsi: ufs: ufs-qcom: Add support for UFS device version detection

On Wed, Nov 29, 2023 at 12:28:35AM -0800, Can Guo wrote:
> From: "Bao D. Nguyen" <[email protected]>
>
> A spare register in UFS host controller is used to indicate the UFS device
> version. The spare register is populated by bootloader for now, but in
> future it will be populated by HW automatically during link startup with
> its best efforts in any boot stages prior to Linux.
>
> During host driver init, read the spare register, if it is not populated
> with a UFS device version, go ahead with the dual init mechanism. If a UFS
> device version is in there, use the UFS device version together with host
> controller's HW version to decide the proper PHY gear which should be used
> to configure the UFS PHY without going through the second init.
>
> Signed-off-by: Bao D. Nguyen <[email protected]>
> Signed-off-by: Can Guo <[email protected]>
> ---
> drivers/ufs/host/ufs-qcom.c | 23 ++++++++++++++++++-----
> drivers/ufs/host/ufs-qcom.h | 2 ++
> 2 files changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
> index 9c0ebbc..e94dea2 100644
> --- a/drivers/ufs/host/ufs-qcom.c
> +++ b/drivers/ufs/host/ufs-qcom.c
> @@ -1068,15 +1068,28 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
> static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
> {
> struct ufs_host_params *host_params = &host->host_params;
> + u32 val, dev_major = 0;

No need to initialize dev_major.

>
> host->phy_gear = host_params->hs_tx_gear;
>
> - /*
> - * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> - * Switching to max gear will be performed during reinit if supported.
> - */
> - if (host->hw_ver.major < 0x4)
> + if (host->hw_ver.major < 0x4) {
> + /*
> + * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> + * Switching to max gear will be performed during reinit if supported.
> + */
> host->phy_gear = UFS_HS_G2;
> + } else {

Can you please add a comment here to describe what is happening?

> + val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
> + dev_major = FIELD_GET(GENMASK(7, 4), val);

It'd be good to add a macro for GENMASK().

> +
> + /* UFS device version populated, no need to do init twice */

"Since the UFS device version is populated, let's remove the REINIT quirk as the
negotiated gear won't change during boot. So there is no need to do reinit."

> + if (dev_major != 0)

0x0

> + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
> +
> + /* For UFS 3.1 and older, apply HS-G4 PHY gear to save power */
> + if (dev_major < 0x4 && dev_major > 0)

if (dev_major > 0x0 && dev_major < 0x4)

- Mani

> + host->phy_gear = UFS_HS_G4;
> + }
> }
>
> static void ufs_qcom_set_host_params(struct ufs_hba *hba)
> diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
> index 11419eb..d12fc5a 100644
> --- a/drivers/ufs/host/ufs-qcom.h
> +++ b/drivers/ufs/host/ufs-qcom.h
> @@ -54,6 +54,8 @@ enum {
> UFS_AH8_CFG = 0xFC,
>
> REG_UFS_CFG3 = 0x271C,
> +
> + REG_UFS_DEBUG_SPARE_CFG = 0x284C,
> };
>
> /* QCOM UFS host controller vendor specific debug registers */
> --
> 2.7.4
>
>

--
மணிவண்ணன் சதாசிவம்

2023-11-30 07:29:29

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v6 10/10] scsi: ufs: ufs-qcom: Add support for UFS device version detection

On Wed, Nov 29, 2023 at 02:04:35PM -0500, Eric Chanudet wrote:
> On Wed, Nov 29, 2023 at 12:28:35AM -0800, Can Guo wrote:
> > From: "Bao D. Nguyen" <[email protected]>
> >
> > A spare register in UFS host controller is used to indicate the UFS device
> > version. The spare register is populated by bootloader for now, but in
> > future it will be populated by HW automatically during link startup with
> > its best efforts in any boot stages prior to Linux.
> >
> > During host driver init, read the spare register, if it is not populated
> > with a UFS device version, go ahead with the dual init mechanism. If a UFS
> > device version is in there, use the UFS device version together with host
> > controller's HW version to decide the proper PHY gear which should be used
> > to configure the UFS PHY without going through the second init.
> >
> > Signed-off-by: Bao D. Nguyen <[email protected]>
> > Signed-off-by: Can Guo <[email protected]>
> > ---
> > drivers/ufs/host/ufs-qcom.c | 23 ++++++++++++++++++-----
> > drivers/ufs/host/ufs-qcom.h | 2 ++
> > 2 files changed, 20 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
> > index 9c0ebbc..e94dea2 100644
> > --- a/drivers/ufs/host/ufs-qcom.c
> > +++ b/drivers/ufs/host/ufs-qcom.c
> > @@ -1068,15 +1068,28 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
> > static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
> > {
> > struct ufs_host_params *host_params = &host->host_params;
> > + u32 val, dev_major = 0;
> >
> > host->phy_gear = host_params->hs_tx_gear;
> >
> > - /*
> > - * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> > - * Switching to max gear will be performed during reinit if supported.
> > - */
> > - if (host->hw_ver.major < 0x4)
> > + if (host->hw_ver.major < 0x4) {
> > + /*
> > + * Power up the PHY using the minimum supported gear (UFS_HS_G2).
> > + * Switching to max gear will be performed during reinit if supported.
> > + */
> > host->phy_gear = UFS_HS_G2;
> > + } else {
> > + val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
> > + dev_major = FIELD_GET(GENMASK(7, 4), val);
> > +
> > + /* UFS device version populated, no need to do init twice */
>
> This change documents the content of the register as "UFS device
> version", both inline in the code and in the commit description. Earlier
> in this series[1], Mani mentioned it was the gear info:
> > > [...]populating a spare register in the bootloader with the max gear
> > > info that the bootloader has already found[...]
>
> Is it the gear number as in HS-G4? Or the version as in UFS controller
> revision 3.1?
>

That was a mistake from my end, apologies. The register has the device version
only and the driver uses both device and host controller's version info to
decide the initial gear.

- Mani

> [1] https://lore.kernel.org/all/20231018124741.GA47321@thinkpad/
>
> > + if (dev_major != 0)
> > + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
> > +
> > + /* For UFS 3.1 and older, apply HS-G4 PHY gear to save power */
> > + if (dev_major < 0x4 && dev_major > 0)
> > + host->phy_gear = UFS_HS_G4;
> > + }
> > }
> >
> > static void ufs_qcom_set_host_params(struct ufs_hba *hba)
> > diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
> > index 11419eb..d12fc5a 100644
> > --- a/drivers/ufs/host/ufs-qcom.h
> > +++ b/drivers/ufs/host/ufs-qcom.h
> > @@ -54,6 +54,8 @@ enum {
> > UFS_AH8_CFG = 0xFC,
> >
> > REG_UFS_CFG3 = 0x271C,
> > +
> > + REG_UFS_DEBUG_SPARE_CFG = 0x284C,
> > };
> >
> > /* QCOM UFS host controller vendor specific debug registers */
> > --
> > 2.7.4
> >
> >
>
> --
> Eric Chanudet
>
>

--
மணிவண்ணன் சதாசிவம்

2023-11-30 07:44:43

by Can Guo

[permalink] [raw]
Subject: Re: [PATCH v6 04/10] scsi: ufs: ufs-qcom: Allow the first init start with the maximum supported gear



On 11/30/2023 2:42 PM, Manivannan Sadhasivam wrote:
> On Wed, Nov 29, 2023 at 12:28:29AM -0800, Can Guo wrote:
>> During host driver init, the phy_gear is set to the minimum supported gear
>> (HS_G2). Then, during the first power mode change, the negotiated gear, say
>> HS-G4, is updated to the phy_gear variable so that in the second init the
>> updated phy_gear can be used to program the PHY.
>>
>> But the current code only allows update the phy_gear to a higher value. If
>> one wants to start the first init with the maximum support gear, say HS-G4,
>> the phy_gear is not updated to HS-G3 if the device only supports HS-G3.
>>
>> The original check added there is intend to make sure the phy_gear won't be
>> updated when gear is scaled down (during clock scaling). Update the check
>> so that one can start the first init with the maximum support gear without
>> breaking the original fix by checking the ufshcd_state, that is, allow
>> update to phy_gear only if power mode change is invoked from
>> ufshcd_probe_hba().
>>
>> This change is a preparation patch for the next patches in the same series.
>
> If you happen to respin the series, please remove this line. When the patches
> get merged, there will be no concept of patches/series as all will be git
> commits.
>
> You can have this information in the comment section (below --- line) though.
>

Sure, will remove it in next version.

Thanks,
Can Guo.

>>
>> Signed-off-by: Can Guo <[email protected]>
>
> Reviewed-by: Manivannan Sadhasivam <[email protected]>
>
> - Mani
>
>> ---
>> drivers/ufs/host/ufs-qcom.c | 9 +++++----
>> 1 file changed, 5 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
>> index 9a90019..81056b9 100644
>> --- a/drivers/ufs/host/ufs-qcom.c
>> +++ b/drivers/ufs/host/ufs-qcom.c
>> @@ -916,11 +916,12 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
>> }
>>
>> /*
>> - * Update phy_gear only when the gears are scaled to a higher value. This is
>> - * because, the PHY gear settings are backwards compatible and we only need to
>> - * change the PHY gear settings while scaling to higher gears.
>> + * During UFS driver probe, always update the PHY gear to match the negotiated
>> + * gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled,
>> + * the second init can program the optimal PHY settings. This allows one to start
>> + * the first init with either the minimum or the maximum support gear.
>> */
>> - if (dev_req_params->gear_tx > host->phy_gear)
>> + if (hba->ufshcd_state == UFSHCD_STATE_RESET)
>> host->phy_gear = dev_req_params->gear_tx;
>>
>> /* enable the device ref clock before changing to HS mode */
>> --
>> 2.7.4
>>
>>
>

2023-11-30 07:50:01

by Can Guo

[permalink] [raw]
Subject: Re: [PATCH v6 06/10] scsi: ufs: ufs-qcom: Set initial PHY gear to max HS gear for HW ver 4 and newer



On 11/30/2023 2:47 PM, Manivannan Sadhasivam wrote:
> On Wed, Nov 29, 2023 at 12:28:31AM -0800, Can Guo wrote:
>> Since HW ver 4, max HS gear can be get from UFS host controller's register,
>> use the max HS gear as the initial PHY gear instead of UFS_HS_G2, so that
>> we don't need to update the hard code for newer targets in future.
>>
>> Signed-off-by: Can Guo <[email protected]>
>
> One comment below. With that addressed,
>
> Reviewed-by: Manivannan Sadhasivam <[email protected]>
>
>> ---
>> drivers/ufs/host/ufs-qcom.c | 21 +++++++++++++++------
>> 1 file changed, 15 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
>> index aca6199..30f4ca6 100644
>> --- a/drivers/ufs/host/ufs-qcom.c
>> +++ b/drivers/ufs/host/ufs-qcom.c
>> @@ -1060,6 +1060,20 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
>> hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
>> }
>>
>> +static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
>> +{
>> + struct ufs_host_params *host_params = &host->host_params;
>> +
>> + host->phy_gear = host_params->hs_tx_gear;
>> +
>> + /*
>> + * Power up the PHY using the minimum supported gear (UFS_HS_G2).
>> + * Switching to max gear will be performed during reinit if supported.
>
> As I mentioned in v5, you need to reword this comment to make it clear we are
> setting G2 only for platforms < v4. Something like below:
>
> "For controllers whose major version is < 4, power up the PHY using minimum
> supported gear (UFS_HS_G2). Switching to max gear will be performed during
> reinit if supported. For newer controllers (>= 4), PHY will be powered up using
> max supported gear."

Sorry that I missed this one, will add in next version.

Thanks,
Can Guo.

>
> - Mani
>
>> + */
>> + if (host->hw_ver.major < 0x4)
>> + host->phy_gear = UFS_HS_G2;
>> +}
>> +
>> static void ufs_qcom_set_host_params(struct ufs_hba *hba)
>> {
>> struct ufs_qcom_host *host = ufshcd_get_variant(hba);
>> @@ -1296,6 +1310,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
>> ufs_qcom_set_caps(hba);
>> ufs_qcom_advertise_quirks(hba);
>> ufs_qcom_set_host_params(hba);
>> + ufs_qcom_set_phy_gear(host);
>>
>> err = ufs_qcom_ice_init(host);
>> if (err)
>> @@ -1313,12 +1328,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
>> dev_warn(dev, "%s: failed to configure the testbus %d\n",
>> __func__, err);
>>
>> - /*
>> - * Power up the PHY using the minimum supported gear (UFS_HS_G2).
>> - * Switching to max gear will be performed during reinit if supported.
>> - */
>> - host->phy_gear = UFS_HS_G2;
>> -
>> return 0;
>>
>> out_variant_clear:
>> --
>> 2.7.4
>>
>>
>

2023-11-30 08:15:43

by Can Guo

[permalink] [raw]
Subject: Re: [PATCH v6 08/10] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550



On 11/30/2023 3:12 PM, Manivannan Sadhasivam wrote:
> On Wed, Nov 29, 2023 at 12:28:33AM -0800, Can Guo wrote:
>> On SM8550, two sets of UFS PHY settings are provided, one set is to support
>> HS-G5, another set is to support HS-G4 and lower gears. The two sets of PHY
>> settings are programming different values to different registers, mixing
>> the two sets and/or overwriting one set with another set is definitely not
>> blessed by UFS PHY designers.
>>
>> To add HS-G5 support for SM8550, split the two sets of PHY settings into
>> their dedicated overlay tables, only the common parts of the two sets of
>> PHY settings are left in the .tbls.
>>
>> Consider we are going to add even higher gear support in future, to avoid
>> adding more tables with different names, rename the .tbls_hs_g4 and make it
>> an array, a size of 2 is enough as of now.
>>
>> In this case, .tbls alone is not a complete set of PHY settings, so either
>> tbls_hs_overlay[0] or tbls_hs_overlay[1] must be applied on top of the
>> .tbls to become a complete set of PHY settings.
>>
>> Signed-off-by: Can Guo <[email protected]>
>> ---
>> drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 2 +
>> drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h | 2 +
>> .../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 9 ++
>> drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 170 ++++++++++++++++++---
>> 4 files changed, 163 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
>> index c23d5e4..e563af5 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
>> @@ -18,6 +18,7 @@
>> #define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
>> #define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
>> #define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc
>> +#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c
>> #define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158
>> #define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c
>> #define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184
>> @@ -27,5 +28,6 @@
>> #define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8
>> #define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4
>> #define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc
>> +#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220
>>
>> #endif
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
>> index f420f8f..ef392ce 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
>> @@ -56,6 +56,8 @@
>> #define QSERDES_V6_COM_SYS_CLK_CTRL 0xe4
>> #define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8
>> #define QSERDES_V6_COM_PLL_IVCO 0xf4
>> +#define QSERDES_V6_COM_CMN_IETRIM 0xfc
>> +#define QSERDES_V6_COM_CMN_IPTRIM 0x100
>> #define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110
>> #define QSERDES_V6_COM_RESETSM_CNTRL 0x118
>> #define QSERDES_V6_COM_LOCK_CMP_EN 0x120
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
>> index 674f158..48f31c8 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
>> @@ -15,8 +15,15 @@
>>
>> #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08
>> #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
>> +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24
>> +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54
>> #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4
>> +#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc
>> +#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0
>> +#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4
>> #define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178
>> +#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc
>> +#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4
>> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208
>> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c
>> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214
>> @@ -28,6 +35,8 @@
>> #define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264
>> #define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270
>> #define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280
>> +#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284
>> #define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c
>> +#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8
>>
>> #endif
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
>> index 2173418..7e5f1154 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
>> @@ -41,6 +41,8 @@
>>
>> #define PHY_INIT_COMPLETE_TIMEOUT 10000
>>
>> +#define NUM_OVERLAY 2
>> +
>> struct qmp_phy_init_tbl {
>> unsigned int offset;
>> unsigned int val;
>> @@ -754,15 +756,22 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
>> +};
>> +
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
>> +};
>> +
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = {
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a),
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
>> @@ -771,19 +780,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
>> };
>>
>> -static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = {
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b),
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c),
>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
>> };
>>
>> static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = {
>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
>> +};
>> +
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = {
>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c),
>> };
>>
>> static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
>> - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
>>
>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2),
>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2),
>> @@ -799,16 +813,45 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
>> };
>>
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = {
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
>> +};
>> +
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = {
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff),
>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30),
>> +};
>> +
>> static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = {
>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69),
>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
>> - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
>> +};
>> +
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = {
>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
>> };
>>
>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_pcs[] = {
>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f),
>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e),
>> +};
>> +
>> struct qmp_ufs_offsets {
>> u16 serdes;
>> u16 pcs;
>> @@ -828,6 +871,8 @@ struct qmp_phy_cfg_tbls {
>> int rx_num;
>> const struct qmp_phy_init_tbl *pcs;
>> int pcs_num;
>> + /* Maximum supported Gear of this tbls */
>> + u32 max_gear;
>> };
>>
>> /* struct qmp_phy_cfg - per-PHY initialization config */
>> @@ -835,13 +880,15 @@ struct qmp_phy_cfg {
>> int lanes;
>>
>> const struct qmp_ufs_offsets *offsets;
>> + /* Maximum supported Gear of this config */
>> + u32 max_supported_gear;
>>
>> /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */
>> const struct qmp_phy_cfg_tbls tbls;
>> /* Additional sequence for HS Series B */
>> const struct qmp_phy_cfg_tbls tbls_hs_b;
>> - /* Additional sequence for HS G4 */
>> - const struct qmp_phy_cfg_tbls tbls_hs_g4;
>> + /* Additional sequence for different HS Gears */
>> + const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY];
>>
>> /* clock ids to be requested */
>> const char * const *clk_list;
>> @@ -944,6 +991,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
>> .lanes = 1,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G3,
>>
>> .tbls = {
>> .serdes = msm8996_ufsphy_serdes,
>> @@ -969,6 +1017,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G4,
>>
>> .tbls = {
>> .serdes = sm8350_ufsphy_serdes,
>> @@ -984,13 +1033,14 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
>> .serdes = sm8350_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>> },
>> - .tbls_hs_g4 = {
>> + .tbls_hs_overlay[0] = {
>> .tx = sm8350_ufsphy_g4_tx,
>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>> .rx = sm8350_ufsphy_g4_rx,
>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>> .pcs = sm8350_ufsphy_g4_pcs,
>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> },
>> .clk_list = sm8450_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
>> @@ -1003,6 +1053,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G4,
>>
>> .tbls = {
>> .serdes = sm8150_ufsphy_serdes,
>> @@ -1018,13 +1069,14 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
>> .serdes = sm8150_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
>> },
>> - .tbls_hs_g4 = {
>> + .tbls_hs_overlay[0] = {
>> .tx = sm8250_ufsphy_hs_g4_tx,
>> .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
>> .rx = sc7280_ufsphy_hs_g4_rx,
>> .rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx),
>> .pcs = sm8150_ufsphy_hs_g4_pcs,
>> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> },
>> .clk_list = sm8450_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
>> @@ -1037,6 +1089,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G4,
>>
>> .tbls = {
>> .serdes = sm8350_ufsphy_serdes,
>> @@ -1052,13 +1105,14 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
>> .serdes = sm8350_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>> },
>> - .tbls_hs_g4 = {
>> + .tbls_hs_overlay[0] = {
>> .tx = sm8350_ufsphy_g4_tx,
>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>> .rx = sm8350_ufsphy_g4_rx,
>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>> .pcs = sm8350_ufsphy_g4_pcs,
>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> },
>> .clk_list = sdm845_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>> @@ -1071,6 +1125,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G3,
>>
>> .tbls = {
>> .serdes = sdm845_ufsphy_serdes,
>> @@ -1099,6 +1154,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
>> .lanes = 1,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G3,
>>
>> .tbls = {
>> .serdes = sm6115_ufsphy_serdes,
>> @@ -1127,6 +1183,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = {
>> .lanes = 1,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G3,
>>
>> .tbls = {
>> .serdes = sdm845_ufsphy_serdes,
>> @@ -1155,6 +1212,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G4,
>>
>> .tbls = {
>> .serdes = sm8150_ufsphy_serdes,
>> @@ -1170,13 +1228,14 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
>> .serdes = sm8150_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
>> },
>> - .tbls_hs_g4 = {
>> + .tbls_hs_overlay[0] = {
>> .tx = sm8150_ufsphy_hs_g4_tx,
>> .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx),
>> .rx = sm8150_ufsphy_hs_g4_rx,
>> .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx),
>> .pcs = sm8150_ufsphy_hs_g4_pcs,
>> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> },
>> .clk_list = sdm845_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>> @@ -1189,6 +1248,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G4,
>>
>> .tbls = {
>> .serdes = sm8150_ufsphy_serdes,
>> @@ -1204,13 +1264,14 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
>> .serdes = sm8150_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
>> },
>> - .tbls_hs_g4 = {
>> + .tbls_hs_overlay[0] = {
>> .tx = sm8250_ufsphy_hs_g4_tx,
>> .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
>> .rx = sm8250_ufsphy_hs_g4_rx,
>> .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx),
>> .pcs = sm8150_ufsphy_hs_g4_pcs,
>> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> },
>> .clk_list = sdm845_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>> @@ -1223,6 +1284,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G4,
>>
>> .tbls = {
>> .serdes = sm8350_ufsphy_serdes,
>> @@ -1238,13 +1300,14 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
>> .serdes = sm8350_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>> },
>> - .tbls_hs_g4 = {
>> + .tbls_hs_overlay[0] = {
>> .tx = sm8350_ufsphy_g4_tx,
>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>> .rx = sm8350_ufsphy_g4_rx,
>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>> .pcs = sm8350_ufsphy_g4_pcs,
>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> },
>> .clk_list = sdm845_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>> @@ -1257,6 +1320,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets,
>> + .max_supported_gear = UFS_HS_G4,
>>
>> .tbls = {
>> .serdes = sm8350_ufsphy_serdes,
>> @@ -1272,13 +1336,14 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
>> .serdes = sm8350_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>> },
>> - .tbls_hs_g4 = {
>> + .tbls_hs_overlay[0] = {
>> .tx = sm8350_ufsphy_g4_tx,
>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>> .rx = sm8350_ufsphy_g4_rx,
>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>> .pcs = sm8350_ufsphy_g4_pcs,
>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> },
>> .clk_list = sm8450_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
>> @@ -1291,6 +1356,7 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
>> .lanes = 2,
>>
>> .offsets = &qmp_ufs_offsets_v6,
>> + .max_supported_gear = UFS_HS_G5,
>>
>> .tbls = {
>> .serdes = sm8550_ufsphy_serdes,
>> @@ -1306,6 +1372,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
>> .serdes = sm8550_ufsphy_hs_b_serdes,
>> .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
>> },
>> + .tbls_hs_overlay[0] = {
>> + .serdes = sm8550_ufsphy_g4_serdes,
>> + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes),
>> + .tx = sm8550_ufsphy_g4_tx,
>> + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx),
>> + .rx = sm8550_ufsphy_g4_rx,
>> + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx),
>> + .pcs = sm8550_ufsphy_g4_pcs,
>> + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs),
>> + .max_gear = UFS_HS_G4,
>> + },
>> + .tbls_hs_overlay[1] = {
>> + .serdes = sm8550_ufsphy_g5_serdes,
>> + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes),
>> + .rx = sm8550_ufsphy_g5_rx,
>> + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx),
>> + .pcs = sm8550_ufsphy_g5_pcs,
>> + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs),
>> + .max_gear = UFS_HS_G5,
>> + },
>> .clk_list = sdm845_ufs_phy_clk_l,
>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>> .vreg_list = qmp_phy_vreg_l,
>> @@ -1368,17 +1454,55 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls
>> qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num);
>> }
>>
>> +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
>> +{
>> + u32 max_gear, floor_max_gear = cfg->max_supported_gear;
>> + int i = NUM_OVERLAY - 1;
>
> Just use i directly in the for loop. Also, please rename "i" with "idx" to make
> it clear.

OK

>
>> + int ret = -EINVAL;
>> +
>> + for (; i >= 0; i --) {
>
> i--
>
>> + max_gear = cfg->tbls_hs_overlay[i].max_gear;
>> +
>> + if (max_gear == 0)
>> + continue;
>
> You are setting max_gear even for targets with a single overlay. How can this
> become 0?

Say 8550 has two overlays, 8450 has one overlay. We are sweeping all
overlays as NUM_OVERLAY == 2, so for 8450, there is one overlay
initialized, another one not initialized (max_gear == 0), we are
skipping the one which is not initialized.

>
>> +
>> + /* Direct matching, bail */
>> + if (qmp->submode == max_gear)
>> + return i;
>> +
>> + /* If no direct matching, the lowest gear is the best matching */
>> + if (max_gear < floor_max_gear) {
>> + ret = i;
>> + floor_max_gear = max_gear;
>> + }
>> + }
>> +
>> + return ret;
>> +}
>> +
>> static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
>> {
>> + int i;
>> + bool apply_overlay = false;
>> +
>> + i = qmp_ufs_get_gear_overlay(qmp, cfg);
>> + if (i >= 0)
>> + apply_overlay = true;
>
> How about?
>
> ```
> int idx;
>
> idx = qmp_ufs_get_gear_overlay(qmp, cfg);
>
> qmp_ufs_serdes_init(qmp, &cfg->tbls);
> qmp_ufs_lanes_init(qmp, &cfg->tbls);
> ...
>
> if (idx >= 0) {
> qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[idx]);
> qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[idx]);
> ...
> }
> ```
>
> Since the ordering doesn't matter for init sequence, you can program the overlay
> tables under a single condition.

We can do that, but we need to be careful. When I say (in my previous
reply) the ordering does not matter, that saying is from the UFS PHY HPG
doc. However, in SW implementation, the 'tbls_hs_b' is actually
overwriting one COM_VCO_TUNE_MAP register, the same register is also
programmed by common table or overlay table. So qmp_ufs_serdes_init(qmp,
&cfg->tbls_hs_b) should come after overlays.

Thanks,
Can Guo.

>
> - Mani
>

2023-11-30 08:22:20

by Can Guo

[permalink] [raw]
Subject: Re: [PATCH v6 10/10] scsi: ufs: ufs-qcom: Add support for UFS device version detection



On 11/30/2023 3:25 PM, Manivannan Sadhasivam wrote:
> On Wed, Nov 29, 2023 at 12:28:35AM -0800, Can Guo wrote:
>> From: "Bao D. Nguyen" <[email protected]>
>>
>> A spare register in UFS host controller is used to indicate the UFS device
>> version. The spare register is populated by bootloader for now, but in
>> future it will be populated by HW automatically during link startup with
>> its best efforts in any boot stages prior to Linux.
>>
>> During host driver init, read the spare register, if it is not populated
>> with a UFS device version, go ahead with the dual init mechanism. If a UFS
>> device version is in there, use the UFS device version together with host
>> controller's HW version to decide the proper PHY gear which should be used
>> to configure the UFS PHY without going through the second init.
>>
>> Signed-off-by: Bao D. Nguyen <[email protected]>
>> Signed-off-by: Can Guo <[email protected]>
>> ---
>> drivers/ufs/host/ufs-qcom.c | 23 ++++++++++++++++++-----
>> drivers/ufs/host/ufs-qcom.h | 2 ++
>> 2 files changed, 20 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
>> index 9c0ebbc..e94dea2 100644
>> --- a/drivers/ufs/host/ufs-qcom.c
>> +++ b/drivers/ufs/host/ufs-qcom.c
>> @@ -1068,15 +1068,28 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
>> static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
>> {
>> struct ufs_host_params *host_params = &host->host_params;
>> + u32 val, dev_major = 0;
>
> No need to initialize dev_major.

True.

>
>>
>> host->phy_gear = host_params->hs_tx_gear;
>>
>> - /*
>> - * Power up the PHY using the minimum supported gear (UFS_HS_G2).
>> - * Switching to max gear will be performed during reinit if supported.
>> - */
>> - if (host->hw_ver.major < 0x4)
>> + if (host->hw_ver.major < 0x4) {
>> + /*
>> + * Power up the PHY using the minimum supported gear (UFS_HS_G2).
>> + * Switching to max gear will be performed during reinit if supported.
>> + */
>> host->phy_gear = UFS_HS_G2;
>> + } else {
>
> Can you please add a comment here to describe what is happening?

Will do.

>
>> + val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
>> + dev_major = FIELD_GET(GENMASK(7, 4), val);
>
> It'd be good to add a macro for GENMASK().

OK

>
>> +
>> + /* UFS device version populated, no need to do init twice */
>
> "Since the UFS device version is populated, let's remove the REINIT quirk as the
> negotiated gear won't change during boot. So there is no need to do reinit."
>

Nice comment.

>> + if (dev_major != 0)
>
> 0x0

Done

>
>> + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
>> +
>> + /* For UFS 3.1 and older, apply HS-G4 PHY gear to save power */
>> + if (dev_major < 0x4 && dev_major > 0)
>
> if (dev_major > 0x0 && dev_major < 0x4)
>

Sure.

Thanks,
Can Guo.

> - Mani
>
>> + host->phy_gear = UFS_HS_G4;
>> + }
>> }
>>
>> static void ufs_qcom_set_host_params(struct ufs_hba *hba)
>> diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
>> index 11419eb..d12fc5a 100644
>> --- a/drivers/ufs/host/ufs-qcom.h
>> +++ b/drivers/ufs/host/ufs-qcom.h
>> @@ -54,6 +54,8 @@ enum {
>> UFS_AH8_CFG = 0xFC,
>>
>> REG_UFS_CFG3 = 0x271C,
>> +
>> + REG_UFS_DEBUG_SPARE_CFG = 0x284C,
>> };
>>
>> /* QCOM UFS host controller vendor specific debug registers */
>> --
>> 2.7.4
>>
>>
>

2023-11-30 08:38:52

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v6 08/10] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550

On Thu, Nov 30, 2023 at 04:14:25PM +0800, Can Guo wrote:
>
>
> On 11/30/2023 3:12 PM, Manivannan Sadhasivam wrote:
> > On Wed, Nov 29, 2023 at 12:28:33AM -0800, Can Guo wrote:
> > > On SM8550, two sets of UFS PHY settings are provided, one set is to support
> > > HS-G5, another set is to support HS-G4 and lower gears. The two sets of PHY
> > > settings are programming different values to different registers, mixing
> > > the two sets and/or overwriting one set with another set is definitely not
> > > blessed by UFS PHY designers.
> > >
> > > To add HS-G5 support for SM8550, split the two sets of PHY settings into
> > > their dedicated overlay tables, only the common parts of the two sets of
> > > PHY settings are left in the .tbls.
> > >
> > > Consider we are going to add even higher gear support in future, to avoid
> > > adding more tables with different names, rename the .tbls_hs_g4 and make it
> > > an array, a size of 2 is enough as of now.
> > >
> > > In this case, .tbls alone is not a complete set of PHY settings, so either
> > > tbls_hs_overlay[0] or tbls_hs_overlay[1] must be applied on top of the
> > > .tbls to become a complete set of PHY settings.
> > >
> > > Signed-off-by: Can Guo <[email protected]>
> > > ---
> > > drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 2 +
> > > drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h | 2 +
> > > .../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 9 ++
> > > drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 170 ++++++++++++++++++---
> > > 4 files changed, 163 insertions(+), 20 deletions(-)
> > >
> > > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
> > > index c23d5e4..e563af5 100644
> > > --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
> > > +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
> > > @@ -18,6 +18,7 @@
> > > #define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
> > > #define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
> > > #define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc
> > > +#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c
> > > #define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158
> > > #define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c
> > > #define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184
> > > @@ -27,5 +28,6 @@
> > > #define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8
> > > #define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4
> > > #define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc
> > > +#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220
> > > #endif
> > > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
> > > index f420f8f..ef392ce 100644
> > > --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
> > > +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
> > > @@ -56,6 +56,8 @@
> > > #define QSERDES_V6_COM_SYS_CLK_CTRL 0xe4
> > > #define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8
> > > #define QSERDES_V6_COM_PLL_IVCO 0xf4
> > > +#define QSERDES_V6_COM_CMN_IETRIM 0xfc
> > > +#define QSERDES_V6_COM_CMN_IPTRIM 0x100
> > > #define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110
> > > #define QSERDES_V6_COM_RESETSM_CNTRL 0x118
> > > #define QSERDES_V6_COM_LOCK_CMP_EN 0x120
> > > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
> > > index 674f158..48f31c8 100644
> > > --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
> > > +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
> > > @@ -15,8 +15,15 @@
> > > #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08
> > > #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
> > > +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24
> > > +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54
> > > #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4
> > > +#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc
> > > +#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0
> > > +#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4
> > > #define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178
> > > +#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc
> > > +#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4
> > > #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208
> > > #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c
> > > #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214
> > > @@ -28,6 +35,8 @@
> > > #define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264
> > > #define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270
> > > #define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280
> > > +#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284
> > > #define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c
> > > +#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8
> > > #endif
> > > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
> > > index 2173418..7e5f1154 100644
> > > --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
> > > +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
> > > @@ -41,6 +41,8 @@
> > > #define PHY_INIT_COMPLETE_TIMEOUT 10000
> > > +#define NUM_OVERLAY 2
> > > +
> > > struct qmp_phy_init_tbl {
> > > unsigned int offset;
> > > unsigned int val;
> > > @@ -754,15 +756,22 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
> > > - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
> > > - QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
> > > - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
> > > +};
> > > +
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
> > > +};
> > > +
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = {
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a),
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
> > > @@ -771,19 +780,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
> > > QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
> > > };
> > > -static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
> > > - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = {
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b),
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c),
> > > + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
> > > };
> > > static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = {
> > > QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
> > > QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
> > > +};
> > > +
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = {
> > > QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c),
> > > };
> > > static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
> > > QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
> > > - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
> > > QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2),
> > > QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2),
> > > @@ -799,16 +813,45 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
> > > QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
> > > };
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = {
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
> > > +};
> > > +
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = {
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff),
> > > + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30),
> > > +};
> > > +
> > > static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = {
> > > QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69),
> > > QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
> > > QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
> > > - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
> > > QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
> > > +};
> > > +
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = {
> > > + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
> > > QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
> > > QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
> > > };
> > > +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_pcs[] = {
> > > + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
> > > + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f),
> > > + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e),
> > > +};
> > > +
> > > struct qmp_ufs_offsets {
> > > u16 serdes;
> > > u16 pcs;
> > > @@ -828,6 +871,8 @@ struct qmp_phy_cfg_tbls {
> > > int rx_num;
> > > const struct qmp_phy_init_tbl *pcs;
> > > int pcs_num;
> > > + /* Maximum supported Gear of this tbls */
> > > + u32 max_gear;
> > > };
> > > /* struct qmp_phy_cfg - per-PHY initialization config */
> > > @@ -835,13 +880,15 @@ struct qmp_phy_cfg {
> > > int lanes;
> > > const struct qmp_ufs_offsets *offsets;
> > > + /* Maximum supported Gear of this config */
> > > + u32 max_supported_gear;
> > > /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */
> > > const struct qmp_phy_cfg_tbls tbls;
> > > /* Additional sequence for HS Series B */
> > > const struct qmp_phy_cfg_tbls tbls_hs_b;
> > > - /* Additional sequence for HS G4 */
> > > - const struct qmp_phy_cfg_tbls tbls_hs_g4;
> > > + /* Additional sequence for different HS Gears */
> > > + const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY];
> > > /* clock ids to be requested */
> > > const char * const *clk_list;
> > > @@ -944,6 +991,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
> > > .lanes = 1,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G3,
> > > .tbls = {
> > > .serdes = msm8996_ufsphy_serdes,
> > > @@ -969,6 +1017,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G4,
> > > .tbls = {
> > > .serdes = sm8350_ufsphy_serdes,
> > > @@ -984,13 +1033,14 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
> > > .serdes = sm8350_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> > > },
> > > - .tbls_hs_g4 = {
> > > + .tbls_hs_overlay[0] = {
> > > .tx = sm8350_ufsphy_g4_tx,
> > > .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> > > .rx = sm8350_ufsphy_g4_rx,
> > > .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> > > .pcs = sm8350_ufsphy_g4_pcs,
> > > .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > },
> > > .clk_list = sm8450_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
> > > @@ -1003,6 +1053,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G4,
> > > .tbls = {
> > > .serdes = sm8150_ufsphy_serdes,
> > > @@ -1018,13 +1069,14 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
> > > .serdes = sm8150_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
> > > },
> > > - .tbls_hs_g4 = {
> > > + .tbls_hs_overlay[0] = {
> > > .tx = sm8250_ufsphy_hs_g4_tx,
> > > .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
> > > .rx = sc7280_ufsphy_hs_g4_rx,
> > > .rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx),
> > > .pcs = sm8150_ufsphy_hs_g4_pcs,
> > > .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > },
> > > .clk_list = sm8450_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
> > > @@ -1037,6 +1089,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G4,
> > > .tbls = {
> > > .serdes = sm8350_ufsphy_serdes,
> > > @@ -1052,13 +1105,14 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
> > > .serdes = sm8350_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> > > },
> > > - .tbls_hs_g4 = {
> > > + .tbls_hs_overlay[0] = {
> > > .tx = sm8350_ufsphy_g4_tx,
> > > .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> > > .rx = sm8350_ufsphy_g4_rx,
> > > .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> > > .pcs = sm8350_ufsphy_g4_pcs,
> > > .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > },
> > > .clk_list = sdm845_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> > > @@ -1071,6 +1125,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G3,
> > > .tbls = {
> > > .serdes = sdm845_ufsphy_serdes,
> > > @@ -1099,6 +1154,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
> > > .lanes = 1,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G3,
> > > .tbls = {
> > > .serdes = sm6115_ufsphy_serdes,
> > > @@ -1127,6 +1183,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = {
> > > .lanes = 1,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G3,
> > > .tbls = {
> > > .serdes = sdm845_ufsphy_serdes,
> > > @@ -1155,6 +1212,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G4,
> > > .tbls = {
> > > .serdes = sm8150_ufsphy_serdes,
> > > @@ -1170,13 +1228,14 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
> > > .serdes = sm8150_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
> > > },
> > > - .tbls_hs_g4 = {
> > > + .tbls_hs_overlay[0] = {
> > > .tx = sm8150_ufsphy_hs_g4_tx,
> > > .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx),
> > > .rx = sm8150_ufsphy_hs_g4_rx,
> > > .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx),
> > > .pcs = sm8150_ufsphy_hs_g4_pcs,
> > > .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > },
> > > .clk_list = sdm845_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> > > @@ -1189,6 +1248,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G4,
> > > .tbls = {
> > > .serdes = sm8150_ufsphy_serdes,
> > > @@ -1204,13 +1264,14 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
> > > .serdes = sm8150_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
> > > },
> > > - .tbls_hs_g4 = {
> > > + .tbls_hs_overlay[0] = {
> > > .tx = sm8250_ufsphy_hs_g4_tx,
> > > .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
> > > .rx = sm8250_ufsphy_hs_g4_rx,
> > > .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx),
> > > .pcs = sm8150_ufsphy_hs_g4_pcs,
> > > .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > },
> > > .clk_list = sdm845_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> > > @@ -1223,6 +1284,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G4,
> > > .tbls = {
> > > .serdes = sm8350_ufsphy_serdes,
> > > @@ -1238,13 +1300,14 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
> > > .serdes = sm8350_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> > > },
> > > - .tbls_hs_g4 = {
> > > + .tbls_hs_overlay[0] = {
> > > .tx = sm8350_ufsphy_g4_tx,
> > > .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> > > .rx = sm8350_ufsphy_g4_rx,
> > > .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> > > .pcs = sm8350_ufsphy_g4_pcs,
> > > .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > },
> > > .clk_list = sdm845_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> > > @@ -1257,6 +1320,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets,
> > > + .max_supported_gear = UFS_HS_G4,
> > > .tbls = {
> > > .serdes = sm8350_ufsphy_serdes,
> > > @@ -1272,13 +1336,14 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
> > > .serdes = sm8350_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
> > > },
> > > - .tbls_hs_g4 = {
> > > + .tbls_hs_overlay[0] = {
> > > .tx = sm8350_ufsphy_g4_tx,
> > > .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
> > > .rx = sm8350_ufsphy_g4_rx,
> > > .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
> > > .pcs = sm8350_ufsphy_g4_pcs,
> > > .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > },
> > > .clk_list = sm8450_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
> > > @@ -1291,6 +1356,7 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
> > > .lanes = 2,
> > > .offsets = &qmp_ufs_offsets_v6,
> > > + .max_supported_gear = UFS_HS_G5,
> > > .tbls = {
> > > .serdes = sm8550_ufsphy_serdes,
> > > @@ -1306,6 +1372,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
> > > .serdes = sm8550_ufsphy_hs_b_serdes,
> > > .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
> > > },
> > > + .tbls_hs_overlay[0] = {
> > > + .serdes = sm8550_ufsphy_g4_serdes,
> > > + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes),
> > > + .tx = sm8550_ufsphy_g4_tx,
> > > + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx),
> > > + .rx = sm8550_ufsphy_g4_rx,
> > > + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx),
> > > + .pcs = sm8550_ufsphy_g4_pcs,
> > > + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs),
> > > + .max_gear = UFS_HS_G4,
> > > + },
> > > + .tbls_hs_overlay[1] = {
> > > + .serdes = sm8550_ufsphy_g5_serdes,
> > > + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes),
> > > + .rx = sm8550_ufsphy_g5_rx,
> > > + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx),
> > > + .pcs = sm8550_ufsphy_g5_pcs,
> > > + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs),
> > > + .max_gear = UFS_HS_G5,
> > > + },
> > > .clk_list = sdm845_ufs_phy_clk_l,
> > > .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
> > > .vreg_list = qmp_phy_vreg_l,
> > > @@ -1368,17 +1454,55 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls
> > > qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num);
> > > }
> > > +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
> > > +{
> > > + u32 max_gear, floor_max_gear = cfg->max_supported_gear;
> > > + int i = NUM_OVERLAY - 1;
> >
> > Just use i directly in the for loop. Also, please rename "i" with "idx" to make
> > it clear.
>
> OK
>
> >
> > > + int ret = -EINVAL;
> > > +
> > > + for (; i >= 0; i --) {
> >
> > i--
> >
> > > + max_gear = cfg->tbls_hs_overlay[i].max_gear;
> > > +
> > > + if (max_gear == 0)
> > > + continue;
> >
> > You are setting max_gear even for targets with a single overlay. How can this
> > become 0?
>
> Say 8550 has two overlays, 8450 has one overlay. We are sweeping all
> overlays as NUM_OVERLAY == 2, so for 8450, there is one overlay initialized,
> another one not initialized (max_gear == 0), we are skipping the one which
> is not initialized.
>

This is confusing at its best :) Please check for the existence of the actual
table instead. Like,

for (idx = NUM_OVERLAY - 1; i >= 0, i--) {

/* Skip if the table is not available */
if (!cfg->tbls_hs_overlay[i].serdes)
continue;

...
}

> >
> > > +
> > > + /* Direct matching, bail */
> > > + if (qmp->submode == max_gear)
> > > + return i;
> > > +
> > > + /* If no direct matching, the lowest gear is the best matching */
> > > + if (max_gear < floor_max_gear) {
> > > + ret = i;
> > > + floor_max_gear = max_gear;
> > > + }
> > > + }
> > > +
> > > + return ret;
> > > +}
> > > +
> > > static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
> > > {
> > > + int i;
> > > + bool apply_overlay = false;
> > > +
> > > + i = qmp_ufs_get_gear_overlay(qmp, cfg);
> > > + if (i >= 0)
> > > + apply_overlay = true;
> >
> > How about?
> >
> > ```
> > int idx;
> >
> > idx = qmp_ufs_get_gear_overlay(qmp, cfg);
> >
> > qmp_ufs_serdes_init(qmp, &cfg->tbls);
> > qmp_ufs_lanes_init(qmp, &cfg->tbls);
> > ...
> >
> > if (idx >= 0) {
> > qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[idx]);
> > qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[idx]);
> > ...
> > }
> > ```
> >
> > Since the ordering doesn't matter for init sequence, you can program the overlay
> > tables under a single condition.
>
> We can do that, but we need to be careful. When I say (in my previous reply)
> the ordering does not matter, that saying is from the UFS PHY HPG doc.
> However, in SW implementation, the 'tbls_hs_b' is actually overwriting one
> COM_VCO_TUNE_MAP register, the same register is also programmed by common
> table or overlay table. So qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b) should
> come after overlays.
>

Then you can program tbls_hs_b after overlay tables. Wouldn't that work?

- Mani

> Thanks,
> Can Guo.
>
> >
> > - Mani
> >

--
மணிவண்ணன் சதாசிவம்

2023-11-30 08:52:18

by Can Guo

[permalink] [raw]
Subject: Re: [PATCH v6 08/10] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550



On 11/30/2023 4:38 PM, Manivannan Sadhasivam wrote:
> On Thu, Nov 30, 2023 at 04:14:25PM +0800, Can Guo wrote:
>>
>>
>> On 11/30/2023 3:12 PM, Manivannan Sadhasivam wrote:
>>> On Wed, Nov 29, 2023 at 12:28:33AM -0800, Can Guo wrote:
>>>> On SM8550, two sets of UFS PHY settings are provided, one set is to support
>>>> HS-G5, another set is to support HS-G4 and lower gears. The two sets of PHY
>>>> settings are programming different values to different registers, mixing
>>>> the two sets and/or overwriting one set with another set is definitely not
>>>> blessed by UFS PHY designers.
>>>>
>>>> To add HS-G5 support for SM8550, split the two sets of PHY settings into
>>>> their dedicated overlay tables, only the common parts of the two sets of
>>>> PHY settings are left in the .tbls.
>>>>
>>>> Consider we are going to add even higher gear support in future, to avoid
>>>> adding more tables with different names, rename the .tbls_hs_g4 and make it
>>>> an array, a size of 2 is enough as of now.
>>>>
>>>> In this case, .tbls alone is not a complete set of PHY settings, so either
>>>> tbls_hs_overlay[0] or tbls_hs_overlay[1] must be applied on top of the
>>>> .tbls to become a complete set of PHY settings.
>>>>
>>>> Signed-off-by: Can Guo <[email protected]>
>>>> ---
>>>> drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 2 +
>>>> drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h | 2 +
>>>> .../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 9 ++
>>>> drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 170 ++++++++++++++++++---
>>>> 4 files changed, 163 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
>>>> index c23d5e4..e563af5 100644
>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
>>>> @@ -18,6 +18,7 @@
>>>> #define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
>>>> #define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
>>>> #define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc
>>>> +#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c
>>>> #define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158
>>>> #define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c
>>>> #define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184
>>>> @@ -27,5 +28,6 @@
>>>> #define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8
>>>> #define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4
>>>> #define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc
>>>> +#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220
>>>> #endif
>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
>>>> index f420f8f..ef392ce 100644
>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
>>>> @@ -56,6 +56,8 @@
>>>> #define QSERDES_V6_COM_SYS_CLK_CTRL 0xe4
>>>> #define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8
>>>> #define QSERDES_V6_COM_PLL_IVCO 0xf4
>>>> +#define QSERDES_V6_COM_CMN_IETRIM 0xfc
>>>> +#define QSERDES_V6_COM_CMN_IPTRIM 0x100
>>>> #define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110
>>>> #define QSERDES_V6_COM_RESETSM_CNTRL 0x118
>>>> #define QSERDES_V6_COM_LOCK_CMP_EN 0x120
>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
>>>> index 674f158..48f31c8 100644
>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
>>>> @@ -15,8 +15,15 @@
>>>> #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08
>>>> #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
>>>> +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24
>>>> +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54
>>>> #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4
>>>> +#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc
>>>> +#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0
>>>> +#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4
>>>> #define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178
>>>> +#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc
>>>> +#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4
>>>> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208
>>>> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c
>>>> #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214
>>>> @@ -28,6 +35,8 @@
>>>> #define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264
>>>> #define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270
>>>> #define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280
>>>> +#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284
>>>> #define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c
>>>> +#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8
>>>> #endif
>>>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
>>>> index 2173418..7e5f1154 100644
>>>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
>>>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
>>>> @@ -41,6 +41,8 @@
>>>> #define PHY_INIT_COMPLETE_TIMEOUT 10000
>>>> +#define NUM_OVERLAY 2
>>>> +
>>>> struct qmp_phy_init_tbl {
>>>> unsigned int offset;
>>>> unsigned int val;
>>>> @@ -754,15 +756,22 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
>>>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
>>>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
>>>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
>>>> +};
>>>> +
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
>>>> +};
>>>> +
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = {
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a),
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
>>>> @@ -771,19 +780,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
>>>> QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
>>>> };
>>>> -static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = {
>>>> - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44),
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = {
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b),
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c),
>>>> + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
>>>> };
>>>> static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = {
>>>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
>>>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
>>>> +};
>>>> +
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = {
>>>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c),
>>>> };
>>>> static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
>>>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
>>>> - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
>>>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2),
>>>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2),
>>>> @@ -799,16 +813,45 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
>>>> QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
>>>> };
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = {
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
>>>> +};
>>>> +
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = {
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff),
>>>> + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30),
>>>> +};
>>>> +
>>>> static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = {
>>>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69),
>>>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
>>>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
>>>> - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
>>>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
>>>> +};
>>>> +
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = {
>>>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
>>>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
>>>> QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
>>>> };
>>>> +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_pcs[] = {
>>>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
>>>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f),
>>>> + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e),
>>>> +};
>>>> +
>>>> struct qmp_ufs_offsets {
>>>> u16 serdes;
>>>> u16 pcs;
>>>> @@ -828,6 +871,8 @@ struct qmp_phy_cfg_tbls {
>>>> int rx_num;
>>>> const struct qmp_phy_init_tbl *pcs;
>>>> int pcs_num;
>>>> + /* Maximum supported Gear of this tbls */
>>>> + u32 max_gear;
>>>> };
>>>> /* struct qmp_phy_cfg - per-PHY initialization config */
>>>> @@ -835,13 +880,15 @@ struct qmp_phy_cfg {
>>>> int lanes;
>>>> const struct qmp_ufs_offsets *offsets;
>>>> + /* Maximum supported Gear of this config */
>>>> + u32 max_supported_gear;
>>>> /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */
>>>> const struct qmp_phy_cfg_tbls tbls;
>>>> /* Additional sequence for HS Series B */
>>>> const struct qmp_phy_cfg_tbls tbls_hs_b;
>>>> - /* Additional sequence for HS G4 */
>>>> - const struct qmp_phy_cfg_tbls tbls_hs_g4;
>>>> + /* Additional sequence for different HS Gears */
>>>> + const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY];
>>>> /* clock ids to be requested */
>>>> const char * const *clk_list;
>>>> @@ -944,6 +991,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
>>>> .lanes = 1,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G3,
>>>> .tbls = {
>>>> .serdes = msm8996_ufsphy_serdes,
>>>> @@ -969,6 +1017,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G4,
>>>> .tbls = {
>>>> .serdes = sm8350_ufsphy_serdes,
>>>> @@ -984,13 +1033,14 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
>>>> .serdes = sm8350_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>>>> },
>>>> - .tbls_hs_g4 = {
>>>> + .tbls_hs_overlay[0] = {
>>>> .tx = sm8350_ufsphy_g4_tx,
>>>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>>>> .rx = sm8350_ufsphy_g4_rx,
>>>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>>>> .pcs = sm8350_ufsphy_g4_pcs,
>>>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> },
>>>> .clk_list = sm8450_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
>>>> @@ -1003,6 +1053,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G4,
>>>> .tbls = {
>>>> .serdes = sm8150_ufsphy_serdes,
>>>> @@ -1018,13 +1069,14 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = {
>>>> .serdes = sm8150_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
>>>> },
>>>> - .tbls_hs_g4 = {
>>>> + .tbls_hs_overlay[0] = {
>>>> .tx = sm8250_ufsphy_hs_g4_tx,
>>>> .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
>>>> .rx = sc7280_ufsphy_hs_g4_rx,
>>>> .rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx),
>>>> .pcs = sm8150_ufsphy_hs_g4_pcs,
>>>> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> },
>>>> .clk_list = sm8450_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
>>>> @@ -1037,6 +1089,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G4,
>>>> .tbls = {
>>>> .serdes = sm8350_ufsphy_serdes,
>>>> @@ -1052,13 +1105,14 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
>>>> .serdes = sm8350_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>>>> },
>>>> - .tbls_hs_g4 = {
>>>> + .tbls_hs_overlay[0] = {
>>>> .tx = sm8350_ufsphy_g4_tx,
>>>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>>>> .rx = sm8350_ufsphy_g4_rx,
>>>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>>>> .pcs = sm8350_ufsphy_g4_pcs,
>>>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> },
>>>> .clk_list = sdm845_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>>>> @@ -1071,6 +1125,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G3,
>>>> .tbls = {
>>>> .serdes = sdm845_ufsphy_serdes,
>>>> @@ -1099,6 +1154,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
>>>> .lanes = 1,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G3,
>>>> .tbls = {
>>>> .serdes = sm6115_ufsphy_serdes,
>>>> @@ -1127,6 +1183,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = {
>>>> .lanes = 1,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G3,
>>>> .tbls = {
>>>> .serdes = sdm845_ufsphy_serdes,
>>>> @@ -1155,6 +1212,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G4,
>>>> .tbls = {
>>>> .serdes = sm8150_ufsphy_serdes,
>>>> @@ -1170,13 +1228,14 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
>>>> .serdes = sm8150_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
>>>> },
>>>> - .tbls_hs_g4 = {
>>>> + .tbls_hs_overlay[0] = {
>>>> .tx = sm8150_ufsphy_hs_g4_tx,
>>>> .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx),
>>>> .rx = sm8150_ufsphy_hs_g4_rx,
>>>> .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx),
>>>> .pcs = sm8150_ufsphy_hs_g4_pcs,
>>>> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> },
>>>> .clk_list = sdm845_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>>>> @@ -1189,6 +1248,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G4,
>>>> .tbls = {
>>>> .serdes = sm8150_ufsphy_serdes,
>>>> @@ -1204,13 +1264,14 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
>>>> .serdes = sm8150_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
>>>> },
>>>> - .tbls_hs_g4 = {
>>>> + .tbls_hs_overlay[0] = {
>>>> .tx = sm8250_ufsphy_hs_g4_tx,
>>>> .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
>>>> .rx = sm8250_ufsphy_hs_g4_rx,
>>>> .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx),
>>>> .pcs = sm8150_ufsphy_hs_g4_pcs,
>>>> .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> },
>>>> .clk_list = sdm845_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>>>> @@ -1223,6 +1284,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G4,
>>>> .tbls = {
>>>> .serdes = sm8350_ufsphy_serdes,
>>>> @@ -1238,13 +1300,14 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
>>>> .serdes = sm8350_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>>>> },
>>>> - .tbls_hs_g4 = {
>>>> + .tbls_hs_overlay[0] = {
>>>> .tx = sm8350_ufsphy_g4_tx,
>>>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>>>> .rx = sm8350_ufsphy_g4_rx,
>>>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>>>> .pcs = sm8350_ufsphy_g4_pcs,
>>>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> },
>>>> .clk_list = sdm845_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>>>> @@ -1257,6 +1320,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets,
>>>> + .max_supported_gear = UFS_HS_G4,
>>>> .tbls = {
>>>> .serdes = sm8350_ufsphy_serdes,
>>>> @@ -1272,13 +1336,14 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
>>>> .serdes = sm8350_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
>>>> },
>>>> - .tbls_hs_g4 = {
>>>> + .tbls_hs_overlay[0] = {
>>>> .tx = sm8350_ufsphy_g4_tx,
>>>> .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
>>>> .rx = sm8350_ufsphy_g4_rx,
>>>> .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
>>>> .pcs = sm8350_ufsphy_g4_pcs,
>>>> .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> },
>>>> .clk_list = sm8450_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
>>>> @@ -1291,6 +1356,7 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
>>>> .lanes = 2,
>>>> .offsets = &qmp_ufs_offsets_v6,
>>>> + .max_supported_gear = UFS_HS_G5,
>>>> .tbls = {
>>>> .serdes = sm8550_ufsphy_serdes,
>>>> @@ -1306,6 +1372,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
>>>> .serdes = sm8550_ufsphy_hs_b_serdes,
>>>> .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
>>>> },
>>>> + .tbls_hs_overlay[0] = {
>>>> + .serdes = sm8550_ufsphy_g4_serdes,
>>>> + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes),
>>>> + .tx = sm8550_ufsphy_g4_tx,
>>>> + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx),
>>>> + .rx = sm8550_ufsphy_g4_rx,
>>>> + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx),
>>>> + .pcs = sm8550_ufsphy_g4_pcs,
>>>> + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs),
>>>> + .max_gear = UFS_HS_G4,
>>>> + },
>>>> + .tbls_hs_overlay[1] = {
>>>> + .serdes = sm8550_ufsphy_g5_serdes,
>>>> + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes),
>>>> + .rx = sm8550_ufsphy_g5_rx,
>>>> + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx),
>>>> + .pcs = sm8550_ufsphy_g5_pcs,
>>>> + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs),
>>>> + .max_gear = UFS_HS_G5,
>>>> + },
>>>> .clk_list = sdm845_ufs_phy_clk_l,
>>>> .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
>>>> .vreg_list = qmp_phy_vreg_l,
>>>> @@ -1368,17 +1454,55 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls
>>>> qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num);
>>>> }
>>>> +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
>>>> +{
>>>> + u32 max_gear, floor_max_gear = cfg->max_supported_gear;
>>>> + int i = NUM_OVERLAY - 1;
>>>
>>> Just use i directly in the for loop. Also, please rename "i" with "idx" to make
>>> it clear.
>>
>> OK
>>
>>>
>>>> + int ret = -EINVAL;
>>>> +
>>>> + for (; i >= 0; i --) {
>>>
>>> i--
>>>
>>>> + max_gear = cfg->tbls_hs_overlay[i].max_gear;
>>>> +
>>>> + if (max_gear == 0)
>>>> + continue;
>>>
>>> You are setting max_gear even for targets with a single overlay. How can this
>>> become 0?
>>
>> Say 8550 has two overlays, 8450 has one overlay. We are sweeping all
>> overlays as NUM_OVERLAY == 2, so for 8450, there is one overlay initialized,
>> another one not initialized (max_gear == 0), we are skipping the one which
>> is not initialized.
>>
>
> This is confusing at its best :) Please check for the existence of the actual
> table instead. Like,
>
> for (idx = NUM_OVERLAY - 1; i >= 0, i--) {
>
> /* Skip if the table is not available */
> if (!cfg->tbls_hs_overlay[i].serdes)
> continue;
>
> ...
> }

We cannot expect overlay must has its own serdes, or tx/rx/pcs, hence I
am checking max_gear intead of any specific member.

>
>>>
>>>> +
>>>> + /* Direct matching, bail */
>>>> + if (qmp->submode == max_gear)
>>>> + return i;
>>>> +
>>>> + /* If no direct matching, the lowest gear is the best matching */
>>>> + if (max_gear < floor_max_gear) {
>>>> + ret = i;
>>>> + floor_max_gear = max_gear;
>>>> + }
>>>> + }
>>>> +
>>>> + return ret;
>>>> +}
>>>> +
>>>> static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
>>>> {
>>>> + int i;
>>>> + bool apply_overlay = false;
>>>> +
>>>> + i = qmp_ufs_get_gear_overlay(qmp, cfg);
>>>> + if (i >= 0)
>>>> + apply_overlay = true;
>>>
>>> How about?
>>>
>>> ```
>>> int idx;
>>>
>>> idx = qmp_ufs_get_gear_overlay(qmp, cfg);
>>>
>>> qmp_ufs_serdes_init(qmp, &cfg->tbls);
>>> qmp_ufs_lanes_init(qmp, &cfg->tbls);
>>> ...
>>>
>>> if (idx >= 0) {
>>> qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[idx]);
>>> qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[idx]);
>>> ...
>>> }
>>> ```
>>>
>>> Since the ordering doesn't matter for init sequence, you can program the overlay
>>> tables under a single condition.
>>
>> We can do that, but we need to be careful. When I say (in my previous reply)
>> the ordering does not matter, that saying is from the UFS PHY HPG doc.
>> However, in SW implementation, the 'tbls_hs_b' is actually overwriting one
>> COM_VCO_TUNE_MAP register, the same register is also programmed by common
>> table or overlay table. So qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b) should
>> come after overlays.
>>
>
> Then you can program tbls_hs_b after overlay tables. Wouldn't that work?

I am programming tbls_hs_b after overlay tables, just a heads up in case
you are surprised :).

Thanks,
Can Guo.

>
> - Mani
>
>> Thanks,
>> Can Guo.
>>
>>>
>>> - Mani
>>>
>

2023-11-30 09:34:49

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v6 08/10] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550

On Thu, Nov 30, 2023 at 04:49:12PM +0800, Can Guo wrote:
>
>
> On 11/30/2023 4:38 PM, Manivannan Sadhasivam wrote:
> > On Thu, Nov 30, 2023 at 04:14:25PM +0800, Can Guo wrote:

[...]

> > > > > +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
> > > > > +{
> > > > > + u32 max_gear, floor_max_gear = cfg->max_supported_gear;
> > > > > + int i = NUM_OVERLAY - 1;
> > > >
> > > > Just use i directly in the for loop. Also, please rename "i" with "idx" to make
> > > > it clear.
> > >
> > > OK
> > >
> > > >
> > > > > + int ret = -EINVAL;
> > > > > +
> > > > > + for (; i >= 0; i --) {
> > > >
> > > > i--
> > > >
> > > > > + max_gear = cfg->tbls_hs_overlay[i].max_gear;
> > > > > +
> > > > > + if (max_gear == 0)
> > > > > + continue;
> > > >
> > > > You are setting max_gear even for targets with a single overlay. How can this
> > > > become 0?
> > >
> > > Say 8550 has two overlays, 8450 has one overlay. We are sweeping all
> > > overlays as NUM_OVERLAY == 2, so for 8450, there is one overlay initialized,
> > > another one not initialized (max_gear == 0), we are skipping the one which
> > > is not initialized.
> > >
> >
> > This is confusing at its best :) Please check for the existence of the actual
> > table instead. Like,
> >
> > for (idx = NUM_OVERLAY - 1; i >= 0, i--) {
> >
> > /* Skip if the table is not available */
> > if (!cfg->tbls_hs_overlay[i].serdes)
> > continue;
> >
> > ...
> > }
>
> We cannot expect overlay must has its own serdes, or tx/rx/pcs, hence I am
> checking max_gear intead of any specific member.
>

Hmm, then please add the comment as I suggested above.

> >
> > > >
> > > > > +
> > > > > + /* Direct matching, bail */
> > > > > + if (qmp->submode == max_gear)
> > > > > + return i;
> > > > > +
> > > > > + /* If no direct matching, the lowest gear is the best matching */
> > > > > + if (max_gear < floor_max_gear) {
> > > > > + ret = i;
> > > > > + floor_max_gear = max_gear;
> > > > > + }
> > > > > + }
> > > > > +
> > > > > + return ret;
> > > > > +}
> > > > > +
> > > > > static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
> > > > > {
> > > > > + int i;
> > > > > + bool apply_overlay = false;
> > > > > +
> > > > > + i = qmp_ufs_get_gear_overlay(qmp, cfg);
> > > > > + if (i >= 0)
> > > > > + apply_overlay = true;
> > > >
> > > > How about?
> > > >
> > > > ```
> > > > int idx;
> > > >
> > > > idx = qmp_ufs_get_gear_overlay(qmp, cfg);
> > > >
> > > > qmp_ufs_serdes_init(qmp, &cfg->tbls);
> > > > qmp_ufs_lanes_init(qmp, &cfg->tbls);
> > > > ...
> > > >
> > > > if (idx >= 0) {
> > > > qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[idx]);
> > > > qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[idx]);
> > > > ...
> > > > }
> > > > ```
> > > >
> > > > Since the ordering doesn't matter for init sequence, you can program the overlay
> > > > tables under a single condition.
> > >
> > > We can do that, but we need to be careful. When I say (in my previous reply)
> > > the ordering does not matter, that saying is from the UFS PHY HPG doc.
> > > However, in SW implementation, the 'tbls_hs_b' is actually overwriting one
> > > COM_VCO_TUNE_MAP register, the same register is also programmed by common
> > > table or overlay table. So qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b) should
> > > come after overlays.
> > >
> >
> > Then you can program tbls_hs_b after overlay tables. Wouldn't that work?
>
> I am programming tbls_hs_b after overlay tables, just a heads up in case you
> are surprised :).
>

Cool!

- Mani

--
மணிவண்ணன் சதாசிவம்

2023-11-30 09:37:18

by Can Guo

[permalink] [raw]
Subject: Re: [PATCH v6 08/10] phy: qualcomm: phy-qcom-qmp-ufs: Add High Speed Gear 5 support for SM8550



On 11/30/2023 5:34 PM, Manivannan Sadhasivam wrote:
> On Thu, Nov 30, 2023 at 04:49:12PM +0800, Can Guo wrote:
>>
>>
>> On 11/30/2023 4:38 PM, Manivannan Sadhasivam wrote:
>>> On Thu, Nov 30, 2023 at 04:14:25PM +0800, Can Guo wrote:
>
> [...]
>
>>>>>> +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
>>>>>> +{
>>>>>> + u32 max_gear, floor_max_gear = cfg->max_supported_gear;
>>>>>> + int i = NUM_OVERLAY - 1;
>>>>>
>>>>> Just use i directly in the for loop. Also, please rename "i" with "idx" to make
>>>>> it clear.
>>>>
>>>> OK
>>>>
>>>>>
>>>>>> + int ret = -EINVAL;
>>>>>> +
>>>>>> + for (; i >= 0; i --) {
>>>>>
>>>>> i--
>>>>>
>>>>>> + max_gear = cfg->tbls_hs_overlay[i].max_gear;
>>>>>> +
>>>>>> + if (max_gear == 0)
>>>>>> + continue;
>>>>>
>>>>> You are setting max_gear even for targets with a single overlay. How can this
>>>>> become 0?
>>>>
>>>> Say 8550 has two overlays, 8450 has one overlay. We are sweeping all
>>>> overlays as NUM_OVERLAY == 2, so for 8450, there is one overlay initialized,
>>>> another one not initialized (max_gear == 0), we are skipping the one which
>>>> is not initialized.
>>>>
>>>
>>> This is confusing at its best :) Please check for the existence of the actual
>>> table instead. Like,
>>>
>>> for (idx = NUM_OVERLAY - 1; i >= 0, i--) {
>>>
>>> /* Skip if the table is not available */
>>> if (!cfg->tbls_hs_overlay[i].serdes)
>>> continue;
>>>
>>> ...
>>> }
>>
>> We cannot expect overlay must has its own serdes, or tx/rx/pcs, hence I am
>> checking max_gear intead of any specific member.
>>
>
> Hmm, then please add the comment as I suggested above.

Sure

Thanks,
Can Guo.

>
>>>
>>>>>
>>>>>> +
>>>>>> + /* Direct matching, bail */
>>>>>> + if (qmp->submode == max_gear)
>>>>>> + return i;
>>>>>> +
>>>>>> + /* If no direct matching, the lowest gear is the best matching */
>>>>>> + if (max_gear < floor_max_gear) {
>>>>>> + ret = i;
>>>>>> + floor_max_gear = max_gear;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + return ret;
>>>>>> +}
>>>>>> +
>>>>>> static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
>>>>>> {
>>>>>> + int i;
>>>>>> + bool apply_overlay = false;
>>>>>> +
>>>>>> + i = qmp_ufs_get_gear_overlay(qmp, cfg);
>>>>>> + if (i >= 0)
>>>>>> + apply_overlay = true;
>>>>>
>>>>> How about?
>>>>>
>>>>> ```
>>>>> int idx;
>>>>>
>>>>> idx = qmp_ufs_get_gear_overlay(qmp, cfg);
>>>>>
>>>>> qmp_ufs_serdes_init(qmp, &cfg->tbls);
>>>>> qmp_ufs_lanes_init(qmp, &cfg->tbls);
>>>>> ...
>>>>>
>>>>> if (idx >= 0) {
>>>>> qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[idx]);
>>>>> qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[idx]);
>>>>> ...
>>>>> }
>>>>> ```
>>>>>
>>>>> Since the ordering doesn't matter for init sequence, you can program the overlay
>>>>> tables under a single condition.
>>>>
>>>> We can do that, but we need to be careful. When I say (in my previous reply)
>>>> the ordering does not matter, that saying is from the UFS PHY HPG doc.
>>>> However, in SW implementation, the 'tbls_hs_b' is actually overwriting one
>>>> COM_VCO_TUNE_MAP register, the same register is also programmed by common
>>>> table or overlay table. So qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b) should
>>>> come after overlays.
>>>>
>>>
>>> Then you can program tbls_hs_b after overlay tables. Wouldn't that work?
>>
>> I am programming tbls_hs_b after overlay tables, just a heads up in case you
>> are surprised :).
>>
>
> Cool!
>
> - Mani
>