]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: ufs: qcom: Add quirks for Samsung UFS devices
authorManish Pandey <quic_mapa@quicinc.com>
Fri, 11 Apr 2025 12:16:29 +0000 (17:46 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 12 Apr 2025 02:13:00 +0000 (22:13 -0400)
Introduce quirks for Samsung UFS devices to adjust PA TX HSG1 sync
length and TX_HS_EQUALIZER settings on the Qualcomm UFS Host
controller. This ensures proper functionality of Samsung UFS devices
with the Qualcomm UFS Host controller.

Signed-off-by: Manish Pandey <quic_mapa@quicinc.com>
Link: https://lore.kernel.org/r/20250411121630.21330-2-quic_mapa@quicinc.com
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/host/ufs-qcom.c
drivers/ufs/host/ufs-qcom.h

index 1b37449fbffc50ac4ae347f0d2586e0ee79a14f3..c0761ccc1381e37be7411a02724a56a0b54c48b6 100644 (file)
        ((((c) >> 16) & MCQ_QCFGPTR_MASK) * MCQ_QCFGPTR_UNIT)
 #define MCQ_QCFG_SIZE  0x40
 
+/* De-emphasis for gear-5 */
+#define DEEMPHASIS_3_5_dB      0x04
+#define NO_DEEMPHASIS          0x0
+
 enum {
        TSTBUS_UAWM,
        TSTBUS_UARM,
@@ -795,6 +799,23 @@ static int ufs_qcom_icc_update_bw(struct ufs_qcom_host *host)
        return ufs_qcom_icc_set_bw(host, bw_table.mem_bw, bw_table.cfg_bw);
 }
 
+static void ufs_qcom_set_tx_hs_equalizer(struct ufs_hba *hba, u32 gear, u32 tx_lanes)
+{
+       u32 equalizer_val;
+       int ret, i;
+
+       /* Determine the equalizer value based on the gear */
+       equalizer_val = (gear == 5) ? DEEMPHASIS_3_5_dB : NO_DEEMPHASIS;
+
+       for (i = 0; i < tx_lanes; i++) {
+               ret = ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(TX_HS_EQUALIZER, i),
+                                    equalizer_val);
+               if (ret)
+                       dev_err(hba->dev, "%s: failed equalizer lane %d\n",
+                               __func__, i);
+       }
+}
+
 static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
                                enum ufs_notify_change_status status,
                                const struct ufs_pa_layer_attr *dev_max_params,
@@ -846,6 +867,11 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
                                                dev_req_params->gear_tx,
                                                PA_INITIAL_ADAPT);
                }
+
+               if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TX_DEEMPHASIS_TUNING)
+                       ufs_qcom_set_tx_hs_equalizer(hba,
+                                       dev_req_params->gear_tx, dev_req_params->lane_tx);
+
                break;
        case POST_CHANGE:
                if (ufs_qcom_cfg_timers(hba, false)) {
@@ -893,6 +919,16 @@ static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba)
                            (pa_vs_config_reg1 | (1 << 12)));
 }
 
+static void ufs_qcom_override_pa_tx_hsg1_sync_len(struct ufs_hba *hba)
+{
+       int err;
+
+       err = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_TX_HSG1_SYNC_LENGTH),
+                                 PA_TX_HSG1_SYNC_LENGTH_VAL);
+       if (err)
+               dev_err(hba->dev, "Failed (%d) set PA_TX_HSG1_SYNC_LENGTH\n", err);
+}
+
 static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba)
 {
        int err = 0;
@@ -900,6 +936,9 @@ static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba)
        if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME)
                err = ufs_qcom_quirk_host_pa_saveconfigtime(hba);
 
+       if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TX_HSG1_SYNC_LENGTH)
+               ufs_qcom_override_pa_tx_hsg1_sync_len(hba);
+
        return err;
 }
 
@@ -914,6 +953,10 @@ static struct ufs_dev_quirk ufs_qcom_dev_fixups[] = {
        { .wmanufacturerid = UFS_VENDOR_WDC,
          .model = UFS_ANY_MODEL,
          .quirk = UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE },
+       { .wmanufacturerid = UFS_VENDOR_SAMSUNG,
+         .model = UFS_ANY_MODEL,
+         .quirk = UFS_DEVICE_QUIRK_PA_TX_HSG1_SYNC_LENGTH |
+                  UFS_DEVICE_QUIRK_PA_TX_DEEMPHASIS_TUNING },
        {}
 };
 
index d0e6ec9128e79dcdfa03e0b4602b5b5cdb8333de..05d4cb569c50058e1b2cfc727a510eeea7db2d7c 100644 (file)
@@ -122,8 +122,11 @@ enum {
                                 TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN)
 
 /* QUniPro Vendor specific attributes */
+#define PA_TX_HSG1_SYNC_LENGTH 0x1552
 #define PA_VS_CONFIG_REG1      0x9000
 #define DME_VS_CORE_CLK_CTRL   0xD002
+#define TX_HS_EQUALIZER                0x0037
+
 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
 #define CLK_1US_CYCLES_MASK_V4                         GENMASK(27, 16)
 #define CLK_1US_CYCLES_MASK                            GENMASK(7, 0)
@@ -141,6 +144,21 @@ enum {
 #define UNIPRO_CORE_CLK_FREQ_201_5_MHZ         202
 #define UNIPRO_CORE_CLK_FREQ_403_MHZ           403
 
+/* TX_HSG1_SYNC_LENGTH attr value */
+#define PA_TX_HSG1_SYNC_LENGTH_VAL     0x4A
+
+/*
+ * Some ufs device vendors need a different TSync length.
+ * Enable this quirk to give an additional TX_HS_SYNC_LENGTH.
+ */
+#define UFS_DEVICE_QUIRK_PA_TX_HSG1_SYNC_LENGTH                BIT(16)
+
+/*
+ * Some ufs device vendors need a different Deemphasis setting.
+ * Enable this quirk to tune TX Deemphasis parameters.
+ */
+#define UFS_DEVICE_QUIRK_PA_TX_DEEMPHASIS_TUNING       BIT(17)
+
 /* ICE allocator type to share AES engines among TX stream and RX stream */
 #define ICE_ALLOCATOR_TYPE 2