Commit 216f74e8 authored by Alim Akhtar's avatar Alim Akhtar Committed by Martin K. Petersen
Browse files

scsi: ufs: host: ufs-exynos: Add support for FSD UFS HCI

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: default avatarBharat Uppal <bharat.uppal@samsung.com>
Signed-off-by: default avatarBharat Uppal <bharat.uppal@samsung.com>
Signed-off-by: default avatarAlim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent daa782a5
Loading
Loading
Loading
Loading
+140 −0
Original line number Diff line number Diff line
@@ -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 },
	{},
};

+1 −0
Original line number Diff line number Diff line
@@ -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