Add sleep pin tests to edacloud

Change-Id: I2283faa3ff1b75febfaf706d861f169368479a60
diff --git a/hw/top_matcha/dv/chip_sim_cfg.hjson b/hw/top_matcha/dv/chip_sim_cfg.hjson
index 8be09e9..1fbdabb 100644
--- a/hw/top_matcha/dv/chip_sim_cfg.hjson
+++ b/hw/top_matcha/dv/chip_sim_cfg.hjson
@@ -653,7 +653,7 @@
     {
       name: chip_sw_sleep_pin_mio_dio_val
       uvm_test_seq: chip_sw_sleep_pin_mio_dio_val_vseq
-      sw_images: ["//sw/device/tests/sim_dv:sleep_pin_mio_dio_val_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:sleep_pin_mio_dio_val_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
       // Starting the chip in prod LC state frees up all MIOs for this test.
       run_opts: ["+use_otp_image=OtpTypeLcStProd"]
@@ -661,7 +661,7 @@
     {
       name: chip_sw_sleep_pin_wake
       uvm_test_seq: chip_sw_sleep_pin_wake_vseq
-      sw_images: ["//sw/device/tests/sim_dv:sleep_pin_wake_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:sleep_pin_wake_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
       // Starting the chip in prod LC state frees up all MIOs for this test.
       run_opts: ["+use_otp_image=OtpTypeLcStProd"]
@@ -2110,7 +2110,9 @@
         "chip_sw_rv_timer_irq",
         "chip_sw_sensor_ctrl_alert",
         "chip_sw_sensor_ctrl_status",
+        "chip_sw_sleep_pin_mio_dio_val",
         "chip_sw_sleep_pin_retention",
+        "chip_sw_sleep_pin_wake",
         "chip_sw_smc_cam_irq_test",
         "chip_sw_smc_ctrl_test",
         "chip_sw_smc_env_test",
@@ -2201,7 +2203,9 @@
         "chip_sw_rv_timer_irq",
         "chip_sw_sensor_ctrl_alert",
         "chip_sw_sensor_ctrl_status",
+        "chip_sw_sleep_pin_mio_dio_val",
         "chip_sw_sleep_pin_retention",
+        "chip_sw_sleep_pin_wake",
         "chip_sw_smc_cam_irq_test",
         "chip_sw_smc_ctrl_test",
         "chip_sw_smc_env_test",
diff --git a/hw/top_matcha/dv/env/seq_lib/chip_sw_sleep_pin_wake_vseq.sv b/hw/top_matcha/dv/env/seq_lib/chip_sw_sleep_pin_wake_vseq.sv
index 5a38b64..4925dc0 100644
--- a/hw/top_matcha/dv/env/seq_lib/chip_sw_sleep_pin_wake_vseq.sv
+++ b/hw/top_matcha/dv/env/seq_lib/chip_sw_sleep_pin_wake_vseq.sv
@@ -1,3 +1,4 @@
+// Copyright 2023 Google LLC.
 // Copyright lowRISC contributors.
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
@@ -80,6 +81,9 @@
     fork
       begin
         `DV_WAIT(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInBootRom)
+
+        drive_pad(pad_type, pad_idx, 1'bz);
+        cfg.chip_vif.gpios_if.set_pulldown_en({32{1'b1}});
         cfg.chip_vif.sw_straps_if.drive(0);
       end
       // On low power exit, the ROM restarts execution. The testbench at some point, drives the SW
diff --git a/sw/device/tests/sim_dv/BUILD b/sw/device/tests/sim_dv/BUILD
index 99a1de3..621ecc8 100644
--- a/sw/device/tests/sim_dv/BUILD
+++ b/sw/device/tests/sim_dv/BUILD
@@ -119,22 +119,6 @@
     ],
 )
 
-matcha_dv_test(
-    name = "sleep_pin_retention_test",
-    srcs = ["sleep_pin_retention_test.c"],
-    deps = [
-        "//sw/device/lib/dif:pinmux",
-        "//sw/device/lib/dif:rv_plic_sec",
-        "//sw/device/lib/testing:isr_testutils",
-        "//sw/device/tests:test_dv_lib",
-        "@lowrisc_opentitan//sw/device/lib/dif:gpio",
-        "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr",
-        "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils",
-        "@lowrisc_opentitan//sw/device/lib/testing:rand_testutils",
-        "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils",
-    ],
-)
-
 cc_library(
     name = "pwrmgr_sleep_all_wake_ups_impl",
     srcs = [
@@ -232,6 +216,45 @@
     ],
 )
 
+cc_library(
+    name = "sleep_pin_test_lib",
+    deps = [
+        "//sw/device/lib/dif:pinmux",
+        "//sw/device/lib/dif:rv_plic_sec",
+        "//sw/device/lib/testing:isr_testutils",
+        "//sw/device/tests:test_dv_lib",
+        "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr",
+        "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils",
+        "@lowrisc_opentitan//sw/device/lib/testing:rand_testutils",
+        "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils",
+    ],
+)
+
+matcha_dv_test(
+    name = "sleep_pin_mio_dio_val_test",
+    srcs = ["sleep_pin_mio_dio_val_test.c"],
+    deps = [
+        ":sleep_pin_test_lib",
+    ],
+)
+
+matcha_dv_test(
+    name = "sleep_pin_wake_test",
+    srcs = ["sleep_pin_wake_test.c"],
+    deps = [
+        ":sleep_pin_test_lib",
+    ],
+)
+
+matcha_dv_test(
+    name = "sleep_pin_retention_test",
+    srcs = ["sleep_pin_retention_test.c"],
+    deps = [
+        ":sleep_pin_test_lib",
+        "@lowrisc_opentitan//sw/device/lib/dif:gpio",
+    ],
+)
+
 ################################################################################
 #  Place the Opentitan-sourced DV test below.                                  #
 #  Opentitan DV binary build flow does not support centOS7, so we pull the     #
diff --git a/sw/device/tests/sim_dv/sleep_pin_mio_dio_val_test.c b/sw/device/tests/sim_dv/sleep_pin_mio_dio_val_test.c
new file mode 100644
index 0000000..43503ae
--- /dev/null
+++ b/sw/device/tests/sim_dv/sleep_pin_mio_dio_val_test.c
@@ -0,0 +1,295 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_pinmux.h"
+#include "sw/device/lib/dif/dif_pwrmgr.h"
+#include "sw/device/lib/dif/dif_rv_plic.h"
+#include "sw/device/lib/runtime/irq.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/autogen/isr_testutils.h"
+#include "sw/device/lib/testing/pwrmgr_testutils.h"
+#include "sw/device/lib/testing/rand_testutils.h"
+#include "sw/device/lib/testing/rv_plic_testutils.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+/**
+ * Test: chip_sw_sleep_pin_mio_dio_val
+ *
+ * chip_sw_sleep_pin_mio_dio_val test is to check the PADs assert desired
+ * values. When the chip enters deep powerdown (turning off power domains
+ * except AON), PADs cannot get the data from off domain logics.
+ *
+ * To not confuse the devices outside of the logic, usually isolation cells are
+ * placed in between (off and on). OpenTitan, on top of the isolation, provides
+ * a functionality to control the PADs output value among **0**, **1**,
+ * **High-Z**, and **Passthrough**. Refer the PINMUX technical specification
+ * for the details.
+ *
+ * In this test, the code randomizes the output values except the
+ * **passthrough**, as **passthrough** is tested in other chip level test. Then
+ * the chosen values are given to the UVM testbenches. UVM testbenches compare
+ * the expected and measured values.
+ */
+
+/* NUM_MIO_PADS */
+/* NUM_DIO_PADS */
+
+/* DioOptOut: Some of DIO PADs are input only or does not need to be tested as
+ * they are alive in deep powerdown state. This lists out the PADs. Its entry
+ * is the index of DIOs.
+ *
+ * ```systemverilog
+ * localparam chip_io_e DioPads [NumDioPads] = '{
+ *   UsbP,       // DIO 0                INOUT
+ *   UsbN,       // DIO 1                INOUT
+ *   SpiHostD0,  // DIO 2                INOUT
+ *   SpiHostD1,  // DIO 3                INOUT
+ *   SpiHostD2,  // DIO 4                INOUT
+ *   SpiHostD3,  // DIO 5                INOUT
+ *   SpiDevD0,   // DIO 6                INOUT
+ *   SpiDevD1,   // DIO 7                INOUT
+ *   SpiDevD2,   // DIO 8                INOUT
+ *   SpiDevD3,   // DIO 9                INOUT
+ *   IoR8,       // DIO 10 EC_RST_L      INOUT
+ *   IoR9,       // DIO 11 FLASH_WP_L    INOUT
+ *   SpiDevClk,  // DIO 12               INPUT
+ *   SpiDevCsL,  // DIO 13               INPUT
+ *   SpiHostClk, // DIO 14               OUTPUT
+ *   SpiHostCsL  // DIO 15               OUTPUT
+ * }
+ * ```
+ */
+
+typedef enum {
+  kDioUsbP,       /* DIO 0                INOUT  */
+  kDioUsbN,       /* DIO 1                INOUT  */
+  kDioSpiHostD0,  /* DIO 2                INOUT  */
+  kDioSpiHostD1,  /* DIO 3                INOUT  */
+  kDioSpiHostD2,  /* DIO 4                INOUT  */
+  kDioSpiHostD3,  /* DIO 5                INOUT  */
+  kDioSpiDevD0,   /* DIO 6                INOUT  */
+  kDioSpiDevD1,   /* DIO 7                INOUT  */
+  kDioSpiDevD2,   /* DIO 8                INOUT  */
+  kDioSpiDevD3,   /* DIO 9                INOUT  */
+  kDioIoR8,       /* DIO 10 EC_RST_L      INOUT  */
+  kDioIoR9,       /* DIO 11 FLASH_WP_L    INOUT  */
+  kDioSpiDevClk,  /* DIO 12               INPUT  */
+  kDioSpiDevCsL,  /* DIO 13               INPUT  */
+  kDioSpiHostClk, /* DIO 14               OUTPUT */
+  kDioSpiHostCsL  /* DIO 15               OUTPUT */
+} dio_pad_idx_t;
+
+enum { kNumOptOutDio = 2 };
+static const uint8_t kOptOutDio[kNumOptOutDio] = {kDioSpiDevClk, kDioSpiDevCsL};
+
+typedef enum {
+  kMioIoR0 = 35,
+  kMioIoR2 = 37,
+  kMioIoR3 = 38,
+  kMioIoR4 = 39
+} mio_pad_idx_t;
+
+/**
+ * If certain MIOs need to be skipped due to tied functionality, specify here.
+ */
+enum { kNumOptOutMio = 0 };
+static const uint8_t kOptOutMio[kNumOptOutMio] = {};
+
+static uint8_t kMioPads[NUM_MIO_PADS] = {0};
+static uint8_t kDioPads[NUM_DIO_PADS] = {0};
+
+// PLIC structures
+static const uint32_t kPlicTarget = kTopMatchaPlicTargetIbex0;
+static dif_pwrmgr_t pwrmgr;
+static dif_pinmux_t pinmux;
+static dif_rv_plic_t plic;
+
+static plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
+                                  .hart_id = kTopMatchaPlicTargetIbex0};
+
+static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
+    .pwrmgr = &pwrmgr,
+    .plic_pwrmgr_start_irq_id = kTopMatchaPlicIrqIdPwrmgrAonWakeup,
+    .expected_irq = kDifPwrmgrIrqWakeup,
+    .is_only_irq = true};
+
+/**
+ * External interrupt handler.
+ */
+void ottf_external_isr(void) {
+  dif_pwrmgr_irq_t irq_id;
+  top_matcha_plic_peripheral_t peripheral;
+
+  isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
+
+  // Check that both the peripheral and the irq id is correct
+  CHECK(peripheral == kTopMatchaPlicPeripheralPwrmgrAon,
+        "IRQ peripheral: %d is incorrect", peripheral);
+  CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
+}
+
+/** Configure pinmux retention value.
+ *
+ * Each gen32 can cover 16 PADs randomization. When each pad ret val draws
+ * **3**, the code calls gen32_range to choose from 0 to 2.
+ */
+void draw_pinmux_ret(const uint32_t num_pins, uint8_t *arr,
+                     const uint8_t *optout, const uint8_t num_optout) {
+  for (int i = 0; i < num_pins; i += 16) {
+    uint32_t val = rand_testutils_gen32();
+    uint32_t min_idx = (i + 16 < num_pins) ? i + 16 : num_pins;
+
+    for (int j = i; j < min_idx; j++) {
+      /* Bit slice 2b at a time and if it is 3, redraw */
+      arr[j] = (val >> ((j & 0xF) * 2)) & 0x3;
+      if (arr[j] == 3) {
+        arr[j] = (uint8_t)rand_testutils_gen32_range(0, 2);
+      }
+    }
+  }
+
+  // OptOut processing after draw.
+  for (int i = 0; i < num_optout; i++) {
+    arr[optout[i]] = 2;  // High-Z always
+  }
+}
+
+/**
+ * Send the chosen values to UVM tb.
+ *
+ * Format:
+ *
+ *     "{DIO/MIO} [i]: {}"
+ */
+void print_chosen_values(void) {
+  LOG_INFO("BEGIN Chosen Retention Types");
+  for (int i = 0; i < NUM_MIO_PADS; ++i) {
+    LOG_INFO("MIO [%d]: %x", i, kMioPads[i]);
+  }
+  for (int i = 0; i < NUM_DIO_PADS; ++i) {
+    LOG_INFO("DIO [%d]: %x", i, kDioPads[i]);
+  }
+  LOG_INFO("END Chosen Retention Types");
+}
+
+/**
+ * Configure PADs retention types.
+ *
+ * @param pinmux Pinmux handle.
+ */
+void configure_pad_retention_types(dif_pinmux_t *pinmux) {
+  uint8_t io;  // 1 for DIO, 0 for MIO
+  uint32_t max_pads;
+  dif_pinmux_pad_kind_t pad_kind;
+  dif_pinmux_sleep_mode_t pad_mode;
+  LOG_INFO("Configuring PADs retention types in PINMUX...");
+
+  // TODO: for loop of writing values to PINMUX CSRs.
+  for (io = 0; io < 2; io++) {
+    max_pads = (io) ? NUM_DIO_PADS : NUM_MIO_PADS;
+    pad_kind = (io) ? kDifPinmuxPadKindDio : kDifPinmuxPadKindMio;
+    for (int i = 0; i < max_pads; i++) {
+      pad_mode = (io) ? (dif_pinmux_sleep_mode_t)(kDioPads[i])
+                      : (dif_pinmux_sleep_mode_t)(kMioPads[i]);
+      CHECK_DIF_OK(dif_pinmux_pad_sleep_enable(pinmux, (dif_pinmux_index_t)i,
+                                               pad_kind, pad_mode));
+    }
+  }
+
+  LOG_INFO("PADs retention modes are configured.");
+}
+
+bool lowpower_prep(dif_pwrmgr_t *pwrmgr, dif_pinmux_t *pinmux, bool deepsleep) {
+  bool result = false;
+  dif_pwrmgr_domain_config_t pwrmgr_domain_cfg = 0;
+
+  LOG_INFO("Selecting PADs retention modes...");
+
+  draw_pinmux_ret(NUM_DIO_PADS, kDioPads, kOptOutDio, kNumOptOutDio);
+  draw_pinmux_ret(NUM_MIO_PADS, kMioPads, kOptOutMio, kNumOptOutMio);
+
+  print_chosen_values();
+
+  // Configure pwrmgr to deep powerdown.
+  configure_pad_retention_types(pinmux);
+
+  if (!deepsleep) {
+    pwrmgr_domain_cfg = kDifPwrmgrDomainOptionMainPowerInLowPower |
+                        kDifPwrmgrDomainOptionUsbClockInActivePower;
+  }
+  CHECK_DIF_OK(dif_pwrmgr_set_domain_config(pwrmgr, pwrmgr_domain_cfg,
+                                            kDifToggleEnabled));
+  CHECK_DIF_OK(dif_pwrmgr_low_power_set_enabled(pwrmgr, kDifToggleEnabled,
+                                                kDifToggleEnabled));
+
+  wait_for_interrupt();  // Entering deep power down.
+
+  return result;
+}
+
+bool test_main(void) {
+  bool result = false;
+
+  // Enable global and external IRQ at Ibex.
+  irq_global_ctrl(true);
+  irq_external_ctrl(true);
+
+  CHECK_DIF_OK(dif_pwrmgr_init(
+      mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr));
+  CHECK_DIF_OK(dif_pinmux_init(
+      mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux));
+  CHECK_DIF_OK(dif_rv_plic_init(
+      mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic));
+
+  if (pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) {
+    uint32_t deep_powerdown_en = rand_testutils_gen32_range(0, 1);
+    bool deepsleep = (deep_powerdown_en) ? true : false;
+
+    // TODO(lowrisc/opentitan#15889): The weak pulls on IOC3 and IOC10 need
+    // to be disabled for this test. Remove this later.
+    dif_pinmux_pad_attr_t out_attr;
+    dif_pinmux_pad_attr_t in_attr = {0};
+    CHECK_DIF_OK(dif_pinmux_pad_write_attrs(&pinmux, kTopMatchaMuxedPadsIoc3,
+                                            kDifPinmuxPadKindMio, in_attr,
+                                            &out_attr));
+    CHECK_DIF_OK(dif_pinmux_pad_write_attrs(&pinmux, kTopMatchaMuxedPadsIoc10,
+                                            kDifPinmuxPadKindMio, in_attr,
+                                            &out_attr));
+
+    if (!deepsleep) {
+      // Enable all the AON interrupts used in this test.
+      rv_plic_testutils_irq_range_enable(&plic, kTopMatchaPlicTargetIbex0,
+                                         kTopMatchaPlicIrqIdPwrmgrAonWakeup,
+                                         kTopMatchaPlicIrqIdPwrmgrAonWakeup);
+      // Enable pwrmgr interrupt
+      CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
+    }
+
+    result = lowpower_prep(&pwrmgr, &pinmux, deepsleep);
+  }
+
+  if (pwrmgr_testutils_is_wakeup_reason(&pwrmgr,
+                                        kDifPwrmgrWakeupRequestSourceThree)) {
+    // TODO: change PINMUX wakeup, not pin detector
+    /**
+     *  Usually this part won't be hit. UVM testbench checks the PAD output
+     *  values and raises an error if failed.
+     */
+  } else {
+    // Other wakeup. This is a failure.
+    dif_pwrmgr_wakeup_reason_t wakeup_reason;
+    CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
+    LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
+              wakeup_reason.types, wakeup_reason.request_sources);
+    result = false;
+  }
+
+  return result;
+}
diff --git a/sw/device/tests/sim_dv/sleep_pin_wake_test.c b/sw/device/tests/sim_dv/sleep_pin_wake_test.c
new file mode 100644
index 0000000..7172111
--- /dev/null
+++ b/sw/device/tests/sim_dv/sleep_pin_wake_test.c
@@ -0,0 +1,187 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "pinmux_regs.h"  // Generated.
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_pinmux.h"
+#include "sw/device/lib/dif/dif_pwrmgr.h"
+#include "sw/device/lib/dif/dif_rv_plic.h"
+#include "sw/device/lib/runtime/irq.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/autogen/isr_testutils.h"
+#include "sw/device/lib/testing/pwrmgr_testutils.h"
+#include "sw/device/lib/testing/rand_testutils.h"
+#include "sw/device/lib/testing/rv_plic_testutils.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+// PLIC structures
+static const uint32_t kPlicTarget = kTopMatchaPlicTargetIbex0;
+static dif_pwrmgr_t pwrmgr;
+static dif_pinmux_t pinmux;
+static dif_rv_plic_t plic;
+
+static const uint32_t kNumDio = 16;  // top_matcha has 16 DIOs
+
+// kDirectDio is a list of Dio index that TB cannot control the PAD value.
+// The list should be incremental order (see the code below)
+#define NUM_DIRECT_DIO 5
+static const uint32_t kDirectDio[NUM_DIRECT_DIO] = {6, 12, 13, 14, 15};
+
+static plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
+                                  .hart_id = kTopMatchaPlicTargetIbex0};
+
+static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
+    .pwrmgr = &pwrmgr,
+    .plic_pwrmgr_start_irq_id = kTopMatchaPlicIrqIdPwrmgrAonWakeup,
+    .expected_irq = kDifPwrmgrIrqWakeup,
+    .is_only_irq = true};
+
+/**
+ * External interrupt handler.
+ */
+void ottf_external_isr(void) {
+  dif_pwrmgr_irq_t irq_id;
+  top_matcha_plic_peripheral_t peripheral;
+
+  isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
+
+  // Check that both the peripheral and the irq id is correct
+  CHECK(peripheral == kTopMatchaPlicPeripheralPwrmgrAon,
+        "IRQ peripheral: %d is incorrect", peripheral);
+  CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
+}
+
+bool test_main(void) {
+  dif_pinmux_index_t detector;
+  dif_pinmux_wakeup_config_t wakeup_cfg;
+
+  // Default Deep Power Down
+  dif_pwrmgr_domain_config_t pwrmgr_domain_cfg = 0;
+
+  // Enable global and external IRQ at Ibex.
+  irq_global_ctrl(true);
+  irq_external_ctrl(true);
+
+  // Initialize power manager
+  CHECK_DIF_OK(dif_pwrmgr_init(
+      mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr));
+  CHECK_DIF_OK(dif_rv_plic_init(
+      mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic));
+  CHECK_DIF_OK(dif_pinmux_init(
+      mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux));
+
+  // Randomly pick one of the wakeup detectors.
+  dif_pinmux_index_t wakeup_detector_selected =
+      rand_testutils_gen32_range(0, PINMUX_PARAM_N_WKUP_DETECT - 1);
+
+  if (pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) {
+    LOG_INFO("Test in POR phase");
+
+    LOG_INFO("pinmux_init end");
+
+    // TODO(lowrisc/opentitan#15889): The weak pulls on IOC3 and IOC10 need
+    // to be disabled for this test. Remove this later.
+    dif_pinmux_pad_attr_t out_attr;
+    dif_pinmux_pad_attr_t in_attr = {0};
+    CHECK_DIF_OK(dif_pinmux_pad_write_attrs(&pinmux, kTopMatchaMuxedPadsIoc3,
+                                            kDifPinmuxPadKindMio, in_attr,
+                                            &out_attr));
+    CHECK_DIF_OK(dif_pinmux_pad_write_attrs(&pinmux, kTopMatchaMuxedPadsIoc10,
+                                            kDifPinmuxPadKindMio, in_attr,
+                                            &out_attr));
+
+    // Random choose low power or deep powerdown
+    uint32_t deep_powerdown_en = rand_testutils_gen32_range(0, 1);
+
+    // Prepare which PAD SW want to select
+    uint32_t mio0_dio1 = rand_testutils_gen32_range(0, 1);
+    uint32_t pad_sel = 0;
+
+    // Enable AonWakeup Interrupt if normal sleep
+    if (deep_powerdown_en == 0) {
+      // Enable all the AON interrupts used in this test.
+      rv_plic_testutils_irq_range_enable(&plic, kTopMatchaPlicTargetIbex0,
+                                         kTopMatchaPlicIrqIdPwrmgrAonWakeup,
+                                         kTopMatchaPlicIrqIdPwrmgrAonWakeup);
+      // Enable pwrmgr interrupt
+      CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
+    }
+
+    // SpiDev CLK(idx 12), CS#(idx 13), D0(idx 6) and SpiHost CLK (14), CS#
+    // (15) are directly connected to the SPI IF. Cannot control them. Roll 3
+    // less and compensated later.
+    if (mio0_dio1) {
+      // DIO
+      pad_sel = rand_testutils_gen32_range(0, kNumDio - 1 - NUM_DIRECT_DIO);
+
+      for (int i = 0; i < NUM_DIRECT_DIO; i++) {
+        if (pad_sel >= kDirectDio[i]) {
+          pad_sel++;
+        }
+      }
+      LOG_INFO("Pad Selection: %d / %d", mio0_dio1, pad_sel);
+    } else {
+      // MIO: 0, 1 are tie-0, tie-1
+      pad_sel = rand_testutils_gen32_range(2, kTopMatchaPinmuxInselLast);
+      LOG_INFO("Pad Selection: %d / %d", mio0_dio1, pad_sel - 2);
+    }
+
+    if (mio0_dio1 == 0) {
+      // Turn off Pinmux output selection
+      CHECK_DIF_OK(dif_pinmux_output_select(
+          &pinmux, pad_sel - 2, kTopMatchaPinmuxOutselConstantHighZ));
+    }
+
+    wakeup_cfg.mode = kDifPinmuxWakeupModePositiveEdge;
+    wakeup_cfg.signal_filter = false;
+    wakeup_cfg.pad_type = mio0_dio1;
+    wakeup_cfg.pad_select = pad_sel;
+
+    // TODO: A better test would be to program ALL wakeup detectors with
+    // randomly chosen pin wakeup sources and prove the right wakeup source
+    // woke up the chip from sleep.
+    CHECK_DIF_OK(dif_pinmux_wakeup_detector_enable(
+        &pinmux, wakeup_detector_selected, wakeup_cfg));
+
+    if (deep_powerdown_en == 0) {
+      pwrmgr_domain_cfg = kDifPwrmgrDomainOptionMainPowerInLowPower |
+                          kDifPwrmgrDomainOptionUsbClockInActivePower;
+    }
+    // Enter low power
+    pwrmgr_testutils_enable_low_power(
+        &pwrmgr, kDifPwrmgrWakeupRequestSourceThree, pwrmgr_domain_cfg);
+
+    LOG_INFO("Entering low power mode.");
+    wait_for_interrupt();
+  }
+
+  if (pwrmgr_testutils_is_wakeup_reason(&pwrmgr,
+                                        kDifPwrmgrWakeupRequestSourceThree)) {
+    LOG_INFO("Test in post-sleep pin wakeup phase");
+    uint32_t wakeup_cause;
+    CHECK_DIF_OK(dif_pinmux_wakeup_cause_get(&pinmux, &wakeup_cause));
+    CHECK(wakeup_cause == 1 << wakeup_detector_selected);
+    CHECK_DIF_OK(
+        dif_pinmux_wakeup_detector_disable(&pinmux, wakeup_detector_selected));
+    return true;
+
+  } else {
+    // Other wakeup. This is a failure.
+    dif_pwrmgr_wakeup_reason_t wakeup_reason;
+    CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
+    LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
+              wakeup_reason.types, wakeup_reason.request_sources);
+    return false;
+  }
+
+  return false;
+}
+
+#undef NUM_DIRECT_DIO
+#undef NUM_LOCKED_MIO