diff options
author | Al Semjonovs <asemjonovs@google.com> | 2022-07-21 10:24:11 -0600 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-08-25 21:35:08 +0000 |
commit | e1b26246ac39d2bfa2dc3e3eff2830eb937dc295 (patch) | |
tree | 5b50f6a78d5fa1c70e188a770a7171ba4b46ff9a /zephyr/mock | |
parent | 014712bd56067a786545507ae1fd615954e864b0 (diff) | |
download | chrome-ec-e1b26246ac39d2bfa2dc3e3eff2830eb937dc295.tar.gz |
zephyr: Mock power sequence driver
Mock power sequence handling
BUG=None
BRANCH=NONE
TEST=./twister -T zephyr/test
Signed-off-by: Al Semjonovs <asemjonovs@google.com>
Change-Id: I8ec3198abfb069501bed2c5aa661e31f780e2c34
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3833564
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Yuval Peress <peress@google.com>
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Diffstat (limited to 'zephyr/mock')
-rw-r--r-- | zephyr/mock/CMakeLists.txt | 7 | ||||
-rw-r--r-- | zephyr/mock/Kconfig | 11 | ||||
-rw-r--r-- | zephyr/mock/include/mock/power.h | 26 | ||||
-rw-r--r-- | zephyr/mock/power.c | 264 |
4 files changed, 308 insertions, 0 deletions
diff --git a/zephyr/mock/CMakeLists.txt b/zephyr/mock/CMakeLists.txt new file mode 100644 index 0000000000..8dd75d036e --- /dev/null +++ b/zephyr/mock/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright 2022 The Chromium OS Authors. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +zephyr_library_sources_ifdef(CONFIG_POWER_SEQUENCE_MOCK power.c) + +cros_ec_library_include_directories(include) diff --git a/zephyr/mock/Kconfig b/zephyr/mock/Kconfig new file mode 100644 index 0000000000..fd04fd773d --- /dev/null +++ b/zephyr/mock/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2022 The ChromiumOS Authors. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +config POWER_SEQUENCE_MOCK + bool "Use a mocked power sequence driver." + help + A simplified power sequence driver that invokes startup/shutdown + and suspend/resume hooks in appropriate state transitions. Any + request that comes in mid sequence is pended and ran after final + state is reached. diff --git a/zephyr/mock/include/mock/power.h b/zephyr/mock/include/mock/power.h new file mode 100644 index 0000000000..8c6f4235c2 --- /dev/null +++ b/zephyr/mock/include/mock/power.h @@ -0,0 +1,26 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef ZEPHYR_TEST_MOCK_POWER_H +#define ZEPHYR_TEST_MOCK_POWER_H + +#include <zephyr/fff.h> +#include "power.h" + +/* Mocks for ec/power/common.c and board specific implementations */ +DECLARE_FAKE_VALUE_FUNC(enum power_state, power_handle_state, enum power_state); +DECLARE_FAKE_VOID_FUNC(chipset_force_shutdown, enum chipset_shutdown_reason); +DECLARE_FAKE_VOID_FUNC(chipset_power_on); +DECLARE_FAKE_VALUE_FUNC(int, command_power, int, char **); + +enum power_state power_handle_state_custom_fake(enum power_state state); + +void chipset_force_shutdown_custom_fake(enum chipset_shutdown_reason reason); + +void chipset_power_on_custom_fake(void); + +int command_power_custom_fake(int argc, char **argv); + +#endif /* ZEPHYR_TEST_MOCK_POWER_H */ diff --git a/zephyr/mock/power.c b/zephyr/mock/power.c new file mode 100644 index 0000000000..dbea522cab --- /dev/null +++ b/zephyr/mock/power.c @@ -0,0 +1,264 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <zephyr/logging/log.h> +#include <zephyr/ztest.h> + +#include "hooks.h" +#include "lid_switch.h" +#include "power.h" +#include "task.h" +#include "util.h" + +#include "mock/power.h" + +LOG_MODULE_REGISTER(mock_power); + +/* Mocks for ec/power/common.c and board specific implementations */ +DEFINE_FAKE_VALUE_FUNC(enum power_state, power_handle_state, enum power_state); +DEFINE_FAKE_VOID_FUNC(chipset_force_shutdown, enum chipset_shutdown_reason); +DEFINE_FAKE_VOID_FUNC(chipset_power_on); +DEFINE_FAKE_VALUE_FUNC(int, command_power, int, char **); + +#define MOCK_POWER_LIST(FAKE) \ + { \ + FAKE(power_handle_state); \ + FAKE(chipset_force_shutdown); \ + FAKE(chipset_power_on); \ + FAKE(command_power); \ + } + +/** + * @brief Reset all the fakes before each test. + */ +static void mock_power_rule_before(const struct ztest_unit_test *test, + void *data) +{ + ARG_UNUSED(test); + ARG_UNUSED(data); + + MOCK_POWER_LIST(RESET_FAKE); + + FFF_RESET_HISTORY(); + + power_handle_state_fake.custom_fake = power_handle_state_custom_fake; + chipset_force_shutdown_fake.custom_fake = + chipset_force_shutdown_custom_fake; + chipset_power_on_fake.custom_fake = chipset_power_on_custom_fake; + command_power_fake.custom_fake = command_power_custom_fake; +} + +ZTEST_RULE(mock_power_rule, mock_power_rule_before, NULL); + +enum power_request_t { + POWER_REQ_NONE, + POWER_REQ_OFF, + POWER_REQ_ON, + POWER_REQ_COUNT, +}; + +static const char *power_req_name[POWER_REQ_COUNT] = { + "none", + "OFF", + "ON", +}; + +static enum power_request_t current_power_request = POWER_REQ_NONE; +static enum power_request_t pending_power_request = POWER_REQ_NONE; + +void handle_power_request(enum power_request_t req) +{ + if (current_power_request == POWER_REQ_NONE) { + current_power_request = req; + } else if (current_power_request != req) { + LOG_INF("MOCK: Handling %s, pend %s request", + power_req_name[current_power_request], + power_req_name[req]); + pending_power_request = req; + } +} + +void power_request_complete(void) +{ + current_power_request = pending_power_request; + pending_power_request = POWER_REQ_NONE; +} + +void chipset_force_shutdown_custom_fake(enum chipset_shutdown_reason reason) +{ + LOG_INF("MOCK %s(%d)", __func__, reason); + handle_power_request(POWER_REQ_OFF); + task_wake(TASK_ID_CHIPSET); +} + +void chipset_power_on_custom_fake(void) +{ + if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { + handle_power_request(POWER_REQ_ON); + task_wake(TASK_ID_CHIPSET); + } +} + +/* Power states that we can report */ +enum power_state_t { + PSTATE_UNKNOWN, + PSTATE_OFF, + PSTATE_ON, + PSTATE_COUNT, +}; + +static const char *const state_name[] = { + "unknown", + "OFF", + "ON", +}; + +int command_power_custom_fake(int argc, char **argv) +{ + int v, req; + + if (argc < 2) { + enum power_state_t state; + + state = PSTATE_UNKNOWN; + if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) + state = PSTATE_OFF; + if (chipset_in_state(CHIPSET_STATE_ON)) + state = PSTATE_ON; + ccprintf("%s\n", state_name[state]); + + return EC_SUCCESS; + } + + if (!parse_bool(argv[1], &v)) { + return EC_ERROR_PARAM1; + } + req = v ? POWER_REQ_ON : POWER_REQ_OFF; + handle_power_request(req); + LOG_INF("MOCK: Requesting power %s\n", power_req_name[req]); + task_wake(TASK_ID_CHIPSET); + + return EC_SUCCESS; +} + +static void mock_lid_event(void) +{ + /* Power task only cares about lid-open events */ + if (!lid_is_open()) { + return; + } + + LOG_INF("MOCK: lid opened %s\n", power_req_name[POWER_REQ_ON]); + handle_power_request(POWER_REQ_ON); + task_wake(TASK_ID_CHIPSET); +} +DECLARE_HOOK(HOOK_LID_CHANGE, mock_lid_event, HOOK_PRIO_DEFAULT); + +enum power_state power_handle_state_custom_fake(enum power_state state) +{ + enum power_state new_state = state; + enum power_request_t request = current_power_request; + + switch (state) { + /* Steady states */ + case POWER_G3: + if (current_power_request == POWER_REQ_ON) { + new_state = POWER_G3S5; + } else if (current_power_request == POWER_REQ_OFF) { + new_state = state; + power_request_complete(); + } + break; + case POWER_S5: /* System is soft-off */ + if (current_power_request == POWER_REQ_ON) { + new_state = POWER_S5S3; + } else if (current_power_request == POWER_REQ_OFF) { + /* S5 timeout should transition to G3 */ + } + break; + case POWER_S3: /* Suspend; RAM on, processor is asleep */ + if (current_power_request == POWER_REQ_ON) { + new_state = POWER_S3S0; + } else if (current_power_request == POWER_REQ_OFF) { + new_state = POWER_S3S5; + } + break; + case POWER_S0: /* System is on */ + if (current_power_request == POWER_REQ_ON) { + new_state = state; + power_request_complete(); + + sleep_notify_transition(SLEEP_NOTIFY_RESUME, + HOOK_CHIPSET_RESUME); + } else if (current_power_request == POWER_REQ_OFF) { + new_state = POWER_S0S3; + } + break; + case POWER_S4: /* System is suspended to disk */ +#ifdef CONFIG_POWER_S0IX + case POWER_S0ix: +#endif + new_state = state; + break; + /* Transitions */ + case POWER_S3S0: /* S3 -> S0 */ +#ifdef CONFIG_CHIPSET_RESUME_INIT_HOOK + hook_notify(HOOK_CHIPSET_RESUME_INIT); +#endif + hook_notify(HOOK_CHIPSET_RESUME); + sleep_resume_transition(); + power_request_complete(); + disable_sleep(SLEEP_MASK_AP_RUN); + new_state = POWER_S0; + break; + case POWER_S0S3: /* S0 -> S3 */ + sleep_notify_transition(SLEEP_NOTIFY_SUSPEND, + HOOK_CHIPSET_SUSPEND); + hook_notify(HOOK_CHIPSET_SUSPEND); +#ifdef CONFIG_CHIPSET_RESUME_INIT_HOOK + hook_notify(HOOK_CHIPSET_SUSPEND_COMPLETE); +#endif + sleep_suspend_transition(); + enable_sleep(SLEEP_MASK_AP_RUN); + new_state = POWER_S3; + break; + case POWER_S5S3: /* S5 -> S3 (skips S4 on non-Intel systems) */ + hook_notify(HOOK_CHIPSET_PRE_INIT); + hook_notify(HOOK_CHIPSET_STARTUP); + sleep_reset_tracking(); + new_state = POWER_S3; + break; + case POWER_S3S5: /* S3 -> S5 (skips S4 on non-Intel systems) */ + hook_notify(HOOK_CHIPSET_SHUTDOWN); + hook_notify(HOOK_CHIPSET_SHUTDOWN_COMPLETE); + new_state = POWER_S5; + break; + case POWER_G3S5: /* G3 -> S5 (at system init time) */ + new_state = POWER_S5; + break; + case POWER_S5G3: /* S5 -> G3 */ + new_state = POWER_G3; + break; +#ifdef CONFIG_POWER_S0IX + case POWER_S0ixS0: /* S0ix -> S0 */ + new_state = POWER_S0; + break; + case POWER_S0S0ix: /* S0 -> S0ix */ + new_state = POWER_S0ix; + break; +#endif + case POWER_S5S4: /* S5 -> S4 */ + case POWER_S4S3: /* S4 -> S3 */ + case POWER_S3S4: /* S3 -> S4 */ + case POWER_S4S5: /* S4 -> S5 */ + default: + break; + } + + LOG_INF("MOCK: power request=%u, state=%u -> new_state=%u\n", request, + state, new_state); + + return new_state; +} |