xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_simple.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  *
3  * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved.
4  *
5  * This program is free software and is provided to you under the terms of the
6  * GNU General Public License version 2 as published by the Free Software
7  * Foundation, and any use by you of this program is subject to the terms
8  * of such GNU licence.
9  *
10  * A copy of the licence is included with the program, and can also be obtained
11  * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12  * Boston, MA  02110-1301, USA.
13  *
14  */
15 
16 
17 
18 #include <linux/thermal.h>
19 #ifdef CONFIG_DEVFREQ_THERMAL
20 #include <linux/devfreq_cooling.h>
21 #endif
22 #include <linux/of.h>
23 #include <linux/math64.h>
24 
25 #include "mali_kbase.h"
26 #include "mali_kbase_defs.h"
27 
28 /*
29  * This model is primarily designed for the Juno platform. It may not be
30  * suitable for other platforms. The additional resources in this model
31  * should preferably be minimal, as this model is rarely used when a dynamic
32  * model is available.
33  */
34 
35 /**
36  * struct kbase_ipa_model_simple_data - IPA context per device
37  * @dynamic_coefficient: dynamic coefficient of the model
38  * @static_coefficient:  static coefficient of the model
39  * @ts:                  Thermal scaling coefficients of the model
40  * @tz_name:             Thermal zone name
41  * @gpu_tz:              thermal zone device
42  */
43 
44 struct kbase_ipa_model_simple_data {
45 	u32 dynamic_coefficient;
46 	u32 static_coefficient;
47 	s32 ts[4];
48 	char tz_name[16];
49 	struct thermal_zone_device *gpu_tz;
50 };
51 #define FALLBACK_STATIC_TEMPERATURE 55000
52 
53 /**
54  * calculate_temp_scaling_factor() - Calculate temperature scaling coefficient
55  * @ts:		Signed coefficients, in order t^0 to t^3, with units Deg^-N
56  * @t:		Temperature, in mDeg C. Range: -2^17 < t < 2^17
57  *
58  * Scale the temperature according to a cubic polynomial whose coefficients are
59  * provided in the device tree. The result is used to scale the static power
60  * coefficient, where 1000000 means no change.
61  *
62  * Return: Temperature scaling factor. Approx range 0 < ret < 10,000,000.
63  */
calculate_temp_scaling_factor(s32 ts[4],s64 t)64 static u32 calculate_temp_scaling_factor(s32 ts[4], s64 t)
65 {
66 	/* Range: -2^24 < t2 < 2^24 m(Deg^2) */
67 	u32 remainder;
68 	// static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
69 	const s64 t2 = div_s64_rem((t * t), 1000, &remainder);
70 
71 	/* Range: -2^31 < t3 < 2^31 m(Deg^3) */
72 	const s64 t3 = div_s64_rem((t * t2), 1000, &remainder);
73 
74 	/*
75 	 * Sum the parts. t^[1-3] are in m(Deg^N), but the coefficients are in
76 	 * Deg^-N, so we need to multiply the last coefficient by 1000.
77 	 * Range: -2^63 < res_big < 2^63
78 	 */
79 	const s64 res_big = ts[3] * t3    /* +/- 2^62 */
80 			  + ts[2] * t2    /* +/- 2^55 */
81 			  + ts[1] * t     /* +/- 2^48 */
82 			  + ts[0] * 1000; /* +/- 2^41 */
83 
84 	/* Range: -2^60 < res_unclamped < 2^60 */
85 	s64 res_unclamped = div_s64_rem(res_big, 1000, &remainder);
86 
87 	/* Clamp to range of 0x to 10x the static power */
88 	return clamp(res_unclamped, (s64) 0, (s64) 10000000);
89 }
90 
model_static_coeff(struct kbase_ipa_model * model,u32 * coeffp)91 static int model_static_coeff(struct kbase_ipa_model *model, u32 *coeffp)
92 {
93 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
94 	unsigned long temp;
95 #else
96 	int temp;
97 #endif
98 	u32 temp_scaling_factor;
99 	struct kbase_ipa_model_simple_data *model_data =
100 		(struct kbase_ipa_model_simple_data *) model->model_data;
101 	struct thermal_zone_device *gpu_tz = model_data->gpu_tz;
102 	u64 coeffp_big;
103 
104 	if (gpu_tz) {
105 		int ret;
106 
107 		ret = gpu_tz->ops->get_temp(gpu_tz, &temp);
108 		if (ret) {
109 			pr_warn_ratelimited("Error reading temperature for gpu thermal zone: %d\n",
110 					ret);
111 			temp = FALLBACK_STATIC_TEMPERATURE;
112 		}
113 	} else {
114 		temp = FALLBACK_STATIC_TEMPERATURE;
115 	}
116 
117 	temp_scaling_factor = calculate_temp_scaling_factor(model_data->ts,
118 							    temp);
119 	coeffp_big = (u64)model_data->static_coefficient * temp_scaling_factor;
120 	*coeffp = div_u64(coeffp_big, 1000000);
121 
122 	return 0;
123 }
124 
model_dynamic_coeff(struct kbase_ipa_model * model,u32 * coeffp,u32 current_freq)125 static int model_dynamic_coeff(struct kbase_ipa_model *model, u32 *coeffp,
126 			       u32 current_freq)
127 {
128 	struct kbase_ipa_model_simple_data *model_data =
129 		(struct kbase_ipa_model_simple_data *) model->model_data;
130 
131 	*coeffp = model_data->dynamic_coefficient;
132 
133 	return 0;
134 }
135 
add_params(struct kbase_ipa_model * model)136 static int add_params(struct kbase_ipa_model *model)
137 {
138 	int err = 0;
139 	struct kbase_ipa_model_simple_data *model_data =
140 			(struct kbase_ipa_model_simple_data *)model->model_data;
141 
142 	err = kbase_ipa_model_add_param_s32(model, "static-coefficient",
143 					    &model_data->static_coefficient,
144 					    1, true);
145 	if (err)
146 		goto end;
147 
148 	err = kbase_ipa_model_add_param_s32(model, "dynamic-coefficient",
149 					    &model_data->dynamic_coefficient,
150 					    1, true);
151 	if (err)
152 		goto end;
153 
154 	err = kbase_ipa_model_add_param_s32(model, "ts",
155 					    model_data->ts, 4, true);
156 	if (err)
157 		goto end;
158 
159 	err = kbase_ipa_model_add_param_string(model, "thermal-zone",
160 					       model_data->tz_name,
161 					       sizeof(model_data->tz_name), true);
162 
163 end:
164 	return err;
165 }
166 
kbase_simple_power_model_init(struct kbase_ipa_model * model)167 static int kbase_simple_power_model_init(struct kbase_ipa_model *model)
168 {
169 	int err;
170 	struct kbase_ipa_model_simple_data *model_data;
171 
172 	model_data = kzalloc(sizeof(struct kbase_ipa_model_simple_data),
173 			     GFP_KERNEL);
174 	if (!model_data)
175 		return -ENOMEM;
176 
177 	model->model_data = (void *) model_data;
178 
179 	err = add_params(model);
180 
181 	return err;
182 }
183 
kbase_simple_power_model_recalculate(struct kbase_ipa_model * model)184 static int kbase_simple_power_model_recalculate(struct kbase_ipa_model *model)
185 {
186 	struct kbase_ipa_model_simple_data *model_data =
187 			(struct kbase_ipa_model_simple_data *)model->model_data;
188 
189 	if (!strnlen(model_data->tz_name, sizeof(model_data->tz_name))) {
190 		model_data->gpu_tz = NULL;
191 	} else {
192 		model_data->gpu_tz = thermal_zone_get_zone_by_name(model_data->tz_name);
193 
194 		if (IS_ERR(model_data->gpu_tz)) {
195 			pr_warn_ratelimited("Error %ld getting thermal zone \'%s\', not yet ready?\n",
196 					    PTR_ERR(model_data->gpu_tz),
197 					    model_data->tz_name);
198 			model_data->gpu_tz = NULL;
199 			return -EPROBE_DEFER;
200 		}
201 	}
202 
203 	return 0;
204 }
205 
kbase_simple_power_model_term(struct kbase_ipa_model * model)206 static void kbase_simple_power_model_term(struct kbase_ipa_model *model)
207 {
208 	struct kbase_ipa_model_simple_data *model_data =
209 			(struct kbase_ipa_model_simple_data *)model->model_data;
210 
211 	kfree(model_data);
212 }
213 
214 struct kbase_ipa_model_ops kbase_simple_ipa_model_ops = {
215 		.name = "mali-simple-power-model",
216 		.init = &kbase_simple_power_model_init,
217 		.recalculate = &kbase_simple_power_model_recalculate,
218 		.term = &kbase_simple_power_model_term,
219 		.get_dynamic_coeff = &model_dynamic_coeff,
220 		.get_static_coeff = &model_static_coeff,
221 		.do_utilization_scaling_in_framework = true,
222 };
223