tests: pm: Add a power domain test
Add simple test to exercise power domain behavior with device runtime. Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
This commit is contained in:
parent
f6f710b142
commit
5a7040f4ba
6 changed files with 264 additions and 0 deletions
8
tests/subsys/pm/power_domain/CMakeLists.txt
Normal file
8
tests/subsys/pm/power_domain/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Copyright (c) 2021 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
project(power_domain)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE src/main.c)
|
24
tests/subsys/pm/power_domain/app.overlay
Normal file
24
tests/subsys/pm/power_domain/app.overlay
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
test_domain: test_domain {
|
||||||
|
compatible = "power-domain";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
test_dev_a: test_dev_a {
|
||||||
|
compatible = "test-device-pm";
|
||||||
|
status = "okay";
|
||||||
|
power-domain = <&test_domain>;
|
||||||
|
};
|
||||||
|
|
||||||
|
test_dev_b: test_dev_b {
|
||||||
|
compatible = "test-device-pm";
|
||||||
|
status = "okay";
|
||||||
|
power-domain = <&test_domain>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Copyright (c) 2021, Intel Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
include: [base.yaml, pm.yaml]
|
||||||
|
|
||||||
|
description: |
|
||||||
|
This binding provides resources required to build and run the
|
||||||
|
tests/subsys/pm/power_domain test in Zephyr.
|
||||||
|
|
||||||
|
compatible: "test-device-pm"
|
6
tests/subsys/pm/power_domain/prj.conf
Normal file
6
tests/subsys/pm/power_domain/prj.conf
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
CONFIG_ZTEST=y
|
||||||
|
CONFIG_PM=y
|
||||||
|
CONFIG_PM_DEVICE=y
|
||||||
|
CONFIG_POWER_DOMAIN=y
|
||||||
|
CONFIG_PM_DEVICE_RUNTIME=y
|
||||||
|
CONFIG_MP_NUM_CPUS=1
|
212
tests/subsys/pm/power_domain/src/main.c
Normal file
212
tests/subsys/pm/power_domain/src/main.c
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Intel Corporation.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ztest.h>
|
||||||
|
#include <pm/device.h>
|
||||||
|
#include <pm/device_runtime.h>
|
||||||
|
|
||||||
|
static int testing_domain_on_notitication;
|
||||||
|
static int testing_domain_off_notitication;
|
||||||
|
|
||||||
|
#define TEST_DOMAIN DT_NODELABEL(test_domain)
|
||||||
|
#define TEST_DEVA DT_NODELABEL(test_dev_a)
|
||||||
|
#define TEST_DEVB DT_NODELABEL(test_dev_b)
|
||||||
|
|
||||||
|
static const struct device *domain, *deva, *devb;
|
||||||
|
|
||||||
|
static int dev_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int domain_pm_action(const struct device *dev,
|
||||||
|
enum pm_device_action action)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case PM_DEVICE_ACTION_RESUME:
|
||||||
|
/* Switch power on */
|
||||||
|
pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_ON, NULL);
|
||||||
|
break;
|
||||||
|
case PM_DEVICE_ACTION_SUSPEND:
|
||||||
|
pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_OFF, NULL);
|
||||||
|
break;
|
||||||
|
case PM_DEVICE_ACTION_TURN_ON:
|
||||||
|
__fallthrough;
|
||||||
|
case PM_DEVICE_ACTION_TURN_OFF:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int deva_pm_action(const struct device *dev,
|
||||||
|
enum pm_device_action pm_action)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
if (testing_domain_on_notitication > 0) {
|
||||||
|
if (pm_action == PM_DEVICE_ACTION_TURN_ON) {
|
||||||
|
testing_domain_on_notitication--;
|
||||||
|
}
|
||||||
|
} else if (testing_domain_off_notitication > 0) {
|
||||||
|
if (pm_action == PM_DEVICE_ACTION_TURN_OFF) {
|
||||||
|
testing_domain_off_notitication--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device B will return -ENOTSUP for TURN_ON and TURN_OFF actions.
|
||||||
|
* This way we can check if the subsystem properly handled its state.
|
||||||
|
*/
|
||||||
|
static int devb_pm_action(const struct device *dev,
|
||||||
|
enum pm_device_action pm_action)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
if (testing_domain_on_notitication > 0) {
|
||||||
|
if (pm_action == PM_DEVICE_ACTION_TURN_ON) {
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
testing_domain_on_notitication--;
|
||||||
|
}
|
||||||
|
} else if (testing_domain_off_notitication > 0) {
|
||||||
|
if (pm_action == PM_DEVICE_ACTION_TURN_OFF) {
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
testing_domain_off_notitication--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PM_DEVICE_DT_DEFINE(TEST_DOMAIN, domain_pm_action);
|
||||||
|
DEVICE_DT_DEFINE(TEST_DOMAIN, dev_init, PM_DEVICE_DT_GET(TEST_DOMAIN),
|
||||||
|
NULL, NULL, POST_KERNEL, 10, NULL);
|
||||||
|
|
||||||
|
PM_DEVICE_DT_DEFINE(TEST_DEVA, deva_pm_action);
|
||||||
|
DEVICE_DT_DEFINE(TEST_DEVA, dev_init, PM_DEVICE_DT_GET(TEST_DEVA),
|
||||||
|
NULL, NULL, POST_KERNEL, 20, NULL);
|
||||||
|
|
||||||
|
PM_DEVICE_DT_DEFINE(TEST_DEVB, devb_pm_action);
|
||||||
|
DEVICE_DT_DEFINE(TEST_DEVB, dev_init, PM_DEVICE_DT_GET(TEST_DEVB),
|
||||||
|
NULL, NULL, POST_KERNEL, 30, NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test the power domain behavior
|
||||||
|
*
|
||||||
|
* Scenarios tested:
|
||||||
|
*
|
||||||
|
* - get + put multiple devices under a domain
|
||||||
|
* - notification when domain state changes
|
||||||
|
*/
|
||||||
|
static void test_power_domain_device_runtime(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
enum pm_device_state state;
|
||||||
|
|
||||||
|
domain = DEVICE_DT_GET(TEST_DOMAIN);
|
||||||
|
deva = DEVICE_DT_GET(TEST_DEVA);
|
||||||
|
devb = DEVICE_DT_GET(TEST_DEVB);
|
||||||
|
|
||||||
|
pm_device_runtime_init_suspended(domain);
|
||||||
|
pm_device_runtime_init_suspended(deva);
|
||||||
|
pm_device_runtime_init_suspended(devb);
|
||||||
|
|
||||||
|
pm_device_runtime_enable(domain);
|
||||||
|
pm_device_runtime_enable(deva);
|
||||||
|
pm_device_runtime_enable(devb);
|
||||||
|
|
||||||
|
/* At this point all devices should be SUSPENDED */
|
||||||
|
pm_device_state_get(domain, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_SUSPENDED, NULL);
|
||||||
|
|
||||||
|
pm_device_state_get(deva, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_SUSPENDED, NULL);
|
||||||
|
|
||||||
|
pm_device_state_get(devb, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_SUSPENDED, NULL);
|
||||||
|
|
||||||
|
/* Now test if "get" a device will resume the domain */
|
||||||
|
ret = pm_device_runtime_get(deva);
|
||||||
|
zassert_equal(ret, 0, NULL);
|
||||||
|
|
||||||
|
pm_device_state_get(deva, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_ACTIVE, NULL);
|
||||||
|
|
||||||
|
pm_device_state_get(domain, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_ACTIVE, NULL);
|
||||||
|
|
||||||
|
ret = pm_device_runtime_get(devb);
|
||||||
|
zassert_equal(ret, 0, NULL);
|
||||||
|
|
||||||
|
ret = pm_device_runtime_put(deva);
|
||||||
|
zassert_equal(ret, 0, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The domain has to still be active since device B
|
||||||
|
* is still in use.
|
||||||
|
*/
|
||||||
|
pm_device_state_get(domain, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_ACTIVE, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now the domain should be suspended since there is no
|
||||||
|
* one using it.
|
||||||
|
*/
|
||||||
|
ret = pm_device_runtime_put(devb);
|
||||||
|
zassert_equal(ret, 0, NULL);
|
||||||
|
|
||||||
|
pm_device_state_get(domain, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_SUSPENDED, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With the domain suspended the device state should be OFF, since
|
||||||
|
* the power was completely cut.
|
||||||
|
*/
|
||||||
|
pm_device_state_get(devb, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_OFF, NULL);
|
||||||
|
|
||||||
|
pm_device_state_get(deva, &state);
|
||||||
|
zassert_equal(state, PM_DEVICE_STATE_OFF, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now lets test that devices are notified when the domain
|
||||||
|
* changes its state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Three devices has to get the notification */
|
||||||
|
testing_domain_on_notitication = 2;
|
||||||
|
ret = pm_device_runtime_get(domain);
|
||||||
|
zassert_equal(ret, 0, NULL);
|
||||||
|
|
||||||
|
zassert_equal(testing_domain_on_notitication, 0, NULL);
|
||||||
|
|
||||||
|
testing_domain_off_notitication = 2;
|
||||||
|
ret = pm_device_runtime_put(domain);
|
||||||
|
zassert_equal(ret, 0, NULL);
|
||||||
|
|
||||||
|
zassert_equal(testing_domain_off_notitication, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_main(void)
|
||||||
|
{
|
||||||
|
ztest_test_suite(power_domain_test,
|
||||||
|
ztest_1cpu_unit_test(test_power_domain_device_runtime));
|
||||||
|
|
||||||
|
ztest_run_test_suite(power_domain_test);
|
||||||
|
}
|
4
tests/subsys/pm/power_domain/testcase.yaml
Normal file
4
tests/subsys/pm/power_domain/testcase.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
tests:
|
||||||
|
subsys.pm.power_domain:
|
||||||
|
platform_allow: native_posix
|
||||||
|
tags: pm
|
Loading…
Add table
Add a link
Reference in a new issue