summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTing Shen <phoenixshen@google.com>2022-12-12 16:11:27 +0800
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-12-30 03:16:39 +0000
commit24e626913064568f0e74dc64dd5ab5483dbbb383 (patch)
treeffcf8e468795623313f320d734231a195cb30b70
parentc35dec39b6e43afc534509dc2726cffdefef8e60 (diff)
downloadchrome-ec-stabilize-15300.B-main.tar.gz
corsola: power sequence teststabilize-15300.B-main
Add a test to verify mt8186 power state machine behavior. power/mt8186.c has above 90% coverage after this CL. BUG=b:256575497 TEST=./twister -v -i --coverage -p native_posix -p unit_testing BRANCH=none Change-Id: I2f274697e83dfc50f6976b8f6d137df6c69da2b9 Signed-off-by: Ting Shen <phoenixshen@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4127103 Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com> Reviewed-by: Eric Yilun Lin <yllin@google.com> Tested-by: Ting Shen <phoenixshen@chromium.org> Commit-Queue: Ting Shen <phoenixshen@chromium.org>
-rw-r--r--power/mt8186.c10
-rw-r--r--zephyr/test/krabby/CMakeLists.txt6
-rw-r--r--zephyr/test/krabby/common.dtsi5
-rw-r--r--zephyr/test/krabby/include/test_state.h17
-rw-r--r--zephyr/test/krabby/krabby.default.overlay30
-rw-r--r--zephyr/test/krabby/prj.conf5
-rw-r--r--zephyr/test/krabby/src/fake.c2
-rw-r--r--zephyr/test/krabby/src/main.c35
-rw-r--r--zephyr/test/krabby/src/power_seq.c406
-rw-r--r--zephyr/test/krabby/src/stubs.c5
-rw-r--r--zephyr/test/krabby/testcase.yaml6
11 files changed, 512 insertions, 15 deletions
diff --git a/power/mt8186.c b/power/mt8186.c
index 723036a21f..00972e53a0 100644
--- a/power/mt8186.c
+++ b/power/mt8186.c
@@ -212,16 +212,6 @@ static void power_reset_host_sleep_state(void)
power_chipset_handle_host_sleep_event(HOST_SLEEP_EVENT_DEFAULT_RESET,
NULL);
}
-
-static void handle_chipset_reset(void)
-{
- if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
- CPRINTS("Chipset reset: exit s3");
- power_reset_host_sleep_state();
- task_wake(TASK_ID_CHIPSET);
- }
-}
-DECLARE_HOOK(HOOK_CHIPSET_RESET, handle_chipset_reset, HOOK_PRIO_FIRST);
#endif /* CONFIG_POWER_TRACK_HOST_SLEEP_STATE */
/*
diff --git a/zephyr/test/krabby/CMakeLists.txt b/zephyr/test/krabby/CMakeLists.txt
index 6e333dd7df..27b5c83002 100644
--- a/zephyr/test/krabby/CMakeLists.txt
+++ b/zephyr/test/krabby/CMakeLists.txt
@@ -8,7 +8,9 @@ project(krabby)
add_subdirectory(${PLATFORM_EC}/zephyr/test/test_utils test_utils)
-zephyr_include_directories("${PLATFORM_EC_PROGRAM_DIR}/corsola/include")
+zephyr_include_directories(
+ "${PLATFORM_EC_PROGRAM_DIR}/corsola/include"
+ include)
target_sources(app PRIVATE
src/stubs.c
@@ -18,6 +20,8 @@ target_sources(app PRIVATE
target_sources_ifdef(CONFIG_TEST_KRABBY
app PRIVATE
src/charger_workaround.c
+ src/main.c
+ src/power_seq.c
src/usb_mux_init.c
src/usbc_config.c
${PLATFORM_EC_PROGRAM_DIR}/corsola/src/ite_charger_workaround.c)
diff --git a/zephyr/test/krabby/common.dtsi b/zephyr/test/krabby/common.dtsi
index 9e94392561..e62b044bbc 100644
--- a/zephyr/test/krabby/common.dtsi
+++ b/zephyr/test/krabby/common.dtsi
@@ -64,6 +64,11 @@
batteries {
default_battery: lgc_ac17a8m {
compatible = "lgc,ac17a8m", "battery-smart";
+ /**
+ * this has to be strictly lower than the desired
+ * voltage in smart battery emulator (5000mV).
+ */
+ voltage_min = <4000>;
};
};
diff --git a/zephyr/test/krabby/include/test_state.h b/zephyr/test/krabby/include/test_state.h
new file mode 100644
index 0000000000..6a2ff6654f
--- /dev/null
+++ b/zephyr/test/krabby/include/test_state.h
@@ -0,0 +1,17 @@
+/* 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_KRABBY_INCLUDE_TEST_STATE_H_
+#define ZEPHYR_TEST_KRABBY_INCLUDE_TEST_STATE_H_
+
+#include <stdbool.h>
+
+struct test_state {
+ bool ec_app_main_run;
+};
+
+bool krabby_predicate_post_main(const void *state);
+
+#endif /* ZEPHYR_TEST_AP_POWER_INCLUDE_TEST_STATE_H_ */
diff --git a/zephyr/test/krabby/krabby.default.overlay b/zephyr/test/krabby/krabby.default.overlay
index 1e88870327..9893a5bcd2 100644
--- a/zephyr/test/krabby/krabby.default.overlay
+++ b/zephyr/test/krabby/krabby.default.overlay
@@ -6,8 +6,36 @@
#include "common.dtsi"
#include "../program/corsola/ite_gpio.dtsi"
#include "../program/corsola/ite_interrupts.dtsi"
+#include "../program/corsola/power_signal.dtsi"
/* remove pinctrl to avoid pull in too many unwanted dependency */
/delete-node/ &pinctrl;
-/delete-node/ &{/hibernate-wake-pins};
+/delete-node/ &int_usb_c0_ppc_bc12;
+/delete-node/ &int_volume_up;
+/delete-node/ &int_volume_down;
+/delete-node/ &int_tablet_mode;
+/delete-node/ &int_usba;
+/delete-node/ &int_wp;
+/delete-node/ &int_spi0_cs;
+/delete-node/ &int_x_ec_gpio2;
+/delete-node/ &int_ccd_mode_odl;
+/delete-node/ &int_base_imu;
+/delete-node/ &int_lid_imu;
+
+&{/aliases} {
+ /delete-property/ int-wp;
+};
+
+/* open-drain is not supported in gpio emul, re-config to push-pull */
+&ec_pmic_en_odl {
+ gpios = <&gpiod 0 (GPIO_OUTPUT_HIGH | GPIO_INPUT | GPIO_VOLTAGE_1P8)>;
+};
+&sys_rst_odl {
+ gpios = <&gpiog 1 GPIO_OUTPUT_LOW>;
+};
+
+/* set default gpio-emul state */
+&power_button_l {
+ gpios = <&gpioe 4 (GPIO_INPUT | GPIO_PULL_UP)>;
+};
diff --git a/zephyr/test/krabby/prj.conf b/zephyr/test/krabby/prj.conf
index 06e36261e9..a6aa5d13cd 100644
--- a/zephyr/test/krabby/prj.conf
+++ b/zephyr/test/krabby/prj.conf
@@ -22,7 +22,10 @@ CONFIG_PLATFORM_EC_CHARGE_RAMP_HW=y
CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY=49
CONFIG_PLATFORM_EC_HOOKS=y
CONFIG_PLATFORM_EC_HOSTCMD=y
-CONFIG_PLATFORM_EC_LID_SWITCH=n
+CONFIG_PLATFORM_EC_LID_SWITCH=y
+CONFIG_PLATFORM_EC_POWERSEQ_HOST_SLEEP=y
+CONFIG_PLATFORM_EC_POWER_BUTTON=y
+CONFIG_PLATFORM_EC_POWER_SLEEP_FAILURE_DETECTION=y
CONFIG_PLATFORM_EC_SWITCH=n
CONFIG_PLATFORM_EC_USBC=y
CONFIG_PLATFORM_EC_USB_CHARGER=y
diff --git a/zephyr/test/krabby/src/fake.c b/zephyr/test/krabby/src/fake.c
index 846f11eb9d..9baff6f74d 100644
--- a/zephyr/test/krabby/src/fake.c
+++ b/zephyr/test/krabby/src/fake.c
@@ -9,9 +9,7 @@
/* LCOV_EXCL_START */
-FAKE_VOID_FUNC(power_button_interrupt, enum gpio_signal);
FAKE_VOID_FUNC(button_interrupt, enum gpio_signal);
-FAKE_VOID_FUNC(lid_interrupt, enum gpio_signal);
FAKE_VOID_FUNC(chipset_reset_request_interrupt, enum gpio_signal);
FAKE_VOID_FUNC(power_signal_interrupt, enum gpio_signal);
FAKE_VOID_FUNC(chipset_watchdog_interrupt, enum gpio_signal);
diff --git a/zephyr/test/krabby/src/main.c b/zephyr/test/krabby/src/main.c
new file mode 100644
index 0000000000..2df530be93
--- /dev/null
+++ b/zephyr/test/krabby/src/main.c
@@ -0,0 +1,35 @@
+/* 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 "ec_app_main.h"
+#include "test_state.h"
+
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+bool krabby_predicate_post_main(const void *state)
+{
+ return ((struct test_state *)state)->ec_app_main_run;
+}
+
+void test_main(void)
+{
+ struct test_state state = {
+ .ec_app_main_run = false,
+ };
+
+ /* Run all the suites that depend on main not being called yet */
+ ztest_run_test_suites(&state);
+
+ ec_app_main();
+
+ state.ec_app_main_run = true;
+
+ /* Run all the suites that depend on main being called */
+ ztest_run_test_suites(&state);
+
+ /* Check that every suite ran */
+ ztest_verify_all_test_suites_ran();
+}
diff --git a/zephyr/test/krabby/src/power_seq.c b/zephyr/test/krabby/src/power_seq.c
new file mode 100644
index 0000000000..9f55baf278
--- /dev/null
+++ b/zephyr/test/krabby/src/power_seq.c
@@ -0,0 +1,406 @@
+/* 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 "common.h"
+#include "ec_tasks.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "power.h"
+#include "power_button.h"
+#include "system.h"
+#include "task.h"
+#include "test_state.h"
+#include "timer.h"
+
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/fff.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+FAKE_VOID_FUNC(chipset_pre_init_hook);
+DECLARE_HOOK(HOOK_CHIPSET_PRE_INIT, chipset_pre_init_hook, HOOK_PRIO_DEFAULT);
+FAKE_VOID_FUNC(chipset_startup_hook);
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, chipset_startup_hook, HOOK_PRIO_DEFAULT);
+FAKE_VOID_FUNC(chipset_resume_hook);
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, chipset_resume_hook, HOOK_PRIO_DEFAULT);
+FAKE_VALUE_FUNC(int, system_jumped_late);
+
+static void set_signal_state(enum power_state state)
+{
+ const struct gpio_dt_spec *ap_ec_sysrst_odl =
+ gpio_get_dt_spec(GPIO_AP_EC_SYSRST_ODL);
+ const struct gpio_dt_spec *ap_in_sleep_l =
+ gpio_get_dt_spec(GPIO_AP_IN_SLEEP_L);
+
+ switch (state) {
+ case POWER_S0:
+ gpio_emul_input_set(ap_in_sleep_l->port, ap_in_sleep_l->pin, 1);
+ gpio_emul_input_set(ap_ec_sysrst_odl->port,
+ ap_ec_sysrst_odl->pin, 1);
+ break;
+ case POWER_S3:
+ gpio_emul_input_set(ap_in_sleep_l->port, ap_in_sleep_l->pin, 0);
+ gpio_emul_input_set(ap_ec_sysrst_odl->port,
+ ap_ec_sysrst_odl->pin, 1);
+ break;
+ case POWER_G3:
+ gpio_emul_input_set(ap_in_sleep_l->port, ap_in_sleep_l->pin, 0);
+ gpio_emul_input_set(ap_ec_sysrst_odl->port,
+ ap_ec_sysrst_odl->pin, 0);
+ break;
+ default:
+ zassert_unreachable("state %d not supported", state);
+ }
+
+ task_wake(TASK_ID_CHIPSET);
+ k_sleep(K_SECONDS(1));
+}
+
+static void power_seq_before(void *f)
+{
+ /* Required for deferred callbacks to work */
+ set_test_runner_tid();
+
+ /* Start from G3 */
+ power_set_state(POWER_G3);
+ set_signal_state(POWER_G3);
+
+ RESET_FAKE(chipset_pre_init_hook);
+ RESET_FAKE(chipset_startup_hook);
+ RESET_FAKE(chipset_resume_hook);
+ RESET_FAKE(system_jumped_late);
+ FFF_RESET_HISTORY();
+}
+
+/* Normal boot sequence, G3 -> S3 -> S0 */
+ZTEST(power_seq, test_power_state_machine)
+{
+ /* G3 -> S3 */
+ power_set_state(POWER_G3);
+ set_signal_state(POWER_S3);
+ zassert_equal(power_get_state(), POWER_S3);
+
+ /* S3 -> S0 */
+ power_set_state(POWER_S3);
+ set_signal_state(POWER_S0);
+ zassert_equal(power_get_state(), POWER_S0);
+
+ /* S0 -> G3 */
+ power_set_state(POWER_S0);
+ set_signal_state(POWER_G3);
+ zassert_equal(power_get_state(), POWER_G3);
+}
+
+/* Verify power btn short press can boot the device */
+ZTEST(power_seq, test_power_btn_short_press)
+{
+ zassert_equal(power_get_state(), POWER_G3);
+
+ power_button_simulate_press(100);
+ k_sleep(K_SECONDS(1));
+
+ /* Verify that power state machine is able to reach S5S3, and back to G3
+ * because power signal is not changed
+ */
+ zassert_equal(chipset_pre_init_hook_fake.call_count, 1);
+ zassert_equal(chipset_startup_hook_fake.call_count, 0);
+ zassert_equal(power_get_state(), POWER_G3);
+}
+
+/* Verify lid open can boot the device */
+ZTEST(power_seq, test_lid_open)
+{
+ const struct gpio_dt_spec *lid_open = gpio_get_dt_spec(GPIO_LID_OPEN);
+
+ gpio_emul_input_set(lid_open->port, lid_open->pin, 0);
+ zassert_equal(power_get_state(), POWER_G3);
+
+ gpio_emul_input_set(lid_open->port, lid_open->pin, 1);
+ k_sleep(K_SECONDS(1));
+
+ /* Verify that power state machine is able to reach S5S3, and back to G3
+ * because power signal is not changed
+ */
+ zassert_equal(chipset_pre_init_hook_fake.call_count, 1);
+ zassert_equal(chipset_startup_hook_fake.call_count, 0);
+ zassert_equal(power_get_state(), POWER_G3);
+}
+
+/* Suspend, S0 -> S3 -> S0 */
+ZTEST(power_seq, test_host_sleep_success)
+{
+ host_clear_events(EC_HOST_EVENT_MASK(EC_HOST_EVENT_HANG_DETECT));
+
+ /* Boot AP */
+ set_signal_state(POWER_S0);
+ zassert_equal(power_get_state(), POWER_S0);
+
+ /* Suspend for 30 seconds */
+ zassert_ok(host_command_process(
+ &(struct host_cmd_handler_args)BUILD_HOST_COMMAND_PARAMS(
+ EC_CMD_HOST_SLEEP_EVENT, 0,
+ (struct ec_params_host_sleep_event){
+ .sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND })));
+ k_sleep(K_MSEC(1));
+ set_signal_state(POWER_S3);
+ k_sleep(K_SECONDS(30));
+ zassert_equal(power_get_state(), POWER_S3);
+
+ /* Resume */
+ set_signal_state(POWER_S0);
+ zassert_ok(host_command_process(
+ &(struct host_cmd_handler_args)BUILD_HOST_COMMAND_PARAMS(
+ EC_CMD_HOST_SLEEP_EVENT, 0,
+ (struct ec_params_host_sleep_event){
+ .sleep_event = HOST_SLEEP_EVENT_S3_RESUME })));
+ zassert_equal(power_get_state(), POWER_S0);
+
+ /* Verify that EC_HOST_EVENT_HANG_DETECT is not triggered */
+ zassert_false(host_is_event_set(EC_HOST_EVENT_HANG_DETECT));
+}
+
+/* Sleep hang, send EC_HOST_EVENT_HANG_DETECT */
+ZTEST(power_seq, test_host_sleep_hang)
+{
+ host_clear_events(EC_HOST_EVENT_MASK(EC_HOST_EVENT_HANG_DETECT));
+
+ /* Boot AP */
+ set_signal_state(POWER_S0);
+ zassert_equal(power_get_state(), POWER_S0);
+
+ /* Send HOST_SLEEP_EVENT_S3_SUSPEND and hang for 30 seconds */
+ zassert_ok(host_command_process(
+ &(struct host_cmd_handler_args)BUILD_HOST_COMMAND_PARAMS(
+ EC_CMD_HOST_SLEEP_EVENT, 0,
+ (struct ec_params_host_sleep_event){
+ .sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND })));
+ k_sleep(K_SECONDS(30));
+
+ /* Verify that EC_HOST_EVENT_HANG_DETECT is triggered */
+ zassert_true(host_is_event_set(EC_HOST_EVENT_HANG_DETECT));
+}
+
+/* Shutdown from EC, S0 -> S5 (8 secs) -> G3 */
+ZTEST(power_seq, test_force_shutdown)
+{
+ const struct gpio_dt_spec *sys_rst_odl =
+ gpio_get_dt_spec(GPIO_SYS_RST_ODL);
+ const struct gpio_dt_spec *ec_pmic_en_odl =
+ gpio_get_dt_spec(GPIO_EC_PMIC_EN_ODL);
+
+ gpio_set_level(GPIO_SYS_RST_ODL, 1);
+ gpio_set_level(GPIO_EC_PMIC_EN_ODL, 1);
+
+ /* Boot AP */
+ set_signal_state(POWER_S0);
+ zassert_equal(power_get_state(), POWER_S0);
+
+ /* Verify that ec resets ap and holds power button */
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_CONSOLE_CMD);
+ zassert_equal(gpio_emul_output_get(sys_rst_odl->port, sys_rst_odl->pin),
+ 0);
+ zassert_equal(gpio_emul_output_get(ec_pmic_en_odl->port,
+ ec_pmic_en_odl->pin),
+ 0);
+
+ /* Emulate AP power down (hw state G3, sw state unchanged),
+ * Verify power state stops at S5
+ */
+ set_signal_state(POWER_G3);
+ zassert_equal(power_get_state(), POWER_S5);
+
+ /* Wait 10 seconds for power button release and drop to G3 */
+ k_sleep(K_SECONDS(10));
+ zassert_equal(gpio_emul_output_get(sys_rst_odl->port, sys_rst_odl->pin),
+ 0);
+ zassert_equal(gpio_emul_output_get(ec_pmic_en_odl->port,
+ ec_pmic_en_odl->pin),
+ 1);
+ zassert_equal(power_get_state(), POWER_G3);
+}
+
+/* Shutdown from AP, S0 -> G3 */
+ZTEST(power_seq, test_force_shutdown_button)
+{
+ const struct gpio_dt_spec *sys_rst_odl =
+ gpio_get_dt_spec(GPIO_SYS_RST_ODL);
+ const struct gpio_dt_spec *ec_pmic_en_odl =
+ gpio_get_dt_spec(GPIO_EC_PMIC_EN_ODL);
+
+ gpio_set_level(GPIO_SYS_RST_ODL, 1);
+ gpio_set_level(GPIO_EC_PMIC_EN_ODL, 1);
+
+ /* Boot AP */
+ set_signal_state(POWER_S0);
+ zassert_equal(power_get_state(), POWER_S0);
+
+ power_button_simulate_press(10000); /* 10 seconds */
+ k_sleep(K_SECONDS(2)); /* AP off after 2 seconds */
+ set_signal_state(POWER_G3);
+ zassert_equal(gpio_emul_output_get(sys_rst_odl->port, sys_rst_odl->pin),
+ 0);
+ zassert_equal(gpio_emul_output_get(ec_pmic_en_odl->port,
+ ec_pmic_en_odl->pin),
+ 1);
+ zassert_equal(power_get_state(), POWER_G3);
+
+ k_sleep(K_SECONDS(10)); /* Wait for power button release */
+}
+
+/* AP reset (S0 -> S0).
+ * Verify power state doesn't change during reset.
+ */
+ZTEST(power_seq, test_chipset_reset)
+{
+ const struct gpio_dt_spec *ap_ec_warm_rst_req =
+ gpio_get_dt_spec(GPIO_AP_EC_WARM_RST_REQ);
+ const struct gpio_dt_spec *ap_ec_sysrst_odl =
+ gpio_get_dt_spec(GPIO_AP_EC_SYSRST_ODL);
+
+ /* Boot AP */
+ set_signal_state(POWER_S0);
+ zassert_equal(power_get_state(), POWER_S0);
+ RESET_FAKE(chipset_resume_hook);
+ /* Clear reset reason */
+ report_ap_reset(CHIPSET_RESET_UNKNOWN);
+
+ /* Trigger AP reboot */
+ gpio_emul_input_set(ap_ec_warm_rst_req->port, ap_ec_warm_rst_req->pin,
+ 0);
+ gpio_emul_input_set(ap_ec_warm_rst_req->port, ap_ec_warm_rst_req->pin,
+ 1);
+
+ /* Simulate sysrst toggle */
+ gpio_emul_input_set(ap_ec_sysrst_odl->port, ap_ec_sysrst_odl->pin, 0);
+ gpio_emul_input_set(ap_ec_sysrst_odl->port, ap_ec_sysrst_odl->pin, 1);
+ k_sleep(K_SECONDS(1));
+
+ /* Back to S0, verify that resume hook is not triggered */
+ zassert_equal(power_get_state(), POWER_S0);
+ zassert_equal(chipset_resume_hook_fake.call_count, 0);
+ /* Also verify that chipset_reset_request_interrupt is called by
+ * checking its side-effect
+ */
+ zassert_equal(chipset_get_shutdown_reason(), CHIPSET_RESET_AP_REQ);
+}
+
+/* AP reset during suspend (S3 -> S0).
+ * Verify state reaches S0 with resume hook triggered.
+ */
+ZTEST(power_seq, test_chipset_reset_in_s3)
+{
+ const struct gpio_dt_spec *ap_ec_warm_rst_req =
+ gpio_get_dt_spec(GPIO_AP_EC_WARM_RST_REQ);
+ const struct gpio_dt_spec *ap_ec_sysrst_odl =
+ gpio_get_dt_spec(GPIO_AP_EC_SYSRST_ODL);
+
+ /* Boot AP */
+ set_signal_state(POWER_S3);
+ zassert_equal(power_get_state(), POWER_S3);
+ RESET_FAKE(chipset_resume_hook);
+ /* Clear reset reason */
+ report_ap_reset(CHIPSET_RESET_UNKNOWN);
+
+ /* Trigger AP reboot */
+ gpio_emul_input_set(ap_ec_warm_rst_req->port, ap_ec_warm_rst_req->pin,
+ 0);
+ gpio_emul_input_set(ap_ec_warm_rst_req->port, ap_ec_warm_rst_req->pin,
+ 1);
+
+ /* Simulate sysrst toggle */
+ gpio_emul_input_set(ap_ec_sysrst_odl->port, ap_ec_sysrst_odl->pin, 0);
+ gpio_emul_input_set(ap_ec_sysrst_odl->port, ap_ec_sysrst_odl->pin, 1);
+ set_signal_state(POWER_S0);
+
+ /* Back to S0, verify that resume hook is triggered */
+ zassert_equal(power_get_state(), POWER_S0);
+ zassert_equal(chipset_resume_hook_fake.call_count, 1);
+ /* Also verify that chipset_reset_request_interrupt is called by
+ * checking its side-effect
+ */
+ zassert_equal(chipset_get_shutdown_reason(), CHIPSET_RESET_AP_REQ);
+}
+
+static void power_chipset_init_subtest(enum power_state signal_state,
+ bool jumped_late, uint32_t reset_flags,
+ enum power_state expected_state,
+ int line)
+{
+ set_signal_state(signal_state);
+
+ system_jumped_late_fake.return_val = jumped_late;
+ system_common_reset_state();
+ system_set_reset_flags(reset_flags);
+
+ power_set_state(power_chipset_init());
+
+ RESET_FAKE(chipset_pre_init_hook);
+ task_wake(TASK_ID_CHIPSET);
+ k_sleep(K_SECONDS(1));
+
+ if (signal_state == expected_state) {
+ /* Expect nothing changed */
+ zassert_equal(chipset_pre_init_hook_fake.call_count, 0,
+ "test_power_chipset_init line %d failed", line);
+ zassert_equal(power_get_state(), expected_state);
+ } else if (expected_state == POWER_S0 && signal_state == POWER_G3) {
+ /* Expect boot to S0 and fail at S5->S3 */
+ zassert_equal(chipset_pre_init_hook_fake.call_count, 1,
+ "test_power_chipset_init line %d failed", line);
+ } else {
+ zassert_unreachable();
+ }
+}
+
+/* Verify initial state decision logic.
+ * Combination that don't make sense (e.g. wake from hibernate but signal
+ * state is already S0) are skipped.
+ */
+ZTEST(power_seq, test_power_chipset_init)
+{
+ const struct gpio_dt_spec *ac_present =
+ gpio_get_dt_spec(GPIO_AC_PRESENT);
+
+ /* system_jumped_late => ignore all flags and boot to S0 */
+ power_chipset_init_subtest(POWER_G3, true, 0, POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_S0, true, 0, POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_G3, true, EC_RESET_FLAG_AP_OFF,
+ POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_S0, true, EC_RESET_FLAG_AP_OFF,
+ POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_G3, true, EC_RESET_FLAG_HIBERNATE,
+ POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_S0, true, EC_RESET_FLAG_HIBERNATE,
+ POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_G3, true, EC_RESET_FLAG_AP_IDLE,
+ POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_S0, true, EC_RESET_FLAG_AP_IDLE,
+ POWER_S0, __LINE__);
+
+ /* No reset flag => always boot to S0 */
+ power_chipset_init_subtest(POWER_G3, false, 0, POWER_S0, __LINE__);
+ power_chipset_init_subtest(POWER_S0, false, 0, POWER_S0, __LINE__);
+
+ /* AP off => stay at G3 */
+ power_chipset_init_subtest(POWER_G3, false, EC_RESET_FLAG_AP_OFF,
+ POWER_G3, __LINE__);
+
+ /* Boot from hibernate => stay at G3 */
+ gpio_emul_input_set(ac_present->port, ac_present->pin, 1);
+ power_chipset_init_subtest(POWER_G3, false, EC_RESET_FLAG_HIBERNATE,
+ POWER_G3, __LINE__);
+
+ /* AP_IDLE => keep current state */
+ power_chipset_init_subtest(POWER_G3, false, EC_RESET_FLAG_AP_IDLE,
+ POWER_G3, __LINE__);
+ power_chipset_init_subtest(POWER_S0, false, EC_RESET_FLAG_AP_IDLE,
+ POWER_S0, __LINE__);
+}
+
+ZTEST_SUITE(power_seq, krabby_predicate_post_main, NULL, power_seq_before, NULL,
+ NULL);
diff --git a/zephyr/test/krabby/src/stubs.c b/zephyr/test/krabby/src/stubs.c
index df1613528d..c5cdf50b44 100644
--- a/zephyr/test/krabby/src/stubs.c
+++ b/zephyr/test/krabby/src/stubs.c
@@ -22,3 +22,8 @@ int board_get_adjusted_usb_pd_port_count(int port)
{
return 2;
}
+
+uint16_t tcpc_get_alert_status(void)
+{
+ return 0;
+}
diff --git a/zephyr/test/krabby/testcase.yaml b/zephyr/test/krabby/testcase.yaml
index c579526d83..82bd8cd3ef 100644
--- a/zephyr/test/krabby/testcase.yaml
+++ b/zephyr/test/krabby/testcase.yaml
@@ -9,7 +9,13 @@ tests:
extra_args: DTC_OVERLAY_FILE="krabby.default.overlay"
extra_configs:
- CONFIG_TEST_KRABBY=y
+ - CONFIG_AP_ARM_MTK_MT8186=y
- CONFIG_MUX_INIT_ADC=y
+ - CONFIG_PLATFORM_EC_CHIPSET_RESUME_INIT_HOOK=y
+ - CONFIG_PLATFORM_EC_EXTPOWER_GPIO=y
+ - CONFIG_PLATFORM_EC_POWERSEQ=y
+ - CONFIG_PLATFORM_EC_POWERSEQ_PP5000_CONTROL=n
+ - CONFIG_SHIMMED_TASKS=y
krabby.tentacruel:
extra_args: DTC_OVERLAY_FILE="krabby.tentacruel.overlay"
extra_configs: