[sw/silicon_creator] Add rstmgr_reset() and functest

Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/lib/drivers/meson.build b/sw/device/silicon_creator/lib/drivers/meson.build
index bf761df..090375c 100644
--- a/sw/device/silicon_creator/lib/drivers/meson.build
+++ b/sw/device/silicon_creator/lib/drivers/meson.build
@@ -201,6 +201,54 @@
   suite: 'mask_rom',
 )
 
+# Mask ROM retention SRAM driver
+sw_silicon_creator_lib_driver_retention_sram = declare_dependency(
+  link_with: static_library(
+    'sw_silicon_creator_lib_driver_retention_sram',
+    sources: [
+      hw_ip_sram_ctrl_reg_h,
+      'retention_sram.c',
+    ],
+    dependencies: [
+      sw_silicon_creator_lib_base_abs_mmio,
+    ],
+  ),
+)
+
+test('sw_silicon_creator_lib_driver_retention_sram_unittest', executable(
+    'sw_silicon_creator_lib_driver_retention_sram_unittest',
+    sources: [
+      'retention_sram_unittest.cc',
+      hw_ip_sram_ctrl_reg_h,
+      'retention_sram.c',
+    ],
+    dependencies: [
+      sw_vendor_gtest,
+      sw_silicon_creator_lib_base_mock_abs_mmio,
+    ],
+    native: true,
+    c_args: ['-DMOCK_ABS_MMIO'],
+    cpp_args: ['-DMOCK_ABS_MMIO'],
+  ),
+  suite: 'mask_rom',
+)
+
+sw_silicon_creator_lib_driver_retention_sram_functest = declare_dependency(
+  link_with: static_library(
+    'sw_silicon_creator_lib_driver_retention_sram_functest',
+    sources: ['retention_sram_functest.c'],
+    dependencies: [
+      sw_silicon_creator_lib_driver_retention_sram,
+    ],
+  ),
+)
+mask_rom_tests += {
+  'sw_silicon_creator_lib_driver_retention_sram_functest': {
+    'library': sw_silicon_creator_lib_driver_retention_sram_functest,
+  }
+}
+
+
 # Mask ROM rstmgr driver
 sw_silicon_creator_lib_driver_rstmgr = declare_dependency(
   link_with: static_library(
@@ -227,12 +275,33 @@
       sw_silicon_creator_lib_base_mock_abs_mmio,
     ],
     native: true,
-    c_args: ['-DMOCK_ABS_MMIO'],
-    cpp_args: ['-DMOCK_ABS_MMIO'],
+    c_args: ['-DMOCK_ABS_MMIO', '-DOT_OFF_TARGET_TEST'],
+    cpp_args: ['-DMOCK_ABS_MMIO', '-DOT_OFF_TARGET_TEST'],
   ),
   suite: 'mask_rom',
 )
 
+
+sw_silicon_creator_lib_driver_rstmgr_functest = declare_dependency(
+  link_with: static_library(
+    'sw_silicon_creator_lib_driver_rstmgr_functest',
+    sources: [
+      hw_ip_rstmgr_reg_h,
+      'rstmgr_functest.c'
+    ],
+    dependencies: [
+      sw_silicon_creator_lib_base_abs_mmio,
+      sw_silicon_creator_lib_driver_rstmgr,
+      sw_silicon_creator_lib_driver_retention_sram,
+    ],
+  ),
+)
+mask_rom_tests += {
+  'sw_silicon_creator_lib_driver_rstmgr_functest': {
+    'library': sw_silicon_creator_lib_driver_rstmgr_functest,
+  }
+}
+
 # Mask ROM alert handler driver
 sw_silicon_creator_lib_driver_alert = declare_dependency(
   link_with: static_library(
@@ -321,53 +390,6 @@
   suite: 'mask_rom',
 )
 
-# Mask ROM retention SRAM driver
-sw_silicon_creator_lib_driver_retention_sram = declare_dependency(
-  link_with: static_library(
-    'sw_silicon_creator_lib_driver_retention_sram',
-    sources: [
-      hw_ip_sram_ctrl_reg_h,
-      'retention_sram.c',
-    ],
-    dependencies: [
-      sw_silicon_creator_lib_base_abs_mmio,
-    ],
-  ),
-)
-
-test('sw_silicon_creator_lib_driver_retention_sram_unittest', executable(
-    'sw_silicon_creator_lib_driver_retention_sram_unittest',
-    sources: [
-      'retention_sram_unittest.cc',
-      hw_ip_sram_ctrl_reg_h,
-      'retention_sram.c',
-    ],
-    dependencies: [
-      sw_vendor_gtest,
-      sw_silicon_creator_lib_base_mock_abs_mmio,
-    ],
-    native: true,
-    c_args: ['-DMOCK_ABS_MMIO'],
-    cpp_args: ['-DMOCK_ABS_MMIO'],
-  ),
-  suite: 'mask_rom',
-)
-
-sw_silicon_creator_lib_driver_retention_sram_functest = declare_dependency(
-  link_with: static_library(
-    'sw_silicon_creator_lib_driver_retention_sram_functest',
-    sources: ['retention_sram_functest.c'],
-    dependencies: [
-      sw_silicon_creator_lib_driver_retention_sram,
-    ],
-  ),
-)
-mask_rom_tests += {
-  'sw_silicon_creator_lib_driver_retention_sram_functest': {
-    'library': sw_silicon_creator_lib_driver_retention_sram_functest,
-  }
-}
-
 # Mask ROM watchdog driver
 sw_silicon_creator_lib_driver_watchdog = declare_dependency(
   link_with: static_library(
diff --git a/sw/device/silicon_creator/lib/drivers/rstmgr.c b/sw/device/silicon_creator/lib/drivers/rstmgr.c
index 3a898b5..bd8e186 100644
--- a/sw/device/silicon_creator/lib/drivers/rstmgr.c
+++ b/sw/device/silicon_creator/lib/drivers/rstmgr.c
@@ -7,6 +7,9 @@
 #include <assert.h>
 
 #include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/macros.h"
+#include "sw/device/lib/base/multibits.h"
+#include "sw/device/lib/runtime/hart.h"
 #include "sw/device/silicon_creator/lib/base/abs_mmio.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
@@ -68,9 +71,19 @@
 }
 
 void rstmgr_reason_clear(uint32_t reasons) {
-  return abs_mmio_write32(kBase + RSTMGR_RESET_INFO_REG_OFFSET, reasons);
+  abs_mmio_write32(kBase + RSTMGR_RESET_INFO_REG_OFFSET, reasons);
 }
 
 void rstmgr_alert_info_enable(void) {
   abs_mmio_write32(kBase + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 1);
 }
+
+void rstmgr_reset(void) {
+  abs_mmio_write32(kBase + RSTMGR_RESET_REQ_REG_OFFSET, kMultiBitBool4True);
+#ifdef OT_PLATFORM_RV32
+  // Wait until the chip resets.
+  while (true) {
+    wait_for_interrupt();
+  }
+#endif
+}
diff --git a/sw/device/silicon_creator/lib/drivers/rstmgr.h b/sw/device/silicon_creator/lib/drivers/rstmgr.h
index 5c9e82f..1b9c13b 100644
--- a/sw/device/silicon_creator/lib/drivers/rstmgr.h
+++ b/sw/device/silicon_creator/lib/drivers/rstmgr.h
@@ -7,6 +7,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <stdnoreturn.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -94,6 +95,16 @@
  */
 void rstmgr_alert_info_enable(void);
 
+/**
+ * Requests a system reset.
+ */
+#ifndef OT_OFF_TARGET_TEST
+// Omit `noreturn` to be able to test this function in off-target tests.
+noreturn
+#endif
+    void
+    rstmgr_reset(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sw/device/silicon_creator/lib/drivers/rstmgr_functest.c b/sw/device/silicon_creator/lib/drivers/rstmgr_functest.c
new file mode 100644
index 0000000..6eadc13
--- /dev/null
+++ b/sw/device/silicon_creator/lib/drivers/rstmgr_functest.c
@@ -0,0 +1,53 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/check.h"
+#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
+#include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
+#include "sw/device/silicon_creator/lib/error.h"
+#include "sw/device/silicon_creator/lib/test_main.h"
+
+const test_config_t kTestConfig;
+
+/**
+ * Test phases tracked in retention RAM.
+ */
+enum {
+  kTestPhaseInit = 0,
+  kTestPhaseReset = 1,
+  kTestPhaseDone = 2,
+};
+
+bool test_main(void) {
+  // Read and clear reset reason.
+  uint32_t reason = rstmgr_reason_get();
+  rstmgr_reason_clear(reason);
+  LOG_INFO("Reset reason: 0x%08x", reason);
+  // This test assumes that reset reason is unique.
+  CHECK(bitfield_popcount32(reason) == 1, "Expected exactly 1 reset reason.");
+
+  // Use the part of the retention RAM reserved for the silicon owner to store
+  // the test phase.
+  volatile uint32_t *phase = &retention_sram_get()->reserved_owner[0];
+
+  if (bitfield_bit32_read(reason, kRstmgrReasonPowerOn)) {
+    // Clear retention RAM on power-on reset.
+    retention_sram_clear();
+    // Request a system reset.
+    *phase = kTestPhaseReset;
+    rstmgr_reset();
+    CHECK(false, "Should have reset before this line.");  // Unreachable
+  } else if (bitfield_bit32_read(reason, kRstmgrReasonSoftwareRequest)) {
+    LOG_INFO("Detected software reset.");
+    CHECK(*phase == kTestPhaseReset, "Unexpected test phase: 0x%08x", *phase);
+    *phase = kTestPhaseDone;
+    return true;
+  }
+  LOG_ERROR("Unknown reset reason: 0x%08x", reason);
+  return false;
+}
diff --git a/sw/device/silicon_creator/lib/drivers/rstmgr_unittest.cc b/sw/device/silicon_creator/lib/drivers/rstmgr_unittest.cc
index 8dccece..6edf499 100644
--- a/sw/device/silicon_creator/lib/drivers/rstmgr_unittest.cc
+++ b/sw/device/silicon_creator/lib/drivers/rstmgr_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "gtest/gtest.h"
 #include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/base/multibits.h"
 #include "sw/device/silicon_creator/lib/base/mock_abs_mmio.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
@@ -54,5 +55,10 @@
   rstmgr_alert_info_enable();
 }
 
+TEST_F(RstmgrTest, Reset) {
+  EXPECT_ABS_WRITE32(base_ + RSTMGR_RESET_REQ_REG_OFFSET, kMultiBitBool4True);
+  rstmgr_reset();
+}
+
 }  // namespace
 }  // namespace rstmgr_unittest