From 2d0aafb8a358476f33e857565576f25c12513104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C5=82=C4=85b?= Date: Wed, 18 Dec 2024 08:30:27 +0100 Subject: [PATCH] [nrf fromlist] tests: drivers: hwinfo: Add test for reset cause on nrf54h20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test that checks reset cause reported by HWINFO. Check that hwinfo_get_supported_reset_cause() returns expected value. Check that hwinfo_get_reset_cause() correctly detects: - RESET_PIN, - RESET_SOFTWARE, - RESET_WATCHDOG. Check that reset cause can be cleared with hwinfo_clear_reset_cause(). Upstream PR #: 83126 Signed-off-by: Sebastian Głąb --- .../drivers/hwinfo/reset_cause/CMakeLists.txt | 8 + .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 2 + .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 14 + .../boards/nrf54h20dk_nrf54h20_cpurad.conf | 2 + .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 14 + .../boards/nrf54l15dk_nrf54l15_cpuapp.overlay | 9 + tests/drivers/hwinfo/reset_cause/prj.conf | 7 + tests/drivers/hwinfo/reset_cause/src/main.c | 353 ++++++++++++++++++ .../drivers/hwinfo/reset_cause/testcase.yaml | 37 ++ 9 files changed, 446 insertions(+) create mode 100644 tests/drivers/hwinfo/reset_cause/CMakeLists.txt create mode 100644 tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.conf create mode 100644 tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.conf create mode 100644 tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.overlay create mode 100644 tests/drivers/hwinfo/reset_cause/boards/nrf54l15dk_nrf54l15_cpuapp.overlay create mode 100644 tests/drivers/hwinfo/reset_cause/prj.conf create mode 100644 tests/drivers/hwinfo/reset_cause/src/main.c create mode 100644 tests/drivers/hwinfo/reset_cause/testcase.yaml diff --git a/tests/drivers/hwinfo/reset_cause/CMakeLists.txt b/tests/drivers/hwinfo/reset_cause/CMakeLists.txt new file mode 100644 index 00000000000..f659d208cb9 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(reset_reason) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..45e31e2fae4 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1,2 @@ +# Disable dcache +CONFIG_DCACHE=n diff --git a/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..ead2840f6f4 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,14 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &wdt010; + }; +}; + +&wdt010 { + status = "okay"; +}; diff --git a/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.conf b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.conf new file mode 100644 index 00000000000..45e31e2fae4 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.conf @@ -0,0 +1,2 @@ +# Disable dcache +CONFIG_DCACHE=n diff --git a/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..ead2840f6f4 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,14 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &wdt010; + }; +}; + +&wdt010 { + status = "okay"; +}; diff --git a/tests/drivers/hwinfo/reset_cause/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/tests/drivers/hwinfo/reset_cause/boards/nrf54l15dk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..8d3dce3b380 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt31 { + status = "okay"; +}; diff --git a/tests/drivers/hwinfo/reset_cause/prj.conf b/tests/drivers/hwinfo/reset_cause/prj.conf new file mode 100644 index 00000000000..edd86844963 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/prj.conf @@ -0,0 +1,7 @@ +CONFIG_HWINFO=y + +CONFIG_WATCHDOG=y +CONFIG_REBOOT=y + +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y diff --git a/tests/drivers/hwinfo/reset_cause/src/main.c b/tests/drivers/hwinfo/reset_cause/src/main.c new file mode 100644 index 00000000000..f5bd25de2b5 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/src/main.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(resetreason, LOG_LEVEL_INF); + +static const struct device *const my_wdt_device = DEVICE_DT_GET(DT_ALIAS(watchdog0)); +static struct wdt_timeout_cfg m_cfg_wdt0; +static int my_wdt_channel; + +#define NOINIT_SECTION ".noinit.test_wdt" +volatile uint32_t machine_state __attribute__((section(NOINIT_SECTION))); +volatile uint32_t supported __attribute__((section(NOINIT_SECTION))); +volatile uint32_t wdt_status __attribute__((section(NOINIT_SECTION))); +volatile uint32_t reboot_status __attribute__((section(NOINIT_SECTION))); + +/* Value used to indicate that the watchdog has fired. */ +#define WDT_HAS_FIRED (0x12345678U) +#define REBOOT_WAS_DONE (0x87654321U) + +/* Highest value in the switch statement in the main() */ +#define LAST_STATE (2) + +static void wdt_int_cb(const struct device *wdt_dev, int channel_id) +{ + ARG_UNUSED(wdt_dev); + ARG_UNUSED(channel_id); + wdt_status = WDT_HAS_FIRED; +} + +/* Print LOG delimiter. */ +static void print_bar(void) +{ + LOG_INF("==================================================================="); +} + +static void print_supported_reset_cause(void) +{ + int32_t ret; + + /* Store supported reset causes in global variable placed at NOINIT_SECTION. */ + ret = hwinfo_get_supported_reset_cause((uint32_t *) &supported); + + /* Print which reset causes are supported. */ + if (ret == 0) { + LOG_INF("Supported reset causes are:"); + if (supported & RESET_PIN) { + LOG_INF(" 0: RESET_PIN is supported"); + } else { + LOG_INF(" 0: no support for RESET_PIN"); + } + if (supported & RESET_SOFTWARE) { + LOG_INF(" 1: RESET_SOFTWARE is supported"); + } else { + LOG_INF(" 1: no support for RESET_SOFTWARE"); + } + if (supported & RESET_BROWNOUT) { + LOG_INF(" 2: RESET_BROWNOUT is supported"); + } else { + LOG_INF(" 2: no support for RESET_BROWNOUT"); + } + if (supported & RESET_POR) { + LOG_INF(" 3: RESET_POR is supported"); + } else { + LOG_INF(" 3: no support for RESET_POR"); + } + if (supported & RESET_WATCHDOG) { + LOG_INF(" 4: RESET_WATCHDOG is supported"); + } else { + LOG_INF(" 4: no support for RESET_WATCHDOG"); + } + if (supported & RESET_DEBUG) { + LOG_INF(" 5: RESET_DEBUG is supported"); + } else { + LOG_INF(" 5: no support for RESET_DEBUG"); + } + if (supported & RESET_SECURITY) { + LOG_INF(" 6: RESET_SECURITY is supported"); + } else { + LOG_INF(" 6: no support for RESET_SECURITY"); + } + if (supported & RESET_LOW_POWER_WAKE) { + LOG_INF(" 7: RESET_LOW_POWER_WAKE is supported"); + } else { + LOG_INF(" 7: no support for RESET_LOW_POWER_WAKE"); + } + if (supported & RESET_CPU_LOCKUP) { + LOG_INF(" 8: RESET_CPU_LOCKUP is supported"); + } else { + LOG_INF(" 8: no support for RESET_CPU_LOCKUP"); + } + if (supported & RESET_PARITY) { + LOG_INF(" 9: RESET_PARITY is supported"); + } else { + LOG_INF(" 9: no support for RESET_PARITY"); + } + if (supported & RESET_PLL) { + LOG_INF("10: RESET_PLL is supported"); + } else { + LOG_INF("10: no support for RESET_PLL"); + } + if (supported & RESET_CLOCK) { + LOG_INF("11: RESET_CLOCK is supported"); + } else { + LOG_INF("11: no support for RESET_CLOCK"); + } + if (supported & RESET_HARDWARE) { + LOG_INF("12: RESET_HARDWARE is supported"); + } else { + LOG_INF("12: no support for RESET_HARDWARE"); + } + if (supported & RESET_USER) { + LOG_INF("13: RESET_USER is supported"); + } else { + LOG_INF("13: no support for RESET_USER"); + } + if (supported & RESET_TEMPERATURE) { + LOG_INF("14: RESET_TEMPERATURE is supported"); + } else { + LOG_INF("14: no support for RESET_TEMPERATURE"); + } + } else if (ret == -ENOSYS) { + LOG_INF("hwinfo_get_supported_reset_cause() is NOT supported"); + supported = 0; + } else { + LOG_ERR("hwinfo_get_supported_reset_cause() failed (ret = %d)", ret); + } + print_bar(); +} + +/* Print current value of reset cause. */ +static void print_current_reset_cause(uint32_t *cause) +{ + int32_t ret; + + ret = hwinfo_get_reset_cause(cause); + if (ret == 0) { + LOG_INF("Current reset cause is:"); + if (*cause & RESET_PIN) { + LOG_INF(" 0: reset due to RESET_PIN"); + } + if (*cause & RESET_SOFTWARE) { + LOG_INF(" 1: reset due to RESET_SOFTWARE"); + } + if (*cause & RESET_BROWNOUT) { + LOG_INF(" 2: reset due to RESET_BROWNOUT"); + } + if (*cause & RESET_POR) { + LOG_INF(" 3: reset due to RESET_POR"); + } + if (*cause & RESET_WATCHDOG) { + LOG_INF(" 4: reset due to RESET_WATCHDOG"); + } + if (*cause & RESET_DEBUG) { + LOG_INF(" 5: reset due to RESET_DEBUG"); + } + if (*cause & RESET_SECURITY) { + LOG_INF(" 6: reset due to RESET_SECURITY"); + } + if (*cause & RESET_LOW_POWER_WAKE) { + LOG_INF(" 7: reset due to RESET_LOW_POWER_WAKE"); + } + if (*cause & RESET_CPU_LOCKUP) { + LOG_INF(" 8: reset due to RESET_CPU_LOCKUP"); + } + if (*cause & RESET_PARITY) { + LOG_INF(" 9: reset due to RESET_PARITY"); + } + if (*cause & RESET_PLL) { + LOG_INF("10: reset due to RESET_PLL"); + } + if (*cause & RESET_CLOCK) { + LOG_INF("11: reset due to RESET_CLOCK"); + } + if (*cause & RESET_HARDWARE) { + LOG_INF("12: reset due to RESET_HARDWARE"); + } + if (*cause & RESET_USER) { + LOG_INF("13: reset due to RESET_USER"); + } + if (*cause & RESET_TEMPERATURE) { + LOG_INF("14: reset due to RESET_TEMPERATURE"); + } + } else if (ret == -ENOSYS) { + LOG_INF("hwinfo_get_reset_cause() is NOT supported"); + *cause = 0; + } else { + LOG_ERR("hwinfo_get_reset_cause() failed (ret = %d)", ret); + } + print_bar(); +} + +/* Clear reset cause. */ +static void test_clear_reset_cause(void) +{ + int32_t ret, temp; + + ret = hwinfo_clear_reset_cause(); + if (ret == 0) { + LOG_INF("hwinfo_clear_reset_cause() was executed"); + } else if (ret == -ENOSYS) { + LOG_INF("hwinfo_get_reset_cause() is NOT supported"); + } else { + LOG_ERR("hwinfo_get_reset_cause() failed (ret = %d)", ret); + } + print_bar(); + + /* Print current value of reset causes -> expected 0 */ + print_current_reset_cause(&temp); + LOG_INF("TEST that all reset causes were cleared"); + if (temp == 0) { + LOG_INF("PASS: reset causes were cleared"); + } else { + LOG_ERR("FAIL: reset case = %u while expected is 0", temp); + } + print_bar(); +} + +void test_reset_software(uint32_t cause) +{ + /* Check that reset cause from sys_reboot is detected. */ + if (supported & RESET_SOFTWARE) { + if (reboot_status != REBOOT_WAS_DONE) { + /* If software reset hasn't happen yet, do it. */ + reboot_status = REBOOT_WAS_DONE; + LOG_INF("Test RESET_SOFTWARE - Rebooting"); + sys_reboot(SYS_REBOOT_COLD); + } else { + /* Software reset was done */ + LOG_INF("TEST that RESET_SOFTWARE was detected"); + if (cause & RESET_SOFTWARE) { + LOG_INF("PASS: RESET_SOFTWARE detected"); + print_bar(); + /* Check RESET_SOFTWARE can be cleared */ + test_clear_reset_cause(); + } else { + LOG_ERR("FAIL: RESET_SOFTWARE not set"); + print_bar(); + } + /* Cleanup */ + reboot_status = 0; + } + } +} + +void test_reset_watchdog(uint32_t cause) +{ + int32_t ret; + + /* Check that reset cause from expired watchdog is detected. */ + if (supported & RESET_WATCHDOG) { + if (wdt_status != WDT_HAS_FIRED) { + /* If watchdog hasn't fired yet, configure it do so. */ + uint32_t watchdog_window = 2000U; + + if (!device_is_ready(my_wdt_device)) { + LOG_ERR("WDT device %s is not ready", my_wdt_device->name); + return; + } + + m_cfg_wdt0.callback = wdt_int_cb; + m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC; + m_cfg_wdt0.window.max = watchdog_window; + m_cfg_wdt0.window.min = 0U; + my_wdt_channel = wdt_install_timeout(my_wdt_device, &m_cfg_wdt0); + if (my_wdt_channel < 0) { + LOG_ERR("wdt_install_timeout() returned %d", my_wdt_channel); + return; + } + + ret = wdt_setup(my_wdt_device, WDT_OPT_PAUSE_HALTED_BY_DBG); + if (ret < 0) { + LOG_ERR("wdt_setup() returned %d", ret); + return; + } + + LOG_INF("Watchdog shall fire in ~%u miliseconds", watchdog_window); + print_bar(); + k_sleep(K_FOREVER); + } else { + /* Watchdog has fired. */ + LOG_INF("TEST that RESET_WATCHDOG was detected"); + if (cause & RESET_WATCHDOG) { + LOG_INF("PASS: RESET_WATCHDOG detected"); + print_bar(); + /* Check RESET_WATCHDOG can be cleared */ + test_clear_reset_cause(); + } else { + LOG_ERR("FAIL: RESET_WATCHDOG not set"); + print_bar(); + } + /* Cleanup */ + wdt_status = 0; + } + } +} + +int main(void) +{ + uint32_t cause; + + LOG_INF("HW Info reset reason test on %s", CONFIG_BOARD_TARGET); + if (wdt_status == WDT_HAS_FIRED) { + LOG_INF("This boot is due to expected watchdog reset"); + } + if (reboot_status == REBOOT_WAS_DONE) { + LOG_INF("This boot is due to expected software reset"); + } + print_bar(); + + /* Test relies on REST_PIN to correctly start. */ + print_current_reset_cause(&cause); + if (cause & RESET_PIN) { + LOG_INF("TEST that RESET_PIN was detected"); + LOG_INF("PASS: RESET_PIN detected"); + print_bar(); + /* Check RESET_PIN can be cleared */ + test_clear_reset_cause(); + machine_state = 0; + reboot_status = 0; + wdt_status = 0; + } + + while (machine_state <= LAST_STATE) { + LOG_DBG("machine_state = %u", machine_state); + LOG_DBG("reboot_status = %u", reboot_status); + LOG_DBG("wdt_status = %u", wdt_status); + + switch (machine_state) { + case 0: /* Print (an store) which reset causes are supported. */ + print_supported_reset_cause(); + machine_state++; + break; + case 1: /* Test RESET_SOFTWARE. */ + test_reset_software(cause); + machine_state++; + case 2: /* Test RESET_WATCHDOG. */ + test_reset_watchdog(cause); + machine_state++; + } + } + + LOG_INF("All tests done"); + return 0; +} diff --git a/tests/drivers/hwinfo/reset_cause/testcase.yaml b/tests/drivers/hwinfo/reset_cause/testcase.yaml new file mode 100644 index 00000000000..8ea87ffa008 --- /dev/null +++ b/tests/drivers/hwinfo/reset_cause/testcase.yaml @@ -0,0 +1,37 @@ +common: + tags: + - drivers + - hwinfo + harness: console + +tests: + drivers.hwinfo.reset_cause: + harness_config: + type: multi_line + ordered: true + regex: + - "HW Info reset reason test on" + - "PASS: RESET_PIN detected" + - "PASS: reset causes were cleared" + - "Supported reset causes are" + - "RESET_PIN is supported" + - "RESET_SOFTWARE is supported" + - "RESET_WATCHDOG is supported" + - "RESET_DEBUG is supported" + - "RESET_LOW_POWER_WAKE is supported" + - "RESET_CPU_LOCKUP is supported" + - "Rebooting" + - "HW Info reset reason test on" + - "PASS: RESET_SOFTWARE detected" + - "PASS: reset causes were cleared" + - "Watchdog shall fire" + - "HW Info reset reason test on" + - "PASS: RESET_WATCHDOG detected" + - "PASS: reset causes were cleared" + - "All tests done" + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad