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