@@ -442,9 +442,25 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba)
442442static 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+
10541113static 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
13031358out_variant_clear :
0 commit comments