MALI: bifrost: Use new APIs for devfreq

Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Change-Id: Ifd0262cbff997a752f81aa4941763c12bde741cf
This commit is contained in:
Finley Xiao
2023-06-09 09:22:00 +08:00
committed by Tao Huang
parent 389088186f
commit 148a53e168
6 changed files with 82 additions and 263 deletions

View File

@@ -49,7 +49,7 @@ static struct monitor_dev_profile mali_mdevp = {
.type = MONITOR_TYPE_DEV,
.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
.high_temp_adjust = rockchip_monitor_dev_high_temp_adjust,
.update_volt = rockchip_monitor_check_rate_volt,
.check_rate_volt = rockchip_monitor_check_rate_volt,
};
/**
@@ -127,132 +127,15 @@ void kbase_devfreq_opp_translate(struct kbase_device *kbdev, unsigned long freq,
}
}
int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data)
{
struct device *dev = data->dev;
struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
struct regulator *vdd_reg = data->regulators[0];
struct dev_pm_opp_supply *old_supply_mem;
struct dev_pm_opp_supply *new_supply_mem;
struct regulator *mem_reg;
struct clk *clk = data->clk;
struct kbase_device *kbdev = dev_get_drvdata(dev);
struct rockchip_opp_info *opp_info = &kbdev->opp_info;
unsigned long old_freq = data->old_opp.rate;
unsigned long new_freq = data->new_opp.rate;
unsigned int reg_count = data->regulator_count;
bool is_set_rm = true;
bool is_set_clk = true;
u32 target_rm = UINT_MAX;
int ret = 0;
if (reg_count > 1) {
old_supply_mem = &data->old_opp.supplies[1];
new_supply_mem = &data->new_opp.supplies[1];
mem_reg = data->regulators[1];
}
if (!pm_runtime_active(dev)) {
is_set_rm = false;
if (opp_info->scmi_clk)
is_set_clk = false;
}
ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks);
if (ret) {
dev_err(dev, "failed to enable opp clks\n");
return ret;
}
rockchip_get_read_margin(dev, opp_info, new_supply_vdd->u_volt,
&target_rm);
/* Change frequency */
dev_dbg(dev, "switching OPP: %lu Hz --> %lu Hz\n", old_freq, new_freq);
/* Scaling up? Scale voltage before frequency */
if (new_freq >= old_freq) {
rockchip_set_intermediate_rate(dev, opp_info, clk, old_freq,
new_freq, true, is_set_clk);
if (reg_count > 1) {
ret = regulator_set_voltage(mem_reg,
new_supply_mem->u_volt,
INT_MAX);
if (ret) {
dev_err(dev, "failed to set volt %lu uV for mem reg\n",
new_supply_mem->u_volt);
goto restore_voltage;
}
}
ret = regulator_set_voltage(vdd_reg, new_supply_vdd->u_volt,
INT_MAX);
if (ret) {
dev_err(dev, "failed to set volt %lu uV for vdd reg\n",
new_supply_vdd->u_volt);
goto restore_voltage;
}
rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm);
if (is_set_clk && clk_set_rate(clk, new_freq)) {
ret = -EINVAL;
dev_err(dev, "failed to set clk rate\n");
goto restore_rm;
}
/* Scaling down? Scale voltage after frequency */
} else {
rockchip_set_intermediate_rate(dev, opp_info, clk, old_freq,
new_freq, false, is_set_clk);
rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm);
if (is_set_clk && clk_set_rate(clk, new_freq)) {
ret = -EINVAL;
dev_err(dev, "failed to set clk rate\n");
goto restore_rm;
}
ret = regulator_set_voltage(vdd_reg, new_supply_vdd->u_volt,
INT_MAX);
if (ret) {
dev_err(dev, "failed to set volt %lu uV for vdd reg\n",
new_supply_vdd->u_volt);
goto restore_freq;
}
if (reg_count > 1) {
ret = regulator_set_voltage(mem_reg,
new_supply_mem->u_volt,
INT_MAX);
if (ret) {
dev_err(dev, "failed to set volt %lu uV for mem reg\n",
new_supply_mem->u_volt);
goto restore_voltage;
}
}
}
clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
return 0;
restore_freq:
if (is_set_clk && clk_set_rate(clk, old_freq))
dev_err(dev, "failed to restore old-freq %lu Hz\n", old_freq);
restore_rm:
rockchip_get_read_margin(dev, opp_info, old_supply_vdd->u_volt,
&target_rm);
rockchip_set_read_margin(dev, opp_info, opp_info->target_rm, is_set_rm);
restore_voltage:
if (reg_count > 1 && old_supply_mem->u_volt)
regulator_set_voltage(mem_reg, old_supply_mem->u_volt, INT_MAX);
regulator_set_voltage(vdd_reg, old_supply_vdd->u_volt, INT_MAX);
clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
return ret;
}
static int
kbase_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
struct rockchip_opp_info *opp_info = &kbdev->opp_info;
struct dev_pm_opp *opp;
int ret = 0;
if (!mali_mdevp.is_checked)
if (!opp_info->is_rate_volt_checked)
return -EINVAL;
opp = devfreq_recommended_opp(dev, freq, flags);
@@ -262,13 +145,18 @@ kbase_devfreq_target(struct device *dev, unsigned long *freq, u32 flags)
if (*freq == kbdev->current_nominal_freq)
return 0;
rockchip_monitor_volt_adjust_lock(kbdev->mdev_info);
rockchip_opp_dvfs_lock(opp_info);
if (pm_runtime_active(dev))
opp_info->is_runtime_active = true;
else
opp_info->is_runtime_active = false;
ret = dev_pm_opp_set_rate(dev, *freq);
if (!ret) {
kbdev->current_nominal_freq = *freq;
KBASE_TLSTREAM_AUX_DEVFREQ_TARGET(kbdev, (u64)*freq);
}
rockchip_monitor_volt_adjust_unlock(kbdev->mdev_info);
rockchip_opp_dvfs_unlock(opp_info);
return ret;
}
@@ -671,23 +559,13 @@ static void kbase_devfreq_work_term(struct kbase_device *kbdev)
destroy_workqueue(workq);
}
static unsigned long kbase_devfreq_get_static_power(struct devfreq *devfreq,
unsigned long voltage)
{
struct device *dev = devfreq->dev.parent;
struct kbase_device *kbdev = dev_get_drvdata(dev);
return rockchip_ipa_get_static_power(kbdev->model_data, voltage);
}
int kbase_devfreq_init(struct kbase_device *kbdev)
{
struct devfreq_cooling_power *kbase_dcp = &kbdev->dfc_power;
struct device_node *np = kbdev->dev->of_node;
struct device_node *model_node;
struct devfreq_dev_profile *dp;
int err;
struct dev_pm_opp *opp;
unsigned int dyn_power_coeff = 0;
unsigned int i;
bool free_devfreq_freq_table = true;
@@ -703,8 +581,6 @@ int kbase_devfreq_init(struct kbase_device *kbdev)
else
kbdev->current_freqs[i] = 0;
}
if (strstr(__clk_get_name(kbdev->clocks[0]), "scmi"))
kbdev->opp_info.scmi_clk = kbdev->clocks[0];
kbdev->current_nominal_freq = kbdev->current_freqs[0];
opp = devfreq_recommended_opp(kbdev->dev, &kbdev->current_nominal_freq, 0);
@@ -729,6 +605,12 @@ int kbase_devfreq_init(struct kbase_device *kbdev)
kbdev->gpu_props.props.core_props.gpu_freq_khz_max =
dp->freq_table[0] / 1000;
};
#if IS_ENABLED(CONFIG_DEVFREQ_THERMAL)
of_property_read_u32(kbdev->dev->of_node, "dynamic-power-coefficient",
&dyn_power_coeff);
if (dyn_power_coeff)
dp->is_cooling_device = true;
#endif
err = kbase_devfreq_init_core_mask_table(kbdev);
if (err)
goto init_core_mask_table_failed;
@@ -770,59 +652,21 @@ int kbase_devfreq_init(struct kbase_device *kbdev)
mali_mdevp.data = kbdev->devfreq;
mali_mdevp.opp_info = &kbdev->opp_info;
kbdev->mdev_info = rockchip_system_monitor_register(kbdev->dev,
&mali_mdevp);
kbdev->mdev_info = rockchip_system_monitor_register(kbdev->dev, &mali_mdevp);
if (IS_ERR(kbdev->mdev_info)) {
dev_dbg(kbdev->dev, "without system monitor\n");
kbdev->mdev_info = NULL;
mali_mdevp.is_checked = true;
}
kbdev->opp_info.is_rate_volt_checked = true;
#if IS_ENABLED(CONFIG_DEVFREQ_THERMAL)
of_property_read_u32(kbdev->dev->of_node, "dynamic-power-coefficient",
(u32 *)&kbase_dcp->dyn_power_coeff);
model_node = of_get_compatible_child(kbdev->dev->of_node,
"simple-power-model");
if (model_node) {
of_node_put(model_node);
kbdev->model_data =
rockchip_ipa_power_model_init(kbdev->dev,
"gpu_leakage");
if (IS_ERR_OR_NULL(kbdev->model_data)) {
kbdev->model_data = NULL;
if (kbase_dcp->dyn_power_coeff)
dev_info(kbdev->dev,
"only calculate dynamic power\n");
else
dev_err(kbdev->dev,
"failed to initialize power model\n");
} else {
kbase_dcp->get_static_power =
kbase_devfreq_get_static_power;
if (kbdev->model_data->dynamic_coefficient)
kbase_dcp->dyn_power_coeff =
kbdev->model_data->dynamic_coefficient;
}
}
if (kbase_dcp->dyn_power_coeff) {
kbdev->devfreq_cooling =
of_devfreq_cooling_register_power(kbdev->dev->of_node,
kbdev->devfreq,
kbase_dcp);
if (IS_ERR(kbdev->devfreq_cooling)) {
err = PTR_ERR(kbdev->devfreq_cooling);
dev_err(kbdev->dev, "failed to register cooling device\n");
goto ipa_init_failed;
}
} else {
if (!dp->is_cooling_device) {
err = kbase_ipa_init(kbdev);
if (err) {
dev_err(kbdev->dev, "IPA initialization failed\n");
goto ipa_init_failed;
}
kbdev->devfreq_cooling = of_devfreq_cooling_register_power(
kbdev->dev->of_node,
kbdev->devfreq_cooling = devfreq_cooling_em_register(
kbdev->devfreq,
&kbase_ipa_power_model_ops);
if (IS_ERR(kbdev->devfreq_cooling)) {

View File

@@ -25,7 +25,6 @@
int kbase_devfreq_init(struct kbase_device *kbdev);
void kbase_devfreq_term(struct kbase_device *kbdev);
int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data);
/**
* kbase_devfreq_force_freq - Set GPU frequency on L2 power on/off.

View File

@@ -168,13 +168,6 @@ static const struct mali_kbase_capability_def kbase_caps_table[MALI_KBASE_NUM_CA
static struct mutex kbase_probe_mutex;
#endif
#ifndef CONFIG_MALI_BIFROST_DEVFREQ
static inline int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data)
{
return -EOPNOTSUPP;
}
#endif
/**
* mali_kbase_supports_cap - Query whether a kbase capability is supported
*
@@ -4597,39 +4590,6 @@ int power_control_init(struct kbase_device *kbdev)
* from completing its initialization.
*/
#if defined(CONFIG_PM_OPP)
#if defined(CONFIG_REGULATOR)
#if (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE)
if (kbdev->nr_regulators > 0) {
kbdev->token = dev_pm_opp_set_regulators(kbdev->dev, regulator_names);
if (kbdev->token < 0) {
err = kbdev->token;
goto regulators_probe_defer;
}
}
#elif (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE)
if (kbdev->nr_regulators > 0) {
kbdev->opp_table =
dev_pm_opp_set_regulators(kbdev->dev, regulator_names,
kbdev->nr_regulators);
if (IS_ERR(kbdev->opp_table)) {
dev_err(kbdev->dev, "Failed to set regulators\n");
return 0;
}
kbdev->opp_table =
dev_pm_opp_register_set_opp_helper(kbdev->dev,
kbase_devfreq_opp_helper);
if (IS_ERR(kbdev->opp_table)) {
dev_pm_opp_put_regulators(kbdev->opp_table);
kbdev->opp_table = NULL;
dev_err(kbdev->dev, "Failed to set opp helper\n");
return 0;
}
}
#endif /* (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) */
#endif /* CONFIG_REGULATOR */
#ifdef CONFIG_ARCH_ROCKCHIP
err = kbase_platform_rk_init_opp_table(kbdev);
if (err)
@@ -4668,18 +4628,11 @@ void power_control_term(struct kbase_device *kbdev)
unsigned int i;
#if defined(CONFIG_PM_OPP)
#ifdef CONFIG_ARCH_ROCKCHIP
kbase_platform_rk_uninit_opp_table(kbdev);
#else
dev_pm_opp_of_remove_table(kbdev->dev);
#if defined(CONFIG_REGULATOR)
#if (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE)
if (kbdev->token > -EPERM) {
dev_pm_opp_unregister_set_opp_helper(kbdev->opp_table);
dev_pm_opp_put_regulators(kbdev->token);
}
#elif (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE)
if (!IS_ERR_OR_NULL(kbdev->opp_table))
dev_pm_opp_put_regulators(kbdev->opp_table);
#endif /* (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) */
#endif /* CONFIG_REGULATOR */
#endif
#endif /* CONFIG_PM_OPP */
for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
@@ -4991,8 +4944,7 @@ static struct dentry *init_debugfs(struct kbase_device *kbdev)
#ifdef CONFIG_MALI_BIFROST_DEVFREQ
#if IS_ENABLED(CONFIG_DEVFREQ_THERMAL)
if (kbdev->devfreq && !kbdev->model_data &&
!kbdev->dfc_power.dyn_power_coeff)
if (kbdev->devfreq && kbdev->devfreq_cooling)
kbase_ipa_debugfs_init(kbdev);
#endif /* CONFIG_DEVFREQ_THERMAL */
#endif /* CONFIG_MALI_BIFROST_DEVFREQ */
@@ -5543,10 +5495,6 @@ static int kbase_platform_device_probe(struct platform_device *pdev)
kbdev->dev = &pdev->dev;
#if (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE)
kbdev->token = -EPERM;
#endif /* (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) */
dev_set_drvdata(kbdev->dev, kbdev);
#if (KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE)
mutex_lock(&kbase_probe_mutex);

View File

@@ -1072,11 +1072,6 @@ struct kbase_device {
#if IS_ENABLED(CONFIG_REGULATOR)
struct regulator *regulators[BASE_MAX_NR_CLOCKS_REGULATORS];
unsigned int nr_regulators;
#if (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE)
int token;
#elif (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE)
struct opp_table *opp_table;
#endif /* (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) */
#endif /* CONFIG_REGULATOR */
char devname[DEVNAME_SIZE];
u32 id;

View File

@@ -90,4 +90,5 @@ extern struct kbase_platform_funcs_conf platform_funcs;
extern struct kbase_clk_rate_trace_op_conf clk_rate_trace_ops;
int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev);
void kbase_platform_rk_uninit_opp_table(struct kbase_device *kbdev);
int kbase_platform_rk_enable_regulator(struct kbase_device *kbdev);

View File

@@ -94,6 +94,7 @@ static void rk_pm_power_off_delay_work(struct work_struct *work)
struct rk_context *platform =
container_of(to_delayed_work(work), struct rk_context, work);
struct kbase_device *kbdev = platform->kbdev;
struct rockchip_opp_info *opp_info = &kbdev->opp_info;
mutex_lock(&platform->lock);
@@ -103,12 +104,12 @@ static void rk_pm_power_off_delay_work(struct work_struct *work)
return;
}
rockchip_monitor_volt_adjust_lock(kbdev->mdev_info);
rockchip_opp_dvfs_lock(opp_info);
if (pm_runtime_enabled(kbdev->dev)) {
D("to put_sync_suspend mali_dev.");
pm_runtime_put_sync_suspend(kbdev->dev);
}
rockchip_monitor_volt_adjust_unlock(kbdev->mdev_info);
rockchip_opp_dvfs_unlock(opp_info);
rk_pm_disable_clk(kbdev);
@@ -208,7 +209,7 @@ static int rk_pm_callback_runtime_on(struct kbase_device *kbdev)
if (!kbdev->current_nominal_freq)
return 0;
ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks);
ret = clk_bulk_prepare_enable(opp_info->nclocks, opp_info->clocks);
if (ret) {
dev_err(kbdev->dev, "failed to enable opp clks\n");
return ret;
@@ -216,12 +217,11 @@ static int rk_pm_callback_runtime_on(struct kbase_device *kbdev)
if (opp_info->data && opp_info->data->set_read_margin)
opp_info->data->set_read_margin(kbdev->dev, opp_info,
opp_info->target_rm);
if (opp_info->scmi_clk) {
if (clk_set_rate(opp_info->scmi_clk,
kbdev->current_nominal_freq))
if (opp_info->is_scmi_clk) {
if (clk_set_rate(opp_info->clk, kbdev->current_nominal_freq))
dev_err(kbdev->dev, "failed to restore clk rate\n");
}
clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
clk_bulk_disable_unprepare(opp_info->nclocks, opp_info->clocks);
return 0;
}
@@ -230,8 +230,8 @@ static void rk_pm_callback_runtime_off(struct kbase_device *kbdev)
{
struct rockchip_opp_info *opp_info = &kbdev->opp_info;
if (opp_info->scmi_clk) {
if (clk_set_rate(opp_info->scmi_clk, POWER_DOWN_FREQ))
if (opp_info->is_scmi_clk) {
if (clk_set_rate(opp_info->clk, POWER_DOWN_FREQ))
dev_err(kbdev->dev, "failed to set power down rate\n");
}
opp_info->current_rm = UINT_MAX;
@@ -242,6 +242,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev)
int ret = 1; /* Assume GPU has been powered off */
int err = 0;
struct rk_context *platform = get_rk_context(kbdev);
struct rockchip_opp_info *opp_info = &kbdev->opp_info;
cancel_delayed_work_sync(&platform->work);
@@ -271,7 +272,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev)
goto out;
}
rockchip_monitor_volt_adjust_lock(kbdev->mdev_info);
rockchip_opp_dvfs_lock(opp_info);
/* 若 mali_dev 的 runtime_pm 是 enabled 的, 则... */
if (pm_runtime_enabled(kbdev->dev)) {
D("to resume mali_dev syncly.");
@@ -280,6 +281,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev)
*/
err = pm_runtime_get_sync(kbdev->dev);
if (err < 0) {
rockchip_opp_dvfs_unlock(opp_info);
E("failed to runtime resume device: %d.", err);
ret = err;
goto out;
@@ -288,7 +290,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev)
ret = 0;
}
}
rockchip_monitor_volt_adjust_unlock(kbdev->mdev_info);
rockchip_opp_dvfs_unlock(opp_info);
platform->is_powered = true;
wake_lock(&platform->wake_lock);
@@ -547,12 +549,11 @@ static int rk3588_gpu_get_soc_info(struct device *dev, struct device_node *np,
}
static int rk3588_gpu_set_soc_info(struct device *dev, struct device_node *np,
int bin, int process, int volt_sel)
struct rockchip_opp_info *opp_info)
{
struct opp_table *opp_table;
u32 supported_hw[2];
int bin = opp_info->bin;
if (volt_sel < 0)
if (opp_info->volt_sel < 0)
return 0;
if (bin < 0)
bin = 0;
@@ -561,14 +562,9 @@ static int rk3588_gpu_set_soc_info(struct device *dev, struct device_node *np,
return 0;
/* SoC Version */
supported_hw[0] = BIT(bin);
opp_info->supported_hw[0] = BIT(bin);
/* Speed Grade */
supported_hw[1] = BIT(volt_sel);
opp_table = dev_pm_opp_set_supported_hw(dev, supported_hw, 2);
if (IS_ERR(opp_table)) {
dev_err(dev, "failed to set supported opp\n");
return PTR_ERR(opp_table);
}
opp_info->supported_hw[1] = BIT(opp_info->volt_sel);
return 0;
}
@@ -608,10 +604,38 @@ static int rk3588_gpu_set_read_margin(struct device *dev,
return 0;
}
static int gpu_opp_config_regulators(struct device *dev,
struct dev_pm_opp *old_opp,
struct dev_pm_opp *new_opp,
struct regulator **regulators,
unsigned int count)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
return rockchip_opp_config_regulators(dev, old_opp, new_opp, regulators,
count, &kbdev->opp_info);
}
static int gpu_opp_config_clks(struct device *dev, struct opp_table *opp_table,
struct dev_pm_opp *opp, void *data,
bool scaling_down)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
return rockchip_opp_config_clks(dev, opp_table, opp, data, scaling_down,
&kbdev->opp_info);
}
static const struct rockchip_opp_data rk3588_gpu_opp_data = {
.get_soc_info = rk3588_gpu_get_soc_info,
.set_soc_info = rk3588_gpu_set_soc_info,
.set_read_margin = rk3588_gpu_set_read_margin,
.config_regulators = gpu_opp_config_regulators,
.config_clks = gpu_opp_config_clks,
};
static const struct rockchip_opp_data rockchip_gpu_opp_data = {
.config_clks = gpu_opp_config_clks,
};
static const struct of_device_id rockchip_mali_of_match[] = {
@@ -624,10 +648,18 @@ static const struct of_device_id rockchip_mali_of_match[] = {
int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev)
{
struct rockchip_opp_info *info = &kbdev->opp_info;
info->data = &rockchip_gpu_opp_data;
rockchip_get_opp_data(rockchip_mali_of_match, &kbdev->opp_info);
return rockchip_init_opp_table(kbdev->dev, &kbdev->opp_info,
"gpu_leakage", "mali");
"clk_mali", "mali");
}
void kbase_platform_rk_uninit_opp_table(struct kbase_device *kbdev)
{
rockchip_uninit_opp_table(kbdev->dev, &kbdev->opp_info);
}
int kbase_platform_rk_enable_regulator(struct kbase_device *kbdev)