[mask_rom] Add a driver for the rstmgr.

This driver allows one to retrieve the last reset reason and enables
capturing of alert escalation info during a reset.

Signed-off-by: Chris Frantz <cfrantz@google.com>
diff --git a/sw/device/silicon_creator/lib/drivers/meson.build b/sw/device/silicon_creator/lib/drivers/meson.build
index 77f5fa3..318e65a 100644
--- a/sw/device/silicon_creator/lib/drivers/meson.build
+++ b/sw/device/silicon_creator/lib/drivers/meson.build
@@ -160,3 +160,35 @@
     ),
   suite: 'mask_rom',
 )
+
+# Mask ROM rstmgr driver
+sw_silicon_creator_lib_driver_rstmgr = declare_dependency(
+  link_with: static_library(
+    'sw_silicon_creator_lib_driver_rstmgr',
+    sources: [
+      hw_ip_rstmgr_reg_h,
+      'rstmgr.c',
+    ],
+    dependencies: [
+      sw_silicon_creator_lib_base_abs_mmio,
+    ],
+  ),
+)
+
+test('sw_silicon_creator_lib_driver_rstmgr_unittest', executable(
+    'sw_silicon_creator_lib_driver_rstmgr_unittest',
+    sources: [
+      'rstmgr_unittest.cc',
+      hw_ip_rstmgr_reg_h,
+      'rstmgr.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',
+)
diff --git a/sw/device/silicon_creator/lib/drivers/rstmgr.c b/sw/device/silicon_creator/lib/drivers/rstmgr.c
new file mode 100644
index 0000000..e3e9dd3
--- /dev/null
+++ b/sw/device/silicon_creator/lib/drivers/rstmgr.c
@@ -0,0 +1,39 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+#include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
+
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/silicon_creator/lib/base/abs_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rstmgr_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RSTMGR_AON_BASE_ADDR,
+};
+
+rstmgr_alert_info_t rstmgr_alert_info;
+
+static void rstmgr_alert_info_collect(void) {
+  rstmgr_alert_info.length = bitfield_field32_read(
+      abs_mmio_read32(kBase + RSTMGR_ALERT_INFO_ATTR_REG_OFFSET),
+      RSTMGR_ALERT_INFO_ATTR_CNT_AVAIL_FIELD);
+  for (uint32_t i = 0; i < rstmgr_alert_info.length; ++i) {
+    abs_mmio_write32(
+        kBase + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET,
+        bitfield_field32_write(0, RSTMGR_ALERT_INFO_CTRL_INDEX_FIELD, i));
+    rstmgr_alert_info.info[i] =
+        abs_mmio_read32(kBase + RSTMGR_ALERT_INFO_REG_OFFSET);
+  }
+}
+
+uint32_t rstmgr_reason_get(void) {
+  rstmgr_alert_info_collect();
+  return abs_mmio_read32(kBase + RSTMGR_RESET_INFO_REG_OFFSET);
+}
+
+void rstmgr_alert_info_enable(void) {
+  abs_mmio_write32(kBase + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 1);
+}
diff --git a/sw/device/silicon_creator/lib/drivers/rstmgr.h b/sw/device/silicon_creator/lib/drivers/rstmgr.h
new file mode 100644
index 0000000..91c50c4
--- /dev/null
+++ b/sw/device/silicon_creator/lib/drivers/rstmgr.h
@@ -0,0 +1,46 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_DRIVERS_RSTMGR_H_
+#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_DRIVERS_RSTMGR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Alert Infomation captured by the reset manager during the last reset.
+ */
+typedef struct RstMgrAlertInfo {
+  /**
+   * Length of alert information.
+   */
+  uint32_t length;
+  /**
+   * Alert info words.
+   */
+  uint32_t info[16];
+} rstmgr_alert_info_t;
+
+extern rstmgr_alert_info_t rstmgr_alert_info;
+
+/**
+ * Get the reason for the last reset.
+ *
+ * This function also captures alert information into `rstmgr_alert_info`.
+ */
+uint32_t rstmgr_reason_get(void);
+
+/**
+ * Enable capturing of alert info in the event of an alert escalation.
+ */
+void rstmgr_alert_info_enable(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_DRIVERS_RSTMGR_H_
diff --git a/sw/device/silicon_creator/lib/drivers/rstmgr_unittest.cc b/sw/device/silicon_creator/lib/drivers/rstmgr_unittest.cc
new file mode 100644
index 0000000..9824d17
--- /dev/null
+++ b/sw/device/silicon_creator/lib/drivers/rstmgr_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
+
+#include "gtest/gtest.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/silicon_creator/lib/base/mock_abs_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rstmgr_regs.h"  // Generated.
+
+namespace rstmgr_unittest {
+namespace {
+using ::testing::ElementsAre;
+
+class RstmgrTest : public mask_rom_test::MaskRomTest {
+ protected:
+  uint32_t base_ = TOP_EARLGREY_RSTMGR_AON_BASE_ADDR;
+  mask_rom_test::MockAbsMmio mmio_;
+};
+
+TEST_F(RstmgrTest, GetResetReason) {
+  EXPECT_ABS_READ32(mmio_, base_ + RSTMGR_ALERT_INFO_ATTR_REG_OFFSET, 5);
+
+  EXPECT_ABS_WRITE32(mmio_, base_ + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 0x00);
+  EXPECT_ABS_READ32(mmio_, base_ + RSTMGR_ALERT_INFO_REG_OFFSET, 1);
+  EXPECT_ABS_WRITE32(mmio_, base_ + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 0x10);
+  EXPECT_ABS_READ32(mmio_, base_ + RSTMGR_ALERT_INFO_REG_OFFSET, 2);
+  EXPECT_ABS_WRITE32(mmio_, base_ + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 0x20);
+  EXPECT_ABS_READ32(mmio_, base_ + RSTMGR_ALERT_INFO_REG_OFFSET, 3);
+  EXPECT_ABS_WRITE32(mmio_, base_ + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 0x30);
+  EXPECT_ABS_READ32(mmio_, base_ + RSTMGR_ALERT_INFO_REG_OFFSET, 4);
+  EXPECT_ABS_WRITE32(mmio_, base_ + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 0x40);
+  EXPECT_ABS_READ32(mmio_, base_ + RSTMGR_ALERT_INFO_REG_OFFSET, 5);
+
+  EXPECT_ABS_READ32(mmio_, base_ + RSTMGR_RESET_INFO_REG_OFFSET, 0x12345);
+
+  EXPECT_EQ(rstmgr_reason_get(), 0x12345);
+  EXPECT_EQ(rstmgr_alert_info.length, 5);
+  EXPECT_THAT(rstmgr_alert_info.info,
+              ElementsAre(1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+}
+
+TEST_F(RstmgrTest, EnableAlertInfo) {
+  EXPECT_ABS_WRITE32(mmio_, base_ + RSTMGR_ALERT_INFO_CTRL_REG_OFFSET, 1);
+  rstmgr_alert_info_enable();
+}
+
+}  // namespace
+}  // namespace rstmgr_unittest