diff options
Diffstat (limited to 'mali-midgard-16.0')
-rwxr-xr-x | mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.c | 169 | ||||
-rwxr-xr-x | mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.h | 47 |
2 files changed, 216 insertions, 0 deletions
diff --git a/mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.c b/mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.c new file mode 100755 index 0000000..d965033 --- /dev/null +++ b/mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.c @@ -0,0 +1,169 @@ +/* + * + * (C) COPYRIGHT 2011-2016 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + +#include <linux/devfreq_cooling.h> +#include <linux/thermal.h> +#include <linux/of.h> +#include <mali_kbase.h> +#include <mali_kbase_defs.h> +#include <backend/gpu/mali_kbase_power_model_simple.h> + +/* + * This model is primarily designed for the Juno platform. It may not be + * suitable for other platforms. + */ + +#define FALLBACK_STATIC_TEMPERATURE 55000 + +static u32 dynamic_coefficient; +static u32 static_coefficient; +static s32 ts[4]; +static struct thermal_zone_device *gpu_tz; + +static unsigned long model_static_power(unsigned long voltage) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) + unsigned long temperature; +#else + int temperature; +#endif + unsigned long temp; + unsigned long temp_squared, temp_cubed, temp_scaling_factor; + const unsigned long voltage_cubed = (voltage * voltage * voltage) >> 10; + + if (gpu_tz) { + int ret; + + ret = gpu_tz->ops->get_temp(gpu_tz, &temperature); + if (ret) { + pr_warn_ratelimited("Error reading temperature for gpu thermal zone: %d\n", + ret); + temperature = FALLBACK_STATIC_TEMPERATURE; + } + } else { + temperature = FALLBACK_STATIC_TEMPERATURE; + } + + /* Calculate the temperature scaling factor. To be applied to the + * voltage scaled power. + */ + temp = temperature / 1000; + temp_squared = temp * temp; + temp_cubed = temp_squared * temp; + temp_scaling_factor = + (ts[3] * temp_cubed) + + (ts[2] * temp_squared) + + (ts[1] * temp) + + ts[0]; + + return (((static_coefficient * voltage_cubed) >> 20) + * temp_scaling_factor) + / 1000000; +} + +static unsigned long model_dynamic_power(unsigned long freq, + unsigned long voltage) +{ + /* The inputs: freq (f) is in Hz, and voltage (v) in mV. + * The coefficient (c) is in mW/(MHz mV mV). + * + * This function calculates the dynamic power after this formula: + * Pdyn (mW) = c (mW/(MHz*mV*mV)) * v (mV) * v (mV) * f (MHz) + */ + const unsigned long v2 = (voltage * voltage) / 1000; /* m*(V*V) */ + const unsigned long f_mhz = freq / 1000000; /* MHz */ + + return (dynamic_coefficient * v2 * f_mhz) / 1000000; /* mW */ +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) +struct devfreq_cooling_ops power_model_simple_ops = { +#else +struct devfreq_cooling_power power_model_simple_ops = { +#endif + .get_static_power = model_static_power, + .get_dynamic_power = model_dynamic_power, +}; + +int kbase_power_model_simple_init(struct kbase_device *kbdev) +{ + struct device_node *power_model_node; + const char *tz_name; + u32 static_power, dynamic_power; + u32 voltage, voltage_squared, voltage_cubed, frequency; + + power_model_node = of_get_child_by_name(kbdev->dev->of_node, + "power_model"); + if (!power_model_node) { + dev_err(kbdev->dev, "could not find power_model node\n"); + return -ENODEV; + } + if (!of_device_is_compatible(power_model_node, + "arm,mali-simple-power-model")) { + dev_err(kbdev->dev, "power_model incompatible with simple power model\n"); + return -ENODEV; + } + + if (of_property_read_string(power_model_node, "thermal-zone", + &tz_name)) { + dev_err(kbdev->dev, "ts in power_model not available\n"); + return -EINVAL; + } + + gpu_tz = thermal_zone_get_zone_by_name(tz_name); + if (IS_ERR(gpu_tz)) { + pr_warn_ratelimited("Error getting gpu thermal zone (%ld), not yet ready?\n", + PTR_ERR(gpu_tz)); + gpu_tz = NULL; + + return -EPROBE_DEFER; + } + + if (of_property_read_u32(power_model_node, "static-power", + &static_power)) { + dev_err(kbdev->dev, "static-power in power_model not available\n"); + return -EINVAL; + } + if (of_property_read_u32(power_model_node, "dynamic-power", + &dynamic_power)) { + dev_err(kbdev->dev, "dynamic-power in power_model not available\n"); + return -EINVAL; + } + if (of_property_read_u32(power_model_node, "voltage", + &voltage)) { + dev_err(kbdev->dev, "voltage in power_model not available\n"); + return -EINVAL; + } + if (of_property_read_u32(power_model_node, "frequency", + &frequency)) { + dev_err(kbdev->dev, "frequency in power_model not available\n"); + return -EINVAL; + } + voltage_squared = (voltage * voltage) / 1000; + voltage_cubed = voltage * voltage * voltage; + static_coefficient = (static_power << 20) / (voltage_cubed >> 10); + dynamic_coefficient = (((dynamic_power * 1000) / voltage_squared) + * 1000) / frequency; + + if (of_property_read_u32_array(power_model_node, "ts", (u32 *)ts, 4)) { + dev_err(kbdev->dev, "ts in power_model not available\n"); + return -EINVAL; + } + + return 0; +} + diff --git a/mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.h b/mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.h new file mode 100755 index 0000000..9b5e69a --- /dev/null +++ b/mali-midgard-16.0/backend/gpu/mali_kbase_power_model_simple.h @@ -0,0 +1,47 @@ +/* + * + * (C) COPYRIGHT 2014-2016 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + +#ifndef _BASE_POWER_MODEL_SIMPLE_H_ +#define _BASE_POWER_MODEL_SIMPLE_H_ + +/** + * kbase_power_model_simple_init - Initialise the simple power model + * @kbdev: Device pointer + * + * The simple power model estimates power based on current voltage, temperature, + * and coefficients read from device tree. It does not take utilization into + * account. + * + * The power model requires coefficients from the power_model node in device + * tree. The absence of this node will prevent the model from functioning, but + * should not prevent the rest of the driver from running. + * + * Return: 0 on success + * -ENOSYS if the power_model node is not present in device tree + * -EPROBE_DEFER if the thermal zone specified in device tree is not + * currently available + * Any other negative value on failure + */ +int kbase_power_model_simple_init(struct kbase_device *kbdev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) +extern struct devfreq_cooling_ops power_model_simple_ops; +#else +extern struct devfreq_cooling_power power_model_simple_ops; +#endif + +#endif /* _BASE_POWER_MODEL_SIMPLE_H_ */ |