From 5b7d19ca436cad5a2d6589c5f857cd6f2984c17c Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Thu, 30 Dec 2021 15:55:43 +0800 Subject: [PATCH] MALI: bifrost: Avoid crash when set rate and read margin 1. change clock rate and read margin only when pd is on. 2. change clock source to normal pll before power down pd. 3. change clock source back to pvtpll and restore clock rate and read margin after power on pd. Signed-off-by: Finley Xiao Change-Id: I2028866fdd70909814aaba7ef6d3af3bf764eb87 --- .../bifrost/backend/gpu/mali_kbase_devfreq.c | 48 ++++++++++++++----- drivers/gpu/arm/bifrost/mali_kbase_defs.h | 2 + .../platform/rk/mali_kbase_config_rk.c | 34 +++++++++++++ 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c index 71bb05c0415d..a105a9f8c40a 100644 --- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c +++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c @@ -28,6 +28,7 @@ #include #include +#include #include #if IS_ENABLED(CONFIG_DEVFREQ_THERMAL) #include @@ -35,6 +36,7 @@ #include #include +#include #include "mali_kbase_devfreq.h" #include @@ -125,6 +127,20 @@ void kbase_devfreq_opp_translate(struct kbase_device *kbdev, unsigned long freq, } } +static int kbase_devfreq_set_read_margin(struct device *dev, + struct rockchip_opp_info *opp_info, + unsigned long volt, + bool is_set_rm) +{ + if (opp_info->data && opp_info->data->set_read_margin) { + if (is_set_rm) + opp_info->data->set_read_margin(dev, opp_info, volt); + opp_info->volt_rm = volt; + } + + return 0; +} + int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data) { struct device *dev = data->dev; @@ -139,8 +155,16 @@ int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data) 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; + bool is_set_rm = true; + bool is_set_clk = true; int ret = 0; + if (!pm_runtime_active(dev)) { + is_set_rm = false; + if (kbdev->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"); @@ -163,24 +187,23 @@ int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data) new_supply_vdd->u_volt); goto restore_voltage; } - if (opp_info->data->set_read_margin) - opp_info->data->set_read_margin(dev, opp_info, - new_supply_vdd->u_volt); + kbase_devfreq_set_read_margin(dev, opp_info, + new_supply_vdd->u_volt, + is_set_rm); } /* Change frequency */ dev_dbg(dev, "switching OPP: %lu Hz --> %lu Hz\n", old_freq, new_freq); - ret = clk_set_rate(clk, new_freq); - if (ret) { + if (is_set_clk && clk_set_rate(clk, new_freq)) { dev_err(dev, "failed to set clk rate: %d\n", ret); goto restore_rm; } /* Scaling down? Scale voltage after frequency */ if (new_freq < old_freq) { - if (opp_info->data->set_read_margin) - opp_info->data->set_read_margin(dev, opp_info, - new_supply_vdd->u_volt); + kbase_devfreq_set_read_margin(dev, opp_info, + new_supply_vdd->u_volt, + is_set_rm); ret = regulator_set_voltage(vdd_reg, new_supply_vdd->u_volt, INT_MAX); if (ret) { @@ -202,12 +225,11 @@ int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data) return 0; restore_freq: - if (clk_set_rate(clk, old_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: - if (opp_info->data->set_read_margin) - opp_info->data->set_read_margin(dev, opp_info, - old_supply_vdd->u_volt); + kbase_devfreq_set_read_margin(dev, opp_info, old_supply_vdd->u_volt, + is_set_rm); restore_voltage: regulator_set_voltage(mem_reg, old_supply_mem->u_volt, INT_MAX); regulator_set_voltage(vdd_reg, old_supply_vdd->u_volt, INT_MAX); @@ -673,6 +695,8 @@ int kbase_devfreq_init(struct kbase_device *kbdev) else kbdev->current_freqs[i] = 0; } + if (strstr(__clk_get_name(kbdev->clocks[0]), "scmi")) + kbdev->scmi_clk = kbdev->clocks[0]; kbdev->current_nominal_freq = kbdev->current_freqs[0]; opp = devfreq_recommended_opp(kbdev->dev, &kbdev->current_nominal_freq, 0); diff --git a/drivers/gpu/arm/bifrost/mali_kbase_defs.h b/drivers/gpu/arm/bifrost/mali_kbase_defs.h index 53572123a4ab..46a0c0571ea9 100755 --- a/drivers/gpu/arm/bifrost/mali_kbase_defs.h +++ b/drivers/gpu/arm/bifrost/mali_kbase_defs.h @@ -670,6 +670,7 @@ struct kbase_process { * @irqs.flags: irq flags * @clocks: Pointer to the input clock resources referenced by * the GPU device node. + * @scmi_clk: Pointer to the input scmi clock resources * @nr_clocks: Number of clocks set in the clocks array. * @regulators: Pointer to the structs corresponding to the * regulators referenced by the GPU device node. @@ -971,6 +972,7 @@ struct kbase_device { } irqs[3]; struct clk *clocks[BASE_MAX_NR_CLOCKS_REGULATORS]; + struct clk *scmi_clk; unsigned int nr_clocks; #if IS_ENABLED(CONFIG_REGULATOR) struct regulator *regulators[BASE_MAX_NR_CLOCKS_REGULATORS]; diff --git a/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c b/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c index 6ec00ebc6d83..f1d07439006b 100755 --- a/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c +++ b/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c @@ -32,9 +32,12 @@ #include #include #include +#include #include "mali_kbase_rk.h" +#define POWER_DOWN_FREQ 200000000 + /** * @file mali_kbase_config_rk.c * 对 platform_config_of_rk 的具体实现. @@ -92,10 +95,12 @@ static void rk_pm_power_off_delay_work(struct work_struct *work) return; } + rockchip_monitor_volt_adjust_lock(kbdev->mdev_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); rk_pm_disable_clk(kbdev); @@ -186,11 +191,38 @@ struct kbase_platform_funcs_conf platform_funcs = { static int rk_pm_callback_runtime_on(struct kbase_device *kbdev) { + struct rockchip_opp_info *opp_info = &kbdev->opp_info; + int ret = 0; + + if (!kbdev->current_nominal_freq) + return 0; + + ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks); + if (ret) { + dev_err(kbdev->dev, "failed to enable opp clks\n"); + return ret; + } + if (kbdev->scmi_clk) { + if (clk_set_rate(kbdev->scmi_clk, kbdev->current_nominal_freq)) + dev_err(kbdev->dev, "failed to restore clk rate\n"); + } + if (opp_info->data && opp_info->data->set_read_margin) + opp_info->data->set_read_margin(kbdev->dev, opp_info, + opp_info->volt_rm); + clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks); + return 0; } static void rk_pm_callback_runtime_off(struct kbase_device *kbdev) { + struct rockchip_opp_info *opp_info = &kbdev->opp_info; + + if (kbdev->scmi_clk) { + if (clk_set_rate(kbdev->scmi_clk, POWER_DOWN_FREQ)) + dev_err(kbdev->dev, "failed to set power down rate\n"); + } + opp_info->current_rm = UINT_MAX; } static int rk_pm_callback_power_on(struct kbase_device *kbdev) @@ -224,6 +256,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev) goto out; } + rockchip_monitor_volt_adjust_lock(kbdev->mdev_info); /* 若 mali_dev 的 runtime_pm 是 enabled 的, 则... */ if (pm_runtime_enabled(kbdev->dev)) { D("to resume mali_dev syncly."); @@ -240,6 +273,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev) ret = 0; } } + rockchip_monitor_volt_adjust_unlock(kbdev->mdev_info); platform->is_powered = true; wake_lock(&platform->wake_lock);