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