[dv/chip] add otp_macro_err check in all_escalation test

This PR adds a DV sequence to trigger otp_macro_err by injecting ECC
errors and read back the partition via DAI interface.

Signed-off-by: Cindy Chen <chencindy@opentitan.org>
diff --git a/hw/top_earlgrey/data/chip_testplan.hjson b/hw/top_earlgrey/data/chip_testplan.hjson
index 9b0c645..5c3001a 100644
--- a/hw/top_earlgrey/data/chip_testplan.hjson
+++ b/hw/top_earlgrey/data/chip_testplan.hjson
@@ -2853,6 +2853,20 @@
       stage: V3
       tests: ["chip_sw_otp_ctrl_vendor_test_csr_access"]
     }
+    {
+      name: chip_sw_otp_ctrl_escalation
+      desc: '''Verify escalation from otp_ctrl macro fatal error.
+
+            - Inject ECC fatal error into OTP macro's HW cfg partition, and read back this macro
+              via DAI interface.
+            - Because this fatal error will immediately turn off CPU, so the DV sequence will probe
+              the alert interface to make sure alert and escalation is triggered.
+
+            X'ref with chip_sw_all_escalation_resets.
+            '''
+      stage: V3
+      tests: ["chip_sw_otp_ctrl_escalation"]
+    }
 
     // FLASH (pre-verified IP) integration tests:
     {
diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
index c4259d4..9243dd5 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -745,6 +745,14 @@
       en_run_modes: ["sw_test_mode_test_rom"]
     }
     {
+      name: chip_sw_otp_ctrl_escalation
+      uvm_test_seq: chip_sw_otp_ctrl_escalation_vseq
+      sw_images: ["//sw/device/tests/sim_dv:all_escalation_resets_test:1"]
+      en_run_modes: ["sw_test_mode_test_rom"]
+      run_opts: ["+bypass_alert_ready_to_end_check=1"]
+      reseed: 1
+    }
+    {
       // Set higher reseed value to reach all kmac_data to lc_ctrl toggle coverage.
       name: chip_sw_lc_ctrl_transition
       uvm_test_seq: chip_sw_lc_ctrl_transition_vseq
diff --git a/hw/top_earlgrey/dv/env/chip_env.core b/hw/top_earlgrey/dv/env/chip_env.core
index 69e4012..1d4dc89 100644
--- a/hw/top_earlgrey/dv/env/chip_env.core
+++ b/hw/top_earlgrey/dv/env/chip_env.core
@@ -96,6 +96,7 @@
       - seq_lib/chip_sw_lc_walkthrough_testunlocks_vseq.sv: {is_include_file: true}
       - seq_lib/chip_sw_lc_ctrl_program_error_vseq.sv: {is_include_file: true}
       - seq_lib/chip_sw_otp_ctrl_vendor_test_csr_access_vseq.sv: {is_include_file: true}
+      - seq_lib/chip_sw_otp_ctrl_escalation_vseq.sv: {is_include_file: true}
       - seq_lib/chip_sw_spi_device_tx_rx_vseq.sv: {is_include_file: true}
       - seq_lib/chip_sw_spi_host_tx_rx_vseq.sv: {is_include_file: true}
       - seq_lib/chip_sw_spi_passthrough_collision_vseq.sv: {is_include_file: true}
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_otp_ctrl_escalation_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_otp_ctrl_escalation_vseq.sv
new file mode 100644
index 0000000..81319f6
--- /dev/null
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_otp_ctrl_escalation_vseq.sv
@@ -0,0 +1,48 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This virtual sequence triggers OTP macro and check fatal errors by backdoor injecting ECC errors
+// and read back the injected error via DAI interface.
+// Because these fatal alert in OTP immediately will send the error information to LC_CTRL and turn
+// off CPU, this sequence will check alerts via backdoor probing.
+
+class chip_sw_otp_ctrl_escalation_vseq extends chip_sw_base_vseq;
+  `uvm_object_utils(chip_sw_otp_ctrl_escalation_vseq)
+
+  `uvm_object_new
+
+  virtual task body();
+    bit [TL_AW-1:0] hw_cfg_addr = otp_ctrl_reg_pkg::HwCfgOffset;
+    bit [TL_DW-1:0] val;
+    bit [7:0] sw_alert_num[];
+
+    super.body();
+
+    // Disable scoreboard tl error checks since we will trigger faults which cannot be predicted.
+    cfg.en_scb_tl_err_chk = 0;
+
+    // Let SW know the expected alert.
+    sw_alert_num = {TopEarlgreyAlertIdOtpCtrlFatalMacroError};
+    sw_symbol_backdoor_overwrite("kExpectedAlertNumber", sw_alert_num);
+
+    `DV_WAIT(cfg.sw_logger_vif.printed_log == "Ready for fault injection",
+             "Timeout waiting for fault injection request.")
+
+    val = cfg.mem_bkdr_util_h[Otp].read32(hw_cfg_addr);
+
+    // Inject 2 bits error in this hw_cfg_addr to trigger a ECC non-correctable error.
+    cfg.mem_bkdr_util_h[Otp].inject_errors(hw_cfg_addr, 2);
+
+
+    `DV_WAIT(cfg.sw_logger_vif.printed_log == "OTP_CTRL error inject done",
+             "Timeout waiting for OTP_CTRL error injection done.")
+
+    // TODO: backdoor check if alerts are firing.
+
+    // Backdoor write back the original value so the chip can reboot successfully.
+    cfg.mem_bkdr_util_h[Otp].write32(hw_cfg_addr, val);
+
+  endtask
+
+endclass
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
index 07ff42f..d551457 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
@@ -42,6 +42,7 @@
 `include "chip_sw_lc_walkthrough_vseq.sv"
 `include "chip_sw_lc_walkthrough_testunlocks_vseq.sv"
 `include "chip_sw_otp_ctrl_vendor_test_csr_access_vseq.sv"
+`include "chip_sw_otp_ctrl_escalation_vseq.sv"
 `include "chip_sw_spi_device_tx_rx_vseq.sv"
 `include "chip_sw_spi_host_tx_rx_vseq.sv"
 `include "chip_sw_spi_passthrough_vseq.sv"
diff --git a/sw/device/tests/sim_dv/all_escalation_resets_test.c b/sw/device/tests/sim_dv/all_escalation_resets_test.c
index 7e0f86f..85a916b 100644
--- a/sw/device/tests/sim_dv/all_escalation_resets_test.c
+++ b/sw/device/tests/sim_dv/all_escalation_resets_test.c
@@ -848,13 +848,16 @@
       fault_checker = fc;
     } break;
       // TODO add mechanism to inject:
-      // kTopEarlgreyAlertIdOtpCtrlFatalMacroError uncorrectable ecc from macro
-      // In any partition otp_ctrl_part_unbuf error_q = MacroEccUncorrError
       // kTopEarlgreyAlertIdOtpCtrlFatalPrimOtpAlert force at prim_otp interface
       // u_otp output fatal_alert_o.
       // forcing otp_prog_err_o from lc_ctrl_fsm and
       // kTopEarlgreyAlertIdLcCtrlFatalStateError using sparse fsm.
       // alerts, and corresponding CSR bit to check.
+    case kTopEarlgreyAlertIdOtpCtrlFatalMacroError: {
+      fault_checker_t fc = {otp_ctrl_fault_checker, otp_ctrl_inst_name,
+                            sparse_fsm_check};
+      fault_checker = fc;
+    } break;
     case kTopEarlgreyAlertIdOtpCtrlFatalCheckError: {
       fault_checker_t fc = {otp_ctrl_fault_checker, otp_ctrl_inst_name,
                             sparse_fsm_check};
@@ -991,6 +994,14 @@
   // DO NOT CHANGE THIS: it is used to notify the SV side.
   LOG_INFO("Ready for fault injection");
 
+  // OTP ecc macro error test requires otp to read backdoor injected error
+  // macro.
+  if (kExpectedAlertNumber == kTopEarlgreyAlertIdOtpCtrlFatalMacroError) {
+    CHECK_DIF_OK(
+        dif_otp_ctrl_dai_read_start(&otp_ctrl, kDifOtpCtrlPartitionHwCfg, 0));
+    LOG_INFO("OTP_CTRL error inject done");
+  }
+
   // FlashCtrlFatalErr test requires host read request.
   if (kExpectedAlertNumber == kTopEarlgreyAlertIdFlashCtrlFatalErr) {
     enum {
@@ -1116,10 +1127,12 @@
 
     // ISRs should not run if flash_ctrl or sram_ctrl_main get a fault because
     // flash or sram accesses are blocked in those cases. For lc_ctrl fatal
-    // state the lc_ctrl blocks the CPU.
+    // state, otp_fatal alerts tha will trigger LC to escalate, the lc_ctrl
+    // blocks the CPU.
     if (kExpectedAlertNumber == kTopEarlgreyAlertIdFlashCtrlFatalStdErr ||
         kExpectedAlertNumber == kTopEarlgreyAlertIdSramCtrlMainFatalError ||
         kExpectedAlertNumber == kTopEarlgreyAlertIdLcCtrlFatalStateError ||
+        kExpectedAlertNumber == kTopEarlgreyAlertIdOtpCtrlFatalMacroError ||
         kExpectedAlertNumber == kTopEarlgreyAlertIdOtpCtrlFatalCheckError) {
       CHECK(interrupt_count == 0,
             "Expected regular ISR should not run for flash_ctrl, lc_ctrl fatal "