]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
scsi: ufs: ufs-qcom: Implement vops tx_eqtr_notify()
authorCan Guo <can.guo@oss.qualcomm.com>
Wed, 25 Mar 2026 15:21:51 +0000 (08:21 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 27 Mar 2026 21:20:30 +0000 (17:20 -0400)
On some platforms, HW does not support triggering TX EQTR from the most
reliable High-Speed (HS) Gear (HS Gear1), but only allows to trigger TX
EQTR for the target HS Gear from the same HS Gear. To work around the HW
limitation, implement vops tx_eqtr_notify() to change Power Mode to the
target TX EQTR HS Gear prior to TX EQTR procedure and change Power Mode
back to HS Gear1 (the most reliable gear) post TX EQTR procedure.

Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Can Guo <can.guo@oss.qualcomm.com>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Link: https://patch.msgid.link/20260325152154.1604082-10-can.guo@oss.qualcomm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/host/ufs-qcom.c

index b94fe93b830e675fbe9d4eab1c3e5b3bb12114c5..eac5e95e740b1e5d256f52da242341939cba1b0f 100644 (file)
@@ -2505,6 +2505,46 @@ static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq)
        return min_t(u32, gear, hba->max_pwr_info.info.gear_rx);
 }
 
+static int ufs_qcom_tx_eqtr_notify(struct ufs_hba *hba,
+                                  enum ufs_notify_change_status status,
+                                  struct ufs_pa_layer_attr *pwr_mode)
+{
+       struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+       struct ufs_pa_layer_attr pwr_mode_hs_g1 = {
+               .gear_rx = UFS_HS_G1,
+               .gear_tx = UFS_HS_G1,
+               .lane_rx = pwr_mode->lane_rx,
+               .lane_tx = pwr_mode->lane_tx,
+               .pwr_rx = FAST_MODE,
+               .pwr_tx = FAST_MODE,
+               .hs_rate = pwr_mode->hs_rate,
+       };
+       u32 gear = pwr_mode->gear_tx;
+       u32 rate = pwr_mode->hs_rate;
+       int ret;
+
+       if (host->hw_ver.major != 0x7 || host->hw_ver.minor > 0x1)
+               return 0;
+
+       if (status == PRE_CHANGE) {
+               /* PMC to target HS Gear. */
+               ret = ufshcd_change_power_mode(hba, pwr_mode,
+                                              UFSHCD_PMC_POLICY_DONT_FORCE);
+               if (ret)
+                       dev_err(hba->dev, "%s: Failed to PMC to target HS-G%u, Rate-%s: %d\n",
+                               __func__, gear, ufs_hs_rate_to_str(rate), ret);
+       } else {
+               /* PMC back to HS-G1. */
+               ret = ufshcd_change_power_mode(hba, &pwr_mode_hs_g1,
+                                              UFSHCD_PMC_POLICY_DONT_FORCE);
+               if (ret)
+                       dev_err(hba->dev, "%s: Failed to PMC to HS-G1, Rate-%s: %d\n",
+                               __func__, ufs_hs_rate_to_str(rate), ret);
+       }
+
+       return ret;
+}
+
 /*
  * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
  *
@@ -2535,6 +2575,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
        .get_outstanding_cqs    = ufs_qcom_get_outstanding_cqs,
        .config_esi             = ufs_qcom_config_esi,
        .freq_to_gear_speed     = ufs_qcom_freq_to_gear_speed,
+       .tx_eqtr_notify         = ufs_qcom_tx_eqtr_notify,
 };
 
 static const struct ufs_hba_variant_ops ufs_hba_qcom_sa8255p_vops = {