[dif/pwrmgr] add alert test functionality

This fixes #7641.

Signed-off-by: Timothy Trippel <ttrippel@google.com>
diff --git a/sw/device/lib/dif/dif_pwrmgr.c b/sw/device/lib/dif/dif_pwrmgr.c
index d94f6a1..80b2b4f 100644
--- a/sw/device/lib/dif/dif_pwrmgr.c
+++ b/sw/device/lib/dif/dif_pwrmgr.c
@@ -594,3 +594,25 @@
                       snapshot);
   return kDifPwrmgrOk;
 }
+
+dif_pwrmgr_result_t dif_pwrmgr_alert_force(const dif_pwrmgr_t *pwrmgr,
+                                           dif_pwrmgr_alert_t alert) {
+  if (pwrmgr == NULL) {
+    return kDifPwrmgrBadArg;
+  }
+
+  bitfield_bit32_index_t index;
+  switch (alert) {
+    case kDifPwrmgrAlertFatalFault:
+      index = PWRMGR_ALERT_TEST_FATAL_FAULT_BIT;
+      break;
+    default:
+      return kDifPwrmgrBadArg;
+  }
+
+  uint32_t reg = bitfield_bit32_write(0, index, true);
+  mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_ALERT_TEST_REG_OFFSET,
+                      reg);
+
+  return kDifPwrmgrOk;
+}
diff --git a/sw/device/lib/dif/dif_pwrmgr.h b/sw/device/lib/dif/dif_pwrmgr.h
index e444ae0..92cf8a8 100644
--- a/sw/device/lib/dif/dif_pwrmgr.h
+++ b/sw/device/lib/dif/dif_pwrmgr.h
@@ -277,6 +277,17 @@
 typedef uint32_t dif_pwrmgr_irq_snapshot_t;
 
 /**
+ * Power manager alerts.
+ */
+typedef enum dif_pwrmgr_alert {
+  /**
+   * A fatal alert is triggered when a fatal TL-UL bus integrity fault is
+   * detected.
+   */
+  kDifPwrmgrAlertFatalFault = 0,
+} dif_pwrmgr_alert_t;
+
+/**
  * Creates a new handle for power manager.
  *
  * This function does not actuate the hardware.
@@ -565,6 +576,18 @@
 dif_pwrmgr_result_t dif_pwrmgr_irq_restore_all(
     const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_irq_snapshot_t snapshot);
 
+/**
+ * Forces a particular alert, causing it to be serviced as if hardware had
+ * asserted it.
+ *
+ * @param pwrmgr A power manager handle.
+ * @param alert A power manager alert type.
+ * @return The result of the operation.
+ */
+DIF_WARN_UNUSED_RESULT
+dif_pwrmgr_result_t dif_pwrmgr_alert_force(const dif_pwrmgr_t *pwrmgr,
+                                           dif_pwrmgr_alert_t alert);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus
diff --git a/sw/device/lib/dif/dif_pwrmgr_unittest.cc b/sw/device/lib/dif/dif_pwrmgr_unittest.cc
index 25c143e..a192e8c 100644
--- a/sw/device/lib/dif/dif_pwrmgr_unittest.cc
+++ b/sw/device/lib/dif/dif_pwrmgr_unittest.cc
@@ -894,5 +894,22 @@
   EXPECT_EQ(dif_pwrmgr_irq_restore_all(&pwrmgr_, snapshot), kDifPwrmgrOk);
 }
 
+class AlertTest : public DifPwrmgrInitialized {};
+
+TEST_F(AlertTest, ForceBadArgs) {
+  EXPECT_EQ(dif_pwrmgr_alert_force(nullptr, kDifPwrmgrAlertFatalFault),
+            kDifPwrmgrBadArg);
+  EXPECT_EQ(
+      dif_pwrmgr_alert_force(&pwrmgr_, static_cast<dif_pwrmgr_alert_t>(1)),
+      kDifPwrmgrBadArg);
+}
+
+TEST_F(AlertTest, Force) {
+  EXPECT_WRITE32(PWRMGR_ALERT_TEST_REG_OFFSET, {{0, true}});
+
+  EXPECT_EQ(dif_pwrmgr_alert_force(&pwrmgr_, kDifPwrmgrAlertFatalFault),
+            kDifPwrmgrOk);
+}
+
 }  // namespace
 }  // namespace dif_pwrmgr_unittest