Merge "scsi: ufs-qcom: Add sysfs node for multilevel clock scaling support"
This commit is contained in:
committed by
Gerrit - the friendly Code Review server
commit
be29c66a52
@@ -30,6 +30,7 @@
|
|||||||
#include "ufshci.h"
|
#include "ufshci.h"
|
||||||
#include "ufs_quirks.h"
|
#include "ufs_quirks.h"
|
||||||
#include "ufshcd-crypto-qti.h"
|
#include "ufshcd-crypto-qti.h"
|
||||||
|
#include <trace/hooks/ufshcd.h>
|
||||||
|
|
||||||
#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
|
#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
|
||||||
(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
|
(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
|
||||||
@@ -46,7 +47,6 @@
|
|||||||
|
|
||||||
#define ANDROID_BOOT_DEV_MAX 30
|
#define ANDROID_BOOT_DEV_MAX 30
|
||||||
|
|
||||||
|
|
||||||
/* Max number of log pages */
|
/* Max number of log pages */
|
||||||
#define UFS_QCOM_MAX_LOG_SZ 10
|
#define UFS_QCOM_MAX_LOG_SZ 10
|
||||||
#define ufs_qcom_log_str(host, fmt, ...) \
|
#define ufs_qcom_log_str(host, fmt, ...) \
|
||||||
@@ -60,6 +60,15 @@ static char android_boot_dev[ANDROID_BOOT_DEV_MAX];
|
|||||||
|
|
||||||
static DEFINE_PER_CPU(struct freq_qos_request, qos_min_req);
|
static DEFINE_PER_CPU(struct freq_qos_request, qos_min_req);
|
||||||
|
|
||||||
|
/* clk freq mode */
|
||||||
|
enum {
|
||||||
|
LOW_SVS,
|
||||||
|
NOM,
|
||||||
|
TURBO,
|
||||||
|
TURBO_L1,
|
||||||
|
INVAL_MODE,
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TSTBUS_UAWM,
|
TSTBUS_UAWM,
|
||||||
TSTBUS_UARM,
|
TSTBUS_UARM,
|
||||||
@@ -106,6 +115,8 @@ static int ufs_qcom_update_qos_constraints(struct qos_cpu_group *qcg,
|
|||||||
static int ufs_qcom_unvote_qos_all(struct ufs_hba *hba);
|
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 void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host);
|
||||||
static int ufs_qcom_mod_min_cpufreq(unsigned int cpu, s32 new_val);
|
static int ufs_qcom_mod_min_cpufreq(unsigned int cpu, s32 new_val);
|
||||||
|
static void ufs_qcom_hook_clock_scaling(void *used, struct ufs_hba *hba, bool *force_out,
|
||||||
|
bool *force_saling, bool *scale_up);
|
||||||
|
|
||||||
static inline void cancel_dwork_unvote_cpufreq(struct ufs_hba *hba)
|
static inline void cancel_dwork_unvote_cpufreq(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
@@ -634,8 +645,11 @@ out:
|
|||||||
static int ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)
|
static int ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
struct ufs_clk_info *clki;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list);
|
||||||
|
|
||||||
/* Enable UTP internal clock gating */
|
/* Enable UTP internal clock gating */
|
||||||
ufshcd_writel(hba,
|
ufshcd_writel(hba,
|
||||||
ufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL,
|
ufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL,
|
||||||
@@ -656,9 +670,11 @@ static int ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* As per HPG, ATTR_HW_CGC_EN bit should be enabled when operating at
|
* As per HPG, ATTR_HW_CGC_EN bit should be enabled when operating at
|
||||||
* more than 300mhz and hence should be disable in UFS init sequence
|
* more than 300mhz for target which support multi level clk scaling
|
||||||
|
* and hence should be disable in UFS init sequence for those target.
|
||||||
|
* For rest all other target set the default to 1 like earlier target.
|
||||||
*/
|
*/
|
||||||
if (host->ml_scale_up)
|
if (host->ml_scale_sup && (clk_get_rate(clki->clk) <= UFS_NOM_THRES_FREQ))
|
||||||
err = ufshcd_dme_rmw(hba, PA_VS_CLK_CFG_REG_MASK,
|
err = ufshcd_dme_rmw(hba, PA_VS_CLK_CFG_REG_MASK,
|
||||||
PA_VS_CLK_CFG_REG_MASK1, PA_VS_CLK_CFG_REG);
|
PA_VS_CLK_CFG_REG_MASK1, PA_VS_CLK_CFG_REG);
|
||||||
else
|
else
|
||||||
@@ -816,6 +832,16 @@ static int __ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
|
|||||||
core_clk_rate = DEFAULT_CLK_RATE_HZ;
|
core_clk_rate = DEFAULT_CLK_RATE_HZ;
|
||||||
|
|
||||||
core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC;
|
core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As per HPG, some target needs SYS1CLK_1US_REG as Fs/2 where
|
||||||
|
* Fs is system clock frequency in MHz if operating beyond 300Mhz.
|
||||||
|
* Add 1 to it if its not multiple of 2.
|
||||||
|
*/
|
||||||
|
if (core_clk_rate > UFS_NOM_THRES_FREQ && host->turbo_additional_conf_req)
|
||||||
|
core_clk_cycles_per_us = core_clk_cycles_per_us/2 +
|
||||||
|
(core_clk_cycles_per_us % 2);
|
||||||
|
|
||||||
if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) {
|
if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) {
|
||||||
ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
|
ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
|
||||||
/*
|
/*
|
||||||
@@ -916,6 +942,7 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_max_freq_mode(struct ufs_hba *hba)
|
|||||||
{
|
{
|
||||||
struct ufs_clk_info *clki;
|
struct ufs_clk_info *clki;
|
||||||
struct list_head *head = &hba->clk_list_head;
|
struct list_head *head = &hba->clk_list_head;
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
u32 max_freq = 0;
|
u32 max_freq = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@@ -923,6 +950,10 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_max_freq_mode(struct ufs_hba *hba)
|
|||||||
if (!IS_ERR_OR_NULL(clki->clk) &&
|
if (!IS_ERR_OR_NULL(clki->clk) &&
|
||||||
(!strcmp(clki->name, "core_clk_unipro"))) {
|
(!strcmp(clki->name, "core_clk_unipro"))) {
|
||||||
max_freq = clki->max_freq;
|
max_freq = clki->max_freq;
|
||||||
|
/* clk mode change from TURBO to NOM */
|
||||||
|
if ((host->clk_curr_mode == TURBO) &&
|
||||||
|
(host->clk_next_mode == NOM))
|
||||||
|
max_freq = UFS_NOM_THRES_FREQ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -934,6 +965,15 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_max_freq_mode(struct ufs_hba *hba)
|
|||||||
case 150000000:
|
case 150000000:
|
||||||
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150, 6);
|
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150, 6);
|
||||||
break;
|
break;
|
||||||
|
case 600000000:
|
||||||
|
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 300, 12);
|
||||||
|
break;
|
||||||
|
case 550000000:
|
||||||
|
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 275, 11);
|
||||||
|
break;
|
||||||
|
case 806400000:
|
||||||
|
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 202, 9);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
break;
|
break;
|
||||||
@@ -1053,6 +1093,60 @@ static void ufs_qcom_validate_link_params(struct ufs_hba *hba)
|
|||||||
ufs_qcom_dump_attribs(hba);
|
ufs_qcom_dump_attribs(hba);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ufs_qcom_apply_turbo_setting(struct ufs_hba *hba)
|
||||||
|
{
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (host->turbo_unipro_attr_applied)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (host->turbo_additional_conf_req)
|
||||||
|
ufshcd_rmwl(host->hba, TEST_BUS_CTRL_2_HCI_SEL_TURBO_MASK,
|
||||||
|
TEST_BUS_CTRL_2_HCI_SEL_TURBO,
|
||||||
|
UFS_TEST_BUS_CTRL_2);
|
||||||
|
|
||||||
|
err = ufshcd_dme_rmw(hba, PA_VS_CLK_CFG_REG_MASK_TURBO,
|
||||||
|
ATTR_HW_CGC_EN_TURBO, PA_VS_CLK_CFG_REG);
|
||||||
|
if (err)
|
||||||
|
dev_err(hba->dev, "%s apply of turbo setting failed\n", __func__);
|
||||||
|
/*
|
||||||
|
* clear bit 1 of ICE_CONTROL Register to support ice
|
||||||
|
* core clock frequency greater than 300 MHz
|
||||||
|
*/
|
||||||
|
if (host->turbo_additional_conf_req)
|
||||||
|
ufshcd_ice_rmwl(host, ICE_CONTROL, 0, REG_UFS_ICE_CONTROL);
|
||||||
|
|
||||||
|
host->turbo_unipro_attr_applied = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ufs_qcom_remove_turbo_setting(struct ufs_hba *hba)
|
||||||
|
{
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!host->turbo_unipro_attr_applied)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (host->turbo_additional_conf_req)
|
||||||
|
ufshcd_rmwl(host->hba, TEST_BUS_CTRL_2_HCI_SEL_TURBO_MASK,
|
||||||
|
TEST_BUS_CTRL_2_HCI_SEL_NONTURBO,
|
||||||
|
UFS_TEST_BUS_CTRL_2);
|
||||||
|
|
||||||
|
err = ufshcd_dme_rmw(hba, PA_VS_CLK_CFG_REG_MASK_TURBO,
|
||||||
|
ATTR_HW_CGC_EN_NON_TURBO, PA_VS_CLK_CFG_REG);
|
||||||
|
if (err)
|
||||||
|
dev_err(hba->dev, "%s remove of turbo setting failed\n", __func__);
|
||||||
|
/*
|
||||||
|
* Set bit 1 of ICE_CONTROL Register to support ice
|
||||||
|
* core clock frequency lesser or equal than 300 MHz
|
||||||
|
*/
|
||||||
|
if (host->turbo_additional_conf_req)
|
||||||
|
ufshcd_ice_rmwl(host, ICE_CONTROL, 1, REG_UFS_ICE_CONTROL);
|
||||||
|
|
||||||
|
host->turbo_unipro_attr_applied = false;
|
||||||
|
}
|
||||||
|
|
||||||
static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
|
static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
|
||||||
enum ufs_notify_change_status status)
|
enum ufs_notify_change_status status)
|
||||||
{
|
{
|
||||||
@@ -1068,6 +1162,9 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (host->ml_scale_sup)
|
||||||
|
ufs_qcom_apply_turbo_setting(hba);
|
||||||
|
|
||||||
if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE,
|
if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE,
|
||||||
0, true)) {
|
0, true)) {
|
||||||
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
|
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
|
||||||
@@ -1973,19 +2070,84 @@ static void ufshcd_parse_pm_levels(struct ufs_hba *hba)
|
|||||||
* ufs_qcom_parse_multilevel_support - read from DTS where multi level
|
* ufs_qcom_parse_multilevel_support - read from DTS where multi level
|
||||||
* clock scaling support is enabled
|
* clock scaling support is enabled
|
||||||
*/
|
*/
|
||||||
static void ufs_qcom_parse_multilevel_clkscale_support(struct ufs_qcom_host *host)
|
static void ufs_qcom_parse_turbo_clk_freq(struct ufs_qcom_host *host)
|
||||||
{
|
{
|
||||||
struct device_node *np = host->hba->dev->of_node;
|
struct device_node *np = host->hba->dev->of_node;
|
||||||
|
|
||||||
if (!np)
|
if (!np)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
host->ml_scale_up = of_property_read_bool(np,
|
host->ml_scale_sup = of_property_read_bool(np, "multi-level-clk-scaling-support");
|
||||||
"multi-level-clk-scaling-support");
|
|
||||||
|
|
||||||
if (host->ml_scale_up)
|
if (!host->ml_scale_sup)
|
||||||
dev_info(host->hba->dev, "(%s) Mullti level clock scale enabled\n",
|
return;
|
||||||
__func__);
|
|
||||||
|
host->axi_turbo_clk_freq = UFS_QCOM_DEFAULT_TURBO_FREQ;
|
||||||
|
host->axi_turbo_l1_clk_freq = UFS_QCOM_DEFAULT_TURBO_L1_FREQ;
|
||||||
|
host->ice_turbo_clk_freq = UFS_QCOM_DEFAULT_TURBO_FREQ;
|
||||||
|
host->ice_turbo_l1_clk_freq = UFS_QCOM_DEFAULT_TURBO_L1_FREQ;
|
||||||
|
host->unipro_turbo_clk_freq = UFS_QCOM_DEFAULT_TURBO_FREQ;
|
||||||
|
host->unipro_turbo_l1_clk_freq = UFS_QCOM_DEFAULT_TURBO_L1_FREQ;
|
||||||
|
|
||||||
|
of_property_read_u32(np, "axi-turbo-clk-freq", &host->axi_turbo_clk_freq);
|
||||||
|
of_property_read_u32(np, "axi-turbo-l1-clk-freq", &host->axi_turbo_l1_clk_freq);
|
||||||
|
of_property_read_u32(np, "ice-turbo-clk-freq", &host->ice_turbo_clk_freq);
|
||||||
|
of_property_read_u32(np, "ice-turbo-l1-clk-freq", &host->ice_turbo_l1_clk_freq);
|
||||||
|
of_property_read_u32(np, "unipro-turbo-clk-freq", &host->unipro_turbo_clk_freq);
|
||||||
|
of_property_read_u32(np, "unipro-turbo-l1-clk-freq", &host->unipro_turbo_l1_clk_freq);
|
||||||
|
|
||||||
|
/* only some target need specific turbo setting */
|
||||||
|
if (host->axi_turbo_l1_clk_freq > 403000000)
|
||||||
|
host->turbo_additional_conf_req = true;
|
||||||
|
|
||||||
|
dev_info(host->hba->dev, "%s multi_level_clk_scaling_support = %d\n", __func__,
|
||||||
|
host->ml_scale_sup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TUBRO freq mode for ice/unipro/axi clk is needed only for few UFS3.x devices
|
||||||
|
* for which AFC latencies is high(>500ns). For other devices, overwrite max
|
||||||
|
* clk freq from turbo clkfreq read from DT back to NOM freq(300mhz) and
|
||||||
|
* set back clk rate to this freq.
|
||||||
|
*/
|
||||||
|
static int ufs_qcom_update_max_clk_freq(struct ufs_hba *hba)
|
||||||
|
{
|
||||||
|
struct ufs_clk_info *clki;
|
||||||
|
struct list_head *head = &hba->clk_list_head;
|
||||||
|
u32 max_freq = UFS_NOM_THRES_FREQ;
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list);
|
||||||
|
if (clki->max_freq > UFS_NOM_THRES_FREQ) {
|
||||||
|
/* if ml_scale_sup is true and UFS 3.x continue with turbo freq */
|
||||||
|
if (host->ml_scale_sup && host->limit_phy_submode)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
/* Initial freq read from DT is 300mhz, continue with that */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list_empty(head))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
list_for_each_entry(clki, head, list) {
|
||||||
|
if (!IS_ERR_OR_NULL(clki->clk)) {
|
||||||
|
if (!strcmp(clki->name, "core_clk") ||
|
||||||
|
!strcmp(clki->name, "core_clk_unipro") ||
|
||||||
|
!strcmp(clki->name, "core_clk_ice")) {
|
||||||
|
clki->max_freq = max_freq;
|
||||||
|
ret = clk_set_rate(clki->clk, clki->max_freq);
|
||||||
|
if (ret)
|
||||||
|
dev_err(hba->dev,
|
||||||
|
"%s:clk_set_rate failed\n", __func__);
|
||||||
|
/* multi level clk scale not needed */
|
||||||
|
host->ml_scale_sup = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba)
|
static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba)
|
||||||
@@ -3106,8 +3268,9 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
|||||||
ufs_qcom_parse_pm_level(hba);
|
ufs_qcom_parse_pm_level(hba);
|
||||||
ufs_qcom_parse_limits(host);
|
ufs_qcom_parse_limits(host);
|
||||||
ufs_qcom_parse_g4_workaround_flag(host);
|
ufs_qcom_parse_g4_workaround_flag(host);
|
||||||
|
ufs_qcom_parse_turbo_clk_freq(host);
|
||||||
|
ufs_qcom_update_max_clk_freq(hba);
|
||||||
ufs_qcom_parse_lpm(host);
|
ufs_qcom_parse_lpm(host);
|
||||||
ufs_qcom_parse_multilevel_clkscale_support(host);
|
|
||||||
if (host->disable_lpm)
|
if (host->disable_lpm)
|
||||||
pm_runtime_forbid(host->hba->dev);
|
pm_runtime_forbid(host->hba->dev);
|
||||||
|
|
||||||
@@ -3259,6 +3422,40 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ufs_qcom_turbo_specific_clk_scale_up_pre_change(struct ufs_hba *hba)
|
||||||
|
{
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
struct ufs_pa_layer_attr *attr = &host->dev_req_params;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to run in turbo mode when scale up is called during
|
||||||
|
* disabling clk scaling(using sysfs).
|
||||||
|
*/
|
||||||
|
if (!hba->clk_scaling.is_enabled) {
|
||||||
|
host->clk_next_mode = TURBO;
|
||||||
|
host->is_turbo_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is case when clk mode changes from TURBO to NOM. Here the
|
||||||
|
* turbo related setting would be removed in clock scale up
|
||||||
|
* post change.
|
||||||
|
*/
|
||||||
|
if ((host->clk_curr_mode == TURBO) && (host->clk_next_mode == NOM))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Apply turbo related setting before changing to turbo mode */
|
||||||
|
ufs_qcom_apply_turbo_setting(hba);
|
||||||
|
|
||||||
|
if (attr)
|
||||||
|
__ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
|
||||||
|
attr->hs_rate, false, true);
|
||||||
|
|
||||||
|
err = ufs_qcom_set_dme_vs_core_clk_ctrl_max_freq_mode(hba);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
|
static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
@@ -3268,6 +3465,9 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
|
|||||||
if (!ufs_qcom_cap_qunipro(host))
|
if (!ufs_qcom_cap_qunipro(host))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (host->ml_scale_sup)
|
||||||
|
return ufs_qcom_turbo_specific_clk_scale_up_pre_change(hba);
|
||||||
|
|
||||||
if (attr)
|
if (attr)
|
||||||
__ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
|
__ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
|
||||||
attr->hs_rate, false, true);
|
attr->hs_rate, false, true);
|
||||||
@@ -3277,10 +3477,43 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ufs_turbo_specific_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
|
||||||
|
{
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
struct ufs_pa_layer_attr *attr = &host->dev_req_params;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!ufs_qcom_cap_qunipro(host))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* removed turbo setting when scaling down from TURBO to NOM */
|
||||||
|
if (host->ml_scale_sup)
|
||||||
|
ufs_qcom_remove_turbo_setting(hba);
|
||||||
|
|
||||||
|
if (attr)
|
||||||
|
ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
|
||||||
|
attr->hs_rate, false);
|
||||||
|
|
||||||
|
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 300, 12);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
|
static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clk mode change is from TURBO to NOM, so we would have to remove
|
||||||
|
* turbo specific setting and also set counter/register according to
|
||||||
|
* new UFS clk freq. So is apparently considered similar to clk scale
|
||||||
|
* down scenarios. Hence call turbo specific clk scale down API
|
||||||
|
* to change this setting.
|
||||||
|
*/
|
||||||
|
if ((host->clk_curr_mode == TURBO) && (host->clk_next_mode == NOM)) {
|
||||||
|
ufs_turbo_specific_qcom_clk_scale_up_post_change(hba);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
hba->clk_gating.delay_ms = UFS_QCOM_CLK_GATING_DELAY_MS_PERF;
|
hba->clk_gating.delay_ms = UFS_QCOM_CLK_GATING_DELAY_MS_PERF;
|
||||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||||
@@ -3357,6 +3590,112 @@ static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Override freq from TURBO to NOM(300mhz) when changing freq mode from
|
||||||
|
* TURBO to NOM when busy_percentage falls below the predefined threshold.
|
||||||
|
* This also updates the curr clk freq variable defined in host structure for
|
||||||
|
* bookkeeping purpose which can be read using sysfs.
|
||||||
|
*/
|
||||||
|
static int ufs_qcom_override_clk_freq(struct ufs_hba *hba)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct ufs_clk_info *clki;
|
||||||
|
struct list_head *head = &hba->clk_list_head;
|
||||||
|
unsigned long max_freq = UFS_NOM_THRES_FREQ;
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
|
||||||
|
if (list_empty(head))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Freq override from TURBO to NOM(300mhz) is required only when changing clk mode
|
||||||
|
* from TURBO to NOM. We should avoid overriding to NOM when clk scaling is disable
|
||||||
|
* so that we operate at turbo freq in case clk scaling is disabled.
|
||||||
|
*/
|
||||||
|
if (hba->clk_scaling.is_enabled &&
|
||||||
|
!((host->clk_curr_mode == TURBO) && (host->clk_next_mode == NOM))) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No Need to override, continue with TURBO or LOWSVS freq,
|
||||||
|
* update curr clk freq before return
|
||||||
|
*/
|
||||||
|
if (host->clk_next_mode == TURBO) {
|
||||||
|
host->curr_axi_freq = host->axi_turbo_clk_freq;
|
||||||
|
host->curr_unipro_freq = host->unipro_turbo_clk_freq;
|
||||||
|
host->curr_ice_freq = host->ice_turbo_clk_freq;
|
||||||
|
} else if (host->clk_next_mode == LOW_SVS) {
|
||||||
|
host->curr_axi_freq = clki->min_freq;
|
||||||
|
host->curr_unipro_freq = clki->min_freq;
|
||||||
|
host->curr_ice_freq = clki->min_freq;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list);
|
||||||
|
list_for_each_entry(clki, head, list) {
|
||||||
|
if (!IS_ERR_OR_NULL(clki->clk)) {
|
||||||
|
if (!strcmp(clki->name, "core_clk") ||
|
||||||
|
!strcmp(clki->name, "core_clk_unipro") ||
|
||||||
|
!strcmp(clki->name, "core_clk_ice")) {
|
||||||
|
|
||||||
|
if (!strcmp(clki->name, "core_clk")) {
|
||||||
|
/*
|
||||||
|
* clock scale up request when clk scaling
|
||||||
|
* is being disable(sysfs)
|
||||||
|
*/
|
||||||
|
if (!hba->clk_scaling.is_enabled)
|
||||||
|
max_freq = clki->max_freq;
|
||||||
|
|
||||||
|
ret = clk_set_rate(clki->clk, max_freq);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
host->curr_axi_freq = max_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(clki->name, "core_clk_ice")) {
|
||||||
|
/*
|
||||||
|
* clock scale up request when clk scaling
|
||||||
|
* is being disable(sysfs)
|
||||||
|
*/
|
||||||
|
if (!hba->clk_scaling.is_enabled)
|
||||||
|
max_freq = clki->max_freq;
|
||||||
|
|
||||||
|
ret = clk_set_rate(clki->clk, max_freq);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
host->curr_ice_freq = max_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(clki->name, "core_clk_unipro")) {
|
||||||
|
/*
|
||||||
|
* clock scale up request when clk scaling
|
||||||
|
* is being disable(sysfs)
|
||||||
|
*/
|
||||||
|
if (!hba->clk_scaling.is_enabled)
|
||||||
|
max_freq = clki->max_freq;
|
||||||
|
|
||||||
|
ret = clk_set_rate(clki->clk, max_freq);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
host->curr_unipro_freq = max_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
out:
|
||||||
|
if (ret) {
|
||||||
|
dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
|
||||||
|
__func__, clki->name,
|
||||||
|
max_freq, ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
|
static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
|
||||||
bool scale_up, enum ufs_notify_change_status status)
|
bool scale_up, enum ufs_notify_change_status status)
|
||||||
{
|
{
|
||||||
@@ -3370,7 +3709,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
|
|||||||
return err;
|
return err;
|
||||||
if (scale_up) {
|
if (scale_up) {
|
||||||
err = ufs_qcom_clk_scale_up_pre_change(hba);
|
err = ufs_qcom_clk_scale_up_pre_change(hba);
|
||||||
if (!host->cpufreq_dis) {
|
if (!host->cpufreq_dis && !atomic_read(&host->scale_up)) {
|
||||||
atomic_set(&host->num_reqs_threshold, 0);
|
atomic_set(&host->num_reqs_threshold, 0);
|
||||||
queue_delayed_work(host->ufs_qos->workq,
|
queue_delayed_work(host->ufs_qos->workq,
|
||||||
&host->fwork,
|
&host->fwork,
|
||||||
@@ -3384,6 +3723,8 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
|
|||||||
if (err)
|
if (err)
|
||||||
ufshcd_uic_hibern8_exit(hba);
|
ufshcd_uic_hibern8_exit(hba);
|
||||||
} else {
|
} else {
|
||||||
|
if (host->ml_scale_sup)
|
||||||
|
ufs_qcom_override_clk_freq(hba);
|
||||||
if (scale_up)
|
if (scale_up)
|
||||||
err = ufs_qcom_clk_scale_up_post_change(hba);
|
err = ufs_qcom_clk_scale_up_post_change(hba);
|
||||||
else
|
else
|
||||||
@@ -3400,8 +3741,28 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
|
|||||||
dev_req_params->pwr_rx,
|
dev_req_params->pwr_rx,
|
||||||
dev_req_params->hs_rate,
|
dev_req_params->hs_rate,
|
||||||
false);
|
false);
|
||||||
|
/*
|
||||||
|
* set is_max_bw_needed to 1 so that IB value of max_bw
|
||||||
|
* row from DT would be picked. IB value is voted to make
|
||||||
|
* sure voting is guranteed to keep bus vote to Turbo mode
|
||||||
|
*/
|
||||||
|
if (host->ml_scale_sup && host->is_turbo_enabled)
|
||||||
|
host->bus_vote.is_max_bw_needed = true;
|
||||||
|
else
|
||||||
|
host->bus_vote.is_max_bw_needed = false;
|
||||||
|
|
||||||
ufs_qcom_update_bus_bw_vote(host);
|
ufs_qcom_update_bus_bw_vote(host);
|
||||||
ufshcd_uic_hibern8_exit(hba);
|
ufshcd_uic_hibern8_exit(hba);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update clk curr mode with clk next mode in end of
|
||||||
|
* clk scaling post sequence and mark clk next mode
|
||||||
|
* as INVAL.
|
||||||
|
*/
|
||||||
|
if (host->ml_scale_sup) {
|
||||||
|
host->clk_curr_mode = host->clk_next_mode;
|
||||||
|
host->clk_next_mode = INVAL_MODE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
@@ -3762,6 +4123,90 @@ static void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host)
|
|||||||
host->bypass_g4_cfgready = of_property_read_bool(np, str);
|
host->bypass_g4_cfgready = of_property_read_bool(np, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ufs_qcom_hook_clock_scaling - Influence the UFS clock scaling policy
|
||||||
|
* @force_out: flag to decide whether to skip scale up/down check in ufshcd_devfreq_target
|
||||||
|
* @force_scaling: Decide whether to do force scaling in ufshcd_devfreq_target
|
||||||
|
* @scale_up: scale up or down request coming from devfreq
|
||||||
|
*
|
||||||
|
* This API Updates force_out, force_scaling and scale_up parameter before returning.
|
||||||
|
* It also updates clk_next_mode and is_turbo_enabled. Based on this, required setting
|
||||||
|
* would be applied as part of clk scaling pre and post
|
||||||
|
* sequence. At end of clk scaling post sequence clk_curr_mode would be updated with
|
||||||
|
* clk_next_mode value.
|
||||||
|
*/
|
||||||
|
static void ufs_qcom_hook_clock_scaling(void *unused, struct ufs_hba *hba, bool *force_out,
|
||||||
|
bool *force_scaling, bool *scale_up)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* TURBO_DOWN_THRESHOLD is the busy% threshold to scale down from TURBO to NOM.
|
||||||
|
*
|
||||||
|
* TODO: Need to adjust threshold taking into account of power and perf tradeoff
|
||||||
|
*/
|
||||||
|
#define TURBO_DOWN_THRESHOLD 50
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
struct devfreq_dev_status *stat = &hba->devfreq->last_status;
|
||||||
|
struct ufs_clk_info *clki;
|
||||||
|
int busy_percentage;
|
||||||
|
|
||||||
|
if (!host->ml_scale_sup)
|
||||||
|
return;
|
||||||
|
|
||||||
|
busy_percentage = (stat->busy_time * 100)/(stat->total_time);
|
||||||
|
clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list);
|
||||||
|
/*
|
||||||
|
* In case of clk scale down, we align with devfreq i.e we
|
||||||
|
* scale down from either TURBO(TURBO_L1) or NOM to LOW_SVS if
|
||||||
|
* scale down is received from devfreq
|
||||||
|
*/
|
||||||
|
if (!(*scale_up)) {
|
||||||
|
host->is_turbo_enabled = false;
|
||||||
|
host->clk_next_mode = LOW_SVS;
|
||||||
|
*force_out = false;
|
||||||
|
*force_scaling = false;
|
||||||
|
host->turbo_down_thres_cnt = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* This is scale_up from LOW_SVS to TURBO */
|
||||||
|
if (clki->curr_freq == clki->min_freq) {
|
||||||
|
*force_out = false;
|
||||||
|
*force_scaling = false;
|
||||||
|
host->clk_curr_mode = LOW_SVS;
|
||||||
|
host->clk_next_mode = TURBO;
|
||||||
|
host->turbo_down_thres_cnt = 0;
|
||||||
|
host->is_turbo_enabled = true;
|
||||||
|
return;
|
||||||
|
} else if (host->is_turbo_enabled) {
|
||||||
|
/* We are currently operating in TURBO freq */
|
||||||
|
if (busy_percentage < TURBO_DOWN_THRESHOLD) {
|
||||||
|
/*
|
||||||
|
* To avoid ping-pong b/w different clk mode ,
|
||||||
|
* have a threshold count to scale down from TURBO
|
||||||
|
* to NOM mode.
|
||||||
|
*/
|
||||||
|
if (++host->turbo_down_thres_cnt == 2) {
|
||||||
|
/* We need to scale down from TURBO or TURBO_L1 to NOM */
|
||||||
|
host->clk_next_mode = NOM;
|
||||||
|
host->is_turbo_enabled = false;
|
||||||
|
*force_out = false;
|
||||||
|
*force_scaling = true;
|
||||||
|
*scale_up = true;
|
||||||
|
host->turbo_down_thres_cnt = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Continue with TURBO clk freq */
|
||||||
|
host->turbo_down_thres_cnt = 0;
|
||||||
|
*force_out = true;
|
||||||
|
*force_scaling = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*force_out = false;
|
||||||
|
*force_scaling = false;
|
||||||
|
host->turbo_down_thres_cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* ufs_qcom_parse_lpm - read from DTS whether LPM modes should be disabled.
|
* ufs_qcom_parse_lpm - read from DTS whether LPM modes should be disabled.
|
||||||
*/
|
*/
|
||||||
@@ -4042,9 +4487,81 @@ static ssize_t crash_on_err_store(struct device *dev,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DEVICE_ATTR_RW(crash_on_err);
|
static DEVICE_ATTR_RW(crash_on_err);
|
||||||
|
|
||||||
|
static ssize_t clk_mode_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
static const char * const mode[] = {
|
||||||
|
"LOW_SVS",
|
||||||
|
"NORM",
|
||||||
|
"TURBO",
|
||||||
|
"TURBO_L1",
|
||||||
|
"INVAL_MODE",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Print current clk mode info */
|
||||||
|
return sysfs_emit(buf,
|
||||||
|
"Clk_mode: %s ,turbo_enabled: %d, axi_freq:%ld,unipro_freq:%ld, ice_freq: %ld\n",
|
||||||
|
mode[host->clk_curr_mode], host->is_turbo_enabled,
|
||||||
|
host->curr_axi_freq,
|
||||||
|
host->curr_unipro_freq,
|
||||||
|
host->curr_ice_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RO(clk_mode);
|
||||||
|
|
||||||
|
static ssize_t turbo_support_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
|
||||||
|
/* Print whether turbo support is enabled or not */
|
||||||
|
return sysfs_emit(buf, "%d\n", host->ml_scale_sup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t turbo_support_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||||
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
|
bool value;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
|
if (kstrtobool(buf, &value))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
down_read(&hba->clk_scaling_lock);
|
||||||
|
if (host->clk_curr_mode == TURBO) {
|
||||||
|
/*
|
||||||
|
* Since curr_mode is turbo, turbo support
|
||||||
|
* can't be enabled/disabled
|
||||||
|
*/
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host->ml_scale_sup == value)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
host->ml_scale_sup = value;
|
||||||
|
if (atomic_read(&host->scale_up))
|
||||||
|
host->clk_curr_mode = NOM;
|
||||||
|
else
|
||||||
|
host->clk_curr_mode = LOW_SVS;
|
||||||
|
out:
|
||||||
|
up_read(&hba->clk_scaling_lock);
|
||||||
|
return ret ? ret : count;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RW(turbo_support);
|
||||||
|
|
||||||
static struct attribute *ufs_qcom_sysfs_attrs[] = {
|
static struct attribute *ufs_qcom_sysfs_attrs[] = {
|
||||||
&dev_attr_err_state.attr,
|
&dev_attr_err_state.attr,
|
||||||
&dev_attr_power_mode.attr,
|
&dev_attr_power_mode.attr,
|
||||||
@@ -4053,6 +4570,8 @@ static struct attribute *ufs_qcom_sysfs_attrs[] = {
|
|||||||
&dev_attr_err_count.attr,
|
&dev_attr_err_count.attr,
|
||||||
&dev_attr_dbg_state.attr,
|
&dev_attr_dbg_state.attr,
|
||||||
&dev_attr_crash_on_err.attr,
|
&dev_attr_crash_on_err.attr,
|
||||||
|
&dev_attr_clk_mode.attr,
|
||||||
|
&dev_attr_turbo_support.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4164,6 +4683,8 @@ static void ufs_qcom_register_hooks(void)
|
|||||||
ufs_qcom_hook_send_tm_command, NULL);
|
ufs_qcom_hook_send_tm_command, NULL);
|
||||||
register_trace_android_vh_ufs_check_int_errors(
|
register_trace_android_vh_ufs_check_int_errors(
|
||||||
ufs_qcom_hook_check_int_errors, NULL);
|
ufs_qcom_hook_check_int_errors, NULL);
|
||||||
|
register_trace_android_vh_ufs_clock_scaling(
|
||||||
|
ufs_qcom_hook_clock_scaling, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ARM_QCOM_CPUFREQ_HW
|
#ifdef CONFIG_ARM_QCOM_CPUFREQ_HW
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
|
/* Copyright (c) 2013-2022, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef UFS_QCOM_H_
|
#ifndef UFS_QCOM_H_
|
||||||
@@ -53,12 +53,21 @@
|
|||||||
#define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B
|
#define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B
|
||||||
#define UFS_QCOM_LIMIT_DESIRED_MODE FAST
|
#define UFS_QCOM_LIMIT_DESIRED_MODE FAST
|
||||||
#define UFS_QCOM_LIMIT_PHY_SUBMODE UFS_QCOM_PHY_SUBMODE_G4
|
#define UFS_QCOM_LIMIT_PHY_SUBMODE UFS_QCOM_PHY_SUBMODE_G4
|
||||||
|
#define UFS_QCOM_DEFAULT_TURBO_FREQ 300000000
|
||||||
|
#define UFS_QCOM_DEFAULT_TURBO_L1_FREQ 300000000
|
||||||
|
#define UFS_NOM_THRES_FREQ 300000000
|
||||||
|
|
||||||
/* default value of auto suspend is 3 seconds */
|
/* default value of auto suspend is 3 seconds */
|
||||||
#define UFS_QCOM_AUTO_SUSPEND_DELAY 3000
|
#define UFS_QCOM_AUTO_SUSPEND_DELAY 3000
|
||||||
#define UFS_QCOM_CLK_GATING_DELAY_MS_PWR_SAVE 10
|
#define UFS_QCOM_CLK_GATING_DELAY_MS_PWR_SAVE 10
|
||||||
#define UFS_QCOM_CLK_GATING_DELAY_MS_PERF 50
|
#define UFS_QCOM_CLK_GATING_DELAY_MS_PERF 50
|
||||||
|
|
||||||
|
/* QCOM ICE registers */
|
||||||
|
#define REG_UFS_ICE_CONTROL 0x00
|
||||||
|
|
||||||
|
/* bit definitions for QCOM_ICE_REG_CONTROL register */
|
||||||
|
#define ICE_CONTROL BIT(1)
|
||||||
|
|
||||||
/* QCOM UFS host controller vendor specific registers */
|
/* QCOM UFS host controller vendor specific registers */
|
||||||
enum {
|
enum {
|
||||||
REG_UFS_SYS1CLK_1US = 0xC0,
|
REG_UFS_SYS1CLK_1US = 0xC0,
|
||||||
@@ -190,6 +199,10 @@ enum ufs_qcom_phy_init_type {
|
|||||||
#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK_V4 0xFFF
|
#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK_V4 0xFFF
|
||||||
#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_OFFSET_V4 0x10
|
#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_OFFSET_V4 0x10
|
||||||
|
|
||||||
|
#define PA_VS_CLK_CFG_REG_MASK_TURBO 0x100
|
||||||
|
#define ATTR_HW_CGC_EN_TURBO 0x100
|
||||||
|
#define ATTR_HW_CGC_EN_NON_TURBO 0x000
|
||||||
|
|
||||||
#define PA_VS_CORE_CLK_40NS_CYCLES 0x9007
|
#define PA_VS_CORE_CLK_40NS_CYCLES 0x9007
|
||||||
#define PA_VS_CORE_CLK_40NS_CYCLES_MASK 0xF
|
#define PA_VS_CORE_CLK_40NS_CYCLES_MASK 0xF
|
||||||
|
|
||||||
@@ -204,6 +217,10 @@ enum ufs_qcom_phy_init_type {
|
|||||||
#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
|
#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
|
||||||
#define DME_VS_CORE_CLK_CTRL_DME_HW_CGC_EN BIT(9)
|
#define DME_VS_CORE_CLK_CTRL_DME_HW_CGC_EN BIT(9)
|
||||||
|
|
||||||
|
#define TEST_BUS_CTRL_2_HCI_SEL_TURBO_MASK 0x010
|
||||||
|
#define TEST_BUS_CTRL_2_HCI_SEL_TURBO 0x010
|
||||||
|
#define TEST_BUS_CTRL_2_HCI_SEL_NONTURBO 0x000
|
||||||
|
|
||||||
/* Device Quirks */
|
/* Device Quirks */
|
||||||
/*
|
/*
|
||||||
* Some ufs devices may need more time to be in hibern8 before exiting.
|
* Some ufs devices may need more time to be in hibern8 before exiting.
|
||||||
@@ -423,8 +440,29 @@ struct ufs_qcom_host {
|
|||||||
void *ufs_ipc_log_ctx;
|
void *ufs_ipc_log_ctx;
|
||||||
bool dbg_en;
|
bool dbg_en;
|
||||||
struct nvmem_cell *nvmem_cell;
|
struct nvmem_cell *nvmem_cell;
|
||||||
/*multi level clock scaling support*/
|
|
||||||
bool ml_scale_up;
|
/* Multi level clk scaling Support */
|
||||||
|
bool ml_scale_sup;
|
||||||
|
bool is_turbo_enabled;
|
||||||
|
/* threshold count to scale down from turbo to NOM */
|
||||||
|
u32 turbo_down_thres_cnt;
|
||||||
|
/* turbo freq for UFS clocks read from DT */
|
||||||
|
u32 axi_turbo_clk_freq;
|
||||||
|
u32 axi_turbo_l1_clk_freq;
|
||||||
|
u32 ice_turbo_clk_freq;
|
||||||
|
u32 ice_turbo_l1_clk_freq;
|
||||||
|
u32 unipro_turbo_clk_freq;
|
||||||
|
u32 unipro_turbo_l1_clk_freq;
|
||||||
|
bool turbo_unipro_attr_applied;
|
||||||
|
/* some target need additional setting to support turbo mode*/
|
||||||
|
bool turbo_additional_conf_req;
|
||||||
|
/* current UFS clocks freq */
|
||||||
|
u32 curr_axi_freq;
|
||||||
|
u32 curr_ice_freq;
|
||||||
|
u32 curr_unipro_freq;
|
||||||
|
/* Indicates curr and next clk mode */
|
||||||
|
u32 clk_next_mode;
|
||||||
|
u32 clk_curr_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u32
|
static inline u32
|
||||||
@@ -489,6 +527,16 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void ufshcd_ice_rmwl(struct ufs_qcom_host *host, u32 mask, u32 val, u32 reg)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
tmp = readl_relaxed((host)->ice_mmio + (reg));
|
||||||
|
tmp &= ~mask;
|
||||||
|
tmp |= (val & mask);
|
||||||
|
writel_relaxed(tmp, (host)->ice_mmio + (reg));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IOCTL opcode for ufs queries has the following opcode after
|
* IOCTL opcode for ufs queries has the following opcode after
|
||||||
* SCSI_IOCTL_GET_PCI
|
* SCSI_IOCTL_GET_PCI
|
||||||
|
|||||||
Reference in New Issue
Block a user