scsi: ufs: host: ufs-exynos: Add support for FSD UFS HCI
authorAlim Akhtar <alim.akhtar@samsung.com>
Fri, 10 Jun 2022 10:41:19 +0000 (16:11 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 14 Jun 2022 01:57:33 +0000 (21:57 -0400)
Adds support of UFS HCI which is found in Tesla Full Self-Driving (FSD)
SoC.

Link: https://lore.kernel.org/r/20220610104119.66401-7-alim.akhtar@samsung.com
Co-developed-by: Bharat Uppal <bharat.uppal@samsung.com>
Signed-off-by: Bharat Uppal <bharat.uppal@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/host/ufs-exynos.c
drivers/ufs/host/ufs-exynos.h

index cc128af..6994306 100644 (file)
@@ -146,6 +146,10 @@ enum {
 #define UNIPRO_DME_PWR_REQ_REMOTEL2TIMER1      0x0A8
 #define UNIPRO_DME_PWR_REQ_REMOTEL2TIMER2      0x0AC
 
+#define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER0        0x78B8
+#define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER1        0x78BC
+#define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER2        0x78C0
+
 /*
  * UFS Protector registers
  */
@@ -1474,6 +1478,99 @@ static int exynosauto_ufs_vh_init(struct ufs_hba *hba)
        return 0;
 }
 
+static int fsd_ufs_pre_link(struct exynos_ufs *ufs)
+{
+       int i;
+       struct ufs_hba *hba = ufs->hba;
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_CLK_PERIOD),
+                      DIV_ROUND_UP(NSEC_PER_SEC,  ufs->mclk_rate));
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0x201), 0x12);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40);
+
+       for_each_ufs_tx_lane(ufs, i) {
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xAA, i),
+                              DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8F, i), 0x3F);
+       }
+
+       for_each_ufs_rx_lane(ufs, i) {
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x12, i),
+                              DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x5C, i), 0x38);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0F, i), 0x0);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x65, i), 0x1);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x69, i), 0x1);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x21, i), 0x0);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x22, i), 0x0);
+       }
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_AUTOMODE_THLD), 0x4E20);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OPTION_SUITE), 0x2e820183);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0x0);
+
+       exynos_ufs_establish_connt(ufs);
+
+       return 0;
+}
+
+static int fsd_ufs_post_link(struct exynos_ufs *ufs)
+{
+       int i;
+       struct ufs_hba *hba = ufs->hba;
+       u32 hw_cap_min_tactivate;
+       u32 peer_rx_min_actv_time_cap;
+       u32 max_rx_hibern8_time_cap;
+
+       ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(0x8F, 4),
+                       &hw_cap_min_tactivate); /* HW Capability of MIN_TACTIVATE */
+       ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TACTIVATE),
+                       &peer_rx_min_actv_time_cap);    /* PA_TActivate */
+       ufshcd_dme_get(hba, UIC_ARG_MIB(PA_HIBERN8TIME),
+                       &max_rx_hibern8_time_cap);      /* PA_Hibern8Time */
+
+       if (peer_rx_min_actv_time_cap >= hw_cap_min_tactivate)
+               ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_TACTIVATE),
+                                       peer_rx_min_actv_time_cap + 1);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), max_rx_hibern8_time_cap + 1);
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), 0x01);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SAVECONFIGTIME), 0xFA);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), 0x00);
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40);
+
+       for_each_ufs_rx_lane(ufs, i) {
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x35, i), 0x05);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x73, i), 0x01);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x41, i), 0x02);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x42, i), 0xAC);
+       }
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0);
+
+       return 0;
+}
+
+static int fsd_ufs_pre_pwr_change(struct exynos_ufs *ufs,
+                                       struct ufs_pa_layer_attr *pwr)
+{
+       struct ufs_hba *hba = ufs->hba;
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), 0x1);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), 0x1);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), 12000);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), 32000);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), 16000);
+
+       unipro_writel(ufs, 12000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER0);
+       unipro_writel(ufs, 32000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER1);
+       unipro_writel(ufs, 16000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER2);
+
+       return 0;
+}
+
 static struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
        .name                           = "exynos_ufs",
        .init                           = exynos_ufs_init,
@@ -1596,6 +1693,47 @@ static struct exynos_ufs_drv_data exynos_ufs_drvs = {
        .post_pwr_change        = exynos7_ufs_post_pwr_change,
 };
 
+static struct exynos_ufs_uic_attr fsd_uic_attr = {
+       .tx_trailingclks                = 0x10,
+       .tx_dif_p_nsec                  = 3000000,      /* unit: ns */
+       .tx_dif_n_nsec                  = 1000000,      /* unit: ns */
+       .tx_high_z_cnt_nsec             = 20000,        /* unit: ns */
+       .tx_base_unit_nsec              = 100000,       /* unit: ns */
+       .tx_gran_unit_nsec              = 4000,         /* unit: ns */
+       .tx_sleep_cnt                   = 1000,         /* unit: ns */
+       .tx_min_activatetime            = 0xa,
+       .rx_filler_enable               = 0x2,
+       .rx_dif_p_nsec                  = 1000000,      /* unit: ns */
+       .rx_hibern8_wait_nsec           = 4000000,      /* unit: ns */
+       .rx_base_unit_nsec              = 100000,       /* unit: ns */
+       .rx_gran_unit_nsec              = 4000,         /* unit: ns */
+       .rx_sleep_cnt                   = 1280,         /* unit: ns */
+       .rx_stall_cnt                   = 320,          /* unit: ns */
+       .rx_hs_g1_sync_len_cap          = SYNC_LEN_COARSE(0xf),
+       .rx_hs_g2_sync_len_cap          = SYNC_LEN_COARSE(0xf),
+       .rx_hs_g3_sync_len_cap          = SYNC_LEN_COARSE(0xf),
+       .rx_hs_g1_prep_sync_len_cap     = PREP_LEN(0xf),
+       .rx_hs_g2_prep_sync_len_cap     = PREP_LEN(0xf),
+       .rx_hs_g3_prep_sync_len_cap     = PREP_LEN(0xf),
+       .pa_dbg_option_suite            = 0x2E820183,
+};
+
+struct exynos_ufs_drv_data fsd_ufs_drvs = {
+       .uic_attr               = &fsd_uic_attr,
+       .quirks                 = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
+                                 UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR |
+                                 UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
+                                 UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING |
+                                 UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR,
+       .opts                   = EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL |
+                                 EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
+                                 EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
+                                 EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX,
+       .pre_link               = fsd_ufs_pre_link,
+       .post_link              = fsd_ufs_post_link,
+       .pre_pwr_change         = fsd_ufs_pre_pwr_change,
+};
+
 static const struct of_device_id exynos_ufs_of_match[] = {
        { .compatible = "samsung,exynos7-ufs",
          .data       = &exynos_ufs_drvs },
@@ -1603,6 +1741,8 @@ static const struct of_device_id exynos_ufs_of_match[] = {
          .data       = &exynosauto_ufs_drvs },
        { .compatible = "samsung,exynosautov9-ufs-vh",
          .data       = &exynosauto_ufs_vh_drvs },
+       { .compatible = "tesla,fsd-ufs",
+         .data       = &fsd_ufs_drvs },
        {},
 };
 
index 0b0a3d5..a4bd664 100644 (file)
@@ -22,6 +22,7 @@
 #define PA_DBG_RXPHY_CFGUPDT   0x9519
 #define PA_DBG_MODE            0x9529
 #define PA_DBG_SKIP_RESET_PHY  0x9539
+#define PA_DBG_AUTOMODE_THLD   0x9536
 #define PA_DBG_OV_TM           0x9540
 #define PA_DBG_SKIP_LINE_RESET 0x9541
 #define PA_DBG_LINE_RESET_REQ  0x9543