summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/system.c2
-rw-r--r--zephyr/test/qcom_power/boards/native_posix.overlay5
-rw-r--r--zephyr/test/qcom_power/prj.conf2
-rw-r--r--zephyr/test/qcom_power/src/main.c193
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();