1 /*
2  * Copyright (c) 2018 Intel Corporation.
3  * Copyright (c) 2022 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/pm/policy.h>
9 #include <zephyr/sys_clock.h>
10 #include <zephyr/pm/device.h>
11 
12 extern int32_t max_latency_cyc;
13 
pm_policy_next_state(uint8_t cpu,int32_t ticks)14 const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
15 {
16 	int64_t cyc = -1;
17 	uint8_t num_cpu_states;
18 	const struct pm_state_info *cpu_states;
19 
20 #ifdef CONFIG_PM_NEED_ALL_DEVICES_IDLE
21 	if (pm_device_is_any_busy()) {
22 		return NULL;
23 	}
24 #endif
25 
26 	if (ticks != K_TICKS_FOREVER) {
27 		cyc = k_ticks_to_cyc_ceil32(ticks);
28 	}
29 
30 	num_cpu_states = pm_state_cpu_get_all(cpu, &cpu_states);
31 
32 	for (int16_t i = (int16_t)num_cpu_states - 1; i >= 0; i--) {
33 		const struct pm_state_info *state = &cpu_states[i];
34 		uint32_t min_residency_cyc, exit_latency_cyc;
35 
36 		/* check if there is a lock on state + substate */
37 		if (pm_policy_state_lock_is_active(state->state, state->substate_id)) {
38 			continue;
39 		}
40 
41 		min_residency_cyc = k_us_to_cyc_ceil32(state->min_residency_us);
42 		exit_latency_cyc = k_us_to_cyc_ceil32(state->exit_latency_us);
43 
44 		/* skip state if it brings too much latency */
45 		if ((max_latency_cyc >= 0) &&
46 		    (exit_latency_cyc >= max_latency_cyc)) {
47 			continue;
48 		}
49 
50 		if ((cyc < 0) ||
51 		    (cyc >= (min_residency_cyc + exit_latency_cyc))) {
52 			return state;
53 		}
54 	}
55 
56 	return NULL;
57 }
58