diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index d08d9f29b00c..044693107ea8 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -672,6 +673,36 @@ static int ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) return err; } +static void ufs_qcom_force_mem_config(struct ufs_hba *hba) +{ + struct ufs_clk_info *clki; + + /* + * Configure the behavior of ufs clocks core and peripheral + * memory state when they are turned off. + * This configuration is required to allow retaining + * ICE crypto configuration (including keys) when + * core_clk_ice is turned off, and powering down + * non-ICE RAMs of host controller. + * + * This is applicable only to gcc clocks. + */ + list_for_each_entry(clki, &hba->clk_list_head, list) { + + /* skip it for non-gcc (rpmh) clocks */ + if (!strcmp(clki->name, "ref_clk")) + continue; + + if (!strcmp(clki->name, "core_clk_ice") || + !strcmp(clki->name, "core_clk_ice_hw_ctl")) + qcom_clk_set_flags(clki->clk, CLKFLAG_RETAIN_MEM); + else + qcom_clk_set_flags(clki->clk, CLKFLAG_NORETAIN_MEM); + qcom_clk_set_flags(clki->clk, CLKFLAG_NORETAIN_PERIPH); + qcom_clk_set_flags(clki->clk, CLKFLAG_PERIPH_OFF_CLEAR); + } +} + static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { @@ -680,6 +711,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: + ufs_qcom_force_mem_config(hba); ufs_qcom_power_up_sequence(hba); /* * The PHY PLL output is the source of tx/rx lane symbol