[sw,tests] Verify that the data within the retention SRAM survives low power entry-exit
For test: chip_sw_sleep_sram_ret_contents.
This test writes data to the retention SRAM and then enters low power mode. Upon wake
from low power the data is read back and checked against the original data written.
Signed-off-by: Dave Williams <dave.williams@ensilica.com>
diff --git a/hw/top_earlgrey/data/chip_testplan.hjson b/hw/top_earlgrey/data/chip_testplan.hjson
index 250441c..89a4095 100644
--- a/hw/top_earlgrey/data/chip_testplan.hjson
+++ b/hw/top_earlgrey/data/chip_testplan.hjson
@@ -2081,7 +2081,7 @@
TODO: how to deal with the scramble keys on low power exit?
'''
milestone: V2
- tests: []
+ tests: ["chip_sw_sleep_sram_ret_contents"]
}
{
name: chip_sw_sram_execution
diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
index 991b591..46b35ac 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -384,6 +384,13 @@
en_run_modes: ["sw_test_mode_test_rom"]
}
{
+ name: chip_sw_sleep_sram_ret_contents
+ uvm_test_seq: chip_sw_base_vseq
+ sw_images: ["sw/device/tests/sram_ctrl_sleep_sram_ret_contents_test:1"]
+ en_run_modes: ["sw_test_mode_test_rom"]
+ run_opts: ["+sw_test_timeout_ns=7000000"]
+ }
+ {
name: chip_sw_coremark
uvm_test_seq: chip_sw_base_vseq
sw_images: ["sw/device/benchmarks/coremark/coremark_top_earlgrey:1:external"]
diff --git a/sw/device/tests/meson.build b/sw/device/tests/meson.build
index fba6809..05c1586 100644
--- a/sw/device/tests/meson.build
+++ b/sw/device/tests/meson.build
@@ -724,6 +724,29 @@
}
}
+# SRAM Controller low power retention SRAM contents test.
+sram_ctrl_sleep_sram_ret_contents_test_lib = declare_dependency(
+ link_with: static_library(
+ 'sram_ctrl_sleep_sram_ret_contents_test_lib',
+ sources: ['sram_ctrl_sleep_sram_ret_contents_test.c'],
+ dependencies: [
+ sw_lib_mmio,
+ sw_lib_dif_aon_timer,
+ sw_lib_dif_pwrmgr,
+ sw_lib_dif_rstmgr,
+ sw_lib_testing_aon_timer_testutils,
+ sw_lib_testing_pwrmgr_testutils,
+ sw_lib_testing_rstmgr_testutils,
+ sw_lib_runtime_log,
+ top_earlgrey,
+ ],
+ ),
+)
+sw_tests += {
+ 'sram_ctrl_sleep_sram_ret_contents_test': {
+ 'library': sram_ctrl_sleep_sram_ret_contents_test_lib,
+ }
+}
# AON Timer irq test.
aon_timer_irq_test = declare_dependency(
diff --git a/sw/device/tests/sram_ctrl_sleep_sram_ret_contents_test.c b/sw/device/tests/sram_ctrl_sleep_sram_ret_contents_test.c
new file mode 100644
index 0000000..8d797db
--- /dev/null
+++ b/sw/device/tests/sram_ctrl_sleep_sram_ret_contents_test.c
@@ -0,0 +1,116 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_aon_timer.h"
+#include "sw/device/lib/dif/dif_pwrmgr.h"
+#include "sw/device/lib/dif/dif_rstmgr.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/aon_timer_testutils.h"
+#include "sw/device/lib/testing/check.h"
+#include "sw/device/lib/testing/pwrmgr_testutils.h"
+#include "sw/device/lib/testing/rstmgr_testutils.h"
+#include "sw/device/lib/testing/test_framework/ottf.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+
+#define NUM_TEST_WORDS 16
+
+const test_config_t kTestConfig;
+
+// Random data to read/write to/from retention SRAM.
+const uint32_t kTestData[NUM_TEST_WORDS] = {
+ 0xe647e5d5, 0x4b5fe6f6, 0x1608a98a, 0x5e347116, 0xb2dc5e92, 0x899e3c0f,
+ 0xc98295c2, 0x0fa84434, 0x15747561, 0xfecb5aa1, 0x7a78bb8c, 0x8f9c5d0f,
+ 0x49338fbd, 0x093e82cb, 0xaaa58121, 0x5b806f96,
+};
+
+static void retention_sram_check(bool do_write) {
+ mmio_region_t sram_region_ret_base_addr =
+ mmio_region_from_addr(TOP_EARLGREY_SRAM_CTRL_RET_AON_RAM_BASE_ADDR);
+ for (int i = 0; i < NUM_TEST_WORDS; ++i) {
+ if (do_write) {
+ mmio_region_write32(sram_region_ret_base_addr, i * sizeof(uint32_t),
+ kTestData[i]);
+ }
+ uint32_t read_data =
+ mmio_region_read32(sram_region_ret_base_addr, i * sizeof(uint32_t));
+ CHECK(read_data == kTestData[i]);
+ }
+}
+
+bool test_main(void) {
+ dif_pwrmgr_t pwrmgr;
+ dif_rstmgr_t rstmgr;
+ dif_aon_timer_t aon_timer;
+
+ CHECK_DIF_OK(dif_pwrmgr_init(
+ mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR), &pwrmgr));
+ CHECK_DIF_OK(dif_rstmgr_init(
+ mmio_region_from_addr(TOP_EARLGREY_RSTMGR_AON_BASE_ADDR), &rstmgr));
+ CHECK_DIF_OK(dif_aon_timer_init(
+ mmio_region_from_addr(TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR), &aon_timer));
+
+ dif_rstmgr_reset_info_bitfield_t rstmgr_reset_info;
+ CHECK_DIF_OK(dif_rstmgr_reset_info_get(&rstmgr, &rstmgr_reset_info));
+
+ LOG_INFO("Reset info = %0x", rstmgr_reset_info);
+
+ if (rstmgr_reset_info == kDifRstmgrResetInfoPor) {
+ LOG_INFO("POR reset");
+
+ // Write data to retention SRAM and readback (to test basic functionality.)
+ retention_sram_check(true);
+
+ // Prepare rstmgr for a reset.
+ rstmgr_testutils_pre_reset(&rstmgr);
+ aon_timer_testutils_wakeup_config(&aon_timer, 20);
+ // Deep sleep.
+ pwrmgr_testutils_enable_low_power(&pwrmgr,
+ kDifPwrmgrWakeupRequestSourceFive, 0);
+
+ // Enter low power mode.
+ LOG_INFO("Issue WFI to enter sleep");
+ wait_for_interrupt();
+ } else if (rstmgr_reset_info & kDifRstmgrResetInfoLowPowerExit) {
+ if (!(rstmgr_reset_info & kDifRstmgrResetInfoWatchdog)) {
+ LOG_INFO("Wakeup reset");
+
+ CHECK(pwrmgr_testutils_is_wakeup_reason(
+ &pwrmgr, kDifPwrmgrWakeupRequestSourceFive));
+
+ LOG_INFO("Aon timer wakeup detected");
+
+ // Check that the previously written retention SRAM data can still
+ // be read successfully.
+ retention_sram_check(false);
+
+ // Prepare rstmgr for a reset.
+ rstmgr_testutils_pre_reset(&rstmgr);
+ // Deep sleep.
+ pwrmgr_testutils_enable_low_power(&pwrmgr,
+ kDifPwrmgrWakeupRequestSourceTwo, 0);
+ // Enable watchdog timer.
+ CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
+ &pwrmgr, kDifPwrmgrReqTypeReset, kDifPwrmgrResetRequestSourceTwo,
+ kDifToggleEnabled));
+
+ CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&aon_timer));
+ aon_timer_testutils_watchdog_config(&aon_timer, 0xffffffff, 10, false);
+
+ // Enter low power mode.
+ LOG_INFO("Issue WFI to enter sleep");
+ wait_for_interrupt();
+ } else {
+ LOG_INFO("Watchdog reset");
+ // Check that the previously written retention SRAM data can still
+ // be read successfully.
+ retention_sram_check(false);
+ }
+ } else {
+ LOG_FATAL("Unexepected reset type detected.");
+ }
+
+ return true;
+}