return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
 }
 
+u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
+{
+       /* HCI version 1.0 and 1.1 supports UniPro 1.41 */
+       if ((hba->ufs_version == UFSHCI_VERSION_10) ||
+           (hba->ufs_version == UFSHCI_VERSION_11))
+               return UFS_UNIPRO_VER_1_41;
+       else
+               return UFS_UNIPRO_VER_1_6;
+}
+EXPORT_SYMBOL(ufshcd_get_local_unipro_ver);
+
+static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
+{
+       /*
+        * If both host and device support UniPro ver1.6 or later, PA layer
+        * parameters tuning happens during link startup itself.
+        *
+        * We can manually tune PA layer parameters if either host or device
+        * doesn't support UniPro ver 1.6 or later. But to keep manual tuning
+        * logic simple, we will only do manual tuning if local unipro version
+        * doesn't support ver1.6 or later.
+        */
+       if (ufshcd_get_local_unipro_ver(hba) < UFS_UNIPRO_VER_1_6)
+               return true;
+       else
+               return false;
+}
+
 static void ufshcd_ungate_work(struct work_struct *work)
 {
        int ret;
        }
 }
 
+/**
+ * ufshcd_tune_pa_tactivate - Tunes PA_TActivate of local UniPro
+ * @hba: per-adapter instance
+ *
+ * PA_TActivate parameter can be tuned manually if UniPro version is less than
+ * 1.61. PA_TActivate needs to be greater than or equal to peerM-PHY's
+ * RX_MIN_ACTIVATETIME_CAPABILITY attribute. This optimal value can help reduce
+ * the hibern8 exit latency.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_tune_pa_tactivate(struct ufs_hba *hba)
+{
+       int ret = 0;
+       u32 peer_rx_min_activatetime = 0, tuned_pa_tactivate;
+
+       ret = ufshcd_dme_peer_get(hba,
+                                 UIC_ARG_MIB_SEL(
+                                       RX_MIN_ACTIVATETIME_CAPABILITY,
+                                       UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+                                 &peer_rx_min_activatetime);
+       if (ret)
+               goto out;
+
+       /* make sure proper unit conversion is applied */
+       tuned_pa_tactivate =
+               ((peer_rx_min_activatetime * RX_MIN_ACTIVATETIME_UNIT_US)
+                / PA_TACTIVATE_TIME_UNIT_US);
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE),
+                            tuned_pa_tactivate);
+
+out:
+       return ret;
+}
+
+/**
+ * ufshcd_tune_pa_hibern8time - Tunes PA_Hibern8Time of local UniPro
+ * @hba: per-adapter instance
+ *
+ * PA_Hibern8Time parameter can be tuned manually if UniPro version is less than
+ * 1.61. PA_Hibern8Time needs to be maximum of local M-PHY's
+ * TX_HIBERN8TIME_CAPABILITY & peer M-PHY's RX_HIBERN8TIME_CAPABILITY.
+ * This optimal value can help reduce the hibern8 exit latency.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_tune_pa_hibern8time(struct ufs_hba *hba)
+{
+       int ret = 0;
+       u32 local_tx_hibern8_time_cap = 0, peer_rx_hibern8_time_cap = 0;
+       u32 max_hibern8_time, tuned_pa_hibern8time;
+
+       ret = ufshcd_dme_get(hba,
+                            UIC_ARG_MIB_SEL(TX_HIBERN8TIME_CAPABILITY,
+                                       UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+                                 &local_tx_hibern8_time_cap);
+       if (ret)
+               goto out;
+
+       ret = ufshcd_dme_peer_get(hba,
+                                 UIC_ARG_MIB_SEL(RX_HIBERN8TIME_CAPABILITY,
+                                       UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+                                 &peer_rx_hibern8_time_cap);
+       if (ret)
+               goto out;
+
+       max_hibern8_time = max(local_tx_hibern8_time_cap,
+                              peer_rx_hibern8_time_cap);
+       /* make sure proper unit conversion is applied */
+       tuned_pa_hibern8time = ((max_hibern8_time * HIBERN8TIME_UNIT_US)
+                               / PA_HIBERN8_TIME_UNIT_US);
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME),
+                            tuned_pa_hibern8time);
+out:
+       return ret;
+}
+
+static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
+{
+       if (ufshcd_is_unipro_pa_params_tuning_req(hba)) {
+               ufshcd_tune_pa_tactivate(hba);
+               ufshcd_tune_pa_hibern8time(hba);
+       }
+
+       if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE)
+               /* set 1ms timeout for PA_TACTIVATE */
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10);
+}
+
 /**
  * ufshcd_probe_hba - probe hba to detect device and initialize
  * @hba: per-adapter instance
                goto out;
 
        ufs_advertise_fixup_device(hba);
+       ufshcd_tune_unipro_params(hba);
 
        ret = ufshcd_set_vccq_rail_unused(hba,
                (hba->dev_quirks & UFS_DEVICE_NO_VCCQ) ? true : false);
 
 /*
  * M-TX Configuration Attributes
  */
+#define TX_HIBERN8TIME_CAPABILITY              0x000F
 #define TX_MODE                                        0x0021
 #define TX_HSRATE_SERIES                       0x0022
 #define TX_HSGEAR                              0x0023
 #define RX_ENTER_HIBERN8                       0x00A7
 #define RX_BYPASS_8B10B_ENABLE                 0x00A8
 #define RX_TERMINATION_FORCE_ENABLE            0x0089
+#define RX_MIN_ACTIVATETIME_CAPABILITY         0x008F
+#define RX_HIBERN8TIME_CAPABILITY              0x0092
 
 #define is_mphy_tx_attr(attr)                  (attr < RX_MODE)
+#define RX_MIN_ACTIVATETIME_UNIT_US            100
+#define HIBERN8TIME_UNIT_US                    100
 /*
  * PHY Adpater attributes
  */
 #define PA_STALLNOCONFIGTIME   0x15A3
 #define PA_SAVECONFIGTIME      0x15A4
 
+#define PA_TACTIVATE_TIME_UNIT_US      10
+#define PA_HIBERN8_TIME_UNIT_US                100
+
+/* PHY Adapter Protocol Constants */
+#define PA_MAXDATALANES        4
+
 /* PA power modes */
 enum {
        FAST_MODE       = 1,
        UFS_HS_G3,              /* HS Gear 3 */
 };
 
+enum ufs_unipro_ver {
+       UFS_UNIPRO_VER_RESERVED = 0,
+       UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */
+       UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */
+       UFS_UNIPRO_VER_1_6 = 3,  /* UniPro version 1.6 */
+       UFS_UNIPRO_VER_MAX = 4,  /* UniPro unsupported version */
+       /* UniPro version field mask in PA_LOCALVERINFO */
+       UFS_UNIPRO_VER_MASK = 0xF,
+};
+
 /*
  * Data Link Layer Attributes
  */