1 /*
2 * Copyright (c) 2020 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/sys/printk.h>
8 #include <zephyr/types.h>
9 #include <zephyr/pm/device.h>
10 #include <zephyr/pm/device_runtime.h>
11 #include <zephyr/ztest.h>
12 #include <ksched.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/pm/pm.h>
15 #include "dummy_driver.h"
16
17 #define SLEEP_MSEC 100
18 #define SLEEP_TIMEOUT K_MSEC(SLEEP_MSEC)
19
20 /* for checking power suspend and resume order between system and devices */
21 static bool enter_low_power;
22 static bool notify_app_entry;
23 static bool notify_app_exit;
24 static bool set_pm;
25 static bool leave_idle;
26 static bool idle_entered;
27 static bool testing_device_runtime;
28 static bool testing_device_order;
29 static bool testing_device_lock;
30 static bool testing_force_state;
31
32 enum pm_state forced_state;
33 static const struct device *device_dummy;
34 static struct dummy_driver_api *api;
35
36 static const struct device *const device_a =
37 DEVICE_DT_GET(DT_INST(0, test_device_pm));
38 static const struct device *const device_c =
39 DEVICE_DT_GET(DT_INST(2, test_device_pm));
40
41 /*
42 * According with the initialization level, devices A, B and C are
43 * initialized in the following order A -> B -> C.
44 *
45 * The power management subsystem uses this order to suspend and resume
46 * devices. Devices are suspended in the reverse order:
47 *
48 * C -> B -> A
49 *
50 * While resuming uses the initialization order:
51 *
52 * A -> B -> C
53 *
54 * This test checks if these order is correct checking devices A and C states
55 * when suspending / resuming device B.
56 */
57
device_a_pm_action(const struct device * dev,enum pm_device_action pm_action)58 static int device_a_pm_action(const struct device *dev,
59 enum pm_device_action pm_action)
60 {
61 ARG_UNUSED(dev);
62 ARG_UNUSED(pm_action);
63
64 return 0;
65 }
66
67 PM_DEVICE_DT_DEFINE(DT_INST(0, test_device_pm), device_a_pm_action);
68
69 DEVICE_DT_DEFINE(DT_INST(0, test_device_pm), NULL,
70 PM_DEVICE_DT_GET(DT_INST(0, test_device_pm)), NULL, NULL,
71 PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
72 NULL);
73
74
device_b_pm_action(const struct device * dev,enum pm_device_action pm_action)75 static int device_b_pm_action(const struct device *dev,
76 enum pm_device_action pm_action)
77 {
78 enum pm_device_state state_a;
79 enum pm_device_state state_c;
80
81 if (!testing_device_order) {
82 return 0;
83 }
84
85 (void)pm_device_state_get(device_a, &state_a);
86 (void)pm_device_state_get(device_c, &state_c);
87
88 switch (pm_action) {
89 case PM_DEVICE_ACTION_RESUME:
90 /* Check if device C is still suspended */
91 zassert_equal(state_c, PM_DEVICE_STATE_SUSPENDED,
92 "Inconsistent states");
93 /* Check if device A is already active */
94 zassert_equal(state_a, PM_DEVICE_STATE_ACTIVE,
95 "Inconsistent states");
96 break;
97 case PM_DEVICE_ACTION_SUSPEND:
98 /* Check if device C is already suspended */
99 zassert_equal(state_c, PM_DEVICE_STATE_SUSPENDED,
100 "Inconsistent states");
101 /* Check if device A is still active */
102 zassert_equal(state_a, PM_DEVICE_STATE_ACTIVE,
103 "Inconsistent states");
104 break;
105 default:
106 break;
107 }
108
109 return 0;
110 }
111
112 PM_DEVICE_DT_DEFINE(DT_INST(1, test_device_pm), device_b_pm_action);
113
114 DEVICE_DT_DEFINE(DT_INST(1, test_device_pm), NULL,
115 PM_DEVICE_DT_GET(DT_INST(1, test_device_pm)), NULL, NULL,
116 PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
117 NULL);
118
device_c_pm_action(const struct device * dev,enum pm_device_action pm_action)119 static int device_c_pm_action(const struct device *dev,
120 enum pm_device_action pm_action)
121 {
122 ARG_UNUSED(dev);
123 ARG_UNUSED(pm_action);
124
125 return 0;
126 }
127
128 PM_DEVICE_DT_DEFINE(DT_INST(2, test_device_pm), device_c_pm_action);
129
130 DEVICE_DT_DEFINE(DT_INST(2, test_device_pm), NULL,
131 PM_DEVICE_DT_GET(DT_INST(2, test_device_pm)), NULL, NULL,
132 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
133 NULL);
134
device_init_failed(const struct device * dev)135 static int device_init_failed(const struct device *dev)
136 {
137 ARG_UNUSED(dev);
138
139 /* Return error to mark device as not ready. */
140 return -EIO;
141 }
142
device_d_pm_action(const struct device * dev,enum pm_device_action pm_action)143 static int device_d_pm_action(const struct device *dev,
144 enum pm_device_action pm_action)
145 {
146 ARG_UNUSED(dev);
147 ARG_UNUSED(pm_action);
148
149 zassert_unreachable("Entered PM handler for unready device");
150
151 return 0;
152 }
153
154 PM_DEVICE_DT_DEFINE(DT_INST(3, test_device_pm), device_d_pm_action);
155
156 DEVICE_DT_DEFINE(DT_INST(3, test_device_pm), device_init_failed,
157 PM_DEVICE_DT_GET(DT_INST(3, test_device_pm)), NULL, NULL,
158 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
159 NULL);
160
pm_state_set(enum pm_state state,uint8_t substate_id)161 void pm_state_set(enum pm_state state, uint8_t substate_id)
162 {
163 ARG_UNUSED(substate_id);
164 ARG_UNUSED(state);
165
166 enum pm_device_state device_power_state;
167
168 /* If testing device order this function does not need to anything */
169 if (testing_device_order) {
170 return;
171 }
172
173 if (testing_device_lock) {
174 pm_device_state_get(device_a, &device_power_state);
175
176 /*
177 * If the device has its state locked the device has
178 * to be ACTIVE
179 */
180 zassert_true(device_power_state == PM_DEVICE_STATE_ACTIVE,
181 NULL);
182 return;
183 }
184
185 if (testing_force_state) {
186 /* if forced to given power state was called */
187 set_pm = true;
188 zassert_equal(state, forced_state, NULL);
189 testing_force_state = false;
190 }
191
192 /* at this point, notify_pm_state_entry() implemented in
193 * this file has been called and set_pm should have been set
194 */
195 zassert_true(set_pm == true,
196 "Notification to enter suspend was not sent to the App");
197
198 /* this function is called after devices enter low power state */
199 pm_device_state_get(device_dummy, &device_power_state);
200
201 if (testing_device_runtime) {
202 /* If device runtime is enable, the device should still be
203 * active
204 */
205 zassert_true(device_power_state == PM_DEVICE_STATE_ACTIVE);
206 } else {
207 /* at this point, devices have been deactivated */
208 zassert_false(device_power_state == PM_DEVICE_STATE_ACTIVE);
209 }
210
211 /* this function is called when system entering low power state, so
212 * parameter state should not be PM_STATE_ACTIVE
213 */
214 zassert_false(state == PM_STATE_ACTIVE,
215 "Entering low power state with a wrong parameter");
216 }
217
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)218 void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
219 {
220 ARG_UNUSED(state);
221 ARG_UNUSED(substate_id);
222
223 /* pm_system_suspend is entered with irq locked
224 * unlock irq before leave pm_system_suspend
225 */
226 irq_unlock(0);
227 }
228
229 /* Our PM policy handler */
pm_policy_next_state(uint8_t cpu,int32_t ticks)230 const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
231 {
232 static struct pm_state_info info;
233
234 ARG_UNUSED(cpu);
235
236 /* make sure this is idle thread */
237 zassert_true(z_is_idle_thread_object(_current));
238 zassert_true(ticks == _kernel.idle);
239 zassert_false(k_can_yield());
240 idle_entered = true;
241
242 if (enter_low_power) {
243 enter_low_power = false;
244 notify_app_entry = true;
245 info.state = PM_STATE_SUSPEND_TO_IDLE;
246 } else {
247 /* only test pm_policy_next_state()
248 * no PM operation done
249 */
250 info.state = PM_STATE_ACTIVE;
251 }
252 return &info;
253 }
254
255 /* implement in application, called by idle thread */
notify_pm_state_entry(enum pm_state state)256 static void notify_pm_state_entry(enum pm_state state)
257 {
258 enum pm_device_state device_power_state;
259
260 /* enter suspend */
261 zassert_true(notify_app_entry == true,
262 "Notification to enter suspend was not sent to the App");
263 zassert_true(z_is_idle_thread_object(_current));
264 zassert_equal(state, PM_STATE_SUSPEND_TO_IDLE);
265
266 pm_device_state_get(device_dummy, &device_power_state);
267 if (testing_device_runtime) {
268 /* If device runtime is enable, the device should still be
269 * active
270 */
271 zassert_true(device_power_state == PM_DEVICE_STATE_ACTIVE);
272 } else {
273 /* at this point, devices should not be active */
274 zassert_false(device_power_state == PM_DEVICE_STATE_ACTIVE);
275 }
276 set_pm = true;
277 notify_app_exit = true;
278 }
279
280 /* implement in application, called by idle thread */
notify_pm_state_exit(enum pm_state state)281 static void notify_pm_state_exit(enum pm_state state)
282 {
283 enum pm_device_state device_power_state;
284
285 /* leave suspend */
286 zassert_true(notify_app_exit == true,
287 "Notification to leave suspend was not sent to the App");
288 zassert_true(z_is_idle_thread_object(_current));
289 zassert_equal(state, PM_STATE_SUSPEND_TO_IDLE);
290
291 /* at this point, devices are active again*/
292 pm_device_state_get(device_dummy, &device_power_state);
293 zassert_equal(device_power_state, PM_DEVICE_STATE_ACTIVE);
294 leave_idle = true;
295
296 }
297
298 /*
299 * @brief test power idle
300 *
301 * @details
302 * - The global idle routine executes when no other work is available
303 * - The idle routine provide a timeout parameter to the suspend routine
304 * indicating the amount of time guaranteed to expire before the next
305 * timeout, pm_policy_next_state() handle this parameter.
306 * - In this case, pm_policy_next_sate() return PM_STATE_ACTIVE,
307 * so there is no low power operation happen.
308 *
309 * @see pm_policy_next_state()
310 *
311 * @ingroup power_tests
312 */
ZTEST(power_management_1cpu,test_power_idle)313 ZTEST(power_management_1cpu, test_power_idle)
314 {
315 TC_PRINT("give way to idle thread\n");
316 k_sleep(SLEEP_TIMEOUT);
317 zassert_true(idle_entered, "Never entered idle thread");
318 }
319
320 static struct pm_notifier notifier = {
321 .state_entry = notify_pm_state_entry,
322 .state_exit = notify_pm_state_exit,
323 };
324
325 /*
326 * @brief test power state transition
327 *
328 * @details
329 * - The system support control of power state ordering between
330 * subsystems and devices
331 * - The application can control system power state transitions in idle thread
332 * through pm_notify_pm_state_entry and pm_notify_pm_state_exit
333 *
334 * @see pm_notify_pm_state_entry(), pm_notify_pm_state_exit()
335 *
336 * @ingroup power_tests
337 */
ZTEST(power_management_1cpu,test_power_state_trans)338 ZTEST(power_management_1cpu, test_power_state_trans)
339 {
340 int ret;
341
342 pm_notifier_register(¬ifier);
343 enter_low_power = true;
344
345 ret = pm_device_runtime_disable(device_dummy);
346 zassert_true(ret == 0, "Failed to disable device runtime PM");
347
348 /* give way to idle thread */
349 k_sleep(SLEEP_TIMEOUT);
350 zassert_true(leave_idle);
351
352 ret = pm_device_runtime_enable(device_dummy);
353 zassert_true(ret == 0, "Failed to enable device runtime PM");
354
355 pm_notifier_unregister(¬ifier);
356 }
357
358 /*
359 * @brief notification between system and device
360 *
361 * @details
362 * - device driver notify its power state change by pm_device_runtime_get and
363 * pm_device_runtime_put_async
364 * - system inform device system power state change through device interface
365 * pm_action_cb
366 *
367 * @see pm_device_runtime_get(), pm_device_runtime_put_async(),
368 * pm_device_action_run(), pm_device_state_get()
369 *
370 * @ingroup power_tests
371 */
ZTEST(power_management_1cpu,test_power_state_notification)372 ZTEST(power_management_1cpu, test_power_state_notification)
373 {
374 int ret;
375 enum pm_device_state device_power_state;
376
377 pm_notifier_register(¬ifier);
378 enter_low_power = true;
379
380 ret = api->open(device_dummy);
381 zassert_true(ret == 0, "Fail to open device");
382
383 pm_device_state_get(device_dummy, &device_power_state);
384 zassert_equal(device_power_state, PM_DEVICE_STATE_ACTIVE);
385
386
387 /* The device should be kept active even when the system goes idle */
388 testing_device_runtime = true;
389
390 k_sleep(SLEEP_TIMEOUT);
391 zassert_true(leave_idle);
392
393 api->close(device_dummy);
394 pm_device_state_get(device_dummy, &device_power_state);
395 zassert_equal(device_power_state, PM_DEVICE_STATE_SUSPENDED);
396 pm_notifier_unregister(¬ifier);
397 testing_device_runtime = false;
398 }
399
ZTEST(power_management_1cpu,test_device_order)400 ZTEST(power_management_1cpu, test_device_order)
401 {
402 zassert_true(device_is_ready(device_a), "device a not ready");
403 zassert_true(device_is_ready(device_c), "device c not ready");
404
405 testing_device_order = true;
406 enter_low_power = true;
407
408 k_sleep(SLEEP_TIMEOUT);
409
410 testing_device_order = false;
411 }
412
413 /**
414 * @brief Test the device busy APIs.
415 */
ZTEST(power_management_1cpu,test_busy)416 ZTEST(power_management_1cpu, test_busy)
417 {
418 bool busy;
419
420 busy = pm_device_is_any_busy();
421 zassert_false(busy);
422
423 pm_device_busy_set(device_dummy);
424
425 busy = pm_device_is_any_busy();
426 zassert_true(busy);
427
428 busy = pm_device_is_busy(device_dummy);
429 zassert_true(busy);
430
431 pm_device_busy_clear(device_dummy);
432
433 busy = pm_device_is_any_busy();
434 zassert_false(busy);
435
436 busy = pm_device_is_busy(device_dummy);
437 zassert_false(busy);
438 }
439
ZTEST(power_management_1cpu,test_device_state_lock)440 ZTEST(power_management_1cpu, test_device_state_lock)
441 {
442 pm_device_state_lock(device_a);
443 zassert_true(pm_device_state_is_locked(device_a));
444
445 testing_device_lock = true;
446 enter_low_power = true;
447
448 k_sleep(SLEEP_TIMEOUT);
449
450 pm_device_state_unlock(device_a);
451
452 testing_device_lock = false;
453 }
454
ZTEST(power_management_1cpu,test_empty_states)455 ZTEST(power_management_1cpu, test_empty_states)
456 {
457 const struct pm_state_info *cpu_states;
458 uint8_t state = pm_state_cpu_get_all(1u, &cpu_states);
459
460 zassert_equal(state, 0, NULL);
461 }
462
ZTEST(power_management_1cpu,test_force_state)463 ZTEST(power_management_1cpu, test_force_state)
464 {
465 forced_state = PM_STATE_STANDBY;
466 bool ret = pm_state_force(0, &(struct pm_state_info) {forced_state, 0, 0});
467
468 zassert_equal(ret, true, "Error in force state");
469
470 testing_force_state = true;
471 k_sleep(K_SECONDS(1U));
472 }
473
power_management_1cpu_teardown(void * data)474 void power_management_1cpu_teardown(void *data)
475 {
476 pm_notifier_unregister(¬ifier);
477 }
478
power_management_1cpu_setup(void)479 static void *power_management_1cpu_setup(void)
480 {
481 device_dummy = device_get_binding(DUMMY_DRIVER_NAME);
482 api = (struct dummy_driver_api *)device_dummy->api;
483 return NULL;
484 }
485
486 ZTEST_SUITE(power_management_1cpu, NULL, power_management_1cpu_setup,
487 ztest_simple_1cpu_before, ztest_simple_1cpu_after,
488 power_management_1cpu_teardown);
489