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