1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "clock_soc.h"
9 #include "tc2_dvfs.h"
10 #include "tc2_psu.h"
11 #include "tc2_timer.h"
12 
13 #include <mod_dvfs.h>
14 #include <mod_scmi_perf.h>
15 
16 #include <fwk_element.h>
17 #include <fwk_macros.h>
18 #include <fwk_module.h>
19 #include <fwk_module_idx.h>
20 
21 /*
22  * The power cost figures in this file are built using the dynamic power
23  * consumption formula (P = CfV^2), where C represents the capacitance of one
24  * processing element in the domain (a core or shader core). This power figure
25  * is scaled linearly with the number of processing elements in the performance
26  * domain to give a rough representation of the overall power draw. The
27  * capacitance constants are given in mW/MHz/V^2 and were taken from the Linux
28  * device trees, which provide a dynamic-power-coefficient field in uW/MHz/V^2.
29  * This conversion of units, from uW/MHz/V^2 to mW/MHz/V^2, is done by dividing
30  * by 1000.
31  */
32 
33 /* dynamic-power-coeffient/1000 */
34 #define HAYES_DPC      0.230
35 #define HUNTER_DPC     0.495
36 #define HUNTER_ELP_DPC 1.054
37 
38 static struct mod_dvfs_opp operating_points_hayes[6] = {
39     {
40         .level = 768 * 1000000UL,
41         .frequency = 768 * FWK_KHZ,
42         .voltage = 550,
43         .power = (uint32_t)(HAYES_DPC * 768 * 0.550 * 0.550),
44     },
45     {
46         .level = 1153 * 1000000UL,
47         .frequency = 1153 * FWK_KHZ,
48         .voltage = 650,
49         .power = (uint32_t)(HAYES_DPC * 1153 * 0.650 * 0.650),
50     },
51     {
52         .level = 1537 * 1000000UL,
53         .frequency = 1537 * FWK_KHZ,
54         .voltage = 750,
55         .power = (uint32_t)(HAYES_DPC * 1537 * 0.750 * 0.750),
56     },
57     {
58         .level = 1844 * 1000000UL,
59         .frequency = 1844 * FWK_KHZ,
60         .voltage = 850,
61         .power = (uint32_t)(HAYES_DPC * 1844 * 0.850 * 0.850),
62     },
63     {
64         .level = 2152 * 1000000UL,
65         .frequency = 2152 * FWK_KHZ,
66         .voltage = 950,
67         .power = (uint32_t)(HAYES_DPC * 2152 * 0.950 * 0.950),
68     },
69     { 0 }
70 };
71 
72 static struct mod_dvfs_opp operating_points_hunter[6] = {
73     {
74         .level = 946 * 1000000UL,
75         .frequency = 946 * FWK_KHZ,
76         .voltage = 550,
77         .power = (uint32_t)(HUNTER_DPC * 946 * 0.550 * 0.550),
78     },
79     {
80         .level = 1419 * 1000000UL,
81         .frequency = 1419 * FWK_KHZ,
82         .voltage = 650,
83         .power = (uint32_t)(HUNTER_DPC * 1419 * 0.650 * 0.650),
84     },
85     {
86         .level = 1893 * 1000000UL,
87         .frequency = 1893 * FWK_KHZ,
88         .voltage = 750,
89         .power = (uint32_t)(HUNTER_DPC * 1893 * 0.750 * 0.750),
90     },
91     {
92         .level = 2271 * 1000000UL,
93         .frequency = 2271 * FWK_KHZ,
94         .voltage = 850,
95         .power = (uint32_t)(HUNTER_DPC * 2271 * 0.850 * 0.850),
96     },
97     {
98         .level = 2650 * 1000000UL,
99         .frequency = 2650 * FWK_KHZ,
100         .voltage = 950,
101         .power = (uint32_t)(HUNTER_DPC * 2650 * 0.950 * 0.950),
102     },
103     { 0 }
104 };
105 
106 static struct mod_dvfs_opp operating_points_hunter_elp[6] = {
107     {
108         .level = 1088 * 1000000UL,
109         .frequency = 1088 * FWK_KHZ,
110         .voltage = 550,
111         .power = (uint32_t)(HUNTER_ELP_DPC * 1088 * 0.550 * 0.550),
112     },
113     {
114         .level = 1632 * 1000000UL,
115         .frequency = 1632 * FWK_KHZ,
116         .voltage = 650,
117         .power = (uint32_t)(HUNTER_ELP_DPC * 1632 * 0.650 * 0.650),
118     },
119     {
120         .level = 2176 * 1000000UL,
121         .frequency = 2176 * FWK_KHZ,
122         .voltage = 750,
123         .power = (uint32_t)(HUNTER_ELP_DPC * 2176 * 0.750 * 0.750),
124     },
125     {
126         .level = 2612 * 1000000UL,
127         .frequency = 2612 * FWK_KHZ,
128         .voltage = 850,
129         .power = (uint32_t)(HUNTER_ELP_DPC * 2612 * 0.850 * 0.850),
130     },
131     {
132         .level = 3047 * 1000000UL,
133         .frequency = 3047 * FWK_KHZ,
134         .voltage = 950,
135         .power = (uint32_t)(HUNTER_ELP_DPC * 3047 * 0.950 * 0.950),
136     },
137     { 0 }
138 };
139 
140 static const struct mod_dvfs_domain_config cpu_group_hayes = {
141     .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, PSU_ELEMENT_IDX_HAYES),
142     .clock_id =
143         FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, CLOCK_IDX_CPU_GROUP_HAYES),
144     .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
145         FWK_MODULE_IDX_TIMER,
146         0,
147         TC2_CONFIG_TIMER_DVFS_CPU_HAYES),
148     .retry_ms = 1,
149     .latency = 1200,
150     .sustained_idx = 2,
151     .opps = operating_points_hayes,
152 };
153 
154 static const struct mod_dvfs_domain_config cpu_group_hunter = {
155     .psu_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, PSU_ELEMENT_IDX_HUNTER),
156     .clock_id =
157         FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, CLOCK_IDX_CPU_GROUP_HUNTER),
158     .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
159         FWK_MODULE_IDX_TIMER,
160         0,
161         TC2_CONFIG_TIMER_DVFS_CPU_HUNTER),
162     .retry_ms = 1,
163     .latency = 1200,
164     .sustained_idx = 2,
165     .opps = operating_points_hunter,
166 };
167 
168 static const struct mod_dvfs_domain_config cpu_group_hunter_elp = {
169     .psu_id =
170         FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PSU, PSU_ELEMENT_IDX_HUNTER_ELP),
171     .clock_id = FWK_ID_ELEMENT_INIT(
172         FWK_MODULE_IDX_CLOCK,
173         CLOCK_IDX_CPU_GROUP_HUNTER_ELP),
174     .alarm_id = FWK_ID_SUB_ELEMENT_INIT(
175         FWK_MODULE_IDX_TIMER,
176         0,
177         TC2_CONFIG_TIMER_DVFS_CPU_HUNTER_ELP),
178     .retry_ms = 1,
179     .latency = 1200,
180     .sustained_idx = 2,
181     .opps = operating_points_hunter_elp,
182 };
183 
184 static const struct fwk_element element_table[DVFS_ELEMENT_IDX_COUNT + 1] = {
185     [DVFS_ELEMENT_IDX_HAYES] =
186         {
187             .name = "CPU_GROUP_HAYES",
188             .data = &cpu_group_hayes,
189         },
190     [DVFS_ELEMENT_IDX_HUNTER] =
191         {
192             .name = "CPU_GROUP_HUNTER",
193             .data = &cpu_group_hunter,
194         },
195     [DVFS_ELEMENT_IDX_HUNTER_ELP] =
196         {
197             .name = "CPU_GROUP_HUNTER_ELP",
198             .data = &cpu_group_hunter_elp,
199         },
200     { 0 },
201 };
202 
dvfs_get_element_table(fwk_id_t module_id)203 static const struct fwk_element *dvfs_get_element_table(fwk_id_t module_id)
204 {
205     return element_table;
206 }
207 
208 const struct fwk_module_config config_dvfs = {
209     .elements = FWK_MODULE_DYNAMIC_ELEMENTS(dvfs_get_element_table),
210 };
211