[sw/silicon_creator] Use OTP library in shutdown module

1. Follow the redaction policy in #7353 (no redaction in RMA and
   test unlocked lifecycle states).
2. Use the OTP library to read from OTP.

The OTP and lifecycle libraries use sec_mmio underneath the hood.
Since sec_mmio can trigger a call to shutdown_finalize we need to
avoid calling it from shutdown_finalize. To acheive this a new
shutdown_redact_policy function has been added that determines
the redaction policy to apply without using either library.

This change required an increase in the number of registers that
`sec_mmio_ctx` has capacity to track. I've bumped it up to 200 for
now.

Signed-off-by: Michael Munday <mike.munday@lowrisc.org>
diff --git a/sw/device/silicon_creator/lib/shutdown.c b/sw/device/silicon_creator/lib/shutdown.c
index 170aec2..d4546bb 100644
--- a/sw/device/silicon_creator/lib/shutdown.c
+++ b/sw/device/silicon_creator/lib/shutdown.c
@@ -14,11 +14,13 @@
 #include "sw/device/silicon_creator/lib/base/abs_mmio.h"
 #include "sw/device/silicon_creator/lib/drivers/alert.h"
 #include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
+#include "sw/device/silicon_creator/lib/drivers/otp.h"
 
 #include "alert_handler_regs.h"
 #include "flash_ctrl_regs.h"
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
 #include "keymgr_regs.h"
+#include "lc_ctrl_regs.h"
 #include "otp_ctrl_regs.h"
 #include "sram_ctrl_regs.h"
 
@@ -46,16 +48,6 @@
   static ALWAYS_INLINE modifiers_ void name_
 #endif
 
-// TODO: use the real OTP driver after it's converted to abs_mmio.
-#ifdef OT_OFF_TARGET_TEST
-extern uint32_t otp_read32(uint32_t address);
-#else
-inline uint32_t otp_read32(uint32_t address) {
-  return abs_mmio_read32(TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR +
-                         OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET + address);
-}
-#endif
-
 // Convert the alert class to an index.
 // This is required because I expect to change the constant definitions in
 // alert_class_t to have reasonable hamming distances.
@@ -174,7 +166,13 @@
   return error;
 }
 
-uint32_t shutdown_redact(rom_error_t reason, shutdown_error_redact_t severity) {
+/**
+ * Implementation of `shutdown_redact` that is guaranteed to be inlined.
+ *
+ * This function must be inlined because it is called from `shutdown_finalize`.
+ */
+static ALWAYS_INLINE uint32_t
+shutdown_redact_inline(rom_error_t reason, shutdown_error_redact_t severity) {
   uint32_t redacted = (uint32_t)reason;
   if (reason == kErrorOk) {
     return 0;
@@ -196,6 +194,70 @@
   return redacted;
 }
 
+uint32_t shutdown_redact(rom_error_t reason, shutdown_error_redact_t severity) {
+  return shutdown_redact_inline(reason, severity);
+}
+
+/**
+ * Implementation of `shutdown_redact_policy` that is guaranteed to be inlined.
+ *
+ * This function must be inlined because it is called from `shutdown_finalize`.
+ */
+static ALWAYS_INLINE shutdown_error_redact_t
+shutdown_redact_policy_inline(void) {
+  // Determine the error code redaction policy to apply according to the
+  // lifecycle state and OTP configuration.
+  //
+  // Note that we cannot use the lifecycle or OTP libraries since an error
+  // may trigger a call to `shutdown_finalize`.
+  lifecycle_state_t lc_state = (lifecycle_state_t)bitfield_field32_read(
+      abs_mmio_read32(TOP_EARLGREY_LC_CTRL_BASE_ADDR +
+                      LC_CTRL_LC_STATE_REG_OFFSET),
+      LC_CTRL_LC_STATE_STATE_FIELD);
+  switch (lc_state) {
+    case kLcStateRaw:
+    case kLcStateTestUnlocked0:
+    case kLcStateTestUnlocked1:
+    case kLcStateTestUnlocked2:
+    case kLcStateTestUnlocked3:
+    case kLcStateTestUnlocked4:
+    case kLcStateTestUnlocked5:
+    case kLcStateTestUnlocked6:
+    case kLcStateTestUnlocked7:
+    case kLcStateRma:
+      // No error redaction in RAW, TEST_UNLOCKED and RMA states.
+      return kShutdownErrorRedactNone;
+    case kLcStateProd:
+    case kLcStateProdEnd:
+    case kLcStateDev:
+      // In production states use the redaction level specified in OTP.
+      return (shutdown_error_redact_t)abs_mmio_read32(
+          TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR +
+          OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
+          OTP_CTRL_PARAM_ROM_ERROR_REPORTING_OFFSET);
+    default:
+      // Redact everything if in an unexpected lifecycle state.
+      return kShutdownErrorRedactAll;
+  }
+}
+
+shutdown_error_redact_t shutdown_redact_policy(void) {
+  return shutdown_redact_policy_inline();
+}
+
+SHUTDOWN_FUNC(NO_MODIFIERS, shutdown_report_error(rom_error_t reason)) {
+  // Call the inline variant of `shutdown_redact_policy` because we want to
+  // guarantee that we won't jump to a different function.
+  shutdown_error_redact_t policy = shutdown_redact_policy_inline();
+
+  // Call the inline variant of `shutdown_redact` because we want to guarantee
+  // that we won't jump to a different function.
+  uint32_t redacted_error = shutdown_redact_inline(reason, policy);
+
+  // TODO(lowRISC/opentitan#8236): base_printf is in the .text section.
+  base_printf("boot_fault: 0x%08x\n", redacted_error);
+}
+
 SHUTDOWN_FUNC(NO_MODIFIERS, shutdown_software_escalate(void)) {
   // TODO(lowRISC/opentitan#7148): Use a software alert when available.
   // For now, signal a fatal_intg_error from SRAM.
@@ -265,12 +327,7 @@
 __attribute__((section(".shutdown")))
 #endif
 void shutdown_finalize(rom_error_t reason) {
-  uint32_t redacted_error = shutdown_redact(
-      reason, otp_read32(OTP_CTRL_PARAM_ROM_ERROR_REPORTING_OFFSET));
-
-  // TODO(lowRISC/opentitan#8236): base_printf is in the .text section.
-  base_printf("boot_fault: 0x%08x\n", redacted_error);
-
+  shutdown_report_error(reason);
   shutdown_software_escalate();
   shutdown_keymgr_kill();
   shutdown_flash_kill();