Message ID | 20220531012220.80563-6-alim.akhtar@samsung.com |
---|---|
State | New |
Headers | show |
Series | Add support for UFS controller found in FSD SoC | expand |
Hi, > -----Original Message----- > From: Alim Akhtar <alim.akhtar@samsung.com> > Sent: Tuesday, May 31, 2022 10:22 AM > To: linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; > linux-scsi@vger.kernel.org; linux-phy@lists.infradead.org > Cc: devicetree@vger.kernel.org; robh+dt@kernel.org; > krzysztof.kozlowski+dt@linaro.org; vkoul@kernel.org; avri.altman@wdc.com; > bvanassche@acm.org; martin.petersen@oracle.com; chanho61.park@samsung.com; > pankaj.dubey@samsung.com; Alim Akhtar <alim.akhtar@samsung.com>; linux- > fsd@tesla.com; Bharat Uppal <bharat.uppal@samsung.com> > Subject: [PATCH 5/6] ufs: host: ufs-exynos: add support for fsd ufs hci > > Adds support of UFS HCI which is found in Tesla FSD SoC. FSD also have an > addition bit for MPHY APB clock which was not there (was reserved) for > previous exynos SoC. > > Cc: linux-fsd@tesla.com > Signed-off-by: Bharat Uppal <bharat.uppal@samsung.com> > Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com> > --- > drivers/ufs/host/ufs-exynos.c | 143 +++++++++++++++++++++++++++++++++- > 1 file changed, 142 insertions(+), 1 deletion(-) > > diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c > index a81d8cbd542f..b3efdc4caca2 100644 > --- a/drivers/ufs/host/ufs-exynos.c > +++ b/drivers/ufs/host/ufs-exynos.c > @@ -52,11 +52,12 @@ > #define HCI_ERR_EN_DME_LAYER 0x88 > #define HCI_CLKSTOP_CTRL 0xB0 > #define REFCLKOUT_STOP BIT(4) > +#define MPHY_APBCLK_STOP BIT(3) > #define REFCLK_STOP BIT(2) > #define UNIPRO_MCLK_STOP BIT(1) > #define UNIPRO_PCLK_STOP BIT(0) > #define CLK_STOP_MASK (REFCLKOUT_STOP | REFCLK_STOP |\ > - UNIPRO_MCLK_STOP |\ > + UNIPRO_MCLK_STOP | MPHY_APBCLK_STOP|\ Please make this change into a separate patch of this series. > UNIPRO_PCLK_STOP) > #define HCI_MISC 0xB4 > #define REFCLK_CTRL_EN BIT(7) > @@ -386,6 +387,104 @@ static int exynos7_ufs_post_pwr_change(struct > exynos_ufs *ufs, > return 0; > } > > +static inline 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); > + 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(0x155E), 0x0); Use PA_LOCAL_TX_LCC_ENABLE instead of 0x155E. I think you can find more values from unipro.h. Please try to use as much as possible :) > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x3000), 0x0); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x3001), 0x1); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x4021), 0x1); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x4020), 0x1); They can be set from exynos_ufs_establish_connt. > + > + return 0; > +} > + > +static inline 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 inline 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(0x1569), 0x1); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x1584), 0x1); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2041), 8064); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2042), 28224); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2043), 20160); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B0), 12000); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B1), 32000); > + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B2), 16000); > + > + unipro_writel(ufs, 8064, 0x7888); > + unipro_writel(ufs, 28224, 0x788C); > + unipro_writel(ufs, 20160, 0x7890); > + unipro_writel(ufs, 12000, 0x78B8); > + unipro_writel(ufs, 32000, 0x78BC); > + unipro_writel(ufs, 16000, 0x78C0); > + > + return 0; > +} > + > /* > * exynos_ufs_auto_ctrl_hcc - HCI core clock control by h/w > * Control should be disabled in the below cases @@ -1595,6 +1694,46 @@ > 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 | > + 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 }, > @@ -1602,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 }, > {}, > }; > > -- > 2.25.1
Hi Chanho Thanks for the review. >-----Original Message----- >From: Chanho Park [mailto:chanho61.park@samsung.com] >Sent: Tuesday, May 31, 2022 1:07 PM >To: 'Alim Akhtar' <alim.akhtar@samsung.com>; linux-arm- >kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux- >scsi@vger.kernel.org; linux-phy@lists.infradead.org >Cc: devicetree@vger.kernel.org; robh+dt@kernel.org; >krzysztof.kozlowski+dt@linaro.org; vkoul@kernel.org; avri.altman@wdc.com; >bvanassche@acm.org; martin.petersen@oracle.com; >pankaj.dubey@samsung.com; linux-fsd@tesla.com; 'Bharat Uppal' ><bharat.uppal@samsung.com> >Subject: RE: [PATCH 5/6] ufs: host: ufs-exynos: add support for fsd ufs hci > >Hi, > >> -----Original Message----- >> From: Alim Akhtar <alim.akhtar@samsung.com> >> Sent: Tuesday, May 31, 2022 10:22 AM >> To: linux-arm-kernel@lists.infradead.org; >> linux-kernel@vger.kernel.org; linux-scsi@vger.kernel.org; >> linux-phy@lists.infradead.org >> Cc: devicetree@vger.kernel.org; robh+dt@kernel.org; >> krzysztof.kozlowski+dt@linaro.org; vkoul@kernel.org; >> avri.altman@wdc.com; bvanassche@acm.org; >martin.petersen@oracle.com; >> chanho61.park@samsung.com; pankaj.dubey@samsung.com; Alim Akhtar >> <alim.akhtar@samsung.com>; linux- fsd@tesla.com; Bharat Uppal >> <bharat.uppal@samsung.com> >> Subject: [PATCH 5/6] ufs: host: ufs-exynos: add support for fsd ufs >> hci >> >> Adds support of UFS HCI which is found in Tesla FSD SoC. FSD also have >> an addition bit for MPHY APB clock which was not there (was reserved) >> for previous exynos SoC. >> >> Cc: linux-fsd@tesla.com >> Signed-off-by: Bharat Uppal <bharat.uppal@samsung.com> >> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com> >> --- >> drivers/ufs/host/ufs-exynos.c | 143 >> +++++++++++++++++++++++++++++++++- >> 1 file changed, 142 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/ufs/host/ufs-exynos.c >> b/drivers/ufs/host/ufs-exynos.c index a81d8cbd542f..b3efdc4caca2 >> 100644 >> --- a/drivers/ufs/host/ufs-exynos.c >> +++ b/drivers/ufs/host/ufs-exynos.c >> @@ -52,11 +52,12 @@ >> #define HCI_ERR_EN_DME_LAYER 0x88 >> #define HCI_CLKSTOP_CTRL 0xB0 >> #define REFCLKOUT_STOP BIT(4) >> +#define MPHY_APBCLK_STOP BIT(3) >> #define REFCLK_STOP BIT(2) >> #define UNIPRO_MCLK_STOP BIT(1) >> #define UNIPRO_PCLK_STOP BIT(0) >> #define CLK_STOP_MASK (REFCLKOUT_STOP | REFCLK_STOP |\ >> - UNIPRO_MCLK_STOP |\ >> + UNIPRO_MCLK_STOP | >MPHY_APBCLK_STOP|\ > >Please make this change into a separate patch of this series. > Sure, will separate it out. >> UNIPRO_PCLK_STOP) >> #define HCI_MISC 0xB4 >> #define REFCLK_CTRL_EN BIT(7) >> @@ -386,6 +387,104 @@ static int exynos7_ufs_post_pwr_change(struct >> exynos_ufs *ufs, >> return 0; >> } >> >> +static inline 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); >> + 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(0x155E), 0x0); > >Use PA_LOCAL_TX_LCC_ENABLE instead of 0x155E. I think you can find more >values from unipro.h. >Please try to use as much as possible :) > Noted >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x3000), 0x0); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x3001), 0x1); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x4021), 0x1); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x4020), 0x1); > >They can be set from exynos_ufs_establish_connt. > Ok, >> + >> + return 0; >> +} >> + >> +static inline 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 inline 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(0x1569), 0x1); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x1584), 0x1); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2041), 8064); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2042), 28224); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2043), 20160); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B0), 12000); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B1), 32000); >> + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B2), 16000); >> + >> + unipro_writel(ufs, 8064, 0x7888); >> + unipro_writel(ufs, 28224, 0x788C); >> + unipro_writel(ufs, 20160, 0x7890); >> + unipro_writel(ufs, 12000, 0x78B8); >> + unipro_writel(ufs, 32000, 0x78BC); >> + unipro_writel(ufs, 16000, 0x78C0); >> + >> + return 0; >> +} >> + >> /* >> * exynos_ufs_auto_ctrl_hcc - HCI core clock control by h/w >> * Control should be disabled in the below cases @@ -1595,6 +1694,46 >> @@ 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 | >> + 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 }, >> @@ -1602,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 }, >> {}, >> }; >> >> -- >> 2.25.1 >
diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index a81d8cbd542f..b3efdc4caca2 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -52,11 +52,12 @@ #define HCI_ERR_EN_DME_LAYER 0x88 #define HCI_CLKSTOP_CTRL 0xB0 #define REFCLKOUT_STOP BIT(4) +#define MPHY_APBCLK_STOP BIT(3) #define REFCLK_STOP BIT(2) #define UNIPRO_MCLK_STOP BIT(1) #define UNIPRO_PCLK_STOP BIT(0) #define CLK_STOP_MASK (REFCLKOUT_STOP | REFCLK_STOP |\ - UNIPRO_MCLK_STOP |\ + UNIPRO_MCLK_STOP | MPHY_APBCLK_STOP|\ UNIPRO_PCLK_STOP) #define HCI_MISC 0xB4 #define REFCLK_CTRL_EN BIT(7) @@ -386,6 +387,104 @@ static int exynos7_ufs_post_pwr_change(struct exynos_ufs *ufs, return 0; } +static inline 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); + 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(0x155E), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x3000), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x3001), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x4021), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x4020), 0x1); + + return 0; +} + +static inline 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 inline 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(0x1569), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x1584), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2041), 8064); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2042), 28224); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x2043), 20160); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B0), 12000); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B1), 32000); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15B2), 16000); + + unipro_writel(ufs, 8064, 0x7888); + unipro_writel(ufs, 28224, 0x788C); + unipro_writel(ufs, 20160, 0x7890); + unipro_writel(ufs, 12000, 0x78B8); + unipro_writel(ufs, 32000, 0x78BC); + unipro_writel(ufs, 16000, 0x78C0); + + return 0; +} + /* * exynos_ufs_auto_ctrl_hcc - HCI core clock control by h/w * Control should be disabled in the below cases @@ -1595,6 +1694,46 @@ 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 | + 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 }, @@ -1602,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 }, {}, };