diff options
Diffstat (limited to 'zephyr/test/drivers/host_cmd')
-rw-r--r-- | zephyr/test/drivers/host_cmd/CMakeLists.txt | 17 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/battery_cut_off.c | 107 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/get_panic_info.c | 98 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/get_pd_port_caps.c | 58 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/host_event_commands.c | 238 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/host_event_commands_deprecated.c | 256 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/keyboard_mkbp.c | 81 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/motion_sense.c | 868 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/pd_chip_info.c | 65 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/pd_control.c | 129 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/pd_log.c | 135 | ||||
-rw-r--r-- | zephyr/test/drivers/host_cmd/src/usb_pd_control.c | 151 |
12 files changed, 2203 insertions, 0 deletions
diff --git a/zephyr/test/drivers/host_cmd/CMakeLists.txt b/zephyr/test/drivers/host_cmd/CMakeLists.txt new file mode 100644 index 0000000000..ddd8e4d54c --- /dev/null +++ b/zephyr/test/drivers/host_cmd/CMakeLists.txt @@ -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. + +target_sources(app PRIVATE + src/battery_cut_off.c + src/get_panic_info.c + src/get_pd_port_caps.c + src/host_event_commands.c + src/host_event_commands_deprecated.c + src/keyboard_mkbp.c + src/motion_sense.c + src/pd_control.c + src/pd_chip_info.c + src/pd_log.c + src/usb_pd_control.c +) diff --git a/zephyr/test/drivers/host_cmd/src/battery_cut_off.c b/zephyr/test/drivers/host_cmd/src/battery_cut_off.c new file mode 100644 index 0000000000..ed9d96481d --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/battery_cut_off.c @@ -0,0 +1,107 @@ +/* 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/drivers/emul.h> +#include <zephyr/ztest.h> + +#include "battery.h" +#include "emul/emul_common_i2c.h" +#include "emul/emul_smart_battery.h" +#include "hooks.h" +#include "host_command.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +struct host_cmd_battery_cut_off_fixture { + const struct emul *emul; + struct i2c_common_emul_data *i2c_emul; +}; + +static void *host_cmd_battery_cut_off_setup(void) +{ + static struct host_cmd_battery_cut_off_fixture fixture = { + .emul = EMUL_DT_GET(DT_NODELABEL(battery)), + }; + + fixture.i2c_emul = emul_smart_battery_get_i2c_common_data(fixture.emul); + + return &fixture; +} + +static void host_cmd_battery_cut_off_before(void *f) +{ + ARG_UNUSED(f); + test_set_battery_level(75); +} + +static void host_cmd_battery_cut_off_after(void *f) +{ + struct host_cmd_battery_cut_off_fixture *fixture = f; + + i2c_common_emul_set_write_fail_reg(fixture->i2c_emul, + I2C_COMMON_EMUL_NO_FAIL_REG); + set_ac_enabled(true); + hook_notify(HOOK_AC_CHANGE); + k_msleep(500); +} + +ZTEST_SUITE(host_cmd_battery_cut_off, drivers_predicate_post_main, + host_cmd_battery_cut_off_setup, host_cmd_battery_cut_off_before, + host_cmd_battery_cut_off_after, NULL); + +ZTEST_USER_F(host_cmd_battery_cut_off, test_fail_sb_write) +{ + int rv; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_SIMPLE(EC_CMD_BATTERY_CUT_OFF, UINT8_C(0)); + + /* Force a failure on the battery i2c write to 0x00 */ + i2c_common_emul_set_write_fail_reg(fixture->i2c_emul, 0); + + rv = host_command_process(&args); + zassert_equal(EC_RES_ERROR, rv, "Expected 0, but got %d", rv); +} + +ZTEST_USER(host_cmd_battery_cut_off, test_cutoff_battery) +{ + int rv; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_SIMPLE(EC_CMD_BATTERY_CUT_OFF, UINT8_C(0)); + + rv = host_command_process(&args); + zassert_equal(EC_RES_SUCCESS, rv, "Expected 0, but got %d", rv); + zassert_true(battery_is_cut_off(), NULL); +} + +ZTEST_USER(host_cmd_battery_cut_off, test_cutoff_v1) +{ + int rv; + struct ec_params_battery_cutoff params = { + .flags = 0, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_BATTERY_CUT_OFF, UINT8_C(1), params); + + rv = host_command_process(&args); + zassert_equal(EC_RES_SUCCESS, rv, "Expected 0, but got %d", rv); + zassert_true(battery_is_cut_off(), NULL); +} + +ZTEST_USER(host_cmd_battery_cut_off, test_cutoff_at_shutdown) +{ + int rv; + struct ec_params_battery_cutoff params = { + .flags = EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_BATTERY_CUT_OFF, UINT8_C(1), params); + + rv = host_command_process(&args); + zassert_equal(EC_RES_SUCCESS, rv, "Expected 0, but got %d", rv); + zassert_false(battery_is_cut_off(), NULL); + hook_notify(HOOK_CHIPSET_SHUTDOWN); + zassert_true(WAIT_FOR(battery_is_cut_off(), 1500000, k_msleep(250)), + NULL); +} diff --git a/zephyr/test/drivers/host_cmd/src/get_panic_info.c b/zephyr/test/drivers/host_cmd/src/get_panic_info.c new file mode 100644 index 0000000000..04b83d07f9 --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/get_panic_info.c @@ -0,0 +1,98 @@ +/* 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/ztest.h> + +#include "host_command.h" +#include "panic.h" +#include "test/drivers/test_state.h" + +struct host_cmd_get_panic_info_fixture { + struct panic_data saved_pdata; +}; + +static void *host_cmd_get_panic_info_setup(void) +{ + static struct host_cmd_get_panic_info_fixture fixture = { 0 }; + + return &fixture; +} + +static void host_cmd_get_panic_info_before(void *f) +{ + struct host_cmd_get_panic_info_fixture *fixture = f; + struct panic_data *pdata = get_panic_data_write(); + + fixture->saved_pdata = *pdata; +} + +static void host_cmd_get_panic_info_after(void *f) +{ + struct host_cmd_get_panic_info_fixture *fixture = f; + struct panic_data *pdata = get_panic_data_write(); + + *pdata = fixture->saved_pdata; +} + +ZTEST_SUITE(host_cmd_get_panic_info, drivers_predicate_post_main, + host_cmd_get_panic_info_setup, host_cmd_get_panic_info_before, + host_cmd_get_panic_info_after, NULL); + +ZTEST_USER(host_cmd_get_panic_info, test_get_panic_info) +{ + struct panic_data *pdata = get_panic_data_write(); + struct panic_data response = { 0 }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE( + EC_CMD_GET_PANIC_INFO, UINT8_C(0), response); + + pdata->arch = 0; + pdata->struct_version = 1; + pdata->flags = 2; + pdata->reserved = 3; + pdata->struct_size = sizeof(struct panic_data); + pdata->magic = PANIC_DATA_MAGIC; + + zassert_ok(host_command_process(&args), NULL); + zassert_equal(sizeof(struct panic_data), args.response_size, NULL); + zassert_equal(0, response.arch, NULL); + zassert_equal(1, response.struct_version, NULL); + zassert_equal(2, response.flags, NULL); + zassert_equal(3, response.reserved, NULL); + zassert_equal(sizeof(struct panic_data), response.struct_size, NULL); + zassert_equal(PANIC_DATA_MAGIC, response.magic, NULL); + zassert_equal(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD, + PANIC_DATA_FLAG_OLD_HOSTCMD, NULL); +} + +ZTEST_USER(host_cmd_get_panic_info, test_get_panic_info_bad_magic) +{ + struct panic_data *pdata = get_panic_data_write(); + struct panic_data expected = { 0 }; + struct panic_data response = { 0 }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE( + EC_CMD_GET_PANIC_INFO, UINT8_C(0), response); + + pdata->magic = PANIC_DATA_MAGIC + 1; + zassert_ok(host_command_process(&args), NULL); + /* Check that nothing was written to response */ + zassert_mem_equal(&response, &expected, sizeof(struct panic_data), + NULL); +} + +ZTEST_USER(host_cmd_get_panic_info, test_get_panic_info_size_is_zero) +{ + struct panic_data *pdata = get_panic_data_write(); + struct panic_data expected = { 0 }; + struct panic_data response = { 0 }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE( + EC_CMD_GET_PANIC_INFO, UINT8_C(0), response); + + pdata->magic = PANIC_DATA_MAGIC; + pdata->struct_size = 0; + zassert_ok(host_command_process(&args), NULL); + /* Check that nothing was written to response */ + zassert_mem_equal(&response, &expected, sizeof(struct panic_data), + NULL); +} diff --git a/zephyr/test/drivers/host_cmd/src/get_pd_port_caps.c b/zephyr/test/drivers/host_cmd/src/get_pd_port_caps.c new file mode 100644 index 0000000000..907329f8a1 --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/get_pd_port_caps.c @@ -0,0 +1,58 @@ +/* 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/shell/shell.h> +#include <zephyr/ztest.h> + +#include "console.h" +#include "ec_commands.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +ZTEST_USER(host_cmd_get_pd_port_caps, test_good_index) +{ + struct ec_params_get_pd_port_caps params = { .port = 0 }; + struct ec_response_get_pd_port_caps response; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND( + EC_CMD_GET_PD_PORT_CAPS, 0, response, params); + + zassert_ok(host_command_process(&args), + "Failed to process get_pd_port_caps for port %d", + params.port); + + /* Verify standard Chromebook responses for these fields */ + zassert_equal(response.pd_power_role_cap, EC_PD_POWER_ROLE_DUAL, + "Bad dual role"); + zassert_equal(response.pd_try_power_role_cap, + EC_PD_TRY_POWER_ROLE_SOURCE, "Bad try role"); + zassert_equal(response.pd_data_role_cap, EC_PD_DATA_ROLE_DUAL, + "Bad data role"); + zassert_equal(response.pd_port_location, EC_PD_PORT_LOCATION_UNKNOWN, + "Unexpected port location"); +} + +ZTEST_USER(host_cmd_get_pd_port_caps, test_bad_index) +{ + struct ec_params_get_pd_port_caps params = { .port = 32 }; + struct ec_response_get_pd_port_caps response; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND( + EC_CMD_GET_PD_PORT_CAPS, 0, response, params); + + zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM, + "Failed to fail get_pd_port_caps for port %d", + params.port); +} + +static void host_cmd_get_pd_port_caps_begin(void *data) +{ + ARG_UNUSED(data); + + /* Assume we have at least one USB-C port */ + zassume_true(board_get_usb_pd_port_count() > 0, + "Insufficient TCPCs found"); +} + +ZTEST_SUITE(host_cmd_get_pd_port_caps, drivers_predicate_post_main, NULL, + host_cmd_get_pd_port_caps_begin, NULL, NULL); diff --git a/zephyr/test/drivers/host_cmd/src/host_event_commands.c b/zephyr/test/drivers/host_cmd/src/host_event_commands.c new file mode 100644 index 0000000000..c2f7e72045 --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/host_event_commands.c @@ -0,0 +1,238 @@ +/* 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/ztest.h> +#include "include/lpc.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +struct host_cmd_host_event_commands_fixture { + struct host_events_ctx ctx; +}; + +static void *host_cmd_host_event_commands_setup(void) +{ + static struct host_cmd_host_event_commands_fixture fixture = { 0 }; + + return &fixture; +} + +static void host_cmd_host_event_commands_before(void *fixture) +{ + struct host_cmd_host_event_commands_fixture *f = fixture; + + host_events_save(&f->ctx); +} + +static void host_cmd_host_event_commands_after(void *fixture) +{ + struct host_cmd_host_event_commands_fixture *f = fixture; + + host_events_restore(&f->ctx); +} + +ZTEST_SUITE(host_cmd_host_event_commands, drivers_predicate_post_main, + host_cmd_host_event_commands_setup, + host_cmd_host_event_commands_before, + host_cmd_host_event_commands_after, NULL); + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT invalid host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_invalid_cmd) +{ + enum ec_status ret_val; + struct ec_response_host_event result = { 0 }; + + ret_val = host_cmd_host_event(0xFF, 0, &result); + + zassert_equal(ret_val, EC_RES_INVALID_PARAM, "Expected=%d, returned=%d", + EC_RES_INVALID_PARAM, ret_val); +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT get host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_get_cmd) +{ + enum ec_status ret_val; + struct ec_response_host_event result = { 0 }; + struct { + uint8_t mask; + enum ec_status result; + } event_get[] = { + { EC_HOST_EVENT_MAIN, EC_RES_ACCESS_DENIED }, + { EC_HOST_EVENT_B, EC_RES_SUCCESS }, +#ifdef CONFIG_HOSTCMD_X86 + { EC_HOST_EVENT_SCI_MASK, EC_RES_SUCCESS }, + { EC_HOST_EVENT_SMI_MASK, EC_RES_SUCCESS }, + { EC_HOST_EVENT_ALWAYS_REPORT_MASK, EC_RES_SUCCESS }, + { EC_HOST_EVENT_ACTIVE_WAKE_MASK, EC_RES_SUCCESS }, +#ifdef CONFIG_POWER_S0IX + { EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, EC_RES_SUCCESS }, +#endif /* CONFIG_POWER_S0IX */ + { EC_HOST_EVENT_LAZY_WAKE_MASK_S3, EC_RES_SUCCESS }, + { EC_HOST_EVENT_LAZY_WAKE_MASK_S5, EC_RES_SUCCESS }, +#endif /* CONFIG_HOSTCMD_X86 */ + { 0xFF, EC_RES_INVALID_PARAM }, + }; + + for (int i = 0; i < ARRAY_SIZE(event_get); i++) { + ret_val = host_cmd_host_event(EC_HOST_EVENT_GET, + event_get[i].mask, &result); + zassert_equal(ret_val, event_get[i].result, + "[%d] Expected=%d, returned=%d", i, + event_get[i].result, ret_val); + } +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT set host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_set_cmd) +{ + enum ec_status ret_val; + struct ec_response_host_event result = { 0 }; + struct { + uint8_t mask; + enum ec_status result; + } event_set[] = { + { EC_HOST_EVENT_MAIN, EC_RES_ACCESS_DENIED }, + { EC_HOST_EVENT_B, EC_RES_ACCESS_DENIED }, +#ifdef CONFIG_HOSTCMD_X86 + { EC_HOST_EVENT_SCI_MASK, EC_RES_SUCCESS }, + { EC_HOST_EVENT_SMI_MASK, EC_RES_SUCCESS }, + { EC_HOST_EVENT_ALWAYS_REPORT_MASK, EC_RES_SUCCESS }, + { EC_HOST_EVENT_ACTIVE_WAKE_MASK, EC_RES_SUCCESS }, +#ifdef CONFIG_POWER_S0IX + { EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, EC_RES_SUCCESS }, +#endif /* CONFIG_POWER_S0IX */ + { EC_HOST_EVENT_LAZY_WAKE_MASK_S3, EC_RES_SUCCESS }, + { EC_HOST_EVENT_LAZY_WAKE_MASK_S5, EC_RES_SUCCESS }, +#endif /* CONFIG_HOSTCMD_X86 */ + { 0xFF, EC_RES_INVALID_PARAM }, + }; + + for (int i = 0; i < ARRAY_SIZE(event_set); i++) { + ret_val = host_cmd_host_event(EC_HOST_EVENT_SET, + event_set[i].mask, &result); + zassert_equal(ret_val, event_set[i].result, + "[%d] Expected=%d, returned=%d", i, + event_set[i].result, ret_val); + } +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT clear host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_clear_cmd) +{ + enum ec_status ret_val; + struct ec_response_host_event result = { 0 }; + struct { + uint8_t mask; + enum ec_status result; + } event_set[] = { + { EC_HOST_EVENT_MAIN, EC_RES_SUCCESS }, + { EC_HOST_EVENT_B, EC_RES_SUCCESS }, +#ifdef CONFIG_HOSTCMD_X86 + { EC_HOST_EVENT_SCI_MASK, EC_RES_ACCESS_DENIED }, + { EC_HOST_EVENT_SMI_MASK, EC_RES_ACCESS_DENIED }, + { EC_HOST_EVENT_ALWAYS_REPORT_MASK, EC_RES_ACCESS_DENIED }, + { EC_HOST_EVENT_ACTIVE_WAKE_MASK, EC_RES_ACCESS_DENIED }, +#ifdef CONFIG_POWER_S0IX + { EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, EC_RES_ACCESS_DENIED }, +#endif /* CONFIG_POWER_S0IX */ + { EC_HOST_EVENT_LAZY_WAKE_MASK_S3, EC_RES_ACCESS_DENIED }, + { EC_HOST_EVENT_LAZY_WAKE_MASK_S5, EC_RES_ACCESS_DENIED }, +#endif /* CONFIG_HOSTCMD_X86 */ + { 0xFF, EC_RES_INVALID_PARAM }, + }; + + for (int i = 0; i < ARRAY_SIZE(event_set); i++) { + ret_val = host_cmd_host_event(EC_HOST_EVENT_CLEAR, + event_set[i].mask, &result); + zassert_equal(ret_val, event_set[i].result, + "Expected [%d] result=%d, returned=%d", i, + event_set[i].result, ret_val); + } +} + +enum ec_status host_event_mask_cmd_helper(uint32_t command, uint32_t mask, + struct ec_response_host_event_mask *r) +{ + enum ec_status ret_val; + + struct ec_params_host_event_mask params = { + .mask = mask, + }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND(command, 0, *r, params); + + ret_val = host_command_process(&args); + + return ret_val; +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_CLEAR clear host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_clear__cmd) +{ + enum ec_status ret_val; + host_event_t events; + host_event_t mask = EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY); + host_event_t lpc_event_mask; + struct ec_response_host_event_mask response = { 0 }; + + lpc_event_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SMI); + lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, lpc_event_mask | mask); + + host_set_single_event(EC_HOST_EVENT_KEYBOARD_RECOVERY); + events = host_get_events(); + + zassert_true(events & mask, "events=0x%X", events); + + ret_val = host_event_mask_cmd_helper(EC_CMD_HOST_EVENT_CLEAR, mask, + &response); + + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); + + events = host_get_events(); + zassert_false(events & mask, "events=0x%X", events); +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_CLEAR_B clear host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_clear_b_cmd) +{ + enum ec_status ret_val; + host_event_t events_b; + host_event_t mask = EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY); + host_event_t lpc_event_mask; + struct ec_response_host_event_mask response = { 0 }; + struct ec_response_host_event result = { 0 }; + + lpc_event_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SMI); + lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, lpc_event_mask | mask); + + host_set_single_event(EC_HOST_EVENT_KEYBOARD_RECOVERY); + + host_cmd_host_event(EC_HOST_EVENT_GET, EC_HOST_EVENT_B, &result); + events_b = result.value; + zassert_true(events_b & mask, "events_b=0x%X", events_b); + + ret_val = host_event_mask_cmd_helper(EC_CMD_HOST_EVENT_CLEAR_B, mask, + &response); + + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); + + host_cmd_host_event(EC_HOST_EVENT_GET, EC_HOST_EVENT_B, &result); + events_b = result.value; + zassert_false(events_b & mask, "events_b=0x%X", events_b); +} diff --git a/zephyr/test/drivers/host_cmd/src/host_event_commands_deprecated.c b/zephyr/test/drivers/host_cmd/src/host_event_commands_deprecated.c new file mode 100644 index 0000000000..6d0a386d6e --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/host_event_commands_deprecated.c @@ -0,0 +1,256 @@ +/* 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. + */ + +/* Tests for deprecated EC_CMD_HOST_EVENT_* commands */ + +#include <zephyr/ztest.h> +#include "include/lpc.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +#define HOST_EVENT_TEST_MASK_VAL EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) + +static void +host_event_get_wake_mask_helper(struct ec_response_host_event_mask *r) +{ + enum ec_status ret_val; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE( + EC_CMD_HOST_EVENT_GET_WAKE_MASK, 0, *r); + + ret_val = host_command_process(&args); + + /* EC_CMD_HOST_EVENT_GET_WAKE_MASK always returns success */ + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); +} + +static void host_event_set_wake_mask_helper(uint32_t mask) +{ + enum ec_status ret_val; + struct ec_params_host_event_mask params = { .mask = mask }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_HOST_EVENT_SET_WAKE_MASK, 0, params); + + ret_val = host_command_process(&args); + + /* EC_CMD_HOST_EVENT_SET_WAKE_MASK always returns success */ + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_GET_WAKE_MASK host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_get_wake_mask) +{ +#ifdef CONFIG_HOSTCMD_X86 + struct ec_response_host_event_mask result = { 0 }; + + host_event_get_wake_mask_helper(&result); +#else + ztest_test_skip(); +#endif +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_SET_WAKE_MASK host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_set_wake_mask) +{ +#ifdef CONFIG_HOSTCMD_X86 + struct ec_response_host_event_mask result = { 0 }; + + /* Read the current mask */ + host_event_get_wake_mask_helper(&result); + + /* Default mask is expected to be clear */ + zassert_false(result.mask, "Default host event wake mask is not clear"); + + host_event_set_wake_mask_helper(HOST_EVENT_TEST_MASK_VAL); + + /* Verify the mask changed */ + host_event_get_wake_mask_helper(&result); + + zassert_equal(result.mask, HOST_EVENT_TEST_MASK_VAL, + "Expected wake mask 0x%08x, returned mask 0x%08x", + HOST_EVENT_TEST_MASK_VAL, result.mask); + + /* Clean up the mask */ + host_event_set_wake_mask_helper(0); +#else + ztest_test_skip(); +#endif +} + +static void +host_event_get_smi_mask_helper(struct ec_response_host_event_mask *r) +{ + enum ec_status ret_val; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE( + EC_CMD_HOST_EVENT_GET_SMI_MASK, 0, *r); + + ret_val = host_command_process(&args); + + /* EC_CMD_HOST_EVENT_GET_SMI_MASK always returns success */ + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); +} + +static void host_event_set_smi_mask_helper(uint32_t mask) +{ + enum ec_status ret_val; + struct ec_params_host_event_mask params = { .mask = mask }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_HOST_EVENT_SET_SMI_MASK, 0, params); + + ret_val = host_command_process(&args); + + /* EC_CMD_HOST_EVENT_SET_SMI_MASK always returns success */ + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_GET_SMI_MASK host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_get_smi_mask) +{ +#ifdef CONFIG_HOSTCMD_X86 + struct ec_response_host_event_mask result = { 0 }; + + host_event_get_smi_mask_helper(&result); +#else + ztest_test_skip(); +#endif +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_SET_SMI_MASK host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_set_smi_mask) +{ +#ifdef CONFIG_HOSTCMD_X86 + struct ec_response_host_event_mask result = { 0 }; + + /* Read the current mask */ + host_event_get_smi_mask_helper(&result); + + /* Default mask is expected to be clear */ + zassert_false(result.mask, "Default host event SMI mask is not clear"); + + host_event_set_smi_mask_helper(HOST_EVENT_TEST_MASK_VAL); + + /* Verify the mask changed */ + host_event_get_smi_mask_helper(&result); + + zassert_equal(result.mask, HOST_EVENT_TEST_MASK_VAL, + "Expected SMI mask 0x%08x, returned mask 0x%08x", + HOST_EVENT_TEST_MASK_VAL, result.mask); + + /* Clean up the mask */ + host_event_set_smi_mask_helper(0); +#else + ztest_test_skip(); +#endif +} + +static void host_event_get_b_helper(struct ec_response_host_event_mask *r) +{ + enum ec_status ret_val; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_RESPONSE(EC_CMD_HOST_EVENT_GET_B, 0, *r); + + ret_val = host_command_process(&args); + + /* EC_CMD_HOST_EVENT_GET_B always returns success */ + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_GET_B host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_get_b) +{ +#ifdef CONFIG_HOSTCMD_X86 + struct ec_response_host_event_mask result = { 0 }; + + host_event_get_b_helper(&result); +#else + ztest_test_skip(); +#endif +} + +static void +host_event_get_sci_mask_helper(struct ec_response_host_event_mask *r) +{ + enum ec_status ret_val; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE( + EC_CMD_HOST_EVENT_GET_SCI_MASK, 0, *r); + + ret_val = host_command_process(&args); + + /* EC_CMD_HOST_EVENT_GET_SCI_MASK always returns success */ + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); +} + +static void host_event_set_sci_mask_helper(uint32_t mask) +{ + enum ec_status ret_val; + struct ec_params_host_event_mask params = { .mask = mask }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_HOST_EVENT_SET_SCI_MASK, 0, params); + + ret_val = host_command_process(&args); + + /* EC_CMD_HOST_EVENT_SET_SCI_MASK always returns success */ + zassert_equal(ret_val, EC_RES_SUCCESS, "Expected %d, returned %d", + EC_RES_SUCCESS, ret_val); +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_GET_SCI_MASK host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_get_sci_mask) +{ +#ifdef CONFIG_HOSTCMD_X86 + struct ec_response_host_event_mask result = { 0 }; + + host_event_get_sci_mask_helper(&result); +#else + ztest_test_skip(); +#endif +} + +/** + * @brief TestPurpose: Verify EC_CMD_HOST_EVENT_SET_SCI_MASK host command. + */ +ZTEST_USER(host_cmd_host_event_commands, test_host_event_set_sci_mask) +{ +#ifdef CONFIG_HOSTCMD_X86 + struct ec_response_host_event_mask result = { 0 }; + + /* Read the current mask */ + host_event_get_sci_mask_helper(&result); + + /* Default mask is expected to be clear */ + zassert_false(result.mask, "Default host event SCI mask is not clear"); + + host_event_set_sci_mask_helper(HOST_EVENT_TEST_MASK_VAL); + + /* Verify the mask changed */ + host_event_get_sci_mask_helper(&result); + + zassert_equal(result.mask, HOST_EVENT_TEST_MASK_VAL, + "Expected SCI mask 0x%08x, returned mask 0x%08x", + HOST_EVENT_TEST_MASK_VAL, result.mask); + + /* Clean up the mask */ + host_event_set_sci_mask_helper(0); +#else + ztest_test_skip(); +#endif +} diff --git a/zephyr/test/drivers/host_cmd/src/keyboard_mkbp.c b/zephyr/test/drivers/host_cmd/src/keyboard_mkbp.c new file mode 100644 index 0000000000..4c74a48ab4 --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/keyboard_mkbp.c @@ -0,0 +1,81 @@ +/* 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/ztest.h> +#include "include/keyboard_mkbp.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +struct keyboard_mkbp_commands_fixture { + struct ec_mkbp_config config; +}; + +static void *keyboard_mkbp_setup(void) +{ + static struct keyboard_mkbp_commands_fixture fixture = { 0 }; + + return &fixture; +} + +static void keyboard_mkbp_before(void *fixture) +{ + struct keyboard_mkbp_commands_fixture *f = fixture; + + get_keyscan_config(&f->config); +} + +static void keyboard_mkbp_after(void *fixture) +{ + struct keyboard_mkbp_commands_fixture *f = fixture; + struct ec_params_mkbp_set_config req = { 0 }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_PARAMS(EC_CMD_MKBP_SET_CONFIG, 0, req); + + req.config = f->config; + host_command_process(&args); +} + +ZTEST_SUITE(keyboard_mkbp_commands, drivers_predicate_post_main, + keyboard_mkbp_setup, keyboard_mkbp_before, keyboard_mkbp_after, + NULL); + +/** + * @brief TestPurpose: Verify EC_CMD_MKBP_GET_CONFIG host command. + */ +ZTEST_USER(keyboard_mkbp_commands, test_mkbp_get_config_cmd) +{ + enum ec_status ret_val; + struct ec_response_mkbp_get_config resp; + + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_RESPONSE(EC_CMD_MKBP_GET_CONFIG, 0, resp); + + ret_val = host_command_process(&args); + + zassert_ok(ret_val, "Expected=%d, returned=%d", EC_SUCCESS, ret_val); +} + +/** + * @brief TestPurpose: Verify EC_CMD_MKBP_SET_CONFIG host command. + */ +ZTEST_USER(keyboard_mkbp_commands, test_mkbp_set_config_cmd) +{ + enum ec_status ret_val; + struct ec_params_mkbp_set_config req = { 0 }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_PARAMS(EC_CMD_MKBP_SET_CONFIG, 0, req); + + get_keyscan_config(&req.config); + + req.config.valid_mask = + EC_MKBP_VALID_SCAN_PERIOD | EC_MKBP_VALID_POLL_TIMEOUT | + EC_MKBP_VALID_MIN_POST_SCAN_DELAY | + EC_MKBP_VALID_OUTPUT_SETTLE | EC_MKBP_VALID_DEBOUNCE_DOWN | + EC_MKBP_VALID_DEBOUNCE_UP | EC_MKBP_VALID_FIFO_MAX_DEPTH; + + ret_val = host_command_process(&args); + + zassert_ok(ret_val, "Expected=%d, returned=%d", EC_SUCCESS, ret_val); +} diff --git a/zephyr/test/drivers/host_cmd/src/motion_sense.c b/zephyr/test/drivers/host_cmd/src/motion_sense.c new file mode 100644 index 0000000000..c75f327fed --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/motion_sense.c @@ -0,0 +1,868 @@ +/* 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/fff.h> +#include <zephyr/shell/shell.h> +#include <zephyr/ztest.h> + +#include "atomic.h" +#include "console.h" +#include "driver/accel_bma2x2.h" +#include "motion_sense.h" +#include "motion_sense_fifo.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +FAKE_VALUE_FUNC(int, mock_set_range, struct motion_sensor_t *, int, int); +FAKE_VALUE_FUNC(int, mock_set_offset, const struct motion_sensor_t *, + const int16_t *, int16_t); +FAKE_VALUE_FUNC(int, mock_get_offset, const struct motion_sensor_t *, int16_t *, + int16_t *); +FAKE_VALUE_FUNC(int, mock_set_scale, const struct motion_sensor_t *, + const uint16_t *, int16_t); +FAKE_VALUE_FUNC(int, mock_get_scale, const struct motion_sensor_t *, uint16_t *, + int16_t *); +FAKE_VALUE_FUNC(int, mock_perform_calib, struct motion_sensor_t *, int); + +/** + * Get the size needed for a struct ec_response_motion_sense + */ +#define RESPONSE_MOTION_SENSE_BUFFER_SIZE(n) \ + (sizeof(struct ec_response_motion_sense) + \ + n * sizeof(struct ec_response_motion_sensor_data)) + +#define RESPONSE_SENSOR_FIFO_SIZE(n) \ + (sizeof(struct ec_response_motion_sense) + n * sizeof(uint16_t)) + +struct host_cmd_motion_sense_fixture { + const struct accelgyro_drv *sensor_0_drv; + struct accelgyro_drv mock_drv; +}; + +static void *host_cmd_motion_sense_setup(void) +{ + static struct host_cmd_motion_sense_fixture fixture = { + .mock_drv = { + .set_range = mock_set_range, + .set_offset = mock_set_offset, + .get_offset = mock_get_offset, + .set_scale = mock_set_scale, + .get_scale = mock_get_scale, + .perform_calib = mock_perform_calib, + }, + }; + + fixture.sensor_0_drv = motion_sensors[0].drv; + + return &fixture; +} + +static void host_cmd_motion_sense_before(void *fixture) +{ + ARG_UNUSED(fixture); + RESET_FAKE(mock_set_range); + RESET_FAKE(mock_set_offset); + RESET_FAKE(mock_get_offset); + RESET_FAKE(mock_set_scale); + RESET_FAKE(mock_get_scale); + RESET_FAKE(mock_perform_calib); + FFF_RESET_HISTORY(); + + zassume_ok(shell_execute_cmd(get_ec_shell(), "accelinit 0"), NULL); + + atomic_clear(&motion_sensors[0].flush_pending); + motion_sensors[0].config[SENSOR_CONFIG_AP].odr = 0; + motion_sensors[0].config[SENSOR_CONFIG_AP].ec_rate = 1000 * MSEC; +} + +static void host_cmd_motion_sense_after(void *fixture) +{ + struct host_cmd_motion_sense_fixture *this = fixture; + struct ec_response_motion_sense response; + + motion_sensors[0].drv = this->sensor_0_drv; + host_cmd_motion_sense_int_enable(0, &response); + motion_sensors[0].flags &= ~MOTIONSENSE_FLAG_IN_SPOOF_MODE; + motion_sensors[0].config[SENSOR_CONFIG_AP].odr = 0; + motion_sensors[0].config[SENSOR_CONFIG_AP].ec_rate = 1000 * MSEC; +} + +ZTEST_SUITE(host_cmd_motion_sense, drivers_predicate_post_main, + host_cmd_motion_sense_setup, host_cmd_motion_sense_before, + host_cmd_motion_sense_after, NULL); + +ZTEST_USER(host_cmd_motion_sense, test_dump) +{ + uint8_t response_buffer[RESPONSE_MOTION_SENSE_BUFFER_SIZE( + ALL_MOTION_SENSORS)]; + struct ec_response_motion_sense *result = + (struct ec_response_motion_sense *)response_buffer; + + /* Set up the motion sensor data */ + for (int i = 0; i < ALL_MOTION_SENSORS; ++i) { + motion_sensors[i].xyz[0] = i; + motion_sensors[i].xyz[1] = i + 1; + motion_sensors[i].xyz[2] = i + 2; + } + + /* Make sure that the accelerometer status presence bit is off */ + *host_get_memmap(EC_MEMMAP_ACC_STATUS) &= + ~(EC_MEMMAP_ACC_STATUS_PRESENCE_BIT); + + /* Dump all the sensors info */ + host_cmd_motion_sense_dump(ALL_MOTION_SENSORS, result); + + zassert_equal(result->dump.module_flags, 0, NULL); + zassert_equal(result->dump.sensor_count, ALL_MOTION_SENSORS, NULL); + + /* + * Test the values returned in the dump. Normally we shouldn't be doing + * tests in a loop, but since the number of sensors (as well as the + * order) is adjustable by devicetree, it would be too difficult to hard + * code here. + */ + for (int i = 0; i < ALL_MOTION_SENSORS; ++i) { + zassert_equal(result->dump.sensor[i].flags, + MOTIONSENSE_SENSOR_FLAG_PRESENT, NULL); + zassert_equal(result->dump.sensor[i].data[0], i, NULL); + zassert_equal(result->dump.sensor[i].data[1], i + 1, NULL); + zassert_equal(result->dump.sensor[i].data[2], i + 2, NULL); + } + + /* Make sure that the accelerometer status presence bit is on */ + *host_get_memmap(EC_MEMMAP_ACC_STATUS) |= + EC_MEMMAP_ACC_STATUS_PRESENCE_BIT; + + /* Dump all the sensors info */ + host_cmd_motion_sense_dump(ALL_MOTION_SENSORS, result); + + zassert_equal(result->dump.module_flags, MOTIONSENSE_MODULE_FLAG_ACTIVE, + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_dump__large_max_sensor_count) +{ + uint8_t response_buffer[RESPONSE_MOTION_SENSE_BUFFER_SIZE( + ALL_MOTION_SENSORS)]; + struct ec_response_motion_sense *result = + (struct ec_response_motion_sense *)response_buffer; + + host_cmd_motion_sense_dump(ALL_MOTION_SENSORS + 1, result); + + zassert_equal(result->dump.sensor_count, ALL_MOTION_SENSORS, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_read_data__invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(host_cmd_motion_sense_data(UINT8_MAX, &response), + EC_RES_INVALID_PARAM, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_read_data) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].xyz[0] = 1; + motion_sensors[0].xyz[1] = 2; + motion_sensors[0].xyz[2] = 3; + + zassert_ok(host_cmd_motion_sense_data(0, &response), NULL); + zassert_equal(response.data.flags, 0, NULL); + zassert_equal(response.data.data[0], 1, NULL); + zassert_equal(response.data.data[1], 2, NULL); + zassert_equal(response.data.data[2], 3, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_get_info__invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(host_cmd_motion_sense_info(/*cmd_version=*/1, + /*sensor_num=*/UINT8_MAX, + &response), + EC_RES_INVALID_PARAM, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_get_info_v1) +{ + struct ec_response_motion_sense response; + + zassert_ok(host_cmd_motion_sense_info(/*cmd_version=*/1, + /*sensor_num=*/0, &response), + NULL); + zassert_equal(response.info.type, motion_sensors[0].type, NULL); + zassert_equal(response.info.location, motion_sensors[0].location, NULL); + zassert_equal(response.info.chip, motion_sensors[0].chip, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_get_info_v3) +{ + struct ec_response_motion_sense response; + + zassert_ok(host_cmd_motion_sense_info(/*cmd_version=*/3, + /*sensor_num=*/0, &response), + NULL); + zassert_equal(response.info.type, motion_sensors[0].type, NULL); + zassert_equal(response.info.location, motion_sensors[0].location, NULL); + zassert_equal(response.info.chip, motion_sensors[0].chip, NULL); + zassert_equal(response.info_3.min_frequency, + motion_sensors[0].min_frequency, NULL); + zassert_equal(response.info_3.max_frequency, + motion_sensors[0].max_frequency, NULL); + zassert_equal(response.info_3.fifo_max_event_count, + CONFIG_ACCEL_FIFO_SIZE, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_get_info_v4__no_read_temp) +{ + struct ec_response_motion_sense response; + + zassert_ok(host_cmd_motion_sense_info(/*cmd_version=*/4, + /*sensor_num=*/0, &response), + NULL); + zassert_equal(response.info.type, motion_sensors[0].type, NULL); + zassert_equal(response.info.location, motion_sensors[0].location, NULL); + zassert_equal(response.info.chip, motion_sensors[0].chip, NULL); + if (IS_ENABLED(CONFIG_ONLINE_CALIB)) { + zassert_true(response.info_4.flags & + MOTION_SENSE_CMD_INFO_FLAG_ONLINE_CALIB, + NULL); + } else { + zassert_false(response.info_4.flags & + MOTION_SENSE_CMD_INFO_FLAG_ONLINE_CALIB, + NULL); + } +} + +ZTEST_USER(host_cmd_motion_sense, test_get_ec_rate__invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(host_cmd_motion_sense_ec_rate( + /*sensor_num=*/0xff, + /*data_rate_ms=*/EC_MOTION_SENSE_NO_VALUE, + &response), + EC_RES_INVALID_PARAM, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_get_ec_rate) +{ + struct ec_response_motion_sense response; + + /* Set the power level to S3, the default config from device-tree is for + * 100ms + */ + test_set_chipset_to_power_level(POWER_S3); + zassert_ok(host_cmd_motion_sense_ec_rate( + /*sensor_num=*/0, + /*data_rate_ms=*/EC_MOTION_SENSE_NO_VALUE, + &response), + NULL); + zassert_equal(response.ec_rate.ret, 1000, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_set_ec_rate) +{ + struct ec_response_motion_sense response; + + /* Set the power level to S3, the default config from device-tree is for + * 100ms + */ + test_set_chipset_to_power_level(POWER_S3); + zassert_ok(host_cmd_motion_sense_ec_rate( + /*sensor_num=*/0, /*data_rate_ms=*/2000, &response), + NULL); + /* The command should return the previous rate */ + zassert_equal(response.ec_rate.ret, 1000, "Expected 1000, but got %d", + response.ec_rate.ret); + /* The sensor's AP config value should be updated */ + zassert_equal(motion_sensors[0].config[SENSOR_CONFIG_AP].ec_rate, + 2000 * MSEC, NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_odr_invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_odr( + /*sensor_num=*/0xff, + /*odr=*/EC_MOTION_SENSE_NO_VALUE, + /*round_up=*/false, &response), + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_odr_get) +{ + struct ec_response_motion_sense response; + + zassume_ok(motion_sensors[0].drv->set_data_rate(&motion_sensors[0], + 1000000, false), + NULL); + zassert_ok(host_cmd_motion_sense_odr(/*sensor_num=*/0, + /*odr=*/EC_MOTION_SENSE_NO_VALUE, + /*round_up=*/false, &response), + NULL); + zassert_equal(BMA2x2_REG_TO_BW(BMA2x2_BW_1000HZ), + response.sensor_odr.ret, "Expected %d, but got %d", + BMA2x2_REG_TO_BW(BMA2x2_BW_1000HZ), + response.sensor_odr.ret); +} + +ZTEST_USER(host_cmd_motion_sense, test_odr_set) +{ + struct ec_response_motion_sense response; + + zassume_ok(motion_sensors[0].drv->set_data_rate(&motion_sensors[0], 0, + false), + NULL); + zassert_ok(host_cmd_motion_sense_odr(/*sensor_num=*/0, + /*odr=*/1000000, + /*round_up=*/true, &response), + NULL); + /* Check the set value */ + zassert_equal(1000000 | ROUND_UP_FLAG, + motion_sensors[0].config[SENSOR_CONFIG_AP].odr, + "Expected %d, but got %d", 1000000 | ROUND_UP_FLAG, + motion_sensors[0].config[SENSOR_CONFIG_AP].odr); + /* Check the returned value */ + zassert_equal(BMA2x2_REG_TO_BW(BMA2x2_BW_7_81HZ), + response.sensor_odr.ret, "Expected %d, but got %d", + BMA2x2_REG_TO_BW(BMA2x2_BW_7_81HZ), + response.sensor_odr.ret); +} + +ZTEST_USER(host_cmd_motion_sense, test_range_invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_range( + /*sensor_num=*/0xff, + /*range=*/EC_MOTION_SENSE_NO_VALUE, + /*round_up=*/false, &response), + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_get_range) +{ + struct ec_response_motion_sense response; + + zassert_ok(host_cmd_motion_sense_range( + /*sensor_num=*/0, /*range=*/EC_MOTION_SENSE_NO_VALUE, + /*round_up=*/false, &response), + NULL); + zassert_equal(motion_sensors[0].current_range, + response.sensor_range.ret, "Expected %d, but got %d", + motion_sensors[0].current_range, + response.sensor_range.ret); +} + +ZTEST_USER(host_cmd_motion_sense, test_null_set_range_in_driver) +{ + struct ec_response_motion_sense response; + struct accelgyro_drv drv = { 0 }; + + motion_sensors[0].drv = &drv; + zassert_equal(EC_RES_INVALID_COMMAND, + host_cmd_motion_sense_range(/*sensor_num=*/0, /*range=*/4, + /*round_up=*/false, + &response), + NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_set_range_error) +{ + struct ec_response_motion_sense response; + + mock_set_range_fake.return_val = 1; + motion_sensors[0].drv = &fixture->mock_drv; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_range(/*sensor_num=*/0, /*range=*/4, + /*round_up=*/false, + &response), + NULL); + zassert_equal(1, mock_set_range_fake.call_count, NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_set_range) +{ + struct ec_response_motion_sense response; + + mock_set_range_fake.return_val = 0; + motion_sensors[0].drv = &fixture->mock_drv; + + zassert_ok(host_cmd_motion_sense_range(/*sensor_num=*/0, /*range=*/4, + /*round_up=*/false, &response), + NULL); + zassert_equal(1, mock_set_range_fake.call_count, NULL); + zassert_equal(4, mock_set_range_fake.arg1_history[0], NULL); + zassert_equal(0, mock_set_range_fake.arg2_history[0], NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_offset_invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_offset( + /*sensor_num=*/0xff, /*flags=*/0, + /*temperature=*/0, /*offset_x=*/0, + /*offset_y=*/0, /*offset_z=*/0, &response), + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_offset_missing_get_offset_in_driver) +{ + struct ec_response_motion_sense response; + struct accelgyro_drv drv = { 0 }; + + motion_sensors[0].drv = &drv; + + zassert_equal(EC_RES_INVALID_COMMAND, + host_cmd_motion_sense_offset( + /*sensor_num=*/0, /*flags=*/0, + /*temperature=*/0, /*offset_x=*/0, + /*offset_y=*/0, /*offset_z=*/0, &response), + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_offset_missing_set_offset_in_driver) +{ + struct ec_response_motion_sense response; + struct accelgyro_drv drv = { 0 }; + + motion_sensors[0].drv = &drv; + + zassert_equal(EC_RES_INVALID_COMMAND, + host_cmd_motion_sense_offset( + /*sensor_num=*/0, + /*flags=*/MOTION_SENSE_SET_OFFSET, + /*temperature=*/0, /*offset_x=*/0, + /*offset_y=*/0, /*offset_z=*/0, &response), + NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_offset_fail_to_set) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_set_offset_fake.return_val = EC_RES_ERROR; + + zassert_equal(EC_RES_ERROR, + host_cmd_motion_sense_offset( + /*sensor_num=*/0, + /*flags=*/MOTION_SENSE_SET_OFFSET, + /*temperature=*/0, /*offset_x=*/0, + /*offset_y=*/0, /*offset_z=*/0, &response), + NULL); + zassert_equal(1, mock_set_offset_fake.call_count, NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_offset_fail_to_get) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_set_offset_fake.return_val = EC_RES_SUCCESS; + mock_get_offset_fake.return_val = EC_RES_ERROR; + + zassert_equal(EC_RES_ERROR, + host_cmd_motion_sense_offset( + /*sensor_num=*/0, + /*flags=*/MOTION_SENSE_SET_OFFSET, + /*temperature=*/0, /*offset_x=*/0, + /*offset_y=*/0, /*offset_z=*/0, &response), + NULL); + zassert_equal(1, mock_set_offset_fake.call_count, NULL); + zassert_equal(1, mock_get_offset_fake.call_count, NULL); + zassert_equal((int16_t *)&response.sensor_offset.offset, + mock_get_offset_fake.arg1_history[0], NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_get_offset) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_get_offset_fake.return_val = EC_RES_SUCCESS; + mock_set_offset_fake.return_val = EC_RES_SUCCESS; + + zassert_ok(host_cmd_motion_sense_offset( + /*sensor_num=*/0, + /*flags=*/MOTION_SENSE_SET_OFFSET, + /*temperature=*/1, /*offset_x=*/2, + /*offset_y=*/3, /*offset_z=*/4, &response), + NULL); + zassert_equal(1, mock_set_offset_fake.call_count, NULL); + zassert_equal(1, mock_get_offset_fake.call_count, NULL); + zassert_equal((int16_t *)&response.sensor_offset.offset, + mock_get_offset_fake.arg1_history[0], NULL); + zassert_equal(1, mock_set_offset_fake.arg2_history[0], NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_scale_invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_scale( + /*sensor_num=*/0xff, + /*flags=*/0, + /*temperature=*/1, /*scale_x=*/2, + /*scale_y=*/3, /*scale_z=*/4, &response), + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_get_scale_not_in_driver) +{ + struct ec_response_motion_sense response; + struct accelgyro_drv drv = *motion_sensors[0].drv; + + drv.get_scale = NULL; + motion_sensors[0].drv = &drv; + + zassert_equal(EC_RES_INVALID_COMMAND, + host_cmd_motion_sense_scale( + /*sensor_num=*/0, + /*flags=*/0, + /*temperature=*/1, /*scale_x=*/2, + /*scale_y=*/3, /*scale_z=*/4, &response), + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_set_scale_not_in_driver) +{ + struct ec_response_motion_sense response; + struct accelgyro_drv drv = *motion_sensors[0].drv; + + drv.set_scale = NULL; + motion_sensors[0].drv = &drv; + + zassert_equal(EC_RES_INVALID_COMMAND, + host_cmd_motion_sense_scale( + /*sensor_num=*/0, + /*flags=*/MOTION_SENSE_SET_OFFSET, + /*temperature=*/1, /*scale_x=*/2, + /*scale_y=*/3, /*scale_z=*/4, &response), + NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_get_scale_fail) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_get_scale_fake.return_val = 1; + + zassert_equal(1, + host_cmd_motion_sense_scale( + /*sensor_num=*/0, + /*flags=*/0, + /*temperature=*/1, /*scale_x=*/2, + /*scale_y=*/3, /*scale_z=*/4, &response), + NULL); + zassert_equal(1, mock_get_scale_fake.call_count, NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_set_scale_fail) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_set_scale_fake.return_val = 1; + + zassert_equal(1, + host_cmd_motion_sense_scale( + /*sensor_num=*/0, + /*flags=*/MOTION_SENSE_SET_OFFSET, + /*temperature=*/1, /*scale_x=*/2, + /*scale_y=*/3, /*scale_z=*/4, &response), + NULL); + zassert_equal(1, mock_set_scale_fake.call_count, NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_set_get_scale) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_set_scale_fake.return_val = 0; + mock_get_scale_fake.return_val = 0; + + zassert_ok(host_cmd_motion_sense_scale( + /*sensor_num=*/0, + /*flags=*/MOTION_SENSE_SET_OFFSET, + /*temperature=*/1, /*scale_x=*/2, + /*scale_y=*/3, /*scale_z=*/4, &response), + NULL); + zassert_equal(1, mock_set_scale_fake.call_count, NULL); + zassert_equal(1, mock_get_scale_fake.call_count, NULL); + zassert_equal(1, mock_set_scale_fake.arg2_history[0], NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_calib_invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_calib(/*sensor_num=*/0xff, + /*enable=*/false, &response), + NULL); +} + +ZTEST_USER(host_cmd_motion_sense, test_calib_not_in_driver) +{ + struct ec_response_motion_sense response; + struct accelgyro_drv drv = { 0 }; + + motion_sensors[0].drv = &drv; + zassert_equal(EC_RES_INVALID_COMMAND, + host_cmd_motion_sense_calib(/*sensor_num=*/0, + /*enable=*/false, &response), + NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_calib_fail) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_perform_calib_fake.return_val = 1; + + zassert_equal(1, + host_cmd_motion_sense_calib(/*sensor_num=*/0, + /*enable=*/false, &response), + NULL); + zassert_equal(1, mock_perform_calib_fake.call_count, NULL); + zassert_false(mock_perform_calib_fake.arg1_history[0], NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_calib_success__fail_get_offset) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_perform_calib_fake.return_val = 0; + mock_get_offset_fake.return_val = 1; + + zassert_equal(1, + host_cmd_motion_sense_calib(/*sensor_num=*/0, + /*enable=*/false, &response), + NULL); + zassert_equal(1, mock_perform_calib_fake.call_count, NULL); + zassert_equal(1, mock_get_offset_fake.call_count, NULL); + zassert_false(mock_perform_calib_fake.arg1_history[0], NULL); +} + +ZTEST_USER_F(host_cmd_motion_sense, test_calib) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].drv = &fixture->mock_drv; + mock_perform_calib_fake.return_val = 0; + mock_get_offset_fake.return_val = 0; + + zassert_ok(host_cmd_motion_sense_calib(/*sensor_num=*/0, + /*enable=*/true, &response), + NULL); + zassert_equal(1, mock_perform_calib_fake.call_count, NULL); + zassert_equal(1, mock_get_offset_fake.call_count, NULL); + zassert_true(mock_perform_calib_fake.arg1_history[0], NULL); +} + +ZTEST(host_cmd_motion_sense, test_fifo_flush__invalid_sensor_num) +{ + int rv; + struct ec_response_motion_sense response; + + rv = host_cmd_motion_sense_fifo_flush(/*sensor_num=*/0xff, &response); + zassert_equal(rv, EC_RES_INVALID_PARAM, NULL); +} + +ZTEST(host_cmd_motion_sense, test_fifo_flush) +{ + uint8_t response_buffer[RESPONSE_SENSOR_FIFO_SIZE(ALL_MOTION_SENSORS)]; + struct ec_response_motion_sense *response = + (struct ec_response_motion_sense *)response_buffer; + + zassert_ok(host_cmd_motion_sense_fifo_flush(/*sensor_num=*/0, response), + NULL); + zassert_equal(1, motion_sensors[0].flush_pending, NULL); +} + +ZTEST(host_cmd_motion_sense, test_fifo_info) +{ + uint8_t response_buffer[RESPONSE_SENSOR_FIFO_SIZE(ALL_MOTION_SENSORS)]; + struct ec_response_motion_sense *response = + (struct ec_response_motion_sense *)response_buffer; + + zassert_ok(host_cmd_motion_sense_fifo_info(response), NULL); +} + +ZTEST(host_cmd_motion_sense, test_fifo_read) +{ + struct ec_response_motion_sensor_data data; + uint8_t response_buffer[RESPONSE_MOTION_SENSE_BUFFER_SIZE(2)]; + struct ec_response_motion_sense *response = + (struct ec_response_motion_sense *)response_buffer; + + motion_sensors[0].oversampling_ratio = 1; + motion_sensors[1].oversampling_ratio = 1; + + data = (struct ec_response_motion_sensor_data){ + .flags = 0, + .sensor_num = 0, + .data = { 0, 1, 2 }, + }; + motion_sense_fifo_stage_data(&data, &motion_sensors[0], 1, 0); + + data = (struct ec_response_motion_sensor_data){ + .flags = 0, + .sensor_num = 1, + .data = { 3, 4, 5 }, + }; + motion_sense_fifo_stage_data(&data, &motion_sensors[1], 1, 5); + motion_sense_fifo_commit_data(); + + /* Read 2 samples */ + zassert_ok(host_cmd_motion_sense_fifo_read(4, response), NULL); + zassert_equal(2, response->fifo_read.number_data, NULL); + + zassert_equal(MOTIONSENSE_SENSOR_FLAG_TIMESTAMP, + response->fifo_read.data[0].flags, NULL); + zassert_equal(0, response->fifo_read.data[0].sensor_num, NULL); + zassert_equal(0, response->fifo_read.data[0].timestamp, NULL); + + zassert_equal(0, response->fifo_read.data[1].flags, NULL); + zassert_equal(0, response->fifo_read.data[1].sensor_num, NULL); + zassert_equal(0, response->fifo_read.data[1].data[0], NULL); + zassert_equal(1, response->fifo_read.data[1].data[1], NULL); + zassert_equal(2, response->fifo_read.data[1].data[2], NULL); + + /* Read the next 2 samples */ + zassert_ok(host_cmd_motion_sense_fifo_read(4, response), NULL); + zassert_equal(2, response->fifo_read.number_data, NULL); + zassert_equal(MOTIONSENSE_SENSOR_FLAG_TIMESTAMP, + response->fifo_read.data[0].flags, NULL); + zassert_equal(1, response->fifo_read.data[0].sensor_num, NULL); + zassert_equal(5, response->fifo_read.data[0].timestamp, NULL); + + zassert_equal(0, response->fifo_read.data[1].flags, NULL); + zassert_equal(1, response->fifo_read.data[1].sensor_num, NULL); + zassert_equal(3, response->fifo_read.data[1].data[0], NULL); + zassert_equal(4, response->fifo_read.data[1].data[1], NULL); + zassert_equal(5, response->fifo_read.data[1].data[2], NULL); +} + +ZTEST(host_cmd_motion_sense, test_int_enable) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_int_enable(2, &response), NULL); + + /* Make sure we start off disabled */ + zassume_ok(host_cmd_motion_sense_int_enable(0, &response), NULL); + + /* Test enable */ + zassert_ok(host_cmd_motion_sense_int_enable(1, &response), NULL); + zassert_ok(host_cmd_motion_sense_int_enable(EC_MOTION_SENSE_NO_VALUE, + &response), + NULL); + zassert_equal(1, response.fifo_int_enable.ret, NULL); + + /* Test disable */ + zassert_ok(host_cmd_motion_sense_int_enable(0, &response), NULL); + zassert_ok(host_cmd_motion_sense_int_enable(EC_MOTION_SENSE_NO_VALUE, + &response), + NULL); + zassert_equal(0, response.fifo_int_enable.ret, NULL); +} + +ZTEST(host_cmd_motion_sense, test_spoof_invalid_sensor_num) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_spoof(0xff, 0, 0, 0, 0, &response), + NULL); +} + +ZTEST(host_cmd_motion_sense, test_spoof_disable) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].flags |= MOTIONSENSE_FLAG_IN_SPOOF_MODE; + zassert_ok(host_cmd_motion_sense_spoof(0, + MOTIONSENSE_SPOOF_MODE_DISABLE, + 0, 0, 0, &response), + NULL); + zassert_equal(0, + motion_sensors[0].flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE, + NULL); + + zassert_ok(host_cmd_motion_sense_spoof(0, MOTIONSENSE_SPOOF_MODE_QUERY, + 0, 0, 0, &response), + NULL); + zassert_false(response.spoof.ret, NULL); +} + +ZTEST(host_cmd_motion_sense, test_spoof_custom) +{ + struct ec_response_motion_sense response; + + zassert_ok(host_cmd_motion_sense_spoof(0, MOTIONSENSE_SPOOF_MODE_CUSTOM, + -8, 16, -32, &response), + NULL); + zassert_equal(MOTIONSENSE_FLAG_IN_SPOOF_MODE, + motion_sensors[0].flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE, + NULL); + zassert_equal(-8, motion_sensors[0].spoof_xyz[0], NULL); + zassert_equal(16, motion_sensors[0].spoof_xyz[1], NULL); + zassert_equal(-32, motion_sensors[0].spoof_xyz[2], NULL); + + zassert_ok(host_cmd_motion_sense_spoof(0, MOTIONSENSE_SPOOF_MODE_QUERY, + 0, 0, 0, &response), + NULL); + zassert_true(response.spoof.ret, NULL); +} + +ZTEST(host_cmd_motion_sense, test_spoof_lock_current) +{ + struct ec_response_motion_sense response; + + motion_sensors[0].raw_xyz[0] = 64; + motion_sensors[0].raw_xyz[1] = 48; + motion_sensors[0].raw_xyz[2] = 32; + zassert_ok(host_cmd_motion_sense_spoof( + 0, MOTIONSENSE_SPOOF_MODE_LOCK_CURRENT, 0, 0, 0, + &response), + NULL); + zassert_equal(MOTIONSENSE_FLAG_IN_SPOOF_MODE, + motion_sensors[0].flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE, + NULL); + zassert_equal(64, motion_sensors[0].spoof_xyz[0], NULL); + zassert_equal(48, motion_sensors[0].spoof_xyz[1], NULL); + zassert_equal(32, motion_sensors[0].spoof_xyz[2], NULL); + + zassert_ok(host_cmd_motion_sense_spoof(0, MOTIONSENSE_SPOOF_MODE_QUERY, + 0, 0, 0, &response), + NULL); + zassert_true(response.spoof.ret, NULL); +} + +ZTEST(host_cmd_motion_sense, test_spoof_invalid_mode) +{ + struct ec_response_motion_sense response; + + zassert_equal(EC_RES_INVALID_PARAM, + host_cmd_motion_sense_spoof(0, 0xff, 0, 0, 0, &response), + NULL); +} diff --git a/zephyr/test/drivers/host_cmd/src/pd_chip_info.c b/zephyr/test/drivers/host_cmd/src/pd_chip_info.c new file mode 100644 index 0000000000..95e2339899 --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/pd_chip_info.c @@ -0,0 +1,65 @@ +/* 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/shell/shell.h> +#include <zephyr/ztest.h> + +#include "console.h" +#include "ec_commands.h" +#include "test/drivers/stubs.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +#define TEST_PORT USBC_PORT_C0 +#define BAD_PORT 65 + +static enum ec_status run_pd_chip_info(int port, + struct ec_response_pd_chip_info_v1 *resp) +{ + struct ec_params_pd_chip_info params = { .port = port, .live = true }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND(EC_CMD_PD_CHIP_INFO, 1, resp, params); + + return host_command_process(&args); +} + +ZTEST_USER(host_cmd_pd_chip_info, test_good_index) +{ + struct ec_response_pd_chip_info_v1 response; + + zassert_ok(run_pd_chip_info(TEST_PORT, &response), + "Failed to process pd_get_chip_info for port %d", TEST_PORT); + /* + * Note: verification of the specific fields depends on the chips used + * and therefore would belong in a driver-level test + */ +} + +ZTEST_USER(host_cmd_pd_chip_info, test_bad_index) +{ + struct ec_response_pd_chip_info_v1 response; + + zassume_true(board_get_usb_pd_port_count() < BAD_PORT, + "Intended bad port exists"); + zassert_equal(run_pd_chip_info(BAD_PORT, &response), + EC_RES_INVALID_PARAM, + "Failed to fail pd_chip_info for port %d", BAD_PORT); +} + +static void host_cmd_pd_chip_info_begin(void *data) +{ + ARG_UNUSED(data); + + /* Assume we have at least one USB-C port */ + zassume_true(board_get_usb_pd_port_count() > 0, + "Insufficient TCPCs found"); + + /* Set the system into S0, since the AP would drive these commands */ + test_set_chipset_to_s0(); + k_sleep(K_SECONDS(1)); +} + +ZTEST_SUITE(host_cmd_pd_chip_info, drivers_predicate_post_main, NULL, + host_cmd_pd_chip_info_begin, NULL, NULL); diff --git a/zephyr/test/drivers/host_cmd/src/pd_control.c b/zephyr/test/drivers/host_cmd/src/pd_control.c new file mode 100644 index 0000000000..e8de27f6ce --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/pd_control.c @@ -0,0 +1,129 @@ +/* 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/fff.h> +#include <zephyr/shell/shell.h> +#include <zephyr/ztest.h> + +#include "console.h" +#include "ec_commands.h" +#include "test/drivers/stubs.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +#define TEST_PORT USBC_PORT_C0 +#define BAD_PORT 82 + +ZTEST_USER(host_cmd_pd_control, test_bad_index) +{ + struct ec_params_pd_control params = { .chip = BAD_PORT, + .subcmd = PD_RESET }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_PARAMS(EC_CMD_PD_CONTROL, 0, params); + + zassume_true(board_get_usb_pd_port_count() < BAD_PORT, + "Intended bad port exists"); + zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM, + "Failed to fail pd_control for port %d", params.chip); +} + +ZTEST_USER(host_cmd_pd_control, test_unimplemented_command) +{ + struct ec_params_pd_control params = { .chip = TEST_PORT, + .subcmd = PD_CHIP_ON }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_PARAMS(EC_CMD_PD_CONTROL, 0, params); + + zassert_equal(host_command_process(&args), EC_RES_INVALID_COMMAND, + "Failed to fail pd_control for port %d", params.chip); +} + +ZTEST_USER(host_cmd_pd_control, test_pd_reset_resume) +{ + /* + * Note: this would ideally be a host command interface check, but + * the only HC return which would cover this is a state string, which + * could be brittle. + */ + zassume_true(pd_is_port_enabled(TEST_PORT), "Port not up at beginning"); + + host_cmd_pd_control(TEST_PORT, PD_RESET); + + zassert_equal(1, board_reset_pd_mcu_fake.call_count, + "Failed to see board reset"); + + /* Give some PD task processing time */ + k_sleep(K_SECONDS(1)); + + zassert_false(pd_is_port_enabled(TEST_PORT), "Port failed to suspend"); + + host_cmd_pd_control(TEST_PORT, PD_RESUME); + + /* Give some PD task processing time */ + k_sleep(K_SECONDS(1)); + + zassert_true(pd_is_port_enabled(TEST_PORT), "Port failed to resume"); + + RESET_FAKE(board_reset_pd_mcu); +} + +ZTEST_USER(host_cmd_pd_control, test_suspend_resume) +{ + /* + * Note: this would ideally be a host command interface check, but + * the only HC return which would cover this is a state string, which + * could be brittle. + */ + zassume_true(pd_is_port_enabled(TEST_PORT), "Port not up at beginning"); + + host_cmd_pd_control(TEST_PORT, PD_SUSPEND); + + /* Give some PD task processing time */ + k_sleep(K_SECONDS(1)); + + zassert_false(pd_is_port_enabled(TEST_PORT), "Port failed to suspend"); + + host_cmd_pd_control(TEST_PORT, PD_RESUME); + + /* Give some PD task processing time */ + k_sleep(K_SECONDS(1)); + + zassert_true(pd_is_port_enabled(TEST_PORT), "Port failed to resume"); +} + +ZTEST_USER(host_cmd_pd_control, test_control_disable) +{ + struct ec_params_pd_control params = { .chip = TEST_PORT, + .subcmd = PD_RESET }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_PARAMS(EC_CMD_PD_CONTROL, 0, params); + + host_cmd_pd_control(TEST_PORT, PD_CONTROL_DISABLE); + + zassert_equal(host_command_process(&args), EC_RES_ACCESS_DENIED, + "Access was not denied for port %d", params.chip); + + /* + * Disable lasts as long as the EC is booted. Use a test hook to + * restore our state to a normal one + */ + pd_control_port_enable(TEST_PORT); +} + +static void host_cmd_pd_control_begin(void *data) +{ + ARG_UNUSED(data); + + /* Assume we have at least one USB-C port */ + zassume_true(board_get_usb_pd_port_count() > 0, + "Insufficient TCPCs found"); + + /* Set the system into S0, since the AP would drive these commands */ + test_set_chipset_to_s0(); + k_sleep(K_SECONDS(1)); +} + +ZTEST_SUITE(host_cmd_pd_control, drivers_predicate_post_main, NULL, + host_cmd_pd_control_begin, NULL, NULL); diff --git a/zephyr/test/drivers/host_cmd/src/pd_log.c b/zephyr/test/drivers/host_cmd/src/pd_log.c new file mode 100644 index 0000000000..a6022d8bb1 --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/pd_log.c @@ -0,0 +1,135 @@ +/* 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/kernel.h> +#include <zephyr/ztest.h> + +#include "event_log.h" +#include "host_command.h" +#include "test/drivers/test_state.h" +#include "usb_pd.h" + +/** + * @brief This is the maximum size of a single log entry. + * + * Each entry must contain some common data + up to 16 bytes of additional type + * specific data. + */ +#define MAX_EVENT_LOG_ENTRY_SIZE (sizeof(struct event_log_entry) + 16) + +/** + * @brief The size of the PD log entry data + * + * Logs from the PD include an additional 8 bytes of data to be sent to the AP. + */ +#define PD_LOG_ENTRY_DATA_SIZE (8) + +struct pd_log_fixture { + union { + uint8_t event_log_buffer[MAX_EVENT_LOG_ENTRY_SIZE]; + struct event_log_entry log_entry; + }; +}; + +static void *pd_log_setup(void) +{ + static struct pd_log_fixture fixture; + + return &fixture; +} + +static void pd_log_before(void *f) +{ + struct pd_log_fixture *fixture = f; + + while (log_dequeue_event(&fixture->log_entry) != 0) { + if (fixture->log_entry.type == EVENT_LOG_NO_ENTRY) { + break; + } + } +} + +ZTEST_SUITE(pd_log, drivers_predicate_post_main, pd_log_setup, pd_log_before, + NULL, NULL); + +ZTEST_USER(pd_log, test_bad_type) +{ + struct ec_params_pd_write_log_entry params = { + .type = PD_EVENT_ACC_BASE, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_PD_WRITE_LOG_ENTRY, UINT8_C(0), params); + + zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&args), NULL); +} + +ZTEST_USER(pd_log, test_bad_port) +{ + struct ec_params_pd_write_log_entry params = { + .type = PD_EVENT_MCU_BASE, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_PD_WRITE_LOG_ENTRY, UINT8_C(0), params); + + params.port = board_get_usb_pd_port_count() + 1; + zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&args), NULL); +} + +ZTEST_USER_F(pd_log, test_mcu_charge) +{ + struct ec_params_pd_write_log_entry params = { + .type = PD_EVENT_MCU_CHARGE, + .port = 0, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_PD_WRITE_LOG_ENTRY, UINT8_C(0), params); + + zassert_ok(host_command_process(&args), NULL); + zassert_equal(sizeof(struct event_log_entry) + PD_LOG_ENTRY_DATA_SIZE, + log_dequeue_event(&fixture->log_entry), NULL); + zassert_equal(params.type, fixture->log_entry.type, NULL); + zassert_equal(PD_LOG_ENTRY_DATA_SIZE, fixture->log_entry.size, NULL); + zassert_equal(0, fixture->log_entry.data, NULL); + zassert_within(0, (int64_t)fixture->log_entry.timestamp, 10, + "Expected timestamp %" PRIi64 + " to be within 10 ms of now", + (int64_t)fixture->log_entry.timestamp); +} +ZTEST_USER_F(pd_log, test_mcu_connect) +{ + struct ec_params_pd_write_log_entry params = { + .type = PD_EVENT_MCU_CONNECT, + .port = 0, + }; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND_PARAMS( + EC_CMD_PD_WRITE_LOG_ENTRY, UINT8_C(0), params); + + zassert_ok(host_command_process(&args), NULL); + zassert_equal(sizeof(struct event_log_entry), + log_dequeue_event(&fixture->log_entry), NULL); + zassert_equal(params.type, fixture->log_entry.type, NULL); + zassert_equal(0, fixture->log_entry.size, NULL); + zassert_equal(0, fixture->log_entry.data, NULL); + zassert_within(0, (int64_t)fixture->log_entry.timestamp, 10, + "Expected timestamp %" PRIi64 + " to be within 10 ms of now", + (int64_t)fixture->log_entry.timestamp); +} + +ZTEST_USER_F(pd_log, test_read_log_entry) +{ + uint8_t response_buffer[sizeof(struct ec_response_pd_log) + 16]; + struct ec_response_pd_log *response = + (struct ec_response_pd_log *)response_buffer; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_SIMPLE(EC_CMD_PD_GET_LOG_ENTRY, UINT8_C(0)); + + args.response = response; + args.response_max = sizeof(response_buffer); + + zassert_ok(host_command_process(&args), NULL); + zassert_equal(sizeof(struct event_log_entry), args.response_size, NULL); + zassert_equal(PD_EVENT_NO_ENTRY, response->type, NULL); +} diff --git a/zephyr/test/drivers/host_cmd/src/usb_pd_control.c b/zephyr/test/drivers/host_cmd/src/usb_pd_control.c new file mode 100644 index 0000000000..c439141da9 --- /dev/null +++ b/zephyr/test/drivers/host_cmd/src/usb_pd_control.c @@ -0,0 +1,151 @@ +/* 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/shell/shell.h> +#include <zephyr/ztest.h> + +#include "console.h" +#include "ec_commands.h" +#include "emul/emul_isl923x.h" +#include "emul/tcpc/emul_ps8xxx.h" +#include "emul/tcpc/emul_tcpci.h" +#include "emul/tcpc/emul_tcpci_partner_snk.h" +#include "test/drivers/stubs.h" +#include "test/drivers/test_state.h" +#include "test/drivers/utils.h" + +#define TEST_PORT USBC_PORT_C0 +#define BAD_PORT 42 + +struct host_cmd_usb_pd_control_fixture { + const struct emul *tcpci_emul; + const struct emul *charger_emul; + struct tcpci_partner_data partner; + struct tcpci_snk_emul_data snk_ext; +}; + +static enum ec_status +run_usb_pd_control(int port, struct ec_response_usb_pd_control_v2 *resp) +{ + /* + * Note: while arguments exist to change the PD state, their use is + * discouraged as that causes the response to have non-deterministic + * results. The kernel only uses the "no change" parameters, so that is + * what we shall test here. + */ + struct ec_params_usb_pd_control params = { + .port = port, + .role = USB_PD_CTRL_ROLE_NO_CHANGE, + .mux = USB_PD_CTRL_MUX_NO_CHANGE, + .swap = USB_PD_CTRL_SWAP_NONE + }; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND(EC_CMD_USB_PD_CONTROL, 2, *resp, params); + + return host_command_process(&args); +} + +ZTEST_USER(host_cmd_usb_pd_control, test_good_index_no_partner) +{ + struct ec_response_usb_pd_control_v2 response; + + zassert_ok(run_usb_pd_control(TEST_PORT, &response), + "Failed to process usb_pd_control for port %d", TEST_PORT); + + /* Verify basic not-connected expectations */ + zassert_equal(response.enabled, 0, + "Failed to find nothing enabled: 0x%02x", + response.enabled); + /* Don't verify role, cc, or polarity as it isn't meaningful */ + zassert_equal(response.control_flags, 0, "Failed to see flags cleared"); +} + +ZTEST_USER_F(host_cmd_usb_pd_control, test_good_index_sink_partner) +{ + struct ec_response_usb_pd_control_v2 response; + + /* Attach simple sink that shouldn't do any swaps */ + connect_sink_to_port(&fixture->partner, fixture->tcpci_emul, + fixture->charger_emul); + + /* Wait for connection to settle */ + k_sleep(K_SECONDS(1)); + + zassert_ok(run_usb_pd_control(TEST_PORT, &response), + "Failed to process usb_pd_control for port %d", TEST_PORT); + + /* Verify basic sink expectations */ + zassert_equal( + response.enabled, + (PD_CTRL_RESP_ENABLED_COMMS | PD_CTRL_RESP_ENABLED_CONNECTED | + PD_CTRL_RESP_ENABLED_PD_CAPABLE), + "Failed to see full connection: 0x%02x", response.enabled); + /* + * We should be source, DFP, Vconn source, and we set our sink caps + * to USB comms + */ + zassert_equal(response.role, + (PD_CTRL_RESP_ROLE_USB_COMM | PD_CTRL_RESP_ROLE_POWER | + PD_CTRL_RESP_ROLE_DATA | PD_CTRL_RESP_ROLE_VCONN), + "Failed to see expected role: 0x%02x", response.role); + zassert_equal(response.cc_state, PD_CC_UFP_ATTACHED, + "Failed to see UFP attached"); + zassert_equal(response.control_flags, 0, "Failed to see flags cleared"); +} + +ZTEST_USER(host_cmd_usb_pd_control, test_bad_index) +{ + struct ec_response_usb_pd_control_v2 response; + + zassume_true(board_get_usb_pd_port_count() < BAD_PORT, + "Intended bad port exists"); + zassert_equal(run_usb_pd_control(BAD_PORT, &response), + EC_RES_INVALID_PARAM, + "Failed to fail usb_pd_control for port %d", BAD_PORT); +} + +static void *host_cmd_usb_pd_control_setup(void) +{ + static struct host_cmd_usb_pd_control_fixture fixture; + struct tcpci_partner_data *partner = &fixture.partner; + struct tcpci_snk_emul_data *snk_ext = &fixture.snk_ext; + + tcpci_partner_init(partner, PD_REV30); + partner->extensions = tcpci_snk_emul_init(snk_ext, partner, NULL); + + /* Get references for the emulators */ + fixture.tcpci_emul = EMUL_DT_GET(DT_NODELABEL(tcpci_emul)); + fixture.charger_emul = EMUL_DT_GET(DT_NODELABEL(isl923x_emul)); + + /* Sink 5V 3A. */ + snk_ext->pdo[0] = PDO_FIXED(5000, 3000, PDO_FIXED_COMM_CAP); + + return &fixture; +} + +static void host_cmd_usb_pd_control_before(void *data) +{ + ARG_UNUSED(data); + + /* Assume we have at least one USB-C port */ + zassume_true(board_get_usb_pd_port_count() > 0, + "Insufficient TCPCs found"); + + /* Set the system into S0, since the AP would drive these commands */ + test_set_chipset_to_s0(); + k_sleep(K_SECONDS(1)); +} + +static void host_cmd_usb_pd_control_after(void *data) +{ + struct host_cmd_usb_pd_control_fixture *fixture = data; + + disconnect_sink_from_port(fixture->tcpci_emul); + k_sleep(K_SECONDS(1)); +} + +ZTEST_SUITE(host_cmd_usb_pd_control, drivers_predicate_post_main, + host_cmd_usb_pd_control_setup, host_cmd_usb_pd_control_before, + host_cmd_usb_pd_control_after, NULL); |