1155ebf23SPascal Paillet // SPDX-License-Identifier: BSD-2-Clause
2155ebf23SPascal Paillet /*
3155ebf23SPascal Paillet * Copyright (c) 2022-2024, STMicroelectronics
4155ebf23SPascal Paillet */
5155ebf23SPascal Paillet
6155ebf23SPascal Paillet #include <assert.h>
7155ebf23SPascal Paillet #include <config.h>
8155ebf23SPascal Paillet #include <drivers/clk.h>
9155ebf23SPascal Paillet #include <drivers/clk_dt.h>
10155ebf23SPascal Paillet #include <drivers/regulator.h>
11155ebf23SPascal Paillet #include <drivers/stm32_cpu_opp.h>
12155ebf23SPascal Paillet #ifdef CFG_STM32MP13
13155ebf23SPascal Paillet #include <drivers/stm32mp1_pwr.h>
14155ebf23SPascal Paillet #endif
15155ebf23SPascal Paillet #include <initcall.h>
16155ebf23SPascal Paillet #include <io.h>
17155ebf23SPascal Paillet #include <keep.h>
18155ebf23SPascal Paillet #include <kernel/dt.h>
19155ebf23SPascal Paillet #include <kernel/dt_driver.h>
20155ebf23SPascal Paillet #include <kernel/mutex.h>
21155ebf23SPascal Paillet #include <kernel/panic.h>
22155ebf23SPascal Paillet #include <kernel/pm.h>
23155ebf23SPascal Paillet #include <libfdt.h>
24*2bfcd5deSPascal Paillet #include <stm32_util.h>
25155ebf23SPascal Paillet #include <trace.h>
26155ebf23SPascal Paillet
27155ebf23SPascal Paillet /*
28155ebf23SPascal Paillet * struct cpu_dvfs - CPU DVFS registered operating point
29155ebf23SPascal Paillet * @freq_khz: CPU frequency in kilohertz (kHz)
30155ebf23SPascal Paillet * @volt_uv: CPU voltage level in microvolts (uV)
31155ebf23SPascal Paillet */
32155ebf23SPascal Paillet struct cpu_dvfs {
33155ebf23SPascal Paillet unsigned int freq_khz;
34155ebf23SPascal Paillet int volt_uv;
35155ebf23SPascal Paillet };
36155ebf23SPascal Paillet
37155ebf23SPascal Paillet /*
38155ebf23SPascal Paillet * struct cpu_opp - CPU operating point
39155ebf23SPascal Paillet *
40155ebf23SPascal Paillet * @current_opp: Index of current CPU operating point in @dvfs array
41155ebf23SPascal Paillet * @opp_count: Number of cells of @dvfs
42155ebf23SPascal Paillet * @clock: CPU clock handle
43155ebf23SPascal Paillet * @regul: CPU regulator supply handle
44155ebf23SPascal Paillet * @dvfs: Array of the supported CPU operating points
45155ebf23SPascal Paillet * @sustained_freq_khz: Max long term sustainable frequency in kHz
46155ebf23SPascal Paillet */
47155ebf23SPascal Paillet struct cpu_opp {
48155ebf23SPascal Paillet unsigned int current_opp;
49155ebf23SPascal Paillet unsigned int opp_count;
50155ebf23SPascal Paillet struct clk *clock;
51155ebf23SPascal Paillet struct regulator *regul;
52155ebf23SPascal Paillet struct cpu_dvfs *dvfs;
53155ebf23SPascal Paillet unsigned int sustained_freq_khz;
54155ebf23SPascal Paillet };
55155ebf23SPascal Paillet
56155ebf23SPascal Paillet static struct cpu_opp cpu_opp;
57155ebf23SPascal Paillet
58155ebf23SPascal Paillet /* Mutex for protecting CPU OPP changes */
59155ebf23SPascal Paillet static struct mutex cpu_opp_mu = MUTEX_INITIALIZER;
60155ebf23SPascal Paillet
stm32_cpu_opp_count(void)61155ebf23SPascal Paillet unsigned int stm32_cpu_opp_count(void)
62155ebf23SPascal Paillet {
63155ebf23SPascal Paillet return cpu_opp.opp_count;
64155ebf23SPascal Paillet }
65155ebf23SPascal Paillet
stm32_cpu_opp_sustained_level(void)66155ebf23SPascal Paillet unsigned int stm32_cpu_opp_sustained_level(void)
67155ebf23SPascal Paillet {
68155ebf23SPascal Paillet return cpu_opp.sustained_freq_khz;
69155ebf23SPascal Paillet }
70155ebf23SPascal Paillet
71155ebf23SPascal Paillet /* Perf level relates straight to CPU frequency in kHz */
stm32_cpu_opp_level(unsigned int opp)72155ebf23SPascal Paillet unsigned int stm32_cpu_opp_level(unsigned int opp)
73155ebf23SPascal Paillet {
74155ebf23SPascal Paillet assert(opp < cpu_opp.opp_count);
75155ebf23SPascal Paillet
76155ebf23SPascal Paillet return cpu_opp.dvfs[opp].freq_khz;
77155ebf23SPascal Paillet }
78155ebf23SPascal Paillet
set_opp_clk_rate(unsigned int opp)79155ebf23SPascal Paillet static TEE_Result set_opp_clk_rate(unsigned int opp)
80155ebf23SPascal Paillet {
81155ebf23SPascal Paillet return clk_set_rate(cpu_opp.clock, cpu_opp.dvfs[opp].freq_khz * 1000);
82155ebf23SPascal Paillet }
83155ebf23SPascal Paillet
set_opp_voltage(unsigned int opp)84155ebf23SPascal Paillet static TEE_Result set_opp_voltage(unsigned int opp)
85155ebf23SPascal Paillet {
86155ebf23SPascal Paillet return regulator_set_voltage(cpu_opp.regul, cpu_opp.dvfs[opp].volt_uv);
87155ebf23SPascal Paillet }
88155ebf23SPascal Paillet
895abc2963SPascal Paillet /*
905abc2963SPascal Paillet * This function returns true if the given OPP voltage can be managed.
915abc2963SPascal Paillet * If the exact voltage value is not supported by the regulator,
925abc2963SPascal Paillet * the function may adjust the input parameter volt_uv to a higher
935abc2963SPascal Paillet * supported value and still return true.
945abc2963SPascal Paillet */
opp_voltage_is_supported(struct regulator * regul,uint32_t * volt_uv)955abc2963SPascal Paillet static bool opp_voltage_is_supported(struct regulator *regul, uint32_t *volt_uv)
965abc2963SPascal Paillet {
975abc2963SPascal Paillet int target_volt_uv = 0;
985abc2963SPascal Paillet int new_volt_uv = 0;
995abc2963SPascal Paillet int min_uv = 0;
1005abc2963SPascal Paillet int max_uv = 0;
1015abc2963SPascal Paillet struct regulator_voltages_desc *desc = NULL;
1025abc2963SPascal Paillet const int *levels = NULL;
1035abc2963SPascal Paillet TEE_Result res = TEE_ERROR_GENERIC;
1045abc2963SPascal Paillet
1055abc2963SPascal Paillet assert(*volt_uv < INT_MAX);
1065abc2963SPascal Paillet target_volt_uv = (int)*volt_uv;
1075abc2963SPascal Paillet
1085abc2963SPascal Paillet res = regulator_supported_voltages(regul, &desc, &levels);
1095abc2963SPascal Paillet if (res) {
1105abc2963SPascal Paillet regulator_get_range(regul, &min_uv, &max_uv);
1115abc2963SPascal Paillet if (target_volt_uv > max_uv)
1125abc2963SPascal Paillet return false;
1135abc2963SPascal Paillet if (target_volt_uv < min_uv)
1145abc2963SPascal Paillet *volt_uv = min_uv;
1155abc2963SPascal Paillet return true;
1165abc2963SPascal Paillet }
1175abc2963SPascal Paillet
1185abc2963SPascal Paillet if (desc->type == VOLTAGE_TYPE_FULL_LIST) {
1195abc2963SPascal Paillet unsigned int i = 0;
1205abc2963SPascal Paillet
1215abc2963SPascal Paillet for (i = 0 ; i < desc->num_levels; i++) {
1225abc2963SPascal Paillet if (levels[i] >= target_volt_uv) {
1235abc2963SPascal Paillet new_volt_uv = levels[i];
1245abc2963SPascal Paillet break;
1255abc2963SPascal Paillet }
1265abc2963SPascal Paillet }
1275abc2963SPascal Paillet if (new_volt_uv == 0)
1285abc2963SPascal Paillet return false;
1295abc2963SPascal Paillet
1305abc2963SPascal Paillet } else if (desc->type == VOLTAGE_TYPE_INCREMENT) {
1315abc2963SPascal Paillet int min = levels[0];
1325abc2963SPascal Paillet int max = levels[1];
1335abc2963SPascal Paillet int step = levels[2];
1345abc2963SPascal Paillet
1355abc2963SPascal Paillet if (new_volt_uv > max)
1365abc2963SPascal Paillet return false;
1375abc2963SPascal Paillet
1385abc2963SPascal Paillet new_volt_uv = min +
1395abc2963SPascal Paillet DIV_ROUND_UP(target_volt_uv - min, step) * step;
1405abc2963SPascal Paillet } else {
1415abc2963SPascal Paillet return false;
1425abc2963SPascal Paillet }
1435abc2963SPascal Paillet
1445abc2963SPascal Paillet *volt_uv = new_volt_uv;
1455abc2963SPascal Paillet
1465abc2963SPascal Paillet return true;
1475abc2963SPascal Paillet }
1485abc2963SPascal Paillet
set_clock_then_voltage(unsigned int opp)149155ebf23SPascal Paillet static TEE_Result set_clock_then_voltage(unsigned int opp)
150155ebf23SPascal Paillet {
151155ebf23SPascal Paillet TEE_Result res = TEE_ERROR_GENERIC;
152155ebf23SPascal Paillet
153155ebf23SPascal Paillet res = set_opp_clk_rate(opp);
154155ebf23SPascal Paillet if (res)
155155ebf23SPascal Paillet return res;
156155ebf23SPascal Paillet
157155ebf23SPascal Paillet #ifdef CFG_STM32MP13
158155ebf23SPascal Paillet if (cpu_opp.dvfs[opp].volt_uv <= PWR_MPU_RAM_LOW_SPEED_THRESHOLD)
159155ebf23SPascal Paillet io_setbits32(stm32_pwr_base() + PWR_CR1_OFF,
160155ebf23SPascal Paillet PWR_CR1_MPU_RAM_LOW_SPEED);
161155ebf23SPascal Paillet #endif
162155ebf23SPascal Paillet
163155ebf23SPascal Paillet res = set_opp_voltage(opp);
164155ebf23SPascal Paillet if (res) {
165155ebf23SPascal Paillet /* Restore previous OPP */
166155ebf23SPascal Paillet #ifdef CFG_STM32MP13
167155ebf23SPascal Paillet if (cpu_opp.dvfs[cpu_opp.current_opp].volt_uv >
168155ebf23SPascal Paillet PWR_MPU_RAM_LOW_SPEED_THRESHOLD)
169155ebf23SPascal Paillet io_clrbits32(stm32_pwr_base() + PWR_CR1_OFF,
170155ebf23SPascal Paillet PWR_CR1_MPU_RAM_LOW_SPEED);
171155ebf23SPascal Paillet #endif
172155ebf23SPascal Paillet
173155ebf23SPascal Paillet if (set_opp_clk_rate(cpu_opp.current_opp))
174155ebf23SPascal Paillet panic();
175155ebf23SPascal Paillet
176155ebf23SPascal Paillet return res;
177155ebf23SPascal Paillet }
178155ebf23SPascal Paillet
179155ebf23SPascal Paillet return TEE_SUCCESS;
180155ebf23SPascal Paillet }
181155ebf23SPascal Paillet
set_voltage_then_clock(unsigned int opp)182155ebf23SPascal Paillet static TEE_Result set_voltage_then_clock(unsigned int opp)
183155ebf23SPascal Paillet {
184155ebf23SPascal Paillet TEE_Result res = TEE_ERROR_GENERIC;
185155ebf23SPascal Paillet
186155ebf23SPascal Paillet res = set_opp_voltage(opp);
187155ebf23SPascal Paillet if (res)
188155ebf23SPascal Paillet return res;
189155ebf23SPascal Paillet
190155ebf23SPascal Paillet #ifdef CFG_STM32MP13
191155ebf23SPascal Paillet if (cpu_opp.dvfs[opp].volt_uv > PWR_MPU_RAM_LOW_SPEED_THRESHOLD)
192155ebf23SPascal Paillet io_clrbits32(stm32_pwr_base() + PWR_CR1_OFF,
193155ebf23SPascal Paillet PWR_CR1_MPU_RAM_LOW_SPEED);
194155ebf23SPascal Paillet #endif
195155ebf23SPascal Paillet
196155ebf23SPascal Paillet res = set_opp_clk_rate(opp);
197155ebf23SPascal Paillet if (res) {
198155ebf23SPascal Paillet /* Restore previous OPP */
199155ebf23SPascal Paillet #ifdef CFG_STM32MP13
200155ebf23SPascal Paillet if (cpu_opp.dvfs[cpu_opp.current_opp].volt_uv <=
201155ebf23SPascal Paillet PWR_MPU_RAM_LOW_SPEED_THRESHOLD)
202155ebf23SPascal Paillet io_setbits32(stm32_pwr_base() + PWR_CR1_OFF,
203155ebf23SPascal Paillet PWR_CR1_MPU_RAM_LOW_SPEED);
204155ebf23SPascal Paillet #endif
205155ebf23SPascal Paillet
206155ebf23SPascal Paillet if (set_opp_voltage(cpu_opp.current_opp))
207155ebf23SPascal Paillet panic();
208155ebf23SPascal Paillet
209155ebf23SPascal Paillet return res;
210155ebf23SPascal Paillet }
211155ebf23SPascal Paillet
212155ebf23SPascal Paillet return TEE_SUCCESS;
213155ebf23SPascal Paillet }
214155ebf23SPascal Paillet
stm32_cpu_opp_set_level(unsigned int level)215155ebf23SPascal Paillet TEE_Result stm32_cpu_opp_set_level(unsigned int level)
216155ebf23SPascal Paillet {
217155ebf23SPascal Paillet unsigned int current_level = 0;
218155ebf23SPascal Paillet TEE_Result res = TEE_ERROR_GENERIC;
219155ebf23SPascal Paillet unsigned int opp = 0;
220155ebf23SPascal Paillet
221155ebf23SPascal Paillet DMSG("Set OPP to %ukHz", level);
222155ebf23SPascal Paillet
223155ebf23SPascal Paillet if (!cpu_opp.opp_count)
224155ebf23SPascal Paillet return TEE_ERROR_GENERIC;
225155ebf23SPascal Paillet
226155ebf23SPascal Paillet mutex_lock(&cpu_opp_mu);
227155ebf23SPascal Paillet
228155ebf23SPascal Paillet current_level = stm32_cpu_opp_level(cpu_opp.current_opp);
229155ebf23SPascal Paillet
230155ebf23SPascal Paillet if (level == current_level) {
231155ebf23SPascal Paillet mutex_unlock(&cpu_opp_mu);
232155ebf23SPascal Paillet return TEE_SUCCESS;
233155ebf23SPascal Paillet }
234155ebf23SPascal Paillet
235155ebf23SPascal Paillet for (opp = 0; opp < cpu_opp.opp_count; opp++)
236155ebf23SPascal Paillet if (level == cpu_opp.dvfs[opp].freq_khz)
237155ebf23SPascal Paillet break;
238155ebf23SPascal Paillet
239155ebf23SPascal Paillet if (opp == cpu_opp.opp_count) {
240155ebf23SPascal Paillet mutex_unlock(&cpu_opp_mu);
241155ebf23SPascal Paillet return TEE_ERROR_BAD_PARAMETERS;
242155ebf23SPascal Paillet }
243155ebf23SPascal Paillet
244155ebf23SPascal Paillet if (level < current_level)
245155ebf23SPascal Paillet res = set_clock_then_voltage(opp);
246155ebf23SPascal Paillet else
247155ebf23SPascal Paillet res = set_voltage_then_clock(opp);
248155ebf23SPascal Paillet
249155ebf23SPascal Paillet if (res)
250155ebf23SPascal Paillet EMSG("Failed to set OPP to %ukHz", level);
251155ebf23SPascal Paillet else
252155ebf23SPascal Paillet cpu_opp.current_opp = opp;
253155ebf23SPascal Paillet
254155ebf23SPascal Paillet mutex_unlock(&cpu_opp_mu);
255155ebf23SPascal Paillet
256155ebf23SPascal Paillet return res;
257155ebf23SPascal Paillet }
258155ebf23SPascal Paillet
stm32_cpu_opp_read_level(unsigned int * level)259155ebf23SPascal Paillet TEE_Result stm32_cpu_opp_read_level(unsigned int *level)
260155ebf23SPascal Paillet {
261155ebf23SPascal Paillet if (!cpu_opp.opp_count) {
262155ebf23SPascal Paillet EMSG("No CPU OPP defined");
263155ebf23SPascal Paillet return TEE_ERROR_GENERIC;
264155ebf23SPascal Paillet }
265155ebf23SPascal Paillet
266155ebf23SPascal Paillet *level = stm32_cpu_opp_level(cpu_opp.current_opp);
267155ebf23SPascal Paillet
268155ebf23SPascal Paillet return TEE_SUCCESS;
269155ebf23SPascal Paillet }
270155ebf23SPascal Paillet
stm32_cpu_opp_is_supported(const void * fdt,int subnode)271*2bfcd5deSPascal Paillet static TEE_Result stm32_cpu_opp_is_supported(const void *fdt, int subnode)
272*2bfcd5deSPascal Paillet {
273*2bfcd5deSPascal Paillet const fdt32_t *cuint32 = NULL;
274*2bfcd5deSPascal Paillet uint32_t opp = 0;
275*2bfcd5deSPascal Paillet
276*2bfcd5deSPascal Paillet cuint32 = fdt_getprop(fdt, subnode, "opp-supported-hw", NULL);
277*2bfcd5deSPascal Paillet if (!cuint32) {
278*2bfcd5deSPascal Paillet DMSG("Can't find property opp-supported-hw");
279*2bfcd5deSPascal Paillet return TEE_ERROR_GENERIC;
280*2bfcd5deSPascal Paillet }
281*2bfcd5deSPascal Paillet
282*2bfcd5deSPascal Paillet opp = fdt32_to_cpu(*cuint32);
283*2bfcd5deSPascal Paillet if (!stm32mp_supports_cpu_opp(opp)) {
284*2bfcd5deSPascal Paillet DMSG("Not supported opp-supported-hw %#"PRIx32, opp);
285*2bfcd5deSPascal Paillet return TEE_ERROR_NOT_SUPPORTED;
286*2bfcd5deSPascal Paillet }
287*2bfcd5deSPascal Paillet
288*2bfcd5deSPascal Paillet return TEE_SUCCESS;
289*2bfcd5deSPascal Paillet }
290*2bfcd5deSPascal Paillet
cpu_opp_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * hdl __unused)291155ebf23SPascal Paillet static TEE_Result cpu_opp_pm(enum pm_op op, unsigned int pm_hint,
292155ebf23SPascal Paillet const struct pm_callback_handle *hdl __unused)
293155ebf23SPascal Paillet {
294155ebf23SPascal Paillet assert(op == PM_OP_SUSPEND || op == PM_OP_RESUME);
295155ebf23SPascal Paillet
296155ebf23SPascal Paillet /* nothing to do if RCC clock tree is not lost */
297155ebf23SPascal Paillet if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
298155ebf23SPascal Paillet return TEE_SUCCESS;
299155ebf23SPascal Paillet
300155ebf23SPascal Paillet if (op == PM_OP_RESUME) {
301155ebf23SPascal Paillet unsigned long clk_cpu = 0;
302155ebf23SPascal Paillet unsigned int opp = cpu_opp.current_opp;
303155ebf23SPascal Paillet
304155ebf23SPascal Paillet DMSG("Resume to OPP %u", opp);
305155ebf23SPascal Paillet
306155ebf23SPascal Paillet clk_cpu = clk_get_rate(cpu_opp.clock);
307155ebf23SPascal Paillet assert(clk_cpu);
308155ebf23SPascal Paillet if (cpu_opp.dvfs[opp].freq_khz * 1000 >= clk_cpu)
309155ebf23SPascal Paillet return set_voltage_then_clock(opp);
310155ebf23SPascal Paillet else
311155ebf23SPascal Paillet return set_clock_then_voltage(opp);
312155ebf23SPascal Paillet }
313155ebf23SPascal Paillet
314155ebf23SPascal Paillet return TEE_SUCCESS;
315155ebf23SPascal Paillet }
316155ebf23SPascal Paillet DECLARE_KEEP_PAGER(cpu_opp_pm);
317155ebf23SPascal Paillet
stm32_cpu_opp_get_dt_subnode(const void * fdt,int node)318155ebf23SPascal Paillet static TEE_Result stm32_cpu_opp_get_dt_subnode(const void *fdt, int node)
319155ebf23SPascal Paillet {
320155ebf23SPascal Paillet const fdt64_t *cuint64 = NULL;
321155ebf23SPascal Paillet const fdt32_t *cuint32 = NULL;
322155ebf23SPascal Paillet uint64_t freq_hz = 0;
323155ebf23SPascal Paillet uint64_t freq_khz = 0;
324155ebf23SPascal Paillet uint64_t freq_khz_opp_def = 0;
325155ebf23SPascal Paillet uint32_t volt_uv = 0;
326155ebf23SPascal Paillet unsigned long clk_cpu = 0;
327155ebf23SPascal Paillet unsigned int i = 0;
328155ebf23SPascal Paillet int subnode = 0;
329155ebf23SPascal Paillet TEE_Result res = TEE_ERROR_GENERIC;
330155ebf23SPascal Paillet
331155ebf23SPascal Paillet cpu_opp.dvfs = calloc(CFG_STM32MP_OPP_COUNT, sizeof(*cpu_opp.dvfs));
332155ebf23SPascal Paillet if (!cpu_opp.dvfs)
333155ebf23SPascal Paillet return TEE_ERROR_OUT_OF_MEMORY;
334155ebf23SPascal Paillet
335155ebf23SPascal Paillet cpu_opp.opp_count = CFG_STM32MP_OPP_COUNT;
336155ebf23SPascal Paillet
337155ebf23SPascal Paillet fdt_for_each_subnode(subnode, fdt, node) {
338155ebf23SPascal Paillet cuint64 = fdt_getprop(fdt, subnode, "opp-hz", NULL);
339155ebf23SPascal Paillet if (!cuint64) {
340155ebf23SPascal Paillet EMSG("Missing opp-hz in node %s",
341155ebf23SPascal Paillet fdt_get_name(fdt, subnode, NULL));
342155ebf23SPascal Paillet res = TEE_ERROR_GENERIC;
343155ebf23SPascal Paillet goto err;
344155ebf23SPascal Paillet }
345155ebf23SPascal Paillet
346155ebf23SPascal Paillet freq_hz = fdt64_to_cpu(*cuint64);
347155ebf23SPascal Paillet freq_khz = freq_hz / ULL(1000);
348155ebf23SPascal Paillet if (freq_khz > (uint64_t)UINT32_MAX) {
349155ebf23SPascal Paillet EMSG("Invalid opp-hz %"PRIu64" in node %s",
350155ebf23SPascal Paillet freq_khz, fdt_get_name(fdt, subnode, NULL));
351155ebf23SPascal Paillet res = TEE_ERROR_GENERIC;
352155ebf23SPascal Paillet goto err;
353155ebf23SPascal Paillet }
354155ebf23SPascal Paillet
355155ebf23SPascal Paillet cuint32 = fdt_getprop(fdt, subnode, "opp-microvolt", NULL);
356155ebf23SPascal Paillet if (!cuint32) {
357155ebf23SPascal Paillet EMSG("Missing opp-microvolt in node %s",
358155ebf23SPascal Paillet fdt_get_name(fdt, subnode, NULL));
359155ebf23SPascal Paillet res = TEE_ERROR_GENERIC;
360155ebf23SPascal Paillet goto err;
361155ebf23SPascal Paillet }
362155ebf23SPascal Paillet
363155ebf23SPascal Paillet volt_uv = fdt32_to_cpu(*cuint32);
364155ebf23SPascal Paillet
365*2bfcd5deSPascal Paillet /* skip OPP when the SOC does not support it */
366*2bfcd5deSPascal Paillet if (stm32_cpu_opp_is_supported(fdt, subnode) != TEE_SUCCESS) {
367*2bfcd5deSPascal Paillet DMSG("Skip SoC OPP %"PRIu64"kHz/%"PRIu32"uV",
368*2bfcd5deSPascal Paillet freq_khz, volt_uv);
369*2bfcd5deSPascal Paillet cpu_opp.opp_count--;
370*2bfcd5deSPascal Paillet continue;
371*2bfcd5deSPascal Paillet }
372*2bfcd5deSPascal Paillet
3735abc2963SPascal Paillet /* skip OPP when voltage is not supported */
3745abc2963SPascal Paillet if (!opp_voltage_is_supported(cpu_opp.regul, &volt_uv)) {
3755abc2963SPascal Paillet DMSG("Skip volt OPP %"PRIu64"kHz/%"PRIu32"uV",
3765abc2963SPascal Paillet freq_khz, volt_uv);
3775abc2963SPascal Paillet cpu_opp.opp_count--;
3785abc2963SPascal Paillet continue;
3795abc2963SPascal Paillet }
3805abc2963SPascal Paillet
381155ebf23SPascal Paillet if (i == cpu_opp.opp_count) {
382155ebf23SPascal Paillet EMSG("Too many OPP defined in node %s",
383155ebf23SPascal Paillet fdt_get_name(fdt, node, NULL));
384155ebf23SPascal Paillet res = TEE_ERROR_GENERIC;
385155ebf23SPascal Paillet goto err;
386155ebf23SPascal Paillet }
387155ebf23SPascal Paillet
388155ebf23SPascal Paillet cpu_opp.dvfs[i].freq_khz = freq_khz;
389155ebf23SPascal Paillet cpu_opp.dvfs[i].volt_uv = volt_uv;
390155ebf23SPascal Paillet
391155ebf23SPascal Paillet DMSG("Found OPP %u (%"PRIu64"kHz/%"PRIu32"uV) from DT",
392155ebf23SPascal Paillet i, freq_khz, volt_uv);
393155ebf23SPascal Paillet
394155ebf23SPascal Paillet /* Select the max "st,opp-default" node as current OPP */
395155ebf23SPascal Paillet if (fdt_getprop(fdt, subnode, "st,opp-default", NULL) &&
396155ebf23SPascal Paillet freq_khz > freq_khz_opp_def) {
397155ebf23SPascal Paillet cpu_opp.current_opp = i;
398155ebf23SPascal Paillet freq_khz_opp_def = freq_khz;
399155ebf23SPascal Paillet }
400155ebf23SPascal Paillet
401155ebf23SPascal Paillet i++;
402155ebf23SPascal Paillet }
403155ebf23SPascal Paillet
404155ebf23SPascal Paillet /* At least one OPP node shall have a "st,opp-default" property */
405155ebf23SPascal Paillet if (freq_khz_opp_def == 0) {
406155ebf23SPascal Paillet EMSG("No default OPP found");
407155ebf23SPascal Paillet res = TEE_ERROR_GENERIC;
408155ebf23SPascal Paillet goto err;
409155ebf23SPascal Paillet }
410155ebf23SPascal Paillet
411155ebf23SPascal Paillet /* Use the highest default OPP as sustained freq */
412155ebf23SPascal Paillet cpu_opp.sustained_freq_khz = freq_khz_opp_def;
413155ebf23SPascal Paillet
414155ebf23SPascal Paillet /* Apply the current OPP */
415155ebf23SPascal Paillet DMSG("Set OPP to %"PRIu64"kHz", freq_khz_opp_def);
416155ebf23SPascal Paillet clk_cpu = clk_get_rate(cpu_opp.clock);
417155ebf23SPascal Paillet assert(clk_cpu);
418155ebf23SPascal Paillet if (freq_khz_opp_def * ULL(1000) > clk_cpu)
419155ebf23SPascal Paillet res = set_voltage_then_clock(cpu_opp.current_opp);
420155ebf23SPascal Paillet else
421155ebf23SPascal Paillet res = set_clock_then_voltage(cpu_opp.current_opp);
422155ebf23SPascal Paillet
423155ebf23SPascal Paillet if (res) {
424155ebf23SPascal Paillet EMSG("Failed to set default OPP %u", cpu_opp.current_opp);
425155ebf23SPascal Paillet goto err;
426155ebf23SPascal Paillet }
427155ebf23SPascal Paillet
428155ebf23SPascal Paillet register_pm_driver_cb(cpu_opp_pm, NULL, "cpu-opp");
429155ebf23SPascal Paillet
430155ebf23SPascal Paillet return TEE_SUCCESS;
431155ebf23SPascal Paillet
432155ebf23SPascal Paillet err:
433155ebf23SPascal Paillet free(cpu_opp.dvfs);
434155ebf23SPascal Paillet cpu_opp.dvfs = NULL;
435155ebf23SPascal Paillet cpu_opp.opp_count = 0;
436155ebf23SPascal Paillet
437155ebf23SPascal Paillet return res;
438155ebf23SPascal Paillet }
439155ebf23SPascal Paillet
440155ebf23SPascal Paillet static TEE_Result
stm32_cpu_init(const void * fdt,int node,const void * compat_data __unused)441155ebf23SPascal Paillet stm32_cpu_init(const void *fdt, int node, const void *compat_data __unused)
442155ebf23SPascal Paillet {
443155ebf23SPascal Paillet const fdt32_t *cuint = NULL;
444155ebf23SPascal Paillet int opp_node = 0;
445155ebf23SPascal Paillet int len = 0;
446155ebf23SPascal Paillet uint32_t phandle = 0;
447155ebf23SPascal Paillet TEE_Result res = TEE_SUCCESS;
448155ebf23SPascal Paillet
449155ebf23SPascal Paillet cuint = fdt_getprop(fdt, node, "operating-points-v2", &len);
450155ebf23SPascal Paillet if (!cuint || len != sizeof(uint32_t)) {
451155ebf23SPascal Paillet DMSG("No CPU operating points");
452155ebf23SPascal Paillet return TEE_SUCCESS;
453155ebf23SPascal Paillet }
454155ebf23SPascal Paillet
455155ebf23SPascal Paillet res = clk_dt_get_by_index(fdt, node, 0, &cpu_opp.clock);
456155ebf23SPascal Paillet if (res)
457155ebf23SPascal Paillet return res;
458155ebf23SPascal Paillet
459155ebf23SPascal Paillet res = regulator_dt_get_supply(fdt, node, "cpu", &cpu_opp.regul);
460155ebf23SPascal Paillet if (res)
461155ebf23SPascal Paillet return res;
462155ebf23SPascal Paillet
463155ebf23SPascal Paillet phandle = fdt32_to_cpu(*cuint);
464155ebf23SPascal Paillet opp_node = fdt_node_offset_by_phandle(fdt, phandle);
465155ebf23SPascal Paillet
466155ebf23SPascal Paillet return stm32_cpu_opp_get_dt_subnode(fdt, opp_node);
467155ebf23SPascal Paillet }
468155ebf23SPascal Paillet
469155ebf23SPascal Paillet static const struct dt_device_match stm32_cpu_match_table[] = {
470155ebf23SPascal Paillet { .compatible = "arm,cortex-a7" },
471155ebf23SPascal Paillet { .compatible = "arm,cortex-a35" },
472155ebf23SPascal Paillet { }
473155ebf23SPascal Paillet };
474155ebf23SPascal Paillet
475155ebf23SPascal Paillet DEFINE_DT_DRIVER(stm32_cpu_dt_driver) = {
476155ebf23SPascal Paillet .name = "stm32-cpu",
477155ebf23SPascal Paillet .match_table = stm32_cpu_match_table,
478155ebf23SPascal Paillet .probe = &stm32_cpu_init,
479155ebf23SPascal Paillet };
480155ebf23SPascal Paillet
stm32_cpu_initcall(void)481155ebf23SPascal Paillet static TEE_Result stm32_cpu_initcall(void)
482155ebf23SPascal Paillet {
483155ebf23SPascal Paillet TEE_Result res = TEE_ERROR_GENERIC;
484155ebf23SPascal Paillet const void *fdt = get_embedded_dt();
485155ebf23SPascal Paillet int node = fdt_path_offset(fdt, "/cpus/cpu@0");
486155ebf23SPascal Paillet
487155ebf23SPascal Paillet if (node < 0) {
488155ebf23SPascal Paillet EMSG("cannot find /cpus/cpu@0 node");
489155ebf23SPascal Paillet panic();
490155ebf23SPascal Paillet }
491155ebf23SPascal Paillet
492155ebf23SPascal Paillet res = dt_driver_maybe_add_probe_node(fdt, node);
493155ebf23SPascal Paillet if (res) {
494155ebf23SPascal Paillet EMSG("Failed on node %s with %#"PRIx32,
495155ebf23SPascal Paillet fdt_get_name(fdt, node, NULL), res);
496155ebf23SPascal Paillet panic();
497155ebf23SPascal Paillet }
498155ebf23SPascal Paillet
499155ebf23SPascal Paillet return TEE_SUCCESS;
500155ebf23SPascal Paillet }
501155ebf23SPascal Paillet
502155ebf23SPascal Paillet early_init(stm32_cpu_initcall);
503155ebf23SPascal Paillet
504