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