PA_VS_CORE_CLK_40NS_CYCLES attribute represents the required number of Qunipro core clock for 40 nanoseconds. For UFS host controller V4 and above PA_VS_CORE_CLK_40NS_CYCLES needs to be programmed as per frequency of unipro core clk of UFS host controller. Add Support to configure PA_VS_CORE_CLK_40NS_CYCLES for Controller V4 and above to align with the hardware specification and to avoid functionality issues like h8 enter/exit failure, command timeout. Co-developed-by: Naveen Kumar Goud Arepalli <quic_narepall@xxxxxxxxxxx> Signed-off-by: Naveen Kumar Goud Arepalli <quic_narepall@xxxxxxxxxxx> Signed-off-by: Nitin Rawat <quic_nitirawa@xxxxxxxxxxx> --- drivers/ufs/host/ufs-qcom.c | 78 ++++++++++++++++++++++++++++++++++++- drivers/ufs/host/ufs-qcom.h | 12 ++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index b2be9ff272a4..a4855f0b93b0 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1292,6 +1292,77 @@ static void ufs_qcom_exit(struct ufs_hba *hba) phy_exit(host->generic_phy); } +/** + * ufs_qcom_set_clk_40ns_cycles - Configure 40ns clk cycles + * + * @hba: host controller instance + * @cycles_in_1us: No of cycles in 1us to be configured + * + * Returns error if dme get/set configuration for 40ns fails + * and returns zero on success. + */ +static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba, + u32 cycles_in_1us) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + u32 cycles_in_40ns; + u32 reg; + int err; + + /* + * UFS host controller V4.0.0 onwards needs to program + * PA_VS_CORE_CLK_40NS_CYCLES attribute per programmed + * frequency of unipro core clk of UFS host controller. + */ + if (host->hw_ver.major < 4) + return 0; + + /* + * Generic formulae for cycles_in_40ns = (freq_unipro/25) is not + * applicable for all frequencies. For ex: ceil(37.5 MHz/25) will + * be 2 and ceil(403 MHZ/25) will be 17 whereas Hardware + * specification expect to be 16. Hence use exact hardware spec + * mandated value for cycles_in_40ns instead of calculating using + * generic formulae. + */ + switch (cycles_in_1us) { + case UNIPRO_CORE_CLK_FREQ_403_MHZ: + cycles_in_40ns = 16; + break; + case UNIPRO_CORE_CLK_FREQ_300_MHZ: + cycles_in_40ns = 12; + break; + case UNIPRO_CORE_CLK_FREQ_201_5_MHZ: + cycles_in_40ns = 8; + break; + case UNIPRO_CORE_CLK_FREQ_150_MHZ: + cycles_in_40ns = 6; + break; + case UNIPRO_CORE_CLK_FREQ_100_MHZ: + cycles_in_40ns = 4; + break; + case UNIPRO_CORE_CLK_FREQ_75_MHZ: + cycles_in_40ns = 3; + break; + case UNIPRO_CORE_CLK_FREQ_37_5_MHZ: + cycles_in_40ns = 2; + break; + default: + dev_err(hba->dev, "UNIPRO clk freq %u MHz not supported\n", + cycles_in_1us); + return -EINVAL; + } + + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), ®); + if (err) + return err; + + reg &= ~PA_VS_CORE_CLK_40NS_CYCLES_MASK; + reg |= cycles_in_40ns; + + return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg); +} + static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -1334,9 +1405,14 @@ static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) /* Clear CORE_CLK_DIV_EN */ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; - return ufshcd_dme_set(hba, + err = ufshcd_dme_set(hba, UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), core_clk_ctrl_reg); + if (err) + return err; + + /* Configure unipro core clk 40ns attribute */ + return ufs_qcom_set_clk_40ns_cycles(hba, cycles_in_1us); } static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 3c6ef1259af3..264d429e72fe 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -132,6 +132,18 @@ enum { #define CLK_1US_CYCLES_MASK_V4 GENMASK(27, 16) #define CLK_1US_CYCLES_MASK GENMASK(7, 0) #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) +#define PA_VS_CORE_CLK_40NS_CYCLES 0x9007 +#define PA_VS_CORE_CLK_40NS_CYCLES_MASK GENMASK(6, 0) + + +/* QCOM UFS host controller core clk frequencies */ +#define UNIPRO_CORE_CLK_FREQ_37_5_MHZ 38 +#define UNIPRO_CORE_CLK_FREQ_75_MHZ 75 +#define UNIPRO_CORE_CLK_FREQ_100_MHZ 100 +#define UNIPRO_CORE_CLK_FREQ_150_MHZ 150 +#define UNIPRO_CORE_CLK_FREQ_300_MHZ 300 +#define UNIPRO_CORE_CLK_FREQ_201_5_MHZ 202 +#define UNIPRO_CORE_CLK_FREQ_403_MHZ 403 static inline void ufs_qcom_get_controller_revision(struct ufs_hba *hba, -- 2.17.1