Skip to content

Commit 90b74d5

Browse files
Merge patch series "Enable HS-G5 support on SM8550"
Can Guo <[email protected]> says: 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. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
2 parents edc22a7 + dc7c948 commit 90b74d5

File tree

7 files changed

+133
-80
lines changed

7 files changed

+133
-80
lines changed

drivers/ufs/host/ufs-exynos.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
765765
{
766766
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
767767
struct phy *generic_phy = ufs->phy;
768-
struct ufs_dev_params ufs_exynos_cap;
768+
struct ufs_host_params host_params;
769769
int ret;
770770

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

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

779-
ret = ufshcd_get_pwr_dev_param(&ufs_exynos_cap,
780-
dev_max_params, dev_req_params);
779+
ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
781780
if (ret) {
782781
pr_err("%s: failed to determine capabilities\n", __func__);
783782
goto out;

drivers/ufs/host/ufs-hisi.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,9 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba,
293293
return err;
294294
}
295295

296-
static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param)
296+
static void ufs_hisi_set_dev_cap(struct ufs_host_params *host_params)
297297
{
298-
ufshcd_init_pwr_dev_param(hisi_param);
298+
ufshcd_init_host_params(host_params);
299299
}
300300

301301
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,
365365
struct ufs_pa_layer_attr *dev_max_params,
366366
struct ufs_pa_layer_attr *dev_req_params)
367367
{
368-
struct ufs_dev_params ufs_hisi_cap;
368+
struct ufs_host_params host_params;
369369
int ret = 0;
370370

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

378378
switch (status) {
379379
case PRE_CHANGE:
380-
ufs_hisi_set_dev_cap(&ufs_hisi_cap);
381-
ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap,
382-
dev_max_params, dev_req_params);
380+
ufs_hisi_set_dev_cap(&host_params);
381+
ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
383382
if (ret) {
384383
dev_err(hba->dev,
385384
"%s: failed to determine capabilities\n", __func__);

drivers/ufs/host/ufs-mediatek.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -996,16 +996,14 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
996996
struct ufs_pa_layer_attr *dev_req_params)
997997
{
998998
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
999-
struct ufs_dev_params host_cap;
999+
struct ufs_host_params host_params;
10001000
int ret;
10011001

1002-
ufshcd_init_pwr_dev_param(&host_cap);
1003-
host_cap.hs_rx_gear = UFS_HS_G5;
1004-
host_cap.hs_tx_gear = UFS_HS_G5;
1002+
ufshcd_init_host_params(&host_params);
1003+
host_params.hs_rx_gear = UFS_HS_G5;
1004+
host_params.hs_tx_gear = UFS_HS_G5;
10051005

1006-
ret = ufshcd_get_pwr_dev_param(&host_cap,
1007-
dev_max_params,
1008-
dev_req_params);
1006+
ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
10091007
if (ret) {
10101008
pr_info("%s: failed to determine capabilities\n",
10111009
__func__);

drivers/ufs/host/ufs-qcom.c

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,25 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba)
442442
static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
443443
{
444444
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
445+
struct ufs_host_params *host_params = &host->host_params;
445446
struct phy *phy = host->generic_phy;
447+
enum phy_mode mode;
446448
int ret;
447449

450+
/*
451+
* HW ver 5 can only support up to HS-G5 Rate-A due to HW limitations.
452+
* If the HS-G5 PHY gear is used, update host_params->hs_rate to Rate-A,
453+
* so that the subsequent power mode change shall stick to Rate-A.
454+
*/
455+
if (host->hw_ver.major == 0x5) {
456+
if (host->phy_gear == UFS_HS_G5)
457+
host_params->hs_rate = PA_HS_MODE_A;
458+
else
459+
host_params->hs_rate = PA_HS_MODE_B;
460+
}
461+
462+
mode = host_params->hs_rate == PA_HS_MODE_B ? PHY_MODE_UFS_HS_B : PHY_MODE_UFS_HS_A;
463+
448464
/* Reset UFS Host Controller and PHY */
449465
ret = ufs_qcom_host_reset(hba);
450466
if (ret)
@@ -459,7 +475,9 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
459475
return ret;
460476
}
461477

462-
phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->phy_gear);
478+
ret = phy_set_mode_ext(phy, mode, host->phy_gear);
479+
if (ret)
480+
goto out_disable_phy;
463481

464482
/* power on phy - start serdes and phy's power and clocks */
465483
ret = phy_power_on(phy);
@@ -898,7 +916,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
898916
struct ufs_pa_layer_attr *dev_req_params)
899917
{
900918
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
901-
struct ufs_dev_params ufs_qcom_cap;
919+
struct ufs_host_params *host_params = &host->host_params;
902920
int ret = 0;
903921

904922
if (!dev_req_params) {
@@ -908,27 +926,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
908926

909927
switch (status) {
910928
case PRE_CHANGE:
911-
ufshcd_init_pwr_dev_param(&ufs_qcom_cap);
912-
ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE;
913-
914-
/* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */
915-
ufs_qcom_cap.hs_tx_gear = ufs_qcom_cap.hs_rx_gear = ufs_qcom_get_hs_gear(hba);
916-
917-
ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap,
918-
dev_max_params,
919-
dev_req_params);
929+
ret = ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params);
920930
if (ret) {
921931
dev_err(hba->dev, "%s: failed to determine capabilities\n",
922932
__func__);
923933
return ret;
924934
}
925935

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

934945
/* enable the device ref clock before changing to HS mode */
@@ -1051,6 +1062,54 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
10511062
hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
10521063
}
10531064

1065+
static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
1066+
{
1067+
struct ufs_host_params *host_params = &host->host_params;
1068+
u32 val, dev_major;
1069+
1070+
host->phy_gear = host_params->hs_tx_gear;
1071+
1072+
if (host->hw_ver.major < 0x4) {
1073+
/*
1074+
* For controllers whose major HW version is < 4, power up the
1075+
* PHY using minimum supported gear (UFS_HS_G2). Switching to
1076+
* max gear will be performed during reinit if supported.
1077+
* For newer controllers, whose major HW version is >= 4, power
1078+
* up the PHY using max supported gear.
1079+
*/
1080+
host->phy_gear = UFS_HS_G2;
1081+
} else if (host->hw_ver.major >= 0x5) {
1082+
val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
1083+
dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, val);
1084+
1085+
/*
1086+
* Since the UFS device version is populated, let's remove the
1087+
* REINIT quirk as the negotiated gear won't change during boot.
1088+
* So there is no need to do reinit.
1089+
*/
1090+
if (dev_major != 0x0)
1091+
host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
1092+
1093+
/*
1094+
* For UFS 3.1 device and older, power up the PHY using HS-G4
1095+
* PHY gear to save power.
1096+
*/
1097+
if (dev_major > 0x0 && dev_major < 0x4)
1098+
host->phy_gear = UFS_HS_G4;
1099+
}
1100+
}
1101+
1102+
static void ufs_qcom_set_host_params(struct ufs_hba *hba)
1103+
{
1104+
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
1105+
struct ufs_host_params *host_params = &host->host_params;
1106+
1107+
ufshcd_init_host_params(host_params);
1108+
1109+
/* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */
1110+
host_params->hs_tx_gear = host_params->hs_rx_gear = ufs_qcom_get_hs_gear(hba);
1111+
}
1112+
10541113
static void ufs_qcom_set_caps(struct ufs_hba *hba)
10551114
{
10561115
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1275,6 +1334,8 @@ static int ufs_qcom_init(struct ufs_hba *hba)
12751334

12761335
ufs_qcom_set_caps(hba);
12771336
ufs_qcom_advertise_quirks(hba);
1337+
ufs_qcom_set_host_params(hba);
1338+
ufs_qcom_set_phy_gear(host);
12781339

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

1295-
/*
1296-
* Power up the PHY using the minimum supported gear (UFS_HS_G2).
1297-
* Switching to max gear will be performed during reinit if supported.
1298-
*/
1299-
host->phy_gear = UFS_HS_G2;
1300-
13011356
return 0;
13021357

13031358
out_variant_clear:

drivers/ufs/host/ufs-qcom.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
#define UFS_HW_VER_MINOR_MASK GENMASK(27, 16)
2424
#define UFS_HW_VER_STEP_MASK GENMASK(15, 0)
2525

26+
#define UFS_DEV_VER_MAJOR_MASK GENMASK(7, 4)
27+
2628
/* vendor specific pre-defined parameters */
2729
#define SLOW 1
2830
#define FAST 2
2931

30-
#define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B
31-
3232
/* QCOM UFS host controller vendor specific registers */
3333
enum {
3434
REG_UFS_SYS1CLK_1US = 0xC0,
@@ -56,6 +56,8 @@ enum {
5656
UFS_AH8_CFG = 0xFC,
5757

5858
REG_UFS_CFG3 = 0x271C,
59+
60+
REG_UFS_DEBUG_SPARE_CFG = 0x284C,
5961
};
6062

6163
/* QCOM UFS host controller vendor specific debug registers */
@@ -240,6 +242,7 @@ struct ufs_qcom_host {
240242

241243
struct gpio_desc *device_reset;
242244

245+
struct ufs_host_params host_params;
243246
u32 phy_gear;
244247

245248
bool esi_enabled;

0 commit comments

Comments
 (0)