1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "config_dvfs.h"
9 #include "config_psu.h"
10 #include "juno_alarm_idx.h"
11 #include "juno_clock.h"
12 #include "juno_id.h"
13
14 #include <mod_dvfs.h>
15 #include <mod_scmi_perf.h>
16
17 #include <fwk_assert.h>
18 #include <fwk_element.h>
19 #include <fwk_id.h>
20 #include <fwk_macros.h>
21 #include <fwk_module.h>
22 #include <fwk_module_idx.h>
23 #include <fwk_status.h>
24
25 #include <stddef.h>
26
27 /*
28 * The power cost figures from this file are built using the dynamic power
29 * consumption formula (P = CfV^2), where C represents the capacitance of one
30 * processing element in the domain (a core or shader core). This power figure
31 * is scaled linearly with the number of processing elements in the performance
32 * domain to give a rough representation of the overall power draw. The
33 * capacitance constants are given in mW/MHz/V^2 and were taken from the Linux
34 * device trees, which provide a dynamic-power-coefficient field in uW/MHz/V^2.
35 */
36
37 static const struct mod_dvfs_domain_config cpu_group_little_r0 = {
38 .psu_id =
39 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VLITTLE),
40 .clock_id =
41 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_LITTLECLK),
42 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
43 FWK_MODULE_IDX_TIMER,
44 0,
45 JUNO_DVFS_ALARM_VLITTLE_IDX),
46 .retry_ms = 1,
47 .latency = 1450,
48 .sustained_idx = 2,
49 .opps =
50 (struct mod_dvfs_opp[]){
51 {
52 .level = 450 * 1000000UL,
53 .frequency = 450 * FWK_KHZ,
54 .voltage = 820,
55 .power = (uint32_t)(0.14 * 450 * 0.820 * 0.820),
56 },
57 {
58 .level = 575 * 1000000UL,
59 .frequency = 575 * FWK_KHZ,
60 .voltage = 850,
61 .power = (uint32_t)(0.14 * 575 * 0.850 * 0.850),
62 },
63 {
64 .level = 700 * 1000000UL,
65 .frequency = 700 * FWK_KHZ,
66 .voltage = 900,
67 .power = (uint32_t)(0.14 * 700 * 0.900 * 0.900),
68 },
69 {
70 .level = 775 * 1000000UL,
71 .frequency = 775 * FWK_KHZ,
72 .voltage = 950,
73 .power = (uint32_t)(0.14 * 775 * 0.950 * 0.950),
74 },
75 {
76 .level = 850 * 1000000UL,
77 .frequency = 850 * FWK_KHZ,
78 .voltage = 1000,
79 .power = (uint32_t)(0.14 * 850 * 1.000 * 1.000),
80 },
81 { 0 } }
82 };
83
84 static const struct mod_dvfs_domain_config cpu_group_little_r1 = {
85 .psu_id =
86 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VLITTLE),
87 .clock_id =
88 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_LITTLECLK),
89 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
90 FWK_MODULE_IDX_TIMER,
91 0,
92 JUNO_DVFS_ALARM_VLITTLE_IDX),
93 .retry_ms = 1,
94 .latency = 1450,
95 .sustained_idx = 0,
96 .opps =
97 (struct mod_dvfs_opp[]){
98 {
99 .level = 650 * 1000000UL,
100 .frequency = 650 * FWK_KHZ,
101 .voltage = 800,
102 .power = (uint32_t)(0.14 * 650 * 0.800 * 0.800),
103 },
104 { 0 },
105 }
106 };
107
108 static const struct mod_dvfs_domain_config cpu_group_little_r2 = {
109 .psu_id =
110 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VLITTLE),
111 .clock_id =
112 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_LITTLECLK),
113 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
114 FWK_MODULE_IDX_TIMER,
115 0,
116 JUNO_DVFS_ALARM_VLITTLE_IDX),
117 .retry_ms = 1,
118 .latency = 1450,
119 .sustained_idx = 1,
120 .opps =
121 (struct mod_dvfs_opp[]){
122 {
123 .level = 450 * 1000000UL,
124 .frequency = 450 * FWK_KHZ,
125 .voltage = 820,
126 .power = (uint32_t)(0.14 * 450 * 0.820 * 0.820),
127 },
128 {
129 .level = 800 * 1000000UL,
130 .frequency = 800 * FWK_KHZ,
131 .voltage = 900,
132 .power = (uint32_t)(0.14 * 800 * 0.900 * 0.900),
133 },
134 {
135 .level = 950 * 1000000UL,
136 .frequency = 950 * FWK_KHZ,
137 .voltage = 1000,
138 .power = (uint32_t)(0.14 * 950 * 1.000 * 1.000),
139 },
140 { 0 } }
141 };
142
143 static const struct mod_dvfs_domain_config cpu_group_big_r0 = {
144 .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VBIG),
145 .clock_id =
146 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_BIGCLK),
147 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
148 FWK_MODULE_IDX_TIMER,
149 0,
150 JUNO_DVFS_ALARM_BIG_IDX),
151 .retry_ms = 1,
152 .latency = 1450,
153 .sustained_idx = 2,
154 .opps =
155 (struct mod_dvfs_opp[]){
156 {
157 .level = 450 * 1000000UL,
158 .frequency = 450 * FWK_KHZ,
159 .voltage = 820,
160 .power = (uint32_t)(0.53 * 450 * 0.820 * 0.820),
161 },
162 {
163 .level = 625 * 1000000UL,
164 .frequency = 625 * FWK_KHZ,
165 .voltage = 850,
166 .power = (uint32_t)(0.53 * 625 * 0.850 * 0.850),
167 },
168 {
169 .level = 800 * 1000000UL,
170 .frequency = 800 * FWK_KHZ,
171 .voltage = 900,
172 .power = (uint32_t)(0.53 * 800 * 0.900 * 0.900),
173 },
174 {
175 .level = 950 * 1000000UL,
176 .frequency = 950 * FWK_KHZ,
177 .voltage = 950,
178 .power = (uint32_t)(0.53 * 950 * 0.950 * 0.950),
179 },
180 {
181 .level = 1100 * 1000000UL,
182 .frequency = 1100 * FWK_KHZ,
183 .voltage = 1000,
184 .power = (uint32_t)(0.53 * 1100 * 1.000 * 1.000),
185 },
186 { 0 } }
187 };
188
189 static const struct mod_dvfs_domain_config cpu_group_big_r1 = {
190 .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VBIG),
191 .clock_id =
192 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_BIGCLK),
193 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
194 FWK_MODULE_IDX_TIMER,
195 0,
196 JUNO_DVFS_ALARM_BIG_IDX),
197 .retry_ms = 1,
198 .latency = 1450,
199 .sustained_idx = 1,
200 .opps =
201 (struct mod_dvfs_opp[]){
202 {
203 .level = 600 * 1000000UL,
204 .frequency = 600 * FWK_KHZ,
205 .voltage = 800,
206 .power = (uint32_t)(0.53 * 600 * 0.800 * 0.800),
207 },
208 {
209 .level = 900 * 1000000UL,
210 .frequency = 900 * FWK_KHZ,
211 .voltage = 900,
212 .power = (uint32_t)(0.53 * 900 * 0.900 * 0.900),
213 },
214 {
215 .level = 1150 * 1000000UL,
216 .frequency = 1150 * FWK_KHZ,
217 .voltage = 1000,
218 .power = (uint32_t)(0.53 * 1150 * 1.000 * 1.000),
219 },
220 { 0 } }
221 };
222
223 static const struct mod_dvfs_domain_config cpu_group_big_r2 = {
224 .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VBIG),
225 .clock_id =
226 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_BIGCLK),
227 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
228 FWK_MODULE_IDX_TIMER,
229 0,
230 JUNO_DVFS_ALARM_BIG_IDX),
231 .retry_ms = 1,
232 .latency = 1450,
233 .sustained_idx = 1,
234 .opps =
235 (struct mod_dvfs_opp[]){
236 {
237 .level = 600 * 1000000UL,
238 .frequency = 600 * FWK_KHZ,
239 .voltage = 820,
240 .power = (uint32_t)(0.45 * 600 * 0.820 * 0.820),
241 },
242 {
243 .level = 1000 * 1000000UL,
244 .frequency = 1000 * FWK_KHZ,
245 .voltage = 900,
246 .power = (uint32_t)(0.45 * 1000 * 0.900 * 0.900),
247 },
248 {
249 .level = 1200 * 1000000UL,
250 .frequency = 1200 * FWK_KHZ,
251 .voltage = 1000,
252 .power = (uint32_t)(0.45 * 1200 * 1.000 * 1.000),
253 },
254 { 0 } }
255 };
256
257 static const struct mod_dvfs_domain_config gpu_r0 = {
258 .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VGPU),
259 .clock_id =
260 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_GPUCLK),
261 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
262 FWK_MODULE_IDX_TIMER,
263 0,
264 JUNO_DVFS_ALARM_GPU_IDX),
265 .retry_ms = 1,
266 .latency = 1450,
267 .sustained_idx = 4,
268 .opps =
269 (struct mod_dvfs_opp[]){
270 {
271 .level = 450 * 1000000UL,
272 .frequency = 450 * FWK_KHZ,
273 .voltage = 820,
274 .power = (uint32_t)(4.6875 * 450 * 0.820 * 0.820),
275 },
276 {
277 .level = 487500 * 1000UL,
278 .frequency = 487500,
279 .voltage = 825,
280 .power = (uint32_t)(4.6875 * 487.5 * 0.825 * 0.825),
281 },
282 {
283 .level = 525 * 1000000UL,
284 .frequency = 525 * FWK_KHZ,
285 .voltage = 850,
286 .power = (uint32_t)(4.6875 * 525 * 0.850 * 0.850),
287 },
288 {
289 .level = 562500 * 1000UL,
290 .frequency = 562500,
291 .voltage = 875,
292 .power = (uint32_t)(4.6875 * 562.5 * 0.875 * 0.875),
293 },
294 {
295 .level = 600 * 1000000UL,
296 .frequency = 600 * FWK_KHZ,
297 .voltage = 900,
298 .power = (uint32_t)(4.6875 * 600 * 0.900 * 0.900),
299 },
300 { 0 } }
301 };
302
303 static const struct mod_dvfs_domain_config gpu_r1 = {
304 .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VGPU),
305 .clock_id =
306 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_GPUCLK),
307 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
308 FWK_MODULE_IDX_TIMER,
309 0,
310 JUNO_DVFS_ALARM_GPU_IDX),
311 .retry_ms = 1,
312 .latency = 1450,
313 .sustained_idx = 4,
314 .opps =
315 (struct mod_dvfs_opp[]){
316 {
317 .level = 450 * 1000000UL,
318 .frequency = 450 * FWK_KHZ,
319 .voltage = 820,
320 .power = (uint32_t)(4.6875 * 450 * 0.820 * 0.820),
321 },
322 {
323 .level = 487500 * 1000UL,
324 .frequency = 487500,
325 .voltage = 825,
326 .power = (uint32_t)(4.6875 * 487.5 * 0.825 * 0.825),
327 },
328 {
329 .level = 525 * 1000000UL,
330 .frequency = 525 * FWK_KHZ,
331 .voltage = 850,
332 .power = (uint32_t)(4.6875 * 525 * 0.850 * 0.850),
333 },
334 {
335 .level = 562500 * 1000UL,
336 .frequency = 562500,
337 .voltage = 875,
338 .power = (uint32_t)(4.6875 * 562.5 * 0.875 * 0.875),
339 },
340 {
341 .level = 600 * 1000000UL,
342 .frequency = 600 * FWK_KHZ,
343 .voltage = 900,
344 .power = (uint32_t)(4.6875 * 600 * 0.900 * 0.900),
345 },
346 { 0 } }
347 };
348
349 static const struct mod_dvfs_domain_config gpu_r2 = {
350 .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, MOD_PSU_ELEMENT_IDX_VGPU),
351 .clock_id =
352 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, JUNO_CLOCK_IDX_GPUCLK),
353 .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
354 FWK_MODULE_IDX_TIMER,
355 0,
356 JUNO_DVFS_ALARM_GPU_IDX),
357 .retry_ms = 1,
358 .latency = 1450,
359 .sustained_idx = 1,
360 .opps =
361 (struct mod_dvfs_opp[]){
362 {
363 .level = 450 * 1000000UL,
364 .frequency = 450 * FWK_KHZ,
365 .voltage = 820,
366 .power = (uint32_t)(4.6875 * 450 * 0.820 * 0.820),
367 },
368 {
369 .level = 600 * 1000000UL,
370 .frequency = 600 * FWK_KHZ,
371 .voltage = 900,
372 .power = (uint32_t)(4.6875 * 600 * 0.900 * 0.900),
373 },
374 { 0 } }
375 };
376
377 static const struct fwk_element element_table_r0[] = {
378 [DVFS_ELEMENT_IDX_LITTLE] = {
379 .name = "LITTLE_CPU",
380 .data = &cpu_group_little_r0,
381 },
382 [DVFS_ELEMENT_IDX_BIG] = {
383 .name = "BIG_CPU",
384 .data = &cpu_group_big_r0,
385 },
386 [DVFS_ELEMENT_IDX_GPU] = {
387 .name = "GPU",
388 .data = &gpu_r0,
389 },
390 { 0 }
391 };
392
393 static const struct fwk_element element_table_r1[] = {
394 [DVFS_ELEMENT_IDX_LITTLE] = {
395 .name = "LITTLE_CPU",
396 .data = &cpu_group_little_r1,
397 },
398 [DVFS_ELEMENT_IDX_BIG] = {
399 .name = "BIG_CPU",
400 .data = &cpu_group_big_r1,
401 },
402 [DVFS_ELEMENT_IDX_GPU] = {
403 .name = "GPU",
404 .data = &gpu_r1,
405 },
406 { 0 }
407 };
408
409 static const struct fwk_element element_table_r2[] = {
410 [DVFS_ELEMENT_IDX_LITTLE] = {
411 .name = "LITTLE_CPU",
412 .data = &cpu_group_little_r2,
413 },
414 [DVFS_ELEMENT_IDX_BIG] = {
415 .name = "BIG_CPU",
416 .data = &cpu_group_big_r2,
417 },
418 [DVFS_ELEMENT_IDX_GPU] = {
419 .name = "GPU",
420 .data = &gpu_r2,
421 },
422 { 0 }
423 };
424
dvfs_get_element_table(fwk_id_t module_id)425 static const struct fwk_element *dvfs_get_element_table(fwk_id_t module_id)
426 {
427 int status;
428 enum juno_idx_revision revision = (enum juno_idx_revision)0U;
429
430 status = juno_id_get_revision(&revision);
431 fwk_assert(status == FWK_SUCCESS);
432
433 if (revision == JUNO_IDX_REVISION_R0) {
434 return element_table_r0;
435 }
436 if (revision == JUNO_IDX_REVISION_R1) {
437 return element_table_r1;
438 }
439 return element_table_r2;
440 }
441
442 struct fwk_module_config config_dvfs = {
443 .elements = FWK_MODULE_DYNAMIC_ELEMENTS(dvfs_get_element_table),
444 };
445