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:
Flavio Ceolin 2021-12-03 00:15:58 -08:00 committed by Anas Nashif
commit 5a7040f4ba
6 changed files with 264 additions and 0 deletions

View 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)

View 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>;
};
};

View file

@ -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"

View 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

View 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);
}

View file

@ -0,0 +1,4 @@
tests:
subsys.pm.power_domain:
platform_allow: native_posix
tags: pm