Loading drivers/scsi/ufs/ufs-qcom.c +74 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ static int ufs_qcom_init_sysfs(struct ufs_hba *hba); static int ufs_qcom_update_qos_constraints(struct qos_cpu_group *qcg, enum constraint type); static int ufs_qcom_unvote_qos_all(struct ufs_hba *hba); static void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host); static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, struct ufs_pa_layer_attr *dev_max, struct ufs_pa_layer_attr *agreed_pwr) Loading Loading @@ -813,6 +813,61 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_max_freq_mode(struct ufs_hba *hba) return err; } /** * ufs_qcom_bypass_cfgready_signal - Tunes PA_VS_CONFIG_REG1 and * PA_VS_CONFIG_REG2 vendor specific attributes of local unipro * to bypass CFGREADY signal on Config interface between UFS * controller and PHY. * * The issue is related to config signals sampling from PHY * to controller. The PHY signals which are driven by 150MHz * clock and sampled by 300MHz instead of 150MHZ. * * The issue will be seen when only one of tx_cfg_rdyn_0 * and tx_cfg_rdyn_1 is 0 around sampling clock edge and * if timing is not met as timing margin for some devices is * very less in one of the corner. * * To workaround this issue, controller should bypass the Cfgready * signal(TX_CFGREADY and RX_CFGREDY) because controller still wait * for another signal tx_savestatusn which will serve same purpose. * * The corresponding HW CR: 'QCTDD06985523' UFS HSG4 test fails * in SDF MAX GLS is linked to this issue. */ static int ufs_qcom_bypass_cfgready_signal(struct ufs_hba *hba) { int err = 0; u32 pa_vs_config_reg1; u32 pa_vs_config_reg2; u32 mask; err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), &pa_vs_config_reg1); if (err) goto out; err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), (pa_vs_config_reg1 | BIT_TX_EOB_COND)); if (err) goto out; err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG2), &pa_vs_config_reg2); if (err) goto out; mask = (BIT_RX_EOB_COND | BIT_LINKCFG_WAIT_LL1_RX_CFG_RDY | H8_ENTER_COND_MASK); pa_vs_config_reg2 = (pa_vs_config_reg2 & ~mask) | (0x2 << H8_ENTER_COND_OFFSET); err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG2), (pa_vs_config_reg2)); out: return err; } static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { Loading Loading @@ -853,6 +908,9 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, err = ufshcd_disable_host_tx_lcc(hba); if (err) goto out; if (host->bypass_g4_cfgready) err = ufs_qcom_bypass_cfgready_signal(hba); break; case POST_CHANGE: ufs_qcom_link_startup_post_change(hba); Loading Loading @@ -2602,6 +2660,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_parse_pm_level(hba); ufs_qcom_parse_limits(host); ufs_qcom_parse_g4_workaround_flag(host); ufs_qcom_parse_lpm(host); if (host->disable_lpm) pm_runtime_forbid(host->hba->dev); Loading Loading @@ -3180,6 +3239,20 @@ static void ufs_qcom_parse_limits(struct ufs_qcom_host *host) of_property_read_u32(np, "limit-phy-submode", &host->limit_phy_submode); } /* * ufs_qcom_parse_g4_workaround_flag - read bypass-g4-cfgready entry from DT */ static void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host) { struct device_node *np = host->hba->dev->of_node; const char *str = "bypass-g4-cfgready"; if (!np) return; host->bypass_g4_cfgready = of_property_read_bool(np, str); } /* * ufs_qcom_parse_lpm - read from DTS whether LPM modes should be disabled. */ Loading drivers/scsi/ufs/ufs-qcom.h +11 −2 Original line number Diff line number Diff line Loading @@ -168,8 +168,16 @@ enum ufs_qcom_phy_init_type { /* QUniPro Vendor specific attributes */ #define PA_VS_CONFIG_REG1 0x9000 #define BIT_TX_EOB_COND BIT(23) #define PA_VS_CONFIG_REG2 0x9005 #define H8_ENTER_COND_OFFSET 0x6 #define H8_ENTER_COND_MASK GENMASK(6, 7) #define BIT_RX_EOB_COND BIT(5) #define BIT_LINKCFG_WAIT_LL1_RX_CFG_RDY BIT(26) #define SAVECONFIGTIME_MODE_MASK 0x6000 #define DME_VS_CORE_CLK_CTRL 0xD002 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) #define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF Loading Loading @@ -367,6 +375,7 @@ struct ufs_qcom_host { atomic_t scale_up; atomic_t clks_on; struct ufs_qcom_qos_req *ufs_qos; bool bypass_g4_cfgready; }; static inline u32 Loading Loading
drivers/scsi/ufs/ufs-qcom.c +74 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ static int ufs_qcom_init_sysfs(struct ufs_hba *hba); static int ufs_qcom_update_qos_constraints(struct qos_cpu_group *qcg, enum constraint type); static int ufs_qcom_unvote_qos_all(struct ufs_hba *hba); static void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host); static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, struct ufs_pa_layer_attr *dev_max, struct ufs_pa_layer_attr *agreed_pwr) Loading Loading @@ -813,6 +813,61 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_max_freq_mode(struct ufs_hba *hba) return err; } /** * ufs_qcom_bypass_cfgready_signal - Tunes PA_VS_CONFIG_REG1 and * PA_VS_CONFIG_REG2 vendor specific attributes of local unipro * to bypass CFGREADY signal on Config interface between UFS * controller and PHY. * * The issue is related to config signals sampling from PHY * to controller. The PHY signals which are driven by 150MHz * clock and sampled by 300MHz instead of 150MHZ. * * The issue will be seen when only one of tx_cfg_rdyn_0 * and tx_cfg_rdyn_1 is 0 around sampling clock edge and * if timing is not met as timing margin for some devices is * very less in one of the corner. * * To workaround this issue, controller should bypass the Cfgready * signal(TX_CFGREADY and RX_CFGREDY) because controller still wait * for another signal tx_savestatusn which will serve same purpose. * * The corresponding HW CR: 'QCTDD06985523' UFS HSG4 test fails * in SDF MAX GLS is linked to this issue. */ static int ufs_qcom_bypass_cfgready_signal(struct ufs_hba *hba) { int err = 0; u32 pa_vs_config_reg1; u32 pa_vs_config_reg2; u32 mask; err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), &pa_vs_config_reg1); if (err) goto out; err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), (pa_vs_config_reg1 | BIT_TX_EOB_COND)); if (err) goto out; err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG2), &pa_vs_config_reg2); if (err) goto out; mask = (BIT_RX_EOB_COND | BIT_LINKCFG_WAIT_LL1_RX_CFG_RDY | H8_ENTER_COND_MASK); pa_vs_config_reg2 = (pa_vs_config_reg2 & ~mask) | (0x2 << H8_ENTER_COND_OFFSET); err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG2), (pa_vs_config_reg2)); out: return err; } static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { Loading Loading @@ -853,6 +908,9 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, err = ufshcd_disable_host_tx_lcc(hba); if (err) goto out; if (host->bypass_g4_cfgready) err = ufs_qcom_bypass_cfgready_signal(hba); break; case POST_CHANGE: ufs_qcom_link_startup_post_change(hba); Loading Loading @@ -2602,6 +2660,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_parse_pm_level(hba); ufs_qcom_parse_limits(host); ufs_qcom_parse_g4_workaround_flag(host); ufs_qcom_parse_lpm(host); if (host->disable_lpm) pm_runtime_forbid(host->hba->dev); Loading Loading @@ -3180,6 +3239,20 @@ static void ufs_qcom_parse_limits(struct ufs_qcom_host *host) of_property_read_u32(np, "limit-phy-submode", &host->limit_phy_submode); } /* * ufs_qcom_parse_g4_workaround_flag - read bypass-g4-cfgready entry from DT */ static void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host) { struct device_node *np = host->hba->dev->of_node; const char *str = "bypass-g4-cfgready"; if (!np) return; host->bypass_g4_cfgready = of_property_read_bool(np, str); } /* * ufs_qcom_parse_lpm - read from DTS whether LPM modes should be disabled. */ Loading
drivers/scsi/ufs/ufs-qcom.h +11 −2 Original line number Diff line number Diff line Loading @@ -168,8 +168,16 @@ enum ufs_qcom_phy_init_type { /* QUniPro Vendor specific attributes */ #define PA_VS_CONFIG_REG1 0x9000 #define BIT_TX_EOB_COND BIT(23) #define PA_VS_CONFIG_REG2 0x9005 #define H8_ENTER_COND_OFFSET 0x6 #define H8_ENTER_COND_MASK GENMASK(6, 7) #define BIT_RX_EOB_COND BIT(5) #define BIT_LINKCFG_WAIT_LL1_RX_CFG_RDY BIT(26) #define SAVECONFIGTIME_MODE_MASK 0x6000 #define DME_VS_CORE_CLK_CTRL 0xD002 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) #define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF Loading Loading @@ -367,6 +375,7 @@ struct ufs_qcom_host { atomic_t scale_up; atomic_t clks_on; struct ufs_qcom_qos_req *ufs_qos; bool bypass_g4_cfgready; }; static inline u32 Loading