diff options
-rw-r--r-- | common/system.c | 2 | ||||
-rw-r--r-- | zephyr/test/qcom_power/boards/native_posix.overlay | 5 | ||||
-rw-r--r-- | zephyr/test/qcom_power/prj.conf | 2 | ||||
-rw-r--r-- | zephyr/test/qcom_power/src/main.c | 193 |
4 files changed, 195 insertions, 7 deletions
diff --git a/common/system.c b/common/system.c index 047b96e799..c3a0f8ac58 100644 --- a/common/system.c +++ b/common/system.c @@ -1739,7 +1739,7 @@ static enum ec_status host_command_reboot(struct host_cmd_handler_args *args) } DECLARE_HOST_COMMAND(EC_CMD_REBOOT_EC, host_command_reboot, EC_VER_MASK(0)); -int system_can_boot_ap(void) +test_mockable int system_can_boot_ap(void) { int soc = -1; int pow = -1; diff --git a/zephyr/test/qcom_power/boards/native_posix.overlay b/zephyr/test/qcom_power/boards/native_posix.overlay index cda68b4b4c..820db360b7 100644 --- a/zephyr/test/qcom_power/boards/native_posix.overlay +++ b/zephyr/test/qcom_power/boards/native_posix.overlay @@ -113,6 +113,11 @@ flags = <GPIO_INT_EDGE_BOTH>; handler = "power_signal_interrupt"; }; + int_power_button: power_button { + irq-pin = <&gpio_ec_pwr_btn_odl>; + flags = <GPIO_INT_EDGE_BOTH>; + handler = "power_button_interrupt"; + }; }; gpio1: gpio@101 { diff --git a/zephyr/test/qcom_power/prj.conf b/zephyr/test/qcom_power/prj.conf index 476a1760d2..d741784117 100644 --- a/zephyr/test/qcom_power/prj.conf +++ b/zephyr/test/qcom_power/prj.conf @@ -28,6 +28,7 @@ CONFIG_SHIMMED_TASKS=y # QCom power sequencing CONFIG_AP_ARM_QUALCOMM_SC7280=y +CONFIG_PLATFORM_EC_CHIPSET_RESUME_INIT_HOOK=y CONFIG_PLATFORM_EC_EXTPOWER=y CONFIG_PLATFORM_EC_EXTPOWER_GPIO=y CONFIG_PLATFORM_EC_HOSTCMD=y @@ -36,4 +37,5 @@ CONFIG_PLATFORM_EC_POWERSEQ=y CONFIG_PLATFORM_EC_POWERSEQ_HOST_SLEEP=y CONFIG_PLATFORM_EC_POWERSEQ_SC7280=y CONFIG_PLATFORM_EC_POWER_BUTTON=y +CONFIG_PLATFORM_EC_POWER_SLEEP_FAILURE_DETECTION=y CONFIG_PLATFORM_EC_SWITCHCAP_GPIO=y diff --git a/zephyr/test/qcom_power/src/main.c b/zephyr/test/qcom_power/src/main.c index 6f299119ff..92bbe851c9 100644 --- a/zephyr/test/qcom_power/src/main.c +++ b/zephyr/test/qcom_power/src/main.c @@ -10,6 +10,9 @@ #include <zephyr/drivers/gpio/gpio_emul.h> #include <zephyr/drivers/gpio.h> #include <zephyr/shell/shell_dummy.h> +#include <zephyr/fff.h> + +#include <setjmp.h> #include "gpio_signal.h" #include "power/qcom.h" @@ -19,12 +22,14 @@ #include "console.h" #include "task.h" #include "hooks.h" +#include "host_command.h" #define AP_RST_L_NODE DT_PATH(named_gpios, ap_rst_l) #define POWER_GOOD_NODE DT_PATH(named_gpios, mb_power_good) #define AP_SUSPEND_NODE DT_PATH(named_gpios, ap_suspend) #define SWITCHCAP_PG_NODE DT_PATH(named_gpios, switchcap_pg_int_l) #define PMIC_RESIN_L_NODE DT_PATH(named_gpios, pmic_resin_l) +#define EC_PWR_BTN_ODL_NODE DT_PATH(named_gpios, ec_pwr_btn_odl) static int chipset_reset_count; @@ -34,6 +39,11 @@ static void do_chipset_reset(void) } DECLARE_HOOK(HOOK_CHIPSET_RESET, do_chipset_reset, HOOK_PRIO_DEFAULT); +DEFINE_FFF_GLOBALS; + +FAKE_VALUE_FUNC(int, system_can_boot_ap); +FAKE_VALUE_FUNC(int, battery_wait_for_stable); + /* Tests the chipset_ap_rst_interrupt() handler when in S3. * * When the system is in S3, and ap_rst_l is pulsed 1-3 times then @@ -240,6 +250,179 @@ ZTEST(qcom_power, test_chipset_reset_success) zassert_equal(power_get_state(), POWER_S0); } +/* Sent the host command, set the gpio, wait for transition to S3. */ +ZTEST(qcom_power, test_request_sleep) +{ + static const struct device *ap_suspend_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(AP_SUSPEND_NODE, gpios)); + struct ec_params_host_sleep_event params = { + .sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_HOST_SLEEP_EVENT, UINT8_C(0), params); + + zassert_ok(host_command_process(&args)); + zassert_ok(gpio_emul_input_set(ap_suspend_dev, + DT_GPIO_PIN(AP_SUSPEND_NODE, gpios), 1)); + k_sleep(K_SECONDS(16)); + zassert_equal(power_get_state(), POWER_S3); + zassert_false(host_is_event_set(EC_HOST_EVENT_HANG_DETECT)); +} + +/* Sent the host command, don't set the gpio, look for host event. */ +ZTEST(qcom_power, test_request_sleep_timeout) +{ + const char *buffer; + size_t buffer_size; + struct ec_params_host_sleep_event params = { + .sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_HOST_SLEEP_EVENT, UINT8_C(0), params); + + shell_backend_dummy_clear_output(get_ec_shell()); + zassert_ok(host_command_process(&args)); + k_sleep(K_SECONDS(16)); + zassert_equal(power_get_state(), POWER_S0); + buffer = shell_backend_dummy_get_output(get_ec_shell(), &buffer_size); + zassert_true(strstr(buffer, "Detected sleep hang!") != NULL, + "Invalid console output %s", buffer); + zassert_true(host_is_event_set(EC_HOST_EVENT_HANG_DETECT)); +} + +ZTEST(qcom_power, test_chipset_force_shutdown) +{ + chipset_force_shutdown(CHIPSET_SHUTDOWN_G3); + k_sleep(K_SECONDS(11)); + zassert_equal(power_get_state(), POWER_G3); +} + +ZTEST(qcom_power, test_power_button) +{ + static const struct device *ec_pwr_btn_odl_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(EC_PWR_BTN_ODL_NODE, gpios)); + + power_set_state(POWER_G3); + k_sleep(K_MSEC(10)); + zassert_equal(power_get_state(), POWER_G3); + + zassert_ok(gpio_emul_input_set(ec_pwr_btn_odl_dev, + DT_GPIO_PIN(EC_PWR_BTN_ODL_NODE, gpios), + 0)); + k_sleep(K_MSEC(100)); + zassert_ok(gpio_emul_input_set(ec_pwr_btn_odl_dev, + DT_GPIO_PIN(EC_PWR_BTN_ODL_NODE, gpios), + 1)); + k_sleep(K_MSEC(500)); + zassert_equal(power_get_state(), POWER_S0); +} + +ZTEST(qcom_power, test_power_button_no_power_good) +{ + static const struct device *ec_pwr_btn_odl_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(EC_PWR_BTN_ODL_NODE, gpios)); + static const struct device *power_good_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(POWER_GOOD_NODE, gpios)); + + zassert_ok(gpio_emul_input_set(power_good_dev, + DT_GPIO_PIN(POWER_GOOD_NODE, gpios), 0)); + power_set_state(POWER_G3); + k_sleep(K_MSEC(10)); + zassert_equal(power_get_state(), POWER_G3); + + zassert_ok(gpio_emul_input_set(ec_pwr_btn_odl_dev, + DT_GPIO_PIN(EC_PWR_BTN_ODL_NODE, gpios), + 0)); + k_sleep(K_MSEC(100)); + zassert_ok(gpio_emul_input_set(ec_pwr_btn_odl_dev, + DT_GPIO_PIN(EC_PWR_BTN_ODL_NODE, gpios), + 1)); + k_sleep(K_MSEC(900)); + zassert_equal(power_get_state(), POWER_S5, "power_state=%d", + power_get_state()); +} + +ZTEST(qcom_power, test_power_button_battery_low) +{ + static const struct device *ec_pwr_btn_odl_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(EC_PWR_BTN_ODL_NODE, gpios)); + + RESET_FAKE(system_can_boot_ap); + system_can_boot_ap_fake.return_val = 0; + + power_set_state(POWER_G3); + k_sleep(K_MSEC(10)); + zassert_equal(power_get_state(), POWER_G3); + + zassert_ok(gpio_emul_input_set(ec_pwr_btn_odl_dev, + DT_GPIO_PIN(EC_PWR_BTN_ODL_NODE, gpios), + 0)); + k_sleep(K_MSEC(100)); + zassert_ok(gpio_emul_input_set(ec_pwr_btn_odl_dev, + DT_GPIO_PIN(EC_PWR_BTN_ODL_NODE, gpios), + 1)); + /* > CAN_BOOT_AP_CHECK_TIMEOUT + CAN_BOOT_AP_CHECK_WAIT */ + k_sleep(K_MSEC(1800)); + zassert_equal(power_get_state(), POWER_S5); +} + +ZTEST(qcom_power, test_host_sleep_event_resume) +{ + static const struct device *ap_suspend_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(AP_SUSPEND_NODE, gpios)); + struct ec_params_host_sleep_event params = { + .sleep_event = HOST_SLEEP_EVENT_S3_RESUME, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_HOST_SLEEP_EVENT, UINT8_C(0), params); + + /* Get into S3 first */ + power_signal_enable_interrupt(GPIO_AP_SUSPEND); + zassert_ok(gpio_emul_input_set(ap_suspend_dev, + DT_GPIO_PIN(AP_SUSPEND_NODE, gpios), 1)); + power_set_state(POWER_S3); + task_wake(TASK_ID_CHIPSET); + k_sleep(K_MSEC(10)); + zassert_equal(power_get_state(), POWER_S3); + + /* Exit suspend via gpio. */ + zassert_ok(gpio_emul_input_set(ap_suspend_dev, + DT_GPIO_PIN(AP_SUSPEND_NODE, gpios), 0)); + k_sleep(K_MSEC(100)); + zassert_equal(power_get_state(), POWER_S0, "power_state=%d", + power_get_state()); + + /* Call host command to notify ec resume is done. */ + zassert_ok(host_command_process(&args)); + k_sleep(K_MSEC(10)); + zassert_equal(power_get_state(), POWER_S0, "power_state=%d", + power_get_state()); + + /* Check that AP_SUSPEND interrupts are disabled & we are in S0. */ + zassert_ok(gpio_emul_input_set(ap_suspend_dev, + DT_GPIO_PIN(AP_SUSPEND_NODE, gpios), 1)); + k_sleep(K_MSEC(100)); + zassert_equal(power_get_state(), POWER_S0); +} + +static jmp_buf assert_jumpdata; +static int num_asserts; + +void assert_post_action(const char *file, unsigned int line) +{ + ++num_asserts; + longjmp(assert_jumpdata, 1); +} + +ZTEST(qcom_power, test_invalid_power_state) +{ + if (setjmp(assert_jumpdata) == 0) { + power_handle_state(POWER_S4); + zassert_unreachable(); + } + zassert_equal(num_asserts, 1); +} + void start_in_s0(void *fixture) { static const struct device *ap_rst_dev = @@ -253,6 +436,9 @@ void start_in_s0(void *fixture) static const struct device *pmic_resin_l_dev = DEVICE_DT_GET(DT_GPIO_CTLR(PMIC_RESIN_L_NODE, gpios)); + RESET_FAKE(system_can_boot_ap); + system_can_boot_ap_fake.return_val = 1; + power_signal_disable_interrupt(GPIO_AP_SUSPEND); power_signal_enable_interrupt(GPIO_AP_RST_L); zassert_ok(gpio_emul_input_set(power_good_dev, @@ -283,16 +469,11 @@ void qcom_cleanup(void *fixture) gpio_remove_callback(pmic_resin_l_dev, &gpio_callback); gpio_callback.handler = NULL; } + host_clear_events(EC_HOST_EVENT_MASK(EC_HOST_EVENT_HANG_DETECT)); } ZTEST_SUITE(qcom_power, NULL, NULL, start_in_s0, qcom_cleanup, NULL); -/* Wait until battery is totally stable */ -int battery_wait_for_stable(void) -{ - return EC_SUCCESS; -} - void test_main(void) { ec_app_main(); |