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