Merge branch 'stable/for-jens-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / ufs / ufs-qcom.c
index 6652a8171de60c41e07299559d3e993cb3d5163e..4cdffa46d401a5ea6120ba5d350e453158166a31 100644 (file)
@@ -307,6 +307,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
 static unsigned long
 ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
 {
+       struct ufs_qcom_host *host = hba->priv;
        struct ufs_clk_info *clki;
        u32 core_clk_period_in_ns;
        u32 tx_clk_cycles_per_us = 0;
@@ -330,6 +331,16 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
                {UFS_HS_G2, 0x49},
        };
 
+       /*
+        * The Qunipro controller does not use following registers:
+        * SYS1CLK_1US_REG, TX_SYMBOL_CLK_1US_REG, CLK_NS_REG &
+        * UFS_REG_PA_LINK_STARTUP_TIMER
+        * But UTP controller uses SYS1CLK_1US_REG register for Interrupt
+        * Aggregation logic.
+       */
+       if (ufs_qcom_cap_qunipro(host) && !ufshcd_is_intr_aggr_allowed(hba))
+               goto out;
+
        if (gear == 0) {
                dev_err(hba->dev, "%s: invalid gear = %d\n", __func__, gear);
                goto out_error;
@@ -683,6 +694,16 @@ out:
        return ret;
 }
 
+static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
+{
+       struct ufs_qcom_host *host = hba->priv;
+
+       if (host->hw_ver.major == 0x1)
+               return UFSHCI_VERSION_11;
+       else
+               return UFSHCI_VERSION_20;
+}
+
 /**
  * ufs_qcom_advertise_quirks - advertise the known QCOM UFS controller quirks
  * @hba: host controller instance
@@ -696,13 +717,24 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
 {
        struct ufs_qcom_host *host = hba->priv;
 
-       if (host->hw_ver.major == 0x1)
-               hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS;
+       if (host->hw_ver.major == 0x01) {
+               hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
+                           | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP
+                           | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE;
+
+               if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001)
+                       hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR;
+       }
 
        if (host->hw_ver.major >= 0x2) {
+               hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
+               hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
+
                if (!ufs_qcom_cap_qunipro(host))
                        /* Legacy UniPro mode still need following quirks */
-                       hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS;
+                       hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
+                               | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE
+                               | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP);
        }
 }
 
@@ -1005,6 +1037,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
        .name                   = "qcom",
        .init                   = ufs_qcom_init,
        .exit                   = ufs_qcom_exit,
+       .get_ufs_hci_version    = ufs_qcom_get_ufs_hci_version,
        .clk_scale_notify       = ufs_qcom_clk_scale_notify,
        .setup_clocks           = ufs_qcom_setup_clocks,
        .hce_enable_notify      = ufs_qcom_hce_enable_notify,