From 8d2a02b24d66aa359e83eebc1ed3c0f85367a1cb Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 16 May 2024 03:11:33 +0000 Subject: [PATCH] AX88772C_eeprom and ax8872c build together --- kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c | 443 ++++++++++++++++++++++++++++++------------------------ 1 files changed, 245 insertions(+), 198 deletions(-) diff --git a/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c b/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c index d647609..02fb00d 100644 --- a/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c +++ b/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2022 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -23,10 +23,12 @@ #include <mali_kbase.h> #include <tl/mali_kbase_tracepoints.h> +#include <backend/gpu/mali_kbase_devfreq.h> #include <backend/gpu/mali_kbase_pm_internal.h> #include <linux/of.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/devfreq.h> #if IS_ENABLED(CONFIG_DEVFREQ_THERMAL) #include <linux/devfreq_cooling.h> @@ -34,6 +36,8 @@ #include <linux/version.h> #include <linux/pm_opp.h> +#include <linux/pm_runtime.h> +#include "mali_kbase_devfreq.h" #include <soc/rockchip/rockchip_ipa.h> #include <soc/rockchip/rockchip_opp_select.h> @@ -42,14 +46,53 @@ static struct devfreq_simple_ondemand_data ondemand_data; static struct monitor_dev_profile mali_mdevp = { - .type = MONITOR_TPYE_DEV, + .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, }; +/** + * get_voltage() - Get the voltage value corresponding to the nominal frequency + * used by devfreq. + * @kbdev: Device pointer + * @freq: Nominal frequency in Hz passed by devfreq. + * + * This function will be called only when the opp table which is compatible with + * "operating-points-v2-mali", is not present in the devicetree for GPU device. + * + * Return: Voltage value in micro volts, 0 in case of error. + */ +static unsigned long get_voltage(struct kbase_device *kbdev, unsigned long freq) +{ + struct dev_pm_opp *opp; + unsigned long voltage = 0; + +#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE + rcu_read_lock(); +#endif + + opp = dev_pm_opp_find_freq_exact(kbdev->dev, freq, true); + + if (IS_ERR_OR_NULL(opp)) + dev_err(kbdev->dev, "Failed to get opp (%d)\n", PTR_ERR_OR_ZERO(opp)); + else { + voltage = dev_pm_opp_get_voltage(opp); +#if KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE + dev_pm_opp_put(opp); +#endif + } + +#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE + rcu_read_unlock(); +#endif + + /* Return the voltage in micro volts */ + return voltage; +} + void kbase_devfreq_opp_translate(struct kbase_device *kbdev, unsigned long freq, - unsigned long volt, u64 *core_mask, - unsigned long *freqs, unsigned long *volts) + u64 *core_mask, unsigned long *freqs, unsigned long *volts) { unsigned int i; @@ -73,167 +116,161 @@ * and nominal frequency and the corresponding voltage. */ if (i == kbdev->num_opps) { + unsigned long voltage = get_voltage(kbdev, freq); + *core_mask = kbdev->gpu_props.props.raw_props.shader_present; for (i = 0; i < kbdev->nr_clocks; i++) { freqs[i] = freq; - volts[i] = volt; + volts[i] = voltage; } } } +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 *target_freq, u32 flags) +kbase_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { struct kbase_device *kbdev = dev_get_drvdata(dev); struct dev_pm_opp *opp; - unsigned long nominal_freq, nominal_volt; - unsigned long freqs[BASE_MAX_NR_CLOCKS_REGULATORS] = {0}; - unsigned long old_freqs[BASE_MAX_NR_CLOCKS_REGULATORS] = {0}; - unsigned long volts[BASE_MAX_NR_CLOCKS_REGULATORS] = {0}; - unsigned int i; - u64 core_mask = 0; + int ret = 0; - nominal_freq = *target_freq; + if (!mali_mdevp.is_checked) + return -EINVAL; -#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE - rcu_read_lock(); -#endif - opp = devfreq_recommended_opp(dev, &nominal_freq, flags); - if (IS_ERR_OR_NULL(opp)) { -#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE - rcu_read_unlock(); -#endif - dev_err(dev, "Failed to get opp (%ld)\n", PTR_ERR(opp)); + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) return PTR_ERR(opp); - } - nominal_volt = dev_pm_opp_get_voltage(opp); -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - rcu_read_unlock(); -#endif -#if KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE dev_pm_opp_put(opp); -#endif - kbase_devfreq_opp_translate(kbdev, - nominal_freq, - nominal_volt, - &core_mask, - freqs, - volts); - - /* - * Only update if there is a change of frequency - */ - if (kbdev->current_nominal_freq == nominal_freq) { - unsigned int i; - int err; - - *target_freq = nominal_freq; - -#ifdef CONFIG_REGULATOR - for (i = 0; i < kbdev->nr_regulators; i++) { - if (kbdev->current_voltages[i] == volts[i]) - continue; - - err = regulator_set_voltage(kbdev->regulators[i], - volts[i], - INT_MAX); - if (err) { - dev_err(dev, "Failed to set voltage (%d)\n", err); - return err; - } - kbdev->current_voltages[i] = volts[i]; - } -#endif + if (*freq == kbdev->current_nominal_freq) return 0; + rockchip_monitor_volt_adjust_lock(kbdev->mdev_info); + 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); - dev_dbg(dev, "%lu-->%lu\n", kbdev->current_nominal_freq, nominal_freq); - -#if IS_ENABLED(CONFIG_REGULATOR) - /* Regulators and clocks work in pairs: every clock has a regulator, - * and we never expect to have more regulators than clocks. - * - * We always need to increase the voltage before increasing - * the frequency of a regulator/clock pair, otherwise the clock - * wouldn't have enough power to perform the transition. - * - * It's always safer to decrease the frequency before decreasing - * voltage of a regulator/clock pair, otherwise the clock could have - * problems operating if it is deprived of the necessary power - * to sustain its current frequency (even if that happens for a short - * transition interval). - */ - - for (i = 0; i < kbdev->nr_clocks; i++) - old_freqs[i] = kbdev->current_freqs[i]; - - for (i = 0; i < kbdev->nr_clocks; i++) { - if (kbdev->regulators[i] && - kbdev->current_voltages[i] != volts[i] && - old_freqs[i] < freqs[i]) { - int err; - - err = regulator_set_voltage(kbdev->regulators[i], - volts[i], INT_MAX); - if (!err) { - kbdev->current_voltages[i] = volts[i]; - } else { - dev_err(dev, "Failed to increase voltage (%d) (target %lu)\n", - err, volts[i]); - return err; - } - } - } -#endif - - for (i = 0; i < kbdev->nr_clocks; i++) { - if (kbdev->clocks[i]) { - int err; - - err = clk_set_rate(kbdev->clocks[i], freqs[i]); - if (!err) { - kbdev->current_freqs[i] = freqs[i]; - } else { - dev_err(dev, "Failed to set clock %lu (target %lu)\n", - freqs[i], *target_freq); - return err; - } - } - } - -#if IS_ENABLED(CONFIG_REGULATOR) - for (i = 0; i < kbdev->nr_clocks; i++) { - if (kbdev->regulators[i] && - kbdev->current_voltages[i] != volts[i] && - old_freqs[i] > freqs[i]) { - int err; - - err = regulator_set_voltage(kbdev->regulators[i], - volts[i], INT_MAX); - if (!err) { - kbdev->current_voltages[i] = volts[i]; - } else { - dev_err(dev, "Failed to decrease voltage (%d) (target %lu)\n", - err, volts[i]); - return err; - } - } - } -#endif - - kbase_devfreq_set_core_mask(kbdev, core_mask); - - *target_freq = nominal_freq; - kbdev->current_nominal_freq = nominal_freq; - kbdev->current_core_mask = core_mask; - if (kbdev->devfreq) - kbdev->devfreq->last_status.current_frequency = nominal_freq; - - KBASE_TLSTREAM_AUX_DEVFREQ_TARGET(kbdev, (u64)nominal_freq); - - return 0; + return ret; } void kbase_devfreq_force_freq(struct kbase_device *kbdev, unsigned long freq) @@ -267,7 +304,8 @@ stat->private_data = NULL; #if MALI_USE_CSF && defined CONFIG_DEVFREQ_THERMAL - kbase_ipa_reset_data(kbdev); + if (!kbdev->dfc_power.dyn_power_coeff) + kbase_ipa_reset_data(kbdev); #endif return 0; @@ -318,6 +356,7 @@ count, i); dp->max_state = i; + /* Have the lowest clock as suspend clock. * It may be overridden by 'opp-mali-errata-1485982'. @@ -642,19 +681,16 @@ return rockchip_ipa_get_static_power(kbdev->model_data, voltage); } -static struct devfreq_cooling_power kbase_cooling_power = { - .get_static_power = &kbase_devfreq_get_static_power, -}; - int kbase_devfreq_init(struct kbase_device *kbdev) { - struct devfreq_cooling_power *kbase_dcp = &kbase_cooling_power; + 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 long opp_rate; unsigned int i; + bool free_devfreq_freq_table = true; if (kbdev->nr_clocks == 0) { dev_err(kbdev->dev, "Clock not available for devfreq\n"); @@ -668,11 +704,18 @@ 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); + if (IS_ERR(opp)) + return PTR_ERR(opp); + dev_pm_opp_put(opp); dp = &kbdev->devfreq_profile; - dp->initial_freq = kbdev->current_freqs[0]; + dp->initial_freq = kbdev->current_nominal_freq; dp->polling_ms = 100; dp->target = kbase_devfreq_target; dp->get_dev_status = kbase_devfreq_status; @@ -687,12 +730,9 @@ kbdev->gpu_props.props.core_props.gpu_freq_khz_max = dp->freq_table[0] / 1000; }; - err = kbase_devfreq_init_core_mask_table(kbdev); - if (err) { - kbase_devfreq_term_freq_table(kbdev); - return err; - } + if (err) + goto init_core_mask_table_failed; of_property_read_u32(np, "upthreshold", &ondemand_data.upthreshold); @@ -703,21 +743,18 @@ if (IS_ERR(kbdev->devfreq)) { err = PTR_ERR(kbdev->devfreq); kbdev->devfreq = NULL; - kbase_devfreq_term_core_mask_table(kbdev); - kbase_devfreq_term_freq_table(kbdev); - dev_err(kbdev->dev, "Fail to add devfreq device(%d)\n", err); - return err; + dev_err(kbdev->dev, "Fail to add devfreq device(%d)", err); + goto devfreq_add_dev_failed; } + + /* Explicit free of freq table isn't needed after devfreq_add_device() */ + free_devfreq_freq_table = false; /* Initialize devfreq suspend/resume workqueue */ err = kbase_devfreq_work_init(kbdev); if (err) { - if (devfreq_remove_device(kbdev->devfreq)) - dev_err(kbdev->dev, "Fail to rm devfreq\n"); - kbdev->devfreq = NULL; - kbase_devfreq_term_core_mask_table(kbdev); - dev_err(kbdev->dev, "Fail to init devfreq workqueue\n"); - return err; + dev_err(kbdev->dev, "Fail to init devfreq workqueue"); + goto devfreq_work_init_failed; } /* devfreq_add_device only copies a few of kbdev->dev's fields, so @@ -728,44 +765,47 @@ err = devfreq_register_opp_notifier(kbdev->dev, kbdev->devfreq); if (err) { dev_err(kbdev->dev, - "Failed to register OPP notifier (%d)\n", err); + "Failed to register OPP notifier (%d)", err); goto opp_notifier_failed; } - opp_rate = kbdev->current_freqs[0]; /* Bifrost GPU has only 1 clock. */ - opp = devfreq_recommended_opp(kbdev->dev, &opp_rate, 0); - if (!IS_ERR(opp)) - dev_pm_opp_put(opp); - kbdev->devfreq->last_status.current_frequency = opp_rate; - mali_mdevp.data = kbdev->devfreq; + mali_mdevp.opp_info = &kbdev->opp_info; 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; } #if IS_ENABLED(CONFIG_DEVFREQ_THERMAL) - if (of_find_compatible_node(kbdev->dev->of_node, NULL, - "simple-power-model")) { - of_property_read_u32(kbdev->dev->of_node, - "dynamic-power-coefficient", - (u32 *)&kbase_dcp->dyn_power_coeff); - kbdev->model_data = rockchip_ipa_power_model_init(kbdev->dev, - "gpu_leakage"); + 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; - dev_err(kbdev->dev, "failed to initialize power model\n"); - } else if (kbdev->model_data->dynamic_coefficient) { - kbase_dcp->dyn_power_coeff = - kbdev->model_data->dynamic_coefficient; + 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) { - err = -EINVAL; - dev_err(kbdev->dev, "failed to get dynamic-coefficient\n"); - goto ipa_init_failed; - } + } + if (kbase_dcp->dyn_power_coeff) { kbdev->devfreq_cooling = of_devfreq_cooling_register_power(kbdev->dev->of_node, kbdev->devfreq, @@ -773,7 +813,7 @@ if (IS_ERR(kbdev->devfreq_cooling)) { err = PTR_ERR(kbdev->devfreq_cooling); dev_err(kbdev->dev, "failed to register cooling device\n"); - goto cooling_reg_failed; + goto ipa_init_failed; } } else { err = kbase_ipa_init(kbdev); @@ -793,7 +833,6 @@ err); goto cooling_reg_failed; } - } #endif @@ -809,12 +848,18 @@ opp_notifier_failed: kbase_devfreq_work_term(kbdev); +devfreq_work_init_failed: if (devfreq_remove_device(kbdev->devfreq)) - dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err); + dev_err(kbdev->dev, "Failed to terminate devfreq (%d)", err); kbdev->devfreq = NULL; +devfreq_add_dev_failed: kbase_devfreq_term_core_mask_table(kbdev); + +init_core_mask_table_failed: + if (free_devfreq_freq_table) + kbase_devfreq_term_freq_table(kbdev); return err; } @@ -828,10 +873,6 @@ #if IS_ENABLED(CONFIG_DEVFREQ_THERMAL) if (kbdev->devfreq_cooling) devfreq_cooling_unregister(kbdev->devfreq_cooling); - - if (!kbdev->model_data) - kbase_ipa_term(kbdev); - kfree(kbdev->model_data); #endif devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq); @@ -845,4 +886,10 @@ kbdev->devfreq = NULL; kbase_devfreq_term_core_mask_table(kbdev); + +#if IS_ENABLED(CONFIG_DEVFREQ_THERMAL) + if (!kbdev->model_data) + kbase_ipa_term(kbdev); + kfree(kbdev->model_data); +#endif } -- Gitblit v1.6.2