1 /*
2 * Copyright 2025 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/shell/shell.h>
9 #include <zephyr/pm/pm.h>
10 #include <zephyr/pm/policy.h>
11 #include <zephyr/logging/log.h>
12
13 LOG_MODULE_REGISTER(pm_cpu_shell, CONFIG_PM_LOG_LEVEL);
14
15 /* Supported states info from devicetree (CPU0) */
16 static const struct pm_state_info residency_info[] =
17 PM_STATE_INFO_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0));
18
cmd_cpu_states(const struct shell * sh,size_t argc,char ** argv)19 static int cmd_cpu_states(const struct shell *sh, size_t argc, char **argv)
20 {
21 ARG_UNUSED(argc);
22 ARG_UNUSED(argv);
23
24 /* sanity check for first */
25 if (ARRAY_SIZE(residency_info) == 0U) {
26 shell_warn(sh, "No pm states");
27 return -EINVAL;
28 }
29
30 shell_print(sh, "Supported Low Power States:");
31
32 ARRAY_FOR_EACH_PTR(residency_info, state_info) {
33 shell_print(sh,
34 " - State: %s, Substate: %d, Residency: %dus, Latency: %dus, PM Device Disabled: %s",
35 pm_state_to_str(state_info->state),
36 state_info->substate_id,
37 state_info->min_residency_us,
38 state_info->exit_latency_us,
39 state_info->pm_device_disabled ? "Yes" : "No");
40 }
41
42 return 0;
43 }
44
cmd_cpu_available(const struct shell * sh,size_t argc,char ** argv)45 static int cmd_cpu_available(const struct shell *sh, size_t argc, char **argv)
46 {
47 ARG_UNUSED(argc);
48 ARG_UNUSED(argv);
49
50 /* sanity check for first */
51 if (ARRAY_SIZE(residency_info) == 0U) {
52 shell_warn(sh, "No pm states");
53 return -EINVAL;
54 }
55
56 bool available;
57 bool locked;
58
59 shell_print(sh, "Check whether the low power states of the current core are supported:");
60
61 ARRAY_FOR_EACH_PTR(residency_info, state_info) {
62 available = pm_policy_state_is_available(state_info->state,
63 state_info->substate_id);
64 locked = pm_policy_state_lock_is_active(state_info->state,
65 state_info->substate_id);
66
67 shell_print(sh, " - %-16s sub=%-3u avail=%c lock=%c",
68 pm_state_to_str(state_info->state),
69 state_info->substate_id,
70 available ? 'Y' : 'N',
71 locked ? 'Y' : 'N');
72 }
73
74 return 0;
75 }
76
cmd_cpu_lock(const struct shell * sh,size_t argc,char ** argv)77 static int cmd_cpu_lock(const struct shell *sh, size_t argc, char **argv)
78 {
79 ARG_UNUSED(argc);
80
81 enum pm_state st;
82 uint8_t sub;
83 int err;
84
85 if (pm_state_from_str(argv[1], &st) < 0) {
86 shell_error(sh, "Unknown state: %s", argv[1]);
87 return -EINVAL;
88 }
89
90 sub = shell_strtoul(argv[2], 0, &err);
91 if (err < 0) {
92 shell_error(sh, "Unable to parse input (err %d), substate", err);
93 return err;
94 }
95
96 pm_policy_state_lock_get(st, sub);
97
98 shell_print(sh, "Locked %s sub=%u", argv[1], sub);
99
100 return 0;
101 }
102
cmd_cpu_unlock(const struct shell * sh,size_t argc,char ** argv)103 static int cmd_cpu_unlock(const struct shell *sh, size_t argc, char **argv)
104 {
105 ARG_UNUSED(argc);
106
107 enum pm_state st;
108 uint8_t sub;
109 int err = 0;
110
111 if (pm_state_from_str(argv[1], &st) < 0) {
112 shell_error(sh, "Unknown state: %s", argv[1]);
113 return -EINVAL;
114 }
115
116 sub = shell_strtoul(argv[2], 0, &err);
117 if (err < 0) {
118 shell_error(sh, "Unable to parse input (err %d), substate", err);
119 return err;
120 }
121
122 pm_policy_state_lock_put(st, sub);
123
124 shell_print(sh, "Unlocked %s sub=%u", argv[1], sub);
125
126 return 0;
127 }
128
cmd_cpu_idle(const struct shell * sh,size_t argc,char ** argv)129 static int cmd_cpu_idle(const struct shell *sh, size_t argc, char **argv)
130 {
131 ARG_UNUSED(argc);
132
133 int err;
134 uint32_t ms;
135
136 ms = shell_strtoul(argv[1], 0, &err);
137 if (err < 0) {
138 shell_error(sh, "Unable to parse input (err %d), times", err);
139 return err;
140 }
141
142 k_msleep(ms);
143
144 shell_print(sh, "Woke up");
145
146 return 0;
147 }
148
149 SHELL_STATIC_SUBCMD_SET_CREATE(
150 cpu_cmds,
151 SHELL_CMD_ARG(states, NULL,
152 SHELL_HELP("List supported CPU low power states", ""), cmd_cpu_states, 1, 0),
153 SHELL_CMD_ARG(available, NULL,
154 SHELL_HELP("Show availability/locks for each state", ""), cmd_cpu_available, 1, 0),
155 SHELL_CMD_ARG(lock, NULL,
156 SHELL_HELP("Lock a state", "<state> <substate>"), cmd_cpu_lock, 2, 1),
157 SHELL_CMD_ARG(unlock, NULL,
158 SHELL_HELP("Unlock a state", "<state> <substate>"), cmd_cpu_unlock, 2, 1),
159 SHELL_CMD_ARG(idle, NULL,
160 SHELL_HELP("Sleep current thread to let PM work", "<ms>"), cmd_cpu_idle, 2, 0),
161 SHELL_SUBCMD_SET_END
162 );
163
164 SHELL_CMD_REGISTER(cpu, &cpu_cmds, "CPU core and power state commands", NULL);
165