> Subject: [PATCH v2 6/7] 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. > > Signed-off-by: Bharat Uppal <bharat.uppal@xxxxxxxxxxx> > Signed-off-by: Alim Akhtar <alim.akhtar@xxxxxxxxxxx> > --- > drivers/ufs/host/ufs-exynos.c | 138 ++++++++++++++++++++++++++++++++++ > 1 file changed, 138 insertions(+) > > diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c > index cc128aff8871..7e0ab8a8662e 100644 > --- a/drivers/ufs/host/ufs-exynos.c > +++ b/drivers/ufs/host/ufs-exynos.c > @@ -1474,6 +1474,102 @@ 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(0x9514), 1000000000L / 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), 1000000000L / > ufs->mclk_rate); Use NSEC_PER_SEC and DIV_ROUND_UP as well. > + 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), 1000000000L / > 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(0x9536), 0x4E20); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x9564), 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(0x15A8), > + &peer_rx_min_actv_time_cap); /* PA_TActivate */ > + ufshcd_dme_get(hba, UIC_ARG_MIB(0x15A7), > + &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(0x15A8), > + peer_rx_min_actv_time_cap + 1); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15A7), max_rx_hibern8_time_cap + > 1); > + > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x9529), 0x01); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15A4), 0xFA); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x9529), 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(DL_FC0PROTTIMEOUTVAL), 8064); > + ufshcd_dme_set(hba, UIC_ARG_MIB(DL_TC0REPLAYTIMEOUTVAL), 28224); > + ufshcd_dme_set(hba, UIC_ARG_MIB(DL_AFC0REQTIMEOUTVAL), 20160); > + 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); If you set custom pwrmode setting, you'll need to set UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING. > + > + unipro_writel(ufs, 8064, 0x7888); > + unipro_writel(ufs, 28224, 0x788C); > + unipro_writel(ufs, 20160, 0x7890); Duplicated setting with above dme_set calls. (DL_FC0PROTTIMEOUTVAL / DL_TC0REPLAYTIMEOUTVAL / DL_AFC0REQTIMEOUTVAL) Unipro registers are mirrored and you can use unipro_* APIs but need to choose one of them. > + unipro_writel(ufs, 12000, 0x78B8); > + unipro_writel(ufs, 32000, 0x78BC); > + unipro_writel(ufs, 16000, 0x78C0); Put some documents the register as DME_POWERMODE_REQ_REMOTEL2TIMER0/1/2 or use macro for them. Best Regards, Chanho Park