diff options
author | Diana Z <dzigterman@chromium.org> | 2023-03-31 15:25:34 -0600 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-04-07 15:26:52 +0000 |
commit | 53f35199ba36aa3d983015399453326ee4724240 (patch) | |
tree | 318a5412ccbb5d8aa8fc67ed62365b13819a8a43 | |
parent | 414bd1fd6b99ae3d28cbccd458ce66e129592de2 (diff) | |
download | chrome-ec-53f35199ba36aa3d983015399453326ee4724240.tar.gz |
Zephyr test: Test NXP PPC interrupts
Add support for testing interrupts with the NX20P384X driver.
BRANCH=None
BUG=b:276468569
TEST=./twister -T ./zephyr/test
Change-Id: I3856063c367ec6d8ffcbd8599c3b62fa73e01b1f
Signed-off-by: Diana Z <dzigterman@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4389620
Reviewed-by: Tomasz Michalec <tmichalec@google.com>
-rw-r--r-- | driver/ppc/nx20p348x.c | 1 | ||||
-rw-r--r-- | zephyr/emul/emul_nx20p348x.c | 59 | ||||
-rw-r--r-- | zephyr/include/emul/emul_nx20p348x.h | 7 | ||||
-rw-r--r-- | zephyr/test/drivers/Kconfig | 1 | ||||
-rw-r--r-- | zephyr/test/drivers/nx20p348x/src/nx20p348x.c | 132 | ||||
-rw-r--r-- | zephyr/test/drivers/nx20p348x/usbc.dts | 1 | ||||
-rw-r--r-- | zephyr/test/drivers/usbc_ppc/ppc_alts.dts | 1 |
7 files changed, 184 insertions, 18 deletions
diff --git a/driver/ppc/nx20p348x.c b/driver/ppc/nx20p348x.c index b11dee30f4..cb35e9ff23 100644 --- a/driver/ppc/nx20p348x.c +++ b/driver/ppc/nx20p348x.c @@ -502,7 +502,6 @@ static int nx20p348x_dump(int port) int reg; int rv; - ccprintf("Port %d NX20P348X registers\n", port); for (reg_addr = NX20P348X_DEVICE_ID_REG; reg_addr <= NX20P348X_DEVICE_CONTROL_REG; reg_addr++) { rv = read_reg(port, reg_addr, ®); diff --git a/zephyr/emul/emul_nx20p348x.c b/zephyr/emul/emul_nx20p348x.c index a483295a69..c6704c2278 100644 --- a/zephyr/emul/emul_nx20p348x.c +++ b/zephyr/emul/emul_nx20p348x.c @@ -11,6 +11,9 @@ #include "util.h" #include <zephyr/device.h> +#include <zephyr/devicetree/gpio.h> +#include <zephyr/drivers/emul.h> +#include <zephyr/drivers/gpio/gpio_emul.h> #include <zephyr/logging/log.h> #include <zephyr/ztest.h> @@ -26,6 +29,7 @@ LOG_MODULE_REGISTER(emul_nx20p348x); struct nx20p348x_emul_data { struct i2c_common_emul_data common; + struct gpio_dt_spec irq_gpio; uint8_t regs[NX20P348X_MAX_REG + 1]; }; @@ -42,6 +46,16 @@ struct nx20p348x_reg_default nx20p348x_defaults[] = { { .offset = NX20P348X_5V_SRC_OCP_THRESHOLD_REG, .val = 0x0B }, }; +static void nx20p348x_emul_interrupt_set(const struct emul *emul, int val) +{ + struct nx20p348x_emul_data *data = + (struct nx20p348x_emul_data *)emul->data; + + int res = gpio_emul_input_set(data->irq_gpio.port, data->irq_gpio.pin, + val); + __ASSERT_NO_MSG(res == 0); +} + void nx20p348x_emul_reset_regs(const struct emul *emul) { struct nx20p348x_emul_data *data = @@ -54,6 +68,7 @@ void nx20p348x_emul_reset_regs(const struct emul *emul) data->regs[def.offset] = def.val; } + nx20p348x_emul_interrupt_set(emul, 1); } uint8_t nx20p348x_emul_peek(const struct emul *emul, int reg) @@ -66,26 +81,40 @@ uint8_t nx20p348x_emul_peek(const struct emul *emul, int reg) return data->regs[reg]; } +void nx20p348x_emul_set_interrupt1(const struct emul *emul, uint8_t val) +{ + struct nx20p348x_emul_data *data = + (struct nx20p348x_emul_data *)emul->data; + + data->regs[NX20P348X_INTERRUPT1_REG] = val; + + nx20p348x_emul_interrupt_set(emul, 0); +} + static int nx20p348x_emul_read(const struct emul *emul, int reg, uint8_t *val, int bytes, void *unused_data) { struct nx20p348x_emul_data *data = (struct nx20p348x_emul_data *)emul->data; - if (!IN_RANGE(reg, 0, NX20P348X_MAX_REG)) { - LOG_ERR("Register out of range: %d", reg); + if (!IN_RANGE(reg, 0, NX20P348X_MAX_REG)) return -EINVAL; - } - if (bytes != 0) { - LOG_ERR("Emulator expects single byte transactions: " - "%d bytes requested", - bytes); + if (bytes != 0) return -EINVAL; - } *val = data->regs[reg]; + /* Interrupt registers are clear on read and de-assert when serviced */ + if (reg == NX20P348X_INTERRUPT1_REG || + reg == NX20P348X_INTERRUPT2_REG) { + data->regs[reg] = 0; + + if (data->regs[NX20P348X_INTERRUPT1_REG] == 0 && + data->regs[NX20P348X_INTERRUPT2_REG] == 0) + nx20p348x_emul_interrupt_set(emul, 1); + } + return 0; } @@ -95,17 +124,11 @@ static int nx20p348x_emul_write(const struct emul *emul, int reg, uint8_t val, struct nx20p348x_emul_data *data = (struct nx20p348x_emul_data *)emul->data; - if (!IN_RANGE(reg, 0, NX20P348X_MAX_REG)) { - LOG_ERR("Register out of range: %d", reg); + if (!IN_RANGE(reg, 0, NX20P348X_MAX_REG)) return -EINVAL; - } - if (bytes != 1) { - LOG_ERR("Emulator expects single byte transactions: " - "%d bytes written", - bytes); + if (bytes != 1) return -EINVAL; - } data->regs[reg] = val; @@ -129,13 +152,15 @@ static int nx20p348x_emul_init(const struct emul *emul, } #define INIT_NX20P348X_EMUL(n) \ - static struct i2c_common_emul_cfg common_cfg_##n; \ static struct nx20p348x_emul_data nx20p348x_emul_data_##n; \ static struct i2c_common_emul_cfg common_cfg_##n = { \ .dev_label = DT_NODE_FULL_NAME(DT_DRV_INST(n)), \ .data = &nx20p348x_emul_data_##n.common, \ .addr = DT_INST_REG_ADDR(n) \ }; \ + static struct nx20p348x_emul_data nx20p348x_emul_data_##n = { \ + .irq_gpio = GPIO_DT_SPEC_INST_GET_OR(n, irq_gpios, {}), \ + }; \ EMUL_DT_INST_DEFINE(n, nx20p348x_emul_init, &nx20p348x_emul_data_##n, \ &common_cfg_##n, &i2c_common_emul_api, NULL) diff --git a/zephyr/include/emul/emul_nx20p348x.h b/zephyr/include/emul/emul_nx20p348x.h index 74e0041230..a8435ee530 100644 --- a/zephyr/include/emul/emul_nx20p348x.h +++ b/zephyr/include/emul/emul_nx20p348x.h @@ -17,4 +17,11 @@ */ uint8_t nx20p348x_emul_peek(const struct emul *emul, int reg); +/** + * Set an interrupt in the first interrupt register + * + * @param emul - NX20P383X emulator data + * @param val - value for interrupt register + */ +void nx20p348x_emul_set_interrupt1(const struct emul *emul, uint8_t val); #endif diff --git a/zephyr/test/drivers/Kconfig b/zephyr/test/drivers/Kconfig index 1cafa840df..eed9233cd7 100644 --- a/zephyr/test/drivers/Kconfig +++ b/zephyr/test/drivers/Kconfig @@ -101,6 +101,7 @@ config LINK_TEST_SUITE_NX20P348X bool "Link and test the nx20p348x tests" select PLATFORM_EC_CONSOLE_CMD_PPC_DUMP select PLATFORM_EC_USBC_PPC_NX20P3483 + select PLATFORM_EC_USB_PD_LOGGING config LINK_TEST_SUITE_PANIC_OUTPUT bool "Link and test the panic_output tests" diff --git a/zephyr/test/drivers/nx20p348x/src/nx20p348x.c b/zephyr/test/drivers/nx20p348x/src/nx20p348x.c index 5f98768d06..151a7dea66 100644 --- a/zephyr/test/drivers/nx20p348x/src/nx20p348x.c +++ b/zephyr/test/drivers/nx20p348x/src/nx20p348x.c @@ -112,3 +112,135 @@ ZTEST(nx20p348x_driver, test_ppc_dump) /* Weakly verify something reasonable was output to console */ zassert_not_null(strstr(outbuffer, "]: 0x")); } + +ZTEST_F(nx20p348x_driver, test_db_exit_err) +{ + uint8_t reg; + + /* Test an error to exit dead battery mode */ + nx20p348x_emul_set_interrupt1(fixture->nx20p348x_emul, + NX20P348X_INT1_DBEXIT_ERR); + + /* Give the interrupt time to process */ + k_sleep(K_MSEC(500)); + + /* Interrupt should have set DB exit in the control register */ + reg = nx20p348x_emul_peek(fixture->nx20p348x_emul, + NX20P348X_DEVICE_CONTROL_REG); + zassert_equal((reg & NX20P348X_CTRL_DB_EXIT), NX20P348X_CTRL_DB_EXIT); +} + +ZTEST_F(nx20p348x_driver, test_db_exit_err_max) +{ + uint8_t reg; + + /* Set a DB exit error 10 times */ + for (int i = 0; i < 10; i++) { + nx20p348x_emul_set_interrupt1(fixture->nx20p348x_emul, + NX20P348X_INT1_DBEXIT_ERR); + k_sleep(K_MSEC(500)); + } + + /* Interrupt should now be masked by the driver */ + reg = nx20p348x_emul_peek(fixture->nx20p348x_emul, + NX20P348X_INTERRUPT1_MASK_REG); + zassert_equal((reg & NX20P348X_INT1_DBEXIT_ERR), + NX20P348X_INT1_DBEXIT_ERR); +} + +/* Add filler in case of event data */ +#define MAX_RESPONSE_PD_LOG_ENTRY_SIZE (sizeof(struct ec_response_pd_log) + 16) + +static void flush_pd_log(void) +{ + uint8_t response_buffer[MAX_RESPONSE_PD_LOG_ENTRY_SIZE]; + 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, 0); + + args.response = response; + args.response_max = sizeof(response_buffer); + + for (int i = 0; i < 10; i++) { + zassert_ok(host_command_process(&args)); + + if (response->type == PD_EVENT_NO_ENTRY) + return; + + k_sleep(K_MSEC(500)); + } + + zassert_unreachable("Failed to flush PD log"); +} + +ZTEST_F(nx20p348x_driver, test_vbus_overcurrent) +{ + uint8_t response_buffer[MAX_RESPONSE_PD_LOG_ENTRY_SIZE]; + 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, 0); + + flush_pd_log(); + + /* Set up overcurrent */ + nx20p348x_emul_set_interrupt1(fixture->nx20p348x_emul, + NX20P348X_INT1_OC_5VSRC); + k_sleep(K_MSEC(500)); + + args.response = response; + args.response_max = sizeof(response_buffer); + + zassert_ok(host_command_process(&args)); + zassert_equal(TEST_PORT, PD_LOG_PORT(response->size_port)); + zassert_equal(0, PD_LOG_SIZE(response->size_port)); + zassert_equal(PD_EVENT_PS_FAULT, response->type); + zassert_equal(PS_FAULT_OCP, response->data); +} + +ZTEST_F(nx20p348x_driver, test_vbus_reverse_current) +{ + uint8_t response_buffer[MAX_RESPONSE_PD_LOG_ENTRY_SIZE]; + 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, 0); + + flush_pd_log(); + + /* Set up reverse current */ + nx20p348x_emul_set_interrupt1(fixture->nx20p348x_emul, + NX20P348X_INT1_RCP_5VSRC); + k_sleep(K_MSEC(500)); + + args.response = response; + args.response_max = sizeof(response_buffer); + + zassert_ok(host_command_process(&args)); + zassert_equal(TEST_PORT, PD_LOG_PORT(response->size_port)); + zassert_equal(0, PD_LOG_SIZE(response->size_port)); + zassert_equal(PD_EVENT_PS_FAULT, response->type); + zassert_equal(PS_FAULT_OCP, response->data); +} + +ZTEST_F(nx20p348x_driver, test_vbus_short) +{ + const struct shell *shell_zephyr = get_ec_shell(); + const char *outbuffer; + size_t buffer_size; + + shell_backend_dummy_clear_output(shell_zephyr); + + /* Set up Vbus short, which we only report in the console */ + nx20p348x_emul_set_interrupt1(fixture->nx20p348x_emul, + NX20P348X_INT1_SC_5VSRC); + k_sleep(K_MSEC(500)); + + outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size); + + zassert_true(buffer_size > 0); + + /* Weakly verify something reasonable was output to console */ + zassert_not_null(strstr(outbuffer, "short")); +} diff --git a/zephyr/test/drivers/nx20p348x/usbc.dts b/zephyr/test/drivers/nx20p348x/usbc.dts index 09650cea69..86fb5781d6 100644 --- a/zephyr/test/drivers/nx20p348x/usbc.dts +++ b/zephyr/test/drivers/nx20p348x/usbc.dts @@ -21,5 +21,6 @@ compatible = "nxp,nx20p348x"; status = "okay"; reg = <0x71>; + irq-gpios = < &gpio0 14 GPIO_ACTIVE_LOW >; }; }; diff --git a/zephyr/test/drivers/usbc_ppc/ppc_alts.dts b/zephyr/test/drivers/usbc_ppc/ppc_alts.dts index d0978238c3..ed84ff0662 100644 --- a/zephyr/test/drivers/usbc_ppc/ppc_alts.dts +++ b/zephyr/test/drivers/usbc_ppc/ppc_alts.dts @@ -20,6 +20,7 @@ compatible = "nxp,nx20p348x"; status = "okay"; reg = <0x77>; + irq-gpios = < &gpio0 14 GPIO_ACTIVE_LOW >; is-alt; }; |