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(&notifier);
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(&notifier);
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(&notifier);
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(&notifier);
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(&notifier);
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